aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/Linden
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden')
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs897
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/MeshCost.cs671
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs4
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs11
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs448
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs419
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs18
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs297
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs9
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs193
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs10
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs3
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs1506
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs115
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs134
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs4
16 files changed, 3579 insertions, 1160 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
index 1d4c7f0..762e22a 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
@@ -26,6 +26,7 @@
26 */ 26 */
27 27
28using System; 28using System;
29using System.Timers;
29using System.Collections; 30using System.Collections;
30using System.Collections.Generic; 31using System.Collections.Generic;
31using System.IO; 32using System.IO;
@@ -54,14 +55,16 @@ using PermissionMask = OpenSim.Framework.PermissionMask;
54namespace OpenSim.Region.ClientStack.Linden 55namespace OpenSim.Region.ClientStack.Linden
55{ 56{
56 public delegate void UpLoadedAsset( 57 public delegate void UpLoadedAsset(
57 string assetName, string description, UUID assetID, UUID inventoryItem, UUID parentFolder, 58 string assetName, string description, UUID assetID, UUID inventoryItem, UUID parentFolder,
58 byte[] data, string inventoryType, string assetType); 59 byte[] data, string inventoryType, string assetType,
60 int cost, UUID texturesFolder, int nreqtextures, int nreqmeshs, int nreqinstances,
61 bool IsAtestUpload, ref string error);
59 62
60 public delegate UUID UpdateItem(UUID itemID, byte[] data); 63 public delegate UUID UpdateItem(UUID itemID, byte[] data);
61 64
62 public delegate void UpdateTaskScript(UUID itemID, UUID primID, bool isScriptRunning, byte[] data, ref ArrayList errors); 65 public delegate void UpdateTaskScript(UUID itemID, UUID primID, bool isScriptRunning, byte[] data, ref ArrayList errors);
63 66
64 public delegate void NewInventoryItem(UUID userID, InventoryItemBase item); 67 public delegate void NewInventoryItem(UUID userID, InventoryItemBase item, uint cost);
65 68
66 public delegate void NewAsset(AssetBase asset); 69 public delegate void NewAsset(AssetBase asset);
67 70
@@ -87,6 +90,7 @@ namespace OpenSim.Region.ClientStack.Linden
87 90
88 private Scene m_Scene; 91 private Scene m_Scene;
89 private Caps m_HostCapsObj; 92 private Caps m_HostCapsObj;
93 private ModelCost m_ModelCost;
90 94
91 private static readonly string m_requestPath = "0000/"; 95 private static readonly string m_requestPath = "0000/";
92 // private static readonly string m_mapLayerPath = "0001/"; 96 // private static readonly string m_mapLayerPath = "0001/";
@@ -98,7 +102,8 @@ namespace OpenSim.Region.ClientStack.Linden
98 private static readonly string m_copyFromNotecardPath = "0007/"; 102 private static readonly string m_copyFromNotecardPath = "0007/";
99 // private static readonly string m_remoteParcelRequestPath = "0009/";// This is in the LandManagementModule. 103 // private static readonly string m_remoteParcelRequestPath = "0009/";// This is in the LandManagementModule.
100 private static readonly string m_getObjectPhysicsDataPath = "0101/"; 104 private static readonly string m_getObjectPhysicsDataPath = "0101/";
101 /* 0102 - 0103 RESERVED */ 105 private static readonly string m_getObjectCostPath = "0102/";
106 private static readonly string m_ResourceCostSelectedPath = "0103/";
102 private static readonly string m_UpdateAgentInformationPath = "0500/"; 107 private static readonly string m_UpdateAgentInformationPath = "0500/";
103 108
104 // These are callbacks which will be setup by the scene so that we can update scene data when we 109 // These are callbacks which will be setup by the scene so that we can update scene data when we
@@ -114,12 +119,50 @@ namespace OpenSim.Region.ClientStack.Linden
114 private IAssetService m_assetService; 119 private IAssetService m_assetService;
115 private bool m_dumpAssetsToFile = false; 120 private bool m_dumpAssetsToFile = false;
116 private string m_regionName; 121 private string m_regionName;
122
117 private int m_levelUpload = 0; 123 private int m_levelUpload = 0;
118 124
125 private bool m_enableFreeTestUpload = false; // allows "TEST-" prefix hack
126 private bool m_ForceFreeTestUpload = false; // forces all uploads to be test
127
128 private bool m_enableModelUploadTextureToInventory = false; // place uploaded textures also in inventory
129 // may not be visible till relog
130
131 private bool m_RestrictFreeTestUploadPerms = false; // reduces also the permitions. Needs a creator defined!!
132 private UUID m_testAssetsCreatorID = UUID.Zero;
133
134 private float m_PrimScaleMin = 0.001f;
135
136 private enum FileAgentInventoryState : int
137 {
138 idle = 0,
139 processRequest = 1,
140 waitUpload = 2,
141 processUpload = 3
142 }
143 private FileAgentInventoryState m_FileAgentInventoryState = FileAgentInventoryState.idle;
144
119 public BunchOfCaps(Scene scene, Caps caps) 145 public BunchOfCaps(Scene scene, Caps caps)
120 { 146 {
121 m_Scene = scene; 147 m_Scene = scene;
122 m_HostCapsObj = caps; 148 m_HostCapsObj = caps;
149
150 // create a model upload cost provider
151 m_ModelCost = new ModelCost();
152 // tell it about scene object limits
153 m_ModelCost.NonPhysicalPrimScaleMax = m_Scene.m_maxNonphys;
154 m_ModelCost.PhysicalPrimScaleMax = m_Scene.m_maxPhys;
155
156// m_ModelCost.ObjectLinkedPartsMax = ??
157// m_ModelCost.PrimScaleMin = ??
158
159 m_PrimScaleMin = m_ModelCost.PrimScaleMin;
160 float modelTextureUploadFactor = m_ModelCost.ModelTextureCostFactor;
161 float modelUploadFactor = m_ModelCost.ModelMeshCostFactor;
162 float modelMinUploadCostFactor = m_ModelCost.ModelMinCostFactor;
163 float modelPrimCreationCost = m_ModelCost.primCreationCost;
164 float modelMeshByteCost = m_ModelCost.bytecost;
165
123 IConfigSource config = m_Scene.Config; 166 IConfigSource config = m_Scene.Config;
124 if (config != null) 167 if (config != null)
125 { 168 {
@@ -134,6 +177,37 @@ namespace OpenSim.Region.ClientStack.Linden
134 { 177 {
135 m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures); 178 m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures);
136 } 179 }
180 // economy for model upload
181 IConfig EconomyConfig = config.Configs["Economy"];
182 if (EconomyConfig != null)
183 {
184 modelUploadFactor = EconomyConfig.GetFloat("MeshModelUploadCostFactor", modelUploadFactor);
185 modelTextureUploadFactor = EconomyConfig.GetFloat("MeshModelUploadTextureCostFactor", modelTextureUploadFactor);
186 modelMinUploadCostFactor = EconomyConfig.GetFloat("MeshModelMinCostFactor", modelMinUploadCostFactor);
187 // next 2 are normalized so final cost is afected by modelUploadFactor above and normal cost
188 modelPrimCreationCost = EconomyConfig.GetFloat("ModelPrimCreationCost", modelPrimCreationCost);
189 modelMeshByteCost = EconomyConfig.GetFloat("ModelMeshByteCost", modelMeshByteCost);
190
191 m_enableModelUploadTextureToInventory = EconomyConfig.GetBoolean("MeshModelAllowTextureToInventory", m_enableModelUploadTextureToInventory);
192
193 m_RestrictFreeTestUploadPerms = EconomyConfig.GetBoolean("m_RestrictFreeTestUploadPerms", m_RestrictFreeTestUploadPerms);
194 m_enableFreeTestUpload = EconomyConfig.GetBoolean("AllowFreeTestUpload", m_enableFreeTestUpload);
195 m_ForceFreeTestUpload = EconomyConfig.GetBoolean("ForceFreeTestUpload", m_ForceFreeTestUpload);
196 string testcreator = EconomyConfig.GetString("TestAssetsCreatorID", "");
197 if (testcreator != "")
198 {
199 UUID id;
200 UUID.TryParse(testcreator, out id);
201 if (id != null)
202 m_testAssetsCreatorID = id;
203 }
204
205 m_ModelCost.ModelMeshCostFactor = modelUploadFactor;
206 m_ModelCost.ModelTextureCostFactor = modelTextureUploadFactor;
207 m_ModelCost.ModelMinCostFactor = modelMinUploadCostFactor;
208 m_ModelCost.primCreationCost = modelPrimCreationCost;
209 m_ModelCost.bytecost = modelMeshByteCost;
210 }
137 } 211 }
138 212
139 m_assetService = m_Scene.AssetService; 213 m_assetService = m_Scene.AssetService;
@@ -145,6 +219,8 @@ namespace OpenSim.Region.ClientStack.Linden
145 ItemUpdatedCall = m_Scene.CapsUpdateInventoryItemAsset; 219 ItemUpdatedCall = m_Scene.CapsUpdateInventoryItemAsset;
146 TaskScriptUpdatedCall = m_Scene.CapsUpdateTaskInventoryScriptAsset; 220 TaskScriptUpdatedCall = m_Scene.CapsUpdateTaskInventoryScriptAsset;
147 GetClient = m_Scene.SceneGraph.GetControllingClient; 221 GetClient = m_Scene.SceneGraph.GetControllingClient;
222
223 m_FileAgentInventoryState = FileAgentInventoryState.idle;
148 } 224 }
149 225
150 /// <summary> 226 /// <summary>
@@ -190,7 +266,6 @@ namespace OpenSim.Region.ClientStack.Linden
190 { 266 {
191 try 267 try
192 { 268 {
193 // I don't think this one works...
194 m_HostCapsObj.RegisterHandler( 269 m_HostCapsObj.RegisterHandler(
195 "NewFileAgentInventory", 270 "NewFileAgentInventory",
196 new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDAssetUploadResponse>( 271 new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDAssetUploadResponse>(
@@ -212,6 +287,10 @@ namespace OpenSim.Region.ClientStack.Linden
212 = new RestStreamHandler( 287 = new RestStreamHandler(
213 "POST", capsBase + m_getObjectPhysicsDataPath, GetObjectPhysicsData, "GetObjectPhysicsData", null); 288 "POST", capsBase + m_getObjectPhysicsDataPath, GetObjectPhysicsData, "GetObjectPhysicsData", null);
214 m_HostCapsObj.RegisterHandler("GetObjectPhysicsData", getObjectPhysicsDataHandler); 289 m_HostCapsObj.RegisterHandler("GetObjectPhysicsData", getObjectPhysicsDataHandler);
290 IRequestHandler getObjectCostHandler = new RestStreamHandler("POST", capsBase + m_getObjectCostPath, GetObjectCost);
291 m_HostCapsObj.RegisterHandler("GetObjectCost", getObjectCostHandler);
292 IRequestHandler ResourceCostSelectedHandler = new RestStreamHandler("POST", capsBase + m_ResourceCostSelectedPath, ResourceCostSelected);
293 m_HostCapsObj.RegisterHandler("ResourceCostSelected", ResourceCostSelectedHandler);
215 294
216 IRequestHandler UpdateAgentInformationHandler 295 IRequestHandler UpdateAgentInformationHandler
217 = new RestStreamHandler( 296 = new RestStreamHandler(
@@ -270,6 +349,9 @@ namespace OpenSim.Region.ClientStack.Linden
270 m_log.DebugFormat( 349 m_log.DebugFormat(
271 "[CAPS]: Received SEED caps request in {0} for agent {1}", m_regionName, m_HostCapsObj.AgentID); 350 "[CAPS]: Received SEED caps request in {0} for agent {1}", m_regionName, m_HostCapsObj.AgentID);
272 351
352 if (!m_HostCapsObj.WaitForActivation())
353 return string.Empty;
354
273 if (!m_Scene.CheckClient(m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint)) 355 if (!m_Scene.CheckClient(m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint))
274 { 356 {
275 m_log.WarnFormat( 357 m_log.WarnFormat(
@@ -399,62 +481,176 @@ namespace OpenSim.Region.ClientStack.Linden
399 //m_log.Debug("[CAPS]: NewAgentInventoryRequest Request is: " + llsdRequest.ToString()); 481 //m_log.Debug("[CAPS]: NewAgentInventoryRequest Request is: " + llsdRequest.ToString());
400 //m_log.Debug("asset upload request via CAPS" + llsdRequest.inventory_type + " , " + llsdRequest.asset_type); 482 //m_log.Debug("asset upload request via CAPS" + llsdRequest.inventory_type + " , " + llsdRequest.asset_type);
401 483
484 // start by getting the client
485 IClientAPI client = null;
486 m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client);
487
488 // check current state so we only have one service at a time
489 lock (m_ModelCost)
490 {
491 switch (m_FileAgentInventoryState)
492 {
493 case FileAgentInventoryState.processRequest:
494 case FileAgentInventoryState.processUpload:
495 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
496 resperror.message = "Uploader busy processing previus request";
497 resperror.identifier = UUID.Zero;
498
499 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
500 errorResponse.uploader = "";
501 errorResponse.state = "error";
502 errorResponse.error = resperror;
503 return errorResponse;
504 break;
505 case FileAgentInventoryState.waitUpload:
506 // todo stop current uploader server
507 break;
508 case FileAgentInventoryState.idle:
509 default:
510 break;
511 }
512
513 m_FileAgentInventoryState = FileAgentInventoryState.processRequest;
514 }
515
516 int cost = 0;
517 int nreqtextures = 0;
518 int nreqmeshs= 0;
519 int nreqinstances = 0;
520 bool IsAtestUpload = false;
521
522 string assetName = llsdRequest.name;
523
524 LLSDAssetUploadResponseData meshcostdata = new LLSDAssetUploadResponseData();
525
402 if (llsdRequest.asset_type == "texture" || 526 if (llsdRequest.asset_type == "texture" ||
403 llsdRequest.asset_type == "animation" || 527 llsdRequest.asset_type == "animation" ||
528 llsdRequest.asset_type == "mesh" ||
404 llsdRequest.asset_type == "sound") 529 llsdRequest.asset_type == "sound")
405 { 530 {
406 ScenePresence avatar = null; 531 ScenePresence avatar = null;
407 IClientAPI client = null;
408 m_Scene.TryGetScenePresence(m_HostCapsObj.AgentID, out avatar); 532 m_Scene.TryGetScenePresence(m_HostCapsObj.AgentID, out avatar);
409 533
410 // check user level 534 // check user level
411 if (avatar != null) 535 if (avatar != null)
412 { 536 {
413 client = avatar.ControllingClient;
414
415 if (avatar.UserLevel < m_levelUpload) 537 if (avatar.UserLevel < m_levelUpload)
416 { 538 {
417 if (client != null) 539 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
418 client.SendAgentAlertMessage("Unable to upload asset. Insufficient permissions.", false); 540 resperror.message = "Insufficient permissions to upload";
541 resperror.identifier = UUID.Zero;
419 542
420 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse(); 543 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
421 errorResponse.uploader = ""; 544 errorResponse.uploader = "";
422 errorResponse.state = "error"; 545 errorResponse.state = "error";
546 errorResponse.error = resperror;
547 lock (m_ModelCost)
548 m_FileAgentInventoryState = FileAgentInventoryState.idle;
423 return errorResponse; 549 return errorResponse;
424 } 550 }
425 } 551 }
426 552
427 // check funds 553 // check test upload and funds
428 if (client != null) 554 if (client != null)
429 { 555 {
430 IMoneyModule mm = m_Scene.RequestModuleInterface<IMoneyModule>(); 556 IMoneyModule mm = m_Scene.RequestModuleInterface<IMoneyModule>();
431 557
558 int baseCost = 0;
432 if (mm != null) 559 if (mm != null)
560 baseCost = mm.UploadCharge;
561
562 string warning = String.Empty;
563
564 if (llsdRequest.asset_type == "mesh")
433 { 565 {
434 if (!mm.UploadCovered(client.AgentId, mm.UploadCharge)) 566 string error;
567 int modelcost;
568
569 if (!m_ModelCost.MeshModelCost(llsdRequest.asset_resources, baseCost, out modelcost,
570 meshcostdata, out error, ref warning))
435 { 571 {
436 client.SendAgentAlertMessage("Unable to upload asset. Insufficient funds.", false); 572 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
573 resperror.message = error;
574 resperror.identifier = UUID.Zero;
437 575
438 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse(); 576 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
439 errorResponse.uploader = ""; 577 errorResponse.uploader = "";
440 errorResponse.state = "error"; 578 errorResponse.state = "error";
579 errorResponse.error = resperror;
580
581 lock (m_ModelCost)
582 m_FileAgentInventoryState = FileAgentInventoryState.idle;
441 return errorResponse; 583 return errorResponse;
442 } 584 }
585 cost = modelcost;
586 }
587 else
588 {
589 cost = baseCost;
590 }
591
592 if (cost > 0 && mm != null)
593 {
594 // check for test upload
595
596 if (m_ForceFreeTestUpload) // all are test
597 {
598 if (!(assetName.Length > 5 && assetName.StartsWith("TEST-"))) // has normal name lets change it
599 assetName = "TEST-" + assetName;
600
601 IsAtestUpload = true;
602 }
603
604 else if (m_enableFreeTestUpload) // only if prefixed with "TEST-"
605 {
606
607 IsAtestUpload = (assetName.Length > 5 && assetName.StartsWith("TEST-"));
608 }
609
610
611 if(IsAtestUpload) // let user know, still showing cost estimation
612 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";
613
614 // check funds
615 else
616 {
617 if (!mm.UploadCovered(client.AgentId, (int)cost))
618 {
619 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
620 resperror.message = "Insuficient funds";
621 resperror.identifier = UUID.Zero;
622
623 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
624 errorResponse.uploader = "";
625 errorResponse.state = "error";
626 errorResponse.error = resperror;
627 lock (m_ModelCost)
628 m_FileAgentInventoryState = FileAgentInventoryState.idle;
629 return errorResponse;
630 }
631 }
443 } 632 }
633
634 if (client != null && warning != String.Empty)
635 client.SendAgentAlertMessage(warning, true);
444 } 636 }
445 } 637 }
446 638
447 string assetName = llsdRequest.name;
448 string assetDes = llsdRequest.description; 639 string assetDes = llsdRequest.description;
449 string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath; 640 string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath;
450 UUID newAsset = UUID.Random(); 641 UUID newAsset = UUID.Random();
451 UUID newInvItem = UUID.Random(); 642 UUID newInvItem = UUID.Random();
452 UUID parentFolder = llsdRequest.folder_id; 643 UUID parentFolder = llsdRequest.folder_id;
453 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000"); 644 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000");
645 UUID texturesFolder = UUID.Zero;
646
647 if(!IsAtestUpload && m_enableModelUploadTextureToInventory)
648 texturesFolder = llsdRequest.texture_folder_id;
454 649
455 AssetUploader uploader = 650 AssetUploader uploader =
456 new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type, 651 new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type,
457 llsdRequest.asset_type, capsBase + uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile); 652 llsdRequest.asset_type, capsBase + uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile, cost,
653 texturesFolder, nreqtextures, nreqmeshs, nreqinstances, IsAtestUpload);
458 654
459 m_HostCapsObj.HttpListener.AddStreamHandler( 655 m_HostCapsObj.HttpListener.AddStreamHandler(
460 new BinaryStreamHandler( 656 new BinaryStreamHandler(
@@ -472,10 +668,22 @@ namespace OpenSim.Region.ClientStack.Linden
472 string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase + 668 string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase +
473 uploaderPath; 669 uploaderPath;
474 670
671
475 LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse(); 672 LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse();
476 uploadResponse.uploader = uploaderURL; 673 uploadResponse.uploader = uploaderURL;
477 uploadResponse.state = "upload"; 674 uploadResponse.state = "upload";
675 uploadResponse.upload_price = (int)cost;
676
677 if (llsdRequest.asset_type == "mesh")
678 {
679 uploadResponse.data = meshcostdata;
680 }
681
478 uploader.OnUpLoad += UploadCompleteHandler; 682 uploader.OnUpLoad += UploadCompleteHandler;
683
684 lock (m_ModelCost)
685 m_FileAgentInventoryState = FileAgentInventoryState.waitUpload;
686
479 return uploadResponse; 687 return uploadResponse;
480 } 688 }
481 689
@@ -487,8 +695,14 @@ namespace OpenSim.Region.ClientStack.Linden
487 /// <param name="data"></param> 695 /// <param name="data"></param>
488 public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID, 696 public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID,
489 UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType, 697 UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType,
490 string assetType) 698 string assetType, int cost,
699 UUID texturesFolder, int nreqtextures, int nreqmeshs, int nreqinstances,
700 bool IsAtestUpload, ref string error)
491 { 701 {
702
703 lock (m_ModelCost)
704 m_FileAgentInventoryState = FileAgentInventoryState.processUpload;
705
492 m_log.DebugFormat( 706 m_log.DebugFormat(
493 "[BUNCH OF CAPS]: Uploaded asset {0} for inventory item {1}, inv type {2}, asset type {3}", 707 "[BUNCH OF CAPS]: Uploaded asset {0} for inventory item {1}, inv type {2}, asset type {3}",
494 assetID, inventoryItem, inventoryType, assetType); 708 assetID, inventoryItem, inventoryType, assetType);
@@ -496,117 +710,247 @@ namespace OpenSim.Region.ClientStack.Linden
496 sbyte assType = 0; 710 sbyte assType = 0;
497 sbyte inType = 0; 711 sbyte inType = 0;
498 712
713 IClientAPI client = null;
714
715 UUID owner_id = m_HostCapsObj.AgentID;
716 UUID creatorID;
717
718 bool istest = IsAtestUpload && m_enableFreeTestUpload && (cost > 0);
719
720 bool restrictPerms = m_RestrictFreeTestUploadPerms && istest;
721
722 if (istest && m_testAssetsCreatorID != UUID.Zero)
723 creatorID = m_testAssetsCreatorID;
724 else
725 creatorID = owner_id;
726
727 string creatorIDstr = creatorID.ToString();
728
729 IMoneyModule mm = m_Scene.RequestModuleInterface<IMoneyModule>();
730 if (mm != null)
731 {
732 // make sure client still has enougth credit
733 if (!mm.UploadCovered(m_HostCapsObj.AgentID, (int)cost))
734 {
735 error = "Insufficient funds.";
736 return;
737 }
738 }
739
740 // strings to types
499 if (inventoryType == "sound") 741 if (inventoryType == "sound")
500 { 742 {
501 inType = 1; 743 inType = (sbyte)InventoryType.Sound;
502 assType = 1; 744 assType = (sbyte)AssetType.Sound;
503 } 745 }
504 else if (inventoryType == "animation") 746 else if (inventoryType == "animation")
505 { 747 {
506 inType = 19; 748 inType = (sbyte)InventoryType.Animation;
507 assType = 20; 749 assType = (sbyte)AssetType.Animation;
508 } 750 }
509 else if (inventoryType == "wearable") 751 else if (inventoryType == "wearable")
510 { 752 {
511 inType = 18; 753 inType = (sbyte)InventoryType.Wearable;
512 switch (assetType) 754 switch (assetType)
513 { 755 {
514 case "bodypart": 756 case "bodypart":
515 assType = 13; 757 assType = (sbyte)AssetType.Bodypart;
516 break; 758 break;
517 case "clothing": 759 case "clothing":
518 assType = 5; 760 assType = (sbyte)AssetType.Clothing;
519 break; 761 break;
520 } 762 }
521 } 763 }
522 else if (inventoryType == "object") 764 else if (inventoryType == "object")
523 { 765 {
524 inType = (sbyte)InventoryType.Object; 766 if (assetType == "mesh") // this code for now is for mesh models uploads only
525 assType = (sbyte)AssetType.Object;
526
527 List<Vector3> positions = new List<Vector3>();
528 List<Quaternion> rotations = new List<Quaternion>();
529 OSDMap request = (OSDMap)OSDParser.DeserializeLLSDXml(data);
530 OSDArray instance_list = (OSDArray)request["instance_list"];
531 OSDArray mesh_list = (OSDArray)request["mesh_list"];
532 OSDArray texture_list = (OSDArray)request["texture_list"];
533 SceneObjectGroup grp = null;
534
535 List<UUID> textures = new List<UUID>();
536 for (int i = 0; i < texture_list.Count; i++)
537 { 767 {
538 AssetBase textureAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Texture, ""); 768 inType = (sbyte)InventoryType.Object;
539 textureAsset.Data = texture_list[i].AsBinary(); 769 assType = (sbyte)AssetType.Object;
540 m_assetService.Store(textureAsset);
541 textures.Add(textureAsset.FullID);
542 }
543 770
544 for (int i = 0; i < mesh_list.Count; i++) 771 List<Vector3> positions = new List<Vector3>();
545 { 772 List<Quaternion> rotations = new List<Quaternion>();
546 PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateBox(); 773 OSDMap request = (OSDMap)OSDParser.DeserializeLLSDXml(data);
547 774
548 Primitive.TextureEntry textureEntry 775 // compare and get updated information
549 = new Primitive.TextureEntry(Primitive.TextureEntry.WHITE_TEXTURE);
550 OSDMap inner_instance_list = (OSDMap)instance_list[i];
551 776
552 OSDArray face_list = (OSDArray)inner_instance_list["face_list"]; 777 bool mismatchError = true;
553 for (uint face = 0; face < face_list.Count; face++) 778
779 while (mismatchError)
554 { 780 {
555 OSDMap faceMap = (OSDMap)face_list[(int)face]; 781 mismatchError = false;
556 Primitive.TextureEntryFace f = pbs.Textures.CreateFace(face); 782 }
557 if(faceMap.ContainsKey("fullbright"))
558 f.Fullbright = faceMap["fullbright"].AsBoolean();
559 if (faceMap.ContainsKey ("diffuse_color"))
560 f.RGBA = faceMap["diffuse_color"].AsColor4();
561 783
562 int textureNum = faceMap["image"].AsInteger(); 784 if (mismatchError)
563 float imagerot = faceMap["imagerot"].AsInteger(); 785 {
564 float offsets = (float)faceMap["offsets"].AsReal(); 786 error = "Upload and fee estimation information don't match";
565 float offsett = (float)faceMap["offsett"].AsReal(); 787 lock (m_ModelCost)
566 float scales = (float)faceMap["scales"].AsReal(); 788 m_FileAgentInventoryState = FileAgentInventoryState.idle;
567 float scalet = (float)faceMap["scalet"].AsReal();
568 789
569 if(imagerot != 0) 790 return;
570 f.Rotation = imagerot; 791 }
571 792
572 if(offsets != 0) 793 OSDArray instance_list = (OSDArray)request["instance_list"];
573 f.OffsetU = offsets; 794 OSDArray mesh_list = (OSDArray)request["mesh_list"];
795 OSDArray texture_list = (OSDArray)request["texture_list"];
796 SceneObjectGroup grp = null;
574 797
575 if (offsett != 0) 798 // create and store texture assets
576 f.OffsetV = offsett; 799 bool doTextInv = (!istest && m_enableModelUploadTextureToInventory &&
800 texturesFolder != UUID.Zero);
577 801
578 if (scales != 0)
579 f.RepeatU = scales;
580 802
581 if (scalet != 0) 803 List<UUID> textures = new List<UUID>();
582 f.RepeatV = scalet;
583 804
584 if (textures.Count > textureNum) 805
585 f.TextureID = textures[textureNum]; 806 if (doTextInv)
586 else 807 m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client);
587 f.TextureID = Primitive.TextureEntry.WHITE_TEXTURE;
588 808
589 textureEntry.FaceTextures[face] = f; 809 if(client == null) // don't put textures in inventory if there is no client
810 doTextInv = false;
811
812 for (int i = 0; i < texture_list.Count; i++)
813 {
814 AssetBase textureAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Texture, creatorIDstr);
815 textureAsset.Data = texture_list[i].AsBinary();
816 if (istest)
817 textureAsset.Local = true;
818 m_assetService.Store(textureAsset);
819 textures.Add(textureAsset.FullID);
820
821 if (doTextInv)
822 {
823 string name = assetName;
824 if (name.Length > 25)
825 name = name.Substring(0, 24);
826 name += "_Texture#" + i.ToString();
827 InventoryItemBase texitem = new InventoryItemBase();
828 texitem.Owner = m_HostCapsObj.AgentID;
829 texitem.CreatorId = creatorIDstr;
830 texitem.CreatorData = String.Empty;
831 texitem.ID = UUID.Random();
832 texitem.AssetID = textureAsset.FullID;
833 texitem.Description = "mesh model texture";
834 texitem.Name = name;
835 texitem.AssetType = (int)AssetType.Texture;
836 texitem.InvType = (int)InventoryType.Texture;
837 texitem.Folder = texturesFolder;
838
839 texitem.CurrentPermissions
840 = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer | PermissionMask.Export);
841
842 texitem.BasePermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export;
843 texitem.EveryOnePermissions = 0;
844 texitem.NextPermissions = (uint)PermissionMask.All;
845 texitem.CreationDate = Util.UnixTimeSinceEpoch();
846
847 m_Scene.AddInventoryItem(client, texitem);
848 texitem = null;
849 }
590 } 850 }
591 851
592 pbs.TextureEntry = textureEntry.GetBytes(); 852 // create and store meshs assets
853 List<UUID> meshAssets = new List<UUID>();
854 for (int i = 0; i < mesh_list.Count; i++)
855 {
856 AssetBase meshAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Mesh, creatorIDstr);
857 meshAsset.Data = mesh_list[i].AsBinary();
858 if (istest)
859 meshAsset.Local = true;
860 m_assetService.Store(meshAsset);
861 meshAssets.Add(meshAsset.FullID);
862 }
863
864 int skipedMeshs = 0;
865 // build prims from instances
866 for (int i = 0; i < instance_list.Count; i++)
867 {
868 OSDMap inner_instance_list = (OSDMap)instance_list[i];
869
870 // skip prims that are 2 small
871 Vector3 scale = inner_instance_list["scale"].AsVector3();
872
873 if (scale.X < m_PrimScaleMin || scale.Y < m_PrimScaleMin || scale.Z < m_PrimScaleMin)
874 {
875 skipedMeshs++;
876 continue;
877 }
878
879 PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateBox();
880
881 Primitive.TextureEntry textureEntry
882 = new Primitive.TextureEntry(Primitive.TextureEntry.WHITE_TEXTURE);
883
593 884
594 AssetBase meshAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Mesh, ""); 885 OSDArray face_list = (OSDArray)inner_instance_list["face_list"];
595 meshAsset.Data = mesh_list[i].AsBinary(); 886 for (uint face = 0; face < face_list.Count; face++)
596 m_assetService.Store(meshAsset); 887 {
888 OSDMap faceMap = (OSDMap)face_list[(int)face];
889 Primitive.TextureEntryFace f = pbs.Textures.CreateFace(face);
890 if (faceMap.ContainsKey("fullbright"))
891 f.Fullbright = faceMap["fullbright"].AsBoolean();
892 if (faceMap.ContainsKey("diffuse_color"))
893 f.RGBA = faceMap["diffuse_color"].AsColor4();
894
895 int textureNum = faceMap["image"].AsInteger();
896 float imagerot = faceMap["imagerot"].AsInteger();
897 float offsets = (float)faceMap["offsets"].AsReal();
898 float offsett = (float)faceMap["offsett"].AsReal();
899 float scales = (float)faceMap["scales"].AsReal();
900 float scalet = (float)faceMap["scalet"].AsReal();
901
902 if (imagerot != 0)
903 f.Rotation = imagerot;
904
905 if (offsets != 0)
906 f.OffsetU = offsets;
597 907
598 pbs.SculptEntry = true; 908 if (offsett != 0)
599 pbs.SculptTexture = meshAsset.FullID; 909 f.OffsetV = offsett;
600 pbs.SculptType = (byte)SculptType.Mesh;
601 pbs.SculptData = meshAsset.Data;
602 910
603 Vector3 position = inner_instance_list["position"].AsVector3(); 911 if (scales != 0)
604 Vector3 scale = inner_instance_list["scale"].AsVector3(); 912 f.RepeatU = scales;
605 Quaternion rotation = inner_instance_list["rotation"].AsQuaternion(); 913
914 if (scalet != 0)
915 f.RepeatV = scalet;
916
917 if (textures.Count > textureNum)
918 f.TextureID = textures[textureNum];
919 else
920 f.TextureID = Primitive.TextureEntry.WHITE_TEXTURE;
921
922 textureEntry.FaceTextures[face] = f;
923 }
924
925 pbs.TextureEntry = textureEntry.GetBytes();
926
927 bool hasmesh = false;
928 if (inner_instance_list.ContainsKey("mesh")) // seems to happen always but ...
929 {
930 int meshindx = inner_instance_list["mesh"].AsInteger();
931 if (meshAssets.Count > meshindx)
932 {
933 pbs.SculptEntry = true;
934 pbs.SculptType = (byte)SculptType.Mesh;
935 pbs.SculptTexture = meshAssets[meshindx]; // actual asset UUID after meshs suport introduction
936 // data will be requested from asset on rez (i hope)
937 hasmesh = true;
938 }
939 }
940
941 Vector3 position = inner_instance_list["position"].AsVector3();
942 Quaternion rotation = inner_instance_list["rotation"].AsQuaternion();
943
944 // for now viwers do send fixed defaults
945 // but this may change
946// int physicsShapeType = inner_instance_list["physics_shape_type"].AsInteger();
947 byte physicsShapeType = (byte)PhysShapeType.prim; // default for mesh is simple convex
948 if(hasmesh)
949 physicsShapeType = (byte) PhysShapeType.convex; // default for mesh is simple convex
950// int material = inner_instance_list["material"].AsInteger();
951 byte material = (byte)Material.Wood;
606 952
607// no longer used - begin ------------------------ 953// no longer used - begin ------------------------
608// int physicsShapeType = inner_instance_list["physics_shape_type"].AsInteger();
609// int material = inner_instance_list["material"].AsInteger();
610// int mesh = inner_instance_list["mesh"].AsInteger(); 954// int mesh = inner_instance_list["mesh"].AsInteger();
611 955
612// OSDMap permissions = (OSDMap)inner_instance_list["permissions"]; 956// OSDMap permissions = (OSDMap)inner_instance_list["permissions"];
@@ -621,24 +965,49 @@ namespace OpenSim.Region.ClientStack.Linden
621// UUID owner_id = permissions["owner_id"].AsUUID(); 965// UUID owner_id = permissions["owner_id"].AsUUID();
622// int owner_mask = permissions["owner_mask"].AsInteger(); 966// int owner_mask = permissions["owner_mask"].AsInteger();
623// no longer used - end ------------------------ 967// no longer used - end ------------------------
968
969
970 SceneObjectPart prim
971 = new SceneObjectPart(owner_id, pbs, position, Quaternion.Identity, Vector3.Zero);
972
973 prim.Scale = scale;
974 rotations.Add(rotation);
975 positions.Add(position);
976 prim.UUID = UUID.Random();
977 prim.CreatorID = creatorID;
978 prim.OwnerID = owner_id;
979 prim.GroupID = UUID.Zero;
980 prim.LastOwnerID = creatorID;
981 prim.CreationDate = Util.UnixTimeSinceEpoch();
982
983 if (grp == null)
984 prim.Name = assetName;
985 else
986 prim.Name = assetName + "#" + i.ToString();
624 987
625 UUID owner_id = m_HostCapsObj.AgentID; 988 prim.EveryoneMask = 0;
989 prim.GroupMask = 0;
626 990
627 SceneObjectPart prim 991 if (restrictPerms)
628 = new SceneObjectPart(owner_id, pbs, position, Quaternion.Identity, Vector3.Zero); 992 {
993 prim.BaseMask = (uint)(PermissionMask.Move | PermissionMask.Modify);
994 prim.OwnerMask = (uint)(PermissionMask.Move | PermissionMask.Modify);
995 prim.NextOwnerMask = 0;
996 }
997 else
998 {
999 prim.BaseMask = (uint)PermissionMask.All | (uint)PermissionMask.Export;
1000 prim.OwnerMask = (uint)PermissionMask.All | (uint)PermissionMask.Export;
1001 prim.NextOwnerMask = (uint)PermissionMask.Transfer;
1002 }
1003
1004 if(istest)
1005 prim.Description = "For testing only. Other uses are prohibited";
1006 else
1007 prim.Description = "";
629 1008
630 prim.Scale = scale; 1009 prim.Material = material;
631 //prim.OffsetPosition = position; 1010 prim.PhysicsShapeType = physicsShapeType;
632 rotations.Add(rotation);
633 positions.Add(position);
634 prim.UUID = UUID.Random();
635 prim.CreatorID = owner_id;
636 prim.OwnerID = owner_id;
637 prim.GroupID = UUID.Zero;
638 prim.LastOwnerID = prim.OwnerID;
639 prim.CreationDate = Util.UnixTimeSinceEpoch();
640 prim.Name = assetName;
641 prim.Description = "";
642 1011
643// prim.BaseMask = (uint)base_mask; 1012// prim.BaseMask = (uint)base_mask;
644// prim.EveryoneMask = (uint)everyone_mask; 1013// prim.EveryoneMask = (uint)everyone_mask;
@@ -646,52 +1015,64 @@ namespace OpenSim.Region.ClientStack.Linden
646// prim.NextOwnerMask = (uint)next_owner_mask; 1015// prim.NextOwnerMask = (uint)next_owner_mask;
647// prim.OwnerMask = (uint)owner_mask; 1016// prim.OwnerMask = (uint)owner_mask;
648 1017
649 if (grp == null) 1018 if (grp == null)
650 grp = new SceneObjectGroup(prim); 1019 {
651 else 1020 grp = new SceneObjectGroup(prim);
652 grp.AddPart(prim); 1021 grp.LastOwnerID = creatorID;
653 } 1022 }
1023 else
1024 grp.AddPart(prim);
1025 }
654 1026
655 Vector3 rootPos = positions[0]; 1027 Vector3 rootPos = positions[0];
656 1028
657 if (grp.Parts.Length > 1) 1029 if (grp.Parts.Length > 1)
658 { 1030 {
659 // Fix first link number 1031 // Fix first link number
660 grp.RootPart.LinkNum++; 1032 grp.RootPart.LinkNum++;
661 1033
662 Quaternion rootRotConj = Quaternion.Conjugate(rotations[0]); 1034 Quaternion rootRotConj = Quaternion.Conjugate(rotations[0]);
663 Quaternion tmprot; 1035 Quaternion tmprot;
664 Vector3 offset; 1036 Vector3 offset;
665 1037
666 // fix children rotations and positions 1038 // fix children rotations and positions
667 for (int i = 1; i < rotations.Count; i++) 1039 for (int i = 1; i < rotations.Count; i++)
668 { 1040 {
669 tmprot = rotations[i]; 1041 tmprot = rotations[i];
670 tmprot = rootRotConj * tmprot; 1042 tmprot = rootRotConj * tmprot;
1043
1044 grp.Parts[i].RotationOffset = tmprot;
671 1045
672 grp.Parts[i].RotationOffset = tmprot; 1046 offset = positions[i] - rootPos;
673 1047
674 offset = positions[i] - rootPos; 1048 offset *= rootRotConj;
1049 grp.Parts[i].OffsetPosition = offset;
1050 }
675 1051
676 offset *= rootRotConj; 1052 grp.AbsolutePosition = rootPos;
677 grp.Parts[i].OffsetPosition = offset; 1053 grp.UpdateGroupRotationR(rotations[0]);
1054 }
1055 else
1056 {
1057 grp.AbsolutePosition = rootPos;
1058 grp.UpdateGroupRotationR(rotations[0]);
678 } 1059 }
679 1060
680 grp.AbsolutePosition = rootPos; 1061 data = ASCIIEncoding.ASCII.GetBytes(SceneObjectSerializer.ToOriginalXmlFormat(grp));
681 grp.UpdateGroupRotationR(rotations[0]);
682 } 1062 }
683 else 1063
1064 else // not a mesh model
684 { 1065 {
685 grp.AbsolutePosition = rootPos; 1066 m_log.ErrorFormat("[CAPS Asset Upload] got unsuported assetType for object upload");
686 grp.UpdateGroupRotationR(rotations[0]); 1067 return;
687 } 1068 }
688
689 data = ASCIIEncoding.ASCII.GetBytes(SceneObjectSerializer.ToOriginalXmlFormat(grp));
690 } 1069 }
691 1070
692 AssetBase asset; 1071 AssetBase asset;
693 asset = new AssetBase(assetID, assetName, assType, m_HostCapsObj.AgentID.ToString()); 1072 asset = new AssetBase(assetID, assetName, assType, creatorIDstr);
694 asset.Data = data; 1073 asset.Data = data;
1074 if (istest)
1075 asset.Local = true;
695 if (AddNewAsset != null) 1076 if (AddNewAsset != null)
696 AddNewAsset(asset); 1077 AddNewAsset(asset);
697 else if (m_assetService != null) 1078 else if (m_assetService != null)
@@ -699,11 +1080,17 @@ namespace OpenSim.Region.ClientStack.Linden
699 1080
700 InventoryItemBase item = new InventoryItemBase(); 1081 InventoryItemBase item = new InventoryItemBase();
701 item.Owner = m_HostCapsObj.AgentID; 1082 item.Owner = m_HostCapsObj.AgentID;
702 item.CreatorId = m_HostCapsObj.AgentID.ToString(); 1083 item.CreatorId = creatorIDstr;
703 item.CreatorData = String.Empty; 1084 item.CreatorData = String.Empty;
704 item.ID = inventoryItem; 1085 item.ID = inventoryItem;
705 item.AssetID = asset.FullID; 1086 item.AssetID = asset.FullID;
706 item.Description = assetDescription; 1087 if (istest)
1088 {
1089 item.Description = "For testing only. Other uses are prohibited";
1090 item.Flags = (uint) (InventoryItemFlags.SharedSingleReference);
1091 }
1092 else
1093 item.Description = assetDescription;
707 item.Name = assetName; 1094 item.Name = assetName;
708 item.AssetType = assType; 1095 item.AssetType = assType;
709 item.InvType = inType; 1096 item.InvType = inType;
@@ -711,18 +1098,56 @@ namespace OpenSim.Region.ClientStack.Linden
711 1098
712 // If we set PermissionMask.All then when we rez the item the next permissions will replace the current 1099 // If we set PermissionMask.All then when we rez the item the next permissions will replace the current
713 // (owner) permissions. This becomes a problem if next permissions are changed. 1100 // (owner) permissions. This becomes a problem if next permissions are changed.
714 item.CurrentPermissions
715 = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer | PermissionMask.Export);
716 1101
717 item.BasePermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export; 1102 if (restrictPerms)
718 item.EveryOnePermissions = 0; 1103 {
719 item.NextPermissions = (uint)PermissionMask.All; 1104 item.BasePermissions = (uint)(PermissionMask.Move | PermissionMask.Modify);
1105 item.CurrentPermissions = (uint)(PermissionMask.Move | PermissionMask.Modify);
1106 item.EveryOnePermissions = 0;
1107 item.NextPermissions = 0;
1108 }
1109 else
1110 {
1111 item.BasePermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export;
1112 item.CurrentPermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export;
1113 item.EveryOnePermissions = 0;
1114 item.NextPermissions = (uint)PermissionMask.Transfer;
1115 }
1116
720 item.CreationDate = Util.UnixTimeSinceEpoch(); 1117 item.CreationDate = Util.UnixTimeSinceEpoch();
721 1118
1119 m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client);
1120
722 if (AddNewInventoryItem != null) 1121 if (AddNewInventoryItem != null)
723 { 1122 {
724 AddNewInventoryItem(m_HostCapsObj.AgentID, item); 1123 if (istest)
1124 {
1125 m_Scene.AddInventoryItem(client, item);
1126/*
1127 AddNewInventoryItem(m_HostCapsObj.AgentID, item, 0);
1128 if (client != null)
1129 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);
1130 */
1131 }
1132 else
1133 {
1134 AddNewInventoryItem(m_HostCapsObj.AgentID, item, (uint)cost);
1135// if (client != null)
1136// {
1137// // let users see anything.. i don't so far
1138// string str;
1139// if (cost > 0)
1140// // dont remember where is money unit name to put here
1141// str = "Upload complete. charged " + cost.ToString() + "$";
1142// else
1143// str = "Upload complete";
1144// client.SendAgentAlertMessage(str, true);
1145// }
1146 }
725 } 1147 }
1148
1149 lock (m_ModelCost)
1150 m_FileAgentInventoryState = FileAgentInventoryState.idle;
726 } 1151 }
727 1152
728 /// <summary> 1153 /// <summary>
@@ -915,6 +1340,120 @@ namespace OpenSim.Region.ClientStack.Linden
915 return response; 1340 return response;
916 } 1341 }
917 1342
1343 public string GetObjectCost(string request, string path,
1344 string param, IOSHttpRequest httpRequest,
1345 IOSHttpResponse httpResponse)
1346 {
1347 OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request);
1348 OSDMap resp = new OSDMap();
1349
1350 OSDArray object_ids = (OSDArray)req["object_ids"];
1351
1352 for (int i = 0; i < object_ids.Count; i++)
1353 {
1354 UUID uuid = object_ids[i].AsUUID();
1355
1356 SceneObjectPart part = m_Scene.GetSceneObjectPart(uuid);
1357
1358 if (part != null)
1359 {
1360 SceneObjectGroup grp = part.ParentGroup;
1361 if (grp != null)
1362 {
1363 float linksetCost;
1364 float linksetPhysCost;
1365 float partCost;
1366 float partPhysCost;
1367
1368 grp.GetResourcesCosts(part, out linksetCost, out linksetPhysCost, out partCost, out partPhysCost);
1369
1370 OSDMap object_data = new OSDMap();
1371 object_data["linked_set_resource_cost"] = linksetCost;
1372 object_data["resource_cost"] = partCost;
1373 object_data["physics_cost"] = partPhysCost;
1374 object_data["linked_set_physics_cost"] = linksetPhysCost;
1375
1376 resp[uuid.ToString()] = object_data;
1377 }
1378 }
1379 }
1380
1381 string response = OSDParser.SerializeLLSDXmlString(resp);
1382 return response;
1383 }
1384
1385 public string ResourceCostSelected(string request, string path,
1386 string param, IOSHttpRequest httpRequest,
1387 IOSHttpResponse httpResponse)
1388 {
1389 OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request);
1390 OSDMap resp = new OSDMap();
1391
1392
1393 float phys=0;
1394 float stream=0;
1395 float simul=0;
1396
1397 if (req.ContainsKey("selected_roots"))
1398 {
1399 OSDArray object_ids = (OSDArray)req["selected_roots"];
1400
1401 // should go by SOG suming costs for all parts
1402 // ll v3 works ok with several objects select we get the list and adds ok
1403 // FS calls per object so results are wrong guess fs bug
1404 for (int i = 0; i < object_ids.Count; i++)
1405 {
1406 UUID uuid = object_ids[i].AsUUID();
1407 float Physc;
1408 float simulc;
1409 float streamc;
1410
1411 SceneObjectGroup grp = m_Scene.GetGroupByPrim(uuid);
1412 if (grp != null)
1413 {
1414 grp.GetSelectedCosts(out Physc, out streamc, out simulc);
1415 phys += Physc;
1416 stream += streamc;
1417 simul += simulc;
1418 }
1419 }
1420 }
1421 else if (req.ContainsKey("selected_prims"))
1422 {
1423 OSDArray object_ids = (OSDArray)req["selected_prims"];
1424
1425 // don't see in use in any of the 2 viewers
1426 // guess it should be for edit linked but... nothing
1427 // should go to SOP per part
1428 for (int i = 0; i < object_ids.Count; i++)
1429 {
1430 UUID uuid = object_ids[i].AsUUID();
1431
1432 SceneObjectPart part = m_Scene.GetSceneObjectPart(uuid);
1433 if (part != null)
1434 {
1435 phys += part.PhysicsCost;
1436 stream += part.StreamingCost;
1437 simul += part.SimulationCost;
1438 }
1439 }
1440 }
1441
1442 if (simul != 0)
1443 {
1444 OSDMap object_data = new OSDMap();
1445
1446 object_data["physics"] = phys;
1447 object_data["streaming"] = stream;
1448 object_data["simulation"] = simul;
1449
1450 resp["selected"] = object_data;
1451 }
1452
1453 string response = OSDParser.SerializeLLSDXmlString(resp);
1454 return response;
1455 }
1456
918 public string UpdateAgentInformation(string request, string path, 1457 public string UpdateAgentInformation(string request, string path,
919 string param, IOSHttpRequest httpRequest, 1458 string param, IOSHttpRequest httpRequest,
920 IOSHttpResponse httpResponse) 1459 IOSHttpResponse httpResponse)
@@ -934,6 +1473,10 @@ namespace OpenSim.Region.ClientStack.Linden
934 1473
935 public class AssetUploader 1474 public class AssetUploader
936 { 1475 {
1476 private static readonly ILog m_log =
1477 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
1478
1479
937 public event UpLoadedAsset OnUpLoad; 1480 public event UpLoadedAsset OnUpLoad;
938 private UpLoadedAsset handlerUpLoad = null; 1481 private UpLoadedAsset handlerUpLoad = null;
939 1482
@@ -948,10 +1491,21 @@ namespace OpenSim.Region.ClientStack.Linden
948 1491
949 private string m_invType = String.Empty; 1492 private string m_invType = String.Empty;
950 private string m_assetType = String.Empty; 1493 private string m_assetType = String.Empty;
1494 private int m_cost;
1495 private string m_error = String.Empty;
1496
1497 private Timer m_timeoutTimer = new Timer();
1498 private UUID m_texturesFolder;
1499 private int m_nreqtextures;
1500 private int m_nreqmeshs;
1501 private int m_nreqinstances;
1502 private bool m_IsAtestUpload;
951 1503
952 public AssetUploader(string assetName, string description, UUID assetID, UUID inventoryItem, 1504 public AssetUploader(string assetName, string description, UUID assetID, UUID inventoryItem,
953 UUID parentFolderID, string invType, string assetType, string path, 1505 UUID parentFolderID, string invType, string assetType, string path,
954 IHttpServer httpServer, bool dumpAssetsToFile) 1506 IHttpServer httpServer, bool dumpAssetsToFile,
1507 int totalCost, UUID texturesFolder, int nreqtextures, int nreqmeshs, int nreqinstances,
1508 bool IsAtestUpload)
955 { 1509 {
956 m_assetName = assetName; 1510 m_assetName = assetName;
957 m_assetDes = description; 1511 m_assetDes = description;
@@ -963,6 +1517,18 @@ namespace OpenSim.Region.ClientStack.Linden
963 m_assetType = assetType; 1517 m_assetType = assetType;
964 m_invType = invType; 1518 m_invType = invType;
965 m_dumpAssetsToFile = dumpAssetsToFile; 1519 m_dumpAssetsToFile = dumpAssetsToFile;
1520 m_cost = totalCost;
1521
1522 m_texturesFolder = texturesFolder;
1523 m_nreqtextures = nreqtextures;
1524 m_nreqmeshs = nreqmeshs;
1525 m_nreqinstances = nreqinstances;
1526 m_IsAtestUpload = IsAtestUpload;
1527
1528 m_timeoutTimer.Elapsed += TimedOut;
1529 m_timeoutTimer.Interval = 120000;
1530 m_timeoutTimer.AutoReset = false;
1531 m_timeoutTimer.Start();
966 } 1532 }
967 1533
968 /// <summary> 1534 /// <summary>
@@ -977,12 +1543,14 @@ namespace OpenSim.Region.ClientStack.Linden
977 UUID inv = inventoryItemID; 1543 UUID inv = inventoryItemID;
978 string res = String.Empty; 1544 string res = String.Empty;
979 LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete(); 1545 LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete();
1546/*
980 uploadComplete.new_asset = newAssetID.ToString(); 1547 uploadComplete.new_asset = newAssetID.ToString();
981 uploadComplete.new_inventory_item = inv; 1548 uploadComplete.new_inventory_item = inv;
982 uploadComplete.state = "complete"; 1549 uploadComplete.state = "complete";
983 1550
984 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete); 1551 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
985 1552*/
1553 m_timeoutTimer.Stop();
986 httpListener.RemoveStreamHandler("POST", uploaderPath); 1554 httpListener.RemoveStreamHandler("POST", uploaderPath);
987 1555
988 // TODO: probably make this a better set of extensions here 1556 // TODO: probably make this a better set of extensions here
@@ -999,12 +1567,49 @@ namespace OpenSim.Region.ClientStack.Linden
999 handlerUpLoad = OnUpLoad; 1567 handlerUpLoad = OnUpLoad;
1000 if (handlerUpLoad != null) 1568 if (handlerUpLoad != null)
1001 { 1569 {
1002 handlerUpLoad(m_assetName, m_assetDes, newAssetID, inv, parentFolder, data, m_invType, m_assetType); 1570 handlerUpLoad(m_assetName, m_assetDes, newAssetID, inv, parentFolder, data, m_invType, m_assetType,
1571 m_cost, m_texturesFolder, m_nreqtextures, m_nreqmeshs, m_nreqinstances, m_IsAtestUpload, ref m_error);
1572 }
1573 if (m_IsAtestUpload)
1574 {
1575 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
1576 resperror.message = "Upload SUCESSEFULL for testing purposes only. Other uses are prohibited. Item will not work after 48 hours or on other regions";
1577 resperror.identifier = inv;
1578
1579 uploadComplete.error = resperror;
1580 uploadComplete.state = "Upload4Testing";
1003 } 1581 }
1582 else
1583 {
1584 if (m_error == String.Empty)
1585 {
1586 uploadComplete.new_asset = newAssetID.ToString();
1587 uploadComplete.new_inventory_item = inv;
1588 // if (m_texturesFolder != UUID.Zero)
1589 // uploadComplete.new_texture_folder_id = m_texturesFolder;
1590 uploadComplete.state = "complete";
1591 }
1592 else
1593 {
1594 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
1595 resperror.message = m_error;
1596 resperror.identifier = inv;
1004 1597
1598 uploadComplete.error = resperror;
1599 uploadComplete.state = "failed";
1600 }
1601 }
1602
1603 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
1005 return res; 1604 return res;
1006 } 1605 }
1007 1606
1607 private void TimedOut(object sender, ElapsedEventArgs args)
1608 {
1609 m_log.InfoFormat("[CAPS]: Removing URL and handler for timed out mesh upload");
1610 httpListener.RemoveStreamHandler("POST", uploaderPath);
1611 }
1612
1008 ///Left this in and commented in case there are unforseen issues 1613 ///Left this in and commented in case there are unforseen issues
1009 //private void SaveAssetToFile(string filename, byte[] data) 1614 //private void SaveAssetToFile(string filename, byte[] data)
1010 //{ 1615 //{
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 c28ba94..725bf06 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
@@ -451,8 +451,8 @@ namespace OpenSim.Region.ClientStack.Linden
451 responsedata["content_type"] = "text/plain"; 451 responsedata["content_type"] = "text/plain";
452 responsedata["keepalive"] = false; 452 responsedata["keepalive"] = false;
453 responsedata["reusecontext"] = false; 453 responsedata["reusecontext"] = false;
454 responsedata["str_response_string"] = "Upstream error: "; 454 responsedata["str_response_string"] = "<llsd></llsd>";
455 responsedata["error_status_text"] = "Upstream error:"; 455 responsedata["error_status_text"] = "<llsd></llsd>";
456 responsedata["http_protocol_version"] = "HTTP/1.0"; 456 responsedata["http_protocol_version"] = "HTTP/1.0";
457 return responsedata; 457 return responsedata;
458 } 458 }
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs
index dab727f..7dcf137 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs
@@ -151,6 +151,12 @@ namespace OpenSim.Region.ClientStack.Linden
151 ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint, 151 ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint,
152 uint locationID, uint flags, string capsURL, UUID agentID) 152 uint locationID, uint flags, string capsURL, UUID agentID)
153 { 153 {
154 // not sure why flags get overwritten here
155 if ((flags & (uint)TeleportFlags.IsFlying) != 0)
156 flags = (uint)TeleportFlags.ViaLocation | (uint)TeleportFlags.IsFlying;
157 else
158 flags = (uint)TeleportFlags.ViaLocation;
159
154 OSDMap info = new OSDMap(); 160 OSDMap info = new OSDMap();
155 info.Add("AgentID", OSD.FromUUID(agentID)); 161 info.Add("AgentID", OSD.FromUUID(agentID));
156 info.Add("LocationID", OSD.FromInteger(4)); // TODO what is this? 162 info.Add("LocationID", OSD.FromInteger(4)); // TODO what is this?
@@ -159,7 +165,8 @@ namespace OpenSim.Region.ClientStack.Linden
159 info.Add("SimAccess", OSD.FromInteger(simAccess)); 165 info.Add("SimAccess", OSD.FromInteger(simAccess));
160 info.Add("SimIP", OSD.FromBinary(regionExternalEndPoint.Address.GetAddressBytes())); 166 info.Add("SimIP", OSD.FromBinary(regionExternalEndPoint.Address.GetAddressBytes()));
161 info.Add("SimPort", OSD.FromInteger(regionExternalEndPoint.Port)); 167 info.Add("SimPort", OSD.FromInteger(regionExternalEndPoint.Port));
162 info.Add("TeleportFlags", OSD.FromULong(1L << 4)); // AgentManager.TeleportFlags.ViaLocation 168// info.Add("TeleportFlags", OSD.FromULong(1L << 4)); // AgentManager.TeleportFlags.ViaLocation
169 info.Add("TeleportFlags", OSD.FromUInteger(flags));
163 170
164 OSDArray infoArr = new OSDArray(); 171 OSDArray infoArr = new OSDArray();
165 infoArr.Add(info); 172 infoArr.Add(info);
@@ -398,7 +405,7 @@ namespace OpenSim.Region.ClientStack.Linden
398 public static OSD partPhysicsProperties(uint localID, byte physhapetype, 405 public static OSD partPhysicsProperties(uint localID, byte physhapetype,
399 float density, float friction, float bounce, float gravmod) 406 float density, float friction, float bounce, float gravmod)
400 { 407 {
401 408
402 OSDMap physinfo = new OSDMap(6); 409 OSDMap physinfo = new OSDMap(6);
403 physinfo["LocalID"] = localID; 410 physinfo["LocalID"] = localID;
404 physinfo["Density"] = density; 411 physinfo["Density"] = density;
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs
index 8e1f63a..7b15284 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(string uri, UUID pId, Scene scene) :
250 base(null, uri, 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(capUrl, 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 54cf285..c8e1e83 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,16 +50,37 @@ namespace OpenSim.Region.ClientStack.Linden
54 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GetTextureModule")] 50 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GetTextureModule")]
55 public class GetTextureModule : INonSharedRegionModule 51 public class GetTextureModule : INonSharedRegionModule
56 { 52 {
57// private static readonly ILog m_log = 53
58// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 54 struct aPollRequest
59 55 {
56 public PollServiceTextureEventArgs thepoll;
57 public UUID reqID;
58 public Hashtable request;
59 public bool send503;
60 }
61
62 public class aPollResponse
63 {
64 public Hashtable response;
65 public int bytes;
66 }
67
68
69 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
70
60 private Scene m_scene; 71 private Scene m_scene;
61 private IAssetService m_assetService;
62 72
63 private bool m_Enabled = false; 73 private static GetTextureHandler m_getTextureHandler;
74
75 private IAssetService m_assetService = null;
76
77 private Dictionary<UUID, string> m_capsDict = new Dictionary<UUID, string>();
78 private static Thread[] m_workerThreads = null;
79
80 private static OpenMetaverse.BlockingQueue<aPollRequest> m_queue =
81 new OpenMetaverse.BlockingQueue<aPollRequest>();
64 82
65 // TODO: Change this to a config option 83 private Dictionary<UUID,PollServiceTextureEventArgs> m_pollservices = new Dictionary<UUID,PollServiceTextureEventArgs>();
66 const string REDIRECT_URL = null;
67 84
68 private string m_URL; 85 private string m_URL;
69 86
@@ -71,40 +88,96 @@ namespace OpenSim.Region.ClientStack.Linden
71 88
72 public void Initialise(IConfigSource source) 89 public void Initialise(IConfigSource source)
73 { 90 {
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 } 91 }
83 92
84 public void AddRegion(Scene s) 93 public void AddRegion(Scene s)
85 { 94 {
86 if (!m_Enabled)
87 return;
88
89 m_scene = s; 95 m_scene = s;
96 m_assetService = s.AssetService;
90 } 97 }
91 98
92 public void RemoveRegion(Scene s) 99 public void RemoveRegion(Scene s)
93 { 100 {
94 if (!m_Enabled)
95 return;
96
97 m_scene.EventManager.OnRegisterCaps -= RegisterCaps; 101 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
102 m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps;
103 m_scene.EventManager.OnThrottleUpdate -= ThrottleUpdate;
98 m_scene = null; 104 m_scene = null;
99 } 105 }
100 106
101 public void RegionLoaded(Scene s) 107 public void RegionLoaded(Scene s)
102 { 108 {
103 if (!m_Enabled) 109 // We'll reuse the same handler for all requests.
104 return; 110 m_getTextureHandler = new GetTextureHandler(m_assetService);
105 111
106 m_assetService = m_scene.RequestModuleInterface<IAssetService>();
107 m_scene.EventManager.OnRegisterCaps += RegisterCaps; 112 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
113 m_scene.EventManager.OnDeregisterCaps += DeregisterCaps;
114 m_scene.EventManager.OnThrottleUpdate += ThrottleUpdate;
115
116 if (m_workerThreads == null)
117 {
118 m_workerThreads = new Thread[2];
119
120 for (uint i = 0; i < 2; i++)
121 {
122 m_workerThreads[i] = Watchdog.StartThread(DoTextureRequests,
123 String.Format("TextureWorkerThread{0}", i),
124 ThreadPriority.Normal,
125 false,
126 false,
127 null,
128 int.MaxValue);
129 }
130 }
131 }
132 private int ExtractImageThrottle(byte[] pthrottles)
133 {
134
135 byte[] adjData;
136 int pos = 0;
137
138 if (!BitConverter.IsLittleEndian)
139 {
140 byte[] newData = new byte[7 * 4];
141 Buffer.BlockCopy(pthrottles, 0, newData, 0, 7 * 4);
142
143 for (int i = 0; i < 7; i++)
144 Array.Reverse(newData, i * 4, 4);
145
146 adjData = newData;
147 }
148 else
149 {
150 adjData = pthrottles;
151 }
152
153 // 0.125f converts from bits to bytes
154 //int resend = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
155 //pos += 4;
156 // int land = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
157 //pos += 4;
158 // int wind = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
159 // pos += 4;
160 // int cloud = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
161 // pos += 4;
162 // int task = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
163 // pos += 4;
164 pos = pos + 20;
165 int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); //pos += 4;
166 //int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
167 return texture;
168 }
169
170 // 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.
171 public void ThrottleUpdate(ScenePresence p)
172 {
173 byte[] throttles = p.ControllingClient.GetThrottlesPacked(1);
174 UUID user = p.UUID;
175 int imagethrottle = ExtractImageThrottle(throttles);
176 PollServiceTextureEventArgs args;
177 if (m_pollservices.TryGetValue(user,out args))
178 {
179 args.UpdateThrottle(imagethrottle);
180 }
108 } 181 }
109 182
110 public void PostInitialise() 183 public void PostInitialise()
@@ -122,28 +195,284 @@ namespace OpenSim.Region.ClientStack.Linden
122 195
123 #endregion 196 #endregion
124 197
125 public void RegisterCaps(UUID agentID, Caps caps) 198 ~GetTextureModule()
126 { 199 {
127 UUID capID = UUID.Random(); 200 foreach (Thread t in m_workerThreads)
201 Watchdog.AbortThread(t.ManagedThreadId);
128 202
129 //caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture)); 203 }
130 if (m_URL == "localhost") 204
205 private class PollServiceTextureEventArgs : PollServiceEventArgs
206 {
207 private List<Hashtable> requests =
208 new List<Hashtable>();
209 private Dictionary<UUID, aPollResponse> responses =
210 new Dictionary<UUID, aPollResponse>();
211
212 private Scene m_scene;
213 private CapsDataThrottler m_throttler = new CapsDataThrottler(100000, 1400000,10000);
214 public PollServiceTextureEventArgs(UUID pId, Scene scene) :
215 base(null, "", null, null, null, pId, int.MaxValue)
131 { 216 {
132// m_log.DebugFormat("[GETTEXTURE]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName); 217 m_scene = scene;
133 caps.RegisterHandler( 218 // x is request id, y is userid
134 "GetTexture", 219 HasEvents = (x, y) =>
135 new GetTextureHandler("/CAPS/" + capID + "/", m_assetService, "GetTexture", agentID.ToString())); 220 {
221 lock (responses)
222 {
223 bool ret = m_throttler.hasEvents(x, responses);
224 m_throttler.ProcessTime();
225 return ret;
226
227 }
228 };
229 GetEvents = (x, y) =>
230 {
231 lock (responses)
232 {
233 try
234 {
235 return responses[x].response;
236 }
237 finally
238 {
239 responses.Remove(x);
240 }
241 }
242 };
243 // x is request id, y is request data hashtable
244 Request = (x, y) =>
245 {
246 aPollRequest reqinfo = new aPollRequest();
247 reqinfo.thepoll = this;
248 reqinfo.reqID = x;
249 reqinfo.request = y;
250 reqinfo.send503 = false;
251
252 lock (responses)
253 {
254 if (responses.Count > 0)
255 {
256 if (m_queue.Count >= 4)
257 {
258 // Never allow more than 4 fetches to wait
259 reqinfo.send503 = true;
260 }
261 }
262 }
263 m_queue.Enqueue(reqinfo);
264 };
265
266 // this should never happen except possible on shutdown
267 NoEvents = (x, y) =>
268 {
269/*
270 lock (requests)
271 {
272 Hashtable request = requests.Find(id => id["RequestID"].ToString() == x.ToString());
273 requests.Remove(request);
274 }
275*/
276 Hashtable response = new Hashtable();
277
278 response["int_response_code"] = 500;
279 response["str_response_string"] = "Script timeout";
280 response["content_type"] = "text/plain";
281 response["keepalive"] = false;
282 response["reusecontext"] = false;
283
284 return response;
285 };
136 } 286 }
287
288 public void Process(aPollRequest requestinfo)
289 {
290 Hashtable response;
291
292 UUID requestID = requestinfo.reqID;
293
294 if (requestinfo.send503)
295 {
296 response = new Hashtable();
297
298 response["int_response_code"] = 503;
299 response["str_response_string"] = "Throttled";
300 response["content_type"] = "text/plain";
301 response["keepalive"] = false;
302 response["reusecontext"] = false;
303
304 lock (responses)
305 responses[requestID] = new aPollResponse() {bytes = 0, response = response};
306
307 return;
308 }
309
310 // If the avatar is gone, don't bother to get the texture
311 if (m_scene.GetScenePresence(Id) == null)
312 {
313 response = new Hashtable();
314
315 response["int_response_code"] = 500;
316 response["str_response_string"] = "Script timeout";
317 response["content_type"] = "text/plain";
318 response["keepalive"] = false;
319 response["reusecontext"] = false;
320
321 lock (responses)
322 responses[requestID] = new aPollResponse() {bytes = 0, response = response};
323
324 return;
325 }
326
327 response = m_getTextureHandler.Handle(requestinfo.request);
328 lock (responses)
329 {
330 responses[requestID] = new aPollResponse()
331 {
332 bytes = (int) response["int_bytes"],
333 response = response
334 };
335
336 }
337 m_throttler.ProcessTime();
338 }
339
340 internal void UpdateThrottle(int pimagethrottle)
341 {
342 m_throttler.ThrottleBytes = pimagethrottle;
343 }
344 }
345
346 private void RegisterCaps(UUID agentID, Caps caps)
347 {
348 m_URL = "/CAPS/" + UUID.Random() + "/";
349
350 // Register this as a poll service
351 PollServiceTextureEventArgs args = new PollServiceTextureEventArgs(agentID, m_scene);
352
353 args.Type = PollServiceEventArgs.EventType.Texture;
354 MainServer.Instance.AddPollServiceHTTPHandler(m_URL, args);
355
356 string hostName = m_scene.RegionInfo.ExternalHostName;
357 uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port;
358 string protocol = "http";
359
360 if (MainServer.Instance.UseSSL)
361 {
362 hostName = MainServer.Instance.SSLCommonName;
363 port = MainServer.Instance.SSLPort;
364 protocol = "https";
365 }
366
367 IExternalCapsModule handler = m_scene.RequestModuleInterface<IExternalCapsModule>();
368 if (handler != null)
369 handler.RegisterExternalUserCapsHandler(agentID, caps, "GetTexture", m_URL);
137 else 370 else
371 caps.RegisterHandler("GetTexture", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, m_URL));
372 m_pollservices[agentID] = args;
373 m_capsDict[agentID] = m_URL;
374 }
375
376 private void DeregisterCaps(UUID agentID, Caps caps)
377 {
378 PollServiceTextureEventArgs args;
379
380 MainServer.Instance.RemoveHTTPHandler("", m_URL);
381 m_capsDict.Remove(agentID);
382
383 if (m_pollservices.TryGetValue(agentID, out args))
138 { 384 {
139// m_log.DebugFormat("[GETTEXTURE]: {0} in region {1}", m_URL, m_scene.RegionInfo.RegionName); 385 m_pollservices.Remove(agentID);
140 IExternalCapsModule handler = m_scene.RequestModuleInterface<IExternalCapsModule>();
141 if (handler != null)
142 handler.RegisterExternalUserCapsHandler(agentID,caps,"GetTexture",m_URL);
143 else
144 caps.RegisterHandler("GetTexture", m_URL);
145 } 386 }
146 } 387 }
147 388
389 private void DoTextureRequests()
390 {
391 while (true)
392 {
393 aPollRequest poolreq = m_queue.Dequeue();
394
395 poolreq.thepoll.Process(poolreq);
396 }
397 }
398 internal sealed class CapsDataThrottler
399 {
400
401 private volatile int currenttime = 0;
402 private volatile int lastTimeElapsed = 0;
403 private volatile int BytesSent = 0;
404 private int oversizedImages = 0;
405 public CapsDataThrottler(int pBytes, int max, int min)
406 {
407 ThrottleBytes = pBytes;
408 lastTimeElapsed = Util.EnvironmentTickCount();
409 }
410 public bool hasEvents(UUID key, Dictionary<UUID, GetTextureModule.aPollResponse> responses)
411 {
412 PassTime();
413 // Note, this is called IN LOCK
414 bool haskey = responses.ContainsKey(key);
415 if (!haskey)
416 {
417 return false;
418 }
419 GetTextureModule.aPollResponse response;
420 if (responses.TryGetValue(key, out response))
421 {
422 // This is any error response
423 if (response.bytes == 0)
424 return true;
425
426 // Normal
427 if (BytesSent + response.bytes <= ThrottleBytes)
428 {
429 BytesSent += response.bytes;
430 //TimeBasedAction timeBasedAction = new TimeBasedAction { byteRemoval = response.bytes, requestId = key, timeMS = currenttime + 1000, unlockyn = false };
431 //m_actions.Add(timeBasedAction);
432 return true;
433 }
434 // Big textures
435 else if (response.bytes > ThrottleBytes && oversizedImages <= ((ThrottleBytes % 50000) + 1))
436 {
437 Interlocked.Increment(ref oversizedImages);
438 BytesSent += response.bytes;
439 //TimeBasedAction timeBasedAction = new TimeBasedAction { byteRemoval = response.bytes, requestId = key, timeMS = currenttime + (((response.bytes % ThrottleBytes)+1)*1000) , unlockyn = false };
440 //m_actions.Add(timeBasedAction);
441 return true;
442 }
443 else
444 {
445 return false;
446 }
447 }
448
449 return haskey;
450 }
451
452 public void ProcessTime()
453 {
454 PassTime();
455 }
456
457 private void PassTime()
458 {
459 currenttime = Util.EnvironmentTickCount();
460 int timeElapsed = Util.EnvironmentTickCountSubtract(currenttime, lastTimeElapsed);
461 //processTimeBasedActions(responses);
462 if (Util.EnvironmentTickCountSubtract(currenttime, timeElapsed) >= 1000)
463 {
464 lastTimeElapsed = Util.EnvironmentTickCount();
465 BytesSent -= ThrottleBytes;
466 if (BytesSent < 0) BytesSent = 0;
467 if (BytesSent < ThrottleBytes)
468 {
469 oversizedImages = 0;
470 }
471 }
472 }
473 public int ThrottleBytes;
474 }
148 } 475 }
476
477
149} 478}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs
index 45d33cd..1b68603 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs
@@ -129,15 +129,15 @@ namespace OpenSim.Region.ClientStack.Linden
129// m_log.DebugFormat("[MESH UPLOAD FLAG MODULE]: MeshUploadFlag request"); 129// m_log.DebugFormat("[MESH UPLOAD FLAG MODULE]: MeshUploadFlag request");
130 130
131 OSDMap data = new OSDMap(); 131 OSDMap data = new OSDMap();
132 ScenePresence sp = m_scene.GetScenePresence(agentID); 132// ScenePresence sp = m_scene.GetScenePresence(m_agentID);
133 data["username"] = sp.Firstname + "." + sp.Lastname; 133// data["username"] = sp.Firstname + "." + sp.Lastname;
134 data["display_name_next_update"] = new OSDDate(DateTime.Now); 134// data["display_name_next_update"] = new OSDDate(DateTime.Now);
135 data["legacy_first_name"] = sp.Firstname; 135// data["legacy_first_name"] = sp.Firstname;
136 data["mesh_upload_status"] = "valid"; 136 data["mesh_upload_status"] = "valid";
137 data["display_name"] = sp.Firstname + " " + sp.Lastname; 137// data["display_name"] = sp.Firstname + " " + sp.Lastname;
138 data["legacy_last_name"] = sp.Lastname; 138// data["legacy_last_name"] = sp.Lastname;
139 data["id"] = agentID; 139// data["id"] = m_agentID;
140 data["is_display_name_default"] = true; 140// data["is_display_name_default"] = true;
141 141
142 //Send back data 142 //Send back data
143 Hashtable responsedata = new Hashtable(); 143 Hashtable responsedata = new Hashtable();
@@ -148,4 +148,4 @@ namespace OpenSim.Region.ClientStack.Linden
148 return responsedata; 148 return responsedata;
149 } 149 }
150 } 150 }
151} \ No newline at end of file 151}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs
deleted file mode 100644
index f69a0bb..0000000
--- a/OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs
+++ /dev/null
@@ -1,297 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Specialized;
31using System.Reflection;
32using System.IO;
33using System.Web;
34using Mono.Addins;
35using log4net;
36using Nini.Config;
37using OpenMetaverse;
38using OpenMetaverse.StructuredData;
39using OpenSim.Framework;
40using OpenSim.Framework.Servers;
41using OpenSim.Framework.Servers.HttpServer;
42using OpenSim.Region.Framework.Interfaces;
43using OpenSim.Region.Framework.Scenes;
44using OpenSim.Services.Interfaces;
45using Caps = OpenSim.Framework.Capabilities.Caps;
46using OpenSim.Framework.Capabilities;
47using PermissionMask = OpenSim.Framework.PermissionMask;
48
49namespace OpenSim.Region.ClientStack.Linden
50{
51 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "NewFileAgentInventoryVariablePriceModule")]
52 public class NewFileAgentInventoryVariablePriceModule : INonSharedRegionModule
53 {
54// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
55
56 private Scene m_scene;
57// private IAssetService m_assetService;
58 private bool m_dumpAssetsToFile = false;
59 private bool m_enabled = true;
60 private int m_levelUpload = 0;
61
62 #region Region Module interfaceBase Members
63
64
65 public Type ReplaceableInterface
66 {
67 get { return null; }
68 }
69
70 public void Initialise(IConfigSource source)
71 {
72 IConfig meshConfig = source.Configs["Mesh"];
73 if (meshConfig == null)
74 return;
75
76 m_enabled = meshConfig.GetBoolean("AllowMeshUpload", true);
77 m_levelUpload = meshConfig.GetInt("LevelUpload", 0);
78 }
79
80 public void AddRegion(Scene pScene)
81 {
82 m_scene = pScene;
83 }
84
85 public void RemoveRegion(Scene scene)
86 {
87
88 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
89 m_scene = null;
90 }
91
92 public void RegionLoaded(Scene scene)
93 {
94
95// m_assetService = m_scene.RequestModuleInterface<IAssetService>();
96 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
97 }
98
99 #endregion
100
101
102 #region Region Module interface
103
104
105
106 public void Close() { }
107
108 public string Name { get { return "NewFileAgentInventoryVariablePriceModule"; } }
109
110
111 public void RegisterCaps(UUID agentID, Caps caps)
112 {
113 if(!m_enabled)
114 return;
115
116 UUID capID = UUID.Random();
117
118// m_log.Debug("[NEW FILE AGENT INVENTORY VARIABLE PRICE]: /CAPS/" + capID);
119 caps.RegisterHandler(
120 "NewFileAgentInventoryVariablePrice",
121 new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDNewFileAngentInventoryVariablePriceReplyResponse>(
122 "POST",
123 "/CAPS/" + capID.ToString(),
124 req => NewAgentInventoryRequest(req, agentID),
125 "NewFileAgentInventoryVariablePrice",
126 agentID.ToString()));
127 }
128
129 #endregion
130
131 public LLSDNewFileAngentInventoryVariablePriceReplyResponse NewAgentInventoryRequest(LLSDAssetUploadRequest llsdRequest, UUID agentID)
132 {
133 //TODO: The Mesh uploader uploads many types of content. If you're going to implement a Money based limit
134 // you need to be aware of this
135
136 //if (llsdRequest.asset_type == "texture" ||
137 // llsdRequest.asset_type == "animation" ||
138 // llsdRequest.asset_type == "sound")
139 // {
140 // check user level
141
142 ScenePresence avatar = null;
143 IClientAPI client = null;
144 m_scene.TryGetScenePresence(agentID, out avatar);
145
146 if (avatar != null)
147 {
148 client = avatar.ControllingClient;
149
150 if (avatar.UserLevel < m_levelUpload)
151 {
152 if (client != null)
153 client.SendAgentAlertMessage("Unable to upload asset. Insufficient permissions.", false);
154
155 LLSDNewFileAngentInventoryVariablePriceReplyResponse errorResponse = new LLSDNewFileAngentInventoryVariablePriceReplyResponse();
156 errorResponse.rsvp = "";
157 errorResponse.state = "error";
158 return errorResponse;
159 }
160 }
161
162 // check funds
163 IMoneyModule mm = m_scene.RequestModuleInterface<IMoneyModule>();
164
165 if (mm != null)
166 {
167 if (!mm.UploadCovered(agentID, mm.UploadCharge))
168 {
169 if (client != null)
170 client.SendAgentAlertMessage("Unable to upload asset. Insufficient funds.", false);
171
172 LLSDNewFileAngentInventoryVariablePriceReplyResponse errorResponse = new LLSDNewFileAngentInventoryVariablePriceReplyResponse();
173 errorResponse.rsvp = "";
174 errorResponse.state = "error";
175 return errorResponse;
176 }
177 }
178
179 // }
180
181 string assetName = llsdRequest.name;
182 string assetDes = llsdRequest.description;
183 string capsBase = "/CAPS/NewFileAgentInventoryVariablePrice/";
184 UUID newAsset = UUID.Random();
185 UUID newInvItem = UUID.Random();
186 UUID parentFolder = llsdRequest.folder_id;
187 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000") + "/";
188
189 AssetUploader uploader =
190 new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type,
191 llsdRequest.asset_type, capsBase + uploaderPath, MainServer.Instance, m_dumpAssetsToFile);
192
193 MainServer.Instance.AddStreamHandler(
194 new BinaryStreamHandler(
195 "POST",
196 capsBase + uploaderPath,
197 uploader.uploaderCaps,
198 "NewFileAgentInventoryVariablePrice",
199 agentID.ToString()));
200
201 string protocol = "http://";
202
203 if (MainServer.Instance.UseSSL)
204 protocol = "https://";
205
206 string uploaderURL = protocol + m_scene.RegionInfo.ExternalHostName + ":" + MainServer.Instance.Port.ToString() + capsBase +
207 uploaderPath;
208
209
210 LLSDNewFileAngentInventoryVariablePriceReplyResponse uploadResponse = new LLSDNewFileAngentInventoryVariablePriceReplyResponse();
211
212 uploadResponse.rsvp = uploaderURL;
213 uploadResponse.state = "upload";
214 uploadResponse.resource_cost = 0;
215 uploadResponse.upload_price = 0;
216
217 uploader.OnUpLoad += //UploadCompleteHandler;
218
219 delegate(
220 string passetName, string passetDescription, UUID passetID,
221 UUID pinventoryItem, UUID pparentFolder, byte[] pdata, string pinventoryType,
222 string passetType)
223 {
224 UploadCompleteHandler(passetName, passetDescription, passetID,
225 pinventoryItem, pparentFolder, pdata, pinventoryType,
226 passetType,agentID);
227 };
228
229 return uploadResponse;
230 }
231
232 public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID,
233 UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType,
234 string assetType,UUID AgentID)
235 {
236// m_log.DebugFormat(
237// "[NEW FILE AGENT INVENTORY VARIABLE PRICE MODULE]: Upload complete for {0}", inventoryItem);
238
239 sbyte assType = 0;
240 sbyte inType = 0;
241
242 if (inventoryType == "sound")
243 {
244 inType = 1;
245 assType = 1;
246 }
247 else if (inventoryType == "animation")
248 {
249 inType = 19;
250 assType = 20;
251 }
252 else if (inventoryType == "wearable")
253 {
254 inType = 18;
255 switch (assetType)
256 {
257 case "bodypart":
258 assType = 13;
259 break;
260 case "clothing":
261 assType = 5;
262 break;
263 }
264 }
265 else if (inventoryType == "mesh")
266 {
267 inType = (sbyte)InventoryType.Mesh;
268 assType = (sbyte)AssetType.Mesh;
269 }
270
271 AssetBase asset;
272 asset = new AssetBase(assetID, assetName, assType, AgentID.ToString());
273 asset.Data = data;
274
275 if (m_scene.AssetService != null)
276 m_scene.AssetService.Store(asset);
277
278 InventoryItemBase item = new InventoryItemBase();
279 item.Owner = AgentID;
280 item.CreatorId = AgentID.ToString();
281 item.ID = inventoryItem;
282 item.AssetID = asset.FullID;
283 item.Description = assetDescription;
284 item.Name = assetName;
285 item.AssetType = assType;
286 item.InvType = inType;
287 item.Folder = parentFolder;
288 item.CurrentPermissions
289 = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer);
290 item.BasePermissions = (uint)PermissionMask.All;
291 item.EveryOnePermissions = 0;
292 item.NextPermissions = (uint)PermissionMask.All;
293 item.CreationDate = Util.UnixTimeSinceEpoch();
294 m_scene.AddInventoryItem(item);
295 }
296 }
297}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs
index a133a69..5196368 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs
@@ -64,6 +64,8 @@ namespace OpenSim.Region.ClientStack.Linden
64 private Commands m_commands = new Commands(); 64 private Commands m_commands = new Commands();
65 public ICommands Commands { get { return m_commands; } } 65 public ICommands Commands { get { return m_commands; } }
66 66
67 public event ConsoleMessage OnConsoleMessage;
68
67 public void Initialise(IConfigSource source) 69 public void Initialise(IConfigSource source)
68 { 70 {
69 m_commands.AddCommand( "Help", false, "help", "help [<item>]", "Display help on a particular command or on a list of commands in a category", Help); 71 m_commands.AddCommand( "Help", false, "help", "help [<item>]", "Display help on a particular command or on a list of commands in a category", Help);
@@ -102,7 +104,7 @@ namespace OpenSim.Region.ClientStack.Linden
102 104
103 public void RegisterCaps(UUID agentID, Caps caps) 105 public void RegisterCaps(UUID agentID, Caps caps)
104 { 106 {
105 if (!m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(agentID)) 107 if (!m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(agentID) && !m_scene.Permissions.IsGod(agentID))
106 return; 108 return;
107 109
108 UUID capID = UUID.Random(); 110 UUID capID = UUID.Random();
@@ -118,6 +120,11 @@ namespace OpenSim.Region.ClientStack.Linden
118 OSD osd = OSD.FromString(message); 120 OSD osd = OSD.FromString(message);
119 121
120 m_eventQueue.Enqueue(EventQueueHelper.BuildEvent("SimConsoleResponse", osd), agentID); 122 m_eventQueue.Enqueue(EventQueueHelper.BuildEvent("SimConsoleResponse", osd), agentID);
123
124 ConsoleMessage handlerConsoleMessage = OnConsoleMessage;
125
126 if (handlerConsoleMessage != null)
127 handlerConsoleMessage( agentID, message);
121 } 128 }
122 129
123 public bool RunCommand(string command, UUID invokerID) 130 public bool RunCommand(string command, UUID invokerID)
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs
index 79a935d..cf95463 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs
@@ -27,6 +27,7 @@
27 27
28using System; 28using System;
29using System.Collections; 29using System.Collections;
30using System.Collections.Generic;
30using System.Collections.Specialized; 31using System.Collections.Specialized;
31using System.Drawing; 32using System.Drawing;
32using System.Drawing.Imaging; 33using System.Drawing.Imaging;
@@ -53,8 +54,8 @@ namespace OpenSim.Region.ClientStack.Linden
53 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "UploadBakedTextureModule")] 54 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "UploadBakedTextureModule")]
54 public class UploadBakedTextureModule : INonSharedRegionModule 55 public class UploadBakedTextureModule : INonSharedRegionModule
55 { 56 {
56// private static readonly ILog m_log = 57 private static readonly ILog m_log =
57// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 58 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
58 59
59 /// <summary> 60 /// <summary>
60 /// For historical reasons this is fixed, but there 61 /// For historical reasons this is fixed, but there
@@ -65,6 +66,8 @@ namespace OpenSim.Region.ClientStack.Linden
65 private bool m_persistBakedTextures; 66 private bool m_persistBakedTextures;
66 private string m_URL; 67 private string m_URL;
67 68
69 private IBakedTextureModule m_BakedTextureModule;
70
68 public void Initialise(IConfigSource source) 71 public void Initialise(IConfigSource source)
69 { 72 {
70 IConfig config = source.Configs["ClientStack.LindenCaps"]; 73 IConfig config = source.Configs["ClientStack.LindenCaps"];
@@ -76,26 +79,203 @@ namespace OpenSim.Region.ClientStack.Linden
76 IConfig appearanceConfig = source.Configs["Appearance"]; 79 IConfig appearanceConfig = source.Configs["Appearance"];
77 if (appearanceConfig != null) 80 if (appearanceConfig != null)
78 m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures); 81 m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures);
82
83
79 } 84 }
80 85
81 public void AddRegion(Scene s) 86 public void AddRegion(Scene s)
82 { 87 {
83 m_scene = s; 88 m_scene = s;
89
84 } 90 }
85 91
86 public void RemoveRegion(Scene s) 92 public void RemoveRegion(Scene s)
87 { 93 {
94 s.EventManager.OnRegisterCaps -= RegisterCaps;
95 s.EventManager.OnNewPresence -= RegisterNewPresence;
96 s.EventManager.OnRemovePresence -= DeRegisterPresence;
97 m_BakedTextureModule = null;
98 m_scene = null;
88 } 99 }
89 100
101
102
90 public void RegionLoaded(Scene s) 103 public void RegionLoaded(Scene s)
91 { 104 {
92 m_scene.EventManager.OnRegisterCaps += RegisterCaps; 105 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
106 m_scene.EventManager.OnNewPresence += RegisterNewPresence;
107 m_scene.EventManager.OnRemovePresence += DeRegisterPresence;
108
109 }
110
111 private void DeRegisterPresence(UUID agentId)
112 {
113 ScenePresence presence = null;
114 if (m_scene.TryGetScenePresence(agentId, out presence))
115 {
116 presence.ControllingClient.OnSetAppearance -= CaptureAppearanceSettings;
117 }
118
119 }
120
121 private void RegisterNewPresence(ScenePresence presence)
122 {
123 presence.ControllingClient.OnSetAppearance += CaptureAppearanceSettings;
124
125 }
126
127 private void CaptureAppearanceSettings(IClientAPI remoteClient, Primitive.TextureEntry textureEntry, byte[] visualParams, Vector3 avSize, WearableCacheItem[] cacheItems)
128 {
129 int maxCacheitemsLoop = cacheItems.Length;
130 if (maxCacheitemsLoop > AvatarWearable.MAX_WEARABLES)
131 {
132 maxCacheitemsLoop = AvatarWearable.MAX_WEARABLES;
133 m_log.WarnFormat("[CACHEDBAKES]: Too Many Cache items Provided {0}, the max is {1}. Truncating!", cacheItems.Length, AvatarWearable.MAX_WEARABLES);
134 }
135
136 m_BakedTextureModule = m_scene.RequestModuleInterface<IBakedTextureModule>();
137 if (cacheItems.Length > 0)
138 {
139 m_log.Debug("[Cacheitems]: " + cacheItems.Length);
140 for (int iter = 0; iter < maxCacheitemsLoop; iter++)
141 {
142 m_log.Debug("[Cacheitems] {" + iter + "/" + cacheItems[iter].TextureIndex + "}: c-" + cacheItems[iter].CacheId + ", t-" +
143 cacheItems[iter].TextureID);
144 }
145
146 ScenePresence p = null;
147 if (m_scene.TryGetScenePresence(remoteClient.AgentId, out p))
148 {
149
150 WearableCacheItem[] existingitems = p.Appearance.WearableCacheItems;
151 if (existingitems == null)
152 {
153 if (m_BakedTextureModule != null)
154 {
155 WearableCacheItem[] savedcache = null;
156 try
157 {
158 if (p.Appearance.WearableCacheItemsDirty)
159 {
160 savedcache = m_BakedTextureModule.Get(p.UUID);
161 p.Appearance.WearableCacheItems = savedcache;
162 p.Appearance.WearableCacheItemsDirty = false;
163 }
164
165 }
166 /*
167 * The following Catch types DO NOT WORK with m_BakedTextureModule.Get
168 * it jumps to the General Packet Exception Handler if you don't catch Exception!
169 *
170 catch (System.Net.Sockets.SocketException)
171 {
172 cacheItems = null;
173 }
174 catch (WebException)
175 {
176 cacheItems = null;
177 }
178 catch (InvalidOperationException)
179 {
180 cacheItems = null;
181 } */
182 catch (Exception)
183 {
184 // The service logs a sufficient error message.
185 }
186
187
188 if (savedcache != null)
189 existingitems = savedcache;
190 }
191 }
192 // Existing items null means it's a fully new appearance
193 if (existingitems == null)
194 {
195
196 for (int i = 0; i < maxCacheitemsLoop; i++)
197 {
198 if (textureEntry.FaceTextures.Length > cacheItems[i].TextureIndex)
199 {
200 Primitive.TextureEntryFace face = textureEntry.FaceTextures[cacheItems[i].TextureIndex];
201 if (face == null)
202 {
203 textureEntry.CreateFace(cacheItems[i].TextureIndex);
204 textureEntry.FaceTextures[cacheItems[i].TextureIndex].TextureID =
205 AppearanceManager.DEFAULT_AVATAR_TEXTURE;
206 continue;
207 }
208 cacheItems[i].TextureID =face.TextureID;
209 if (m_scene.AssetService != null)
210 cacheItems[i].TextureAsset =
211 m_scene.AssetService.GetCached(cacheItems[i].TextureID.ToString());
212 }
213 else
214 {
215 m_log.WarnFormat("[CACHEDBAKES]: Invalid Texture Index Provided, Texture doesn't exist or hasn't been uploaded yet {0}, the max is {1}. Skipping!", cacheItems[i].TextureIndex, textureEntry.FaceTextures.Length);
216 }
217
218
219 }
220 }
221 else
222
223
224 {
225 // for each uploaded baked texture
226 for (int i = 0; i < maxCacheitemsLoop; i++)
227 {
228 if (textureEntry.FaceTextures.Length > cacheItems[i].TextureIndex)
229 {
230 Primitive.TextureEntryFace face = textureEntry.FaceTextures[cacheItems[i].TextureIndex];
231 if (face == null)
232 {
233 textureEntry.CreateFace(cacheItems[i].TextureIndex);
234 textureEntry.FaceTextures[cacheItems[i].TextureIndex].TextureID =
235 AppearanceManager.DEFAULT_AVATAR_TEXTURE;
236 continue;
237 }
238 cacheItems[i].TextureID =
239 face.TextureID;
240 }
241 else
242 {
243 m_log.WarnFormat("[CACHEDBAKES]: Invalid Texture Index Provided, Texture doesn't exist or hasn't been uploaded yet {0}, the max is {1}. Skipping!", cacheItems[i].TextureIndex, textureEntry.FaceTextures.Length);
244 }
245 }
246
247 for (int i = 0; i < maxCacheitemsLoop; i++)
248 {
249 if (cacheItems[i].TextureAsset == null)
250 {
251 cacheItems[i].TextureAsset =
252 m_scene.AssetService.GetCached(cacheItems[i].TextureID.ToString());
253 }
254 }
255 }
256
257
258
259 p.Appearance.WearableCacheItems = cacheItems;
260
261
262
263 if (m_BakedTextureModule != null)
264 {
265 m_BakedTextureModule.Store(remoteClient.AgentId, cacheItems);
266 p.Appearance.WearableCacheItemsDirty = true;
267
268 }
269 }
270 }
93 } 271 }
94 272
95 public void PostInitialise() 273 public void PostInitialise()
96 { 274 {
97 } 275 }
98 276
277
278
99 public void Close() { } 279 public void Close() { }
100 280
101 public string Name { get { return "UploadBakedTextureModule"; } } 281 public string Name { get { return "UploadBakedTextureModule"; } }
@@ -112,13 +292,15 @@ namespace OpenSim.Region.ClientStack.Linden
112 //caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture)); 292 //caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture));
113 if (m_URL == "localhost") 293 if (m_URL == "localhost")
114 { 294 {
295 UploadBakedTextureHandler avatarhandler = new UploadBakedTextureHandler(
296 caps, m_scene.AssetService, m_persistBakedTextures);
297
115 caps.RegisterHandler( 298 caps.RegisterHandler(
116 "UploadBakedTexture", 299 "UploadBakedTexture",
117 new RestStreamHandler( 300 new RestStreamHandler(
118 "POST", 301 "POST",
119 "/CAPS/" + caps.CapsObjectPath + m_uploadBakedTexturePath, 302 "/CAPS/" + caps.CapsObjectPath + m_uploadBakedTexturePath,
120 new UploadBakedTextureHandler( 303 avatarhandler.UploadBakedTexture,
121 caps, m_scene.AssetService, m_persistBakedTextures).UploadBakedTexture,
122 "UploadBakedTexture", 304 "UploadBakedTexture",
123 agentID.ToString())); 305 agentID.ToString()));
124 306
@@ -127,7 +309,6 @@ namespace OpenSim.Region.ClientStack.Linden
127 { 309 {
128 caps.RegisterHandler("UploadBakedTexture", m_URL); 310 caps.RegisterHandler("UploadBakedTexture", m_URL);
129 } 311 }
130
131 } 312 }
132 } 313 }
133} \ No newline at end of file 314}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs
index 164adeb..f816ad3 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs
@@ -34,9 +34,7 @@ using log4net;
34using Nini.Config; 34using Nini.Config;
35using Mono.Addins; 35using Mono.Addins;
36using OpenMetaverse; 36using OpenMetaverse;
37using OpenMetaverse.StructuredData;
38using OpenSim.Framework; 37using OpenSim.Framework;
39using OpenSim.Framework.Monitoring;
40using OpenSim.Framework.Servers; 38using OpenSim.Framework.Servers;
41using OpenSim.Framework.Servers.HttpServer; 39using OpenSim.Framework.Servers.HttpServer;
42using OpenSim.Region.Framework.Interfaces; 40using OpenSim.Region.Framework.Interfaces;
@@ -45,6 +43,9 @@ using OpenSim.Framework.Capabilities;
45using OpenSim.Services.Interfaces; 43using OpenSim.Services.Interfaces;
46using Caps = OpenSim.Framework.Capabilities.Caps; 44using Caps = OpenSim.Framework.Capabilities.Caps;
47using OpenSim.Capabilities.Handlers; 45using OpenSim.Capabilities.Handlers;
46using OpenSim.Framework.Monitoring;
47using OpenMetaverse;
48using OpenMetaverse.StructuredData;
48 49
49namespace OpenSim.Region.ClientStack.Linden 50namespace OpenSim.Region.ClientStack.Linden
50{ 51{
@@ -63,7 +64,7 @@ namespace OpenSim.Region.ClientStack.Linden
63 public List<UUID> folders; 64 public List<UUID> folders;
64 } 65 }
65 66
66// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 67 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
67 68
68 private Scene m_scene; 69 private Scene m_scene;
69 70
@@ -248,7 +249,8 @@ namespace OpenSim.Region.ClientStack.Linden
248 { 249 {
249 if (!reqinfo.folders.Contains(folderID)) 250 if (!reqinfo.folders.Contains(folderID))
250 { 251 {
251 //TODO: Port COF handling from Avination 252 if (sp.COF != UUID.Zero && sp.COF == folderID)
253 highPriority = true;
252 reqinfo.folders.Add(folderID); 254 reqinfo.folders.Add(folderID);
253 } 255 }
254 } 256 }
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs b/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs
index 4d0568d..15d6f7f 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs
@@ -234,6 +234,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
234 m_stopPacket = TexturePacketCount(); 234 m_stopPacket = TexturePacketCount();
235 } 235 }
236 236
237 //Give them at least two packets, to play nice with some broken viewers (SL also behaves this way)
238 if (m_stopPacket == 1 && m_layers[0].End > FIRST_PACKET_SIZE) m_stopPacket++;
239
237 m_currentPacket = StartPacket; 240 m_currentPacket = StartPacket;
238 } 241 }
239 } 242 }
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
index f0d8181..8cbbfd9 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
@@ -102,6 +102,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
102 public event AvatarPickerRequest OnAvatarPickerRequest; 102 public event AvatarPickerRequest OnAvatarPickerRequest;
103 public event StartAnim OnStartAnim; 103 public event StartAnim OnStartAnim;
104 public event StopAnim OnStopAnim; 104 public event StopAnim OnStopAnim;
105 public event ChangeAnim OnChangeAnim;
105 public event Action<IClientAPI> OnRequestAvatarsData; 106 public event Action<IClientAPI> OnRequestAvatarsData;
106 public event LinkObjects OnLinkObjects; 107 public event LinkObjects OnLinkObjects;
107 public event DelinkObjects OnDelinkObjects; 108 public event DelinkObjects OnDelinkObjects;
@@ -129,6 +130,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
129 public event RequestObjectPropertiesFamily OnRequestObjectPropertiesFamily; 130 public event RequestObjectPropertiesFamily OnRequestObjectPropertiesFamily;
130 public event UpdatePrimFlags OnUpdatePrimFlags; 131 public event UpdatePrimFlags OnUpdatePrimFlags;
131 public event UpdatePrimTexture OnUpdatePrimTexture; 132 public event UpdatePrimTexture OnUpdatePrimTexture;
133 public event ClientChangeObject onClientChangeObject;
132 public event UpdateVector OnUpdatePrimGroupPosition; 134 public event UpdateVector OnUpdatePrimGroupPosition;
133 public event UpdateVector OnUpdatePrimSinglePosition; 135 public event UpdateVector OnUpdatePrimSinglePosition;
134 public event UpdatePrimRotation OnUpdatePrimGroupRotation; 136 public event UpdatePrimRotation OnUpdatePrimGroupRotation;
@@ -162,6 +164,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
162 public event RequestTaskInventory OnRequestTaskInventory; 164 public event RequestTaskInventory OnRequestTaskInventory;
163 public event UpdateInventoryItem OnUpdateInventoryItem; 165 public event UpdateInventoryItem OnUpdateInventoryItem;
164 public event CopyInventoryItem OnCopyInventoryItem; 166 public event CopyInventoryItem OnCopyInventoryItem;
167 public event MoveItemsAndLeaveCopy OnMoveItemsAndLeaveCopy;
165 public event MoveInventoryItem OnMoveInventoryItem; 168 public event MoveInventoryItem OnMoveInventoryItem;
166 public event RemoveInventoryItem OnRemoveInventoryItem; 169 public event RemoveInventoryItem OnRemoveInventoryItem;
167 public event RemoveInventoryFolder OnRemoveInventoryFolder; 170 public event RemoveInventoryFolder OnRemoveInventoryFolder;
@@ -260,7 +263,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
260 public event ClassifiedInfoRequest OnClassifiedInfoRequest; 263 public event ClassifiedInfoRequest OnClassifiedInfoRequest;
261 public event ClassifiedInfoUpdate OnClassifiedInfoUpdate; 264 public event ClassifiedInfoUpdate OnClassifiedInfoUpdate;
262 public event ClassifiedDelete OnClassifiedDelete; 265 public event ClassifiedDelete OnClassifiedDelete;
263 public event ClassifiedDelete OnClassifiedGodDelete; 266 public event ClassifiedGodDelete OnClassifiedGodDelete;
264 public event EventNotificationAddRequest OnEventNotificationAddRequest; 267 public event EventNotificationAddRequest OnEventNotificationAddRequest;
265 public event EventNotificationRemoveRequest OnEventNotificationRemoveRequest; 268 public event EventNotificationRemoveRequest OnEventNotificationRemoveRequest;
266 public event EventGodDelete OnEventGodDelete; 269 public event EventGodDelete OnEventGodDelete;
@@ -291,10 +294,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
291 public event GroupVoteHistoryRequest OnGroupVoteHistoryRequest; 294 public event GroupVoteHistoryRequest OnGroupVoteHistoryRequest;
292 public event SimWideDeletesDelegate OnSimWideDeletes; 295 public event SimWideDeletesDelegate OnSimWideDeletes;
293 public event SendPostcard OnSendPostcard; 296 public event SendPostcard OnSendPostcard;
297 public event ChangeInventoryItemFlags OnChangeInventoryItemFlags;
294 public event MuteListEntryUpdate OnUpdateMuteListEntry; 298 public event MuteListEntryUpdate OnUpdateMuteListEntry;
295 public event MuteListEntryRemove OnRemoveMuteListEntry; 299 public event MuteListEntryRemove OnRemoveMuteListEntry;
296 public event GodlikeMessage onGodlikeMessage; 300 public event GodlikeMessage onGodlikeMessage;
297 public event GodUpdateRegionInfoUpdate OnGodUpdateRegionInfoUpdate; 301 public event GodUpdateRegionInfoUpdate OnGodUpdateRegionInfoUpdate;
302 public event GenericCall2 OnUpdateThrottles;
298 303
299 #endregion Events 304 #endregion Events
300 305
@@ -323,11 +328,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
323 private readonly byte[] m_channelVersion = Utils.EmptyBytes; 328 private readonly byte[] m_channelVersion = Utils.EmptyBytes;
324 private readonly IGroupsModule m_GroupsModule; 329 private readonly IGroupsModule m_GroupsModule;
325 330
331 private int m_cachedTextureSerial;
326 private PriorityQueue m_entityUpdates; 332 private PriorityQueue m_entityUpdates;
327 private PriorityQueue m_entityProps; 333 private PriorityQueue m_entityProps;
328 private Prioritizer m_prioritizer; 334 private Prioritizer m_prioritizer;
329 private bool m_disableFacelights = false; 335 private bool m_disableFacelights = false;
336
337 private bool m_VelocityInterpolate = false;
338 private const uint MaxTransferBytesPerPacket = 600;
339
330 private volatile bool m_justEditedTerrain = false; 340 private volatile bool m_justEditedTerrain = false;
341
331 /// <value> 342 /// <value>
332 /// List used in construction of data blocks for an object update packet. This is to stop us having to 343 /// List used in construction of data blocks for an object update packet. This is to stop us having to
333 /// continually recreate it. 344 /// continually recreate it.
@@ -339,13 +350,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
339 /// thread servicing the m_primFullUpdates queue after a kill. If this happens the object persists as an 350 /// thread servicing the m_primFullUpdates queue after a kill. If this happens the object persists as an
340 /// ownerless phantom. 351 /// ownerless phantom.
341 /// 352 ///
342 /// All manipulation of this set has to occur under a lock 353 /// All manipulation of this set has to occur under an m_entityUpdates.SyncRoot lock
343 /// 354 ///
344 /// </value> 355 /// </value>
345 protected HashSet<uint> m_killRecord; 356// protected HashSet<uint> m_killRecord;
346 357
347// protected HashSet<uint> m_attachmentsSent; 358// protected HashSet<uint> m_attachmentsSent;
348 359
360 private bool m_deliverPackets = true;
349 private int m_animationSequenceNumber = 1; 361 private int m_animationSequenceNumber = 1;
350 private bool m_SendLogoutPacketWhenClosing = true; 362 private bool m_SendLogoutPacketWhenClosing = true;
351 363
@@ -392,6 +404,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
392 get { return m_startpos; } 404 get { return m_startpos; }
393 set { m_startpos = value; } 405 set { m_startpos = value; }
394 } 406 }
407 public bool DeliverPackets
408 {
409 get { return m_deliverPackets; }
410 set {
411 m_deliverPackets = value;
412 m_udpClient.m_deliverPackets = value;
413 }
414 }
395 public UUID AgentId { get { return m_agentId; } } 415 public UUID AgentId { get { return m_agentId; } }
396 public ISceneAgent SceneAgent { get; set; } 416 public ISceneAgent SceneAgent { get; set; }
397 public UUID ActiveGroupId { get { return m_activeGroupID; } } 417 public UUID ActiveGroupId { get { return m_activeGroupID; } }
@@ -442,6 +462,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
442 } 462 }
443 463
444 public bool SendLogoutPacketWhenClosing { set { m_SendLogoutPacketWhenClosing = value; } } 464 public bool SendLogoutPacketWhenClosing { set { m_SendLogoutPacketWhenClosing = value; } }
465
445 466
446 #endregion Properties 467 #endregion Properties
447 468
@@ -468,7 +489,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
468 m_entityUpdates = new PriorityQueue(m_scene.Entities.Count); 489 m_entityUpdates = new PriorityQueue(m_scene.Entities.Count);
469 m_entityProps = new PriorityQueue(m_scene.Entities.Count); 490 m_entityProps = new PriorityQueue(m_scene.Entities.Count);
470 m_fullUpdateDataBlocksBuilder = new List<ObjectUpdatePacket.ObjectDataBlock>(); 491 m_fullUpdateDataBlocksBuilder = new List<ObjectUpdatePacket.ObjectDataBlock>();
471 m_killRecord = new HashSet<uint>(); 492// m_killRecord = new HashSet<uint>();
472// m_attachmentsSent = new HashSet<uint>(); 493// m_attachmentsSent = new HashSet<uint>();
473 494
474 m_assetService = m_scene.RequestModuleInterface<IAssetService>(); 495 m_assetService = m_scene.RequestModuleInterface<IAssetService>();
@@ -498,12 +519,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
498 519
499 #region Client Methods 520 #region Client Methods
500 521
522
523 /// <summary>
524 /// Close down the client view
525 /// </summary>
501 public void Close() 526 public void Close()
502 { 527 {
503 Close(false); 528 Close(true, false);
504 } 529 }
505 530
506 public void Close(bool force) 531 public void Close(bool sendStop, bool force)
507 { 532 {
508 // We lock here to prevent race conditions between two threads calling close simultaneously (e.g. 533 // We lock here to prevent race conditions between two threads calling close simultaneously (e.g.
509 // a simultaneous relog just as a client is being closed out due to no packet ack from the old connection. 534 // a simultaneous relog just as a client is being closed out due to no packet ack from the old connection.
@@ -521,7 +546,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
521 } 546 }
522 547
523 IsActive = false; 548 IsActive = false;
524 CloseWithoutChecks(); 549 CloseWithoutChecks(sendStop);
525 } 550 }
526 } 551 }
527 552
@@ -534,12 +559,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
534 /// 559 ///
535 /// Callers must lock ClosingSyncLock before calling. 560 /// Callers must lock ClosingSyncLock before calling.
536 /// </remarks> 561 /// </remarks>
537 public void CloseWithoutChecks() 562 public void CloseWithoutChecks(bool sendStop)
538 { 563 {
539 m_log.DebugFormat( 564 m_log.DebugFormat(
540 "[CLIENT]: Close has been called for {0} attached to scene {1}", 565 "[CLIENT]: Close has been called for {0} attached to scene {1}",
541 Name, m_scene.RegionInfo.RegionName); 566 Name, m_scene.RegionInfo.RegionName);
542 567
568 if (sendStop)
569 {
570 // Send the STOP packet
571 DisableSimulatorPacket disable = (DisableSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.DisableSimulator);
572 OutPacket(disable, ThrottleOutPacketType.Unknown);
573 }
574
543 // Shutdown the image manager 575 // Shutdown the image manager
544 ImageManager.Close(); 576 ImageManager.Close();
545 577
@@ -562,6 +594,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
562 // Disable UDP handling for this client 594 // Disable UDP handling for this client
563 m_udpClient.Shutdown(); 595 m_udpClient.Shutdown();
564 596
597
565 //m_log.InfoFormat("[CLIENTVIEW] Memory pre GC {0}", System.GC.GetTotalMemory(false)); 598 //m_log.InfoFormat("[CLIENTVIEW] Memory pre GC {0}", System.GC.GetTotalMemory(false));
566 //GC.Collect(); 599 //GC.Collect();
567 //m_log.InfoFormat("[CLIENTVIEW] Memory post GC {0}", System.GC.GetTotalMemory(true)); 600 //m_log.InfoFormat("[CLIENTVIEW] Memory post GC {0}", System.GC.GetTotalMemory(true));
@@ -858,7 +891,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
858 reply.ChatData.OwnerID = ownerID; 891 reply.ChatData.OwnerID = ownerID;
859 reply.ChatData.SourceID = fromAgentID; 892 reply.ChatData.SourceID = fromAgentID;
860 893
861 OutPacket(reply, ThrottleOutPacketType.Task); 894 OutPacket(reply, ThrottleOutPacketType.Unknown);
862 } 895 }
863 896
864 /// <summary> 897 /// <summary>
@@ -891,32 +924,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
891 msg.MessageBlock.Message = Util.StringToBytes1024(im.message); 924 msg.MessageBlock.Message = Util.StringToBytes1024(im.message);
892 msg.MessageBlock.BinaryBucket = im.binaryBucket; 925 msg.MessageBlock.BinaryBucket = im.binaryBucket;
893 926
894 if (im.message.StartsWith("[grouptest]")) 927 OutPacket(msg, ThrottleOutPacketType.Task);
895 { // this block is test code for implementing group IM - delete when group IM is finished
896 IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>();
897 if (eq != null)
898 {
899 im.dialog = 17;
900
901 //eq.ChatterboxInvitation(
902 // new UUID("00000000-68f9-1111-024e-222222111123"),
903 // "OpenSimulator Testing", im.fromAgentID, im.message, im.toAgentID, im.fromAgentName, im.dialog, 0,
904 // false, 0, new Vector3(), 1, im.imSessionID, im.fromGroup, im.binaryBucket);
905
906 eq.ChatterboxInvitation(
907 new UUID("00000000-68f9-1111-024e-222222111123"),
908 "OpenSimulator Testing", new UUID(im.fromAgentID), im.message, new UUID(im.toAgentID), im.fromAgentName, im.dialog, 0,
909 false, 0, new Vector3(), 1, new UUID(im.imSessionID), im.fromGroup, Util.StringToBytes256("OpenSimulator Testing"));
910
911 eq.ChatterBoxSessionAgentListUpdates(
912 new UUID("00000000-68f9-1111-024e-222222111123"),
913 new UUID(im.fromAgentID), new UUID(im.toAgentID), false, false, false);
914 }
915
916 Console.WriteLine("SendInstantMessage: " + msg);
917 }
918 else
919 OutPacket(msg, ThrottleOutPacketType.Task);
920 } 928 }
921 } 929 }
922 930
@@ -1154,6 +1162,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1154 public virtual void SendLayerData(float[] map) 1162 public virtual void SendLayerData(float[] map)
1155 { 1163 {
1156 Util.FireAndForget(DoSendLayerData, map); 1164 Util.FireAndForget(DoSendLayerData, map);
1165
1166 // Send it sync, and async. It's not that much data
1167 // and it improves user experience just so much!
1168 DoSendLayerData(map);
1157 } 1169 }
1158 1170
1159 /// <summary> 1171 /// <summary>
@@ -1166,16 +1178,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1166 1178
1167 try 1179 try
1168 { 1180 {
1169 //for (int y = 0; y < 16; y++) 1181 for (int y = 0; y < 16; y++)
1170 //{ 1182 {
1171 // for (int x = 0; x < 16; x++) 1183 for (int x = 0; x < 16; x+=4)
1172 // { 1184 {
1173 // SendLayerData(x, y, map); 1185 SendLayerPacket(x, y, map);
1174 // } 1186 }
1175 //} 1187 }
1176
1177 // Send LayerData in a spiral pattern. Fun!
1178 SendLayerTopRight(map, 0, 0, 15, 15);
1179 } 1188 }
1180 catch (Exception e) 1189 catch (Exception e)
1181 { 1190 {
@@ -1183,51 +1192,35 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1183 } 1192 }
1184 } 1193 }
1185 1194
1186 private void SendLayerTopRight(float[] map, int x1, int y1, int x2, int y2)
1187 {
1188 // Row
1189 for (int i = x1; i <= x2; i++)
1190 SendLayerData(i, y1, map);
1191
1192 // Column
1193 for (int j = y1 + 1; j <= y2; j++)
1194 SendLayerData(x2, j, map);
1195
1196 if (x2 - x1 > 0)
1197 SendLayerBottomLeft(map, x1, y1 + 1, x2 - 1, y2);
1198 }
1199
1200 void SendLayerBottomLeft(float[] map, int x1, int y1, int x2, int y2)
1201 {
1202 // Row in reverse
1203 for (int i = x2; i >= x1; i--)
1204 SendLayerData(i, y2, map);
1205
1206 // Column in reverse
1207 for (int j = y2 - 1; j >= y1; j--)
1208 SendLayerData(x1, j, map);
1209
1210 if (x2 - x1 > 0)
1211 SendLayerTopRight(map, x1 + 1, y1, x2, y2 - 1);
1212 }
1213
1214 /// <summary> 1195 /// <summary>
1215 /// Sends a set of four patches (x, x+1, ..., x+3) to the client 1196 /// Sends a set of four patches (x, x+1, ..., x+3) to the client
1216 /// </summary> 1197 /// </summary>
1217 /// <param name="map">heightmap</param> 1198 /// <param name="map">heightmap</param>
1218 /// <param name="px">X coordinate for patches 0..12</param> 1199 /// <param name="px">X coordinate for patches 0..12</param>
1219 /// <param name="py">Y coordinate for patches 0..15</param> 1200 /// <param name="py">Y coordinate for patches 0..15</param>
1220 // private void SendLayerPacket(float[] map, int y, int x) 1201 private void SendLayerPacket(int x, int y, float[] map)
1221 // { 1202 {
1222 // int[] patches = new int[4]; 1203 int[] patches = new int[4];
1223 // patches[0] = x + 0 + y * 16; 1204 patches[0] = x + 0 + y * 16;
1224 // patches[1] = x + 1 + y * 16; 1205 patches[1] = x + 1 + y * 16;
1225 // patches[2] = x + 2 + y * 16; 1206 patches[2] = x + 2 + y * 16;
1226 // patches[3] = x + 3 + y * 16; 1207 patches[3] = x + 3 + y * 16;
1227 1208
1228 // Packet layerpack = LLClientView.TerrainManager.CreateLandPacket(map, patches); 1209 float[] heightmap = (map.Length == 65536) ?
1229 // OutPacket(layerpack, ThrottleOutPacketType.Land); 1210 map :
1230 // } 1211 LLHeightFieldMoronize(map);
1212
1213 try
1214 {
1215 Packet layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches);
1216 OutPacket(layerpack, ThrottleOutPacketType.Land);
1217 }
1218 catch
1219 {
1220 for (int px = x ; px < x + 4 ; px++)
1221 SendLayerData(px, y, map);
1222 }
1223 }
1231 1224
1232 /// <summary> 1225 /// <summary>
1233 /// Sends a specified patch to a client 1226 /// Sends a specified patch to a client
@@ -1269,7 +1262,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1269 { 1262 {
1270 layerpack.Header.Reliable = true; 1263 layerpack.Header.Reliable = true;
1271 OutPacket(layerpack, 1264 OutPacket(layerpack,
1272 ThrottleOutPacketType.Land); 1265 ThrottleOutPacketType.Task);
1273 } 1266 }
1274 } 1267 }
1275 catch (Exception e) 1268 catch (Exception e)
@@ -1640,7 +1633,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1640 1633
1641 public void SendKillObject(List<uint> localIDs) 1634 public void SendKillObject(List<uint> localIDs)
1642 { 1635 {
1643// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, localID, regionHandle); 1636// foreach (uint id in localIDs)
1637// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, id, regionHandle);
1644 1638
1645 KillObjectPacket kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject); 1639 KillObjectPacket kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject);
1646 // TODO: don't create new blocks if recycling an old packet 1640 // TODO: don't create new blocks if recycling an old packet
@@ -1662,17 +1656,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1662 // We MUST lock for both manipulating the kill record and sending the packet, in order to avoid a race 1656 // We MUST lock for both manipulating the kill record and sending the packet, in order to avoid a race
1663 // condition where a kill can be processed before an out-of-date update for the same object. 1657 // condition where a kill can be processed before an out-of-date update for the same object.
1664 // ProcessEntityUpdates() also takes the m_killRecord lock. 1658 // ProcessEntityUpdates() also takes the m_killRecord lock.
1665 lock (m_killRecord) 1659// lock (m_killRecord)
1666 { 1660// {
1667 foreach (uint localID in localIDs) 1661// foreach (uint localID in localIDs)
1668 m_killRecord.Add(localID); 1662// m_killRecord.Add(localID);
1669 1663
1670 // The throttle queue used here must match that being used for updates. Otherwise, there is a 1664 // The throttle queue used here must match that being used for updates. Otherwise, there is a
1671 // chance that a kill packet put on a separate queue will be sent to the client before an existing 1665 // chance that a kill packet put on a separate queue will be sent to the client before an existing
1672 // update packet on another queue. Receiving updates after kills results in unowned and undeletable 1666 // update packet on another queue. Receiving updates after kills results in unowned and undeletable
1673 // scene objects in a viewer until that viewer is relogged in. 1667 // scene objects in a viewer until that viewer is relogged in.
1674 OutPacket(kill, ThrottleOutPacketType.Task); 1668 OutPacket(kill, ThrottleOutPacketType.Task);
1675 } 1669// }
1676 } 1670 }
1677 } 1671 }
1678 1672
@@ -1794,7 +1788,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1794 newBlock.CreationDate = item.CreationDate; 1788 newBlock.CreationDate = item.CreationDate;
1795 newBlock.SalePrice = item.SalePrice; 1789 newBlock.SalePrice = item.SalePrice;
1796 newBlock.SaleType = item.SaleType; 1790 newBlock.SaleType = item.SaleType;
1797 newBlock.Flags = item.Flags; 1791 newBlock.Flags = item.Flags & 0xff;
1798 1792
1799 newBlock.CRC = 1793 newBlock.CRC =
1800 Helpers.InventoryCRC(newBlock.CreationDate, newBlock.SaleType, 1794 Helpers.InventoryCRC(newBlock.CreationDate, newBlock.SaleType,
@@ -2048,7 +2042,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2048 itemBlock.GroupID = item.GroupID; 2042 itemBlock.GroupID = item.GroupID;
2049 itemBlock.GroupOwned = item.GroupOwned; 2043 itemBlock.GroupOwned = item.GroupOwned;
2050 itemBlock.GroupMask = item.GroupPermissions; 2044 itemBlock.GroupMask = item.GroupPermissions;
2051 itemBlock.Flags = item.Flags; 2045 itemBlock.Flags = item.Flags & 0xff;
2052 itemBlock.SalePrice = item.SalePrice; 2046 itemBlock.SalePrice = item.SalePrice;
2053 itemBlock.SaleType = item.SaleType; 2047 itemBlock.SaleType = item.SaleType;
2054 itemBlock.CreationDate = item.CreationDate; 2048 itemBlock.CreationDate = item.CreationDate;
@@ -2115,7 +2109,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2115 bulkUpdate.ItemData[0].GroupID = item.GroupID; 2109 bulkUpdate.ItemData[0].GroupID = item.GroupID;
2116 bulkUpdate.ItemData[0].GroupOwned = item.GroupOwned; 2110 bulkUpdate.ItemData[0].GroupOwned = item.GroupOwned;
2117 bulkUpdate.ItemData[0].GroupMask = item.GroupPermissions; 2111 bulkUpdate.ItemData[0].GroupMask = item.GroupPermissions;
2118 bulkUpdate.ItemData[0].Flags = item.Flags; 2112 bulkUpdate.ItemData[0].Flags = item.Flags & 0xff;
2119 bulkUpdate.ItemData[0].SalePrice = item.SalePrice; 2113 bulkUpdate.ItemData[0].SalePrice = item.SalePrice;
2120 bulkUpdate.ItemData[0].SaleType = item.SaleType; 2114 bulkUpdate.ItemData[0].SaleType = item.SaleType;
2121 2115
@@ -2131,9 +2125,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2131 OutPacket(bulkUpdate, ThrottleOutPacketType.Asset); 2125 OutPacket(bulkUpdate, ThrottleOutPacketType.Asset);
2132 } 2126 }
2133 2127
2134 /// <see>IClientAPI.SendInventoryItemCreateUpdate(InventoryItemBase)</see>
2135 public void SendInventoryItemCreateUpdate(InventoryItemBase Item, uint callbackId) 2128 public void SendInventoryItemCreateUpdate(InventoryItemBase Item, uint callbackId)
2136 { 2129 {
2130 SendInventoryItemCreateUpdate(Item, UUID.Zero, callbackId);
2131 }
2132
2133 /// <see>IClientAPI.SendInventoryItemCreateUpdate(InventoryItemBase)</see>
2134 public void SendInventoryItemCreateUpdate(InventoryItemBase Item, UUID transactionID, uint callbackId)
2135 {
2137 const uint FULL_MASK_PERMISSIONS = (uint)0x7fffffff; 2136 const uint FULL_MASK_PERMISSIONS = (uint)0x7fffffff;
2138 2137
2139 UpdateCreateInventoryItemPacket InventoryReply 2138 UpdateCreateInventoryItemPacket InventoryReply
@@ -2143,6 +2142,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2143 // TODO: don't create new blocks if recycling an old packet 2142 // TODO: don't create new blocks if recycling an old packet
2144 InventoryReply.AgentData.AgentID = AgentId; 2143 InventoryReply.AgentData.AgentID = AgentId;
2145 InventoryReply.AgentData.SimApproved = true; 2144 InventoryReply.AgentData.SimApproved = true;
2145 InventoryReply.AgentData.TransactionID = transactionID;
2146 InventoryReply.InventoryData = new UpdateCreateInventoryItemPacket.InventoryDataBlock[1]; 2146 InventoryReply.InventoryData = new UpdateCreateInventoryItemPacket.InventoryDataBlock[1];
2147 InventoryReply.InventoryData[0] = new UpdateCreateInventoryItemPacket.InventoryDataBlock(); 2147 InventoryReply.InventoryData[0] = new UpdateCreateInventoryItemPacket.InventoryDataBlock();
2148 InventoryReply.InventoryData[0].ItemID = Item.ID; 2148 InventoryReply.InventoryData[0].ItemID = Item.ID;
@@ -2163,7 +2163,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2163 InventoryReply.InventoryData[0].GroupID = Item.GroupID; 2163 InventoryReply.InventoryData[0].GroupID = Item.GroupID;
2164 InventoryReply.InventoryData[0].GroupOwned = Item.GroupOwned; 2164 InventoryReply.InventoryData[0].GroupOwned = Item.GroupOwned;
2165 InventoryReply.InventoryData[0].GroupMask = Item.GroupPermissions; 2165 InventoryReply.InventoryData[0].GroupMask = Item.GroupPermissions;
2166 InventoryReply.InventoryData[0].Flags = Item.Flags; 2166 InventoryReply.InventoryData[0].Flags = Item.Flags & 0xff;
2167 InventoryReply.InventoryData[0].SalePrice = Item.SalePrice; 2167 InventoryReply.InventoryData[0].SalePrice = Item.SalePrice;
2168 InventoryReply.InventoryData[0].SaleType = Item.SaleType; 2168 InventoryReply.InventoryData[0].SaleType = Item.SaleType;
2169 InventoryReply.InventoryData[0].CreationDate = Item.CreationDate; 2169 InventoryReply.InventoryData[0].CreationDate = Item.CreationDate;
@@ -2212,16 +2212,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2212 replytask.InventoryData.TaskID = taskID; 2212 replytask.InventoryData.TaskID = taskID;
2213 replytask.InventoryData.Serial = serial; 2213 replytask.InventoryData.Serial = serial;
2214 replytask.InventoryData.Filename = fileName; 2214 replytask.InventoryData.Filename = fileName;
2215 OutPacket(replytask, ThrottleOutPacketType.Asset); 2215 OutPacket(replytask, ThrottleOutPacketType.Task);
2216 } 2216 }
2217 2217
2218 public void SendXferPacket(ulong xferID, uint packet, byte[] data) 2218 public void SendXferPacket(ulong xferID, uint packet, byte[] data, bool isTaskInventory)
2219 { 2219 {
2220 ThrottleOutPacketType type = ThrottleOutPacketType.Asset;
2221 if (isTaskInventory)
2222 type = ThrottleOutPacketType.Task;
2223
2220 SendXferPacketPacket sendXfer = (SendXferPacketPacket)PacketPool.Instance.GetPacket(PacketType.SendXferPacket); 2224 SendXferPacketPacket sendXfer = (SendXferPacketPacket)PacketPool.Instance.GetPacket(PacketType.SendXferPacket);
2221 sendXfer.XferID.ID = xferID; 2225 sendXfer.XferID.ID = xferID;
2222 sendXfer.XferID.Packet = packet; 2226 sendXfer.XferID.Packet = packet;
2223 sendXfer.DataPacket.Data = data; 2227 sendXfer.DataPacket.Data = data;
2224 OutPacket(sendXfer, ThrottleOutPacketType.Asset); 2228 OutPacket(sendXfer, type);
2225 } 2229 }
2226 2230
2227 public void SendAbortXferPacket(ulong xferID) 2231 public void SendAbortXferPacket(ulong xferID)
@@ -2408,6 +2412,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2408 OutPacket(sound, ThrottleOutPacketType.Task); 2412 OutPacket(sound, ThrottleOutPacketType.Task);
2409 } 2413 }
2410 2414
2415 public void SendTransferAbort(TransferRequestPacket transferRequest)
2416 {
2417 TransferAbortPacket abort = (TransferAbortPacket)PacketPool.Instance.GetPacket(PacketType.TransferAbort);
2418 abort.TransferInfo.TransferID = transferRequest.TransferInfo.TransferID;
2419 abort.TransferInfo.ChannelType = transferRequest.TransferInfo.ChannelType;
2420 m_log.Debug("[Assets] Aborting transfer; asset request failed");
2421 OutPacket(abort, ThrottleOutPacketType.Task);
2422 }
2423
2411 public void SendTriggeredSound(UUID soundID, UUID ownerID, UUID objectID, UUID parentID, ulong handle, Vector3 position, float gain) 2424 public void SendTriggeredSound(UUID soundID, UUID ownerID, UUID objectID, UUID parentID, ulong handle, Vector3 position, float gain)
2412 { 2425 {
2413 SoundTriggerPacket sound = (SoundTriggerPacket)PacketPool.Instance.GetPacket(PacketType.SoundTrigger); 2426 SoundTriggerPacket sound = (SoundTriggerPacket)PacketPool.Instance.GetPacket(PacketType.SoundTrigger);
@@ -2716,6 +2729,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2716 float friction = part.Friction; 2729 float friction = part.Friction;
2717 float bounce = part.Restitution; 2730 float bounce = part.Restitution;
2718 float gravmod = part.GravityModifier; 2731 float gravmod = part.GravityModifier;
2732
2719 eq.partPhysicsProperties(localid, physshapetype, density, friction, bounce, gravmod,AgentId); 2733 eq.partPhysicsProperties(localid, physshapetype, density, friction, bounce, gravmod,AgentId);
2720 } 2734 }
2721 } 2735 }
@@ -2786,8 +2800,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2786 req.AssetInf.ID, req.AssetInf.Metadata.ContentType); 2800 req.AssetInf.ID, req.AssetInf.Metadata.ContentType);
2787 return; 2801 return;
2788 } 2802 }
2803 int WearableOut = 0;
2804 bool isWearable = false;
2789 2805
2790 //m_log.Debug("sending asset " + req.RequestAssetID); 2806 if (req.AssetInf != null)
2807 isWearable =
2808 ((AssetType) req.AssetInf.Type ==
2809 AssetType.Bodypart || (AssetType) req.AssetInf.Type == AssetType.Clothing);
2810
2811
2812 //m_log.Debug("sending asset " + req.RequestAssetID + ", iswearable: " + isWearable);
2813
2814
2815 //if (isWearable)
2816 // m_log.Debug((AssetType)req.AssetInf.Type);
2817
2791 TransferInfoPacket Transfer = new TransferInfoPacket(); 2818 TransferInfoPacket Transfer = new TransferInfoPacket();
2792 Transfer.TransferInfo.ChannelType = 2; 2819 Transfer.TransferInfo.ChannelType = 2;
2793 Transfer.TransferInfo.Status = 0; 2820 Transfer.TransferInfo.Status = 0;
@@ -2809,7 +2836,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2809 Transfer.TransferInfo.Size = req.AssetInf.Data.Length; 2836 Transfer.TransferInfo.Size = req.AssetInf.Data.Length;
2810 Transfer.TransferInfo.TransferID = req.TransferRequestID; 2837 Transfer.TransferInfo.TransferID = req.TransferRequestID;
2811 Transfer.Header.Zerocoded = true; 2838 Transfer.Header.Zerocoded = true;
2812 OutPacket(Transfer, ThrottleOutPacketType.Asset); 2839 OutPacket(Transfer, isWearable ? ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority : ThrottleOutPacketType.Asset);
2813 2840
2814 if (req.NumPackets == 1) 2841 if (req.NumPackets == 1)
2815 { 2842 {
@@ -2820,12 +2847,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2820 TransferPacket.TransferData.Data = req.AssetInf.Data; 2847 TransferPacket.TransferData.Data = req.AssetInf.Data;
2821 TransferPacket.TransferData.Status = 1; 2848 TransferPacket.TransferData.Status = 1;
2822 TransferPacket.Header.Zerocoded = true; 2849 TransferPacket.Header.Zerocoded = true;
2823 OutPacket(TransferPacket, ThrottleOutPacketType.Asset); 2850 OutPacket(TransferPacket, isWearable ? ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority : ThrottleOutPacketType.Asset);
2824 } 2851 }
2825 else 2852 else
2826 { 2853 {
2827 int processedLength = 0; 2854 int processedLength = 0;
2828 int maxChunkSize = Settings.MAX_PACKET_SIZE - 100; 2855// int maxChunkSize = Settings.MAX_PACKET_SIZE - 100;
2856
2857 int maxChunkSize = (int) MaxTransferBytesPerPacket;
2829 int packetNumber = 0; 2858 int packetNumber = 0;
2830 2859
2831 while (processedLength < req.AssetInf.Data.Length) 2860 while (processedLength < req.AssetInf.Data.Length)
@@ -2851,7 +2880,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2851 TransferPacket.TransferData.Status = 1; 2880 TransferPacket.TransferData.Status = 1;
2852 } 2881 }
2853 TransferPacket.Header.Zerocoded = true; 2882 TransferPacket.Header.Zerocoded = true;
2854 OutPacket(TransferPacket, ThrottleOutPacketType.Asset); 2883 OutPacket(TransferPacket, isWearable ? ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority : ThrottleOutPacketType.Asset);
2855 2884
2856 processedLength += chunkSize; 2885 processedLength += chunkSize;
2857 packetNumber++; 2886 packetNumber++;
@@ -2896,7 +2925,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2896 reply.Data.ParcelID = parcelID; 2925 reply.Data.ParcelID = parcelID;
2897 reply.Data.OwnerID = land.OwnerID; 2926 reply.Data.OwnerID = land.OwnerID;
2898 reply.Data.Name = Utils.StringToBytes(land.Name); 2927 reply.Data.Name = Utils.StringToBytes(land.Name);
2899 reply.Data.Desc = Utils.StringToBytes(land.Description); 2928 if (land != null && land.Description != null && land.Description != String.Empty)
2929 reply.Data.Desc = Utils.StringToBytes(land.Description.Substring(0, land.Description.Length > 254 ? 254: land.Description.Length));
2930 else
2931 reply.Data.Desc = new Byte[0];
2900 reply.Data.ActualArea = land.Area; 2932 reply.Data.ActualArea = land.Area;
2901 reply.Data.BillableArea = land.Area; // TODO: what is this? 2933 reply.Data.BillableArea = land.Area; // TODO: what is this?
2902 2934
@@ -3603,24 +3635,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3603 aw.WearableData = new AgentWearablesUpdatePacket.WearableDataBlock[count]; 3635 aw.WearableData = new AgentWearablesUpdatePacket.WearableDataBlock[count];
3604 AgentWearablesUpdatePacket.WearableDataBlock awb; 3636 AgentWearablesUpdatePacket.WearableDataBlock awb;
3605 int idx = 0; 3637 int idx = 0;
3606 for (int i = 0; i < wearables.Length; i++) 3638
3607 { 3639 for (int i = 0; i < wearables.Length; i++)
3608 for (int j = 0; j < wearables[i].Count; j++) 3640 {
3609 { 3641 for (int j = 0; j < wearables[i].Count; j++)
3610 awb = new AgentWearablesUpdatePacket.WearableDataBlock(); 3642 {
3611 awb.WearableType = (byte)i; 3643 awb = new AgentWearablesUpdatePacket.WearableDataBlock();
3612 awb.AssetID = wearables[i][j].AssetID; 3644 awb.WearableType = (byte) i;
3613 awb.ItemID = wearables[i][j].ItemID; 3645 awb.AssetID = wearables[i][j].AssetID;
3614 aw.WearableData[idx] = awb; 3646 awb.ItemID = wearables[i][j].ItemID;
3615 idx++; 3647 aw.WearableData[idx] = awb;
3616 3648 idx++;
3617// m_log.DebugFormat( 3649
3618// "[APPEARANCE]: Sending wearable item/asset {0} {1} (index {2}) for {3}", 3650 // m_log.DebugFormat(
3619// awb.ItemID, awb.AssetID, i, Name); 3651 // "[APPEARANCE]: Sending wearable item/asset {0} {1} (index {2}) for {3}",
3620 } 3652 // awb.ItemID, awb.AssetID, i, Name);
3621 } 3653 }
3654 }
3622 3655
3623 OutPacket(aw, ThrottleOutPacketType.Task); 3656 OutPacket(aw, ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority);
3624 } 3657 }
3625 3658
3626 public void SendAppearance(UUID agentID, byte[] visualParams, byte[] textureEntry) 3659 public void SendAppearance(UUID agentID, byte[] visualParams, byte[] textureEntry)
@@ -3631,7 +3664,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3631 3664
3632 AvatarAppearancePacket avp = (AvatarAppearancePacket)PacketPool.Instance.GetPacket(PacketType.AvatarAppearance); 3665 AvatarAppearancePacket avp = (AvatarAppearancePacket)PacketPool.Instance.GetPacket(PacketType.AvatarAppearance);
3633 // TODO: don't create new blocks if recycling an old packet 3666 // TODO: don't create new blocks if recycling an old packet
3634 avp.VisualParam = new AvatarAppearancePacket.VisualParamBlock[218]; 3667 avp.VisualParam = new AvatarAppearancePacket.VisualParamBlock[visualParams.Length];
3635 avp.ObjectData.TextureEntry = textureEntry; 3668 avp.ObjectData.TextureEntry = textureEntry;
3636 3669
3637 AvatarAppearancePacket.VisualParamBlock avblock = null; 3670 AvatarAppearancePacket.VisualParamBlock avblock = null;
@@ -3762,7 +3795,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3762 /// </summary> 3795 /// </summary>
3763 public void SendEntityUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags) 3796 public void SendEntityUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags)
3764 { 3797 {
3765 //double priority = m_prioritizer.GetUpdatePriority(this, entity); 3798 if (entity is SceneObjectPart)
3799 {
3800 SceneObjectPart e = (SceneObjectPart)entity;
3801 SceneObjectGroup g = e.ParentGroup;
3802 if (g.RootPart.Shape.State > 30) // HUD
3803 if (g.OwnerID != AgentId)
3804 return; // Don't send updates for other people's HUDs
3805 }
3806
3766 uint priority = m_prioritizer.GetUpdatePriority(this, entity); 3807 uint priority = m_prioritizer.GetUpdatePriority(this, entity);
3767 3808
3768 lock (m_entityUpdates.SyncRoot) 3809 lock (m_entityUpdates.SyncRoot)
@@ -3849,27 +3890,74 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3849 3890
3850 // We must lock for both manipulating the kill record and sending the packet, in order to avoid a race 3891 // We must lock for both manipulating the kill record and sending the packet, in order to avoid a race
3851 // condition where a kill can be processed before an out-of-date update for the same object. 3892 // condition where a kill can be processed before an out-of-date update for the same object.
3852 lock (m_killRecord) 3893 float avgTimeDilation = 1.0f;
3894 IEntityUpdate iupdate;
3895 Int32 timeinqueue; // this is just debugging code & can be dropped later
3896
3897 while (updatesThisCall < maxUpdates)
3853 { 3898 {
3854 float avgTimeDilation = 1.0f; 3899 lock (m_entityUpdates.SyncRoot)
3855 IEntityUpdate iupdate; 3900 if (!m_entityUpdates.TryDequeue(out iupdate, out timeinqueue))
3856 Int32 timeinqueue; // this is just debugging code & can be dropped later 3901 break;
3902
3903 EntityUpdate update = (EntityUpdate)iupdate;
3904
3905 avgTimeDilation += update.TimeDilation;
3906 avgTimeDilation *= 0.5f;
3857 3907
3858 while (updatesThisCall < maxUpdates) 3908 if (update.Entity is SceneObjectPart)
3859 { 3909 {
3860 lock (m_entityUpdates.SyncRoot) 3910 SceneObjectPart part = (SceneObjectPart)update.Entity;
3861 if (!m_entityUpdates.TryDequeue(out iupdate, out timeinqueue))
3862 break;
3863 3911
3864 EntityUpdate update = (EntityUpdate)iupdate; 3912 if (part.ParentGroup.IsDeleted)
3865 3913 continue;
3866 avgTimeDilation += update.TimeDilation;
3867 avgTimeDilation *= 0.5f;
3868 3914
3869 if (update.Entity is SceneObjectPart) 3915 if (part.ParentGroup.IsAttachment)
3916 { // Someone else's HUD, why are we getting these?
3917 if (part.ParentGroup.OwnerID != AgentId &&
3918 part.ParentGroup.RootPart.Shape.State > 30)
3919 continue;
3920 ScenePresence sp;
3921 // Owner is not in the sim, don't update it to
3922 // anyone
3923 if (!m_scene.TryGetScenePresence(part.OwnerID, out sp))
3924 continue;
3925
3926 List<SceneObjectGroup> atts = sp.GetAttachments();
3927 bool found = false;
3928 foreach (SceneObjectGroup att in atts)
3929 {
3930 if (att == part.ParentGroup)
3931 {
3932 found = true;
3933 break;
3934 }
3935 }
3936
3937 // It's an attachment of a valid avatar, but
3938 // doesn't seem to be attached, skip
3939 if (!found)
3940 continue;
3941
3942 // On vehicle crossing, the attachments are received
3943 // while the avatar is still a child. Don't send
3944 // updates here because the LocalId has not yet
3945 // been updated and the viewer will derender the
3946 // attachments until the avatar becomes root.
3947 if (sp.IsChildAgent)
3948 continue;
3949
3950 // If the object is an attachment we don't want it to be in the kill
3951 // record. Else attaching from inworld and subsequently dropping
3952 // it will no longer work.
3953// lock (m_killRecord)
3954// {
3955// m_killRecord.Remove(part.LocalId);
3956// m_killRecord.Remove(part.ParentGroup.RootPart.LocalId);
3957// }
3958 }
3959 else
3870 { 3960 {
3871 SceneObjectPart part = (SceneObjectPart)update.Entity;
3872
3873 // Please do not remove this unless you can demonstrate on the OpenSim mailing list that a client 3961 // Please do not remove this unless you can demonstrate on the OpenSim mailing list that a client
3874 // will never receive an update after a prim kill. Even then, keeping the kill record may be a good 3962 // will never receive an update after a prim kill. Even then, keeping the kill record may be a good
3875 // safety measure. 3963 // safety measure.
@@ -3880,21 +3968,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3880 // 3968 //
3881 // This doesn't appear to apply to child prims - a client will happily ignore these updates 3969 // This doesn't appear to apply to child prims - a client will happily ignore these updates
3882 // after the root prim has been deleted. 3970 // after the root prim has been deleted.
3883 if (m_killRecord.Contains(part.LocalId)) 3971 //
3884 { 3972 // We ignore this for attachments because attaching something from inworld breaks unless we do.
3885 // m_log.WarnFormat( 3973// lock (m_killRecord)
3886 // "[CLIENT]: Preventing update for prim with local id {0} after client for user {1} told it was deleted", 3974// {
3887 // part.LocalId, Name); 3975// if (m_killRecord.Contains(part.LocalId))
3888 continue; 3976// continue;
3889 } 3977// if (m_killRecord.Contains(part.ParentGroup.RootPart.LocalId))
3890 3978// continue;
3891 if (part.ParentGroup.IsAttachment && m_disableFacelights) 3979// }
3980 }
3981
3982 if (part.ParentGroup.IsAttachment && m_disableFacelights)
3983 {
3984 if (part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand &&
3985 part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.RightHand)
3892 { 3986 {
3893 if (part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand && 3987 part.Shape.LightEntry = false;
3894 part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.RightHand)
3895 {
3896 part.Shape.LightEntry = false;
3897 }
3898 } 3988 }
3899 3989
3900 if (part.Shape != null && (part.Shape.SculptType == (byte)SculptType.Mesh)) 3990 if (part.Shape != null && (part.Shape.SculptType == (byte)SculptType.Mesh))
@@ -3905,224 +3995,166 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3905 part.Shape.ProfileHollow = 27500; 3995 part.Shape.ProfileHollow = 27500;
3906 } 3996 }
3907 } 3997 }
3908 3998
3909 #region UpdateFlags to packet type conversion 3999 if (part.Shape != null && (part.Shape.SculptType == (byte)SculptType.Mesh))
3910
3911 PrimUpdateFlags updateFlags = (PrimUpdateFlags)update.Flags;
3912
3913 bool canUseCompressed = true;
3914 bool canUseImproved = true;
3915
3916 // Compressed object updates only make sense for LL primitives
3917 if (!(update.Entity is SceneObjectPart))
3918 { 4000 {
3919 canUseCompressed = false; 4001 // Ensure that mesh has at least 8 valid faces
4002 part.Shape.ProfileBegin = 12500;
4003 part.Shape.ProfileEnd = 0;
4004 part.Shape.ProfileHollow = 27500;
3920 } 4005 }
3921 4006 }
3922 if (updateFlags.HasFlag(PrimUpdateFlags.FullUpdate)) 4007
4008 ++updatesThisCall;
4009
4010 #region UpdateFlags to packet type conversion
4011
4012 PrimUpdateFlags updateFlags = (PrimUpdateFlags)update.Flags;
4013
4014 bool canUseCompressed = true;
4015 bool canUseImproved = true;
4016
4017 // Compressed object updates only make sense for LL primitives
4018 if (!(update.Entity is SceneObjectPart))
4019 {
4020 canUseCompressed = false;
4021 }
4022
4023 if (updateFlags.HasFlag(PrimUpdateFlags.FullUpdate))
4024 {
4025 canUseCompressed = false;
4026 canUseImproved = false;
4027 }
4028 else
4029 {
4030 if (updateFlags.HasFlag(PrimUpdateFlags.Velocity) ||
4031 updateFlags.HasFlag(PrimUpdateFlags.Acceleration) ||
4032 updateFlags.HasFlag(PrimUpdateFlags.CollisionPlane) ||
4033 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3923 { 4034 {
3924 canUseCompressed = false; 4035 canUseCompressed = false;
3925 canUseImproved = false;
3926 } 4036 }
3927 else 4037
4038 if (updateFlags.HasFlag(PrimUpdateFlags.PrimFlags) ||
4039 updateFlags.HasFlag(PrimUpdateFlags.ParentID) ||
4040 updateFlags.HasFlag(PrimUpdateFlags.Scale) ||
4041 updateFlags.HasFlag(PrimUpdateFlags.PrimData) ||
4042 updateFlags.HasFlag(PrimUpdateFlags.Text) ||
4043 updateFlags.HasFlag(PrimUpdateFlags.NameValue) ||
4044 updateFlags.HasFlag(PrimUpdateFlags.ExtraData) ||
4045 updateFlags.HasFlag(PrimUpdateFlags.TextureAnim) ||
4046 updateFlags.HasFlag(PrimUpdateFlags.Sound) ||
4047 updateFlags.HasFlag(PrimUpdateFlags.Particles) ||
4048 updateFlags.HasFlag(PrimUpdateFlags.Material) ||
4049 updateFlags.HasFlag(PrimUpdateFlags.ClickAction) ||
4050 updateFlags.HasFlag(PrimUpdateFlags.MediaURL) ||
4051 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3928 { 4052 {
3929 if (updateFlags.HasFlag(PrimUpdateFlags.Velocity) || 4053 canUseImproved = false;
3930 updateFlags.HasFlag(PrimUpdateFlags.Acceleration) ||
3931 updateFlags.HasFlag(PrimUpdateFlags.CollisionPlane) ||
3932 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3933 {
3934 canUseCompressed = false;
3935 }
3936
3937 if (updateFlags.HasFlag(PrimUpdateFlags.PrimFlags) ||
3938 updateFlags.HasFlag(PrimUpdateFlags.ParentID) ||
3939 updateFlags.HasFlag(PrimUpdateFlags.Scale) ||
3940 updateFlags.HasFlag(PrimUpdateFlags.PrimData) ||
3941 updateFlags.HasFlag(PrimUpdateFlags.Text) ||
3942 updateFlags.HasFlag(PrimUpdateFlags.NameValue) ||
3943 updateFlags.HasFlag(PrimUpdateFlags.ExtraData) ||
3944 updateFlags.HasFlag(PrimUpdateFlags.TextureAnim) ||
3945 updateFlags.HasFlag(PrimUpdateFlags.Sound) ||
3946 updateFlags.HasFlag(PrimUpdateFlags.Particles) ||
3947 updateFlags.HasFlag(PrimUpdateFlags.Material) ||
3948 updateFlags.HasFlag(PrimUpdateFlags.ClickAction) ||
3949 updateFlags.HasFlag(PrimUpdateFlags.MediaURL) ||
3950 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3951 {
3952 canUseImproved = false;
3953 }
3954 } 4054 }
4055 }
3955 4056
3956 #endregion UpdateFlags to packet type conversion 4057 #endregion UpdateFlags to packet type conversion
3957
3958 #region Block Construction
3959
3960 // TODO: Remove this once we can build compressed updates
3961 canUseCompressed = false;
3962
3963 if (!canUseImproved && !canUseCompressed)
3964 {
3965 ObjectUpdatePacket.ObjectDataBlock updateBlock;
3966 4058
3967 if (update.Entity is ScenePresence) 4059 #region Block Construction
3968 {
3969 updateBlock = CreateAvatarUpdateBlock((ScenePresence)update.Entity);
3970 }
3971 else
3972 {
3973 SceneObjectPart part = (SceneObjectPart)update.Entity;
3974 updateBlock = CreatePrimUpdateBlock(part, AgentId);
3975
3976 // If the part has become a private hud since the update was scheduled then we do not
3977 // want to send it to other avatars.
3978 if (part.ParentGroup.IsAttachment
3979 && part.ParentGroup.HasPrivateAttachmentPoint
3980 && part.ParentGroup.AttachedAvatar != AgentId)
3981 continue;
3982
3983 // If the part has since been deleted, then drop the update. In the case of attachments,
3984 // this is to avoid spurious updates to other viewers since post-processing of attachments
3985 // has to change the IsAttachment flag for various reasons (which will end up in a pass
3986 // of the test above).
3987 //
3988 // Actual deletions (kills) happen in another method.
3989 if (part.ParentGroup.IsDeleted)
3990 continue;
3991 }
3992 4060
3993 objectUpdateBlocks.Value.Add(updateBlock); 4061 // TODO: Remove this once we can build compressed updates
3994 objectUpdates.Value.Add(update); 4062 canUseCompressed = false;
3995 }
3996 else if (!canUseImproved)
3997 {
3998 SceneObjectPart part = (SceneObjectPart)update.Entity;
3999 ObjectUpdateCompressedPacket.ObjectDataBlock compressedBlock
4000 = CreateCompressedUpdateBlock(part, updateFlags);
4001
4002 // If the part has since been deleted, then drop the update. In the case of attachments,
4003 // this is to avoid spurious updates to other viewers since post-processing of attachments
4004 // has to change the IsAttachment flag for various reasons (which will end up in a pass
4005 // of the test above).
4006 //
4007 // Actual deletions (kills) happen in another method.
4008 if (part.ParentGroup.IsDeleted)
4009 continue;
4010 4063
4011 compressedUpdateBlocks.Value.Add(compressedBlock); 4064 if (!canUseImproved && !canUseCompressed)
4012 compressedUpdates.Value.Add(update); 4065 {
4066 if (update.Entity is ScenePresence)
4067 {
4068 objectUpdateBlocks.Value.Add(CreateAvatarUpdateBlock((ScenePresence)update.Entity));
4013 } 4069 }
4014 else 4070 else
4015 { 4071 {
4016 if (update.Entity is ScenePresence && ((ScenePresence)update.Entity).UUID == AgentId) 4072 objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId));
4017 {
4018 // Self updates go into a special list
4019 terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
4020 terseAgentUpdates.Value.Add(update);
4021 }
4022 else
4023 {
4024 ImprovedTerseObjectUpdatePacket.ObjectDataBlock terseUpdateBlock
4025 = CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures));
4026
4027 // Everything else goes here
4028 if (update.Entity is SceneObjectPart)
4029 {
4030 SceneObjectPart part = (SceneObjectPart)update.Entity;
4031
4032 // If the part has become a private hud since the update was scheduled then we do not
4033 // want to send it to other avatars.
4034 if (part.ParentGroup.IsAttachment
4035 && part.ParentGroup.HasPrivateAttachmentPoint
4036 && part.ParentGroup.AttachedAvatar != AgentId)
4037 continue;
4038
4039 // If the part has since been deleted, then drop the update. In the case of attachments,
4040 // this is to avoid spurious updates to other viewers since post-processing of attachments
4041 // has to change the IsAttachment flag for various reasons (which will end up in a pass
4042 // of the test above).
4043 //
4044 // Actual deletions (kills) happen in another method.
4045 if (part.ParentGroup.IsDeleted)
4046 continue;
4047 }
4048
4049 terseUpdateBlocks.Value.Add(terseUpdateBlock);
4050 terseUpdates.Value.Add(update);
4051 }
4052 } 4073 }
4053
4054 ++updatesThisCall;
4055
4056 #endregion Block Construction
4057 } 4074 }
4058 4075 else if (!canUseImproved)
4059 #region Packet Sending 4076 {
4060 ushort timeDilation = Utils.FloatToUInt16(avgTimeDilation, 0.0f, 1.0f); 4077 compressedUpdateBlocks.Value.Add(CreateCompressedUpdateBlock((SceneObjectPart)update.Entity, updateFlags));
4061 4078 }
4062 if (terseAgentUpdateBlocks.IsValueCreated) 4079 else
4063 { 4080 {
4064 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value; 4081 if (update.Entity is ScenePresence && ((ScenePresence)update.Entity).UUID == AgentId)
4082 // Self updates go into a special list
4083 terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
4084 else
4085 // Everything else goes here
4086 terseUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
4087 }
4065 4088
4066 ImprovedTerseObjectUpdatePacket packet 4089 #endregion Block Construction
4067 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate); 4090 }
4068 4091
4069 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 4092 #region Packet Sending
4070 packet.RegionData.TimeDilation = timeDilation; 4093
4071 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; 4094 const float TIME_DILATION = 1.0f;
4095 ushort timeDilation = Utils.FloatToUInt16(avgTimeDilation, 0.0f, 1.0f);
4096
4097 if (terseAgentUpdateBlocks.IsValueCreated)
4098 {
4099 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value;
4072 4100
4073 for (int i = 0; i < blocks.Count; i++) 4101 ImprovedTerseObjectUpdatePacket packet
4074 packet.ObjectData[i] = blocks[i]; 4102 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate);
4075 // If any of the packets created from this call go unacknowledged, all of the updates will be resent 4103 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4076 OutPacket(packet, ThrottleOutPacketType.Unknown, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseAgentUpdates.Value, oPacket); }); 4104 packet.RegionData.TimeDilation = timeDilation;
4077 } 4105 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
4078 4106
4079 if (objectUpdateBlocks.IsValueCreated) 4107 for (int i = 0; i < blocks.Count; i++)
4080 { 4108 packet.ObjectData[i] = blocks[i];
4081 List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value;
4082
4083 ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate);
4084 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4085 packet.RegionData.TimeDilation = timeDilation;
4086 packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[blocks.Count];
4087
4088 for (int i = 0; i < blocks.Count; i++)
4089 packet.ObjectData[i] = blocks[i];
4090 // If any of the packets created from this call go unacknowledged, all of the updates will be resent
4091 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(objectUpdates.Value, oPacket); });
4092 }
4093
4094 if (compressedUpdateBlocks.IsValueCreated)
4095 {
4096 List<ObjectUpdateCompressedPacket.ObjectDataBlock> blocks = compressedUpdateBlocks.Value;
4097
4098 ObjectUpdateCompressedPacket packet = (ObjectUpdateCompressedPacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdateCompressed);
4099 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4100 packet.RegionData.TimeDilation = timeDilation;
4101 packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[blocks.Count];
4102
4103 for (int i = 0; i < blocks.Count; i++)
4104 packet.ObjectData[i] = blocks[i];
4105 // If any of the packets created from this call go unacknowledged, all of the updates will be resent
4106 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(compressedUpdates.Value, oPacket); });
4107 }
4108 4109
4109 if (terseUpdateBlocks.IsValueCreated) 4110 OutPacket(packet, ThrottleOutPacketType.Unknown, true);
4110 { 4111 }
4111 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;
4112
4113 ImprovedTerseObjectUpdatePacket packet
4114 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
4115 PacketType.ImprovedTerseObjectUpdate);
4116 4112
4117 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 4113 if (objectUpdateBlocks.IsValueCreated)
4118 packet.RegionData.TimeDilation = timeDilation; 4114 {
4119 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; 4115 List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value;
4120 4116
4121 for (int i = 0; i < blocks.Count; i++) 4117 ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate);
4122 packet.ObjectData[i] = blocks[i]; 4118 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4123 // If any of the packets created from this call go unacknowledged, all of the updates will be resent 4119 packet.RegionData.TimeDilation = timeDilation;
4124 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseUpdates.Value, oPacket); }); 4120 packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[blocks.Count];
4125 } 4121
4122 for (int i = 0; i < blocks.Count; i++)
4123 packet.ObjectData[i] = blocks[i];
4124
4125 OutPacket(packet, ThrottleOutPacketType.Task, true);
4126 }
4127
4128 if (compressedUpdateBlocks.IsValueCreated)
4129 {
4130 List<ObjectUpdateCompressedPacket.ObjectDataBlock> blocks = compressedUpdateBlocks.Value;
4131
4132 ObjectUpdateCompressedPacket packet = (ObjectUpdateCompressedPacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdateCompressed);
4133 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4134 packet.RegionData.TimeDilation = timeDilation;
4135 packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[blocks.Count];
4136
4137 for (int i = 0; i < blocks.Count; i++)
4138 packet.ObjectData[i] = blocks[i];
4139
4140 OutPacket(packet, ThrottleOutPacketType.Task, true);
4141 }
4142
4143 if (terseUpdateBlocks.IsValueCreated)
4144 {
4145 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;
4146
4147 ImprovedTerseObjectUpdatePacket packet
4148 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
4149 PacketType.ImprovedTerseObjectUpdate);
4150 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4151 packet.RegionData.TimeDilation = timeDilation;
4152 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
4153
4154 for (int i = 0; i < blocks.Count; i++)
4155 packet.ObjectData[i] = blocks[i];
4156
4157 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseUpdates.Value, oPacket); });
4126 } 4158 }
4127 4159
4128 #endregion Packet Sending 4160 #endregion Packet Sending
@@ -4442,11 +4474,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4442 4474
4443 // Pass in the delegate so that if this packet needs to be resent, we send the current properties 4475 // Pass in the delegate so that if this packet needs to be resent, we send the current properties
4444 // of the object rather than the properties when the packet was created 4476 // of the object rather than the properties when the packet was created
4445 OutPacket(packet, ThrottleOutPacketType.Task, true, 4477 // HACK : Remove intelligent resending until it's fixed in core
4446 delegate(OutgoingPacket oPacket) 4478 //OutPacket(packet, ThrottleOutPacketType.Task, true,
4447 { 4479 // delegate(OutgoingPacket oPacket)
4448 ResendPropertyUpdates(updates, oPacket); 4480 // {
4449 }); 4481 // ResendPropertyUpdates(updates, oPacket);
4482 // });
4483 OutPacket(packet, ThrottleOutPacketType.Task, true);
4450 4484
4451 // pbcnt += blocks.Count; 4485 // pbcnt += blocks.Count;
4452 // ppcnt++; 4486 // ppcnt++;
@@ -4472,11 +4506,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4472 // of the object rather than the properties when the packet was created 4506 // of the object rather than the properties when the packet was created
4473 List<ObjectPropertyUpdate> updates = new List<ObjectPropertyUpdate>(); 4507 List<ObjectPropertyUpdate> updates = new List<ObjectPropertyUpdate>();
4474 updates.Add(familyUpdates.Value[i]); 4508 updates.Add(familyUpdates.Value[i]);
4475 OutPacket(packet, ThrottleOutPacketType.Task, true, 4509 // HACK : Remove intelligent resending until it's fixed in core
4476 delegate(OutgoingPacket oPacket) 4510 //OutPacket(packet, ThrottleOutPacketType.Task, true,
4477 { 4511 // delegate(OutgoingPacket oPacket)
4478 ResendPropertyUpdates(updates, oPacket); 4512 // {
4479 }); 4513 // ResendPropertyUpdates(updates, oPacket);
4514 // });
4515 OutPacket(packet, ThrottleOutPacketType.Task, true);
4480 4516
4481 // fpcnt++; 4517 // fpcnt++;
4482 // fbcnt++; 4518 // fbcnt++;
@@ -4848,7 +4884,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4848 4884
4849 if (landData.SimwideArea > 0) 4885 if (landData.SimwideArea > 0)
4850 { 4886 {
4851 int simulatorCapacity = (int)(((float)landData.SimwideArea / 65536.0f) * (float)m_scene.RegionInfo.ObjectCapacity * (float)m_scene.RegionInfo.RegionSettings.ObjectBonus); 4887 int simulatorCapacity = (int)((long)landData.SimwideArea * (long)m_scene.RegionInfo.ObjectCapacity * (long)m_scene.RegionInfo.RegionSettings.ObjectBonus / 65536L);
4888 // Never report more than sim total capacity
4889 if (simulatorCapacity > m_scene.RegionInfo.ObjectCapacity)
4890 simulatorCapacity = m_scene.RegionInfo.ObjectCapacity;
4852 updateMessage.SimWideMaxPrims = simulatorCapacity; 4891 updateMessage.SimWideMaxPrims = simulatorCapacity;
4853 } 4892 }
4854 else 4893 else
@@ -4977,14 +5016,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4977 5016
4978 if (notifyCount > 0) 5017 if (notifyCount > 0)
4979 { 5018 {
4980 if (notifyCount > 32) 5019// if (notifyCount > 32)
4981 { 5020// {
4982 m_log.InfoFormat( 5021// m_log.InfoFormat(
4983 "[LAND]: More than {0} avatars own prims on this parcel. Only sending back details of first {0}" 5022// "[LAND]: More than {0} avatars own prims on this parcel. Only sending back details of first {0}"
4984 + " - a developer might want to investigate whether this is a hard limit", 32); 5023// + " - a developer might want to investigate whether this is a hard limit", 32);
4985 5024//
4986 notifyCount = 32; 5025// notifyCount = 32;
4987 } 5026// }
4988 5027
4989 ParcelObjectOwnersReplyPacket.DataBlock[] dataBlock 5028 ParcelObjectOwnersReplyPacket.DataBlock[] dataBlock
4990 = new ParcelObjectOwnersReplyPacket.DataBlock[notifyCount]; 5029 = new ParcelObjectOwnersReplyPacket.DataBlock[notifyCount];
@@ -5039,9 +5078,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5039 { 5078 {
5040 ScenePresence presence = (ScenePresence)entity; 5079 ScenePresence presence = (ScenePresence)entity;
5041 5080
5042 attachPoint = presence.State;
5043 collisionPlane = presence.CollisionPlane;
5044 position = presence.OffsetPosition; 5081 position = presence.OffsetPosition;
5082 rotation = presence.Rotation;
5083
5084 if (presence.ParentID != 0)
5085 {
5086 SceneObjectPart part = m_scene.GetSceneObjectPart(presence.ParentID);
5087 if (part != null && part != part.ParentGroup.RootPart)
5088 {
5089 position = part.OffsetPosition + presence.OffsetPosition * part.RotationOffset;
5090 rotation = part.RotationOffset * presence.Rotation;
5091 }
5092 angularVelocity = Vector3.Zero;
5093 }
5094 else
5095 {
5096 angularVelocity = presence.AngularVelocity;
5097 rotation = presence.Rotation;
5098 }
5099
5100 attachPoint = 0;
5101 collisionPlane = presence.CollisionPlane;
5045 velocity = presence.Velocity; 5102 velocity = presence.Velocity;
5046 acceleration = Vector3.Zero; 5103 acceleration = Vector3.Zero;
5047 5104
@@ -5050,9 +5107,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5050 // may improve movement smoothness. 5107 // may improve movement smoothness.
5051// acceleration = new Vector3(1, 0, 0); 5108// acceleration = new Vector3(1, 0, 0);
5052 5109
5053 angularVelocity = presence.AngularVelocity;
5054 rotation = presence.Rotation;
5055
5056 if (sendTexture) 5110 if (sendTexture)
5057 textureEntry = presence.Appearance.Texture.GetBytes(); 5111 textureEntry = presence.Appearance.Texture.GetBytes();
5058 else 5112 else
@@ -5158,13 +5212,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5158 5212
5159 protected ObjectUpdatePacket.ObjectDataBlock CreateAvatarUpdateBlock(ScenePresence data) 5213 protected ObjectUpdatePacket.ObjectDataBlock CreateAvatarUpdateBlock(ScenePresence data)
5160 { 5214 {
5215 Vector3 offsetPosition = data.OffsetPosition;
5216 Quaternion rotation = data.Rotation;
5217 uint parentID = data.ParentID;
5218
5219 if (parentID != 0)
5220 {
5221 SceneObjectPart part = m_scene.GetSceneObjectPart(parentID);
5222 if (part != null && part != part.ParentGroup.RootPart)
5223 {
5224 offsetPosition = part.OffsetPosition + data.OffsetPosition * part.RotationOffset;
5225 rotation = part.RotationOffset * data.Rotation;
5226 parentID = part.ParentGroup.RootPart.LocalId;
5227 }
5228 }
5229
5161 byte[] objectData = new byte[76]; 5230 byte[] objectData = new byte[76];
5162 5231
5163 data.CollisionPlane.ToBytes(objectData, 0); 5232 data.CollisionPlane.ToBytes(objectData, 0);
5164 data.OffsetPosition.ToBytes(objectData, 16); 5233 offsetPosition.ToBytes(objectData, 16);
5234 Vector3 velocity = new Vector3(0, 0, 0);
5235 Vector3 acceleration = new Vector3(0, 0, 0);
5236 velocity.ToBytes(objectData, 28);
5237 acceleration.ToBytes(objectData, 40);
5165// data.Velocity.ToBytes(objectData, 28); 5238// data.Velocity.ToBytes(objectData, 28);
5166// data.Acceleration.ToBytes(objectData, 40); 5239// data.Acceleration.ToBytes(objectData, 40);
5167 data.Rotation.ToBytes(objectData, 52); 5240 rotation.ToBytes(objectData, 52);
5168 //data.AngularVelocity.ToBytes(objectData, 64); 5241 //data.AngularVelocity.ToBytes(objectData, 64);
5169 5242
5170 ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock(); 5243 ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock();
@@ -5178,14 +5251,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5178 update.NameValue = Utils.StringToBytes("FirstName STRING RW SV " + data.Firstname + "\nLastName STRING RW SV " + 5251 update.NameValue = Utils.StringToBytes("FirstName STRING RW SV " + data.Firstname + "\nLastName STRING RW SV " +
5179 data.Lastname + "\nTitle STRING RW SV " + data.Grouptitle); 5252 data.Lastname + "\nTitle STRING RW SV " + data.Grouptitle);
5180 update.ObjectData = objectData; 5253 update.ObjectData = objectData;
5181 update.ParentID = data.ParentID; 5254 update.ParentID = parentID;
5182 update.PathCurve = 16; 5255 update.PathCurve = 16;
5183 update.PathScaleX = 100; 5256 update.PathScaleX = 100;
5184 update.PathScaleY = 100; 5257 update.PathScaleY = 100;
5185 update.PCode = (byte)PCode.Avatar; 5258 update.PCode = (byte)PCode.Avatar;
5186 update.ProfileCurve = 1; 5259 update.ProfileCurve = 1;
5187 update.PSBlock = Utils.EmptyBytes; 5260 update.PSBlock = Utils.EmptyBytes;
5188 update.Scale = new Vector3(0.45f, 0.6f, 1.9f); 5261 update.Scale = data.Appearance.AvatarSize;
5262// update.Scale.Z -= 0.2f;
5263
5189 update.Text = Utils.EmptyBytes; 5264 update.Text = Utils.EmptyBytes;
5190 update.TextColor = new byte[4]; 5265 update.TextColor = new byte[4];
5191 5266
@@ -5196,10 +5271,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5196 update.TextureEntry = Utils.EmptyBytes; 5271 update.TextureEntry = Utils.EmptyBytes;
5197// update.TextureEntry = (data.Appearance.Texture != null) ? data.Appearance.Texture.GetBytes() : Utils.EmptyBytes; 5272// update.TextureEntry = (data.Appearance.Texture != null) ? data.Appearance.Texture.GetBytes() : Utils.EmptyBytes;
5198 5273
5274/* 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)
5199 update.UpdateFlags = (uint)( 5275 update.UpdateFlags = (uint)(
5200 PrimFlags.Physics | PrimFlags.ObjectModify | PrimFlags.ObjectCopy | PrimFlags.ObjectAnyOwner | 5276 PrimFlags.Physics | PrimFlags.ObjectModify | PrimFlags.ObjectCopy | PrimFlags.ObjectAnyOwner |
5201 PrimFlags.ObjectYouOwner | PrimFlags.ObjectMove | PrimFlags.InventoryEmpty | PrimFlags.ObjectTransfer | 5277 PrimFlags.ObjectYouOwner | PrimFlags.ObjectMove | PrimFlags.InventoryEmpty | PrimFlags.ObjectTransfer |
5202 PrimFlags.ObjectOwnerModify); 5278 PrimFlags.ObjectOwnerModify);
5279*/
5280 update.UpdateFlags = 0;
5203 5281
5204 return update; 5282 return update;
5205 } 5283 }
@@ -5370,8 +5448,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5370 // If AgentUpdate is ever handled asynchronously, then we will also need to construct a new AgentUpdateArgs 5448 // If AgentUpdate is ever handled asynchronously, then we will also need to construct a new AgentUpdateArgs
5371 // for each AgentUpdate packet. 5449 // for each AgentUpdate packet.
5372 AddLocalPacketHandler(PacketType.AgentUpdate, HandleAgentUpdate, false); 5450 AddLocalPacketHandler(PacketType.AgentUpdate, HandleAgentUpdate, false);
5373 5451
5374 AddLocalPacketHandler(PacketType.ViewerEffect, HandleViewerEffect, false); 5452 AddLocalPacketHandler(PacketType.ViewerEffect, HandleViewerEffect, false);
5453 AddLocalPacketHandler(PacketType.VelocityInterpolateOff, HandleVelocityInterpolateOff, false);
5454 AddLocalPacketHandler(PacketType.VelocityInterpolateOn, HandleVelocityInterpolateOn, false);
5375 AddLocalPacketHandler(PacketType.AgentCachedTexture, HandleAgentTextureCached, false); 5455 AddLocalPacketHandler(PacketType.AgentCachedTexture, HandleAgentTextureCached, false);
5376 AddLocalPacketHandler(PacketType.MultipleObjectUpdate, HandleMultipleObjUpdate, false); 5456 AddLocalPacketHandler(PacketType.MultipleObjectUpdate, HandleMultipleObjUpdate, false);
5377 AddLocalPacketHandler(PacketType.MoneyTransferRequest, HandleMoneyTransferRequest, false); 5457 AddLocalPacketHandler(PacketType.MoneyTransferRequest, HandleMoneyTransferRequest, false);
@@ -5523,6 +5603,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5523 AddLocalPacketHandler(PacketType.TransferAbort, HandleTransferAbort, false); 5603 AddLocalPacketHandler(PacketType.TransferAbort, HandleTransferAbort, false);
5524 AddLocalPacketHandler(PacketType.MuteListRequest, HandleMuteListRequest, false); 5604 AddLocalPacketHandler(PacketType.MuteListRequest, HandleMuteListRequest, false);
5525 AddLocalPacketHandler(PacketType.UseCircuitCode, HandleUseCircuitCode); 5605 AddLocalPacketHandler(PacketType.UseCircuitCode, HandleUseCircuitCode);
5606 AddLocalPacketHandler(PacketType.CreateNewOutfitAttachments, HandleCreateNewOutfitAttachments);
5526 AddLocalPacketHandler(PacketType.AgentHeightWidth, HandleAgentHeightWidth, false); 5607 AddLocalPacketHandler(PacketType.AgentHeightWidth, HandleAgentHeightWidth, false);
5527 AddLocalPacketHandler(PacketType.InventoryDescendents, HandleInventoryDescendents); 5608 AddLocalPacketHandler(PacketType.InventoryDescendents, HandleInventoryDescendents);
5528 AddLocalPacketHandler(PacketType.DirPlacesQuery, HandleDirPlacesQuery); 5609 AddLocalPacketHandler(PacketType.DirPlacesQuery, HandleDirPlacesQuery);
@@ -5589,6 +5670,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5589 AddLocalPacketHandler(PacketType.GroupVoteHistoryRequest, HandleGroupVoteHistoryRequest); 5670 AddLocalPacketHandler(PacketType.GroupVoteHistoryRequest, HandleGroupVoteHistoryRequest);
5590 AddLocalPacketHandler(PacketType.SimWideDeletes, HandleSimWideDeletes); 5671 AddLocalPacketHandler(PacketType.SimWideDeletes, HandleSimWideDeletes);
5591 AddLocalPacketHandler(PacketType.SendPostcard, HandleSendPostcard); 5672 AddLocalPacketHandler(PacketType.SendPostcard, HandleSendPostcard);
5673 AddLocalPacketHandler(PacketType.ChangeInventoryItemFlags, HandleChangeInventoryItemFlags);
5592 5674
5593 AddGenericPacketHandler("autopilot", HandleAutopilot); 5675 AddGenericPacketHandler("autopilot", HandleAutopilot);
5594 } 5676 }
@@ -5941,6 +6023,29 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5941 return true; 6023 return true;
5942 } 6024 }
5943 6025
6026 private bool HandleVelocityInterpolateOff(IClientAPI sender, Packet Pack)
6027 {
6028 VelocityInterpolateOffPacket p = (VelocityInterpolateOffPacket)Pack;
6029 if (p.AgentData.SessionID != SessionId ||
6030 p.AgentData.AgentID != AgentId)
6031 return true;
6032
6033 m_VelocityInterpolate = false;
6034 return true;
6035 }
6036
6037 private bool HandleVelocityInterpolateOn(IClientAPI sender, Packet Pack)
6038 {
6039 VelocityInterpolateOnPacket p = (VelocityInterpolateOnPacket)Pack;
6040 if (p.AgentData.SessionID != SessionId ||
6041 p.AgentData.AgentID != AgentId)
6042 return true;
6043
6044 m_VelocityInterpolate = true;
6045 return true;
6046 }
6047
6048
5944 private bool HandleAvatarPropertiesRequest(IClientAPI sender, Packet Pack) 6049 private bool HandleAvatarPropertiesRequest(IClientAPI sender, Packet Pack)
5945 { 6050 {
5946 AvatarPropertiesRequestPacket avatarProperties = (AvatarPropertiesRequestPacket)Pack; 6051 AvatarPropertiesRequestPacket avatarProperties = (AvatarPropertiesRequestPacket)Pack;
@@ -6365,26 +6470,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6365 // Temporarily protect ourselves from the mantis #951 failure. 6470 // Temporarily protect ourselves from the mantis #951 failure.
6366 // However, we could do this for several other handlers where a failure isn't terminal 6471 // However, we could do this for several other handlers where a failure isn't terminal
6367 // for the client session anyway, in order to protect ourselves against bad code in plugins 6472 // for the client session anyway, in order to protect ourselves against bad code in plugins
6473 Vector3 avSize = appear.AgentData.Size;
6368 try 6474 try
6369 { 6475 {
6370 byte[] visualparams = new byte[appear.VisualParam.Length]; 6476 byte[] visualparams = new byte[appear.VisualParam.Length];
6371 for (int i = 0; i < appear.VisualParam.Length; i++) 6477 for (int i = 0; i < appear.VisualParam.Length; i++)
6372 visualparams[i] = appear.VisualParam[i].ParamValue; 6478 visualparams[i] = appear.VisualParam[i].ParamValue;
6373 6479 //var b = appear.WearableData[0];
6480
6374 Primitive.TextureEntry te = null; 6481 Primitive.TextureEntry te = null;
6375 if (appear.ObjectData.TextureEntry.Length > 1) 6482 if (appear.ObjectData.TextureEntry.Length > 1)
6376 te = new Primitive.TextureEntry(appear.ObjectData.TextureEntry, 0, appear.ObjectData.TextureEntry.Length); 6483 te = new Primitive.TextureEntry(appear.ObjectData.TextureEntry, 0, appear.ObjectData.TextureEntry.Length);
6484
6485 WearableCacheItem[] cacheitems = new WearableCacheItem[appear.WearableData.Length];
6486 for (int i=0; i<appear.WearableData.Length;i++)
6487 cacheitems[i] = new WearableCacheItem(){CacheId = appear.WearableData[i].CacheID,TextureIndex=Convert.ToUInt32(appear.WearableData[i].TextureIndex)};
6377 6488
6378 List<CachedTextureRequestArg> hashes = new List<CachedTextureRequestArg>(); 6489
6379 for (int i = 0; i < appear.WearableData.Length; i++)
6380 {
6381 CachedTextureRequestArg arg = new CachedTextureRequestArg();
6382 arg.BakedTextureIndex = appear.WearableData[i].TextureIndex;
6383 arg.WearableHashID = appear.WearableData[i].CacheID;
6384 hashes.Add(arg);
6385 }
6386 6490
6387 handlerSetAppearance(sender, te, visualparams, hashes); 6491 handlerSetAppearance(sender, te, visualparams,avSize, cacheitems);
6388 } 6492 }
6389 catch (Exception e) 6493 catch (Exception e)
6390 { 6494 {
@@ -6593,6 +6697,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6593 { 6697 {
6594 handlerCompleteMovementToRegion(sender, true); 6698 handlerCompleteMovementToRegion(sender, true);
6595 } 6699 }
6700 else
6701 m_log.Debug("HandleCompleteAgentMovement NULL handler");
6702
6596 handlerCompleteMovementToRegion = null; 6703 handlerCompleteMovementToRegion = null;
6597 6704
6598 return true; 6705 return true;
@@ -6610,7 +6717,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6610 return true; 6717 return true;
6611 } 6718 }
6612 #endregion 6719 #endregion
6613 6720/*
6614 StartAnim handlerStartAnim = null; 6721 StartAnim handlerStartAnim = null;
6615 StopAnim handlerStopAnim = null; 6722 StopAnim handlerStopAnim = null;
6616 6723
@@ -6634,6 +6741,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6634 } 6741 }
6635 } 6742 }
6636 return true; 6743 return true;
6744*/
6745 ChangeAnim handlerChangeAnim = null;
6746
6747 for (int i = 0; i < AgentAni.AnimationList.Length; i++)
6748 {
6749 handlerChangeAnim = OnChangeAnim;
6750 if (handlerChangeAnim != null)
6751 {
6752 handlerChangeAnim(AgentAni.AnimationList[i].AnimID, AgentAni.AnimationList[i].StartAnim, false);
6753 }
6754 }
6755
6756 handlerChangeAnim = OnChangeAnim;
6757 if (handlerChangeAnim != null)
6758 {
6759 handlerChangeAnim(UUID.Zero, false, true);
6760 }
6761
6762 return true;
6637 } 6763 }
6638 6764
6639 private bool HandleAgentRequestSit(IClientAPI sender, Packet Pack) 6765 private bool HandleAgentRequestSit(IClientAPI sender, Packet Pack)
@@ -6859,6 +6985,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6859 #endregion 6985 #endregion
6860 6986
6861 m_udpClient.SetThrottles(atpack.Throttle.Throttles); 6987 m_udpClient.SetThrottles(atpack.Throttle.Throttles);
6988 GenericCall2 handler = OnUpdateThrottles;
6989 if (handler != null)
6990 {
6991 handler();
6992 }
6862 return true; 6993 return true;
6863 } 6994 }
6864 6995
@@ -7283,7 +7414,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7283 physdata.Bounce = phsblock.Restitution; 7414 physdata.Bounce = phsblock.Restitution;
7284 physdata.Density = phsblock.Density; 7415 physdata.Density = phsblock.Density;
7285 physdata.Friction = phsblock.Friction; 7416 physdata.Friction = phsblock.Friction;
7286 physdata.GravitationModifier = phsblock.GravityMultiplier; 7417 physdata.GravitationModifier = phsblock.GravityMultiplier;
7287 } 7418 }
7288 7419
7289 handlerUpdatePrimFlags(flags.AgentData.ObjectLocalID, UsePhysics, IsTemporary, IsPhantom, physdata, this); 7420 handlerUpdatePrimFlags(flags.AgentData.ObjectLocalID, UsePhysics, IsTemporary, IsPhantom, physdata, this);
@@ -7869,6 +8000,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7869 // surrounding scene 8000 // surrounding scene
7870 if ((ImageType)block.Type == ImageType.Baked) 8001 if ((ImageType)block.Type == ImageType.Baked)
7871 args.Priority *= 2.0f; 8002 args.Priority *= 2.0f;
8003 int wearableout = 0;
7872 8004
7873 ImageManager.EnqueueReq(args); 8005 ImageManager.EnqueueReq(args);
7874 } 8006 }
@@ -8903,16 +9035,61 @@ namespace OpenSim.Region.ClientStack.LindenUDP
8903 9035
8904 #region Parcel related packets 9036 #region Parcel related packets
8905 9037
9038 // acumulate several HandleRegionHandleRequest consecutive overlaping requests
9039 // to be done with minimal resources as possible
9040 // variables temporary here while in test
9041
9042 Queue<UUID> RegionHandleRequests = new Queue<UUID>();
9043 bool RegionHandleRequestsInService = false;
9044
8906 private bool HandleRegionHandleRequest(IClientAPI sender, Packet Pack) 9045 private bool HandleRegionHandleRequest(IClientAPI sender, Packet Pack)
8907 { 9046 {
8908 RegionHandleRequestPacket rhrPack = (RegionHandleRequestPacket)Pack; 9047 UUID currentUUID;
8909 9048
8910 RegionHandleRequest handlerRegionHandleRequest = OnRegionHandleRequest; 9049 RegionHandleRequest handlerRegionHandleRequest = OnRegionHandleRequest;
8911 if (handlerRegionHandleRequest != null) 9050
9051 if (handlerRegionHandleRequest == null)
9052 return true;
9053
9054 RegionHandleRequestPacket rhrPack = (RegionHandleRequestPacket)Pack;
9055
9056 lock (RegionHandleRequests)
8912 { 9057 {
8913 handlerRegionHandleRequest(this, rhrPack.RequestBlock.RegionID); 9058 if (RegionHandleRequestsInService)
9059 {
9060 // we are already busy doing a previus request
9061 // so enqueue it
9062 RegionHandleRequests.Enqueue(rhrPack.RequestBlock.RegionID);
9063 return true;
9064 }
9065
9066 // else do it
9067 currentUUID = rhrPack.RequestBlock.RegionID;
9068 RegionHandleRequestsInService = true;
8914 } 9069 }
8915 return true; 9070
9071 while (true)
9072 {
9073 handlerRegionHandleRequest(this, currentUUID);
9074
9075 lock (RegionHandleRequests)
9076 {
9077 // exit condition, nothing to do or closed
9078 // current code seems to assume we may loose the handler at anytime,
9079 // so keep checking it
9080 handlerRegionHandleRequest = OnRegionHandleRequest;
9081
9082 if (RegionHandleRequests.Count == 0 || !IsActive || handlerRegionHandleRequest == null)
9083 {
9084 RegionHandleRequests.Clear();
9085 RegionHandleRequestsInService = false;
9086 return true;
9087 }
9088 currentUUID = RegionHandleRequests.Dequeue();
9089 }
9090 }
9091
9092 return true; // actually unreached
8916 } 9093 }
8917 9094
8918 private bool HandleParcelInfoRequest(IClientAPI sender, Packet Pack) 9095 private bool HandleParcelInfoRequest(IClientAPI sender, Packet Pack)
@@ -10168,7 +10345,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10168 handlerUpdateMuteListEntry(this, UpdateMuteListEntry.MuteData.MuteID, 10345 handlerUpdateMuteListEntry(this, UpdateMuteListEntry.MuteData.MuteID,
10169 Utils.BytesToString(UpdateMuteListEntry.MuteData.MuteName), 10346 Utils.BytesToString(UpdateMuteListEntry.MuteData.MuteName),
10170 UpdateMuteListEntry.MuteData.MuteType, 10347 UpdateMuteListEntry.MuteData.MuteType,
10171 UpdateMuteListEntry.AgentData.AgentID); 10348 UpdateMuteListEntry.MuteData.MuteFlags);
10172 return true; 10349 return true;
10173 } 10350 }
10174 return false; 10351 return false;
@@ -10183,8 +10360,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10183 { 10360 {
10184 handlerRemoveMuteListEntry(this, 10361 handlerRemoveMuteListEntry(this,
10185 RemoveMuteListEntry.MuteData.MuteID, 10362 RemoveMuteListEntry.MuteData.MuteID,
10186 Utils.BytesToString(RemoveMuteListEntry.MuteData.MuteName), 10363 Utils.BytesToString(RemoveMuteListEntry.MuteData.MuteName));
10187 RemoveMuteListEntry.AgentData.AgentID);
10188 return true; 10364 return true;
10189 } 10365 }
10190 return false; 10366 return false;
@@ -10228,10 +10404,55 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10228 return false; 10404 return false;
10229 } 10405 }
10230 10406
10407 private bool HandleChangeInventoryItemFlags(IClientAPI client, Packet packet)
10408 {
10409 ChangeInventoryItemFlagsPacket ChangeInventoryItemFlags =
10410 (ChangeInventoryItemFlagsPacket)packet;
10411 ChangeInventoryItemFlags handlerChangeInventoryItemFlags = OnChangeInventoryItemFlags;
10412 if (handlerChangeInventoryItemFlags != null)
10413 {
10414 foreach(ChangeInventoryItemFlagsPacket.InventoryDataBlock b in ChangeInventoryItemFlags.InventoryData)
10415 handlerChangeInventoryItemFlags(this, b.ItemID, b.Flags);
10416 return true;
10417 }
10418 return false;
10419 }
10420
10231 private bool HandleUseCircuitCode(IClientAPI sender, Packet Pack) 10421 private bool HandleUseCircuitCode(IClientAPI sender, Packet Pack)
10232 { 10422 {
10233 return true; 10423 return true;
10234 } 10424 }
10425
10426 private bool HandleCreateNewOutfitAttachments(IClientAPI sender, Packet Pack)
10427 {
10428 CreateNewOutfitAttachmentsPacket packet = (CreateNewOutfitAttachmentsPacket)Pack;
10429
10430 #region Packet Session and User Check
10431 if (m_checkPackets)
10432 {
10433 if (packet.AgentData.SessionID != SessionId ||
10434 packet.AgentData.AgentID != AgentId)
10435 return true;
10436 }
10437 #endregion
10438 MoveItemsAndLeaveCopy handlerMoveItemsAndLeaveCopy = null;
10439 List<InventoryItemBase> items = new List<InventoryItemBase>();
10440 foreach (CreateNewOutfitAttachmentsPacket.ObjectDataBlock n in packet.ObjectData)
10441 {
10442 InventoryItemBase b = new InventoryItemBase();
10443 b.ID = n.OldItemID;
10444 b.Folder = n.OldFolderID;
10445 items.Add(b);
10446 }
10447
10448 handlerMoveItemsAndLeaveCopy = OnMoveItemsAndLeaveCopy;
10449 if (handlerMoveItemsAndLeaveCopy != null)
10450 {
10451 handlerMoveItemsAndLeaveCopy(this, items, packet.HeaderData.NewFolderID);
10452 }
10453
10454 return true;
10455 }
10235 10456
10236 private bool HandleAgentHeightWidth(IClientAPI sender, Packet Pack) 10457 private bool HandleAgentHeightWidth(IClientAPI sender, Packet Pack)
10237 { 10458 {
@@ -10658,6 +10879,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10658 groupProfileReply.GroupData.MaturePublish = d.MaturePublish; 10879 groupProfileReply.GroupData.MaturePublish = d.MaturePublish;
10659 groupProfileReply.GroupData.OwnerRole = d.OwnerRole; 10880 groupProfileReply.GroupData.OwnerRole = d.OwnerRole;
10660 10881
10882 Scene scene = (Scene)m_scene;
10883 if (scene.Permissions.IsGod(sender.AgentId) && (!sender.IsGroupMember(groupProfileRequest.GroupData.GroupID)))
10884 {
10885 ScenePresence p;
10886 if (scene.TryGetScenePresence(sender.AgentId, out p))
10887 {
10888 if (p.GodLevel >= 200)
10889 {
10890 groupProfileReply.GroupData.OpenEnrollment = true;
10891 groupProfileReply.GroupData.MembershipFee = 0;
10892 }
10893 }
10894 }
10895
10661 OutPacket(groupProfileReply, ThrottleOutPacketType.Task); 10896 OutPacket(groupProfileReply, ThrottleOutPacketType.Task);
10662 } 10897 }
10663 return true; 10898 return true;
@@ -11231,11 +11466,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11231 11466
11232 StartLure handlerStartLure = OnStartLure; 11467 StartLure handlerStartLure = OnStartLure;
11233 if (handlerStartLure != null) 11468 if (handlerStartLure != null)
11234 handlerStartLure(startLureRequest.Info.LureType, 11469 {
11235 Utils.BytesToString( 11470 for (int i = 0 ; i < startLureRequest.TargetData.Length ; i++)
11236 startLureRequest.Info.Message), 11471 {
11237 startLureRequest.TargetData[0].TargetID, 11472 handlerStartLure(startLureRequest.Info.LureType,
11238 this); 11473 Utils.BytesToString(
11474 startLureRequest.Info.Message),
11475 startLureRequest.TargetData[i].TargetID,
11476 this);
11477 }
11478 }
11239 return true; 11479 return true;
11240 } 11480 }
11241 private bool HandleTeleportLureRequest(IClientAPI sender, Packet Pack) 11481 private bool HandleTeleportLureRequest(IClientAPI sender, Packet Pack)
@@ -11349,10 +11589,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11349 } 11589 }
11350 #endregion 11590 #endregion
11351 11591
11352 ClassifiedDelete handlerClassifiedGodDelete = OnClassifiedGodDelete; 11592 ClassifiedGodDelete handlerClassifiedGodDelete = OnClassifiedGodDelete;
11353 if (handlerClassifiedGodDelete != null) 11593 if (handlerClassifiedGodDelete != null)
11354 handlerClassifiedGodDelete( 11594 handlerClassifiedGodDelete(
11355 classifiedGodDelete.Data.ClassifiedID, 11595 classifiedGodDelete.Data.ClassifiedID,
11596 classifiedGodDelete.Data.QueryID,
11356 this); 11597 this);
11357 return true; 11598 return true;
11358 } 11599 }
@@ -11655,12 +11896,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11655 /// <param name="simclient"></param> 11896 /// <param name="simclient"></param>
11656 /// <param name="packet"></param> 11897 /// <param name="packet"></param>
11657 /// <returns></returns> 11898 /// <returns></returns>
11658 protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet) 11899 // TODO: Convert old handler to use new method
11900 /*protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet)
11659 { 11901 {
11660 AgentCachedTexturePacket cachedtex = (AgentCachedTexturePacket)packet; 11902 AgentCachedTexturePacket cachedtex = (AgentCachedTexturePacket)packet;
11661 11903
11662 if (cachedtex.AgentData.SessionID != SessionId) 11904 if (cachedtex.AgentData.SessionID != SessionId)
11663 return false; 11905 return false;
11906
11664 11907
11665 List<CachedTextureRequestArg> requestArgs = new List<CachedTextureRequestArg>(); 11908 List<CachedTextureRequestArg> requestArgs = new List<CachedTextureRequestArg>();
11666 11909
@@ -11673,23 +11916,173 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11673 requestArgs.Add(arg); 11916 requestArgs.Add(arg);
11674 } 11917 }
11675 11918
11676 try 11919 CachedTextureRequest handlerCachedTextureRequest = OnCachedTextureRequest;
11920 if (handlerCachedTextureRequest != null)
11677 { 11921 {
11678 CachedTextureRequest handlerCachedTextureRequest = OnCachedTextureRequest; 11922 handlerCachedTextureRequest(simclient,cachedtex.AgentData.SerialNum,requestArgs);
11679 if (handlerCachedTextureRequest != null) 11923 }
11924
11925 return true;
11926 }*/
11927
11928 protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet)
11929 {
11930 //m_log.Debug("texture cached: " + packet.ToString());
11931 AgentCachedTexturePacket cachedtex = (AgentCachedTexturePacket)packet;
11932 AgentCachedTextureResponsePacket cachedresp = (AgentCachedTextureResponsePacket)PacketPool.Instance.GetPacket(PacketType.AgentCachedTextureResponse);
11933
11934 if (cachedtex.AgentData.SessionID != SessionId)
11935 return false;
11936
11937
11938 // TODO: don't create new blocks if recycling an old packet
11939 cachedresp.AgentData.AgentID = AgentId;
11940 cachedresp.AgentData.SessionID = m_sessionId;
11941 cachedresp.AgentData.SerialNum = m_cachedTextureSerial;
11942 m_cachedTextureSerial++;
11943 cachedresp.WearableData =
11944 new AgentCachedTextureResponsePacket.WearableDataBlock[cachedtex.WearableData.Length];
11945
11946 //IAvatarFactoryModule fac = m_scene.RequestModuleInterface<IAvatarFactoryModule>();
11947 // var item = fac.GetBakedTextureFaces(AgentId);
11948 //WearableCacheItem[] items = fac.GetCachedItems(AgentId);
11949
11950 IAssetService cache = m_scene.AssetService;
11951 IBakedTextureModule bakedTextureModule = m_scene.RequestModuleInterface<IBakedTextureModule>();
11952 //bakedTextureModule = null;
11953 int maxWearablesLoop = cachedtex.WearableData.Length;
11954 if (maxWearablesLoop > AvatarWearable.MAX_WEARABLES)
11955 maxWearablesLoop = AvatarWearable.MAX_WEARABLES;
11956
11957 if (bakedTextureModule != null && cache != null)
11958 {
11959 // 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
11960
11961 WearableCacheItem[] cacheItems = null;
11962 ScenePresence p = m_scene.GetScenePresence(AgentId);
11963 if (p.Appearance != null)
11964 if (p.Appearance.WearableCacheItems == null || p.Appearance.WearableCacheItemsDirty)
11965 {
11966 try
11967 {
11968 cacheItems = bakedTextureModule.Get(AgentId);
11969 p.Appearance.WearableCacheItems = cacheItems;
11970 p.Appearance.WearableCacheItemsDirty = false;
11971 }
11972
11973 /*
11974 * The following Catch types DO NOT WORK, it jumps to the General Packet Exception Handler if you don't catch Exception!
11975 *
11976 catch (System.Net.Sockets.SocketException)
11977 {
11978 cacheItems = null;
11979 }
11980 catch (WebException)
11981 {
11982 cacheItems = null;
11983 }
11984 catch (InvalidOperationException)
11985 {
11986 cacheItems = null;
11987 } */
11988 catch (Exception)
11989 {
11990 cacheItems = null;
11991 }
11992
11993 }
11994 else if (p.Appearance.WearableCacheItems != null)
11995 {
11996 cacheItems = p.Appearance.WearableCacheItems;
11997 }
11998
11999 if (cache != null && cacheItems != null)
11680 { 12000 {
11681 handlerCachedTextureRequest(simclient,cachedtex.AgentData.SerialNum,requestArgs); 12001 foreach (WearableCacheItem item in cacheItems)
12002 {
12003
12004 if (cache.GetCached(item.TextureID.ToString()) == null)
12005 {
12006 item.TextureAsset.Temporary = true;
12007 cache.Store(item.TextureAsset);
12008 }
12009
12010
12011 }
12012 }
12013
12014 if (cacheItems != null)
12015 {
12016
12017 for (int i = 0; i < maxWearablesLoop; i++)
12018 {
12019 WearableCacheItem item =
12020 WearableCacheItem.SearchTextureIndex(cachedtex.WearableData[i].TextureIndex,cacheItems);
12021
12022 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
12023 cachedresp.WearableData[i].TextureIndex= cachedtex.WearableData[i].TextureIndex;
12024 cachedresp.WearableData[i].HostName = new byte[0];
12025 if (item != null && cachedtex.WearableData[i].ID == item.CacheId)
12026 {
12027
12028 cachedresp.WearableData[i].TextureID = item.TextureID;
12029 }
12030 else
12031 {
12032 cachedresp.WearableData[i].TextureID = UUID.Zero;
12033 }
12034 }
12035 }
12036 else
12037 {
12038 for (int i = 0; i < maxWearablesLoop; i++)
12039 {
12040 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
12041 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex;
12042 cachedresp.WearableData[i].TextureID = UUID.Zero;
12043 //UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46");
12044 cachedresp.WearableData[i].HostName = new byte[0];
12045 }
11682 } 12046 }
11683 } 12047 }
11684 catch (Exception e) 12048 else
11685 { 12049 {
11686 m_log.ErrorFormat("[CLIENT VIEW]: AgentTextureCached packet handler threw an exception, {0}", e); 12050 if (cache == null)
11687 return false; 12051 {
12052 for (int i = 0; i < maxWearablesLoop; i++)
12053 {
12054 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
12055 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex;
12056 cachedresp.WearableData[i].TextureID = UUID.Zero;
12057 //UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46");
12058 cachedresp.WearableData[i].HostName = new byte[0];
12059 }
12060 }
12061 else
12062 {
12063 for (int i = 0; i < maxWearablesLoop; i++)
12064 {
12065 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
12066 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex;
12067
12068
12069
12070 if (cache.GetCached(cachedresp.WearableData[i].TextureID.ToString()) == null)
12071 cachedresp.WearableData[i].TextureID = UUID.Zero;
12072 //UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46");
12073 else
12074 cachedresp.WearableData[i].TextureID = UUID.Zero;
12075 // UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46");
12076 cachedresp.WearableData[i].HostName = new byte[0];
12077 }
12078 }
11688 } 12079 }
11689 12080 cachedresp.Header.Zerocoded = true;
12081 OutPacket(cachedresp, ThrottleOutPacketType.Task);
12082
11690 return true; 12083 return true;
11691 } 12084 }
11692 12085
11693 /// <summary> 12086 /// <summary>
11694 /// Send a response back to a client when it asks the asset server (via the region server) if it has 12087 /// Send a response back to a client when it asks the asset server (via the region server) if it has
11695 /// its appearance texture cached. 12088 /// its appearance texture cached.
@@ -11753,209 +12146,147 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11753 } 12146 }
11754 else 12147 else
11755 { 12148 {
11756// m_log.DebugFormat( 12149 ClientChangeObject updatehandler = onClientChangeObject;
11757// "[CLIENT]: Processing block {0} type {1} for {2} {3}",
11758// i, block.Type, part.Name, part.LocalId);
11759 12150
11760// // Do this once since fetch parts creates a new array. 12151 if (updatehandler != null)
11761// SceneObjectPart[] parts = part.ParentGroup.Parts; 12152 {
11762// for (int j = 0; j < parts.Length; j++) 12153 ObjectChangeData udata = new ObjectChangeData();
11763// {
11764// part.StoreUndoState();
11765// parts[j].IgnoreUndoUpdate = true;
11766// }
11767 12154
11768 UpdatePrimGroupRotation handlerUpdatePrimGroupRotation; 12155 /*ubit from ll JIRA:
12156 * 0x01 position
12157 * 0x02 rotation
12158 * 0x04 scale
12159
12160 * 0x08 LINK_SET
12161 * 0x10 UNIFORM for scale
12162 */
11769 12163
11770 switch (block.Type) 12164 // translate to internal changes
11771 { 12165 // not all cases .. just the ones older code did
11772 case 1:
11773 Vector3 pos1 = new Vector3(block.Data, 0);
11774 12166
11775 UpdateVector handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; 12167 switch (block.Type)
11776 if (handlerUpdatePrimSinglePosition != null) 12168 {
11777 { 12169 case 1: //change position sp
11778 // m_log.Debug("new movement position is " + pos.X + " , " + pos.Y + " , " + pos.Z); 12170 udata.position = new Vector3(block.Data, 0);
11779 handlerUpdatePrimSinglePosition(localId, pos1, this);
11780 }
11781 break;
11782 12171
11783 case 2: 12172 udata.change = ObjectChangeType.primP;
11784 Quaternion rot1 = new Quaternion(block.Data, 0, true); 12173 updatehandler(localId, udata, this);
12174 break;
11785 12175
11786 UpdatePrimSingleRotation handlerUpdatePrimSingleRotation = OnUpdatePrimSingleRotation; 12176 case 2: // rotation sp
11787 if (handlerUpdatePrimSingleRotation != null) 12177 udata.rotation = new Quaternion(block.Data, 0, true);
11788 {
11789 // m_log.Info("new tab rotation is " + rot1.X + " , " + rot1.Y + " , " + rot1.Z + " , " + rot1.W);
11790 handlerUpdatePrimSingleRotation(localId, rot1, this);
11791 }
11792 break;
11793 12178
11794 case 3: 12179 udata.change = ObjectChangeType.primR;
11795 Vector3 rotPos = new Vector3(block.Data, 0); 12180 updatehandler(localId, udata, this);
11796 Quaternion rot2 = new Quaternion(block.Data, 12, true); 12181 break;
11797 12182
11798 UpdatePrimSingleRotationPosition handlerUpdatePrimSingleRotationPosition = OnUpdatePrimSingleRotationPosition; 12183 case 3: // position plus rotation
11799 if (handlerUpdatePrimSingleRotationPosition != null) 12184 udata.position = new Vector3(block.Data, 0);
11800 { 12185 udata.rotation = new Quaternion(block.Data, 12, true);
11801 // m_log.Debug("new mouse rotation position is " + rotPos.X + " , " + rotPos.Y + " , " + rotPos.Z);
11802 // m_log.Info("new mouse rotation is " + rot2.X + " , " + rot2.Y + " , " + rot2.Z + " , " + rot2.W);
11803 handlerUpdatePrimSingleRotationPosition(localId, rot2, rotPos, this);
11804 }
11805 break;
11806 12186
11807 case 4: 12187 udata.change = ObjectChangeType.primPR;
11808 case 20: 12188 updatehandler(localId, udata, this);
11809 Vector3 scale4 = new Vector3(block.Data, 0); 12189 break;
11810 12190
11811 UpdateVector handlerUpdatePrimScale = OnUpdatePrimScale; 12191 case 4: // scale sp
11812 if (handlerUpdatePrimScale != null) 12192 udata.scale = new Vector3(block.Data, 0);
11813 { 12193 udata.change = ObjectChangeType.primS;
11814 // m_log.Debug("new scale is " + scale4.X + " , " + scale4.Y + " , " + scale4.Z);
11815 handlerUpdatePrimScale(localId, scale4, this);
11816 }
11817 break;
11818 12194
11819 case 5: 12195 updatehandler(localId, udata, this);
11820 Vector3 scale1 = new Vector3(block.Data, 12); 12196 break;
11821 Vector3 pos11 = new Vector3(block.Data, 0);
11822 12197
11823 handlerUpdatePrimScale = OnUpdatePrimScale; 12198 case 0x14: // uniform scale sp
11824 if (handlerUpdatePrimScale != null) 12199 udata.scale = new Vector3(block.Data, 0);
11825 {
11826 // m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z);
11827 handlerUpdatePrimScale(localId, scale1, this);
11828 12200
11829 handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; 12201 udata.change = ObjectChangeType.primUS;
11830 if (handlerUpdatePrimSinglePosition != null) 12202 updatehandler(localId, udata, this);
11831 { 12203 break;
11832 handlerUpdatePrimSinglePosition(localId, pos11, this);
11833 }
11834 }
11835 break;
11836 12204
11837 case 9: 12205 case 5: // scale and position sp
11838 Vector3 pos2 = new Vector3(block.Data, 0); 12206 udata.position = new Vector3(block.Data, 0);
12207 udata.scale = new Vector3(block.Data, 12);
11839 12208
11840 UpdateVector handlerUpdateVector = OnUpdatePrimGroupPosition; 12209 udata.change = ObjectChangeType.primPS;
12210 updatehandler(localId, udata, this);
12211 break;
11841 12212
11842 if (handlerUpdateVector != null) 12213 case 0x15: //uniform scale and position
11843 { 12214 udata.position = new Vector3(block.Data, 0);
11844 handlerUpdateVector(localId, pos2, this); 12215 udata.scale = new Vector3(block.Data, 12);
11845 }
11846 break;
11847 12216
11848 case 10: 12217 udata.change = ObjectChangeType.primPUS;
11849 Quaternion rot3 = new Quaternion(block.Data, 0, true); 12218 updatehandler(localId, udata, this);
12219 break;
11850 12220
11851 UpdatePrimRotation handlerUpdatePrimRotation = OnUpdatePrimGroupRotation; 12221 // now group related (bit 4)
11852 if (handlerUpdatePrimRotation != null) 12222 case 9: //( 8 + 1 )group position
11853 { 12223 udata.position = new Vector3(block.Data, 0);
11854 // Console.WriteLine("new rotation is " + rot3.X + " , " + rot3.Y + " , " + rot3.Z + " , " + rot3.W);
11855 handlerUpdatePrimRotation(localId, rot3, this);
11856 }
11857 break;
11858 12224
11859 case 11: 12225 udata.change = ObjectChangeType.groupP;
11860 Vector3 pos3 = new Vector3(block.Data, 0); 12226 updatehandler(localId, udata, this);
11861 Quaternion rot4 = new Quaternion(block.Data, 12, true); 12227 break;
11862 12228
11863 handlerUpdatePrimGroupRotation = OnUpdatePrimGroupMouseRotation; 12229 case 0x0A: // (8 + 2) group rotation
11864 if (handlerUpdatePrimGroupRotation != null) 12230 udata.rotation = new Quaternion(block.Data, 0, true);
11865 {
11866 // m_log.Debug("new rotation position is " + pos.X + " , " + pos.Y + " , " + pos.Z);
11867 // m_log.Debug("new group mouse rotation is " + rot4.X + " , " + rot4.Y + " , " + rot4.Z + " , " + rot4.W);
11868 handlerUpdatePrimGroupRotation(localId, pos3, rot4, this);
11869 }
11870 break;
11871 case 12:
11872 case 28:
11873 Vector3 scale7 = new Vector3(block.Data, 0);
11874 12231
11875 UpdateVector handlerUpdatePrimGroupScale = OnUpdatePrimGroupScale; 12232 udata.change = ObjectChangeType.groupR;
11876 if (handlerUpdatePrimGroupScale != null) 12233 updatehandler(localId, udata, this);
11877 { 12234 break;
11878 // m_log.Debug("new scale is " + scale7.X + " , " + scale7.Y + " , " + scale7.Z);
11879 handlerUpdatePrimGroupScale(localId, scale7, this);
11880 }
11881 break;
11882 12235
11883 case 13: 12236 case 0x0B: //( 8 + 2 + 1) group rotation and position
11884 Vector3 scale2 = new Vector3(block.Data, 12); 12237 udata.position = new Vector3(block.Data, 0);
11885 Vector3 pos4 = new Vector3(block.Data, 0); 12238 udata.rotation = new Quaternion(block.Data, 12, true);
11886 12239
11887 handlerUpdatePrimScale = OnUpdatePrimScale; 12240 udata.change = ObjectChangeType.groupPR;
11888 if (handlerUpdatePrimScale != null) 12241 updatehandler(localId, udata, this);
11889 { 12242 break;
11890 //m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z);
11891 handlerUpdatePrimScale(localId, scale2, this);
11892 12243
11893 // Change the position based on scale (for bug number 246) 12244 case 0x0C: // (8 + 4) group scale
11894 handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; 12245 // only afects root prim and only sent by viewer editor object tab scaling
11895 // m_log.Debug("new movement position is " + pos.X + " , " + pos.Y + " , " + pos.Z); 12246 // mouse edition only allows uniform scaling
11896 if (handlerUpdatePrimSinglePosition != null) 12247 // SL MAY CHANGE THIS in viewers
11897 {
11898 handlerUpdatePrimSinglePosition(localId, pos4, this);
11899 }
11900 }
11901 break;
11902 12248
11903 case 29: 12249 udata.scale = new Vector3(block.Data, 0);
11904 Vector3 scale5 = new Vector3(block.Data, 12);
11905 Vector3 pos5 = new Vector3(block.Data, 0);
11906 12250
11907 handlerUpdatePrimGroupScale = OnUpdatePrimGroupScale; 12251 udata.change = ObjectChangeType.groupS;
11908 if (handlerUpdatePrimGroupScale != null) 12252 updatehandler(localId, udata, this);
11909 {
11910 // m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z);
11911 part.StoreUndoState(true);
11912 part.IgnoreUndoUpdate = true;
11913 handlerUpdatePrimGroupScale(localId, scale5, this);
11914 handlerUpdateVector = OnUpdatePrimGroupPosition;
11915 12253
11916 if (handlerUpdateVector != null) 12254 break;
11917 {
11918 handlerUpdateVector(localId, pos5, this);
11919 }
11920 12255
11921 part.IgnoreUndoUpdate = false; 12256 case 0x0D: //(8 + 4 + 1) group scale and position
11922 } 12257 // exception as above
11923 12258
11924 break; 12259 udata.position = new Vector3(block.Data, 0);
12260 udata.scale = new Vector3(block.Data, 12);
11925 12261
11926 case 21: 12262 udata.change = ObjectChangeType.groupPS;
11927 Vector3 scale6 = new Vector3(block.Data, 12); 12263 updatehandler(localId, udata, this);
11928 Vector3 pos6 = new Vector3(block.Data, 0); 12264 break;
11929 12265
11930 handlerUpdatePrimScale = OnUpdatePrimScale; 12266 case 0x1C: // (0x10 + 8 + 4 ) group scale UNIFORM
11931 if (handlerUpdatePrimScale != null) 12267 udata.scale = new Vector3(block.Data, 0);
11932 {
11933 part.StoreUndoState(false);
11934 part.IgnoreUndoUpdate = true;
11935 12268
11936 // m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z); 12269 udata.change = ObjectChangeType.groupUS;
11937 handlerUpdatePrimScale(localId, scale6, this); 12270 updatehandler(localId, udata, this);
11938 handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; 12271 break;
11939 if (handlerUpdatePrimSinglePosition != null)
11940 {
11941 handlerUpdatePrimSinglePosition(localId, pos6, this);
11942 }
11943 12272
11944 part.IgnoreUndoUpdate = false; 12273 case 0x1D: // (UNIFORM + GROUP + SCALE + POS)
11945 } 12274 udata.position = new Vector3(block.Data, 0);
11946 break; 12275 udata.scale = new Vector3(block.Data, 12);
11947 12276
11948 default: 12277 udata.change = ObjectChangeType.groupPUS;
11949 m_log.Debug("[CLIENT]: MultipleObjUpdate recieved an unknown packet type: " + (block.Type)); 12278 updatehandler(localId, udata, this);
11950 break; 12279 break;
12280
12281 default:
12282 m_log.Debug("[CLIENT]: MultipleObjUpdate recieved an unknown packet type: " + (block.Type));
12283 break;
12284 }
11951 } 12285 }
11952 12286
11953// for (int j = 0; j < parts.Length; j++)
11954// parts[j].IgnoreUndoUpdate = false;
11955 } 12287 }
11956 } 12288 }
11957 } 12289 }
11958
11959 return true; 12290 return true;
11960 } 12291 }
11961 12292
@@ -12016,9 +12347,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12016 public void SetChildAgentThrottle(byte[] throttles) 12347 public void SetChildAgentThrottle(byte[] throttles)
12017 { 12348 {
12018 m_udpClient.SetThrottles(throttles); 12349 m_udpClient.SetThrottles(throttles);
12350 GenericCall2 handler = OnUpdateThrottles;
12351 if (handler != null)
12352 {
12353 handler();
12354 }
12019 } 12355 }
12020 12356
12021 /// <summary> 12357 /// <summary>
12358 /// Sets the throttles from values supplied by the client
12359 /// </summary>
12360 /// <param name="throttles"></param>
12361 public void SetAgentThrottleSilent(int throttle, int setting)
12362 {
12363 m_udpClient.ForceThrottleSetting(throttle,setting);
12364 //m_udpClient.SetThrottles(throttles);
12365
12366 }
12367
12368
12369 /// <summary>
12022 /// Get the current throttles for this client as a packed byte array 12370 /// Get the current throttles for this client as a packed byte array
12023 /// </summary> 12371 /// </summary>
12024 /// <param name="multiplier">Unused</param> 12372 /// <param name="multiplier">Unused</param>
@@ -12400,7 +12748,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12400// "[LLCLIENTVIEW]: Received transfer request for {0} in {1} type {2} by {3}", 12748// "[LLCLIENTVIEW]: Received transfer request for {0} in {1} type {2} by {3}",
12401// requestID, taskID, (SourceType)sourceType, Name); 12749// requestID, taskID, (SourceType)sourceType, Name);
12402 12750
12751
12752 //Note, the bool returned from the below function is useless since it is always false.
12403 m_assetService.Get(requestID.ToString(), transferRequest, AssetReceived); 12753 m_assetService.Get(requestID.ToString(), transferRequest, AssetReceived);
12754
12404 } 12755 }
12405 12756
12406 /// <summary> 12757 /// <summary>
@@ -12466,7 +12817,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12466 /// <returns></returns> 12817 /// <returns></returns>
12467 private static int CalculateNumPackets(byte[] data) 12818 private static int CalculateNumPackets(byte[] data)
12468 { 12819 {
12469 const uint m_maxPacketSize = 600; 12820// const uint m_maxPacketSize = 600;
12821 uint m_maxPacketSize = MaxTransferBytesPerPacket;
12470 int numPackets = 1; 12822 int numPackets = 1;
12471 12823
12472 if (data == null) 12824 if (data == null)
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
index 202cc62..d52ad7e 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
@@ -95,7 +95,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
95 /// <summary>Packets we have sent that need to be ACKed by the client</summary> 95 /// <summary>Packets we have sent that need to be ACKed by the client</summary>
96 public readonly UnackedPacketCollection NeedAcks = new UnackedPacketCollection(); 96 public readonly UnackedPacketCollection NeedAcks = new UnackedPacketCollection();
97 /// <summary>ACKs that are queued up, waiting to be sent to the client</summary> 97 /// <summary>ACKs that are queued up, waiting to be sent to the client</summary>
98 public readonly OpenSim.Framework.LocklessQueue<uint> PendingAcks = new OpenSim.Framework.LocklessQueue<uint>(); 98 public readonly DoubleLocklessQueue<uint> PendingAcks = new DoubleLocklessQueue<uint>();
99 99
100 /// <summary>Current packet sequence number</summary> 100 /// <summary>Current packet sequence number</summary>
101 public int CurrentSequence; 101 public int CurrentSequence;
@@ -149,7 +149,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
149 /// <summary>Throttle buckets for each packet category</summary> 149 /// <summary>Throttle buckets for each packet category</summary>
150 private readonly TokenBucket[] m_throttleCategories; 150 private readonly TokenBucket[] m_throttleCategories;
151 /// <summary>Outgoing queues for throttled packets</summary> 151 /// <summary>Outgoing queues for throttled packets</summary>
152 private readonly OpenSim.Framework.LocklessQueue<OutgoingPacket>[] m_packetOutboxes = new OpenSim.Framework.LocklessQueue<OutgoingPacket>[THROTTLE_CATEGORY_COUNT]; 152 private readonly DoubleLocklessQueue<OutgoingPacket>[] m_packetOutboxes = new DoubleLocklessQueue<OutgoingPacket>[THROTTLE_CATEGORY_COUNT];
153 /// <summary>A container that can hold one packet for each outbox, used to store 153 /// <summary>A container that can hold one packet for each outbox, used to store
154 /// dequeued packets that are being held for throttling</summary> 154 /// dequeued packets that are being held for throttling</summary>
155 private readonly OutgoingPacket[] m_nextPackets = new OutgoingPacket[THROTTLE_CATEGORY_COUNT]; 155 private readonly OutgoingPacket[] m_nextPackets = new OutgoingPacket[THROTTLE_CATEGORY_COUNT];
@@ -161,6 +161,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
161 161
162 private int m_defaultRTO = 1000; // 1sec is the recommendation in the RFC 162 private int m_defaultRTO = 1000; // 1sec is the recommendation in the RFC
163 private int m_maxRTO = 60000; 163 private int m_maxRTO = 60000;
164 public bool m_deliverPackets = true;
164 165
165 private ClientInfo m_info = new ClientInfo(); 166 private ClientInfo m_info = new ClientInfo();
166 167
@@ -206,7 +207,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
206 ThrottleOutPacketType type = (ThrottleOutPacketType)i; 207 ThrottleOutPacketType type = (ThrottleOutPacketType)i;
207 208
208 // Initialize the packet outboxes, where packets sit while they are waiting for tokens 209 // Initialize the packet outboxes, where packets sit while they are waiting for tokens
209 m_packetOutboxes[i] = new OpenSim.Framework.LocklessQueue<OutgoingPacket>(); 210 m_packetOutboxes[i] = new DoubleLocklessQueue<OutgoingPacket>();
210 // Initialize the token buckets that control the throttling for each category 211 // Initialize the token buckets that control the throttling for each category
211 m_throttleCategories[i] = new TokenBucket(m_throttleCategory, rates.GetRate(type)); 212 m_throttleCategories[i] = new TokenBucket(m_throttleCategory, rates.GetRate(type));
212 } 213 }
@@ -431,11 +432,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP
431 /// </returns> 432 /// </returns>
432 public bool EnqueueOutgoing(OutgoingPacket packet, bool forceQueue) 433 public bool EnqueueOutgoing(OutgoingPacket packet, bool forceQueue)
433 { 434 {
435 return EnqueueOutgoing(packet, forceQueue, false);
436 }
437
438 public bool EnqueueOutgoing(OutgoingPacket packet, bool forceQueue, bool highPriority)
439 {
434 int category = (int)packet.Category; 440 int category = (int)packet.Category;
435 441
436 if (category >= 0 && category < m_packetOutboxes.Length) 442 if (category >= 0 && category < m_packetOutboxes.Length)
437 { 443 {
438 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue = m_packetOutboxes[category]; 444 DoubleLocklessQueue<OutgoingPacket> queue = m_packetOutboxes[category];
445
446 if (m_deliverPackets == false)
447 {
448 queue.Enqueue(packet, highPriority);
449 return true;
450 }
451
439 TokenBucket bucket = m_throttleCategories[category]; 452 TokenBucket bucket = m_throttleCategories[category];
440 453
441 // Don't send this packet if there is already a packet waiting in the queue 454 // Don't send this packet if there is already a packet waiting in the queue
@@ -443,7 +456,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
443 // queued packets 456 // queued packets
444 if (queue.Count > 0) 457 if (queue.Count > 0)
445 { 458 {
446 queue.Enqueue(packet); 459 queue.Enqueue(packet, highPriority);
447 return true; 460 return true;
448 } 461 }
449 462
@@ -456,7 +469,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
456 else 469 else
457 { 470 {
458 // Force queue specified or not enough tokens in the bucket, queue this packet 471 // Force queue specified or not enough tokens in the bucket, queue this packet
459 queue.Enqueue(packet); 472 queue.Enqueue(packet, highPriority);
460 return true; 473 return true;
461 } 474 }
462 } 475 }
@@ -485,8 +498,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
485 /// <returns>True if any packets were sent, otherwise false</returns> 498 /// <returns>True if any packets were sent, otherwise false</returns>
486 public bool DequeueOutgoing() 499 public bool DequeueOutgoing()
487 { 500 {
488 OutgoingPacket packet; 501 if (m_deliverPackets == false) return false;
489 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue; 502
503 OutgoingPacket packet = null;
504 DoubleLocklessQueue<OutgoingPacket> queue;
490 TokenBucket bucket; 505 TokenBucket bucket;
491 bool packetSent = false; 506 bool packetSent = false;
492 ThrottleOutPacketTypeFlags emptyCategories = 0; 507 ThrottleOutPacketTypeFlags emptyCategories = 0;
@@ -517,32 +532,49 @@ namespace OpenSim.Region.ClientStack.LindenUDP
517 // No dequeued packet waiting to be sent, try to pull one off 532 // No dequeued packet waiting to be sent, try to pull one off
518 // this queue 533 // this queue
519 queue = m_packetOutboxes[i]; 534 queue = m_packetOutboxes[i];
520 if (queue.Dequeue(out packet)) 535 if (queue != null)
521 { 536 {
522 // A packet was pulled off the queue. See if we have 537 bool success = false;
523 // enough tokens in the bucket to send it out 538 try
524 if (bucket.RemoveTokens(packet.Buffer.DataLength))
525 { 539 {
526 // Send the packet 540 success = queue.Dequeue(out packet);
527 m_udpServer.SendPacketFinal(packet);
528 packetSent = true;
529 } 541 }
530 else 542 catch
531 { 543 {
532 // Save the dequeued packet for the next iteration 544 m_packetOutboxes[i] = new DoubleLocklessQueue<OutgoingPacket>();
533 m_nextPackets[i] = packet;
534 } 545 }
535 546 if (success)
536 // If the queue is empty after this dequeue, fire the queue 547 {
537 // empty callback now so it has a chance to fill before we 548 // A packet was pulled off the queue. See if we have
538 // get back here 549 // enough tokens in the bucket to send it out
539 if (queue.Count == 0) 550 if (bucket.RemoveTokens(packet.Buffer.DataLength))
551 {
552 // Send the packet
553 m_udpServer.SendPacketFinal(packet);
554 packetSent = true;
555 }
556 else
557 {
558 // Save the dequeued packet for the next iteration
559 m_nextPackets[i] = packet;
560 }
561
562 // If the queue is empty after this dequeue, fire the queue
563 // empty callback now so it has a chance to fill before we
564 // get back here
565 if (queue.Count == 0)
566 emptyCategories |= CategoryToFlag(i);
567 }
568 else
569 {
570 // No packets in this queue. Fire the queue empty callback
571 // if it has not been called recently
540 emptyCategories |= CategoryToFlag(i); 572 emptyCategories |= CategoryToFlag(i);
573 }
541 } 574 }
542 else 575 else
543 { 576 {
544 // No packets in this queue. Fire the queue empty callback 577 m_packetOutboxes[i] = new DoubleLocklessQueue<OutgoingPacket>();
545 // if it has not been called recently
546 emptyCategories |= CategoryToFlag(i); 578 emptyCategories |= CategoryToFlag(i);
547 } 579 }
548 } 580 }
@@ -683,6 +715,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
683 715
684 m_isQueueEmptyRunning = false; 716 m_isQueueEmptyRunning = false;
685 } 717 }
718 internal void ForceThrottleSetting(int throttle, int setting)
719 {
720 m_throttleCategories[throttle].RequestedDripRate = Math.Max(setting, LLUDPServer.MTU); ;
721 }
686 722
687 /// <summary> 723 /// <summary>
688 /// Converts a <seealso cref="ThrottleOutPacketType"/> integer to a 724 /// Converts a <seealso cref="ThrottleOutPacketType"/> integer to a
@@ -727,4 +763,33 @@ namespace OpenSim.Region.ClientStack.LindenUDP
727 } 763 }
728 } 764 }
729 } 765 }
766
767 public class DoubleLocklessQueue<T> : OpenSim.Framework.LocklessQueue<T>
768 {
769 OpenSim.Framework.LocklessQueue<T> highQueue = new OpenSim.Framework.LocklessQueue<T>();
770
771 public override int Count
772 {
773 get
774 {
775 return base.Count + highQueue.Count;
776 }
777 }
778
779 public override bool Dequeue(out T item)
780 {
781 if (highQueue.Dequeue(out item))
782 return true;
783
784 return base.Dequeue(out item);
785 }
786
787 public void Enqueue(T item, bool highPriority)
788 {
789 if (highPriority)
790 highQueue.Enqueue(item);
791 else
792 Enqueue(item);
793 }
794 }
730} 795}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
index de2f9d4..0431b53 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
@@ -184,7 +184,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
184 /// <summary>Handlers for incoming packets</summary> 184 /// <summary>Handlers for incoming packets</summary>
185 //PacketEventDictionary packetEvents = new PacketEventDictionary(); 185 //PacketEventDictionary packetEvents = new PacketEventDictionary();
186 /// <summary>Incoming packets that are awaiting handling</summary> 186 /// <summary>Incoming packets that are awaiting handling</summary>
187 private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>(); 187 //private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>();
188
189 private DoubleQueue<IncomingPacket> packetInbox = new DoubleQueue<IncomingPacket>();
188 190
189 /// <summary></summary> 191 /// <summary></summary>
190 //private UDPClientCollection m_clients = new UDPClientCollection(); 192 //private UDPClientCollection m_clients = new UDPClientCollection();
@@ -239,6 +241,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
239 /// <summary>Flag to signal when clients should send pings</summary> 241 /// <summary>Flag to signal when clients should send pings</summary>
240 protected bool m_sendPing; 242 protected bool m_sendPing;
241 243
244 private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>();
245
242 /// <summary> 246 /// <summary>
243 /// Event used to signal when queued packets are available for sending. 247 /// Event used to signal when queued packets are available for sending.
244 /// </summary> 248 /// </summary>
@@ -977,6 +981,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
977 981
978 #region Queue or Send 982 #region Queue or Send
979 983
984 bool highPriority = false;
985
986 if (category != ThrottleOutPacketType.Unknown && (category & ThrottleOutPacketType.HighPriority) != 0)
987 {
988 category = (ThrottleOutPacketType)((int)category & 127);
989 highPriority = true;
990 }
991
980 OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category, null); 992 OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category, null);
981 // If we were not provided a method for handling unacked, use the UDPServer default method 993 // If we were not provided a method for handling unacked, use the UDPServer default method
982 outgoingPacket.UnackedMethod = ((method == null) ? delegate(OutgoingPacket oPacket) { ResendUnacked(oPacket); } : method); 994 outgoingPacket.UnackedMethod = ((method == null) ? delegate(OutgoingPacket oPacket) { ResendUnacked(oPacket); } : method);
@@ -985,7 +997,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
985 // continue to display the deleted object until relog. Therefore, we need to always queue a kill object 997 // continue to display the deleted object until relog. Therefore, we need to always queue a kill object
986 // packet so that it isn't sent before a queued update packet. 998 // packet so that it isn't sent before a queued update packet.
987 bool requestQueue = type == PacketType.KillObject; 999 bool requestQueue = type == PacketType.KillObject;
988 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, requestQueue)) 1000 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, requestQueue, highPriority))
989 SendPacketFinal(outgoingPacket); 1001 SendPacketFinal(outgoingPacket);
990 1002
991 #endregion Queue or Send 1003 #endregion Queue or Send
@@ -1270,34 +1282,59 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1270 1282
1271 #region Packet to Client Mapping 1283 #region Packet to Client Mapping
1272 1284
1273 // UseCircuitCode handling 1285 // If there is already a client for this endpoint, don't process UseCircuitCode
1274 if (packet.Type == PacketType.UseCircuitCode) 1286 IClientAPI client = null;
1287 if (!m_scene.TryGetClient(endPoint, out client) || !(client is LLClientView))
1275 { 1288 {
1276 // We need to copy the endpoint so that it doesn't get changed when another thread reuses the 1289 // UseCircuitCode handling
1277 // buffer. 1290 if (packet.Type == PacketType.UseCircuitCode)
1278 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet }; 1291 {
1292 // And if there is a UseCircuitCode pending, also drop it
1293 lock (m_pendingCache)
1294 {
1295 if (m_pendingCache.Contains(endPoint))
1296 return;
1279 1297
1280 Util.FireAndForget(HandleUseCircuitCode, array); 1298 m_pendingCache.AddOrUpdate(endPoint, new Queue<UDPPacketBuffer>(), 60);
1299 }
1281 1300
1282 return; 1301 // We need to copy the endpoint so that it doesn't get changed when another thread reuses the
1302 // buffer.
1303 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet };
1304
1305 Util.FireAndForget(HandleUseCircuitCode, array);
1306
1307 return;
1308 }
1283 } 1309 }
1284 else if (packet.Type == PacketType.CompleteAgentMovement) 1310
1311 // If this is a pending connection, enqueue, don't process yet
1312 lock (m_pendingCache)
1285 { 1313 {
1286 // Send ack straight away to let the viewer know that we got it. 1314 Queue<UDPPacketBuffer> queue;
1287 SendAckImmediate(endPoint, packet.Header.Sequence); 1315 if (m_pendingCache.TryGetValue(endPoint, out queue))
1316 {
1317 //m_log.DebugFormat("[LLUDPSERVER]: Enqueued a {0} packet into the pending queue", packet.Type);
1318 queue.Enqueue(buffer);
1319 return;
1320 }
1321 else if (packet.Type == PacketType.CompleteAgentMovement)
1322 {
1323 // Send ack straight away to let the viewer know that we got it.
1324 SendAckImmediate(endPoint, packet.Header.Sequence);
1288 1325
1289 // We need to copy the endpoint so that it doesn't get changed when another thread reuses the 1326 // We need to copy the endpoint so that it doesn't get changed when another thread reuses the
1290 // buffer. 1327 // buffer.
1291 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet }; 1328 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet };
1292 1329
1293 Util.FireAndForget(HandleCompleteMovementIntoRegion, array); 1330 Util.FireAndForget(HandleCompleteMovementIntoRegion, array);
1294 1331
1295 return; 1332 return;
1333 }
1296 } 1334 }
1297 1335
1298 // Determine which agent this packet came from 1336 // Determine which agent this packet came from
1299 IClientAPI client; 1337 if (client == null || !(client is LLClientView))
1300 if (!m_scene.TryGetClient(endPoint, out client) || !(client is LLClientView))
1301 { 1338 {
1302 //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); 1339 //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName);
1303 return; 1340 return;
@@ -1306,7 +1343,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1306 udpClient = ((LLClientView)client).UDPClient; 1343 udpClient = ((LLClientView)client).UDPClient;
1307 1344
1308 if (!udpClient.IsConnected) 1345 if (!udpClient.IsConnected)
1346 {
1347 m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet for a unConnected client in " + m_scene.RegionInfo.RegionName);
1309 return; 1348 return;
1349 }
1310 1350
1311 #endregion Packet to Client Mapping 1351 #endregion Packet to Client Mapping
1312 1352
@@ -1455,7 +1495,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1455 incomingPacket = new IncomingPacket((LLClientView)client, packet); 1495 incomingPacket = new IncomingPacket((LLClientView)client, packet);
1456 } 1496 }
1457 1497
1458 packetInbox.Enqueue(incomingPacket); 1498 if (incomingPacket.Packet.Type == PacketType.AgentUpdate ||
1499 incomingPacket.Packet.Type == PacketType.ChatFromViewer)
1500 packetInbox.EnqueueHigh(incomingPacket);
1501 else
1502 packetInbox.EnqueueLow(incomingPacket);
1459 } 1503 }
1460 1504
1461 #region BinaryStats 1505 #region BinaryStats
@@ -1607,6 +1651,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1607 if (!tp) 1651 if (!tp)
1608 client.SceneAgent.SendInitialDataToMe(); 1652 client.SceneAgent.SendInitialDataToMe();
1609 } 1653 }
1654
1655 // Now we know we can handle more data
1656 Thread.Sleep(200);
1657
1658 // Obtain the queue and remove it from the cache
1659 Queue<UDPPacketBuffer> queue = null;
1660
1661 lock (m_pendingCache)
1662 {
1663 if (!m_pendingCache.TryGetValue(endPoint, out queue))
1664 {
1665 m_log.DebugFormat("[LLUDPSERVER]: Client created but no pending queue present");
1666 return;
1667 }
1668 m_pendingCache.Remove(endPoint);
1669 }
1670
1671 m_log.DebugFormat("[LLUDPSERVER]: Client created, processing pending queue, {0} entries", queue.Count);
1672
1673 // Reinject queued packets
1674 while(queue.Count > 0)
1675 {
1676 UDPPacketBuffer buf = queue.Dequeue();
1677 PacketReceived(buf);
1678 }
1679 queue = null;
1610 } 1680 }
1611 else 1681 else
1612 { 1682 {
@@ -1614,6 +1684,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1614 m_log.WarnFormat( 1684 m_log.WarnFormat(
1615 "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}", 1685 "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}",
1616 uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint); 1686 uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint);
1687 lock (m_pendingCache)
1688 m_pendingCache.Remove(endPoint);
1617 } 1689 }
1618 1690
1619 // m_log.DebugFormat( 1691 // m_log.DebugFormat(
@@ -1812,6 +1884,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1812 1884
1813 while (IsRunningInbound) 1885 while (IsRunningInbound)
1814 { 1886 {
1887 m_scene.ThreadAlive(1);
1815 try 1888 try
1816 { 1889 {
1817 IncomingPacket incomingPacket = null; 1890 IncomingPacket incomingPacket = null;
@@ -1861,6 +1934,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1861 1934
1862 while (base.IsRunningOutbound) 1935 while (base.IsRunningOutbound)
1863 { 1936 {
1937 m_scene.ThreadAlive(2);
1864 try 1938 try
1865 { 1939 {
1866 m_packetSent = false; 1940 m_packetSent = false;
@@ -2096,8 +2170,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2096 Packet packet = incomingPacket.Packet; 2170 Packet packet = incomingPacket.Packet;
2097 LLClientView client = incomingPacket.Client; 2171 LLClientView client = incomingPacket.Client;
2098 2172
2099 if (client.IsActive) 2173// if (client.IsActive)
2100 { 2174// {
2101 m_currentIncomingClient = client; 2175 m_currentIncomingClient = client;
2102 2176
2103 try 2177 try
@@ -2124,13 +2198,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2124 { 2198 {
2125 m_currentIncomingClient = null; 2199 m_currentIncomingClient = null;
2126 } 2200 }
2127 } 2201// }
2128 else 2202// else
2129 { 2203// {
2130 m_log.DebugFormat( 2204// m_log.DebugFormat(
2131 "[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}", 2205// "[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}",
2132 packet.Type, client.Name, m_scene.RegionInfo.RegionName); 2206// packet.Type, client.Name, m_scene.RegionInfo.RegionName);
2133 } 2207// }
2134 2208
2135 IncomingPacketsProcessed++; 2209 IncomingPacketsProcessed++;
2136 } 2210 }
@@ -2146,4 +2220,4 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2146 } 2220 }
2147 } 2221 }
2148 } 2222 }
2149} \ No newline at end of file 2223}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
index d0ed7e8..48c5b37 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
@@ -146,10 +146,6 @@ namespace OpenMetaverse
146 const int SIO_UDP_CONNRESET = -1744830452; 146 const int SIO_UDP_CONNRESET = -1744830452;
147 147
148 IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort); 148 IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort);
149
150 m_log.DebugFormat(
151 "[UDPBASE]: Binding UDP listener using internal IP address config {0}:{1}",
152 ipep.Address, ipep.Port);
153 149
154 m_udpSocket = new Socket( 150 m_udpSocket = new Socket(
155 AddressFamily.InterNetwork, 151 AddressFamily.InterNetwork,