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.cs883
-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.cs424
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs18
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs297
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs9
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs192
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs10
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs3
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs1531
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs115
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs139
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs4
16 files changed, 3587 insertions, 1172 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
index a4fe81c..613bc24 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,6 +710,34 @@ 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 = (sbyte)InventoryType.Sound; 743 inType = (sbyte)InventoryType.Sound;
@@ -525,92 +767,194 @@ namespace OpenSim.Region.ClientStack.Linden
525 } 767 }
526 else if (inventoryType == "object") 768 else if (inventoryType == "object")
527 { 769 {
528 inType = (sbyte)InventoryType.Object; 770 if (assetType == "mesh") // this code for now is for mesh models uploads only
529 assType = (sbyte)AssetType.Object;
530
531 List<Vector3> positions = new List<Vector3>();
532 List<Quaternion> rotations = new List<Quaternion>();
533 OSDMap request = (OSDMap)OSDParser.DeserializeLLSDXml(data);
534 OSDArray instance_list = (OSDArray)request["instance_list"];
535 OSDArray mesh_list = (OSDArray)request["mesh_list"];
536 OSDArray texture_list = (OSDArray)request["texture_list"];
537 SceneObjectGroup grp = null;
538
539 List<UUID> textures = new List<UUID>();
540 for (int i = 0; i < texture_list.Count; i++)
541 { 771 {
542 AssetBase textureAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Texture, ""); 772 inType = (sbyte)InventoryType.Object;
543 textureAsset.Data = texture_list[i].AsBinary(); 773 assType = (sbyte)AssetType.Object;
544 m_assetService.Store(textureAsset);
545 textures.Add(textureAsset.FullID);
546 }
547 774
548 for (int i = 0; i < mesh_list.Count; i++) 775 List<Vector3> positions = new List<Vector3>();
549 { 776 List<Quaternion> rotations = new List<Quaternion>();
550 PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateBox(); 777 OSDMap request = (OSDMap)OSDParser.DeserializeLLSDXml(data);
551 778
552 Primitive.TextureEntry textureEntry 779 // compare and get updated information
553 = new Primitive.TextureEntry(Primitive.TextureEntry.WHITE_TEXTURE);
554 OSDMap inner_instance_list = (OSDMap)instance_list[i];
555 780
556 OSDArray face_list = (OSDArray)inner_instance_list["face_list"]; 781 bool mismatchError = true;
557 for (uint face = 0; face < face_list.Count; face++) 782
783 while (mismatchError)
558 { 784 {
559 OSDMap faceMap = (OSDMap)face_list[(int)face]; 785 mismatchError = false;
560 Primitive.TextureEntryFace f = pbs.Textures.CreateFace(face); 786 }
561 if(faceMap.ContainsKey("fullbright"))
562 f.Fullbright = faceMap["fullbright"].AsBoolean();
563 if (faceMap.ContainsKey ("diffuse_color"))
564 f.RGBA = faceMap["diffuse_color"].AsColor4();
565 787
566 int textureNum = faceMap["image"].AsInteger(); 788 if (mismatchError)
567 float imagerot = faceMap["imagerot"].AsInteger(); 789 {
568 float offsets = (float)faceMap["offsets"].AsReal(); 790 error = "Upload and fee estimation information don't match";
569 float offsett = (float)faceMap["offsett"].AsReal(); 791 lock (m_ModelCost)
570 float scales = (float)faceMap["scales"].AsReal(); 792 m_FileAgentInventoryState = FileAgentInventoryState.idle;
571 float scalet = (float)faceMap["scalet"].AsReal();
572 793
573 if(imagerot != 0) 794 return;
574 f.Rotation = imagerot; 795 }
575 796
576 if(offsets != 0) 797 OSDArray instance_list = (OSDArray)request["instance_list"];
577 f.OffsetU = offsets; 798 OSDArray mesh_list = (OSDArray)request["mesh_list"];
799 OSDArray texture_list = (OSDArray)request["texture_list"];
800 SceneObjectGroup grp = null;
578 801
579 if (offsett != 0) 802 // create and store texture assets
580 f.OffsetV = offsett; 803 bool doTextInv = (!istest && m_enableModelUploadTextureToInventory &&
804 texturesFolder != UUID.Zero);
581 805
582 if (scales != 0)
583 f.RepeatU = scales;
584 806
585 if (scalet != 0) 807 List<UUID> textures = new List<UUID>();
586 f.RepeatV = scalet;
587 808
588 if (textures.Count > textureNum) 809
589 f.TextureID = textures[textureNum]; 810 if (doTextInv)
590 else 811 m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client);
591 f.TextureID = Primitive.TextureEntry.WHITE_TEXTURE;
592 812
593 textureEntry.FaceTextures[face] = f; 813 if(client == null) // don't put textures in inventory if there is no client
814 doTextInv = false;
815
816 for (int i = 0; i < texture_list.Count; i++)
817 {
818 AssetBase textureAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Texture, creatorIDstr);
819 textureAsset.Data = texture_list[i].AsBinary();
820 if (istest)
821 textureAsset.Local = true;
822 m_assetService.Store(textureAsset);
823 textures.Add(textureAsset.FullID);
824
825 if (doTextInv)
826 {
827 string name = assetName;
828 if (name.Length > 25)
829 name = name.Substring(0, 24);
830 name += "_Texture#" + i.ToString();
831 InventoryItemBase texitem = new InventoryItemBase();
832 texitem.Owner = m_HostCapsObj.AgentID;
833 texitem.CreatorId = creatorIDstr;
834 texitem.CreatorData = String.Empty;
835 texitem.ID = UUID.Random();
836 texitem.AssetID = textureAsset.FullID;
837 texitem.Description = "mesh model texture";
838 texitem.Name = name;
839 texitem.AssetType = (int)AssetType.Texture;
840 texitem.InvType = (int)InventoryType.Texture;
841 texitem.Folder = texturesFolder;
842
843 texitem.CurrentPermissions
844 = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer | PermissionMask.Export);
845
846 texitem.BasePermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export;
847 texitem.EveryOnePermissions = 0;
848 texitem.NextPermissions = (uint)PermissionMask.All;
849 texitem.CreationDate = Util.UnixTimeSinceEpoch();
850
851 m_Scene.AddInventoryItem(client, texitem);
852 texitem = null;
853 }
594 } 854 }
595 855
596 pbs.TextureEntry = textureEntry.GetBytes(); 856 // create and store meshs assets
857 List<UUID> meshAssets = new List<UUID>();
858 for (int i = 0; i < mesh_list.Count; i++)
859 {
860 AssetBase meshAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Mesh, creatorIDstr);
861 meshAsset.Data = mesh_list[i].AsBinary();
862 if (istest)
863 meshAsset.Local = true;
864 m_assetService.Store(meshAsset);
865 meshAssets.Add(meshAsset.FullID);
866 }
867
868 int skipedMeshs = 0;
869 // build prims from instances
870 for (int i = 0; i < instance_list.Count; i++)
871 {
872 OSDMap inner_instance_list = (OSDMap)instance_list[i];
873
874 // skip prims that are 2 small
875 Vector3 scale = inner_instance_list["scale"].AsVector3();
876
877 if (scale.X < m_PrimScaleMin || scale.Y < m_PrimScaleMin || scale.Z < m_PrimScaleMin)
878 {
879 skipedMeshs++;
880 continue;
881 }
882
883 PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateBox();
884
885 Primitive.TextureEntry textureEntry
886 = new Primitive.TextureEntry(Primitive.TextureEntry.WHITE_TEXTURE);
887
597 888
598 AssetBase meshAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Mesh, ""); 889 OSDArray face_list = (OSDArray)inner_instance_list["face_list"];
599 meshAsset.Data = mesh_list[i].AsBinary(); 890 for (uint face = 0; face < face_list.Count; face++)
600 m_assetService.Store(meshAsset); 891 {
892 OSDMap faceMap = (OSDMap)face_list[(int)face];
893 Primitive.TextureEntryFace f = pbs.Textures.CreateFace(face);
894 if (faceMap.ContainsKey("fullbright"))
895 f.Fullbright = faceMap["fullbright"].AsBoolean();
896 if (faceMap.ContainsKey("diffuse_color"))
897 f.RGBA = faceMap["diffuse_color"].AsColor4();
898
899 int textureNum = faceMap["image"].AsInteger();
900 float imagerot = faceMap["imagerot"].AsInteger();
901 float offsets = (float)faceMap["offsets"].AsReal();
902 float offsett = (float)faceMap["offsett"].AsReal();
903 float scales = (float)faceMap["scales"].AsReal();
904 float scalet = (float)faceMap["scalet"].AsReal();
905
906 if (imagerot != 0)
907 f.Rotation = imagerot;
908
909 if (offsets != 0)
910 f.OffsetU = offsets;
601 911
602 pbs.SculptEntry = true; 912 if (offsett != 0)
603 pbs.SculptTexture = meshAsset.FullID; 913 f.OffsetV = offsett;
604 pbs.SculptType = (byte)SculptType.Mesh;
605 pbs.SculptData = meshAsset.Data;
606 914
607 Vector3 position = inner_instance_list["position"].AsVector3(); 915 if (scales != 0)
608 Vector3 scale = inner_instance_list["scale"].AsVector3(); 916 f.RepeatU = scales;
609 Quaternion rotation = inner_instance_list["rotation"].AsQuaternion(); 917
918 if (scalet != 0)
919 f.RepeatV = scalet;
920
921 if (textures.Count > textureNum)
922 f.TextureID = textures[textureNum];
923 else
924 f.TextureID = Primitive.TextureEntry.WHITE_TEXTURE;
925
926 textureEntry.FaceTextures[face] = f;
927 }
928
929 pbs.TextureEntry = textureEntry.GetBytes();
930
931 bool hasmesh = false;
932 if (inner_instance_list.ContainsKey("mesh")) // seems to happen always but ...
933 {
934 int meshindx = inner_instance_list["mesh"].AsInteger();
935 if (meshAssets.Count > meshindx)
936 {
937 pbs.SculptEntry = true;
938 pbs.SculptType = (byte)SculptType.Mesh;
939 pbs.SculptTexture = meshAssets[meshindx]; // actual asset UUID after meshs suport introduction
940 // data will be requested from asset on rez (i hope)
941 hasmesh = true;
942 }
943 }
944
945 Vector3 position = inner_instance_list["position"].AsVector3();
946 Quaternion rotation = inner_instance_list["rotation"].AsQuaternion();
947
948 // for now viwers do send fixed defaults
949 // but this may change
950// int physicsShapeType = inner_instance_list["physics_shape_type"].AsInteger();
951 byte physicsShapeType = (byte)PhysShapeType.prim; // default for mesh is simple convex
952 if(hasmesh)
953 physicsShapeType = (byte) PhysShapeType.convex; // default for mesh is simple convex
954// int material = inner_instance_list["material"].AsInteger();
955 byte material = (byte)Material.Wood;
610 956
611// no longer used - begin ------------------------ 957// no longer used - begin ------------------------
612// int physicsShapeType = inner_instance_list["physics_shape_type"].AsInteger();
613// int material = inner_instance_list["material"].AsInteger();
614// int mesh = inner_instance_list["mesh"].AsInteger(); 958// int mesh = inner_instance_list["mesh"].AsInteger();
615 959
616// OSDMap permissions = (OSDMap)inner_instance_list["permissions"]; 960// OSDMap permissions = (OSDMap)inner_instance_list["permissions"];
@@ -625,24 +969,49 @@ namespace OpenSim.Region.ClientStack.Linden
625// UUID owner_id = permissions["owner_id"].AsUUID(); 969// UUID owner_id = permissions["owner_id"].AsUUID();
626// int owner_mask = permissions["owner_mask"].AsInteger(); 970// int owner_mask = permissions["owner_mask"].AsInteger();
627// no longer used - end ------------------------ 971// no longer used - end ------------------------
972
973
974 SceneObjectPart prim
975 = new SceneObjectPart(owner_id, pbs, position, Quaternion.Identity, Vector3.Zero);
976
977 prim.Scale = scale;
978 rotations.Add(rotation);
979 positions.Add(position);
980 prim.UUID = UUID.Random();
981 prim.CreatorID = creatorID;
982 prim.OwnerID = owner_id;
983 prim.GroupID = UUID.Zero;
984 prim.LastOwnerID = creatorID;
985 prim.CreationDate = Util.UnixTimeSinceEpoch();
986
987 if (grp == null)
988 prim.Name = assetName;
989 else
990 prim.Name = assetName + "#" + i.ToString();
628 991
629 UUID owner_id = m_HostCapsObj.AgentID; 992 prim.EveryoneMask = 0;
993 prim.GroupMask = 0;
630 994
631 SceneObjectPart prim 995 if (restrictPerms)
632 = new SceneObjectPart(owner_id, pbs, position, Quaternion.Identity, Vector3.Zero); 996 {
997 prim.BaseMask = (uint)(PermissionMask.Move | PermissionMask.Modify);
998 prim.OwnerMask = (uint)(PermissionMask.Move | PermissionMask.Modify);
999 prim.NextOwnerMask = 0;
1000 }
1001 else
1002 {
1003 prim.BaseMask = (uint)PermissionMask.All | (uint)PermissionMask.Export;
1004 prim.OwnerMask = (uint)PermissionMask.All | (uint)PermissionMask.Export;
1005 prim.NextOwnerMask = (uint)PermissionMask.Transfer;
1006 }
1007
1008 if(istest)
1009 prim.Description = "For testing only. Other uses are prohibited";
1010 else
1011 prim.Description = "";
633 1012
634 prim.Scale = scale; 1013 prim.Material = material;
635 //prim.OffsetPosition = position; 1014 prim.PhysicsShapeType = physicsShapeType;
636 rotations.Add(rotation);
637 positions.Add(position);
638 prim.UUID = UUID.Random();
639 prim.CreatorID = owner_id;
640 prim.OwnerID = owner_id;
641 prim.GroupID = UUID.Zero;
642 prim.LastOwnerID = prim.OwnerID;
643 prim.CreationDate = Util.UnixTimeSinceEpoch();
644 prim.Name = assetName;
645 prim.Description = "";
646 1015
647// prim.BaseMask = (uint)base_mask; 1016// prim.BaseMask = (uint)base_mask;
648// prim.EveryoneMask = (uint)everyone_mask; 1017// prim.EveryoneMask = (uint)everyone_mask;
@@ -650,52 +1019,64 @@ namespace OpenSim.Region.ClientStack.Linden
650// prim.NextOwnerMask = (uint)next_owner_mask; 1019// prim.NextOwnerMask = (uint)next_owner_mask;
651// prim.OwnerMask = (uint)owner_mask; 1020// prim.OwnerMask = (uint)owner_mask;
652 1021
653 if (grp == null) 1022 if (grp == null)
654 grp = new SceneObjectGroup(prim); 1023 {
655 else 1024 grp = new SceneObjectGroup(prim);
656 grp.AddPart(prim); 1025 grp.LastOwnerID = creatorID;
657 } 1026 }
1027 else
1028 grp.AddPart(prim);
1029 }
658 1030
659 Vector3 rootPos = positions[0]; 1031 Vector3 rootPos = positions[0];
660 1032
661 if (grp.Parts.Length > 1) 1033 if (grp.Parts.Length > 1)
662 { 1034 {
663 // Fix first link number 1035 // Fix first link number
664 grp.RootPart.LinkNum++; 1036 grp.RootPart.LinkNum++;
665 1037
666 Quaternion rootRotConj = Quaternion.Conjugate(rotations[0]); 1038 Quaternion rootRotConj = Quaternion.Conjugate(rotations[0]);
667 Quaternion tmprot; 1039 Quaternion tmprot;
668 Vector3 offset; 1040 Vector3 offset;
669 1041
670 // fix children rotations and positions 1042 // fix children rotations and positions
671 for (int i = 1; i < rotations.Count; i++) 1043 for (int i = 1; i < rotations.Count; i++)
672 { 1044 {
673 tmprot = rotations[i]; 1045 tmprot = rotations[i];
674 tmprot = rootRotConj * tmprot; 1046 tmprot = rootRotConj * tmprot;
1047
1048 grp.Parts[i].RotationOffset = tmprot;
675 1049
676 grp.Parts[i].RotationOffset = tmprot; 1050 offset = positions[i] - rootPos;
677 1051
678 offset = positions[i] - rootPos; 1052 offset *= rootRotConj;
1053 grp.Parts[i].OffsetPosition = offset;
1054 }
679 1055
680 offset *= rootRotConj; 1056 grp.AbsolutePosition = rootPos;
681 grp.Parts[i].OffsetPosition = offset; 1057 grp.UpdateGroupRotationR(rotations[0]);
1058 }
1059 else
1060 {
1061 grp.AbsolutePosition = rootPos;
1062 grp.UpdateGroupRotationR(rotations[0]);
682 } 1063 }
683 1064
684 grp.AbsolutePosition = rootPos; 1065 data = ASCIIEncoding.ASCII.GetBytes(SceneObjectSerializer.ToOriginalXmlFormat(grp));
685 grp.UpdateGroupRotationR(rotations[0]);
686 } 1066 }
687 else 1067
1068 else // not a mesh model
688 { 1069 {
689 grp.AbsolutePosition = rootPos; 1070 m_log.ErrorFormat("[CAPS Asset Upload] got unsuported assetType for object upload");
690 grp.UpdateGroupRotationR(rotations[0]); 1071 return;
691 } 1072 }
692
693 data = ASCIIEncoding.ASCII.GetBytes(SceneObjectSerializer.ToOriginalXmlFormat(grp));
694 } 1073 }
695 1074
696 AssetBase asset; 1075 AssetBase asset;
697 asset = new AssetBase(assetID, assetName, assType, m_HostCapsObj.AgentID.ToString()); 1076 asset = new AssetBase(assetID, assetName, assType, creatorIDstr);
698 asset.Data = data; 1077 asset.Data = data;
1078 if (istest)
1079 asset.Local = true;
699 if (AddNewAsset != null) 1080 if (AddNewAsset != null)
700 AddNewAsset(asset); 1081 AddNewAsset(asset);
701 else if (m_assetService != null) 1082 else if (m_assetService != null)
@@ -703,11 +1084,17 @@ namespace OpenSim.Region.ClientStack.Linden
703 1084
704 InventoryItemBase item = new InventoryItemBase(); 1085 InventoryItemBase item = new InventoryItemBase();
705 item.Owner = m_HostCapsObj.AgentID; 1086 item.Owner = m_HostCapsObj.AgentID;
706 item.CreatorId = m_HostCapsObj.AgentID.ToString(); 1087 item.CreatorId = creatorIDstr;
707 item.CreatorData = String.Empty; 1088 item.CreatorData = String.Empty;
708 item.ID = inventoryItem; 1089 item.ID = inventoryItem;
709 item.AssetID = asset.FullID; 1090 item.AssetID = asset.FullID;
710 item.Description = assetDescription; 1091 if (istest)
1092 {
1093 item.Description = "For testing only. Other uses are prohibited";
1094 item.Flags = (uint) (InventoryItemFlags.SharedSingleReference);
1095 }
1096 else
1097 item.Description = assetDescription;
711 item.Name = assetName; 1098 item.Name = assetName;
712 item.AssetType = assType; 1099 item.AssetType = assType;
713 item.InvType = inType; 1100 item.InvType = inType;
@@ -715,18 +1102,56 @@ namespace OpenSim.Region.ClientStack.Linden
715 1102
716 // If we set PermissionMask.All then when we rez the item the next permissions will replace the current 1103 // If we set PermissionMask.All then when we rez the item the next permissions will replace the current
717 // (owner) permissions. This becomes a problem if next permissions are changed. 1104 // (owner) permissions. This becomes a problem if next permissions are changed.
718 item.CurrentPermissions
719 = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer | PermissionMask.Export);
720 1105
721 item.BasePermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export; 1106 if (restrictPerms)
722 item.EveryOnePermissions = 0; 1107 {
723 item.NextPermissions = (uint)PermissionMask.All; 1108 item.BasePermissions = (uint)(PermissionMask.Move | PermissionMask.Modify);
1109 item.CurrentPermissions = (uint)(PermissionMask.Move | PermissionMask.Modify);
1110 item.EveryOnePermissions = 0;
1111 item.NextPermissions = 0;
1112 }
1113 else
1114 {
1115 item.BasePermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export;
1116 item.CurrentPermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export;
1117 item.EveryOnePermissions = 0;
1118 item.NextPermissions = (uint)PermissionMask.Transfer;
1119 }
1120
724 item.CreationDate = Util.UnixTimeSinceEpoch(); 1121 item.CreationDate = Util.UnixTimeSinceEpoch();
725 1122
1123 m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client);
1124
726 if (AddNewInventoryItem != null) 1125 if (AddNewInventoryItem != null)
727 { 1126 {
728 AddNewInventoryItem(m_HostCapsObj.AgentID, item); 1127 if (istest)
1128 {
1129 m_Scene.AddInventoryItem(client, item);
1130/*
1131 AddNewInventoryItem(m_HostCapsObj.AgentID, item, 0);
1132 if (client != null)
1133 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);
1134 */
1135 }
1136 else
1137 {
1138 AddNewInventoryItem(m_HostCapsObj.AgentID, item, (uint)cost);
1139// if (client != null)
1140// {
1141// // let users see anything.. i don't so far
1142// string str;
1143// if (cost > 0)
1144// // dont remember where is money unit name to put here
1145// str = "Upload complete. charged " + cost.ToString() + "$";
1146// else
1147// str = "Upload complete";
1148// client.SendAgentAlertMessage(str, true);
1149// }
1150 }
729 } 1151 }
1152
1153 lock (m_ModelCost)
1154 m_FileAgentInventoryState = FileAgentInventoryState.idle;
730 } 1155 }
731 1156
732 /// <summary> 1157 /// <summary>
@@ -919,6 +1344,120 @@ namespace OpenSim.Region.ClientStack.Linden
919 return response; 1344 return response;
920 } 1345 }
921 1346
1347 public string GetObjectCost(string request, string path,
1348 string param, IOSHttpRequest httpRequest,
1349 IOSHttpResponse httpResponse)
1350 {
1351 OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request);
1352 OSDMap resp = new OSDMap();
1353
1354 OSDArray object_ids = (OSDArray)req["object_ids"];
1355
1356 for (int i = 0; i < object_ids.Count; i++)
1357 {
1358 UUID uuid = object_ids[i].AsUUID();
1359
1360 SceneObjectPart part = m_Scene.GetSceneObjectPart(uuid);
1361
1362 if (part != null)
1363 {
1364 SceneObjectGroup grp = part.ParentGroup;
1365 if (grp != null)
1366 {
1367 float linksetCost;
1368 float linksetPhysCost;
1369 float partCost;
1370 float partPhysCost;
1371
1372 grp.GetResourcesCosts(part, out linksetCost, out linksetPhysCost, out partCost, out partPhysCost);
1373
1374 OSDMap object_data = new OSDMap();
1375 object_data["linked_set_resource_cost"] = linksetCost;
1376 object_data["resource_cost"] = partCost;
1377 object_data["physics_cost"] = partPhysCost;
1378 object_data["linked_set_physics_cost"] = linksetPhysCost;
1379
1380 resp[uuid.ToString()] = object_data;
1381 }
1382 }
1383 }
1384
1385 string response = OSDParser.SerializeLLSDXmlString(resp);
1386 return response;
1387 }
1388
1389 public string ResourceCostSelected(string request, string path,
1390 string param, IOSHttpRequest httpRequest,
1391 IOSHttpResponse httpResponse)
1392 {
1393 OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request);
1394 OSDMap resp = new OSDMap();
1395
1396
1397 float phys=0;
1398 float stream=0;
1399 float simul=0;
1400
1401 if (req.ContainsKey("selected_roots"))
1402 {
1403 OSDArray object_ids = (OSDArray)req["selected_roots"];
1404
1405 // should go by SOG suming costs for all parts
1406 // ll v3 works ok with several objects select we get the list and adds ok
1407 // FS calls per object so results are wrong guess fs bug
1408 for (int i = 0; i < object_ids.Count; i++)
1409 {
1410 UUID uuid = object_ids[i].AsUUID();
1411 float Physc;
1412 float simulc;
1413 float streamc;
1414
1415 SceneObjectGroup grp = m_Scene.GetGroupByPrim(uuid);
1416 if (grp != null)
1417 {
1418 grp.GetSelectedCosts(out Physc, out streamc, out simulc);
1419 phys += Physc;
1420 stream += streamc;
1421 simul += simulc;
1422 }
1423 }
1424 }
1425 else if (req.ContainsKey("selected_prims"))
1426 {
1427 OSDArray object_ids = (OSDArray)req["selected_prims"];
1428
1429 // don't see in use in any of the 2 viewers
1430 // guess it should be for edit linked but... nothing
1431 // should go to SOP per part
1432 for (int i = 0; i < object_ids.Count; i++)
1433 {
1434 UUID uuid = object_ids[i].AsUUID();
1435
1436 SceneObjectPart part = m_Scene.GetSceneObjectPart(uuid);
1437 if (part != null)
1438 {
1439 phys += part.PhysicsCost;
1440 stream += part.StreamingCost;
1441 simul += part.SimulationCost;
1442 }
1443 }
1444 }
1445
1446 if (simul != 0)
1447 {
1448 OSDMap object_data = new OSDMap();
1449
1450 object_data["physics"] = phys;
1451 object_data["streaming"] = stream;
1452 object_data["simulation"] = simul;
1453
1454 resp["selected"] = object_data;
1455 }
1456
1457 string response = OSDParser.SerializeLLSDXmlString(resp);
1458 return response;
1459 }
1460
922 public string UpdateAgentInformation(string request, string path, 1461 public string UpdateAgentInformation(string request, string path,
923 string param, IOSHttpRequest httpRequest, 1462 string param, IOSHttpRequest httpRequest,
924 IOSHttpResponse httpResponse) 1463 IOSHttpResponse httpResponse)
@@ -938,6 +1477,10 @@ namespace OpenSim.Region.ClientStack.Linden
938 1477
939 public class AssetUploader 1478 public class AssetUploader
940 { 1479 {
1480 private static readonly ILog m_log =
1481 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
1482
1483
941 public event UpLoadedAsset OnUpLoad; 1484 public event UpLoadedAsset OnUpLoad;
942 private UpLoadedAsset handlerUpLoad = null; 1485 private UpLoadedAsset handlerUpLoad = null;
943 1486
@@ -952,10 +1495,21 @@ namespace OpenSim.Region.ClientStack.Linden
952 1495
953 private string m_invType = String.Empty; 1496 private string m_invType = String.Empty;
954 private string m_assetType = String.Empty; 1497 private string m_assetType = String.Empty;
1498 private int m_cost;
1499 private string m_error = String.Empty;
1500
1501 private Timer m_timeoutTimer = new Timer();
1502 private UUID m_texturesFolder;
1503 private int m_nreqtextures;
1504 private int m_nreqmeshs;
1505 private int m_nreqinstances;
1506 private bool m_IsAtestUpload;
955 1507
956 public AssetUploader(string assetName, string description, UUID assetID, UUID inventoryItem, 1508 public AssetUploader(string assetName, string description, UUID assetID, UUID inventoryItem,
957 UUID parentFolderID, string invType, string assetType, string path, 1509 UUID parentFolderID, string invType, string assetType, string path,
958 IHttpServer httpServer, bool dumpAssetsToFile) 1510 IHttpServer httpServer, bool dumpAssetsToFile,
1511 int totalCost, UUID texturesFolder, int nreqtextures, int nreqmeshs, int nreqinstances,
1512 bool IsAtestUpload)
959 { 1513 {
960 m_assetName = assetName; 1514 m_assetName = assetName;
961 m_assetDes = description; 1515 m_assetDes = description;
@@ -967,6 +1521,18 @@ namespace OpenSim.Region.ClientStack.Linden
967 m_assetType = assetType; 1521 m_assetType = assetType;
968 m_invType = invType; 1522 m_invType = invType;
969 m_dumpAssetsToFile = dumpAssetsToFile; 1523 m_dumpAssetsToFile = dumpAssetsToFile;
1524 m_cost = totalCost;
1525
1526 m_texturesFolder = texturesFolder;
1527 m_nreqtextures = nreqtextures;
1528 m_nreqmeshs = nreqmeshs;
1529 m_nreqinstances = nreqinstances;
1530 m_IsAtestUpload = IsAtestUpload;
1531
1532 m_timeoutTimer.Elapsed += TimedOut;
1533 m_timeoutTimer.Interval = 120000;
1534 m_timeoutTimer.AutoReset = false;
1535 m_timeoutTimer.Start();
970 } 1536 }
971 1537
972 /// <summary> 1538 /// <summary>
@@ -981,12 +1547,14 @@ namespace OpenSim.Region.ClientStack.Linden
981 UUID inv = inventoryItemID; 1547 UUID inv = inventoryItemID;
982 string res = String.Empty; 1548 string res = String.Empty;
983 LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete(); 1549 LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete();
1550/*
984 uploadComplete.new_asset = newAssetID.ToString(); 1551 uploadComplete.new_asset = newAssetID.ToString();
985 uploadComplete.new_inventory_item = inv; 1552 uploadComplete.new_inventory_item = inv;
986 uploadComplete.state = "complete"; 1553 uploadComplete.state = "complete";
987 1554
988 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete); 1555 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
989 1556*/
1557 m_timeoutTimer.Stop();
990 httpListener.RemoveStreamHandler("POST", uploaderPath); 1558 httpListener.RemoveStreamHandler("POST", uploaderPath);
991 1559
992 // TODO: probably make this a better set of extensions here 1560 // TODO: probably make this a better set of extensions here
@@ -1003,12 +1571,49 @@ namespace OpenSim.Region.ClientStack.Linden
1003 handlerUpLoad = OnUpLoad; 1571 handlerUpLoad = OnUpLoad;
1004 if (handlerUpLoad != null) 1572 if (handlerUpLoad != null)
1005 { 1573 {
1006 handlerUpLoad(m_assetName, m_assetDes, newAssetID, inv, parentFolder, data, m_invType, m_assetType); 1574 handlerUpLoad(m_assetName, m_assetDes, newAssetID, inv, parentFolder, data, m_invType, m_assetType,
1575 m_cost, m_texturesFolder, m_nreqtextures, m_nreqmeshs, m_nreqinstances, m_IsAtestUpload, ref m_error);
1576 }
1577 if (m_IsAtestUpload)
1578 {
1579 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
1580 resperror.message = "Upload SUCESSEFULL for testing purposes only. Other uses are prohibited. Item will not work after 48 hours or on other regions";
1581 resperror.identifier = inv;
1582
1583 uploadComplete.error = resperror;
1584 uploadComplete.state = "Upload4Testing";
1007 } 1585 }
1586 else
1587 {
1588 if (m_error == String.Empty)
1589 {
1590 uploadComplete.new_asset = newAssetID.ToString();
1591 uploadComplete.new_inventory_item = inv;
1592 // if (m_texturesFolder != UUID.Zero)
1593 // uploadComplete.new_texture_folder_id = m_texturesFolder;
1594 uploadComplete.state = "complete";
1595 }
1596 else
1597 {
1598 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
1599 resperror.message = m_error;
1600 resperror.identifier = inv;
1008 1601
1602 uploadComplete.error = resperror;
1603 uploadComplete.state = "failed";
1604 }
1605 }
1606
1607 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
1009 return res; 1608 return res;
1010 } 1609 }
1011 1610
1611 private void TimedOut(object sender, ElapsedEventArgs args)
1612 {
1613 m_log.InfoFormat("[CAPS]: Removing URL and handler for timed out mesh upload");
1614 httpListener.RemoveStreamHandler("POST", uploaderPath);
1615 }
1616
1012 ///Left this in and commented in case there are unforseen issues 1617 ///Left this in and commented in case there are unforseen issues
1013 //private void SaveAssetToFile(string filename, byte[] data) 1618 //private void SaveAssetToFile(string filename, byte[] data)
1014 //{ 1619 //{
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..e053054 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,39 @@ 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 string m_Url = "localhost";
64 81
65 // TODO: Change this to a config option 82 private static OpenMetaverse.BlockingQueue<aPollRequest> m_queue =
66 const string REDIRECT_URL = null; 83 new OpenMetaverse.BlockingQueue<aPollRequest>();
84
85 private Dictionary<UUID,PollServiceTextureEventArgs> m_pollservices = new Dictionary<UUID,PollServiceTextureEventArgs>();
67 86
68 private string m_URL; 87 private string m_URL;
69 88
@@ -72,39 +91,98 @@ namespace OpenSim.Region.ClientStack.Linden
72 public void Initialise(IConfigSource source) 91 public void Initialise(IConfigSource source)
73 { 92 {
74 IConfig config = source.Configs["ClientStack.LindenCaps"]; 93 IConfig config = source.Configs["ClientStack.LindenCaps"];
75 if (config == null) 94 if (config != null)
76 return; 95 m_Url = config.GetString("Cap_GetTexture", "localhost");
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 } 96 }
83 97
84 public void AddRegion(Scene s) 98 public void AddRegion(Scene s)
85 { 99 {
86 if (!m_Enabled)
87 return;
88
89 m_scene = s; 100 m_scene = s;
101 m_assetService = s.AssetService;
90 } 102 }
91 103
92 public void RemoveRegion(Scene s) 104 public void RemoveRegion(Scene s)
93 { 105 {
94 if (!m_Enabled)
95 return;
96
97 m_scene.EventManager.OnRegisterCaps -= RegisterCaps; 106 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
107 m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps;
108 m_scene.EventManager.OnThrottleUpdate -= ThrottleUpdate;
98 m_scene = null; 109 m_scene = null;
99 } 110 }
100 111
101 public void RegionLoaded(Scene s) 112 public void RegionLoaded(Scene s)
102 { 113 {
103 if (!m_Enabled) 114 // We'll reuse the same handler for all requests.
104 return; 115 m_getTextureHandler = new GetTextureHandler(m_assetService);
105 116
106 m_assetService = m_scene.RequestModuleInterface<IAssetService>();
107 m_scene.EventManager.OnRegisterCaps += RegisterCaps; 117 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
118 m_scene.EventManager.OnDeregisterCaps += DeregisterCaps;
119 m_scene.EventManager.OnThrottleUpdate += ThrottleUpdate;
120
121 if (m_workerThreads == null)
122 {
123 m_workerThreads = new Thread[2];
124
125 for (uint i = 0; i < 2; i++)
126 {
127 m_workerThreads[i] = Watchdog.StartThread(DoTextureRequests,
128 String.Format("TextureWorkerThread{0}", i),
129 ThreadPriority.Normal,
130 false,
131 false,
132 null,
133 int.MaxValue);
134 }
135 }
136 }
137 private int ExtractImageThrottle(byte[] pthrottles)
138 {
139
140 byte[] adjData;
141 int pos = 0;
142
143 if (!BitConverter.IsLittleEndian)
144 {
145 byte[] newData = new byte[7 * 4];
146 Buffer.BlockCopy(pthrottles, 0, newData, 0, 7 * 4);
147
148 for (int i = 0; i < 7; i++)
149 Array.Reverse(newData, i * 4, 4);
150
151 adjData = newData;
152 }
153 else
154 {
155 adjData = pthrottles;
156 }
157
158 // 0.125f converts from bits to bytes
159 //int resend = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
160 //pos += 4;
161 // int land = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
162 //pos += 4;
163 // int wind = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
164 // pos += 4;
165 // int cloud = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
166 // pos += 4;
167 // int task = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
168 // pos += 4;
169 pos = pos + 20;
170 int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); //pos += 4;
171 //int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
172 return texture;
173 }
174
175 // 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.
176 public void ThrottleUpdate(ScenePresence p)
177 {
178 byte[] throttles = p.ControllingClient.GetThrottlesPacked(1);
179 UUID user = p.UUID;
180 int imagethrottle = ExtractImageThrottle(throttles);
181 PollServiceTextureEventArgs args;
182 if (m_pollservices.TryGetValue(user,out args))
183 {
184 args.UpdateThrottle(imagethrottle);
185 }
108 } 186 }
109 187
110 public void PostInitialise() 188 public void PostInitialise()
@@ -122,28 +200,290 @@ namespace OpenSim.Region.ClientStack.Linden
122 200
123 #endregion 201 #endregion
124 202
125 public void RegisterCaps(UUID agentID, Caps caps) 203 ~GetTextureModule()
126 { 204 {
127 UUID capID = UUID.Random(); 205 foreach (Thread t in m_workerThreads)
206 Watchdog.AbortThread(t.ManagedThreadId);
128 207
129 //caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture)); 208 }
130 if (m_URL == "localhost") 209
210 private class PollServiceTextureEventArgs : PollServiceEventArgs
211 {
212 private List<Hashtable> requests =
213 new List<Hashtable>();
214 private Dictionary<UUID, aPollResponse> responses =
215 new Dictionary<UUID, aPollResponse>();
216
217 private Scene m_scene;
218 private CapsDataThrottler m_throttler = new CapsDataThrottler(100000, 1400000,10000);
219 public PollServiceTextureEventArgs(UUID pId, Scene scene) :
220 base(null, "", null, null, null, pId, int.MaxValue)
131 { 221 {
132// m_log.DebugFormat("[GETTEXTURE]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName); 222 m_scene = scene;
133 caps.RegisterHandler( 223 // x is request id, y is userid
134 "GetTexture", 224 HasEvents = (x, y) =>
135 new GetTextureHandler("/CAPS/" + capID + "/", m_assetService, "GetTexture", agentID.ToString())); 225 {
226 lock (responses)
227 {
228 bool ret = m_throttler.hasEvents(x, responses);
229 m_throttler.ProcessTime();
230 return ret;
231
232 }
233 };
234 GetEvents = (x, y) =>
235 {
236 lock (responses)
237 {
238 try
239 {
240 return responses[x].response;
241 }
242 finally
243 {
244 responses.Remove(x);
245 }
246 }
247 };
248 // x is request id, y is request data hashtable
249 Request = (x, y) =>
250 {
251 aPollRequest reqinfo = new aPollRequest();
252 reqinfo.thepoll = this;
253 reqinfo.reqID = x;
254 reqinfo.request = y;
255 reqinfo.send503 = false;
256
257 lock (responses)
258 {
259 if (responses.Count > 0)
260 {
261 if (m_queue.Count >= 4)
262 {
263 // Never allow more than 4 fetches to wait
264 reqinfo.send503 = true;
265 }
266 }
267 }
268 m_queue.Enqueue(reqinfo);
269 };
270
271 // this should never happen except possible on shutdown
272 NoEvents = (x, y) =>
273 {
274/*
275 lock (requests)
276 {
277 Hashtable request = requests.Find(id => id["RequestID"].ToString() == x.ToString());
278 requests.Remove(request);
279 }
280*/
281 Hashtable response = new Hashtable();
282
283 response["int_response_code"] = 500;
284 response["str_response_string"] = "Script timeout";
285 response["content_type"] = "text/plain";
286 response["keepalive"] = false;
287 response["reusecontext"] = false;
288
289 return response;
290 };
136 } 291 }
137 else 292
293 public void Process(aPollRequest requestinfo)
138 { 294 {
139// m_log.DebugFormat("[GETTEXTURE]: {0} in region {1}", m_URL, m_scene.RegionInfo.RegionName); 295 Hashtable response;
296
297 UUID requestID = requestinfo.reqID;
298
299 if (requestinfo.send503)
300 {
301 response = new Hashtable();
302
303 response["int_response_code"] = 503;
304 response["str_response_string"] = "Throttled";
305 response["content_type"] = "text/plain";
306 response["keepalive"] = false;
307 response["reusecontext"] = false;
308
309 lock (responses)
310 responses[requestID] = new aPollResponse() {bytes = 0, response = response};
311
312 return;
313 }
314
315 // If the avatar is gone, don't bother to get the texture
316 if (m_scene.GetScenePresence(Id) == null)
317 {
318 response = new Hashtable();
319
320 response["int_response_code"] = 500;
321 response["str_response_string"] = "Script timeout";
322 response["content_type"] = "text/plain";
323 response["keepalive"] = false;
324 response["reusecontext"] = false;
325
326 lock (responses)
327 responses[requestID] = new aPollResponse() {bytes = 0, response = response};
328
329 return;
330 }
331
332 response = m_getTextureHandler.Handle(requestinfo.request);
333 lock (responses)
334 {
335 responses[requestID] = new aPollResponse()
336 {
337 bytes = (int) response["int_bytes"],
338 response = response
339 };
340
341 }
342 m_throttler.ProcessTime();
343 }
344
345 internal void UpdateThrottle(int pimagethrottle)
346 {
347 m_throttler.ThrottleBytes = pimagethrottle;
348 }
349 }
350
351 private void RegisterCaps(UUID agentID, Caps caps)
352 {
353 if (m_Url == "localhost")
354 {
355 string capUrl = "/CAPS/" + UUID.Random() + "/";
356
357 // Register this as a poll service
358 PollServiceTextureEventArgs args = new PollServiceTextureEventArgs(agentID, m_scene);
359
360 args.Type = PollServiceEventArgs.EventType.Texture;
361 MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args);
362
363 string hostName = m_scene.RegionInfo.ExternalHostName;
364 uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port;
365 string protocol = "http";
366
367 if (MainServer.Instance.UseSSL)
368 {
369 hostName = MainServer.Instance.SSLCommonName;
370 port = MainServer.Instance.SSLPort;
371 protocol = "https";
372 }
140 IExternalCapsModule handler = m_scene.RequestModuleInterface<IExternalCapsModule>(); 373 IExternalCapsModule handler = m_scene.RequestModuleInterface<IExternalCapsModule>();
141 if (handler != null) 374 if (handler != null)
142 handler.RegisterExternalUserCapsHandler(agentID,caps,"GetTexture",m_URL); 375 handler.RegisterExternalUserCapsHandler(agentID, caps, "GetTexture", capUrl);
143 else 376 else
144 caps.RegisterHandler("GetTexture", m_URL); 377 caps.RegisterHandler("GetTexture", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl));
378 m_pollservices[agentID] = args;
379 m_capsDict[agentID] = capUrl;
380 }
381 else
382 {
383 caps.RegisterHandler("GetTexture", m_Url);
145 } 384 }
146 } 385 }
147 386
387 private void DeregisterCaps(UUID agentID, Caps caps)
388 {
389 PollServiceTextureEventArgs args;
390
391 MainServer.Instance.RemoveHTTPHandler("", m_URL);
392 m_capsDict.Remove(agentID);
393
394 if (m_pollservices.TryGetValue(agentID, out args))
395 {
396 m_pollservices.Remove(agentID);
397 }
398 }
399
400 private void DoTextureRequests()
401 {
402 while (true)
403 {
404 aPollRequest poolreq = m_queue.Dequeue();
405
406 poolreq.thepoll.Process(poolreq);
407 }
408 }
409 internal sealed class CapsDataThrottler
410 {
411
412 private volatile int currenttime = 0;
413 private volatile int lastTimeElapsed = 0;
414 private volatile int BytesSent = 0;
415 private int oversizedImages = 0;
416 public CapsDataThrottler(int pBytes, int max, int min)
417 {
418 ThrottleBytes = pBytes;
419 lastTimeElapsed = Util.EnvironmentTickCount();
420 }
421 public bool hasEvents(UUID key, Dictionary<UUID, GetTextureModule.aPollResponse> responses)
422 {
423 PassTime();
424 // Note, this is called IN LOCK
425 bool haskey = responses.ContainsKey(key);
426 if (!haskey)
427 {
428 return false;
429 }
430 GetTextureModule.aPollResponse response;
431 if (responses.TryGetValue(key, out response))
432 {
433 // This is any error response
434 if (response.bytes == 0)
435 return true;
436
437 // Normal
438 if (BytesSent + response.bytes <= ThrottleBytes)
439 {
440 BytesSent += response.bytes;
441 //TimeBasedAction timeBasedAction = new TimeBasedAction { byteRemoval = response.bytes, requestId = key, timeMS = currenttime + 1000, unlockyn = false };
442 //m_actions.Add(timeBasedAction);
443 return true;
444 }
445 // Big textures
446 else if (response.bytes > ThrottleBytes && oversizedImages <= ((ThrottleBytes % 50000) + 1))
447 {
448 Interlocked.Increment(ref oversizedImages);
449 BytesSent += response.bytes;
450 //TimeBasedAction timeBasedAction = new TimeBasedAction { byteRemoval = response.bytes, requestId = key, timeMS = currenttime + (((response.bytes % ThrottleBytes)+1)*1000) , unlockyn = false };
451 //m_actions.Add(timeBasedAction);
452 return true;
453 }
454 else
455 {
456 return false;
457 }
458 }
459
460 return haskey;
461 }
462
463 public void ProcessTime()
464 {
465 PassTime();
466 }
467
468 private void PassTime()
469 {
470 currenttime = Util.EnvironmentTickCount();
471 int timeElapsed = Util.EnvironmentTickCountSubtract(currenttime, lastTimeElapsed);
472 //processTimeBasedActions(responses);
473 if (Util.EnvironmentTickCountSubtract(currenttime, timeElapsed) >= 1000)
474 {
475 lastTimeElapsed = Util.EnvironmentTickCount();
476 BytesSent -= ThrottleBytes;
477 if (BytesSent < 0) BytesSent = 0;
478 if (BytesSent < ThrottleBytes)
479 {
480 oversizedImages = 0;
481 }
482 }
483 }
484 public int ThrottleBytes;
485 }
148 } 486 }
487
488
149} 489}
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 4501dd9..47988dd 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
@@ -129,4 +311,4 @@ namespace OpenSim.Region.ClientStack.Linden
129 } 311 }
130 } 312 }
131 } 313 }
132} \ 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 340d2e7..6fc35cd 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 6cb7332..f8e2a60 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)
@@ -1646,7 +1639,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1646 1639
1647 public void SendKillObject(List<uint> localIDs) 1640 public void SendKillObject(List<uint> localIDs)
1648 { 1641 {
1649// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, localID, regionHandle); 1642// foreach (uint id in localIDs)
1643// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, id, regionHandle);
1650 1644
1651 KillObjectPacket kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject); 1645 KillObjectPacket kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject);
1652 // TODO: don't create new blocks if recycling an old packet 1646 // TODO: don't create new blocks if recycling an old packet
@@ -1668,17 +1662,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1668 // We MUST lock for both manipulating the kill record and sending the packet, in order to avoid a race 1662 // We MUST lock for both manipulating the kill record and sending the packet, in order to avoid a race
1669 // condition where a kill can be processed before an out-of-date update for the same object. 1663 // condition where a kill can be processed before an out-of-date update for the same object.
1670 // ProcessEntityUpdates() also takes the m_killRecord lock. 1664 // ProcessEntityUpdates() also takes the m_killRecord lock.
1671 lock (m_killRecord) 1665// lock (m_killRecord)
1672 { 1666// {
1673 foreach (uint localID in localIDs) 1667// foreach (uint localID in localIDs)
1674 m_killRecord.Add(localID); 1668// m_killRecord.Add(localID);
1675 1669
1676 // The throttle queue used here must match that being used for updates. Otherwise, there is a 1670 // The throttle queue used here must match that being used for updates. Otherwise, there is a
1677 // chance that a kill packet put on a separate queue will be sent to the client before an existing 1671 // chance that a kill packet put on a separate queue will be sent to the client before an existing
1678 // update packet on another queue. Receiving updates after kills results in unowned and undeletable 1672 // update packet on another queue. Receiving updates after kills results in unowned and undeletable
1679 // scene objects in a viewer until that viewer is relogged in. 1673 // scene objects in a viewer until that viewer is relogged in.
1680 OutPacket(kill, ThrottleOutPacketType.Task); 1674 OutPacket(kill, ThrottleOutPacketType.Task);
1681 } 1675// }
1682 } 1676 }
1683 } 1677 }
1684 1678
@@ -1800,7 +1794,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1800 newBlock.CreationDate = item.CreationDate; 1794 newBlock.CreationDate = item.CreationDate;
1801 newBlock.SalePrice = item.SalePrice; 1795 newBlock.SalePrice = item.SalePrice;
1802 newBlock.SaleType = item.SaleType; 1796 newBlock.SaleType = item.SaleType;
1803 newBlock.Flags = item.Flags; 1797 newBlock.Flags = item.Flags & 0xff;
1804 1798
1805 newBlock.CRC = 1799 newBlock.CRC =
1806 Helpers.InventoryCRC(newBlock.CreationDate, newBlock.SaleType, 1800 Helpers.InventoryCRC(newBlock.CreationDate, newBlock.SaleType,
@@ -2054,7 +2048,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2054 itemBlock.GroupID = item.GroupID; 2048 itemBlock.GroupID = item.GroupID;
2055 itemBlock.GroupOwned = item.GroupOwned; 2049 itemBlock.GroupOwned = item.GroupOwned;
2056 itemBlock.GroupMask = item.GroupPermissions; 2050 itemBlock.GroupMask = item.GroupPermissions;
2057 itemBlock.Flags = item.Flags; 2051 itemBlock.Flags = item.Flags & 0xff;
2058 itemBlock.SalePrice = item.SalePrice; 2052 itemBlock.SalePrice = item.SalePrice;
2059 itemBlock.SaleType = item.SaleType; 2053 itemBlock.SaleType = item.SaleType;
2060 itemBlock.CreationDate = item.CreationDate; 2054 itemBlock.CreationDate = item.CreationDate;
@@ -2121,7 +2115,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2121 bulkUpdate.ItemData[0].GroupID = item.GroupID; 2115 bulkUpdate.ItemData[0].GroupID = item.GroupID;
2122 bulkUpdate.ItemData[0].GroupOwned = item.GroupOwned; 2116 bulkUpdate.ItemData[0].GroupOwned = item.GroupOwned;
2123 bulkUpdate.ItemData[0].GroupMask = item.GroupPermissions; 2117 bulkUpdate.ItemData[0].GroupMask = item.GroupPermissions;
2124 bulkUpdate.ItemData[0].Flags = item.Flags; 2118 bulkUpdate.ItemData[0].Flags = item.Flags & 0xff;
2125 bulkUpdate.ItemData[0].SalePrice = item.SalePrice; 2119 bulkUpdate.ItemData[0].SalePrice = item.SalePrice;
2126 bulkUpdate.ItemData[0].SaleType = item.SaleType; 2120 bulkUpdate.ItemData[0].SaleType = item.SaleType;
2127 2121
@@ -2137,9 +2131,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2137 OutPacket(bulkUpdate, ThrottleOutPacketType.Asset); 2131 OutPacket(bulkUpdate, ThrottleOutPacketType.Asset);
2138 } 2132 }
2139 2133
2140 /// <see>IClientAPI.SendInventoryItemCreateUpdate(InventoryItemBase)</see>
2141 public void SendInventoryItemCreateUpdate(InventoryItemBase Item, uint callbackId) 2134 public void SendInventoryItemCreateUpdate(InventoryItemBase Item, uint callbackId)
2142 { 2135 {
2136 SendInventoryItemCreateUpdate(Item, UUID.Zero, callbackId);
2137 }
2138
2139 /// <see>IClientAPI.SendInventoryItemCreateUpdate(InventoryItemBase)</see>
2140 public void SendInventoryItemCreateUpdate(InventoryItemBase Item, UUID transactionID, uint callbackId)
2141 {
2143 const uint FULL_MASK_PERMISSIONS = (uint)0x7fffffff; 2142 const uint FULL_MASK_PERMISSIONS = (uint)0x7fffffff;
2144 2143
2145 UpdateCreateInventoryItemPacket InventoryReply 2144 UpdateCreateInventoryItemPacket InventoryReply
@@ -2149,6 +2148,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2149 // TODO: don't create new blocks if recycling an old packet 2148 // TODO: don't create new blocks if recycling an old packet
2150 InventoryReply.AgentData.AgentID = AgentId; 2149 InventoryReply.AgentData.AgentID = AgentId;
2151 InventoryReply.AgentData.SimApproved = true; 2150 InventoryReply.AgentData.SimApproved = true;
2151 InventoryReply.AgentData.TransactionID = transactionID;
2152 InventoryReply.InventoryData = new UpdateCreateInventoryItemPacket.InventoryDataBlock[1]; 2152 InventoryReply.InventoryData = new UpdateCreateInventoryItemPacket.InventoryDataBlock[1];
2153 InventoryReply.InventoryData[0] = new UpdateCreateInventoryItemPacket.InventoryDataBlock(); 2153 InventoryReply.InventoryData[0] = new UpdateCreateInventoryItemPacket.InventoryDataBlock();
2154 InventoryReply.InventoryData[0].ItemID = Item.ID; 2154 InventoryReply.InventoryData[0].ItemID = Item.ID;
@@ -2169,7 +2169,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2169 InventoryReply.InventoryData[0].GroupID = Item.GroupID; 2169 InventoryReply.InventoryData[0].GroupID = Item.GroupID;
2170 InventoryReply.InventoryData[0].GroupOwned = Item.GroupOwned; 2170 InventoryReply.InventoryData[0].GroupOwned = Item.GroupOwned;
2171 InventoryReply.InventoryData[0].GroupMask = Item.GroupPermissions; 2171 InventoryReply.InventoryData[0].GroupMask = Item.GroupPermissions;
2172 InventoryReply.InventoryData[0].Flags = Item.Flags; 2172 InventoryReply.InventoryData[0].Flags = Item.Flags & 0xff;
2173 InventoryReply.InventoryData[0].SalePrice = Item.SalePrice; 2173 InventoryReply.InventoryData[0].SalePrice = Item.SalePrice;
2174 InventoryReply.InventoryData[0].SaleType = Item.SaleType; 2174 InventoryReply.InventoryData[0].SaleType = Item.SaleType;
2175 InventoryReply.InventoryData[0].CreationDate = Item.CreationDate; 2175 InventoryReply.InventoryData[0].CreationDate = Item.CreationDate;
@@ -2218,16 +2218,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2218 replytask.InventoryData.TaskID = taskID; 2218 replytask.InventoryData.TaskID = taskID;
2219 replytask.InventoryData.Serial = serial; 2219 replytask.InventoryData.Serial = serial;
2220 replytask.InventoryData.Filename = fileName; 2220 replytask.InventoryData.Filename = fileName;
2221 OutPacket(replytask, ThrottleOutPacketType.Asset); 2221 OutPacket(replytask, ThrottleOutPacketType.Task);
2222 } 2222 }
2223 2223
2224 public void SendXferPacket(ulong xferID, uint packet, byte[] data) 2224 public void SendXferPacket(ulong xferID, uint packet, byte[] data, bool isTaskInventory)
2225 { 2225 {
2226 ThrottleOutPacketType type = ThrottleOutPacketType.Asset;
2227 if (isTaskInventory)
2228 type = ThrottleOutPacketType.Task;
2229
2226 SendXferPacketPacket sendXfer = (SendXferPacketPacket)PacketPool.Instance.GetPacket(PacketType.SendXferPacket); 2230 SendXferPacketPacket sendXfer = (SendXferPacketPacket)PacketPool.Instance.GetPacket(PacketType.SendXferPacket);
2227 sendXfer.XferID.ID = xferID; 2231 sendXfer.XferID.ID = xferID;
2228 sendXfer.XferID.Packet = packet; 2232 sendXfer.XferID.Packet = packet;
2229 sendXfer.DataPacket.Data = data; 2233 sendXfer.DataPacket.Data = data;
2230 OutPacket(sendXfer, ThrottleOutPacketType.Asset); 2234 OutPacket(sendXfer, type);
2231 } 2235 }
2232 2236
2233 public void SendAbortXferPacket(ulong xferID) 2237 public void SendAbortXferPacket(ulong xferID)
@@ -2414,6 +2418,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2414 OutPacket(sound, ThrottleOutPacketType.Task); 2418 OutPacket(sound, ThrottleOutPacketType.Task);
2415 } 2419 }
2416 2420
2421 public void SendTransferAbort(TransferRequestPacket transferRequest)
2422 {
2423 TransferAbortPacket abort = (TransferAbortPacket)PacketPool.Instance.GetPacket(PacketType.TransferAbort);
2424 abort.TransferInfo.TransferID = transferRequest.TransferInfo.TransferID;
2425 abort.TransferInfo.ChannelType = transferRequest.TransferInfo.ChannelType;
2426 m_log.Debug("[Assets] Aborting transfer; asset request failed");
2427 OutPacket(abort, ThrottleOutPacketType.Task);
2428 }
2429
2417 public void SendTriggeredSound(UUID soundID, UUID ownerID, UUID objectID, UUID parentID, ulong handle, Vector3 position, float gain) 2430 public void SendTriggeredSound(UUID soundID, UUID ownerID, UUID objectID, UUID parentID, ulong handle, Vector3 position, float gain)
2418 { 2431 {
2419 SoundTriggerPacket sound = (SoundTriggerPacket)PacketPool.Instance.GetPacket(PacketType.SoundTrigger); 2432 SoundTriggerPacket sound = (SoundTriggerPacket)PacketPool.Instance.GetPacket(PacketType.SoundTrigger);
@@ -2719,6 +2732,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2719 float friction = part.Friction; 2732 float friction = part.Friction;
2720 float bounce = part.Restitution; 2733 float bounce = part.Restitution;
2721 float gravmod = part.GravityModifier; 2734 float gravmod = part.GravityModifier;
2735
2722 eq.partPhysicsProperties(localid, physshapetype, density, friction, bounce, gravmod,AgentId); 2736 eq.partPhysicsProperties(localid, physshapetype, density, friction, bounce, gravmod,AgentId);
2723 } 2737 }
2724 } 2738 }
@@ -2789,8 +2803,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2789 req.AssetInf.ID, req.AssetInf.Metadata.ContentType); 2803 req.AssetInf.ID, req.AssetInf.Metadata.ContentType);
2790 return; 2804 return;
2791 } 2805 }
2806 int WearableOut = 0;
2807 bool isWearable = false;
2808
2809 if (req.AssetInf != null)
2810 isWearable =
2811 ((AssetType) req.AssetInf.Type ==
2812 AssetType.Bodypart || (AssetType) req.AssetInf.Type == AssetType.Clothing);
2792 2813
2793 //m_log.Debug("sending asset " + req.RequestAssetID); 2814
2815 //m_log.Debug("sending asset " + req.RequestAssetID + ", iswearable: " + isWearable);
2816
2817
2818 //if (isWearable)
2819 // m_log.Debug((AssetType)req.AssetInf.Type);
2820
2794 TransferInfoPacket Transfer = new TransferInfoPacket(); 2821 TransferInfoPacket Transfer = new TransferInfoPacket();
2795 Transfer.TransferInfo.ChannelType = 2; 2822 Transfer.TransferInfo.ChannelType = 2;
2796 Transfer.TransferInfo.Status = 0; 2823 Transfer.TransferInfo.Status = 0;
@@ -2812,7 +2839,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2812 Transfer.TransferInfo.Size = req.AssetInf.Data.Length; 2839 Transfer.TransferInfo.Size = req.AssetInf.Data.Length;
2813 Transfer.TransferInfo.TransferID = req.TransferRequestID; 2840 Transfer.TransferInfo.TransferID = req.TransferRequestID;
2814 Transfer.Header.Zerocoded = true; 2841 Transfer.Header.Zerocoded = true;
2815 OutPacket(Transfer, ThrottleOutPacketType.Asset); 2842 OutPacket(Transfer, isWearable ? ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority : ThrottleOutPacketType.Asset);
2816 2843
2817 if (req.NumPackets == 1) 2844 if (req.NumPackets == 1)
2818 { 2845 {
@@ -2823,12 +2850,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2823 TransferPacket.TransferData.Data = req.AssetInf.Data; 2850 TransferPacket.TransferData.Data = req.AssetInf.Data;
2824 TransferPacket.TransferData.Status = 1; 2851 TransferPacket.TransferData.Status = 1;
2825 TransferPacket.Header.Zerocoded = true; 2852 TransferPacket.Header.Zerocoded = true;
2826 OutPacket(TransferPacket, ThrottleOutPacketType.Asset); 2853 OutPacket(TransferPacket, isWearable ? ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority : ThrottleOutPacketType.Asset);
2827 } 2854 }
2828 else 2855 else
2829 { 2856 {
2830 int processedLength = 0; 2857 int processedLength = 0;
2831 int maxChunkSize = Settings.MAX_PACKET_SIZE - 100; 2858// int maxChunkSize = Settings.MAX_PACKET_SIZE - 100;
2859
2860 int maxChunkSize = (int) MaxTransferBytesPerPacket;
2832 int packetNumber = 0; 2861 int packetNumber = 0;
2833 2862
2834 while (processedLength < req.AssetInf.Data.Length) 2863 while (processedLength < req.AssetInf.Data.Length)
@@ -2854,7 +2883,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2854 TransferPacket.TransferData.Status = 1; 2883 TransferPacket.TransferData.Status = 1;
2855 } 2884 }
2856 TransferPacket.Header.Zerocoded = true; 2885 TransferPacket.Header.Zerocoded = true;
2857 OutPacket(TransferPacket, ThrottleOutPacketType.Asset); 2886 OutPacket(TransferPacket, isWearable ? ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority : ThrottleOutPacketType.Asset);
2858 2887
2859 processedLength += chunkSize; 2888 processedLength += chunkSize;
2860 packetNumber++; 2889 packetNumber++;
@@ -2899,7 +2928,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2899 reply.Data.ParcelID = parcelID; 2928 reply.Data.ParcelID = parcelID;
2900 reply.Data.OwnerID = land.OwnerID; 2929 reply.Data.OwnerID = land.OwnerID;
2901 reply.Data.Name = Utils.StringToBytes(land.Name); 2930 reply.Data.Name = Utils.StringToBytes(land.Name);
2902 reply.Data.Desc = Utils.StringToBytes(land.Description); 2931 if (land != null && land.Description != null && land.Description != String.Empty)
2932 reply.Data.Desc = Utils.StringToBytes(land.Description.Substring(0, land.Description.Length > 254 ? 254: land.Description.Length));
2933 else
2934 reply.Data.Desc = new Byte[0];
2903 reply.Data.ActualArea = land.Area; 2935 reply.Data.ActualArea = land.Area;
2904 reply.Data.BillableArea = land.Area; // TODO: what is this? 2936 reply.Data.BillableArea = land.Area; // TODO: what is this?
2905 2937
@@ -3606,24 +3638,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3606 aw.WearableData = new AgentWearablesUpdatePacket.WearableDataBlock[count]; 3638 aw.WearableData = new AgentWearablesUpdatePacket.WearableDataBlock[count];
3607 AgentWearablesUpdatePacket.WearableDataBlock awb; 3639 AgentWearablesUpdatePacket.WearableDataBlock awb;
3608 int idx = 0; 3640 int idx = 0;
3609 for (int i = 0; i < wearables.Length; i++) 3641
3610 { 3642 for (int i = 0; i < wearables.Length; i++)
3611 for (int j = 0; j < wearables[i].Count; j++) 3643 {
3612 { 3644 for (int j = 0; j < wearables[i].Count; j++)
3613 awb = new AgentWearablesUpdatePacket.WearableDataBlock(); 3645 {
3614 awb.WearableType = (byte)i; 3646 awb = new AgentWearablesUpdatePacket.WearableDataBlock();
3615 awb.AssetID = wearables[i][j].AssetID; 3647 awb.WearableType = (byte) i;
3616 awb.ItemID = wearables[i][j].ItemID; 3648 awb.AssetID = wearables[i][j].AssetID;
3617 aw.WearableData[idx] = awb; 3649 awb.ItemID = wearables[i][j].ItemID;
3618 idx++; 3650 aw.WearableData[idx] = awb;
3619 3651 idx++;
3620// m_log.DebugFormat( 3652
3621// "[APPEARANCE]: Sending wearable item/asset {0} {1} (index {2}) for {3}", 3653 // m_log.DebugFormat(
3622// awb.ItemID, awb.AssetID, i, Name); 3654 // "[APPEARANCE]: Sending wearable item/asset {0} {1} (index {2}) for {3}",
3623 } 3655 // awb.ItemID, awb.AssetID, i, Name);
3624 } 3656 }
3657 }
3625 3658
3626 OutPacket(aw, ThrottleOutPacketType.Task); 3659 OutPacket(aw, ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority);
3627 } 3660 }
3628 3661
3629 public void SendAppearance(UUID agentID, byte[] visualParams, byte[] textureEntry) 3662 public void SendAppearance(UUID agentID, byte[] visualParams, byte[] textureEntry)
@@ -3634,7 +3667,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3634 3667
3635 AvatarAppearancePacket avp = (AvatarAppearancePacket)PacketPool.Instance.GetPacket(PacketType.AvatarAppearance); 3668 AvatarAppearancePacket avp = (AvatarAppearancePacket)PacketPool.Instance.GetPacket(PacketType.AvatarAppearance);
3636 // TODO: don't create new blocks if recycling an old packet 3669 // TODO: don't create new blocks if recycling an old packet
3637 avp.VisualParam = new AvatarAppearancePacket.VisualParamBlock[218]; 3670 avp.VisualParam = new AvatarAppearancePacket.VisualParamBlock[visualParams.Length];
3638 avp.ObjectData.TextureEntry = textureEntry; 3671 avp.ObjectData.TextureEntry = textureEntry;
3639 3672
3640 AvatarAppearancePacket.VisualParamBlock avblock = null; 3673 AvatarAppearancePacket.VisualParamBlock avblock = null;
@@ -3765,7 +3798,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3765 /// </summary> 3798 /// </summary>
3766 public void SendEntityUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags) 3799 public void SendEntityUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags)
3767 { 3800 {
3768 //double priority = m_prioritizer.GetUpdatePriority(this, entity); 3801 if (entity is SceneObjectPart)
3802 {
3803 SceneObjectPart e = (SceneObjectPart)entity;
3804 SceneObjectGroup g = e.ParentGroup;
3805 if (g.RootPart.Shape.State > 30) // HUD
3806 if (g.OwnerID != AgentId)
3807 return; // Don't send updates for other people's HUDs
3808 }
3809
3769 uint priority = m_prioritizer.GetUpdatePriority(this, entity); 3810 uint priority = m_prioritizer.GetUpdatePriority(this, entity);
3770 3811
3771 lock (m_entityUpdates.SyncRoot) 3812 lock (m_entityUpdates.SyncRoot)
@@ -3856,27 +3897,74 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3856 3897
3857 // We must lock for both manipulating the kill record and sending the packet, in order to avoid a race 3898 // We must lock for both manipulating the kill record and sending the packet, in order to avoid a race
3858 // condition where a kill can be processed before an out-of-date update for the same object. 3899 // condition where a kill can be processed before an out-of-date update for the same object.
3859 lock (m_killRecord) 3900 float avgTimeDilation = 1.0f;
3901 IEntityUpdate iupdate;
3902 Int32 timeinqueue; // this is just debugging code & can be dropped later
3903
3904 while (updatesThisCall < maxUpdates)
3860 { 3905 {
3861 float avgTimeDilation = 1.0f; 3906 lock (m_entityUpdates.SyncRoot)
3862 IEntityUpdate iupdate; 3907 if (!m_entityUpdates.TryDequeue(out iupdate, out timeinqueue))
3863 Int32 timeinqueue; // this is just debugging code & can be dropped later 3908 break;
3909
3910 EntityUpdate update = (EntityUpdate)iupdate;
3911
3912 avgTimeDilation += update.TimeDilation;
3913 avgTimeDilation *= 0.5f;
3864 3914
3865 while (updatesThisCall < maxUpdates) 3915 if (update.Entity is SceneObjectPart)
3866 { 3916 {
3867 lock (m_entityUpdates.SyncRoot) 3917 SceneObjectPart part = (SceneObjectPart)update.Entity;
3868 if (!m_entityUpdates.TryDequeue(out iupdate, out timeinqueue))
3869 break;
3870 3918
3871 EntityUpdate update = (EntityUpdate)iupdate; 3919 if (part.ParentGroup.IsDeleted)
3872 3920 continue;
3873 avgTimeDilation += update.TimeDilation;
3874 avgTimeDilation *= 0.5f;
3875 3921
3876 if (update.Entity is SceneObjectPart) 3922 if (part.ParentGroup.IsAttachment)
3923 { // Someone else's HUD, why are we getting these?
3924 if (part.ParentGroup.OwnerID != AgentId &&
3925 part.ParentGroup.RootPart.Shape.State > 30)
3926 continue;
3927 ScenePresence sp;
3928 // Owner is not in the sim, don't update it to
3929 // anyone
3930 if (!m_scene.TryGetScenePresence(part.OwnerID, out sp))
3931 continue;
3932
3933 List<SceneObjectGroup> atts = sp.GetAttachments();
3934 bool found = false;
3935 foreach (SceneObjectGroup att in atts)
3936 {
3937 if (att == part.ParentGroup)
3938 {
3939 found = true;
3940 break;
3941 }
3942 }
3943
3944 // It's an attachment of a valid avatar, but
3945 // doesn't seem to be attached, skip
3946 if (!found)
3947 continue;
3948
3949 // On vehicle crossing, the attachments are received
3950 // while the avatar is still a child. Don't send
3951 // updates here because the LocalId has not yet
3952 // been updated and the viewer will derender the
3953 // attachments until the avatar becomes root.
3954 if (sp.IsChildAgent)
3955 continue;
3956
3957 // If the object is an attachment we don't want it to be in the kill
3958 // record. Else attaching from inworld and subsequently dropping
3959 // it will no longer work.
3960// lock (m_killRecord)
3961// {
3962// m_killRecord.Remove(part.LocalId);
3963// m_killRecord.Remove(part.ParentGroup.RootPart.LocalId);
3964// }
3965 }
3966 else
3877 { 3967 {
3878 SceneObjectPart part = (SceneObjectPart)update.Entity;
3879
3880 // Please do not remove this unless you can demonstrate on the OpenSim mailing list that a client 3968 // Please do not remove this unless you can demonstrate on the OpenSim mailing list that a client
3881 // will never receive an update after a prim kill. Even then, keeping the kill record may be a good 3969 // will never receive an update after a prim kill. Even then, keeping the kill record may be a good
3882 // safety measure. 3970 // safety measure.
@@ -3887,21 +3975,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3887 // 3975 //
3888 // This doesn't appear to apply to child prims - a client will happily ignore these updates 3976 // This doesn't appear to apply to child prims - a client will happily ignore these updates
3889 // after the root prim has been deleted. 3977 // after the root prim has been deleted.
3890 if (m_killRecord.Contains(part.LocalId)) 3978 //
3891 { 3979 // We ignore this for attachments because attaching something from inworld breaks unless we do.
3892 // m_log.WarnFormat( 3980// lock (m_killRecord)
3893 // "[CLIENT]: Preventing update for prim with local id {0} after client for user {1} told it was deleted", 3981// {
3894 // part.LocalId, Name); 3982// if (m_killRecord.Contains(part.LocalId))
3895 continue; 3983// continue;
3896 } 3984// if (m_killRecord.Contains(part.ParentGroup.RootPart.LocalId))
3897 3985// continue;
3898 if (part.ParentGroup.IsAttachment && m_disableFacelights) 3986// }
3987 }
3988
3989 if (part.ParentGroup.IsAttachment && m_disableFacelights)
3990 {
3991 if (part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand &&
3992 part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.RightHand)
3899 { 3993 {
3900 if (part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand && 3994 part.Shape.LightEntry = false;
3901 part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.RightHand)
3902 {
3903 part.Shape.LightEntry = false;
3904 }
3905 } 3995 }
3906 3996
3907 if (part.Shape != null && (part.Shape.SculptType == (byte)SculptType.Mesh)) 3997 if (part.Shape != null && (part.Shape.SculptType == (byte)SculptType.Mesh))
@@ -3912,224 +4002,178 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3912 part.Shape.ProfileHollow = 27500; 4002 part.Shape.ProfileHollow = 27500;
3913 } 4003 }
3914 } 4004 }
3915 4005
3916 #region UpdateFlags to packet type conversion 4006 if (part.Shape != null && (part.Shape.SculptType == (byte)SculptType.Mesh))
3917
3918 PrimUpdateFlags updateFlags = (PrimUpdateFlags)update.Flags;
3919
3920 bool canUseCompressed = true;
3921 bool canUseImproved = true;
3922
3923 // Compressed object updates only make sense for LL primitives
3924 if (!(update.Entity is SceneObjectPart))
3925 { 4007 {
3926 canUseCompressed = false; 4008 // Ensure that mesh has at least 8 valid faces
4009 part.Shape.ProfileBegin = 12500;
4010 part.Shape.ProfileEnd = 0;
4011 part.Shape.ProfileHollow = 27500;
3927 } 4012 }
3928 4013 }
3929 if (updateFlags.HasFlag(PrimUpdateFlags.FullUpdate)) 4014 else if (update.Entity is ScenePresence)
4015 {
4016 ScenePresence presence = (ScenePresence)update.Entity;
4017
4018 // If ParentUUID is not UUID.Zero and ParentID is 0, this
4019 // avatar is in the process of crossing regions while
4020 // sat on an object. In this state, we don't want any
4021 // updates because they will visually orbit the avatar.
4022 // Update will be forced once crossing is completed anyway.
4023 if (presence.ParentUUID != UUID.Zero && presence.ParentID == 0)
4024 continue;
4025 }
4026
4027 ++updatesThisCall;
4028
4029 #region UpdateFlags to packet type conversion
4030
4031 PrimUpdateFlags updateFlags = (PrimUpdateFlags)update.Flags;
4032
4033 bool canUseCompressed = true;
4034 bool canUseImproved = true;
4035
4036 // Compressed object updates only make sense for LL primitives
4037 if (!(update.Entity is SceneObjectPart))
4038 {
4039 canUseCompressed = false;
4040 }
4041
4042 if (updateFlags.HasFlag(PrimUpdateFlags.FullUpdate))
4043 {
4044 canUseCompressed = false;
4045 canUseImproved = false;
4046 }
4047 else
4048 {
4049 if (updateFlags.HasFlag(PrimUpdateFlags.Velocity) ||
4050 updateFlags.HasFlag(PrimUpdateFlags.Acceleration) ||
4051 updateFlags.HasFlag(PrimUpdateFlags.CollisionPlane) ||
4052 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3930 { 4053 {
3931 canUseCompressed = false; 4054 canUseCompressed = false;
3932 canUseImproved = false;
3933 } 4055 }
3934 else 4056
4057 if (updateFlags.HasFlag(PrimUpdateFlags.PrimFlags) ||
4058 updateFlags.HasFlag(PrimUpdateFlags.ParentID) ||
4059 updateFlags.HasFlag(PrimUpdateFlags.Scale) ||
4060 updateFlags.HasFlag(PrimUpdateFlags.PrimData) ||
4061 updateFlags.HasFlag(PrimUpdateFlags.Text) ||
4062 updateFlags.HasFlag(PrimUpdateFlags.NameValue) ||
4063 updateFlags.HasFlag(PrimUpdateFlags.ExtraData) ||
4064 updateFlags.HasFlag(PrimUpdateFlags.TextureAnim) ||
4065 updateFlags.HasFlag(PrimUpdateFlags.Sound) ||
4066 updateFlags.HasFlag(PrimUpdateFlags.Particles) ||
4067 updateFlags.HasFlag(PrimUpdateFlags.Material) ||
4068 updateFlags.HasFlag(PrimUpdateFlags.ClickAction) ||
4069 updateFlags.HasFlag(PrimUpdateFlags.MediaURL) ||
4070 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3935 { 4071 {
3936 if (updateFlags.HasFlag(PrimUpdateFlags.Velocity) || 4072 canUseImproved = false;
3937 updateFlags.HasFlag(PrimUpdateFlags.Acceleration) ||
3938 updateFlags.HasFlag(PrimUpdateFlags.CollisionPlane) ||
3939 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3940 {
3941 canUseCompressed = false;
3942 }
3943
3944 if (updateFlags.HasFlag(PrimUpdateFlags.PrimFlags) ||
3945 updateFlags.HasFlag(PrimUpdateFlags.ParentID) ||
3946 updateFlags.HasFlag(PrimUpdateFlags.Scale) ||
3947 updateFlags.HasFlag(PrimUpdateFlags.PrimData) ||
3948 updateFlags.HasFlag(PrimUpdateFlags.Text) ||
3949 updateFlags.HasFlag(PrimUpdateFlags.NameValue) ||
3950 updateFlags.HasFlag(PrimUpdateFlags.ExtraData) ||
3951 updateFlags.HasFlag(PrimUpdateFlags.TextureAnim) ||
3952 updateFlags.HasFlag(PrimUpdateFlags.Sound) ||
3953 updateFlags.HasFlag(PrimUpdateFlags.Particles) ||
3954 updateFlags.HasFlag(PrimUpdateFlags.Material) ||
3955 updateFlags.HasFlag(PrimUpdateFlags.ClickAction) ||
3956 updateFlags.HasFlag(PrimUpdateFlags.MediaURL) ||
3957 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3958 {
3959 canUseImproved = false;
3960 }
3961 } 4073 }
4074 }
3962 4075
3963 #endregion UpdateFlags to packet type conversion 4076 #endregion UpdateFlags to packet type conversion
3964
3965 #region Block Construction
3966
3967 // TODO: Remove this once we can build compressed updates
3968 canUseCompressed = false;
3969
3970 if (!canUseImproved && !canUseCompressed)
3971 {
3972 ObjectUpdatePacket.ObjectDataBlock updateBlock;
3973 4077
3974 if (update.Entity is ScenePresence) 4078 #region Block Construction
3975 {
3976 updateBlock = CreateAvatarUpdateBlock((ScenePresence)update.Entity);
3977 }
3978 else
3979 {
3980 SceneObjectPart part = (SceneObjectPart)update.Entity;
3981 updateBlock = CreatePrimUpdateBlock(part, AgentId);
3982
3983 // If the part has become a private hud since the update was scheduled then we do not
3984 // want to send it to other avatars.
3985 if (part.ParentGroup.IsAttachment
3986 && part.ParentGroup.HasPrivateAttachmentPoint
3987 && part.ParentGroup.AttachedAvatar != AgentId)
3988 continue;
3989
3990 // If the part has since been deleted, then drop the update. In the case of attachments,
3991 // this is to avoid spurious updates to other viewers since post-processing of attachments
3992 // has to change the IsAttachment flag for various reasons (which will end up in a pass
3993 // of the test above).
3994 //
3995 // Actual deletions (kills) happen in another method.
3996 if (part.ParentGroup.IsDeleted)
3997 continue;
3998 }
3999 4079
4000 objectUpdateBlocks.Value.Add(updateBlock); 4080 // TODO: Remove this once we can build compressed updates
4001 objectUpdates.Value.Add(update); 4081 canUseCompressed = false;
4002 }
4003 else if (!canUseImproved)
4004 {
4005 SceneObjectPart part = (SceneObjectPart)update.Entity;
4006 ObjectUpdateCompressedPacket.ObjectDataBlock compressedBlock
4007 = CreateCompressedUpdateBlock(part, updateFlags);
4008
4009 // If the part has since been deleted, then drop the update. In the case of attachments,
4010 // this is to avoid spurious updates to other viewers since post-processing of attachments
4011 // has to change the IsAttachment flag for various reasons (which will end up in a pass
4012 // of the test above).
4013 //
4014 // Actual deletions (kills) happen in another method.
4015 if (part.ParentGroup.IsDeleted)
4016 continue;
4017 4082
4018 compressedUpdateBlocks.Value.Add(compressedBlock); 4083 if (!canUseImproved && !canUseCompressed)
4019 compressedUpdates.Value.Add(update); 4084 {
4085 if (update.Entity is ScenePresence)
4086 {
4087 objectUpdateBlocks.Value.Add(CreateAvatarUpdateBlock((ScenePresence)update.Entity));
4020 } 4088 }
4021 else 4089 else
4022 { 4090 {
4023 if (update.Entity is ScenePresence && ((ScenePresence)update.Entity).UUID == AgentId) 4091 objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId));
4024 {
4025 // Self updates go into a special list
4026 terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
4027 terseAgentUpdates.Value.Add(update);
4028 }
4029 else
4030 {
4031 ImprovedTerseObjectUpdatePacket.ObjectDataBlock terseUpdateBlock
4032 = CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures));
4033
4034 // Everything else goes here
4035 if (update.Entity is SceneObjectPart)
4036 {
4037 SceneObjectPart part = (SceneObjectPart)update.Entity;
4038
4039 // If the part has become a private hud since the update was scheduled then we do not
4040 // want to send it to other avatars.
4041 if (part.ParentGroup.IsAttachment
4042 && part.ParentGroup.HasPrivateAttachmentPoint
4043 && part.ParentGroup.AttachedAvatar != AgentId)
4044 continue;
4045
4046 // If the part has since been deleted, then drop the update. In the case of attachments,
4047 // this is to avoid spurious updates to other viewers since post-processing of attachments
4048 // has to change the IsAttachment flag for various reasons (which will end up in a pass
4049 // of the test above).
4050 //
4051 // Actual deletions (kills) happen in another method.
4052 if (part.ParentGroup.IsDeleted)
4053 continue;
4054 }
4055
4056 terseUpdateBlocks.Value.Add(terseUpdateBlock);
4057 terseUpdates.Value.Add(update);
4058 }
4059 } 4092 }
4060
4061 ++updatesThisCall;
4062
4063 #endregion Block Construction
4064 } 4093 }
4065 4094 else if (!canUseImproved)
4066 #region Packet Sending 4095 {
4067 ushort timeDilation = Utils.FloatToUInt16(avgTimeDilation, 0.0f, 1.0f); 4096 compressedUpdateBlocks.Value.Add(CreateCompressedUpdateBlock((SceneObjectPart)update.Entity, updateFlags));
4068 4097 }
4069 if (terseAgentUpdateBlocks.IsValueCreated) 4098 else
4070 { 4099 {
4071 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value; 4100 if (update.Entity is ScenePresence && ((ScenePresence)update.Entity).UUID == AgentId)
4101 // Self updates go into a special list
4102 terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
4103 else
4104 // Everything else goes here
4105 terseUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
4106 }
4072 4107
4073 ImprovedTerseObjectUpdatePacket packet 4108 #endregion Block Construction
4074 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate); 4109 }
4075 4110
4076 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 4111 #region Packet Sending
4077 packet.RegionData.TimeDilation = timeDilation; 4112
4078 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; 4113 const float TIME_DILATION = 1.0f;
4114 ushort timeDilation = Utils.FloatToUInt16(avgTimeDilation, 0.0f, 1.0f);
4115
4116 if (terseAgentUpdateBlocks.IsValueCreated)
4117 {
4118 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value;
4079 4119
4080 for (int i = 0; i < blocks.Count; i++) 4120 ImprovedTerseObjectUpdatePacket packet
4081 packet.ObjectData[i] = blocks[i]; 4121 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate);
4082 // If any of the packets created from this call go unacknowledged, all of the updates will be resent 4122 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4083 OutPacket(packet, ThrottleOutPacketType.Unknown, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseAgentUpdates.Value, oPacket); }); 4123 packet.RegionData.TimeDilation = timeDilation;
4084 } 4124 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
4085 4125
4086 if (objectUpdateBlocks.IsValueCreated) 4126 for (int i = 0; i < blocks.Count; i++)
4087 { 4127 packet.ObjectData[i] = blocks[i];
4088 List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value;
4089
4090 ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate);
4091 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4092 packet.RegionData.TimeDilation = timeDilation;
4093 packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[blocks.Count];
4094
4095 for (int i = 0; i < blocks.Count; i++)
4096 packet.ObjectData[i] = blocks[i];
4097 // If any of the packets created from this call go unacknowledged, all of the updates will be resent
4098 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(objectUpdates.Value, oPacket); });
4099 }
4100
4101 if (compressedUpdateBlocks.IsValueCreated)
4102 {
4103 List<ObjectUpdateCompressedPacket.ObjectDataBlock> blocks = compressedUpdateBlocks.Value;
4104
4105 ObjectUpdateCompressedPacket packet = (ObjectUpdateCompressedPacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdateCompressed);
4106 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4107 packet.RegionData.TimeDilation = timeDilation;
4108 packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[blocks.Count];
4109
4110 for (int i = 0; i < blocks.Count; i++)
4111 packet.ObjectData[i] = blocks[i];
4112 // If any of the packets created from this call go unacknowledged, all of the updates will be resent
4113 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(compressedUpdates.Value, oPacket); });
4114 }
4115 4128
4116 if (terseUpdateBlocks.IsValueCreated) 4129 OutPacket(packet, ThrottleOutPacketType.Unknown, true);
4117 { 4130 }
4118 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;
4119
4120 ImprovedTerseObjectUpdatePacket packet
4121 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
4122 PacketType.ImprovedTerseObjectUpdate);
4123 4131
4124 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 4132 if (objectUpdateBlocks.IsValueCreated)
4125 packet.RegionData.TimeDilation = timeDilation; 4133 {
4126 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; 4134 List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value;
4127 4135
4128 for (int i = 0; i < blocks.Count; i++) 4136 ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate);
4129 packet.ObjectData[i] = blocks[i]; 4137 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4130 // If any of the packets created from this call go unacknowledged, all of the updates will be resent 4138 packet.RegionData.TimeDilation = timeDilation;
4131 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseUpdates.Value, oPacket); }); 4139 packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[blocks.Count];
4132 } 4140
4141 for (int i = 0; i < blocks.Count; i++)
4142 packet.ObjectData[i] = blocks[i];
4143
4144 OutPacket(packet, ThrottleOutPacketType.Task, true);
4145 }
4146
4147 if (compressedUpdateBlocks.IsValueCreated)
4148 {
4149 List<ObjectUpdateCompressedPacket.ObjectDataBlock> blocks = compressedUpdateBlocks.Value;
4150
4151 ObjectUpdateCompressedPacket packet = (ObjectUpdateCompressedPacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdateCompressed);
4152 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4153 packet.RegionData.TimeDilation = timeDilation;
4154 packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[blocks.Count];
4155
4156 for (int i = 0; i < blocks.Count; i++)
4157 packet.ObjectData[i] = blocks[i];
4158
4159 OutPacket(packet, ThrottleOutPacketType.Task, true);
4160 }
4161
4162 if (terseUpdateBlocks.IsValueCreated)
4163 {
4164 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;
4165
4166 ImprovedTerseObjectUpdatePacket packet
4167 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
4168 PacketType.ImprovedTerseObjectUpdate);
4169 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4170 packet.RegionData.TimeDilation = timeDilation;
4171 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
4172
4173 for (int i = 0; i < blocks.Count; i++)
4174 packet.ObjectData[i] = blocks[i];
4175
4176 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseUpdates.Value, oPacket); });
4133 } 4177 }
4134 4178
4135 #endregion Packet Sending 4179 #endregion Packet Sending
@@ -4453,11 +4497,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4453 4497
4454 // Pass in the delegate so that if this packet needs to be resent, we send the current properties 4498 // Pass in the delegate so that if this packet needs to be resent, we send the current properties
4455 // of the object rather than the properties when the packet was created 4499 // of the object rather than the properties when the packet was created
4456 OutPacket(packet, ThrottleOutPacketType.Task, true, 4500 // HACK : Remove intelligent resending until it's fixed in core
4457 delegate(OutgoingPacket oPacket) 4501 //OutPacket(packet, ThrottleOutPacketType.Task, true,
4458 { 4502 // delegate(OutgoingPacket oPacket)
4459 ResendPropertyUpdates(updates, oPacket); 4503 // {
4460 }); 4504 // ResendPropertyUpdates(updates, oPacket);
4505 // });
4506 OutPacket(packet, ThrottleOutPacketType.Task, true);
4461 4507
4462 // pbcnt += blocks.Count; 4508 // pbcnt += blocks.Count;
4463 // ppcnt++; 4509 // ppcnt++;
@@ -4483,11 +4529,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4483 // of the object rather than the properties when the packet was created 4529 // of the object rather than the properties when the packet was created
4484 List<ObjectPropertyUpdate> updates = new List<ObjectPropertyUpdate>(); 4530 List<ObjectPropertyUpdate> updates = new List<ObjectPropertyUpdate>();
4485 updates.Add(familyUpdates.Value[i]); 4531 updates.Add(familyUpdates.Value[i]);
4486 OutPacket(packet, ThrottleOutPacketType.Task, true, 4532 // HACK : Remove intelligent resending until it's fixed in core
4487 delegate(OutgoingPacket oPacket) 4533 //OutPacket(packet, ThrottleOutPacketType.Task, true,
4488 { 4534 // delegate(OutgoingPacket oPacket)
4489 ResendPropertyUpdates(updates, oPacket); 4535 // {
4490 }); 4536 // ResendPropertyUpdates(updates, oPacket);
4537 // });
4538 OutPacket(packet, ThrottleOutPacketType.Task, true);
4491 4539
4492 // fpcnt++; 4540 // fpcnt++;
4493 // fbcnt++; 4541 // fbcnt++;
@@ -4885,7 +4933,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4885 4933
4886 if (landData.SimwideArea > 0) 4934 if (landData.SimwideArea > 0)
4887 { 4935 {
4888 int simulatorCapacity = (int)(((float)landData.SimwideArea / 65536.0f) * (float)m_scene.RegionInfo.ObjectCapacity * (float)m_scene.RegionInfo.RegionSettings.ObjectBonus); 4936 int simulatorCapacity = (int)((long)landData.SimwideArea * (long)m_scene.RegionInfo.ObjectCapacity * (long)m_scene.RegionInfo.RegionSettings.ObjectBonus / 65536L);
4937 // Never report more than sim total capacity
4938 if (simulatorCapacity > m_scene.RegionInfo.ObjectCapacity)
4939 simulatorCapacity = m_scene.RegionInfo.ObjectCapacity;
4889 updateMessage.SimWideMaxPrims = simulatorCapacity; 4940 updateMessage.SimWideMaxPrims = simulatorCapacity;
4890 } 4941 }
4891 else 4942 else
@@ -5014,14 +5065,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5014 5065
5015 if (notifyCount > 0) 5066 if (notifyCount > 0)
5016 { 5067 {
5017 if (notifyCount > 32) 5068// if (notifyCount > 32)
5018 { 5069// {
5019 m_log.InfoFormat( 5070// m_log.InfoFormat(
5020 "[LAND]: More than {0} avatars own prims on this parcel. Only sending back details of first {0}" 5071// "[LAND]: More than {0} avatars own prims on this parcel. Only sending back details of first {0}"
5021 + " - a developer might want to investigate whether this is a hard limit", 32); 5072// + " - a developer might want to investigate whether this is a hard limit", 32);
5022 5073//
5023 notifyCount = 32; 5074// notifyCount = 32;
5024 } 5075// }
5025 5076
5026 ParcelObjectOwnersReplyPacket.DataBlock[] dataBlock 5077 ParcelObjectOwnersReplyPacket.DataBlock[] dataBlock
5027 = new ParcelObjectOwnersReplyPacket.DataBlock[notifyCount]; 5078 = new ParcelObjectOwnersReplyPacket.DataBlock[notifyCount];
@@ -5076,34 +5127,34 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5076 { 5127 {
5077 ScenePresence presence = (ScenePresence)entity; 5128 ScenePresence presence = (ScenePresence)entity;
5078 5129
5130 position = presence.OffsetPosition;
5131 rotation = presence.Rotation;
5132
5133 if (presence.ParentID != 0)
5134 {
5135 SceneObjectPart part = m_scene.GetSceneObjectPart(presence.ParentID);
5136 if (part != null && part != part.ParentGroup.RootPart)
5137 {
5138 position = part.OffsetPosition + presence.OffsetPosition * part.RotationOffset;
5139 rotation = part.RotationOffset * presence.Rotation;
5140 }
5141 angularVelocity = Vector3.Zero;
5142 }
5143 else
5144 {
5145 angularVelocity = presence.AngularVelocity;
5146 rotation = presence.Rotation;
5147 }
5148
5149 attachPoint = 0;
5079// m_log.DebugFormat( 5150// m_log.DebugFormat(
5080// "[LLCLIENTVIEW]: Sending terse update to {0} with position {1} in {2}", Name, presence.OffsetPosition, m_scene.Name); 5151// "[LLCLIENTVIEW]: Sending terse update to {0} with position {1} in {2}", Name, presence.OffsetPosition, m_scene.Name);
5081 5152
5082 attachPoint = presence.State; 5153 // attachPoint = presence.State; // Core: commented
5083 collisionPlane = presence.CollisionPlane; 5154 collisionPlane = presence.CollisionPlane;
5084 position = presence.OffsetPosition;
5085 velocity = presence.Velocity; 5155 velocity = presence.Velocity;
5086 acceleration = Vector3.Zero; 5156 acceleration = Vector3.Zero;
5087 5157
5088 // Interestingly, sending this to non-zero will cause the client's avatar to start moving & accelerating
5089 // in that direction, even though we don't model this on the server. Implementing this in the future
5090 // may improve movement smoothness.
5091// acceleration = new Vector3(1, 0, 0);
5092
5093 angularVelocity = presence.AngularVelocity;
5094
5095 // Whilst not in mouselook, an avatar will transmit only the Z rotation as this is the only axis
5096 // it rotates around.
5097 // In mouselook, X and Y co-ordinate will also be sent but when used in Rotation, these cause unwanted
5098 // excessive up and down movements of the camera when looking up and down.
5099 // See http://opensimulator.org/mantis/view.php?id=3274
5100 // This does not affect head movement, since this is controlled entirely by camera movement rather than
5101 // body rotation. It does not affect sitting avatar since it's the sitting part rotation that takes
5102 // effect, not the avatar rotation.
5103 rotation = presence.Rotation;
5104 rotation.X = 0;
5105 rotation.Y = 0;
5106
5107 if (sendTexture) 5158 if (sendTexture)
5108 textureEntry = presence.Appearance.Texture.GetBytes(); 5159 textureEntry = presence.Appearance.Texture.GetBytes();
5109 else 5160 else
@@ -5209,28 +5260,34 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5209 5260
5210 protected ObjectUpdatePacket.ObjectDataBlock CreateAvatarUpdateBlock(ScenePresence data) 5261 protected ObjectUpdatePacket.ObjectDataBlock CreateAvatarUpdateBlock(ScenePresence data)
5211 { 5262 {
5263 Vector3 offsetPosition = data.OffsetPosition;
5264 Quaternion rotation = data.Rotation;
5265 uint parentID = data.ParentID;
5266
5267 if (parentID != 0)
5268 {
5269 SceneObjectPart part = m_scene.GetSceneObjectPart(parentID);
5270 if (part != null && part != part.ParentGroup.RootPart)
5271 {
5272 offsetPosition = part.OffsetPosition + data.OffsetPosition * part.RotationOffset;
5273 rotation = part.RotationOffset * data.Rotation;
5274 parentID = part.ParentGroup.RootPart.LocalId;
5275 }
5276 }
5212// m_log.DebugFormat( 5277// m_log.DebugFormat(
5213// "[LLCLIENTVIEW]: Sending full update to {0} with position {1} in {2}", Name, data.OffsetPosition, m_scene.Name); 5278// "[LLCLIENTVIEW]: Sending full update to {0} with position {1} in {2}", Name, data.OffsetPosition, m_scene.Name);
5214 5279
5215 byte[] objectData = new byte[76]; 5280 byte[] objectData = new byte[76];
5216 5281
5217 data.CollisionPlane.ToBytes(objectData, 0); 5282 data.CollisionPlane.ToBytes(objectData, 0);
5218 data.OffsetPosition.ToBytes(objectData, 16); 5283 offsetPosition.ToBytes(objectData, 16);
5284 Vector3 velocity = new Vector3(0, 0, 0);
5285 Vector3 acceleration = new Vector3(0, 0, 0);
5286 velocity.ToBytes(objectData, 28);
5287 acceleration.ToBytes(objectData, 40);
5219// data.Velocity.ToBytes(objectData, 28); 5288// data.Velocity.ToBytes(objectData, 28);
5220// data.Acceleration.ToBytes(objectData, 40); 5289// data.Acceleration.ToBytes(objectData, 40);
5221 5290 rotation.ToBytes(objectData, 52);
5222 // Whilst not in mouselook, an avatar will transmit only the Z rotation as this is the only axis
5223 // it rotates around.
5224 // In mouselook, X and Y co-ordinate will also be sent but when used in Rotation, these cause unwanted
5225 // excessive up and down movements of the camera when looking up and down.
5226 // See http://opensimulator.org/mantis/view.php?id=3274
5227 // This does not affect head movement, since this is controlled entirely by camera movement rather than
5228 // body rotation. It does not affect sitting avatar since it's the sitting part rotation that takes
5229 // effect, not the avatar rotation.
5230 Quaternion rot = data.Rotation;
5231 rot.X = 0;
5232 rot.Y = 0;
5233 rot.ToBytes(objectData, 52);
5234 //data.AngularVelocity.ToBytes(objectData, 64); 5291 //data.AngularVelocity.ToBytes(objectData, 64);
5235 5292
5236 ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock(); 5293 ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock();
@@ -5257,7 +5314,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5257 update.PCode = (byte)PCode.Avatar; 5314 update.PCode = (byte)PCode.Avatar;
5258 update.ProfileCurve = 1; 5315 update.ProfileCurve = 1;
5259 update.PSBlock = Utils.EmptyBytes; 5316 update.PSBlock = Utils.EmptyBytes;
5260 update.Scale = new Vector3(0.45f, 0.6f, 1.9f); 5317 update.Scale = data.Appearance.AvatarSize;
5318// update.Scale.Z -= 0.2f;
5319
5261 update.Text = Utils.EmptyBytes; 5320 update.Text = Utils.EmptyBytes;
5262 update.TextColor = new byte[4]; 5321 update.TextColor = new byte[4];
5263 5322
@@ -5268,10 +5327,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5268 update.TextureEntry = Utils.EmptyBytes; 5327 update.TextureEntry = Utils.EmptyBytes;
5269// update.TextureEntry = (data.Appearance.Texture != null) ? data.Appearance.Texture.GetBytes() : Utils.EmptyBytes; 5328// update.TextureEntry = (data.Appearance.Texture != null) ? data.Appearance.Texture.GetBytes() : Utils.EmptyBytes;
5270 5329
5330/* 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)
5271 update.UpdateFlags = (uint)( 5331 update.UpdateFlags = (uint)(
5272 PrimFlags.Physics | PrimFlags.ObjectModify | PrimFlags.ObjectCopy | PrimFlags.ObjectAnyOwner | 5332 PrimFlags.Physics | PrimFlags.ObjectModify | PrimFlags.ObjectCopy | PrimFlags.ObjectAnyOwner |
5273 PrimFlags.ObjectYouOwner | PrimFlags.ObjectMove | PrimFlags.InventoryEmpty | PrimFlags.ObjectTransfer | 5333 PrimFlags.ObjectYouOwner | PrimFlags.ObjectMove | PrimFlags.InventoryEmpty | PrimFlags.ObjectTransfer |
5274 PrimFlags.ObjectOwnerModify); 5334 PrimFlags.ObjectOwnerModify);
5335*/
5336 update.UpdateFlags = 0;
5275 5337
5276 return update; 5338 return update;
5277 } 5339 }
@@ -5442,8 +5504,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5442 // If AgentUpdate is ever handled asynchronously, then we will also need to construct a new AgentUpdateArgs 5504 // If AgentUpdate is ever handled asynchronously, then we will also need to construct a new AgentUpdateArgs
5443 // for each AgentUpdate packet. 5505 // for each AgentUpdate packet.
5444 AddLocalPacketHandler(PacketType.AgentUpdate, HandleAgentUpdate, false); 5506 AddLocalPacketHandler(PacketType.AgentUpdate, HandleAgentUpdate, false);
5445 5507
5446 AddLocalPacketHandler(PacketType.ViewerEffect, HandleViewerEffect, false); 5508 AddLocalPacketHandler(PacketType.ViewerEffect, HandleViewerEffect, false);
5509 AddLocalPacketHandler(PacketType.VelocityInterpolateOff, HandleVelocityInterpolateOff, false);
5510 AddLocalPacketHandler(PacketType.VelocityInterpolateOn, HandleVelocityInterpolateOn, false);
5447 AddLocalPacketHandler(PacketType.AgentCachedTexture, HandleAgentTextureCached, false); 5511 AddLocalPacketHandler(PacketType.AgentCachedTexture, HandleAgentTextureCached, false);
5448 AddLocalPacketHandler(PacketType.MultipleObjectUpdate, HandleMultipleObjUpdate, false); 5512 AddLocalPacketHandler(PacketType.MultipleObjectUpdate, HandleMultipleObjUpdate, false);
5449 AddLocalPacketHandler(PacketType.MoneyTransferRequest, HandleMoneyTransferRequest, false); 5513 AddLocalPacketHandler(PacketType.MoneyTransferRequest, HandleMoneyTransferRequest, false);
@@ -5595,6 +5659,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5595 AddLocalPacketHandler(PacketType.TransferAbort, HandleTransferAbort, false); 5659 AddLocalPacketHandler(PacketType.TransferAbort, HandleTransferAbort, false);
5596 AddLocalPacketHandler(PacketType.MuteListRequest, HandleMuteListRequest, false); 5660 AddLocalPacketHandler(PacketType.MuteListRequest, HandleMuteListRequest, false);
5597 AddLocalPacketHandler(PacketType.UseCircuitCode, HandleUseCircuitCode); 5661 AddLocalPacketHandler(PacketType.UseCircuitCode, HandleUseCircuitCode);
5662 AddLocalPacketHandler(PacketType.CreateNewOutfitAttachments, HandleCreateNewOutfitAttachments);
5598 AddLocalPacketHandler(PacketType.AgentHeightWidth, HandleAgentHeightWidth, false); 5663 AddLocalPacketHandler(PacketType.AgentHeightWidth, HandleAgentHeightWidth, false);
5599 AddLocalPacketHandler(PacketType.InventoryDescendents, HandleInventoryDescendents); 5664 AddLocalPacketHandler(PacketType.InventoryDescendents, HandleInventoryDescendents);
5600 AddLocalPacketHandler(PacketType.DirPlacesQuery, HandleDirPlacesQuery); 5665 AddLocalPacketHandler(PacketType.DirPlacesQuery, HandleDirPlacesQuery);
@@ -5661,6 +5726,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5661 AddLocalPacketHandler(PacketType.GroupVoteHistoryRequest, HandleGroupVoteHistoryRequest); 5726 AddLocalPacketHandler(PacketType.GroupVoteHistoryRequest, HandleGroupVoteHistoryRequest);
5662 AddLocalPacketHandler(PacketType.SimWideDeletes, HandleSimWideDeletes); 5727 AddLocalPacketHandler(PacketType.SimWideDeletes, HandleSimWideDeletes);
5663 AddLocalPacketHandler(PacketType.SendPostcard, HandleSendPostcard); 5728 AddLocalPacketHandler(PacketType.SendPostcard, HandleSendPostcard);
5729 AddLocalPacketHandler(PacketType.ChangeInventoryItemFlags, HandleChangeInventoryItemFlags);
5664 5730
5665 AddGenericPacketHandler("autopilot", HandleAutopilot); 5731 AddGenericPacketHandler("autopilot", HandleAutopilot);
5666 } 5732 }
@@ -6013,6 +6079,29 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6013 return true; 6079 return true;
6014 } 6080 }
6015 6081
6082 private bool HandleVelocityInterpolateOff(IClientAPI sender, Packet Pack)
6083 {
6084 VelocityInterpolateOffPacket p = (VelocityInterpolateOffPacket)Pack;
6085 if (p.AgentData.SessionID != SessionId ||
6086 p.AgentData.AgentID != AgentId)
6087 return true;
6088
6089 m_VelocityInterpolate = false;
6090 return true;
6091 }
6092
6093 private bool HandleVelocityInterpolateOn(IClientAPI sender, Packet Pack)
6094 {
6095 VelocityInterpolateOnPacket p = (VelocityInterpolateOnPacket)Pack;
6096 if (p.AgentData.SessionID != SessionId ||
6097 p.AgentData.AgentID != AgentId)
6098 return true;
6099
6100 m_VelocityInterpolate = true;
6101 return true;
6102 }
6103
6104
6016 private bool HandleAvatarPropertiesRequest(IClientAPI sender, Packet Pack) 6105 private bool HandleAvatarPropertiesRequest(IClientAPI sender, Packet Pack)
6017 { 6106 {
6018 AvatarPropertiesRequestPacket avatarProperties = (AvatarPropertiesRequestPacket)Pack; 6107 AvatarPropertiesRequestPacket avatarProperties = (AvatarPropertiesRequestPacket)Pack;
@@ -6444,16 +6533,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6444 for (int i = 0; i < appear.VisualParam.Length; i++) 6533 for (int i = 0; i < appear.VisualParam.Length; i++)
6445 visualparams[i] = appear.VisualParam[i].ParamValue; 6534 visualparams[i] = appear.VisualParam[i].ParamValue;
6446 //var b = appear.WearableData[0]; 6535 //var b = appear.WearableData[0];
6447 6536
6448 Primitive.TextureEntry te = null; 6537 Primitive.TextureEntry te = null;
6449 if (appear.ObjectData.TextureEntry.Length > 1) 6538 if (appear.ObjectData.TextureEntry.Length > 1)
6450 te = new Primitive.TextureEntry(appear.ObjectData.TextureEntry, 0, appear.ObjectData.TextureEntry.Length); 6539 te = new Primitive.TextureEntry(appear.ObjectData.TextureEntry, 0, appear.ObjectData.TextureEntry.Length);
6451 6540
6452 WearableCacheItem[] cacheitems = new WearableCacheItem[appear.WearableData.Length]; 6541 WearableCacheItem[] cacheitems = new WearableCacheItem[appear.WearableData.Length];
6453 for (int i=0; i<appear.WearableData.Length;i++) 6542 for (int i=0; i<appear.WearableData.Length;i++)
6454 cacheitems[i] = new WearableCacheItem(){CacheId = appear.WearableData[i].CacheID,TextureIndex=Convert.ToUInt32(appear.WearableData[i].TextureIndex)}; 6543 cacheitems[i] = new WearableCacheItem(){CacheId = appear.WearableData[i].CacheID,TextureIndex=Convert.ToUInt32(appear.WearableData[i].TextureIndex)};
6455 6544
6456 6545
6457 6546
6458 handlerSetAppearance(sender, te, visualparams,avSize, cacheitems); 6547 handlerSetAppearance(sender, te, visualparams,avSize, cacheitems);
6459 } 6548 }
@@ -6664,6 +6753,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6664 { 6753 {
6665 handlerCompleteMovementToRegion(sender, true); 6754 handlerCompleteMovementToRegion(sender, true);
6666 } 6755 }
6756 else
6757 m_log.Debug("HandleCompleteAgentMovement NULL handler");
6758
6667 handlerCompleteMovementToRegion = null; 6759 handlerCompleteMovementToRegion = null;
6668 6760
6669 return true; 6761 return true;
@@ -6681,7 +6773,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6681 return true; 6773 return true;
6682 } 6774 }
6683 #endregion 6775 #endregion
6684 6776/*
6685 StartAnim handlerStartAnim = null; 6777 StartAnim handlerStartAnim = null;
6686 StopAnim handlerStopAnim = null; 6778 StopAnim handlerStopAnim = null;
6687 6779
@@ -6705,6 +6797,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6705 } 6797 }
6706 } 6798 }
6707 return true; 6799 return true;
6800*/
6801 ChangeAnim handlerChangeAnim = null;
6802
6803 for (int i = 0; i < AgentAni.AnimationList.Length; i++)
6804 {
6805 handlerChangeAnim = OnChangeAnim;
6806 if (handlerChangeAnim != null)
6807 {
6808 handlerChangeAnim(AgentAni.AnimationList[i].AnimID, AgentAni.AnimationList[i].StartAnim, false);
6809 }
6810 }
6811
6812 handlerChangeAnim = OnChangeAnim;
6813 if (handlerChangeAnim != null)
6814 {
6815 handlerChangeAnim(UUID.Zero, false, true);
6816 }
6817
6818 return true;
6708 } 6819 }
6709 6820
6710 private bool HandleAgentRequestSit(IClientAPI sender, Packet Pack) 6821 private bool HandleAgentRequestSit(IClientAPI sender, Packet Pack)
@@ -6950,6 +7061,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6950 #endregion 7061 #endregion
6951 7062
6952 m_udpClient.SetThrottles(atpack.Throttle.Throttles); 7063 m_udpClient.SetThrottles(atpack.Throttle.Throttles);
7064 GenericCall2 handler = OnUpdateThrottles;
7065 if (handler != null)
7066 {
7067 handler();
7068 }
6953 return true; 7069 return true;
6954 } 7070 }
6955 7071
@@ -7374,7 +7490,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7374 physdata.Bounce = phsblock.Restitution; 7490 physdata.Bounce = phsblock.Restitution;
7375 physdata.Density = phsblock.Density; 7491 physdata.Density = phsblock.Density;
7376 physdata.Friction = phsblock.Friction; 7492 physdata.Friction = phsblock.Friction;
7377 physdata.GravitationModifier = phsblock.GravityMultiplier; 7493 physdata.GravitationModifier = phsblock.GravityMultiplier;
7378 } 7494 }
7379 7495
7380 handlerUpdatePrimFlags(flags.AgentData.ObjectLocalID, UsePhysics, IsTemporary, IsPhantom, physdata, this); 7496 handlerUpdatePrimFlags(flags.AgentData.ObjectLocalID, UsePhysics, IsTemporary, IsPhantom, physdata, this);
@@ -7960,6 +8076,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7960 // surrounding scene 8076 // surrounding scene
7961 if ((ImageType)block.Type == ImageType.Baked) 8077 if ((ImageType)block.Type == ImageType.Baked)
7962 args.Priority *= 2.0f; 8078 args.Priority *= 2.0f;
8079 int wearableout = 0;
7963 8080
7964 ImageManager.EnqueueReq(args); 8081 ImageManager.EnqueueReq(args);
7965 } 8082 }
@@ -8994,16 +9111,61 @@ namespace OpenSim.Region.ClientStack.LindenUDP
8994 9111
8995 #region Parcel related packets 9112 #region Parcel related packets
8996 9113
9114 // acumulate several HandleRegionHandleRequest consecutive overlaping requests
9115 // to be done with minimal resources as possible
9116 // variables temporary here while in test
9117
9118 Queue<UUID> RegionHandleRequests = new Queue<UUID>();
9119 bool RegionHandleRequestsInService = false;
9120
8997 private bool HandleRegionHandleRequest(IClientAPI sender, Packet Pack) 9121 private bool HandleRegionHandleRequest(IClientAPI sender, Packet Pack)
8998 { 9122 {
8999 RegionHandleRequestPacket rhrPack = (RegionHandleRequestPacket)Pack; 9123 UUID currentUUID;
9000 9124
9001 RegionHandleRequest handlerRegionHandleRequest = OnRegionHandleRequest; 9125 RegionHandleRequest handlerRegionHandleRequest = OnRegionHandleRequest;
9002 if (handlerRegionHandleRequest != null) 9126
9127 if (handlerRegionHandleRequest == null)
9128 return true;
9129
9130 RegionHandleRequestPacket rhrPack = (RegionHandleRequestPacket)Pack;
9131
9132 lock (RegionHandleRequests)
9003 { 9133 {
9004 handlerRegionHandleRequest(this, rhrPack.RequestBlock.RegionID); 9134 if (RegionHandleRequestsInService)
9135 {
9136 // we are already busy doing a previus request
9137 // so enqueue it
9138 RegionHandleRequests.Enqueue(rhrPack.RequestBlock.RegionID);
9139 return true;
9140 }
9141
9142 // else do it
9143 currentUUID = rhrPack.RequestBlock.RegionID;
9144 RegionHandleRequestsInService = true;
9005 } 9145 }
9006 return true; 9146
9147 while (true)
9148 {
9149 handlerRegionHandleRequest(this, currentUUID);
9150
9151 lock (RegionHandleRequests)
9152 {
9153 // exit condition, nothing to do or closed
9154 // current code seems to assume we may loose the handler at anytime,
9155 // so keep checking it
9156 handlerRegionHandleRequest = OnRegionHandleRequest;
9157
9158 if (RegionHandleRequests.Count == 0 || !IsActive || handlerRegionHandleRequest == null)
9159 {
9160 RegionHandleRequests.Clear();
9161 RegionHandleRequestsInService = false;
9162 return true;
9163 }
9164 currentUUID = RegionHandleRequests.Dequeue();
9165 }
9166 }
9167
9168 return true; // actually unreached
9007 } 9169 }
9008 9170
9009 private bool HandleParcelInfoRequest(IClientAPI sender, Packet Pack) 9171 private bool HandleParcelInfoRequest(IClientAPI sender, Packet Pack)
@@ -10259,7 +10421,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10259 handlerUpdateMuteListEntry(this, UpdateMuteListEntry.MuteData.MuteID, 10421 handlerUpdateMuteListEntry(this, UpdateMuteListEntry.MuteData.MuteID,
10260 Utils.BytesToString(UpdateMuteListEntry.MuteData.MuteName), 10422 Utils.BytesToString(UpdateMuteListEntry.MuteData.MuteName),
10261 UpdateMuteListEntry.MuteData.MuteType, 10423 UpdateMuteListEntry.MuteData.MuteType,
10262 UpdateMuteListEntry.AgentData.AgentID); 10424 UpdateMuteListEntry.MuteData.MuteFlags);
10263 return true; 10425 return true;
10264 } 10426 }
10265 return false; 10427 return false;
@@ -10274,8 +10436,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10274 { 10436 {
10275 handlerRemoveMuteListEntry(this, 10437 handlerRemoveMuteListEntry(this,
10276 RemoveMuteListEntry.MuteData.MuteID, 10438 RemoveMuteListEntry.MuteData.MuteID,
10277 Utils.BytesToString(RemoveMuteListEntry.MuteData.MuteName), 10439 Utils.BytesToString(RemoveMuteListEntry.MuteData.MuteName));
10278 RemoveMuteListEntry.AgentData.AgentID);
10279 return true; 10440 return true;
10280 } 10441 }
10281 return false; 10442 return false;
@@ -10319,10 +10480,55 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10319 return false; 10480 return false;
10320 } 10481 }
10321 10482
10483 private bool HandleChangeInventoryItemFlags(IClientAPI client, Packet packet)
10484 {
10485 ChangeInventoryItemFlagsPacket ChangeInventoryItemFlags =
10486 (ChangeInventoryItemFlagsPacket)packet;
10487 ChangeInventoryItemFlags handlerChangeInventoryItemFlags = OnChangeInventoryItemFlags;
10488 if (handlerChangeInventoryItemFlags != null)
10489 {
10490 foreach(ChangeInventoryItemFlagsPacket.InventoryDataBlock b in ChangeInventoryItemFlags.InventoryData)
10491 handlerChangeInventoryItemFlags(this, b.ItemID, b.Flags);
10492 return true;
10493 }
10494 return false;
10495 }
10496
10322 private bool HandleUseCircuitCode(IClientAPI sender, Packet Pack) 10497 private bool HandleUseCircuitCode(IClientAPI sender, Packet Pack)
10323 { 10498 {
10324 return true; 10499 return true;
10325 } 10500 }
10501
10502 private bool HandleCreateNewOutfitAttachments(IClientAPI sender, Packet Pack)
10503 {
10504 CreateNewOutfitAttachmentsPacket packet = (CreateNewOutfitAttachmentsPacket)Pack;
10505
10506 #region Packet Session and User Check
10507 if (m_checkPackets)
10508 {
10509 if (packet.AgentData.SessionID != SessionId ||
10510 packet.AgentData.AgentID != AgentId)
10511 return true;
10512 }
10513 #endregion
10514 MoveItemsAndLeaveCopy handlerMoveItemsAndLeaveCopy = null;
10515 List<InventoryItemBase> items = new List<InventoryItemBase>();
10516 foreach (CreateNewOutfitAttachmentsPacket.ObjectDataBlock n in packet.ObjectData)
10517 {
10518 InventoryItemBase b = new InventoryItemBase();
10519 b.ID = n.OldItemID;
10520 b.Folder = n.OldFolderID;
10521 items.Add(b);
10522 }
10523
10524 handlerMoveItemsAndLeaveCopy = OnMoveItemsAndLeaveCopy;
10525 if (handlerMoveItemsAndLeaveCopy != null)
10526 {
10527 handlerMoveItemsAndLeaveCopy(this, items, packet.HeaderData.NewFolderID);
10528 }
10529
10530 return true;
10531 }
10326 10532
10327 private bool HandleAgentHeightWidth(IClientAPI sender, Packet Pack) 10533 private bool HandleAgentHeightWidth(IClientAPI sender, Packet Pack)
10328 { 10534 {
@@ -10749,6 +10955,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10749 groupProfileReply.GroupData.MaturePublish = d.MaturePublish; 10955 groupProfileReply.GroupData.MaturePublish = d.MaturePublish;
10750 groupProfileReply.GroupData.OwnerRole = d.OwnerRole; 10956 groupProfileReply.GroupData.OwnerRole = d.OwnerRole;
10751 10957
10958 Scene scene = (Scene)m_scene;
10959 if (scene.Permissions.IsGod(sender.AgentId) && (!sender.IsGroupMember(groupProfileRequest.GroupData.GroupID)))
10960 {
10961 ScenePresence p;
10962 if (scene.TryGetScenePresence(sender.AgentId, out p))
10963 {
10964 if (p.GodLevel >= 200)
10965 {
10966 groupProfileReply.GroupData.OpenEnrollment = true;
10967 groupProfileReply.GroupData.MembershipFee = 0;
10968 }
10969 }
10970 }
10971
10752 OutPacket(groupProfileReply, ThrottleOutPacketType.Task); 10972 OutPacket(groupProfileReply, ThrottleOutPacketType.Task);
10753 } 10973 }
10754 return true; 10974 return true;
@@ -11322,11 +11542,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11322 11542
11323 StartLure handlerStartLure = OnStartLure; 11543 StartLure handlerStartLure = OnStartLure;
11324 if (handlerStartLure != null) 11544 if (handlerStartLure != null)
11325 handlerStartLure(startLureRequest.Info.LureType, 11545 {
11326 Utils.BytesToString( 11546 for (int i = 0 ; i < startLureRequest.TargetData.Length ; i++)
11327 startLureRequest.Info.Message), 11547 {
11328 startLureRequest.TargetData[0].TargetID, 11548 handlerStartLure(startLureRequest.Info.LureType,
11329 this); 11549 Utils.BytesToString(
11550 startLureRequest.Info.Message),
11551 startLureRequest.TargetData[i].TargetID,
11552 this);
11553 }
11554 }
11330 return true; 11555 return true;
11331 } 11556 }
11332 private bool HandleTeleportLureRequest(IClientAPI sender, Packet Pack) 11557 private bool HandleTeleportLureRequest(IClientAPI sender, Packet Pack)
@@ -11440,10 +11665,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11440 } 11665 }
11441 #endregion 11666 #endregion
11442 11667
11443 ClassifiedDelete handlerClassifiedGodDelete = OnClassifiedGodDelete; 11668 ClassifiedGodDelete handlerClassifiedGodDelete = OnClassifiedGodDelete;
11444 if (handlerClassifiedGodDelete != null) 11669 if (handlerClassifiedGodDelete != null)
11445 handlerClassifiedGodDelete( 11670 handlerClassifiedGodDelete(
11446 classifiedGodDelete.Data.ClassifiedID, 11671 classifiedGodDelete.Data.ClassifiedID,
11672 classifiedGodDelete.Data.QueryID,
11447 this); 11673 this);
11448 return true; 11674 return true;
11449 } 11675 }
@@ -11746,12 +11972,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11746 /// <param name="simclient"></param> 11972 /// <param name="simclient"></param>
11747 /// <param name="packet"></param> 11973 /// <param name="packet"></param>
11748 /// <returns></returns> 11974 /// <returns></returns>
11749 protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet) 11975 // TODO: Convert old handler to use new method
11976 /*protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet)
11750 { 11977 {
11751 AgentCachedTexturePacket cachedtex = (AgentCachedTexturePacket)packet; 11978 AgentCachedTexturePacket cachedtex = (AgentCachedTexturePacket)packet;
11752 11979
11753 if (cachedtex.AgentData.SessionID != SessionId) 11980 if (cachedtex.AgentData.SessionID != SessionId)
11754 return false; 11981 return false;
11982
11755 11983
11756 List<CachedTextureRequestArg> requestArgs = new List<CachedTextureRequestArg>(); 11984 List<CachedTextureRequestArg> requestArgs = new List<CachedTextureRequestArg>();
11757 11985
@@ -11764,23 +11992,173 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11764 requestArgs.Add(arg); 11992 requestArgs.Add(arg);
11765 } 11993 }
11766 11994
11767 try 11995 CachedTextureRequest handlerCachedTextureRequest = OnCachedTextureRequest;
11996 if (handlerCachedTextureRequest != null)
11768 { 11997 {
11769 CachedTextureRequest handlerCachedTextureRequest = OnCachedTextureRequest; 11998 handlerCachedTextureRequest(simclient,cachedtex.AgentData.SerialNum,requestArgs);
11770 if (handlerCachedTextureRequest != null) 11999 }
12000
12001 return true;
12002 }*/
12003
12004 protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet)
12005 {
12006 //m_log.Debug("texture cached: " + packet.ToString());
12007 AgentCachedTexturePacket cachedtex = (AgentCachedTexturePacket)packet;
12008 AgentCachedTextureResponsePacket cachedresp = (AgentCachedTextureResponsePacket)PacketPool.Instance.GetPacket(PacketType.AgentCachedTextureResponse);
12009
12010 if (cachedtex.AgentData.SessionID != SessionId)
12011 return false;
12012
12013
12014 // TODO: don't create new blocks if recycling an old packet
12015 cachedresp.AgentData.AgentID = AgentId;
12016 cachedresp.AgentData.SessionID = m_sessionId;
12017 cachedresp.AgentData.SerialNum = m_cachedTextureSerial;
12018 m_cachedTextureSerial++;
12019 cachedresp.WearableData =
12020 new AgentCachedTextureResponsePacket.WearableDataBlock[cachedtex.WearableData.Length];
12021
12022 //IAvatarFactoryModule fac = m_scene.RequestModuleInterface<IAvatarFactoryModule>();
12023 // var item = fac.GetBakedTextureFaces(AgentId);
12024 //WearableCacheItem[] items = fac.GetCachedItems(AgentId);
12025
12026 IAssetService cache = m_scene.AssetService;
12027 IBakedTextureModule bakedTextureModule = m_scene.RequestModuleInterface<IBakedTextureModule>();
12028 //bakedTextureModule = null;
12029 int maxWearablesLoop = cachedtex.WearableData.Length;
12030 if (maxWearablesLoop > AvatarWearable.MAX_WEARABLES)
12031 maxWearablesLoop = AvatarWearable.MAX_WEARABLES;
12032
12033 if (bakedTextureModule != null && cache != null)
12034 {
12035 // 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
12036
12037 WearableCacheItem[] cacheItems = null;
12038 ScenePresence p = m_scene.GetScenePresence(AgentId);
12039 if (p.Appearance != null)
12040 if (p.Appearance.WearableCacheItems == null || p.Appearance.WearableCacheItemsDirty)
12041 {
12042 try
12043 {
12044 cacheItems = bakedTextureModule.Get(AgentId);
12045 p.Appearance.WearableCacheItems = cacheItems;
12046 p.Appearance.WearableCacheItemsDirty = false;
12047 }
12048
12049 /*
12050 * The following Catch types DO NOT WORK, it jumps to the General Packet Exception Handler if you don't catch Exception!
12051 *
12052 catch (System.Net.Sockets.SocketException)
12053 {
12054 cacheItems = null;
12055 }
12056 catch (WebException)
12057 {
12058 cacheItems = null;
12059 }
12060 catch (InvalidOperationException)
12061 {
12062 cacheItems = null;
12063 } */
12064 catch (Exception)
12065 {
12066 cacheItems = null;
12067 }
12068
12069 }
12070 else if (p.Appearance.WearableCacheItems != null)
12071 {
12072 cacheItems = p.Appearance.WearableCacheItems;
12073 }
12074
12075 if (cache != null && cacheItems != null)
12076 {
12077 foreach (WearableCacheItem item in cacheItems)
12078 {
12079
12080 if (cache.GetCached(item.TextureID.ToString()) == null)
12081 {
12082 item.TextureAsset.Temporary = true;
12083 cache.Store(item.TextureAsset);
12084 }
12085
12086
12087 }
12088 }
12089
12090 if (cacheItems != null)
12091 {
12092
12093 for (int i = 0; i < maxWearablesLoop; i++)
12094 {
12095 WearableCacheItem item =
12096 WearableCacheItem.SearchTextureIndex(cachedtex.WearableData[i].TextureIndex,cacheItems);
12097
12098 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
12099 cachedresp.WearableData[i].TextureIndex= cachedtex.WearableData[i].TextureIndex;
12100 cachedresp.WearableData[i].HostName = new byte[0];
12101 if (item != null && cachedtex.WearableData[i].ID == item.CacheId)
12102 {
12103
12104 cachedresp.WearableData[i].TextureID = item.TextureID;
12105 }
12106 else
12107 {
12108 cachedresp.WearableData[i].TextureID = UUID.Zero;
12109 }
12110 }
12111 }
12112 else
11771 { 12113 {
11772 handlerCachedTextureRequest(simclient,cachedtex.AgentData.SerialNum,requestArgs); 12114 for (int i = 0; i < maxWearablesLoop; i++)
12115 {
12116 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
12117 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex;
12118 cachedresp.WearableData[i].TextureID = UUID.Zero;
12119 //UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46");
12120 cachedresp.WearableData[i].HostName = new byte[0];
12121 }
11773 } 12122 }
11774 } 12123 }
11775 catch (Exception e) 12124 else
11776 { 12125 {
11777 m_log.ErrorFormat("[CLIENT VIEW]: AgentTextureCached packet handler threw an exception, {0}", e); 12126 if (cache == null)
11778 return false; 12127 {
12128 for (int i = 0; i < maxWearablesLoop; i++)
12129 {
12130 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
12131 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex;
12132 cachedresp.WearableData[i].TextureID = UUID.Zero;
12133 //UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46");
12134 cachedresp.WearableData[i].HostName = new byte[0];
12135 }
12136 }
12137 else
12138 {
12139 for (int i = 0; i < maxWearablesLoop; i++)
12140 {
12141 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
12142 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex;
12143
12144
12145
12146 if (cache.GetCached(cachedresp.WearableData[i].TextureID.ToString()) == null)
12147 cachedresp.WearableData[i].TextureID = UUID.Zero;
12148 //UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46");
12149 else
12150 cachedresp.WearableData[i].TextureID = UUID.Zero;
12151 // UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46");
12152 cachedresp.WearableData[i].HostName = new byte[0];
12153 }
12154 }
11779 } 12155 }
11780 12156 cachedresp.Header.Zerocoded = true;
12157 OutPacket(cachedresp, ThrottleOutPacketType.Task);
12158
11781 return true; 12159 return true;
11782 } 12160 }
11783 12161
11784 /// <summary> 12162 /// <summary>
11785 /// Send a response back to a client when it asks the asset server (via the region server) if it has 12163 /// Send a response back to a client when it asks the asset server (via the region server) if it has
11786 /// its appearance texture cached. 12164 /// its appearance texture cached.
@@ -11844,209 +12222,147 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11844 } 12222 }
11845 else 12223 else
11846 { 12224 {
11847// m_log.DebugFormat( 12225 ClientChangeObject updatehandler = onClientChangeObject;
11848// "[CLIENT]: Processing block {0} type {1} for {2} {3}",
11849// i, block.Type, part.Name, part.LocalId);
11850 12226
11851// // Do this once since fetch parts creates a new array. 12227 if (updatehandler != null)
11852// SceneObjectPart[] parts = part.ParentGroup.Parts; 12228 {
11853// for (int j = 0; j < parts.Length; j++) 12229 ObjectChangeData udata = new ObjectChangeData();
11854// {
11855// part.StoreUndoState();
11856// parts[j].IgnoreUndoUpdate = true;
11857// }
11858 12230
11859 UpdatePrimGroupRotation handlerUpdatePrimGroupRotation; 12231 /*ubit from ll JIRA:
12232 * 0x01 position
12233 * 0x02 rotation
12234 * 0x04 scale
12235
12236 * 0x08 LINK_SET
12237 * 0x10 UNIFORM for scale
12238 */
11860 12239
11861 switch (block.Type) 12240 // translate to internal changes
11862 { 12241 // not all cases .. just the ones older code did
11863 case 1:
11864 Vector3 pos1 = new Vector3(block.Data, 0);
11865 12242
11866 UpdateVector handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; 12243 switch (block.Type)
11867 if (handlerUpdatePrimSinglePosition != null) 12244 {
11868 { 12245 case 1: //change position sp
11869 // m_log.Debug("new movement position is " + pos.X + " , " + pos.Y + " , " + pos.Z); 12246 udata.position = new Vector3(block.Data, 0);
11870 handlerUpdatePrimSinglePosition(localId, pos1, this);
11871 }
11872 break;
11873 12247
11874 case 2: 12248 udata.change = ObjectChangeType.primP;
11875 Quaternion rot1 = new Quaternion(block.Data, 0, true); 12249 updatehandler(localId, udata, this);
12250 break;
11876 12251
11877 UpdatePrimSingleRotation handlerUpdatePrimSingleRotation = OnUpdatePrimSingleRotation; 12252 case 2: // rotation sp
11878 if (handlerUpdatePrimSingleRotation != null) 12253 udata.rotation = new Quaternion(block.Data, 0, true);
11879 {
11880 // m_log.Info("new tab rotation is " + rot1.X + " , " + rot1.Y + " , " + rot1.Z + " , " + rot1.W);
11881 handlerUpdatePrimSingleRotation(localId, rot1, this);
11882 }
11883 break;
11884 12254
11885 case 3: 12255 udata.change = ObjectChangeType.primR;
11886 Vector3 rotPos = new Vector3(block.Data, 0); 12256 updatehandler(localId, udata, this);
11887 Quaternion rot2 = new Quaternion(block.Data, 12, true); 12257 break;
11888 12258
11889 UpdatePrimSingleRotationPosition handlerUpdatePrimSingleRotationPosition = OnUpdatePrimSingleRotationPosition; 12259 case 3: // position plus rotation
11890 if (handlerUpdatePrimSingleRotationPosition != null) 12260 udata.position = new Vector3(block.Data, 0);
11891 { 12261 udata.rotation = new Quaternion(block.Data, 12, true);
11892 // m_log.Debug("new mouse rotation position is " + rotPos.X + " , " + rotPos.Y + " , " + rotPos.Z);
11893 // m_log.Info("new mouse rotation is " + rot2.X + " , " + rot2.Y + " , " + rot2.Z + " , " + rot2.W);
11894 handlerUpdatePrimSingleRotationPosition(localId, rot2, rotPos, this);
11895 }
11896 break;
11897 12262
11898 case 4: 12263 udata.change = ObjectChangeType.primPR;
11899 case 20: 12264 updatehandler(localId, udata, this);
11900 Vector3 scale4 = new Vector3(block.Data, 0); 12265 break;
11901 12266
11902 UpdateVector handlerUpdatePrimScale = OnUpdatePrimScale; 12267 case 4: // scale sp
11903 if (handlerUpdatePrimScale != null) 12268 udata.scale = new Vector3(block.Data, 0);
11904 { 12269 udata.change = ObjectChangeType.primS;
11905 // m_log.Debug("new scale is " + scale4.X + " , " + scale4.Y + " , " + scale4.Z);
11906 handlerUpdatePrimScale(localId, scale4, this);
11907 }
11908 break;
11909 12270
11910 case 5: 12271 updatehandler(localId, udata, this);
11911 Vector3 scale1 = new Vector3(block.Data, 12); 12272 break;
11912 Vector3 pos11 = new Vector3(block.Data, 0);
11913 12273
11914 handlerUpdatePrimScale = OnUpdatePrimScale; 12274 case 0x14: // uniform scale sp
11915 if (handlerUpdatePrimScale != null) 12275 udata.scale = new Vector3(block.Data, 0);
11916 {
11917 // m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z);
11918 handlerUpdatePrimScale(localId, scale1, this);
11919 12276
11920 handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; 12277 udata.change = ObjectChangeType.primUS;
11921 if (handlerUpdatePrimSinglePosition != null) 12278 updatehandler(localId, udata, this);
11922 { 12279 break;
11923 handlerUpdatePrimSinglePosition(localId, pos11, this);
11924 }
11925 }
11926 break;
11927 12280
11928 case 9: 12281 case 5: // scale and position sp
11929 Vector3 pos2 = new Vector3(block.Data, 0); 12282 udata.position = new Vector3(block.Data, 0);
12283 udata.scale = new Vector3(block.Data, 12);
11930 12284
11931 UpdateVector handlerUpdateVector = OnUpdatePrimGroupPosition; 12285 udata.change = ObjectChangeType.primPS;
12286 updatehandler(localId, udata, this);
12287 break;
11932 12288
11933 if (handlerUpdateVector != null) 12289 case 0x15: //uniform scale and position
11934 { 12290 udata.position = new Vector3(block.Data, 0);
11935 handlerUpdateVector(localId, pos2, this); 12291 udata.scale = new Vector3(block.Data, 12);
11936 }
11937 break;
11938 12292
11939 case 10: 12293 udata.change = ObjectChangeType.primPUS;
11940 Quaternion rot3 = new Quaternion(block.Data, 0, true); 12294 updatehandler(localId, udata, this);
12295 break;
11941 12296
11942 UpdatePrimRotation handlerUpdatePrimRotation = OnUpdatePrimGroupRotation; 12297 // now group related (bit 4)
11943 if (handlerUpdatePrimRotation != null) 12298 case 9: //( 8 + 1 )group position
11944 { 12299 udata.position = new Vector3(block.Data, 0);
11945 // Console.WriteLine("new rotation is " + rot3.X + " , " + rot3.Y + " , " + rot3.Z + " , " + rot3.W);
11946 handlerUpdatePrimRotation(localId, rot3, this);
11947 }
11948 break;
11949 12300
11950 case 11: 12301 udata.change = ObjectChangeType.groupP;
11951 Vector3 pos3 = new Vector3(block.Data, 0); 12302 updatehandler(localId, udata, this);
11952 Quaternion rot4 = new Quaternion(block.Data, 12, true); 12303 break;
11953 12304
11954 handlerUpdatePrimGroupRotation = OnUpdatePrimGroupMouseRotation; 12305 case 0x0A: // (8 + 2) group rotation
11955 if (handlerUpdatePrimGroupRotation != null) 12306 udata.rotation = new Quaternion(block.Data, 0, true);
11956 {
11957 // m_log.Debug("new rotation position is " + pos.X + " , " + pos.Y + " , " + pos.Z);
11958 // m_log.Debug("new group mouse rotation is " + rot4.X + " , " + rot4.Y + " , " + rot4.Z + " , " + rot4.W);
11959 handlerUpdatePrimGroupRotation(localId, pos3, rot4, this);
11960 }
11961 break;
11962 case 12:
11963 case 28:
11964 Vector3 scale7 = new Vector3(block.Data, 0);
11965 12307
11966 UpdateVector handlerUpdatePrimGroupScale = OnUpdatePrimGroupScale; 12308 udata.change = ObjectChangeType.groupR;
11967 if (handlerUpdatePrimGroupScale != null) 12309 updatehandler(localId, udata, this);
11968 { 12310 break;
11969 // m_log.Debug("new scale is " + scale7.X + " , " + scale7.Y + " , " + scale7.Z);
11970 handlerUpdatePrimGroupScale(localId, scale7, this);
11971 }
11972 break;
11973 12311
11974 case 13: 12312 case 0x0B: //( 8 + 2 + 1) group rotation and position
11975 Vector3 scale2 = new Vector3(block.Data, 12); 12313 udata.position = new Vector3(block.Data, 0);
11976 Vector3 pos4 = new Vector3(block.Data, 0); 12314 udata.rotation = new Quaternion(block.Data, 12, true);
11977 12315
11978 handlerUpdatePrimScale = OnUpdatePrimScale; 12316 udata.change = ObjectChangeType.groupPR;
11979 if (handlerUpdatePrimScale != null) 12317 updatehandler(localId, udata, this);
11980 { 12318 break;
11981 //m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z);
11982 handlerUpdatePrimScale(localId, scale2, this);
11983 12319
11984 // Change the position based on scale (for bug number 246) 12320 case 0x0C: // (8 + 4) group scale
11985 handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; 12321 // only afects root prim and only sent by viewer editor object tab scaling
11986 // m_log.Debug("new movement position is " + pos.X + " , " + pos.Y + " , " + pos.Z); 12322 // mouse edition only allows uniform scaling
11987 if (handlerUpdatePrimSinglePosition != null) 12323 // SL MAY CHANGE THIS in viewers
11988 {
11989 handlerUpdatePrimSinglePosition(localId, pos4, this);
11990 }
11991 }
11992 break;
11993 12324
11994 case 29: 12325 udata.scale = new Vector3(block.Data, 0);
11995 Vector3 scale5 = new Vector3(block.Data, 12);
11996 Vector3 pos5 = new Vector3(block.Data, 0);
11997 12326
11998 handlerUpdatePrimGroupScale = OnUpdatePrimGroupScale; 12327 udata.change = ObjectChangeType.groupS;
11999 if (handlerUpdatePrimGroupScale != null) 12328 updatehandler(localId, udata, this);
12000 {
12001 // m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z);
12002 part.StoreUndoState(true);
12003 part.IgnoreUndoUpdate = true;
12004 handlerUpdatePrimGroupScale(localId, scale5, this);
12005 handlerUpdateVector = OnUpdatePrimGroupPosition;
12006 12329
12007 if (handlerUpdateVector != null) 12330 break;
12008 {
12009 handlerUpdateVector(localId, pos5, this);
12010 }
12011 12331
12012 part.IgnoreUndoUpdate = false; 12332 case 0x0D: //(8 + 4 + 1) group scale and position
12013 } 12333 // exception as above
12014 12334
12015 break; 12335 udata.position = new Vector3(block.Data, 0);
12336 udata.scale = new Vector3(block.Data, 12);
12016 12337
12017 case 21: 12338 udata.change = ObjectChangeType.groupPS;
12018 Vector3 scale6 = new Vector3(block.Data, 12); 12339 updatehandler(localId, udata, this);
12019 Vector3 pos6 = new Vector3(block.Data, 0); 12340 break;
12020 12341
12021 handlerUpdatePrimScale = OnUpdatePrimScale; 12342 case 0x1C: // (0x10 + 8 + 4 ) group scale UNIFORM
12022 if (handlerUpdatePrimScale != null) 12343 udata.scale = new Vector3(block.Data, 0);
12023 {
12024 part.StoreUndoState(false);
12025 part.IgnoreUndoUpdate = true;
12026 12344
12027 // m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z); 12345 udata.change = ObjectChangeType.groupUS;
12028 handlerUpdatePrimScale(localId, scale6, this); 12346 updatehandler(localId, udata, this);
12029 handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; 12347 break;
12030 if (handlerUpdatePrimSinglePosition != null)
12031 {
12032 handlerUpdatePrimSinglePosition(localId, pos6, this);
12033 }
12034 12348
12035 part.IgnoreUndoUpdate = false; 12349 case 0x1D: // (UNIFORM + GROUP + SCALE + POS)
12036 } 12350 udata.position = new Vector3(block.Data, 0);
12037 break; 12351 udata.scale = new Vector3(block.Data, 12);
12038 12352
12039 default: 12353 udata.change = ObjectChangeType.groupPUS;
12040 m_log.Debug("[CLIENT]: MultipleObjUpdate recieved an unknown packet type: " + (block.Type)); 12354 updatehandler(localId, udata, this);
12041 break; 12355 break;
12356
12357 default:
12358 m_log.Debug("[CLIENT]: MultipleObjUpdate recieved an unknown packet type: " + (block.Type));
12359 break;
12360 }
12042 } 12361 }
12043 12362
12044// for (int j = 0; j < parts.Length; j++)
12045// parts[j].IgnoreUndoUpdate = false;
12046 } 12363 }
12047 } 12364 }
12048 } 12365 }
12049
12050 return true; 12366 return true;
12051 } 12367 }
12052 12368
@@ -12107,8 +12423,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12107 public void SetChildAgentThrottle(byte[] throttles) 12423 public void SetChildAgentThrottle(byte[] throttles)
12108 { 12424 {
12109 m_udpClient.SetThrottles(throttles); 12425 m_udpClient.SetThrottles(throttles);
12426 GenericCall2 handler = OnUpdateThrottles;
12427 if (handler != null)
12428 {
12429 handler();
12430 }
12431 }
12432
12433 /// <summary>
12434 /// Sets the throttles from values supplied by the client
12435 /// </summary>
12436 /// <param name="throttles"></param>
12437 public void SetAgentThrottleSilent(int throttle, int setting)
12438 {
12439 m_udpClient.ForceThrottleSetting(throttle,setting);
12440 //m_udpClient.SetThrottles(throttles);
12441
12110 } 12442 }
12111 12443
12444
12112 /// <summary> 12445 /// <summary>
12113 /// Get the current throttles for this client as a packed byte array 12446 /// Get the current throttles for this client as a packed byte array
12114 /// </summary> 12447 /// </summary>
@@ -12492,7 +12825,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12492// "[LLCLIENTVIEW]: Received transfer request for {0} in {1} type {2} by {3}", 12825// "[LLCLIENTVIEW]: Received transfer request for {0} in {1} type {2} by {3}",
12493// requestID, taskID, (SourceType)sourceType, Name); 12826// requestID, taskID, (SourceType)sourceType, Name);
12494 12827
12828
12829 //Note, the bool returned from the below function is useless since it is always false.
12495 m_assetService.Get(requestID.ToString(), transferRequest, AssetReceived); 12830 m_assetService.Get(requestID.ToString(), transferRequest, AssetReceived);
12831
12496 } 12832 }
12497 12833
12498 /// <summary> 12834 /// <summary>
@@ -12558,7 +12894,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12558 /// <returns></returns> 12894 /// <returns></returns>
12559 private static int CalculateNumPackets(byte[] data) 12895 private static int CalculateNumPackets(byte[] data)
12560 { 12896 {
12561 const uint m_maxPacketSize = 600; 12897// const uint m_maxPacketSize = 600;
12898 uint m_maxPacketSize = MaxTransferBytesPerPacket;
12562 int numPackets = 1; 12899 int numPackets = 1;
12563 12900
12564 if (data == null) 12901 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 c0a4e56..50dae2a 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
@@ -236,7 +236,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
236 /// <summary>Handlers for incoming packets</summary> 236 /// <summary>Handlers for incoming packets</summary>
237 //PacketEventDictionary packetEvents = new PacketEventDictionary(); 237 //PacketEventDictionary packetEvents = new PacketEventDictionary();
238 /// <summary>Incoming packets that are awaiting handling</summary> 238 /// <summary>Incoming packets that are awaiting handling</summary>
239 private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>(); 239 //private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>();
240
241 private DoubleQueue<IncomingPacket> packetInbox = new DoubleQueue<IncomingPacket>();
240 242
241 /// <summary></summary> 243 /// <summary></summary>
242 //private UDPClientCollection m_clients = new UDPClientCollection(); 244 //private UDPClientCollection m_clients = new UDPClientCollection();
@@ -291,6 +293,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
291 /// <summary>Flag to signal when clients should send pings</summary> 293 /// <summary>Flag to signal when clients should send pings</summary>
292 protected bool m_sendPing; 294 protected bool m_sendPing;
293 295
296 private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>();
297
294 /// <summary> 298 /// <summary>
295 /// Event used to signal when queued packets are available for sending. 299 /// Event used to signal when queued packets are available for sending.
296 /// </summary> 300 /// </summary>
@@ -1058,6 +1062,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1058 1062
1059 #region Queue or Send 1063 #region Queue or Send
1060 1064
1065 bool highPriority = false;
1066
1067 if (category != ThrottleOutPacketType.Unknown && (category & ThrottleOutPacketType.HighPriority) != 0)
1068 {
1069 category = (ThrottleOutPacketType)((int)category & 127);
1070 highPriority = true;
1071 }
1072
1061 OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category, null); 1073 OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category, null);
1062 // If we were not provided a method for handling unacked, use the UDPServer default method 1074 // If we were not provided a method for handling unacked, use the UDPServer default method
1063 outgoingPacket.UnackedMethod = ((method == null) ? delegate(OutgoingPacket oPacket) { ResendUnacked(oPacket); } : method); 1075 outgoingPacket.UnackedMethod = ((method == null) ? delegate(OutgoingPacket oPacket) { ResendUnacked(oPacket); } : method);
@@ -1066,15 +1078,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1066 // continue to display the deleted object until relog. Therefore, we need to always queue a kill object 1078 // continue to display the deleted object until relog. Therefore, we need to always queue a kill object
1067 // packet so that it isn't sent before a queued update packet. 1079 // packet so that it isn't sent before a queued update packet.
1068 bool requestQueue = type == PacketType.KillObject; 1080 bool requestQueue = type == PacketType.KillObject;
1081 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, requestQueue, highPriority))
1069 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, requestQueue)) 1082 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, requestQueue))
1070 { 1083 {
1071 SendPacketFinal(outgoingPacket); 1084 SendPacketFinal(outgoingPacket);
1072 return true; 1085 return true;
1073 } 1086 }
1074 else 1087
1075 { 1088 return false;
1076 return false;
1077 }
1078 1089
1079 #endregion Queue or Send 1090 #endregion Queue or Send
1080 } 1091 }
@@ -1372,34 +1383,59 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1372 1383
1373 #region Packet to Client Mapping 1384 #region Packet to Client Mapping
1374 1385
1375 // UseCircuitCode handling 1386 // If there is already a client for this endpoint, don't process UseCircuitCode
1376 if (packet.Type == PacketType.UseCircuitCode) 1387 IClientAPI client = null;
1388 if (!m_scene.TryGetClient(endPoint, out client) || !(client is LLClientView))
1377 { 1389 {
1378 // We need to copy the endpoint so that it doesn't get changed when another thread reuses the 1390 // UseCircuitCode handling
1379 // buffer. 1391 if (packet.Type == PacketType.UseCircuitCode)
1380 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet }; 1392 {
1393 // And if there is a UseCircuitCode pending, also drop it
1394 lock (m_pendingCache)
1395 {
1396 if (m_pendingCache.Contains(endPoint))
1397 return;
1381 1398
1382 Util.FireAndForget(HandleUseCircuitCode, array); 1399 m_pendingCache.AddOrUpdate(endPoint, new Queue<UDPPacketBuffer>(), 60);
1400 }
1383 1401
1384 return; 1402 // We need to copy the endpoint so that it doesn't get changed when another thread reuses the
1403 // buffer.
1404 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet };
1405
1406 Util.FireAndForget(HandleUseCircuitCode, array);
1407
1408 return;
1409 }
1385 } 1410 }
1386 else if (packet.Type == PacketType.CompleteAgentMovement) 1411
1412 // If this is a pending connection, enqueue, don't process yet
1413 lock (m_pendingCache)
1387 { 1414 {
1388 // Send ack straight away to let the viewer know that we got it. 1415 Queue<UDPPacketBuffer> queue;
1389 SendAckImmediate(endPoint, packet.Header.Sequence); 1416 if (m_pendingCache.TryGetValue(endPoint, out queue))
1417 {
1418 //m_log.DebugFormat("[LLUDPSERVER]: Enqueued a {0} packet into the pending queue", packet.Type);
1419 queue.Enqueue(buffer);
1420 return;
1421 }
1422 else if (packet.Type == PacketType.CompleteAgentMovement)
1423 {
1424 // Send ack straight away to let the viewer know that we got it.
1425 SendAckImmediate(endPoint, packet.Header.Sequence);
1390 1426
1391 // We need to copy the endpoint so that it doesn't get changed when another thread reuses the 1427 // We need to copy the endpoint so that it doesn't get changed when another thread reuses the
1392 // buffer. 1428 // buffer.
1393 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet }; 1429 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet };
1394 1430
1395 Util.FireAndForget(HandleCompleteMovementIntoRegion, array); 1431 Util.FireAndForget(HandleCompleteMovementIntoRegion, array);
1396 1432
1397 return; 1433 return;
1434 }
1398 } 1435 }
1399 1436
1400 // Determine which agent this packet came from 1437 // Determine which agent this packet came from
1401 IClientAPI client; 1438 if (client == null || !(client is LLClientView))
1402 if (!m_scene.TryGetClient(endPoint, out client) || !(client is LLClientView))
1403 { 1439 {
1404 //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); 1440 //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName);
1405 1441
@@ -1416,7 +1452,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1416 udpClient = ((LLClientView)client).UDPClient; 1452 udpClient = ((LLClientView)client).UDPClient;
1417 1453
1418 if (!udpClient.IsConnected) 1454 if (!udpClient.IsConnected)
1455 {
1456 m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet for a unConnected client in " + m_scene.RegionInfo.RegionName);
1419 return; 1457 return;
1458 }
1420 1459
1421 #endregion Packet to Client Mapping 1460 #endregion Packet to Client Mapping
1422 1461
@@ -1570,7 +1609,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1570 incomingPacket = new IncomingPacket((LLClientView)client, packet); 1609 incomingPacket = new IncomingPacket((LLClientView)client, packet);
1571 } 1610 }
1572 1611
1573 packetInbox.Enqueue(incomingPacket); 1612 if (incomingPacket.Packet.Type == PacketType.AgentUpdate ||
1613 incomingPacket.Packet.Type == PacketType.ChatFromViewer)
1614 packetInbox.EnqueueHigh(incomingPacket);
1615 else
1616 packetInbox.EnqueueLow(incomingPacket);
1574 } 1617 }
1575 1618
1576 #region BinaryStats 1619 #region BinaryStats
@@ -1722,6 +1765,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1722 if (!tp) 1765 if (!tp)
1723 client.SceneAgent.SendInitialDataToMe(); 1766 client.SceneAgent.SendInitialDataToMe();
1724 } 1767 }
1768
1769 // Now we know we can handle more data
1770 Thread.Sleep(200);
1771
1772 // Obtain the queue and remove it from the cache
1773 Queue<UDPPacketBuffer> queue = null;
1774
1775 lock (m_pendingCache)
1776 {
1777 if (!m_pendingCache.TryGetValue(endPoint, out queue))
1778 {
1779 m_log.DebugFormat("[LLUDPSERVER]: Client created but no pending queue present");
1780 return;
1781 }
1782 m_pendingCache.Remove(endPoint);
1783 }
1784
1785 m_log.DebugFormat("[LLUDPSERVER]: Client created, processing pending queue, {0} entries", queue.Count);
1786
1787 // Reinject queued packets
1788 while(queue.Count > 0)
1789 {
1790 UDPPacketBuffer buf = queue.Dequeue();
1791 PacketReceived(buf);
1792 }
1793 queue = null;
1725 } 1794 }
1726 else 1795 else
1727 { 1796 {
@@ -1729,6 +1798,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1729 m_log.WarnFormat( 1798 m_log.WarnFormat(
1730 "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}", 1799 "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}",
1731 uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint); 1800 uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint);
1801 lock (m_pendingCache)
1802 m_pendingCache.Remove(endPoint);
1732 } 1803 }
1733 1804
1734 // m_log.DebugFormat( 1805 // m_log.DebugFormat(
@@ -1971,6 +2042,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1971 2042
1972 while (IsRunningInbound) 2043 while (IsRunningInbound)
1973 { 2044 {
2045 m_scene.ThreadAlive(1);
1974 try 2046 try
1975 { 2047 {
1976 IncomingPacket incomingPacket = null; 2048 IncomingPacket incomingPacket = null;
@@ -2020,6 +2092,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2020 2092
2021 while (base.IsRunningOutbound) 2093 while (base.IsRunningOutbound)
2022 { 2094 {
2095 m_scene.ThreadAlive(2);
2023 try 2096 try
2024 { 2097 {
2025 m_packetSent = false; 2098 m_packetSent = false;
@@ -2255,8 +2328,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2255 Packet packet = incomingPacket.Packet; 2328 Packet packet = incomingPacket.Packet;
2256 LLClientView client = incomingPacket.Client; 2329 LLClientView client = incomingPacket.Client;
2257 2330
2258 if (client.IsActive) 2331// if (client.IsActive)
2259 { 2332// {
2260 m_currentIncomingClient = client; 2333 m_currentIncomingClient = client;
2261 2334
2262 try 2335 try
@@ -2283,13 +2356,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2283 { 2356 {
2284 m_currentIncomingClient = null; 2357 m_currentIncomingClient = null;
2285 } 2358 }
2286 } 2359// }
2287 else 2360// else
2288 { 2361// {
2289 m_log.DebugFormat( 2362// m_log.DebugFormat(
2290 "[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}", 2363// "[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}",
2291 packet.Type, client.Name, m_scene.RegionInfo.RegionName); 2364// packet.Type, client.Name, m_scene.RegionInfo.RegionName);
2292 } 2365// }
2293 2366
2294 IncomingPacketsProcessed++; 2367 IncomingPacketsProcessed++;
2295 } 2368 }
@@ -2305,4 +2378,4 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2305 } 2378 }
2306 } 2379 }
2307 } 2380 }
2308} \ No newline at end of file 2381}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
index 88494be..881e768 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,