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.cs921
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/MeshCost.cs671
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs12
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs29
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs442
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs382
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs16
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs296
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs9
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs181
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs200
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs3
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs1475
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs69
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs219
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs4
16 files changed, 3789 insertions, 1140 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
index a534522..83347e2 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
@@ -26,6 +26,7 @@
26 */ 26 */
27 27
28using System; 28using System;
29using System.Timers;
29using System.Collections; 30using System.Collections;
30using System.Collections.Generic; 31using System.Collections.Generic;
31using System.IO; 32using System.IO;
@@ -53,14 +54,16 @@ using OSDMap = OpenMetaverse.StructuredData.OSDMap;
53namespace OpenSim.Region.ClientStack.Linden 54namespace OpenSim.Region.ClientStack.Linden
54{ 55{
55 public delegate void UpLoadedAsset( 56 public delegate void UpLoadedAsset(
56 string assetName, string description, UUID assetID, UUID inventoryItem, UUID parentFolder, 57 string assetName, string description, UUID assetID, UUID inventoryItem, UUID parentFolder,
57 byte[] data, string inventoryType, string assetType); 58 byte[] data, string inventoryType, string assetType,
59 int cost, UUID texturesFolder, int nreqtextures, int nreqmeshs, int nreqinstances,
60 bool IsAtestUpload, ref string error);
58 61
59 public delegate UUID UpdateItem(UUID itemID, byte[] data); 62 public delegate UUID UpdateItem(UUID itemID, byte[] data);
60 63
61 public delegate void UpdateTaskScript(UUID itemID, UUID primID, bool isScriptRunning, byte[] data, ref ArrayList errors); 64 public delegate void UpdateTaskScript(UUID itemID, UUID primID, bool isScriptRunning, byte[] data, ref ArrayList errors);
62 65
63 public delegate void NewInventoryItem(UUID userID, InventoryItemBase item); 66 public delegate void NewInventoryItem(UUID userID, InventoryItemBase item, uint cost);
64 67
65 public delegate void NewAsset(AssetBase asset); 68 public delegate void NewAsset(AssetBase asset);
66 69
@@ -86,6 +89,7 @@ namespace OpenSim.Region.ClientStack.Linden
86 89
87 private Scene m_Scene; 90 private Scene m_Scene;
88 private Caps m_HostCapsObj; 91 private Caps m_HostCapsObj;
92 private ModelCost m_ModelCost;
89 93
90 private static readonly string m_requestPath = "0000/"; 94 private static readonly string m_requestPath = "0000/";
91 // private static readonly string m_mapLayerPath = "0001/"; 95 // private static readonly string m_mapLayerPath = "0001/";
@@ -96,6 +100,9 @@ namespace OpenSim.Region.ClientStack.Linden
96 // private static readonly string m_fetchInventoryPath = "0006/"; 100 // private static readonly string m_fetchInventoryPath = "0006/";
97 private static readonly string m_copyFromNotecardPath = "0007/"; 101 private static readonly string m_copyFromNotecardPath = "0007/";
98 // private static readonly string m_remoteParcelRequestPath = "0009/";// This is in the LandManagementModule. 102 // private static readonly string m_remoteParcelRequestPath = "0009/";// This is in the LandManagementModule.
103 private static readonly string m_getObjectPhysicsDataPath = "0101/";
104 private static readonly string m_getObjectCostPath = "0102/";
105 private static readonly string m_ResourceCostSelectedPath = "0103/";
99 private static readonly string m_UpdateAgentInformationPath = "0500/"; 106 private static readonly string m_UpdateAgentInformationPath = "0500/";
100 107
101 // These are callbacks which will be setup by the scene so that we can update scene data when we 108 // These are callbacks which will be setup by the scene so that we can update scene data when we
@@ -111,12 +118,50 @@ namespace OpenSim.Region.ClientStack.Linden
111 private IAssetService m_assetService; 118 private IAssetService m_assetService;
112 private bool m_dumpAssetsToFile = false; 119 private bool m_dumpAssetsToFile = false;
113 private string m_regionName; 120 private string m_regionName;
121
114 private int m_levelUpload = 0; 122 private int m_levelUpload = 0;
115 123
124 private bool m_enableFreeTestUpload = false; // allows "TEST-" prefix hack
125 private bool m_ForceFreeTestUpload = false; // forces all uploads to be test
126
127 private bool m_enableModelUploadTextureToInventory = false; // place uploaded textures also in inventory
128 // may not be visible till relog
129
130 private bool m_RestrictFreeTestUploadPerms = false; // reduces also the permitions. Needs a creator defined!!
131 private UUID m_testAssetsCreatorID = UUID.Zero;
132
133 private float m_PrimScaleMin = 0.001f;
134
135 private enum FileAgentInventoryState : int
136 {
137 idle = 0,
138 processRequest = 1,
139 waitUpload = 2,
140 processUpload = 3
141 }
142 private FileAgentInventoryState m_FileAgentInventoryState = FileAgentInventoryState.idle;
143
116 public BunchOfCaps(Scene scene, Caps caps) 144 public BunchOfCaps(Scene scene, Caps caps)
117 { 145 {
118 m_Scene = scene; 146 m_Scene = scene;
119 m_HostCapsObj = caps; 147 m_HostCapsObj = caps;
148
149 // create a model upload cost provider
150 m_ModelCost = new ModelCost();
151 // tell it about scene object limits
152 m_ModelCost.NonPhysicalPrimScaleMax = m_Scene.m_maxNonphys;
153 m_ModelCost.PhysicalPrimScaleMax = m_Scene.m_maxPhys;
154
155// m_ModelCost.ObjectLinkedPartsMax = ??
156// m_ModelCost.PrimScaleMin = ??
157
158 m_PrimScaleMin = m_ModelCost.PrimScaleMin;
159 float modelTextureUploadFactor = m_ModelCost.ModelTextureCostFactor;
160 float modelUploadFactor = m_ModelCost.ModelMeshCostFactor;
161 float modelMinUploadCostFactor = m_ModelCost.ModelMinCostFactor;
162 float modelPrimCreationCost = m_ModelCost.primCreationCost;
163 float modelMeshByteCost = m_ModelCost.bytecost;
164
120 IConfigSource config = m_Scene.Config; 165 IConfigSource config = m_Scene.Config;
121 if (config != null) 166 if (config != null)
122 { 167 {
@@ -131,6 +176,37 @@ namespace OpenSim.Region.ClientStack.Linden
131 { 176 {
132 m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures); 177 m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures);
133 } 178 }
179 // economy for model upload
180 IConfig EconomyConfig = config.Configs["Economy"];
181 if (EconomyConfig != null)
182 {
183 modelUploadFactor = EconomyConfig.GetFloat("MeshModelUploadCostFactor", modelUploadFactor);
184 modelTextureUploadFactor = EconomyConfig.GetFloat("MeshModelUploadTextureCostFactor", modelTextureUploadFactor);
185 modelMinUploadCostFactor = EconomyConfig.GetFloat("MeshModelMinCostFactor", modelMinUploadCostFactor);
186 // next 2 are normalized so final cost is afected by modelUploadFactor above and normal cost
187 modelPrimCreationCost = EconomyConfig.GetFloat("ModelPrimCreationCost", modelPrimCreationCost);
188 modelMeshByteCost = EconomyConfig.GetFloat("ModelMeshByteCost", modelMeshByteCost);
189
190 m_enableModelUploadTextureToInventory = EconomyConfig.GetBoolean("MeshModelAllowTextureToInventory", m_enableModelUploadTextureToInventory);
191
192 m_RestrictFreeTestUploadPerms = EconomyConfig.GetBoolean("m_RestrictFreeTestUploadPerms", m_RestrictFreeTestUploadPerms);
193 m_enableFreeTestUpload = EconomyConfig.GetBoolean("AllowFreeTestUpload", m_enableFreeTestUpload);
194 m_ForceFreeTestUpload = EconomyConfig.GetBoolean("ForceFreeTestUpload", m_ForceFreeTestUpload);
195 string testcreator = EconomyConfig.GetString("TestAssetsCreatorID", "");
196 if (testcreator != "")
197 {
198 UUID id;
199 UUID.TryParse(testcreator, out id);
200 if (id != null)
201 m_testAssetsCreatorID = id;
202 }
203
204 m_ModelCost.ModelMeshCostFactor = modelUploadFactor;
205 m_ModelCost.ModelTextureCostFactor = modelTextureUploadFactor;
206 m_ModelCost.ModelMinCostFactor = modelMinUploadCostFactor;
207 m_ModelCost.primCreationCost = modelPrimCreationCost;
208 m_ModelCost.bytecost = modelMeshByteCost;
209 }
134 } 210 }
135 211
136 m_assetService = m_Scene.AssetService; 212 m_assetService = m_Scene.AssetService;
@@ -142,6 +218,8 @@ namespace OpenSim.Region.ClientStack.Linden
142 ItemUpdatedCall = m_Scene.CapsUpdateInventoryItemAsset; 218 ItemUpdatedCall = m_Scene.CapsUpdateInventoryItemAsset;
143 TaskScriptUpdatedCall = m_Scene.CapsUpdateTaskInventoryScriptAsset; 219 TaskScriptUpdatedCall = m_Scene.CapsUpdateTaskInventoryScriptAsset;
144 GetClient = m_Scene.SceneGraph.GetControllingClient; 220 GetClient = m_Scene.SceneGraph.GetControllingClient;
221
222 m_FileAgentInventoryState = FileAgentInventoryState.idle;
145 } 223 }
146 224
147 /// <summary> 225 /// <summary>
@@ -187,7 +265,6 @@ namespace OpenSim.Region.ClientStack.Linden
187 { 265 {
188 try 266 try
189 { 267 {
190 // I don't think this one works...
191 m_HostCapsObj.RegisterHandler( 268 m_HostCapsObj.RegisterHandler(
192 "NewFileAgentInventory", 269 "NewFileAgentInventory",
193 new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDAssetUploadResponse>( 270 new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDAssetUploadResponse>(
@@ -204,6 +281,12 @@ namespace OpenSim.Region.ClientStack.Linden
204 m_HostCapsObj.RegisterHandler("UpdateNotecardAgentInventory", req); 281 m_HostCapsObj.RegisterHandler("UpdateNotecardAgentInventory", req);
205 m_HostCapsObj.RegisterHandler("UpdateScriptAgentInventory", req); 282 m_HostCapsObj.RegisterHandler("UpdateScriptAgentInventory", req);
206 m_HostCapsObj.RegisterHandler("UpdateScriptAgent", req); 283 m_HostCapsObj.RegisterHandler("UpdateScriptAgent", req);
284 IRequestHandler getObjectPhysicsDataHandler = new RestStreamHandler("POST", capsBase + m_getObjectPhysicsDataPath, GetObjectPhysicsData);
285 m_HostCapsObj.RegisterHandler("GetObjectPhysicsData", getObjectPhysicsDataHandler);
286 IRequestHandler getObjectCostHandler = new RestStreamHandler("POST", capsBase + m_getObjectCostPath, GetObjectCost);
287 m_HostCapsObj.RegisterHandler("GetObjectCost", getObjectCostHandler);
288 IRequestHandler ResourceCostSelectedHandler = new RestStreamHandler("POST", capsBase + m_ResourceCostSelectedPath, ResourceCostSelected);
289 m_HostCapsObj.RegisterHandler("ResourceCostSelected", ResourceCostSelectedHandler);
207 IRequestHandler UpdateAgentInformationHandler = new RestStreamHandler("POST", capsBase + m_UpdateAgentInformationPath, UpdateAgentInformation); 290 IRequestHandler UpdateAgentInformationHandler = new RestStreamHandler("POST", capsBase + m_UpdateAgentInformationPath, UpdateAgentInformation);
208 m_HostCapsObj.RegisterHandler("UpdateAgentInformation", UpdateAgentInformationHandler); 291 m_HostCapsObj.RegisterHandler("UpdateAgentInformation", UpdateAgentInformationHandler);
209 292
@@ -388,62 +471,176 @@ namespace OpenSim.Region.ClientStack.Linden
388 //m_log.Debug("[CAPS]: NewAgentInventoryRequest Request is: " + llsdRequest.ToString()); 471 //m_log.Debug("[CAPS]: NewAgentInventoryRequest Request is: " + llsdRequest.ToString());
389 //m_log.Debug("asset upload request via CAPS" + llsdRequest.inventory_type + " , " + llsdRequest.asset_type); 472 //m_log.Debug("asset upload request via CAPS" + llsdRequest.inventory_type + " , " + llsdRequest.asset_type);
390 473
474 // start by getting the client
475 IClientAPI client = null;
476 m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client);
477
478 // check current state so we only have one service at a time
479 lock (m_ModelCost)
480 {
481 switch (m_FileAgentInventoryState)
482 {
483 case FileAgentInventoryState.processRequest:
484 case FileAgentInventoryState.processUpload:
485 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
486 resperror.message = "Uploader busy processing previus request";
487 resperror.identifier = UUID.Zero;
488
489 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
490 errorResponse.uploader = "";
491 errorResponse.state = "error";
492 errorResponse.error = resperror;
493 return errorResponse;
494 break;
495 case FileAgentInventoryState.waitUpload:
496 // todo stop current uploader server
497 break;
498 case FileAgentInventoryState.idle:
499 default:
500 break;
501 }
502
503 m_FileAgentInventoryState = FileAgentInventoryState.processRequest;
504 }
505
506 int cost = 0;
507 int nreqtextures = 0;
508 int nreqmeshs= 0;
509 int nreqinstances = 0;
510 bool IsAtestUpload = false;
511
512 string assetName = llsdRequest.name;
513
514 LLSDAssetUploadResponseData meshcostdata = new LLSDAssetUploadResponseData();
515
391 if (llsdRequest.asset_type == "texture" || 516 if (llsdRequest.asset_type == "texture" ||
392 llsdRequest.asset_type == "animation" || 517 llsdRequest.asset_type == "animation" ||
518 llsdRequest.asset_type == "mesh" ||
393 llsdRequest.asset_type == "sound") 519 llsdRequest.asset_type == "sound")
394 { 520 {
395 ScenePresence avatar = null; 521 ScenePresence avatar = null;
396 IClientAPI client = null;
397 m_Scene.TryGetScenePresence(m_HostCapsObj.AgentID, out avatar); 522 m_Scene.TryGetScenePresence(m_HostCapsObj.AgentID, out avatar);
398 523
399 // check user level 524 // check user level
400 if (avatar != null) 525 if (avatar != null)
401 { 526 {
402 client = avatar.ControllingClient;
403
404 if (avatar.UserLevel < m_levelUpload) 527 if (avatar.UserLevel < m_levelUpload)
405 { 528 {
406 if (client != null) 529 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
407 client.SendAgentAlertMessage("Unable to upload asset. Insufficient permissions.", false); 530 resperror.message = "Insufficient permissions to upload";
531 resperror.identifier = UUID.Zero;
408 532
409 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse(); 533 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
410 errorResponse.uploader = ""; 534 errorResponse.uploader = "";
411 errorResponse.state = "error"; 535 errorResponse.state = "error";
536 errorResponse.error = resperror;
537 lock (m_ModelCost)
538 m_FileAgentInventoryState = FileAgentInventoryState.idle;
412 return errorResponse; 539 return errorResponse;
413 } 540 }
414 } 541 }
415 542
416 // check funds 543 // check test upload and funds
417 if (client != null) 544 if (client != null)
418 { 545 {
419 IMoneyModule mm = m_Scene.RequestModuleInterface<IMoneyModule>(); 546 IMoneyModule mm = m_Scene.RequestModuleInterface<IMoneyModule>();
420 547
548 int baseCost = 0;
421 if (mm != null) 549 if (mm != null)
550 baseCost = mm.UploadCharge;
551
552 string warning = String.Empty;
553
554 if (llsdRequest.asset_type == "mesh")
422 { 555 {
423 if (!mm.UploadCovered(client.AgentId, mm.UploadCharge)) 556 string error;
557 int modelcost;
558
559 if (!m_ModelCost.MeshModelCost(llsdRequest.asset_resources, baseCost, out modelcost,
560 meshcostdata, out error, ref warning))
424 { 561 {
425 client.SendAgentAlertMessage("Unable to upload asset. Insufficient funds.", false); 562 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
563 resperror.message = error;
564 resperror.identifier = UUID.Zero;
426 565
427 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse(); 566 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
428 errorResponse.uploader = ""; 567 errorResponse.uploader = "";
429 errorResponse.state = "error"; 568 errorResponse.state = "error";
569 errorResponse.error = resperror;
570
571 lock (m_ModelCost)
572 m_FileAgentInventoryState = FileAgentInventoryState.idle;
430 return errorResponse; 573 return errorResponse;
431 } 574 }
575 cost = modelcost;
432 } 576 }
577 else
578 {
579 cost = baseCost;
580 }
581
582 if (cost > 0 && mm != null)
583 {
584 // check for test upload
585
586 if (m_ForceFreeTestUpload) // all are test
587 {
588 if (!(assetName.Length > 5 && assetName.StartsWith("TEST-"))) // has normal name lets change it
589 assetName = "TEST-" + assetName;
590
591 IsAtestUpload = true;
592 }
593
594 else if (m_enableFreeTestUpload) // only if prefixed with "TEST-"
595 {
596
597 IsAtestUpload = (assetName.Length > 5 && assetName.StartsWith("TEST-"));
598 }
599
600
601 if(IsAtestUpload) // let user know, still showing cost estimation
602 warning += "Upload will have no cost, for testing purposes only. Other uses are prohibited. Items will not work after 48 hours or on other regions";
603
604 // check funds
605 else
606 {
607 if (!mm.UploadCovered(client.AgentId, (int)cost))
608 {
609 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
610 resperror.message = "Insuficient funds";
611 resperror.identifier = UUID.Zero;
612
613 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
614 errorResponse.uploader = "";
615 errorResponse.state = "error";
616 errorResponse.error = resperror;
617 lock (m_ModelCost)
618 m_FileAgentInventoryState = FileAgentInventoryState.idle;
619 return errorResponse;
620 }
621 }
622 }
623
624 if (client != null && warning != String.Empty)
625 client.SendAgentAlertMessage(warning, true);
433 } 626 }
434 } 627 }
435 628
436 string assetName = llsdRequest.name;
437 string assetDes = llsdRequest.description; 629 string assetDes = llsdRequest.description;
438 string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath; 630 string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath;
439 UUID newAsset = UUID.Random(); 631 UUID newAsset = UUID.Random();
440 UUID newInvItem = UUID.Random(); 632 UUID newInvItem = UUID.Random();
441 UUID parentFolder = llsdRequest.folder_id; 633 UUID parentFolder = llsdRequest.folder_id;
442 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000"); 634 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000");
635 UUID texturesFolder = UUID.Zero;
636
637 if(!IsAtestUpload && m_enableModelUploadTextureToInventory)
638 texturesFolder = llsdRequest.texture_folder_id;
443 639
444 AssetUploader uploader = 640 AssetUploader uploader =
445 new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type, 641 new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type,
446 llsdRequest.asset_type, capsBase + uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile); 642 llsdRequest.asset_type, capsBase + uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile, cost,
643 texturesFolder, nreqtextures, nreqmeshs, nreqinstances, IsAtestUpload);
447 644
448 m_HostCapsObj.HttpListener.AddStreamHandler( 645 m_HostCapsObj.HttpListener.AddStreamHandler(
449 new BinaryStreamHandler( 646 new BinaryStreamHandler(
@@ -461,10 +658,22 @@ namespace OpenSim.Region.ClientStack.Linden
461 string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase + 658 string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase +
462 uploaderPath; 659 uploaderPath;
463 660
661
464 LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse(); 662 LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse();
465 uploadResponse.uploader = uploaderURL; 663 uploadResponse.uploader = uploaderURL;
466 uploadResponse.state = "upload"; 664 uploadResponse.state = "upload";
665 uploadResponse.upload_price = (int)cost;
666
667 if (llsdRequest.asset_type == "mesh")
668 {
669 uploadResponse.data = meshcostdata;
670 }
671
467 uploader.OnUpLoad += UploadCompleteHandler; 672 uploader.OnUpLoad += UploadCompleteHandler;
673
674 lock (m_ModelCost)
675 m_FileAgentInventoryState = FileAgentInventoryState.waitUpload;
676
468 return uploadResponse; 677 return uploadResponse;
469 } 678 }
470 679
@@ -476,8 +685,14 @@ namespace OpenSim.Region.ClientStack.Linden
476 /// <param name="data"></param> 685 /// <param name="data"></param>
477 public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID, 686 public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID,
478 UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType, 687 UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType,
479 string assetType) 688 string assetType, int cost,
689 UUID texturesFolder, int nreqtextures, int nreqmeshs, int nreqinstances,
690 bool IsAtestUpload, ref string error)
480 { 691 {
692
693 lock (m_ModelCost)
694 m_FileAgentInventoryState = FileAgentInventoryState.processUpload;
695
481 m_log.DebugFormat( 696 m_log.DebugFormat(
482 "[BUNCH OF CAPS]: Uploaded asset {0} for inventory item {1}, inv type {2}, asset type {3}", 697 "[BUNCH OF CAPS]: Uploaded asset {0} for inventory item {1}, inv type {2}, asset type {3}",
483 assetID, inventoryItem, inventoryType, assetType); 698 assetID, inventoryItem, inventoryType, assetType);
@@ -485,117 +700,247 @@ namespace OpenSim.Region.ClientStack.Linden
485 sbyte assType = 0; 700 sbyte assType = 0;
486 sbyte inType = 0; 701 sbyte inType = 0;
487 702
703 IClientAPI client = null;
704
705 UUID owner_id = m_HostCapsObj.AgentID;
706 UUID creatorID;
707
708 bool istest = IsAtestUpload && m_enableFreeTestUpload && (cost > 0);
709
710 bool restrictPerms = m_RestrictFreeTestUploadPerms && istest;
711
712 if (istest && m_testAssetsCreatorID != UUID.Zero)
713 creatorID = m_testAssetsCreatorID;
714 else
715 creatorID = owner_id;
716
717 string creatorIDstr = creatorID.ToString();
718
719 IMoneyModule mm = m_Scene.RequestModuleInterface<IMoneyModule>();
720 if (mm != null)
721 {
722 // make sure client still has enougth credit
723 if (!mm.UploadCovered(m_HostCapsObj.AgentID, (int)cost))
724 {
725 error = "Insufficient funds.";
726 return;
727 }
728 }
729
730 // strings to types
488 if (inventoryType == "sound") 731 if (inventoryType == "sound")
489 { 732 {
490 inType = 1; 733 inType = (sbyte)InventoryType.Sound;
491 assType = 1; 734 assType = (sbyte)AssetType.Sound;
492 } 735 }
493 else if (inventoryType == "animation") 736 else if (inventoryType == "animation")
494 { 737 {
495 inType = 19; 738 inType = (sbyte)InventoryType.Animation;
496 assType = 20; 739 assType = (sbyte)AssetType.Animation;
497 } 740 }
498 else if (inventoryType == "wearable") 741 else if (inventoryType == "wearable")
499 { 742 {
500 inType = 18; 743 inType = (sbyte)InventoryType.Wearable;
501 switch (assetType) 744 switch (assetType)
502 { 745 {
503 case "bodypart": 746 case "bodypart":
504 assType = 13; 747 assType = (sbyte)AssetType.Bodypart;
505 break; 748 break;
506 case "clothing": 749 case "clothing":
507 assType = 5; 750 assType = (sbyte)AssetType.Clothing;
508 break; 751 break;
509 } 752 }
510 } 753 }
511 else if (inventoryType == "object") 754 else if (inventoryType == "object")
512 { 755 {
513 inType = (sbyte)InventoryType.Object; 756 if (assetType == "mesh") // this code for now is for mesh models uploads only
514 assType = (sbyte)AssetType.Object;
515
516 List<Vector3> positions = new List<Vector3>();
517 List<Quaternion> rotations = new List<Quaternion>();
518 OSDMap request = (OSDMap)OSDParser.DeserializeLLSDXml(data);
519 OSDArray instance_list = (OSDArray)request["instance_list"];
520 OSDArray mesh_list = (OSDArray)request["mesh_list"];
521 OSDArray texture_list = (OSDArray)request["texture_list"];
522 SceneObjectGroup grp = null;
523
524 List<UUID> textures = new List<UUID>();
525 for (int i = 0; i < texture_list.Count; i++)
526 { 757 {
527 AssetBase textureAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Texture, ""); 758 inType = (sbyte)InventoryType.Object;
528 textureAsset.Data = texture_list[i].AsBinary(); 759 assType = (sbyte)AssetType.Object;
529 m_assetService.Store(textureAsset);
530 textures.Add(textureAsset.FullID);
531 }
532 760
533 for (int i = 0; i < mesh_list.Count; i++) 761 List<Vector3> positions = new List<Vector3>();
534 { 762 List<Quaternion> rotations = new List<Quaternion>();
535 PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateBox(); 763 OSDMap request = (OSDMap)OSDParser.DeserializeLLSDXml(data);
764
765 // compare and get updated information
536 766
537 Primitive.TextureEntry textureEntry 767 bool mismatchError = true;
538 = new Primitive.TextureEntry(Primitive.TextureEntry.WHITE_TEXTURE);
539 OSDMap inner_instance_list = (OSDMap)instance_list[i];
540 768
541 OSDArray face_list = (OSDArray)inner_instance_list["face_list"]; 769 while (mismatchError)
542 for (uint face = 0; face < face_list.Count; face++)
543 { 770 {
544 OSDMap faceMap = (OSDMap)face_list[(int)face]; 771 mismatchError = false;
545 Primitive.TextureEntryFace f = pbs.Textures.CreateFace(face); 772 }
546 if(faceMap.ContainsKey("fullbright"))
547 f.Fullbright = faceMap["fullbright"].AsBoolean();
548 if (faceMap.ContainsKey ("diffuse_color"))
549 f.RGBA = faceMap["diffuse_color"].AsColor4();
550 773
551 int textureNum = faceMap["image"].AsInteger(); 774 if (mismatchError)
552 float imagerot = faceMap["imagerot"].AsInteger(); 775 {
553 float offsets = (float)faceMap["offsets"].AsReal(); 776 error = "Upload and fee estimation information don't match";
554 float offsett = (float)faceMap["offsett"].AsReal(); 777 lock (m_ModelCost)
555 float scales = (float)faceMap["scales"].AsReal(); 778 m_FileAgentInventoryState = FileAgentInventoryState.idle;
556 float scalet = (float)faceMap["scalet"].AsReal();
557 779
558 if(imagerot != 0) 780 return;
559 f.Rotation = imagerot; 781 }
560 782
561 if(offsets != 0) 783 OSDArray instance_list = (OSDArray)request["instance_list"];
562 f.OffsetU = offsets; 784 OSDArray mesh_list = (OSDArray)request["mesh_list"];
785 OSDArray texture_list = (OSDArray)request["texture_list"];
786 SceneObjectGroup grp = null;
563 787
564 if (offsett != 0) 788 // create and store texture assets
565 f.OffsetV = offsett; 789 bool doTextInv = (!istest && m_enableModelUploadTextureToInventory &&
790 texturesFolder != UUID.Zero);
566 791
567 if (scales != 0)
568 f.RepeatU = scales;
569 792
570 if (scalet != 0) 793 List<UUID> textures = new List<UUID>();
571 f.RepeatV = scalet;
572 794
573 if (textures.Count > textureNum) 795
574 f.TextureID = textures[textureNum]; 796 if (doTextInv)
575 else 797 m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client);
576 f.TextureID = Primitive.TextureEntry.WHITE_TEXTURE;
577 798
578 textureEntry.FaceTextures[face] = f; 799 if(client == null) // don't put textures in inventory if there is no client
800 doTextInv = false;
801
802 for (int i = 0; i < texture_list.Count; i++)
803 {
804 AssetBase textureAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Texture, creatorIDstr);
805 textureAsset.Data = texture_list[i].AsBinary();
806 if (istest)
807 textureAsset.Local = true;
808 m_assetService.Store(textureAsset);
809 textures.Add(textureAsset.FullID);
810
811 if (doTextInv)
812 {
813 string name = assetName;
814 if (name.Length > 25)
815 name = name.Substring(0, 24);
816 name += "_Texture#" + i.ToString();
817 InventoryItemBase texitem = new InventoryItemBase();
818 texitem.Owner = m_HostCapsObj.AgentID;
819 texitem.CreatorId = creatorIDstr;
820 texitem.CreatorData = String.Empty;
821 texitem.ID = UUID.Random();
822 texitem.AssetID = textureAsset.FullID;
823 texitem.Description = "mesh model texture";
824 texitem.Name = name;
825 texitem.AssetType = (int)AssetType.Texture;
826 texitem.InvType = (int)InventoryType.Texture;
827 texitem.Folder = texturesFolder;
828
829 texitem.CurrentPermissions
830 = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer);
831
832 texitem.BasePermissions = (uint)PermissionMask.All;
833 texitem.EveryOnePermissions = 0;
834 texitem.NextPermissions = (uint)PermissionMask.All;
835 texitem.CreationDate = Util.UnixTimeSinceEpoch();
836
837 m_Scene.AddInventoryItem(client, texitem);
838 texitem = null;
839 }
579 } 840 }
580 841
581 pbs.TextureEntry = textureEntry.GetBytes(); 842 // create and store meshs assets
843 List<UUID> meshAssets = new List<UUID>();
844 for (int i = 0; i < mesh_list.Count; i++)
845 {
846 AssetBase meshAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Mesh, creatorIDstr);
847 meshAsset.Data = mesh_list[i].AsBinary();
848 if (istest)
849 meshAsset.Local = true;
850 m_assetService.Store(meshAsset);
851 meshAssets.Add(meshAsset.FullID);
852 }
582 853
583 AssetBase meshAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Mesh, ""); 854 int skipedMeshs = 0;
584 meshAsset.Data = mesh_list[i].AsBinary(); 855 // build prims from instances
585 m_assetService.Store(meshAsset); 856 for (int i = 0; i < instance_list.Count; i++)
857 {
858 OSDMap inner_instance_list = (OSDMap)instance_list[i];
586 859
587 pbs.SculptEntry = true; 860 // skip prims that are 2 small
588 pbs.SculptTexture = meshAsset.FullID; 861 Vector3 scale = inner_instance_list["scale"].AsVector3();
589 pbs.SculptType = (byte)SculptType.Mesh;
590 pbs.SculptData = meshAsset.Data;
591 862
592 Vector3 position = inner_instance_list["position"].AsVector3(); 863 if (scale.X < m_PrimScaleMin || scale.Y < m_PrimScaleMin || scale.Z < m_PrimScaleMin)
593 Vector3 scale = inner_instance_list["scale"].AsVector3(); 864 {
594 Quaternion rotation = inner_instance_list["rotation"].AsQuaternion(); 865 skipedMeshs++;
866 continue;
867 }
868
869 PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateBox();
870
871 Primitive.TextureEntry textureEntry
872 = new Primitive.TextureEntry(Primitive.TextureEntry.WHITE_TEXTURE);
873
874
875 OSDArray face_list = (OSDArray)inner_instance_list["face_list"];
876 for (uint face = 0; face < face_list.Count; face++)
877 {
878 OSDMap faceMap = (OSDMap)face_list[(int)face];
879 Primitive.TextureEntryFace f = pbs.Textures.CreateFace(face);
880 if (faceMap.ContainsKey("fullbright"))
881 f.Fullbright = faceMap["fullbright"].AsBoolean();
882 if (faceMap.ContainsKey("diffuse_color"))
883 f.RGBA = faceMap["diffuse_color"].AsColor4();
884
885 int textureNum = faceMap["image"].AsInteger();
886 float imagerot = faceMap["imagerot"].AsInteger();
887 float offsets = (float)faceMap["offsets"].AsReal();
888 float offsett = (float)faceMap["offsett"].AsReal();
889 float scales = (float)faceMap["scales"].AsReal();
890 float scalet = (float)faceMap["scalet"].AsReal();
891
892 if (imagerot != 0)
893 f.Rotation = imagerot;
894
895 if (offsets != 0)
896 f.OffsetU = offsets;
897
898 if (offsett != 0)
899 f.OffsetV = offsett;
900
901 if (scales != 0)
902 f.RepeatU = scales;
903
904 if (scalet != 0)
905 f.RepeatV = scalet;
906
907 if (textures.Count > textureNum)
908 f.TextureID = textures[textureNum];
909 else
910 f.TextureID = Primitive.TextureEntry.WHITE_TEXTURE;
911
912 textureEntry.FaceTextures[face] = f;
913 }
914
915 pbs.TextureEntry = textureEntry.GetBytes();
916
917 bool hasmesh = false;
918 if (inner_instance_list.ContainsKey("mesh")) // seems to happen always but ...
919 {
920 int meshindx = inner_instance_list["mesh"].AsInteger();
921 if (meshAssets.Count > meshindx)
922 {
923 pbs.SculptEntry = true;
924 pbs.SculptType = (byte)SculptType.Mesh;
925 pbs.SculptTexture = meshAssets[meshindx]; // actual asset UUID after meshs suport introduction
926 // data will be requested from asset on rez (i hope)
927 hasmesh = true;
928 }
929 }
930
931 Vector3 position = inner_instance_list["position"].AsVector3();
932 Quaternion rotation = inner_instance_list["rotation"].AsQuaternion();
933
934 // for now viwers do send fixed defaults
935 // but this may change
936// int physicsShapeType = inner_instance_list["physics_shape_type"].AsInteger();
937 byte physicsShapeType = (byte)PhysShapeType.prim; // default for mesh is simple convex
938 if(hasmesh)
939 physicsShapeType = (byte) PhysShapeType.convex; // default for mesh is simple convex
940// int material = inner_instance_list["material"].AsInteger();
941 byte material = (byte)Material.Wood;
595 942
596// no longer used - begin ------------------------ 943// no longer used - begin ------------------------
597// int physicsShapeType = inner_instance_list["physics_shape_type"].AsInteger();
598// int material = inner_instance_list["material"].AsInteger();
599// int mesh = inner_instance_list["mesh"].AsInteger(); 944// int mesh = inner_instance_list["mesh"].AsInteger();
600 945
601// OSDMap permissions = (OSDMap)inner_instance_list["permissions"]; 946// OSDMap permissions = (OSDMap)inner_instance_list["permissions"];
@@ -610,24 +955,42 @@ namespace OpenSim.Region.ClientStack.Linden
610// UUID owner_id = permissions["owner_id"].AsUUID(); 955// UUID owner_id = permissions["owner_id"].AsUUID();
611// int owner_mask = permissions["owner_mask"].AsInteger(); 956// int owner_mask = permissions["owner_mask"].AsInteger();
612// no longer used - end ------------------------ 957// no longer used - end ------------------------
958
959
960 SceneObjectPart prim
961 = new SceneObjectPart(owner_id, pbs, position, Quaternion.Identity, Vector3.Zero);
962
963 prim.Scale = scale;
964 rotations.Add(rotation);
965 positions.Add(position);
966 prim.UUID = UUID.Random();
967 prim.CreatorID = creatorID;
968 prim.OwnerID = owner_id;
969 prim.GroupID = UUID.Zero;
970 prim.LastOwnerID = creatorID;
971 prim.CreationDate = Util.UnixTimeSinceEpoch();
972
973 if (grp == null)
974 prim.Name = assetName;
975 else
976 prim.Name = assetName + "#" + i.ToString();
613 977
614 UUID owner_id = m_HostCapsObj.AgentID; 978 if (restrictPerms)
979 {
980 prim.BaseMask = (uint)(PermissionMask.Move | PermissionMask.Modify);
981 prim.EveryoneMask = 0;
982 prim.GroupMask = 0;
983 prim.NextOwnerMask = 0;
984 prim.OwnerMask = (uint)(PermissionMask.Move | PermissionMask.Modify);
985 }
615 986
616 SceneObjectPart prim 987 if(istest)
617 = new SceneObjectPart(owner_id, pbs, position, Quaternion.Identity, Vector3.Zero); 988 prim.Description = "For testing only. Other uses are prohibited";
989 else
990 prim.Description = "";
618 991
619 prim.Scale = scale; 992 prim.Material = material;
620 prim.OffsetPosition = position; 993 prim.PhysicsShapeType = physicsShapeType;
621 rotations.Add(rotation);
622 positions.Add(position);
623 prim.UUID = UUID.Random();
624 prim.CreatorID = owner_id;
625 prim.OwnerID = owner_id;
626 prim.GroupID = UUID.Zero;
627 prim.LastOwnerID = prim.OwnerID;
628 prim.CreationDate = Util.UnixTimeSinceEpoch();
629 prim.Name = assetName;
630 prim.Description = "";
631 994
632// prim.BaseMask = (uint)base_mask; 995// prim.BaseMask = (uint)base_mask;
633// prim.EveryoneMask = (uint)everyone_mask; 996// prim.EveryoneMask = (uint)everyone_mask;
@@ -635,37 +998,64 @@ namespace OpenSim.Region.ClientStack.Linden
635// prim.NextOwnerMask = (uint)next_owner_mask; 998// prim.NextOwnerMask = (uint)next_owner_mask;
636// prim.OwnerMask = (uint)owner_mask; 999// prim.OwnerMask = (uint)owner_mask;
637 1000
638 if (grp == null) 1001 if (grp == null)
639 grp = new SceneObjectGroup(prim); 1002 {
640 else 1003 grp = new SceneObjectGroup(prim);
641 grp.AddPart(prim); 1004 grp.LastOwnerID = creatorID;
642 } 1005 }
1006 else
1007 grp.AddPart(prim);
1008 }
643 1009
644 // Fix first link number 1010 Vector3 rootPos = positions[0];
645 if (grp.Parts.Length > 1)
646 grp.RootPart.LinkNum++;
647 1011
648 Vector3 rootPos = positions[0]; 1012 if (grp.Parts.Length > 1)
649 grp.AbsolutePosition = rootPos; 1013 {
650 for (int i = 0; i < positions.Count; i++) 1014 // Fix first link number
651 { 1015 grp.RootPart.LinkNum++;
652 Vector3 offset = positions[i] - rootPos; 1016
653 grp.Parts[i].OffsetPosition = offset; 1017 Quaternion rootRotConj = Quaternion.Conjugate(rotations[0]);
1018 Quaternion tmprot;
1019 Vector3 offset;
1020
1021 // fix children rotations and positions
1022 for (int i = 1; i < rotations.Count; i++)
1023 {
1024 tmprot = rotations[i];
1025 tmprot = rootRotConj * tmprot;
1026
1027 grp.Parts[i].RotationOffset = tmprot;
1028
1029 offset = positions[i] - rootPos;
1030
1031 offset *= rootRotConj;
1032 grp.Parts[i].OffsetPosition = offset;
1033 }
1034
1035 grp.AbsolutePosition = rootPos;
1036 grp.UpdateGroupRotationR(rotations[0]);
1037 }
1038 else
1039 {
1040 grp.AbsolutePosition = rootPos;
1041 grp.UpdateGroupRotationR(rotations[0]);
1042 }
1043
1044 data = ASCIIEncoding.ASCII.GetBytes(SceneObjectSerializer.ToOriginalXmlFormat(grp));
654 } 1045 }
655 1046
656 for (int i = 0; i < rotations.Count; i++) 1047 else // not a mesh model
657 { 1048 {
658 if (i != 0) 1049 m_log.ErrorFormat("[CAPS Asset Upload] got unsuported assetType for object upload");
659 grp.Parts[i].RotationOffset = rotations[i]; 1050 return;
660 } 1051 }
661
662 grp.UpdateGroupRotationR(rotations[0]);
663 data = ASCIIEncoding.ASCII.GetBytes(SceneObjectSerializer.ToOriginalXmlFormat(grp));
664 } 1052 }
665 1053
666 AssetBase asset; 1054 AssetBase asset;
667 asset = new AssetBase(assetID, assetName, assType, m_HostCapsObj.AgentID.ToString()); 1055 asset = new AssetBase(assetID, assetName, assType, creatorIDstr);
668 asset.Data = data; 1056 asset.Data = data;
1057 if (istest)
1058 asset.Local = true;
669 if (AddNewAsset != null) 1059 if (AddNewAsset != null)
670 AddNewAsset(asset); 1060 AddNewAsset(asset);
671 else if (m_assetService != null) 1061 else if (m_assetService != null)
@@ -673,11 +1063,17 @@ namespace OpenSim.Region.ClientStack.Linden
673 1063
674 InventoryItemBase item = new InventoryItemBase(); 1064 InventoryItemBase item = new InventoryItemBase();
675 item.Owner = m_HostCapsObj.AgentID; 1065 item.Owner = m_HostCapsObj.AgentID;
676 item.CreatorId = m_HostCapsObj.AgentID.ToString(); 1066 item.CreatorId = creatorIDstr;
677 item.CreatorData = String.Empty; 1067 item.CreatorData = String.Empty;
678 item.ID = inventoryItem; 1068 item.ID = inventoryItem;
679 item.AssetID = asset.FullID; 1069 item.AssetID = asset.FullID;
680 item.Description = assetDescription; 1070 if (istest)
1071 {
1072 item.Description = "For testing only. Other uses are prohibited";
1073 item.Flags = (uint) (InventoryItemFlags.SharedSingleReference);
1074 }
1075 else
1076 item.Description = assetDescription;
681 item.Name = assetName; 1077 item.Name = assetName;
682 item.AssetType = assType; 1078 item.AssetType = assType;
683 item.InvType = inType; 1079 item.InvType = inType;
@@ -685,18 +1081,60 @@ namespace OpenSim.Region.ClientStack.Linden
685 1081
686 // If we set PermissionMask.All then when we rez the item the next permissions will replace the current 1082 // If we set PermissionMask.All then when we rez the item the next permissions will replace the current
687 // (owner) permissions. This becomes a problem if next permissions are changed. 1083 // (owner) permissions. This becomes a problem if next permissions are changed.
688 item.CurrentPermissions
689 = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer);
690 1084
691 item.BasePermissions = (uint)PermissionMask.All; 1085 if (restrictPerms)
692 item.EveryOnePermissions = 0; 1086 {
693 item.NextPermissions = (uint)PermissionMask.All; 1087 item.CurrentPermissions
1088 = (uint)(PermissionMask.Move | PermissionMask.Modify);
1089
1090 item.BasePermissions = (uint)(PermissionMask.Move | PermissionMask.Modify);
1091 item.EveryOnePermissions = 0;
1092 item.NextPermissions = 0;
1093 }
1094 else
1095 {
1096 item.CurrentPermissions
1097 = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer);
1098
1099 item.BasePermissions = (uint)PermissionMask.All;
1100 item.EveryOnePermissions = 0;
1101 item.NextPermissions = (uint)PermissionMask.All;
1102 }
1103
694 item.CreationDate = Util.UnixTimeSinceEpoch(); 1104 item.CreationDate = Util.UnixTimeSinceEpoch();
695 1105
1106 m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client);
1107
696 if (AddNewInventoryItem != null) 1108 if (AddNewInventoryItem != null)
697 { 1109 {
698 AddNewInventoryItem(m_HostCapsObj.AgentID, item); 1110 if (istest)
1111 {
1112 m_Scene.AddInventoryItem(client, item);
1113/*
1114 AddNewInventoryItem(m_HostCapsObj.AgentID, item, 0);
1115 if (client != null)
1116 client.SendAgentAlertMessage("Upload will have no cost, for personal test purposes only. Other uses are forbiden. Items may not work on a another region" , true);
1117 */
1118 }
1119 else
1120 {
1121 AddNewInventoryItem(m_HostCapsObj.AgentID, item, (uint)cost);
1122// if (client != null)
1123// {
1124// // let users see anything.. i don't so far
1125// string str;
1126// if (cost > 0)
1127// // dont remember where is money unit name to put here
1128// str = "Upload complete. charged " + cost.ToString() + "$";
1129// else
1130// str = "Upload complete";
1131// client.SendAgentAlertMessage(str, true);
1132// }
1133 }
699 } 1134 }
1135
1136 lock (m_ModelCost)
1137 m_FileAgentInventoryState = FileAgentInventoryState.idle;
700 } 1138 }
701 1139
702 /// <summary> 1140 /// <summary>
@@ -858,6 +1296,151 @@ namespace OpenSim.Region.ClientStack.Linden
858 return LLSDHelpers.SerialiseLLSDReply(response); 1296 return LLSDHelpers.SerialiseLLSDReply(response);
859 } 1297 }
860 1298
1299 public string GetObjectPhysicsData(string request, string path,
1300 string param, IOSHttpRequest httpRequest,
1301 IOSHttpResponse httpResponse)
1302 {
1303 OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request);
1304 OSDMap resp = new OSDMap();
1305 OSDArray object_ids = (OSDArray)req["object_ids"];
1306
1307 for (int i = 0 ; i < object_ids.Count ; i++)
1308 {
1309 UUID uuid = object_ids[i].AsUUID();
1310
1311 SceneObjectPart obj = m_Scene.GetSceneObjectPart(uuid);
1312 if (obj != null)
1313 {
1314 OSDMap object_data = new OSDMap();
1315
1316 object_data["PhysicsShapeType"] = obj.PhysicsShapeType;
1317 object_data["Density"] = obj.Density;
1318 object_data["Friction"] = obj.Friction;
1319 object_data["Restitution"] = obj.Bounciness;
1320 object_data["GravityMultiplier"] = obj.GravityModifier;
1321
1322 resp[uuid.ToString()] = object_data;
1323 }
1324 }
1325
1326 string response = OSDParser.SerializeLLSDXmlString(resp);
1327 return response;
1328 }
1329
1330 public string GetObjectCost(string request, string path,
1331 string param, IOSHttpRequest httpRequest,
1332 IOSHttpResponse httpResponse)
1333 {
1334 OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request);
1335 OSDMap resp = new OSDMap();
1336
1337 OSDArray object_ids = (OSDArray)req["object_ids"];
1338
1339 for (int i = 0; i < object_ids.Count; i++)
1340 {
1341 UUID uuid = object_ids[i].AsUUID();
1342
1343 SceneObjectPart part = m_Scene.GetSceneObjectPart(uuid);
1344
1345 if (part != null)
1346 {
1347 SceneObjectGroup grp = part.ParentGroup;
1348 if (grp != null)
1349 {
1350 float linksetCost;
1351 float linksetPhysCost;
1352 float partCost;
1353 float partPhysCost;
1354
1355 grp.GetResourcesCosts(part, out linksetCost, out linksetPhysCost, out partCost, out partPhysCost);
1356
1357 OSDMap object_data = new OSDMap();
1358 object_data["linked_set_resource_cost"] = linksetCost;
1359 object_data["resource_cost"] = partCost;
1360 object_data["physics_cost"] = partPhysCost;
1361 object_data["linked_set_physics_cost"] = linksetPhysCost;
1362
1363 resp[uuid.ToString()] = object_data;
1364 }
1365 }
1366 }
1367
1368 string response = OSDParser.SerializeLLSDXmlString(resp);
1369 return response;
1370 }
1371
1372 public string ResourceCostSelected(string request, string path,
1373 string param, IOSHttpRequest httpRequest,
1374 IOSHttpResponse httpResponse)
1375 {
1376 OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request);
1377 OSDMap resp = new OSDMap();
1378
1379
1380 float phys=0;
1381 float stream=0;
1382 float simul=0;
1383
1384 if (req.ContainsKey("selected_roots"))
1385 {
1386 OSDArray object_ids = (OSDArray)req["selected_roots"];
1387
1388 // should go by SOG suming costs for all parts
1389 // ll v3 works ok with several objects select we get the list and adds ok
1390 // FS calls per object so results are wrong guess fs bug
1391 for (int i = 0; i < object_ids.Count; i++)
1392 {
1393 UUID uuid = object_ids[i].AsUUID();
1394 float Physc;
1395 float simulc;
1396 float streamc;
1397
1398 SceneObjectGroup grp = m_Scene.GetGroupByPrim(uuid);
1399 if (grp != null)
1400 {
1401 grp.GetSelectedCosts(out Physc, out streamc, out simulc);
1402 phys += Physc;
1403 stream += streamc;
1404 simul += simulc;
1405 }
1406 }
1407 }
1408 else if (req.ContainsKey("selected_prims"))
1409 {
1410 OSDArray object_ids = (OSDArray)req["selected_prims"];
1411
1412 // don't see in use in any of the 2 viewers
1413 // guess it should be for edit linked but... nothing
1414 // should go to SOP per part
1415 for (int i = 0; i < object_ids.Count; i++)
1416 {
1417 UUID uuid = object_ids[i].AsUUID();
1418
1419 SceneObjectPart part = m_Scene.GetSceneObjectPart(uuid);
1420 if (part != null)
1421 {
1422 phys += part.PhysicsCost;
1423 stream += part.StreamingCost;
1424 simul += part.SimulationCost;
1425 }
1426 }
1427 }
1428
1429 if (simul != 0)
1430 {
1431 OSDMap object_data = new OSDMap();
1432
1433 object_data["physics"] = phys;
1434 object_data["streaming"] = stream;
1435 object_data["simulation"] = simul;
1436
1437 resp["selected"] = object_data;
1438 }
1439
1440 string response = OSDParser.SerializeLLSDXmlString(resp);
1441 return response;
1442 }
1443
861 public string UpdateAgentInformation(string request, string path, 1444 public string UpdateAgentInformation(string request, string path,
862 string param, IOSHttpRequest httpRequest, 1445 string param, IOSHttpRequest httpRequest,
863 IOSHttpResponse httpResponse) 1446 IOSHttpResponse httpResponse)
@@ -877,6 +1460,10 @@ namespace OpenSim.Region.ClientStack.Linden
877 1460
878 public class AssetUploader 1461 public class AssetUploader
879 { 1462 {
1463 private static readonly ILog m_log =
1464 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
1465
1466
880 public event UpLoadedAsset OnUpLoad; 1467 public event UpLoadedAsset OnUpLoad;
881 private UpLoadedAsset handlerUpLoad = null; 1468 private UpLoadedAsset handlerUpLoad = null;
882 1469
@@ -891,10 +1478,21 @@ namespace OpenSim.Region.ClientStack.Linden
891 1478
892 private string m_invType = String.Empty; 1479 private string m_invType = String.Empty;
893 private string m_assetType = String.Empty; 1480 private string m_assetType = String.Empty;
1481 private int m_cost;
1482 private string m_error = String.Empty;
1483
1484 private Timer m_timeoutTimer = new Timer();
1485 private UUID m_texturesFolder;
1486 private int m_nreqtextures;
1487 private int m_nreqmeshs;
1488 private int m_nreqinstances;
1489 private bool m_IsAtestUpload;
894 1490
895 public AssetUploader(string assetName, string description, UUID assetID, UUID inventoryItem, 1491 public AssetUploader(string assetName, string description, UUID assetID, UUID inventoryItem,
896 UUID parentFolderID, string invType, string assetType, string path, 1492 UUID parentFolderID, string invType, string assetType, string path,
897 IHttpServer httpServer, bool dumpAssetsToFile) 1493 IHttpServer httpServer, bool dumpAssetsToFile,
1494 int totalCost, UUID texturesFolder, int nreqtextures, int nreqmeshs, int nreqinstances,
1495 bool IsAtestUpload)
898 { 1496 {
899 m_assetName = assetName; 1497 m_assetName = assetName;
900 m_assetDes = description; 1498 m_assetDes = description;
@@ -906,6 +1504,18 @@ namespace OpenSim.Region.ClientStack.Linden
906 m_assetType = assetType; 1504 m_assetType = assetType;
907 m_invType = invType; 1505 m_invType = invType;
908 m_dumpAssetsToFile = dumpAssetsToFile; 1506 m_dumpAssetsToFile = dumpAssetsToFile;
1507 m_cost = totalCost;
1508
1509 m_texturesFolder = texturesFolder;
1510 m_nreqtextures = nreqtextures;
1511 m_nreqmeshs = nreqmeshs;
1512 m_nreqinstances = nreqinstances;
1513 m_IsAtestUpload = IsAtestUpload;
1514
1515 m_timeoutTimer.Elapsed += TimedOut;
1516 m_timeoutTimer.Interval = 120000;
1517 m_timeoutTimer.AutoReset = false;
1518 m_timeoutTimer.Start();
909 } 1519 }
910 1520
911 /// <summary> 1521 /// <summary>
@@ -920,12 +1530,14 @@ namespace OpenSim.Region.ClientStack.Linden
920 UUID inv = inventoryItemID; 1530 UUID inv = inventoryItemID;
921 string res = String.Empty; 1531 string res = String.Empty;
922 LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete(); 1532 LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete();
1533/*
923 uploadComplete.new_asset = newAssetID.ToString(); 1534 uploadComplete.new_asset = newAssetID.ToString();
924 uploadComplete.new_inventory_item = inv; 1535 uploadComplete.new_inventory_item = inv;
925 uploadComplete.state = "complete"; 1536 uploadComplete.state = "complete";
926 1537
927 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete); 1538 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
928 1539*/
1540 m_timeoutTimer.Stop();
929 httpListener.RemoveStreamHandler("POST", uploaderPath); 1541 httpListener.RemoveStreamHandler("POST", uploaderPath);
930 1542
931 // TODO: probably make this a better set of extensions here 1543 // TODO: probably make this a better set of extensions here
@@ -942,12 +1554,49 @@ namespace OpenSim.Region.ClientStack.Linden
942 handlerUpLoad = OnUpLoad; 1554 handlerUpLoad = OnUpLoad;
943 if (handlerUpLoad != null) 1555 if (handlerUpLoad != null)
944 { 1556 {
945 handlerUpLoad(m_assetName, m_assetDes, newAssetID, inv, parentFolder, data, m_invType, m_assetType); 1557 handlerUpLoad(m_assetName, m_assetDes, newAssetID, inv, parentFolder, data, m_invType, m_assetType,
1558 m_cost, m_texturesFolder, m_nreqtextures, m_nreqmeshs, m_nreqinstances, m_IsAtestUpload, ref m_error);
946 } 1559 }
1560 if (m_IsAtestUpload)
1561 {
1562 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
1563 resperror.message = "Upload SUCESSEFULL for testing purposes only. Other uses are prohibited. Item will not work after 48 hours or on other regions";
1564 resperror.identifier = inv;
1565
1566 uploadComplete.error = resperror;
1567 uploadComplete.state = "Upload4Testing";
1568 }
1569 else
1570 {
1571 if (m_error == String.Empty)
1572 {
1573 uploadComplete.new_asset = newAssetID.ToString();
1574 uploadComplete.new_inventory_item = inv;
1575 // if (m_texturesFolder != UUID.Zero)
1576 // uploadComplete.new_texture_folder_id = m_texturesFolder;
1577 uploadComplete.state = "complete";
1578 }
1579 else
1580 {
1581 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
1582 resperror.message = m_error;
1583 resperror.identifier = inv;
947 1584
1585 uploadComplete.error = resperror;
1586 uploadComplete.state = "failed";
1587 }
1588 }
1589
1590 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
948 return res; 1591 return res;
949 } 1592 }
950 1593
1594 private void TimedOut(object sender, ElapsedEventArgs args)
1595 {
1596 m_log.InfoFormat("[CAPS]: Removing URL and handler for timed out mesh upload");
1597 httpListener.RemoveStreamHandler("POST", uploaderPath);
1598 }
1599
951 ///Left this in and commented in case there are unforseen issues 1600 ///Left this in and commented in case there are unforseen issues
952 //private void SaveAssetToFile(string filename, byte[] data) 1601 //private void SaveAssetToFile(string filename, byte[] data)
953 //{ 1602 //{
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/MeshCost.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/MeshCost.cs
new file mode 100644
index 0000000..4a3fae6
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/MeshCost.cs
@@ -0,0 +1,671 @@
1// Proprietary code of Avination Virtual Limited
2// (c) 2012 Melanie Thielker, Leal Duarte
3//
4
5using System;
6using System.IO;
7using System.Collections;
8using System.Collections.Generic;
9using System.Text;
10
11using OpenMetaverse;
12using OpenMetaverse.StructuredData;
13
14using OpenSim.Framework;
15using OpenSim.Region.Framework;
16using OpenSim.Region.Framework.Scenes;
17using OpenSim.Framework.Capabilities;
18
19using ComponentAce.Compression.Libs.zlib;
20
21using OSDArray = OpenMetaverse.StructuredData.OSDArray;
22using OSDMap = OpenMetaverse.StructuredData.OSDMap;
23
24namespace OpenSim.Region.ClientStack.Linden
25{
26 public struct ModelPrimLimits
27 {
28
29 }
30
31 public class ModelCost
32 {
33
34 // upload fee defaults
35 // fees are normalized to 1.0
36 // this parameters scale them to basic cost ( so 1.0 translates to 10 )
37
38 public float ModelMeshCostFactor = 0.0f; // scale total cost relative to basic (excluding textures)
39 public float ModelTextureCostFactor = 1.0f; // scale textures fee to basic.
40 public float ModelMinCostFactor = 0.0f; // 0.5f; // minimum total model free excluding textures
41
42 // itens costs in normalized values
43 // ie will be multiplied by basicCost and factors above
44 public float primCreationCost = 0.002f; // extra cost for each prim creation overhead
45 // weigthed size to normalized cost
46 public float bytecost = 1e-5f;
47
48 // mesh upload fees based on compressed data sizes
49 // several data sections are counted more that once
50 // to promote user optimization
51 // following parameters control how many extra times they are added
52 // to global size.
53 // LOD meshs
54 const float medSizeWth = 1f; // 2x
55 const float lowSizeWth = 1.5f; // 2.5x
56 const float lowestSizeWth = 2f; // 3x
57 // favor potencially physical optimized meshs versus automatic decomposition
58 const float physMeshSizeWth = 6f; // counts 7x
59 const float physHullSizeWth = 8f; // counts 9x
60
61 // stream cost area factors
62 // more or less like SL
63 const float highLodFactor = 17.36f;
64 const float midLodFactor = 277.78f;
65 const float lowLodFactor = 1111.11f;
66
67 // physics cost is below, identical to SL, assuming shape type convex
68 // server cost is below identical to SL assuming non scripted non physical object
69
70 // internal
71 const int bytesPerCoord = 6; // 3 coords, 2 bytes per each
72
73 // control prims dimensions
74 public float PrimScaleMin = 0.001f;
75 public float NonPhysicalPrimScaleMax = 256f;
76 public float PhysicalPrimScaleMax = 10f;
77 public int ObjectLinkedPartsMax = 512;
78
79 // storage for a single mesh asset cost parameters
80 private class ameshCostParam
81 {
82 // LOD sizes for size dependent streaming cost
83 public int highLODSize;
84 public int medLODSize;
85 public int lowLODSize;
86 public int lowestLODSize;
87 // normalized fee based on compressed data sizes
88 public float costFee;
89 // physics cost
90 public float physicsCost;
91 }
92
93 // calculates a mesh model costs
94 // returns false on error, with a reason on parameter error
95 // resources input LLSD request
96 // basicCost input region assets upload cost
97 // totalcost returns model total upload fee
98 // meshcostdata returns detailed costs for viewer
99 public bool MeshModelCost(LLSDAssetResource resources, int basicCost, out int totalcost,
100 LLSDAssetUploadResponseData meshcostdata, out string error, ref string warning)
101 {
102 totalcost = 0;
103 error = string.Empty;
104
105 if (resources == null ||
106 resources.instance_list == null ||
107 resources.instance_list.Array.Count == 0)
108 {
109 error = "missing model information.";
110 return false;
111 }
112
113 int numberInstances = resources.instance_list.Array.Count;
114
115 if( numberInstances > ObjectLinkedPartsMax )
116 {
117 error = "Model whould have more than " + ObjectLinkedPartsMax.ToString() + " linked prims";
118 return false;
119 }
120
121 meshcostdata.model_streaming_cost = 0.0;
122 meshcostdata.simulation_cost = 0.0;
123 meshcostdata.physics_cost = 0.0;
124 meshcostdata.resource_cost = 0.0;
125
126 meshcostdata.upload_price_breakdown.mesh_instance = 0;
127 meshcostdata.upload_price_breakdown.mesh_physics = 0;
128 meshcostdata.upload_price_breakdown.mesh_streaming = 0;
129 meshcostdata.upload_price_breakdown.model = 0;
130
131 int itmp;
132
133 // textures cost
134 if (resources.texture_list != null && resources.texture_list.Array.Count > 0)
135 {
136 float textures_cost = (float)(resources.texture_list.Array.Count * basicCost);
137 textures_cost *= ModelTextureCostFactor;
138
139 itmp = (int)(textures_cost + 0.5f); // round
140 meshcostdata.upload_price_breakdown.texture = itmp;
141 totalcost += itmp;
142 }
143
144 // meshs assets cost
145 float meshsfee = 0;
146 int numberMeshs = 0;
147 bool haveMeshs = false;
148 List<ameshCostParam> meshsCosts = new List<ameshCostParam>();
149
150 if (resources.mesh_list != null && resources.mesh_list.Array.Count > 0)
151 {
152 numberMeshs = resources.mesh_list.Array.Count;
153
154 for (int i = 0; i < numberMeshs; i++)
155 {
156 ameshCostParam curCost = new ameshCostParam();
157 byte[] data = (byte[])resources.mesh_list.Array[i];
158
159 if (!MeshCost(data, curCost, out error))
160 {
161 return false;
162 }
163 meshsCosts.Add(curCost);
164 meshsfee += curCost.costFee;
165 }
166 haveMeshs = true;
167 }
168
169 // instances (prims) cost
170
171
172 int mesh;
173 int skipedSmall = 0;
174 for (int i = 0; i < numberInstances; i++)
175 {
176 Hashtable inst = (Hashtable)resources.instance_list.Array[i];
177
178 ArrayList ascale = (ArrayList)inst["scale"];
179 Vector3 scale;
180 double tmp;
181 tmp = (double)ascale[0];
182 scale.X = (float)tmp;
183 tmp = (double)ascale[1];
184 scale.Y = (float)tmp;
185 tmp = (double)ascale[2];
186 scale.Z = (float)tmp;
187
188 if (scale.X < PrimScaleMin || scale.Y < PrimScaleMin || scale.Z < PrimScaleMin)
189 {
190 skipedSmall++;
191 continue;
192 }
193
194 if (scale.X > NonPhysicalPrimScaleMax || scale.Y > NonPhysicalPrimScaleMax || scale.Z > NonPhysicalPrimScaleMax)
195 {
196 error = "Model contains parts with sides larger than " + NonPhysicalPrimScaleMax.ToString() + "m. Please ajust scale";
197 return false;
198 }
199
200 if (haveMeshs && inst.ContainsKey("mesh"))
201 {
202 mesh = (int)inst["mesh"];
203
204 if (mesh >= numberMeshs)
205 {
206 error = "Incoerent model information.";
207 return false;
208 }
209
210 // streamming cost
211
212 float sqdiam = scale.LengthSquared();
213
214 ameshCostParam curCost = meshsCosts[mesh];
215 float mesh_streaming = streamingCost(curCost, sqdiam);
216
217 meshcostdata.model_streaming_cost += mesh_streaming;
218 meshcostdata.physics_cost += curCost.physicsCost;
219 }
220 else // instance as no mesh ??
221 {
222 // to do later if needed
223 meshcostdata.model_streaming_cost += 0.5f;
224 meshcostdata.physics_cost += 1.0f;
225 }
226
227 // assume unscripted and static prim server cost
228 meshcostdata.simulation_cost += 0.5f;
229 // charge for prims creation
230 meshsfee += primCreationCost;
231 }
232
233 if (skipedSmall > 0)
234 {
235 if (skipedSmall > numberInstances / 2)
236 {
237 error = "Model contains too many prims smaller than " + PrimScaleMin.ToString() +
238 "m minimum allowed size. Please check scalling";
239 return false;
240 }
241 else
242 warning += skipedSmall.ToString() + " of the requested " +numberInstances.ToString() +
243 " model prims will not upload because they are smaller than " + PrimScaleMin.ToString() +
244 "m minimum allowed size. Please check scalling ";
245 }
246
247 if (meshcostdata.physics_cost <= meshcostdata.model_streaming_cost)
248 meshcostdata.resource_cost = meshcostdata.model_streaming_cost;
249 else
250 meshcostdata.resource_cost = meshcostdata.physics_cost;
251
252 if (meshcostdata.resource_cost < meshcostdata.simulation_cost)
253 meshcostdata.resource_cost = meshcostdata.simulation_cost;
254
255 // scale cost
256 // at this point a cost of 1.0 whould mean basic cost
257 meshsfee *= ModelMeshCostFactor;
258
259 if (meshsfee < ModelMinCostFactor)
260 meshsfee = ModelMinCostFactor;
261
262 // actually scale it to basic cost
263 meshsfee *= (float)basicCost;
264
265 meshsfee += 0.5f; // rounding
266
267 totalcost += (int)meshsfee;
268
269 // breakdown prices
270 // don't seem to be in use so removed code for now
271
272 return true;
273 }
274
275 // single mesh asset cost
276 private bool MeshCost(byte[] data, ameshCostParam cost, out string error)
277 {
278 cost.highLODSize = 0;
279 cost.medLODSize = 0;
280 cost.lowLODSize = 0;
281 cost.lowestLODSize = 0;
282 cost.physicsCost = 0.0f;
283 cost.costFee = 0.0f;
284
285 error = string.Empty;
286
287 if (data == null || data.Length == 0)
288 {
289 error = "Missing model information.";
290 return false;
291 }
292
293 OSD meshOsd = null;
294 int start = 0;
295
296 error = "Invalid model data";
297
298 using (MemoryStream ms = new MemoryStream(data))
299 {
300 try
301 {
302 OSD osd = OSDParser.DeserializeLLSDBinary(ms);
303 if (osd is OSDMap)
304 meshOsd = (OSDMap)osd;
305 else
306 return false;
307 }
308 catch (Exception e)
309 {
310 return false;
311 }
312 start = (int)ms.Position;
313 }
314
315 OSDMap map = (OSDMap)meshOsd;
316 OSDMap tmpmap;
317
318 int highlod_size = 0;
319 int medlod_size = 0;
320 int lowlod_size = 0;
321 int lowestlod_size = 0;
322 int skin_size = 0;
323
324 int hulls_size = 0;
325 int phys_nhulls;
326 int phys_hullsvertices = 0;
327
328 int physmesh_size = 0;
329 int phys_ntriangles = 0;
330
331 int submesh_offset = -1;
332
333 if (map.ContainsKey("physics_convex"))
334 {
335 tmpmap = (OSDMap)map["physics_convex"];
336 if (tmpmap.ContainsKey("offset"))
337 submesh_offset = tmpmap["offset"].AsInteger() + start;
338 if (tmpmap.ContainsKey("size"))
339 hulls_size = tmpmap["size"].AsInteger();
340 }
341
342 if (submesh_offset < 0 || hulls_size == 0)
343 {
344 error = "Missing physics_convex block";
345 return false;
346 }
347
348 if (!hulls(data, submesh_offset, hulls_size, out phys_hullsvertices, out phys_nhulls))
349 {
350 error = "Bad physics_convex block";
351 return false;
352 }
353
354 submesh_offset = -1;
355
356 // only look for LOD meshs sizes
357
358 if (map.ContainsKey("high_lod"))
359 {
360 tmpmap = (OSDMap)map["high_lod"];
361 // see at least if there is a offset for this one
362 if (tmpmap.ContainsKey("offset"))
363 submesh_offset = tmpmap["offset"].AsInteger() + start;
364 if (tmpmap.ContainsKey("size"))
365 highlod_size = tmpmap["size"].AsInteger();
366 }
367
368 if (submesh_offset < 0 || highlod_size <= 0)
369 {
370 error = "Missing high_lod block";
371 return false;
372 }
373
374 bool haveprev = true;
375
376 if (map.ContainsKey("medium_lod"))
377 {
378 tmpmap = (OSDMap)map["medium_lod"];
379 if (tmpmap.ContainsKey("size"))
380 medlod_size = tmpmap["size"].AsInteger();
381 else
382 haveprev = false;
383 }
384
385 if (haveprev && map.ContainsKey("low_lod"))
386 {
387 tmpmap = (OSDMap)map["low_lod"];
388 if (tmpmap.ContainsKey("size"))
389 lowlod_size = tmpmap["size"].AsInteger();
390 else
391 haveprev = false;
392 }
393
394 if (haveprev && map.ContainsKey("lowest_lod"))
395 {
396 tmpmap = (OSDMap)map["lowest_lod"];
397 if (tmpmap.ContainsKey("size"))
398 lowestlod_size = tmpmap["size"].AsInteger();
399 }
400
401 if (map.ContainsKey("skin"))
402 {
403 tmpmap = (OSDMap)map["skin"];
404 if (tmpmap.ContainsKey("size"))
405 skin_size = tmpmap["size"].AsInteger();
406 }
407
408 cost.highLODSize = highlod_size;
409 cost.medLODSize = medlod_size;
410 cost.lowLODSize = lowlod_size;
411 cost.lowestLODSize = lowestlod_size;
412
413 submesh_offset = -1;
414
415 tmpmap = null;
416 if(map.ContainsKey("physics_mesh"))
417 tmpmap = (OSDMap)map["physics_mesh"];
418 else if (map.ContainsKey("physics_shape")) // old naming
419 tmpmap = (OSDMap)map["physics_shape"];
420
421 if(tmpmap != null)
422 {
423 if (tmpmap.ContainsKey("offset"))
424 submesh_offset = tmpmap["offset"].AsInteger() + start;
425 if (tmpmap.ContainsKey("size"))
426 physmesh_size = tmpmap["size"].AsInteger();
427
428 if (submesh_offset >= 0 || physmesh_size > 0)
429 {
430
431 if (!submesh(data, submesh_offset, physmesh_size, out phys_ntriangles))
432 {
433 error = "Model data parsing error";
434 return false;
435 }
436 }
437 }
438
439 // upload is done in convex shape type so only one hull
440 phys_hullsvertices++;
441 cost.physicsCost = 0.04f * phys_hullsvertices;
442
443 float sfee;
444
445 sfee = data.Length; // start with total compressed data size
446
447 // penalize lod meshs that should be more builder optimized
448 sfee += medSizeWth * medlod_size;
449 sfee += lowSizeWth * lowlod_size;
450 sfee += lowestSizeWth * lowlod_size;
451
452 // physics
453 // favor potencial optimized meshs versus automatic decomposition
454 if (physmesh_size != 0)
455 sfee += physMeshSizeWth * (physmesh_size + hulls_size / 4); // reduce cost of mandatory convex hull
456 else
457 sfee += physHullSizeWth * hulls_size;
458
459 // bytes to money
460 sfee *= bytecost;
461
462 cost.costFee = sfee;
463 return true;
464 }
465
466 // parses a LOD or physics mesh component
467 private bool submesh(byte[] data, int offset, int size, out int ntriangles)
468 {
469 ntriangles = 0;
470
471 OSD decodedMeshOsd = new OSD();
472 byte[] meshBytes = new byte[size];
473 System.Buffer.BlockCopy(data, offset, meshBytes, 0, size);
474 try
475 {
476 using (MemoryStream inMs = new MemoryStream(meshBytes))
477 {
478 using (MemoryStream outMs = new MemoryStream())
479 {
480 using (ZOutputStream zOut = new ZOutputStream(outMs))
481 {
482 byte[] readBuffer = new byte[4096];
483 int readLen = 0;
484 while ((readLen = inMs.Read(readBuffer, 0, readBuffer.Length)) > 0)
485 {
486 zOut.Write(readBuffer, 0, readLen);
487 }
488 zOut.Flush();
489 outMs.Seek(0, SeekOrigin.Begin);
490
491 byte[] decompressedBuf = outMs.GetBuffer();
492 decodedMeshOsd = OSDParser.DeserializeLLSDBinary(decompressedBuf);
493 }
494 }
495 }
496 }
497 catch (Exception e)
498 {
499 return false;
500 }
501
502 OSDArray decodedMeshOsdArray = null;
503 if ((!decodedMeshOsd is OSDArray))
504 return false;
505
506 byte[] dummy;
507
508 decodedMeshOsdArray = (OSDArray)decodedMeshOsd;
509 foreach (OSD subMeshOsd in decodedMeshOsdArray)
510 {
511 if (subMeshOsd is OSDMap)
512 {
513 OSDMap subtmpmap = (OSDMap)subMeshOsd;
514 if (subtmpmap.ContainsKey("NoGeometry") && ((OSDBoolean)subtmpmap["NoGeometry"]))
515 continue;
516
517 if (!subtmpmap.ContainsKey("Position"))
518 return false;
519
520 if (subtmpmap.ContainsKey("TriangleList"))
521 {
522 dummy = subtmpmap["TriangleList"].AsBinary();
523 ntriangles += dummy.Length / bytesPerCoord;
524 }
525 else
526 return false;
527 }
528 }
529
530 return true;
531 }
532
533 // parses convex hulls component
534 private bool hulls(byte[] data, int offset, int size, out int nvertices, out int nhulls)
535 {
536 nvertices = 0;
537 nhulls = 1;
538
539 OSD decodedMeshOsd = new OSD();
540 byte[] meshBytes = new byte[size];
541 System.Buffer.BlockCopy(data, offset, meshBytes, 0, size);
542 try
543 {
544 using (MemoryStream inMs = new MemoryStream(meshBytes))
545 {
546 using (MemoryStream outMs = new MemoryStream())
547 {
548 using (ZOutputStream zOut = new ZOutputStream(outMs))
549 {
550 byte[] readBuffer = new byte[4096];
551 int readLen = 0;
552 while ((readLen = inMs.Read(readBuffer, 0, readBuffer.Length)) > 0)
553 {
554 zOut.Write(readBuffer, 0, readLen);
555 }
556 zOut.Flush();
557 outMs.Seek(0, SeekOrigin.Begin);
558
559 byte[] decompressedBuf = outMs.GetBuffer();
560 decodedMeshOsd = OSDParser.DeserializeLLSDBinary(decompressedBuf);
561 }
562 }
563 }
564 }
565 catch (Exception e)
566 {
567 return false;
568 }
569
570 OSDMap cmap = (OSDMap)decodedMeshOsd;
571 if (cmap == null)
572 return false;
573
574 byte[] dummy;
575
576 // must have one of this
577 if (cmap.ContainsKey("BoundingVerts"))
578 {
579 dummy = cmap["BoundingVerts"].AsBinary();
580 nvertices = dummy.Length / bytesPerCoord;
581 }
582 else
583 return false;
584
585/* upload is done with convex shape type
586 if (cmap.ContainsKey("HullList"))
587 {
588 dummy = cmap["HullList"].AsBinary();
589 nhulls += dummy.Length;
590 }
591
592
593 if (cmap.ContainsKey("Positions"))
594 {
595 dummy = cmap["Positions"].AsBinary();
596 nvertices = dummy.Length / bytesPerCoord;
597 }
598 */
599
600 return true;
601 }
602
603 // returns streaming cost from on mesh LODs sizes in curCost and square of prim size length
604 private float streamingCost(ameshCostParam curCost, float sqdiam)
605 {
606 // compute efective areas
607 float ma = 262144f;
608
609 float mh = sqdiam * highLodFactor;
610 if (mh > ma)
611 mh = ma;
612 float mm = sqdiam * midLodFactor;
613 if (mm > ma)
614 mm = ma;
615
616 float ml = sqdiam * lowLodFactor;
617 if (ml > ma)
618 ml = ma;
619
620 float mlst = ma;
621
622 mlst -= ml;
623 ml -= mm;
624 mm -= mh;
625
626 if (mlst < 1.0f)
627 mlst = 1.0f;
628 if (ml < 1.0f)
629 ml = 1.0f;
630 if (mm < 1.0f)
631 mm = 1.0f;
632 if (mh < 1.0f)
633 mh = 1.0f;
634
635 ma = mlst + ml + mm + mh;
636
637 // get LODs compressed sizes
638 // giving 384 bytes bonus
639 int lst = curCost.lowestLODSize - 384;
640 int l = curCost.lowLODSize - 384;
641 int m = curCost.medLODSize - 384;
642 int h = curCost.highLODSize - 384;
643
644 // use previus higher LOD size on missing ones
645 if (m <= 0)
646 m = h;
647 if (l <= 0)
648 l = m;
649 if (lst <= 0)
650 lst = l;
651
652 // force minumum sizes
653 if (lst < 16)
654 lst = 16;
655 if (l < 16)
656 l = 16;
657 if (m < 16)
658 m = 16;
659 if (h < 16)
660 h = 16;
661
662 // compute cost weighted by relative effective areas
663 float cost = (float)lst * mlst + (float)l * ml + (float)m * mm + (float)h * mh;
664 cost /= ma;
665
666 cost *= 0.004f; // overall tunning parameter
667
668 return cost;
669 }
670 }
671}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
index 4d2c0f2..986a665 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
@@ -353,7 +353,7 @@ namespace OpenSim.Region.ClientStack.Linden
353 // TODO: Add EventQueueGet name/description for diagnostics 353 // TODO: Add EventQueueGet name/description for diagnostics
354 MainServer.Instance.AddPollServiceHTTPHandler( 354 MainServer.Instance.AddPollServiceHTTPHandler(
355 eventQueueGetPath, 355 eventQueueGetPath,
356 new PollServiceEventArgs(null, HasEvents, GetEvents, NoEvents, agentID)); 356 new PollServiceEventArgs(null, HasEvents, GetEvents, NoEvents, agentID, 1000));
357 357
358// m_log.DebugFormat( 358// m_log.DebugFormat(
359// "[EVENT QUEUE GET MODULE]: Registered EQG handler {0} for {1} in {2}", 359// "[EVENT QUEUE GET MODULE]: Registered EQG handler {0} for {1} in {2}",
@@ -395,7 +395,7 @@ namespace OpenSim.Region.ClientStack.Linden
395 } 395 }
396 } 396 }
397 397
398 public Hashtable GetEvents(UUID requestID, UUID pAgentId, string request) 398 public Hashtable GetEvents(UUID requestID, UUID pAgentId)
399 { 399 {
400 if (DebugLevel >= 2) 400 if (DebugLevel >= 2)
401 m_log.DebugFormat("POLLED FOR EQ MESSAGES BY {0} in {1}", pAgentId, m_scene.RegionInfo.RegionName); 401 m_log.DebugFormat("POLLED FOR EQ MESSAGES BY {0} in {1}", pAgentId, m_scene.RegionInfo.RegionName);
@@ -807,5 +807,13 @@ namespace OpenSim.Region.ClientStack.Linden
807 { 807 {
808 return EventQueueHelper.BuildEvent(eventName, eventBody); 808 return EventQueueHelper.BuildEvent(eventName, eventBody);
809 } 809 }
810
811 public void partPhysicsProperties(uint localID, byte physhapetype,
812 float density, float friction, float bounce, float gravmod,UUID avatarID)
813 {
814 OSD item = EventQueueHelper.partPhysicsProperties(localID, physhapetype,
815 density, friction, bounce, gravmod);
816 Enqueue(item, avatarID);
817 }
810 } 818 }
811} 819}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs
index 3f49aba..7dcf137 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs
@@ -151,6 +151,12 @@ namespace OpenSim.Region.ClientStack.Linden
151 ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint, 151 ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint,
152 uint locationID, uint flags, string capsURL, UUID agentID) 152 uint locationID, uint flags, string capsURL, UUID agentID)
153 { 153 {
154 // not sure why flags get overwritten here
155 if ((flags & (uint)TeleportFlags.IsFlying) != 0)
156 flags = (uint)TeleportFlags.ViaLocation | (uint)TeleportFlags.IsFlying;
157 else
158 flags = (uint)TeleportFlags.ViaLocation;
159
154 OSDMap info = new OSDMap(); 160 OSDMap info = new OSDMap();
155 info.Add("AgentID", OSD.FromUUID(agentID)); 161 info.Add("AgentID", OSD.FromUUID(agentID));
156 info.Add("LocationID", OSD.FromInteger(4)); // TODO what is this? 162 info.Add("LocationID", OSD.FromInteger(4)); // TODO what is this?
@@ -159,7 +165,8 @@ namespace OpenSim.Region.ClientStack.Linden
159 info.Add("SimAccess", OSD.FromInteger(simAccess)); 165 info.Add("SimAccess", OSD.FromInteger(simAccess));
160 info.Add("SimIP", OSD.FromBinary(regionExternalEndPoint.Address.GetAddressBytes())); 166 info.Add("SimIP", OSD.FromBinary(regionExternalEndPoint.Address.GetAddressBytes()));
161 info.Add("SimPort", OSD.FromInteger(regionExternalEndPoint.Port)); 167 info.Add("SimPort", OSD.FromInteger(regionExternalEndPoint.Port));
162 info.Add("TeleportFlags", OSD.FromULong(1L << 4)); // AgentManager.TeleportFlags.ViaLocation 168// info.Add("TeleportFlags", OSD.FromULong(1L << 4)); // AgentManager.TeleportFlags.ViaLocation
169 info.Add("TeleportFlags", OSD.FromUInteger(flags));
163 170
164 OSDArray infoArr = new OSDArray(); 171 OSDArray infoArr = new OSDArray();
165 infoArr.Add(info); 172 infoArr.Add(info);
@@ -395,5 +402,25 @@ namespace OpenSim.Region.ClientStack.Linden
395 return message; 402 return message;
396 } 403 }
397 404
405 public static OSD partPhysicsProperties(uint localID, byte physhapetype,
406 float density, float friction, float bounce, float gravmod)
407 {
408
409 OSDMap physinfo = new OSDMap(6);
410 physinfo["LocalID"] = localID;
411 physinfo["Density"] = density;
412 physinfo["Friction"] = friction;
413 physinfo["GravityMultiplier"] = gravmod;
414 physinfo["Restitution"] = bounce;
415 physinfo["PhysicsShapeType"] = (int)physhapetype;
416
417 OSDArray array = new OSDArray(1);
418 array.Add(physinfo);
419
420 OSDMap llsdBody = new OSDMap(1);
421 llsdBody.Add("ObjectData", array);
422
423 return BuildEvent("ObjectPhysicsProperties", llsdBody);
424 }
398 } 425 }
399} 426}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs
index 8e1f63a..908f628 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs
@@ -27,11 +27,14 @@
27 27
28using System; 28using System;
29using System.Collections; 29using System.Collections;
30using System.Collections.Generic;
30using System.Collections.Specialized; 31using System.Collections.Specialized;
31using System.Reflection; 32using System.Reflection;
32using System.IO; 33using System.IO;
34using System.Threading;
33using System.Web; 35using System.Web;
34using Mono.Addins; 36using Mono.Addins;
37using OpenSim.Framework.Monitoring;
35using log4net; 38using log4net;
36using Nini.Config; 39using Nini.Config;
37using OpenMetaverse; 40using OpenMetaverse;
@@ -57,9 +60,45 @@ namespace OpenSim.Region.ClientStack.Linden
57 private IAssetService m_AssetService; 60 private IAssetService m_AssetService;
58 private bool m_Enabled = true; 61 private bool m_Enabled = true;
59 private string m_URL; 62 private string m_URL;
63
64 struct aPollRequest
65 {
66 public PollServiceMeshEventArgs thepoll;
67 public UUID reqID;
68 public Hashtable request;
69 }
70
71 public class aPollResponse
72 {
73 public Hashtable response;
74 public int bytes;
75 public int lod;
76 }
77
78
79 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
80
81 private static GetMeshHandler m_getMeshHandler;
82
83 private IAssetService m_assetService = null;
84
85 private Dictionary<UUID, string> m_capsDict = new Dictionary<UUID, string>();
86 private static Thread[] m_workerThreads = null;
87
88 private static OpenMetaverse.BlockingQueue<aPollRequest> m_queue =
89 new OpenMetaverse.BlockingQueue<aPollRequest>();
90
91 private Dictionary<UUID, PollServiceMeshEventArgs> m_pollservices = new Dictionary<UUID, PollServiceMeshEventArgs>();
60 92
61 #region Region Module interfaceBase Members 93 #region Region Module interfaceBase Members
62 94
95 ~GetMeshModule()
96 {
97 foreach (Thread t in m_workerThreads)
98 Watchdog.AbortThread(t.ManagedThreadId);
99
100 }
101
63 public Type ReplaceableInterface 102 public Type ReplaceableInterface
64 { 103 {
65 get { return null; } 104 get { return null; }
@@ -75,6 +114,7 @@ namespace OpenSim.Region.ClientStack.Linden
75 // Cap doesn't exist 114 // Cap doesn't exist
76 if (m_URL != string.Empty) 115 if (m_URL != string.Empty)
77 m_Enabled = true; 116 m_Enabled = true;
117
78 } 118 }
79 119
80 public void AddRegion(Scene pScene) 120 public void AddRegion(Scene pScene)
@@ -83,6 +123,8 @@ namespace OpenSim.Region.ClientStack.Linden
83 return; 123 return;
84 124
85 m_scene = pScene; 125 m_scene = pScene;
126
127 m_assetService = pScene.AssetService;
86 } 128 }
87 129
88 public void RemoveRegion(Scene scene) 130 public void RemoveRegion(Scene scene)
@@ -91,6 +133,9 @@ namespace OpenSim.Region.ClientStack.Linden
91 return; 133 return;
92 134
93 m_scene.EventManager.OnRegisterCaps -= RegisterCaps; 135 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
136 m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps;
137 m_scene.EventManager.OnThrottleUpdate -= ThrottleUpdate;
138
94 m_scene = null; 139 m_scene = null;
95 } 140 }
96 141
@@ -101,6 +146,27 @@ namespace OpenSim.Region.ClientStack.Linden
101 146
102 m_AssetService = m_scene.RequestModuleInterface<IAssetService>(); 147 m_AssetService = m_scene.RequestModuleInterface<IAssetService>();
103 m_scene.EventManager.OnRegisterCaps += RegisterCaps; 148 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
149 // We'll reuse the same handler for all requests.
150 m_getMeshHandler = new GetMeshHandler(m_assetService);
151 m_scene.EventManager.OnDeregisterCaps += DeregisterCaps;
152 m_scene.EventManager.OnThrottleUpdate += ThrottleUpdate;
153
154 if (m_workerThreads == null)
155 {
156 m_workerThreads = new Thread[2];
157
158 for (uint i = 0; i < 2; i++)
159 {
160 m_workerThreads[i] = Watchdog.StartThread(DoMeshRequests,
161 String.Format("MeshWorkerThread{0}", i),
162 ThreadPriority.Normal,
163 false,
164 false,
165 null,
166 int.MaxValue);
167 }
168 }
169
104 } 170 }
105 171
106 172
@@ -110,25 +176,212 @@ namespace OpenSim.Region.ClientStack.Linden
110 176
111 #endregion 177 #endregion
112 178
179 private void DoMeshRequests()
180 {
181 while (true)
182 {
183 aPollRequest poolreq = m_queue.Dequeue();
184
185 poolreq.thepoll.Process(poolreq);
186 }
187 }
188
189 // Now we know when the throttle is changed by the client in the case of a root agent or by a neighbor region in the case of a child agent.
190 public void ThrottleUpdate(ScenePresence p)
191 {
192 byte[] throttles = p.ControllingClient.GetThrottlesPacked(1);
193 UUID user = p.UUID;
194 int imagethrottle = ExtractTaskThrottle(throttles);
195 PollServiceMeshEventArgs args;
196 if (m_pollservices.TryGetValue(user, out args))
197 {
198 args.UpdateThrottle(imagethrottle, p);
199 }
200 }
201
202 private int ExtractTaskThrottle(byte[] pthrottles)
203 {
204
205 byte[] adjData;
206 int pos = 0;
207
208 if (!BitConverter.IsLittleEndian)
209 {
210 byte[] newData = new byte[7 * 4];
211 Buffer.BlockCopy(pthrottles, 0, newData, 0, 7 * 4);
212
213 for (int i = 0; i < 7; i++)
214 Array.Reverse(newData, i * 4, 4);
215
216 adjData = newData;
217 }
218 else
219 {
220 adjData = pthrottles;
221 }
222
223 // 0.125f converts from bits to bytes
224 //int resend = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
225 //pos += 4;
226 // int land = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
227 //pos += 4;
228 // int wind = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
229 // pos += 4;
230 // int cloud = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
231 // pos += 4;
232 pos += 16;
233 int task = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
234 // pos += 4;
235 //int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); //pos += 4;
236 //int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
237 return task;
238 }
239
240 private class PollServiceMeshEventArgs : PollServiceEventArgs
241 {
242 private List<Hashtable> requests =
243 new List<Hashtable>();
244 private Dictionary<UUID, aPollResponse> responses =
245 new Dictionary<UUID, aPollResponse>();
246
247 private Scene m_scene;
248 private MeshCapsDataThrottler m_throttler;
249 public PollServiceMeshEventArgs(UUID pId, Scene scene) :
250 base(null, null, null, null, pId, int.MaxValue)
251 {
252 m_scene = scene;
253 m_throttler = new MeshCapsDataThrottler(100000, 1400000, 10000, scene, pId);
254 // x is request id, y is userid
255 HasEvents = (x, y) =>
256 {
257 lock (responses)
258 {
259 bool ret = m_throttler.hasEvents(x, responses);
260 m_throttler.ProcessTime();
261 return ret;
262
263 }
264 };
265 GetEvents = (x, y) =>
266 {
267 lock (responses)
268 {
269 try
270 {
271 return responses[x].response;
272 }
273 finally
274 {
275 m_throttler.ProcessTime();
276 responses.Remove(x);
277 }
278 }
279 };
280 // x is request id, y is request data hashtable
281 Request = (x, y) =>
282 {
283 aPollRequest reqinfo = new aPollRequest();
284 reqinfo.thepoll = this;
285 reqinfo.reqID = x;
286 reqinfo.request = y;
287
288 m_queue.Enqueue(reqinfo);
289 };
290
291 // this should never happen except possible on shutdown
292 NoEvents = (x, y) =>
293 {
294 /*
295 lock (requests)
296 {
297 Hashtable request = requests.Find(id => id["RequestID"].ToString() == x.ToString());
298 requests.Remove(request);
299 }
300 */
301 Hashtable response = new Hashtable();
302
303 response["int_response_code"] = 500;
304 response["str_response_string"] = "Script timeout";
305 response["content_type"] = "text/plain";
306 response["keepalive"] = false;
307 response["reusecontext"] = false;
308
309 return response;
310 };
311 }
312
313 public void Process(aPollRequest requestinfo)
314 {
315 Hashtable response;
316
317 UUID requestID = requestinfo.reqID;
318
319 // If the avatar is gone, don't bother to get the texture
320 if (m_scene.GetScenePresence(Id) == null)
321 {
322 response = new Hashtable();
323
324 response["int_response_code"] = 500;
325 response["str_response_string"] = "Script timeout";
326 response["content_type"] = "text/plain";
327 response["keepalive"] = false;
328 response["reusecontext"] = false;
329
330 lock (responses)
331 responses[requestID] = new aPollResponse() { bytes = 0, response = response, lod = 0 };
332
333 return;
334 }
335
336 response = m_getMeshHandler.Handle(requestinfo.request);
337 lock (responses)
338 {
339 responses[requestID] = new aPollResponse()
340 {
341 bytes = (int)response["int_bytes"],
342 lod = (int)response["int_lod"],
343 response = response
344 };
345
346 }
347 m_throttler.ProcessTime();
348 }
349
350 internal void UpdateThrottle(int pimagethrottle, ScenePresence p)
351 {
352 m_throttler.UpdateThrottle(pimagethrottle, p);
353 }
354 }
113 355
114 public void RegisterCaps(UUID agentID, Caps caps) 356 public void RegisterCaps(UUID agentID, Caps caps)
115 { 357 {
116// UUID capID = UUID.Random(); 358// UUID capID = UUID.Random();
117
118 //caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture));
119 if (m_URL == "localhost") 359 if (m_URL == "localhost")
120 { 360 {
121// m_log.DebugFormat("[GETMESH]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName); 361 string capUrl = "/CAPS/" + UUID.Random() + "/";
122 GetMeshHandler gmeshHandler = new GetMeshHandler(m_AssetService); 362
123 IRequestHandler reqHandler 363 // Register this as a poll service
124 = new RestHTTPHandler( 364 PollServiceMeshEventArgs args = new PollServiceMeshEventArgs(agentID, m_scene);
125 "GET", 365
126 "/CAPS/" + UUID.Random(), 366 args.Type = PollServiceEventArgs.EventType.Mesh;
127 httpMethod => gmeshHandler.ProcessGetMesh(httpMethod, UUID.Zero, null), 367 MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args);
128 "GetMesh",
129 agentID.ToString());
130 368
131 caps.RegisterHandler("GetMesh", reqHandler); 369 string hostName = m_scene.RegionInfo.ExternalHostName;
370 uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port;
371 string protocol = "http";
372
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,171 @@ 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 }
506 }
507 }
508
509 public void ProcessTime()
510 {
511 PassTime();
512 }
513
514
515 private void PassTime()
516 {
517 currenttime = Util.EnvironmentTickCount();
518 int timeElapsed = Util.EnvironmentTickCountSubtract(currenttime, lastTimeElapsed);
519 //processTimeBasedActions(responses);
520 if (currenttime - timeElapsed >= 1000)
521 {
522 lastTimeElapsed = Util.EnvironmentTickCount();
523 BytesSent -= ThrottleBytes;
524 if (BytesSent < 0) BytesSent = 0;
525 if (BytesSent < ThrottleBytes)
526 {
527 Lod3 = 0;
528 Lod2 = 0;
529 Lod1 = 0;
530 }
531 }
532 }
533 private void AlterThrottle(int setting, ScenePresence p)
534 {
535 p.ControllingClient.SetAgentThrottleSilent((int)Throttle,setting);
536 }
537
538 public int ThrottleBytes
539 {
540 get { return CapSetThrottle; }
541 set { CapSetThrottle = value; }
542 }
543
544 internal void UpdateThrottle(int pimagethrottle, ScenePresence p)
545 {
546 // Client set throttle !
547 UserSetThrottle = pimagethrottle;
548 CapSetThrottle = (int)(pimagethrottle*CapThrottleDistributon);
549 UDPSetThrottle = (int) (pimagethrottle*(100 - CapThrottleDistributon));
550 if (CapSetThrottle < 4068)
551 CapSetThrottle = 4068; // at least two discovery mesh
552 p.ControllingClient.SetAgentThrottleSilent((int) Throttle, UDPSetThrottle);
553 ProcessTime();
554
555 }
556 }
139 557
140 } 558 }
141} 559}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs
index 13415f8..d4dbfb9 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs
@@ -27,18 +27,13 @@
27 27
28using System; 28using System;
29using System.Collections; 29using System.Collections;
30using System.Collections.Specialized; 30using System.Collections.Generic;
31using System.Drawing;
32using System.Drawing.Imaging;
33using System.Reflection; 31using System.Reflection;
34using System.IO; 32using System.Threading;
35using System.Web;
36using log4net; 33using log4net;
37using Nini.Config; 34using Nini.Config;
38using Mono.Addins; 35using Mono.Addins;
39using OpenMetaverse; 36using OpenMetaverse;
40using OpenMetaverse.StructuredData;
41using OpenMetaverse.Imaging;
42using OpenSim.Framework; 37using OpenSim.Framework;
43using OpenSim.Framework.Servers; 38using OpenSim.Framework.Servers;
44using OpenSim.Framework.Servers.HttpServer; 39using OpenSim.Framework.Servers.HttpServer;
@@ -47,6 +42,7 @@ using OpenSim.Region.Framework.Scenes;
47using OpenSim.Services.Interfaces; 42using OpenSim.Services.Interfaces;
48using Caps = OpenSim.Framework.Capabilities.Caps; 43using Caps = OpenSim.Framework.Capabilities.Caps;
49using OpenSim.Capabilities.Handlers; 44using OpenSim.Capabilities.Handlers;
45using OpenSim.Framework.Monitoring;
50 46
51namespace OpenSim.Region.ClientStack.Linden 47namespace OpenSim.Region.ClientStack.Linden
52{ 48{
@@ -54,57 +50,131 @@ namespace OpenSim.Region.ClientStack.Linden
54 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GetTextureModule")] 50 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GetTextureModule")]
55 public class GetTextureModule : INonSharedRegionModule 51 public class GetTextureModule : INonSharedRegionModule
56 { 52 {
57// private static readonly ILog m_log = 53
58// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 54 struct aPollRequest
59 55 {
56 public PollServiceTextureEventArgs thepoll;
57 public UUID reqID;
58 public Hashtable request;
59 }
60
61 public class aPollResponse
62 {
63 public Hashtable response;
64 public int bytes;
65 }
66
67
68 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
69
60 private Scene m_scene; 70 private Scene m_scene;
61 private IAssetService m_assetService;
62 71
63 private bool m_Enabled = false; 72 private static GetTextureHandler m_getTextureHandler;
73
74 private IAssetService m_assetService = null;
75
76 private Dictionary<UUID, string> m_capsDict = new Dictionary<UUID, string>();
77 private static Thread[] m_workerThreads = null;
64 78
65 // TODO: Change this to a config option 79 private static OpenMetaverse.BlockingQueue<aPollRequest> m_queue =
66 const string REDIRECT_URL = null; 80 new OpenMetaverse.BlockingQueue<aPollRequest>();
67 81
68 private string m_URL; 82 private Dictionary<UUID,PollServiceTextureEventArgs> m_pollservices = new Dictionary<UUID,PollServiceTextureEventArgs>();
69 83
70 #region ISharedRegionModule Members 84 #region ISharedRegionModule Members
71 85
72 public void Initialise(IConfigSource source) 86 public void Initialise(IConfigSource source)
73 { 87 {
74 IConfig config = source.Configs["ClientStack.LindenCaps"];
75 if (config == null)
76 return;
77
78 m_URL = config.GetString("Cap_GetTexture", string.Empty);
79 // Cap doesn't exist
80 if (m_URL != string.Empty)
81 m_Enabled = true;
82 } 88 }
83 89
84 public void AddRegion(Scene s) 90 public void AddRegion(Scene s)
85 { 91 {
86 if (!m_Enabled)
87 return;
88
89 m_scene = s; 92 m_scene = s;
93 m_assetService = s.AssetService;
90 } 94 }
91 95
92 public void RemoveRegion(Scene s) 96 public void RemoveRegion(Scene s)
93 { 97 {
94 if (!m_Enabled)
95 return;
96
97 m_scene.EventManager.OnRegisterCaps -= RegisterCaps; 98 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
99 m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps;
100 m_scene.EventManager.OnThrottleUpdate -= ThrottleUpdate;
98 m_scene = null; 101 m_scene = null;
99 } 102 }
100 103
101 public void RegionLoaded(Scene s) 104 public void RegionLoaded(Scene s)
102 { 105 {
103 if (!m_Enabled) 106 // We'll reuse the same handler for all requests.
104 return; 107 m_getTextureHandler = new GetTextureHandler(m_assetService);
105 108
106 m_assetService = m_scene.RequestModuleInterface<IAssetService>();
107 m_scene.EventManager.OnRegisterCaps += RegisterCaps; 109 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
110 m_scene.EventManager.OnDeregisterCaps += DeregisterCaps;
111 m_scene.EventManager.OnThrottleUpdate += ThrottleUpdate;
112
113 if (m_workerThreads == null)
114 {
115 m_workerThreads = new Thread[2];
116
117 for (uint i = 0; i < 2; i++)
118 {
119 m_workerThreads[i] = Watchdog.StartThread(DoTextureRequests,
120 String.Format("TextureWorkerThread{0}", i),
121 ThreadPriority.Normal,
122 false,
123 false,
124 null,
125 int.MaxValue);
126 }
127 }
128 }
129 private int ExtractImageThrottle(byte[] pthrottles)
130 {
131
132 byte[] adjData;
133 int pos = 0;
134
135 if (!BitConverter.IsLittleEndian)
136 {
137 byte[] newData = new byte[7 * 4];
138 Buffer.BlockCopy(pthrottles, 0, newData, 0, 7 * 4);
139
140 for (int i = 0; i < 7; i++)
141 Array.Reverse(newData, i * 4, 4);
142
143 adjData = newData;
144 }
145 else
146 {
147 adjData = pthrottles;
148 }
149
150 // 0.125f converts from bits to bytes
151 //int resend = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
152 //pos += 4;
153 // int land = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
154 //pos += 4;
155 // int wind = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
156 // pos += 4;
157 // int cloud = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
158 // pos += 4;
159 // int task = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
160 // pos += 4;
161 pos = pos + 20;
162 int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); //pos += 4;
163 //int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
164 return texture;
165 }
166
167 // Now we know when the throttle is changed by the client in the case of a root agent or by a neighbor region in the case of a child agent.
168 public void ThrottleUpdate(ScenePresence p)
169 {
170 byte[] throttles = p.ControllingClient.GetThrottlesPacked(1);
171 UUID user = p.UUID;
172 int imagethrottle = ExtractImageThrottle(throttles);
173 PollServiceTextureEventArgs args;
174 if (m_pollservices.TryGetValue(user,out args))
175 {
176 args.UpdateThrottle(imagethrottle);
177 }
108 } 178 }
109 179
110 public void PostInitialise() 180 public void PostInitialise()
@@ -122,24 +192,250 @@ namespace OpenSim.Region.ClientStack.Linden
122 192
123 #endregion 193 #endregion
124 194
125 public void RegisterCaps(UUID agentID, Caps caps) 195 ~GetTextureModule()
196 {
197 foreach (Thread t in m_workerThreads)
198 Watchdog.AbortThread(t.ManagedThreadId);
199
200 }
201
202 private class PollServiceTextureEventArgs : PollServiceEventArgs
126 { 203 {
127 UUID capID = UUID.Random(); 204 private List<Hashtable> requests =
205 new List<Hashtable>();
206 private Dictionary<UUID, aPollResponse> responses =
207 new Dictionary<UUID, aPollResponse>();
128 208
129 //caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture)); 209 private Scene m_scene;
130 if (m_URL == "localhost") 210 private CapsDataThrottler m_throttler = new CapsDataThrottler(100000, 1400000,10000);
211 public PollServiceTextureEventArgs(UUID pId, Scene scene) :
212 base(null, null, null, null, pId, int.MaxValue)
131 { 213 {
132// m_log.DebugFormat("[GETTEXTURE]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName); 214 m_scene = scene;
133 caps.RegisterHandler( 215 // x is request id, y is userid
134 "GetTexture", 216 HasEvents = (x, y) =>
135 new GetTextureHandler("/CAPS/" + capID + "/", m_assetService, "GetTexture", agentID.ToString())); 217 {
218 lock (responses)
219 {
220 bool ret = m_throttler.hasEvents(x, responses);
221 m_throttler.ProcessTime();
222 return ret;
223
224 }
225 };
226 GetEvents = (x, y) =>
227 {
228 lock (responses)
229 {
230 try
231 {
232 return responses[x].response;
233 }
234 finally
235 {
236 responses.Remove(x);
237 }
238 }
239 };
240 // x is request id, y is request data hashtable
241 Request = (x, y) =>
242 {
243 aPollRequest reqinfo = new aPollRequest();
244 reqinfo.thepoll = this;
245 reqinfo.reqID = x;
246 reqinfo.request = y;
247
248 m_queue.Enqueue(reqinfo);
249 };
250
251 // this should never happen except possible on shutdown
252 NoEvents = (x, y) =>
253 {
254/*
255 lock (requests)
256 {
257 Hashtable request = requests.Find(id => id["RequestID"].ToString() == x.ToString());
258 requests.Remove(request);
259 }
260*/
261 Hashtable response = new Hashtable();
262
263 response["int_response_code"] = 500;
264 response["str_response_string"] = "Script timeout";
265 response["content_type"] = "text/plain";
266 response["keepalive"] = false;
267 response["reusecontext"] = false;
268
269 return response;
270 };
136 } 271 }
137 else 272
273 public void Process(aPollRequest requestinfo)
274 {
275 Hashtable response;
276
277 UUID requestID = requestinfo.reqID;
278
279 // If the avatar is gone, don't bother to get the texture
280 if (m_scene.GetScenePresence(Id) == null)
281 {
282 response = new Hashtable();
283
284 response["int_response_code"] = 500;
285 response["str_response_string"] = "Script timeout";
286 response["content_type"] = "text/plain";
287 response["keepalive"] = false;
288 response["reusecontext"] = false;
289
290 lock (responses)
291 responses[requestID] = new aPollResponse() {bytes = 0, response = response};
292
293 return;
294 }
295
296 response = m_getTextureHandler.Handle(requestinfo.request);
297 lock (responses)
298 {
299 responses[requestID] = new aPollResponse()
300 {
301 bytes = (int) response["int_bytes"],
302 response = response
303 };
304
305 }
306 m_throttler.ProcessTime();
307 }
308
309 internal void UpdateThrottle(int pimagethrottle)
310 {
311 m_throttler.ThrottleBytes = pimagethrottle;
312 }
313 }
314
315 private void RegisterCaps(UUID agentID, Caps caps)
316 {
317 string capUrl = "/CAPS/" + UUID.Random() + "/";
318
319 // Register this as a poll service
320 PollServiceTextureEventArgs args = new PollServiceTextureEventArgs(agentID, m_scene);
321
322 args.Type = PollServiceEventArgs.EventType.Texture;
323 MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args);
324
325 string hostName = m_scene.RegionInfo.ExternalHostName;
326 uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port;
327 string protocol = "http";
328
329 if (MainServer.Instance.UseSSL)
330 {
331 hostName = MainServer.Instance.SSLCommonName;
332 port = MainServer.Instance.SSLPort;
333 protocol = "https";
334 }
335 caps.RegisterHandler("GetTexture", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl));
336 m_pollservices[agentID] = args;
337 m_capsDict[agentID] = capUrl;
338 }
339
340 private void DeregisterCaps(UUID agentID, Caps caps)
341 {
342 string capUrl;
343 PollServiceTextureEventArgs args;
344 if (m_capsDict.TryGetValue(agentID, out capUrl))
345 {
346 MainServer.Instance.RemoveHTTPHandler("", capUrl);
347 m_capsDict.Remove(agentID);
348 }
349 if (m_pollservices.TryGetValue(agentID, out args))
138 { 350 {
139// m_log.DebugFormat("[GETTEXTURE]: {0} in region {1}", m_URL, m_scene.RegionInfo.RegionName); 351 m_pollservices.Remove(agentID);
140 caps.RegisterHandler("GetTexture", m_URL);
141 } 352 }
142 } 353 }
143 354
355 private void DoTextureRequests()
356 {
357 while (true)
358 {
359 aPollRequest poolreq = m_queue.Dequeue();
360
361 poolreq.thepoll.Process(poolreq);
362 }
363 }
364 internal sealed class CapsDataThrottler
365 {
366
367 private volatile int currenttime = 0;
368 private volatile int lastTimeElapsed = 0;
369 private volatile int BytesSent = 0;
370 private int oversizedImages = 0;
371 public CapsDataThrottler(int pBytes, int max, int min)
372 {
373 ThrottleBytes = pBytes;
374 lastTimeElapsed = Util.EnvironmentTickCount();
375 }
376 public bool hasEvents(UUID key, Dictionary<UUID, GetTextureModule.aPollResponse> responses)
377 {
378 PassTime();
379 // Note, this is called IN LOCK
380 bool haskey = responses.ContainsKey(key);
381 if (!haskey)
382 {
383 return false;
384 }
385 GetTextureModule.aPollResponse response;
386 if (responses.TryGetValue(key, out response))
387 {
388
389 // Normal
390 if (BytesSent + response.bytes <= ThrottleBytes)
391 {
392 BytesSent += response.bytes;
393 //TimeBasedAction timeBasedAction = new TimeBasedAction { byteRemoval = response.bytes, requestId = key, timeMS = currenttime + 1000, unlockyn = false };
394 //m_actions.Add(timeBasedAction);
395 return true;
396 }
397 // Big textures
398 else if (response.bytes > ThrottleBytes && oversizedImages <= ((ThrottleBytes % 50000) + 1))
399 {
400 Interlocked.Increment(ref oversizedImages);
401 BytesSent += response.bytes;
402 //TimeBasedAction timeBasedAction = new TimeBasedAction { byteRemoval = response.bytes, requestId = key, timeMS = currenttime + (((response.bytes % ThrottleBytes)+1)*1000) , unlockyn = false };
403 //m_actions.Add(timeBasedAction);
404 return true;
405 }
406 else
407 {
408 return false;
409 }
410 }
411
412 return haskey;
413 }
414 public void ProcessTime()
415 {
416 PassTime();
417 }
418
419
420 private void PassTime()
421 {
422 currenttime = Util.EnvironmentTickCount();
423 int timeElapsed = Util.EnvironmentTickCountSubtract(currenttime, lastTimeElapsed);
424 //processTimeBasedActions(responses);
425 if (Util.EnvironmentTickCountSubtract(currenttime, timeElapsed) >= 1000)
426 {
427 lastTimeElapsed = Util.EnvironmentTickCount();
428 BytesSent -= ThrottleBytes;
429 if (BytesSent < 0) BytesSent = 0;
430 if (BytesSent < ThrottleBytes)
431 {
432 oversizedImages = 0;
433 }
434 }
435 }
436 public int ThrottleBytes;
437 }
144 } 438 }
439
440
145} 441}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs
index 33b1f77..60c1814 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs
@@ -129,15 +129,15 @@ namespace OpenSim.Region.ClientStack.Linden
129// m_log.DebugFormat("[MESH UPLOAD FLAG MODULE]: MeshUploadFlag request"); 129// m_log.DebugFormat("[MESH UPLOAD FLAG MODULE]: MeshUploadFlag request");
130 130
131 OSDMap data = new OSDMap(); 131 OSDMap data = new OSDMap();
132 ScenePresence sp = m_scene.GetScenePresence(m_agentID); 132// ScenePresence sp = m_scene.GetScenePresence(m_agentID);
133 data["username"] = sp.Firstname + "." + sp.Lastname; 133// data["username"] = sp.Firstname + "." + sp.Lastname;
134 data["display_name_next_update"] = new OSDDate(DateTime.Now); 134// data["display_name_next_update"] = new OSDDate(DateTime.Now);
135 data["legacy_first_name"] = sp.Firstname; 135// data["legacy_first_name"] = sp.Firstname;
136 data["mesh_upload_status"] = "valid"; 136 data["mesh_upload_status"] = "valid";
137 data["display_name"] = sp.Firstname + " " + sp.Lastname; 137// data["display_name"] = sp.Firstname + " " + sp.Lastname;
138 data["legacy_last_name"] = sp.Lastname; 138// data["legacy_last_name"] = sp.Lastname;
139 data["id"] = m_agentID; 139// data["id"] = m_agentID;
140 data["is_display_name_default"] = true; 140// data["is_display_name_default"] = true;
141 141
142 //Send back data 142 //Send back data
143 Hashtable responsedata = new Hashtable(); 143 Hashtable responsedata = new Hashtable();
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs
deleted file mode 100644
index 5529550..0000000
--- a/OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs
+++ /dev/null
@@ -1,296 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Specialized;
31using System.Reflection;
32using System.IO;
33using System.Web;
34using Mono.Addins;
35using log4net;
36using Nini.Config;
37using OpenMetaverse;
38using OpenMetaverse.StructuredData;
39using OpenSim.Framework;
40using OpenSim.Framework.Servers;
41using OpenSim.Framework.Servers.HttpServer;
42using OpenSim.Region.Framework.Interfaces;
43using OpenSim.Region.Framework.Scenes;
44using OpenSim.Services.Interfaces;
45using Caps = OpenSim.Framework.Capabilities.Caps;
46using OpenSim.Framework.Capabilities;
47
48namespace OpenSim.Region.ClientStack.Linden
49{
50 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "NewFileAgentInventoryVariablePriceModule")]
51 public class NewFileAgentInventoryVariablePriceModule : INonSharedRegionModule
52 {
53// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
54
55 private Scene m_scene;
56// private IAssetService m_assetService;
57 private bool m_dumpAssetsToFile = false;
58 private bool m_enabled = true;
59 private int m_levelUpload = 0;
60
61 #region Region Module interfaceBase Members
62
63
64 public Type ReplaceableInterface
65 {
66 get { return null; }
67 }
68
69 public void Initialise(IConfigSource source)
70 {
71 IConfig meshConfig = source.Configs["Mesh"];
72 if (meshConfig == null)
73 return;
74
75 m_enabled = meshConfig.GetBoolean("AllowMeshUpload", true);
76 m_levelUpload = meshConfig.GetInt("LevelUpload", 0);
77 }
78
79 public void AddRegion(Scene pScene)
80 {
81 m_scene = pScene;
82 }
83
84 public void RemoveRegion(Scene scene)
85 {
86
87 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
88 m_scene = null;
89 }
90
91 public void RegionLoaded(Scene scene)
92 {
93
94// m_assetService = m_scene.RequestModuleInterface<IAssetService>();
95 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
96 }
97
98 #endregion
99
100
101 #region Region Module interface
102
103
104
105 public void Close() { }
106
107 public string Name { get { return "NewFileAgentInventoryVariablePriceModule"; } }
108
109
110 public void RegisterCaps(UUID agentID, Caps caps)
111 {
112 if(!m_enabled)
113 return;
114
115 UUID capID = UUID.Random();
116
117// m_log.Debug("[NEW FILE AGENT INVENTORY VARIABLE PRICE]: /CAPS/" + capID);
118 caps.RegisterHandler(
119 "NewFileAgentInventoryVariablePrice",
120 new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDNewFileAngentInventoryVariablePriceReplyResponse>(
121 "POST",
122 "/CAPS/" + capID.ToString(),
123 req => NewAgentInventoryRequest(req, agentID),
124 "NewFileAgentInventoryVariablePrice",
125 agentID.ToString()));
126 }
127
128 #endregion
129
130 public LLSDNewFileAngentInventoryVariablePriceReplyResponse NewAgentInventoryRequest(LLSDAssetUploadRequest llsdRequest, UUID agentID)
131 {
132 //TODO: The Mesh uploader uploads many types of content. If you're going to implement a Money based limit
133 // you need to be aware of this
134
135 //if (llsdRequest.asset_type == "texture" ||
136 // llsdRequest.asset_type == "animation" ||
137 // llsdRequest.asset_type == "sound")
138 // {
139 // check user level
140
141 ScenePresence avatar = null;
142 IClientAPI client = null;
143 m_scene.TryGetScenePresence(agentID, out avatar);
144
145 if (avatar != null)
146 {
147 client = avatar.ControllingClient;
148
149 if (avatar.UserLevel < m_levelUpload)
150 {
151 if (client != null)
152 client.SendAgentAlertMessage("Unable to upload asset. Insufficient permissions.", false);
153
154 LLSDNewFileAngentInventoryVariablePriceReplyResponse errorResponse = new LLSDNewFileAngentInventoryVariablePriceReplyResponse();
155 errorResponse.rsvp = "";
156 errorResponse.state = "error";
157 return errorResponse;
158 }
159 }
160
161 // check funds
162 IMoneyModule mm = m_scene.RequestModuleInterface<IMoneyModule>();
163
164 if (mm != null)
165 {
166 if (!mm.UploadCovered(agentID, mm.UploadCharge))
167 {
168 if (client != null)
169 client.SendAgentAlertMessage("Unable to upload asset. Insufficient funds.", false);
170
171 LLSDNewFileAngentInventoryVariablePriceReplyResponse errorResponse = new LLSDNewFileAngentInventoryVariablePriceReplyResponse();
172 errorResponse.rsvp = "";
173 errorResponse.state = "error";
174 return errorResponse;
175 }
176 }
177
178 // }
179
180 string assetName = llsdRequest.name;
181 string assetDes = llsdRequest.description;
182 string capsBase = "/CAPS/NewFileAgentInventoryVariablePrice/";
183 UUID newAsset = UUID.Random();
184 UUID newInvItem = UUID.Random();
185 UUID parentFolder = llsdRequest.folder_id;
186 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000") + "/";
187
188 AssetUploader uploader =
189 new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type,
190 llsdRequest.asset_type, capsBase + uploaderPath, MainServer.Instance, m_dumpAssetsToFile);
191
192 MainServer.Instance.AddStreamHandler(
193 new BinaryStreamHandler(
194 "POST",
195 capsBase + uploaderPath,
196 uploader.uploaderCaps,
197 "NewFileAgentInventoryVariablePrice",
198 agentID.ToString()));
199
200 string protocol = "http://";
201
202 if (MainServer.Instance.UseSSL)
203 protocol = "https://";
204
205 string uploaderURL = protocol + m_scene.RegionInfo.ExternalHostName + ":" + MainServer.Instance.Port.ToString() + capsBase +
206 uploaderPath;
207
208
209 LLSDNewFileAngentInventoryVariablePriceReplyResponse uploadResponse = new LLSDNewFileAngentInventoryVariablePriceReplyResponse();
210
211 uploadResponse.rsvp = uploaderURL;
212 uploadResponse.state = "upload";
213 uploadResponse.resource_cost = 0;
214 uploadResponse.upload_price = 0;
215
216 uploader.OnUpLoad += //UploadCompleteHandler;
217
218 delegate(
219 string passetName, string passetDescription, UUID passetID,
220 UUID pinventoryItem, UUID pparentFolder, byte[] pdata, string pinventoryType,
221 string passetType)
222 {
223 UploadCompleteHandler(passetName, passetDescription, passetID,
224 pinventoryItem, pparentFolder, pdata, pinventoryType,
225 passetType,agentID);
226 };
227
228 return uploadResponse;
229 }
230
231 public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID,
232 UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType,
233 string assetType,UUID AgentID)
234 {
235// m_log.DebugFormat(
236// "[NEW FILE AGENT INVENTORY VARIABLE PRICE MODULE]: Upload complete for {0}", inventoryItem);
237
238 sbyte assType = 0;
239 sbyte inType = 0;
240
241 if (inventoryType == "sound")
242 {
243 inType = 1;
244 assType = 1;
245 }
246 else if (inventoryType == "animation")
247 {
248 inType = 19;
249 assType = 20;
250 }
251 else if (inventoryType == "wearable")
252 {
253 inType = 18;
254 switch (assetType)
255 {
256 case "bodypart":
257 assType = 13;
258 break;
259 case "clothing":
260 assType = 5;
261 break;
262 }
263 }
264 else if (inventoryType == "mesh")
265 {
266 inType = (sbyte)InventoryType.Mesh;
267 assType = (sbyte)AssetType.Mesh;
268 }
269
270 AssetBase asset;
271 asset = new AssetBase(assetID, assetName, assType, AgentID.ToString());
272 asset.Data = data;
273
274 if (m_scene.AssetService != null)
275 m_scene.AssetService.Store(asset);
276
277 InventoryItemBase item = new InventoryItemBase();
278 item.Owner = AgentID;
279 item.CreatorId = AgentID.ToString();
280 item.ID = inventoryItem;
281 item.AssetID = asset.FullID;
282 item.Description = assetDescription;
283 item.Name = assetName;
284 item.AssetType = assType;
285 item.InvType = inType;
286 item.Folder = parentFolder;
287 item.CurrentPermissions
288 = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer);
289 item.BasePermissions = (uint)PermissionMask.All;
290 item.EveryOnePermissions = 0;
291 item.NextPermissions = (uint)PermissionMask.All;
292 item.CreationDate = Util.UnixTimeSinceEpoch();
293 m_scene.AddInventoryItem(item);
294 }
295 }
296}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs
index 17c7270..fcac182 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs
@@ -64,6 +64,8 @@ namespace OpenSim.Region.ClientStack.Linden
64 private Commands m_commands = new Commands(); 64 private Commands m_commands = new Commands();
65 public ICommands Commands { get { return m_commands; } } 65 public ICommands Commands { get { return m_commands; } }
66 66
67 public event ConsoleMessage OnConsoleMessage;
68
67 public void Initialise(IConfigSource source) 69 public void Initialise(IConfigSource source)
68 { 70 {
69 m_commands.AddCommand( "Help", false, "help", "help [<item>]", "Display help on a particular command or on a list of commands in a category", Help); 71 m_commands.AddCommand( "Help", false, "help", "help [<item>]", "Display help on a particular command or on a list of commands in a category", Help);
@@ -102,7 +104,7 @@ namespace OpenSim.Region.ClientStack.Linden
102 104
103 public void RegisterCaps(UUID agentID, Caps caps) 105 public void RegisterCaps(UUID agentID, Caps caps)
104 { 106 {
105 if (!m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(agentID)) 107 if (!m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(agentID) && !m_scene.Permissions.IsGod(agentID))
106 return; 108 return;
107 109
108 UUID capID = UUID.Random(); 110 UUID capID = UUID.Random();
@@ -118,6 +120,11 @@ namespace OpenSim.Region.ClientStack.Linden
118 OSD osd = OSD.FromString(message); 120 OSD osd = OSD.FromString(message);
119 121
120 m_eventQueue.Enqueue(EventQueueHelper.BuildEvent("SimConsoleResponse", osd), agentID); 122 m_eventQueue.Enqueue(EventQueueHelper.BuildEvent("SimConsoleResponse", osd), agentID);
123
124 ConsoleMessage handlerConsoleMessage = OnConsoleMessage;
125
126 if (handlerConsoleMessage != null)
127 handlerConsoleMessage( agentID, message);
121 } 128 }
122 129
123 public bool RunCommand(string command, UUID invokerID) 130 public bool RunCommand(string command, UUID invokerID)
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs
index 3b0ccd7..6bed95f 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs
@@ -27,6 +27,7 @@
27 27
28using System; 28using System;
29using System.Collections; 29using System.Collections;
30using System.Collections.Generic;
30using System.Collections.Specialized; 31using System.Collections.Specialized;
31using System.Drawing; 32using System.Drawing;
32using System.Drawing.Imaging; 33using System.Drawing.Imaging;
@@ -53,8 +54,8 @@ namespace OpenSim.Region.ClientStack.Linden
53 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "UploadBakedTextureModule")] 54 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "UploadBakedTextureModule")]
54 public class UploadBakedTextureModule : INonSharedRegionModule 55 public class UploadBakedTextureModule : INonSharedRegionModule
55 { 56 {
56// private static readonly ILog m_log = 57 private static readonly ILog m_log =
57// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 58 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
58 59
59 /// <summary> 60 /// <summary>
60 /// For historical reasons this is fixed, but there 61 /// For historical reasons this is fixed, but there
@@ -64,31 +65,195 @@ namespace OpenSim.Region.ClientStack.Linden
64 private Scene m_scene; 65 private Scene m_scene;
65 private bool m_persistBakedTextures; 66 private bool m_persistBakedTextures;
66 67
68 private IBakedTextureModule m_BakedTextureModule;
69
67 public void Initialise(IConfigSource source) 70 public void Initialise(IConfigSource source)
68 { 71 {
69 IConfig appearanceConfig = source.Configs["Appearance"]; 72 IConfig appearanceConfig = source.Configs["Appearance"];
70 if (appearanceConfig != null) 73 if (appearanceConfig != null)
71 m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures); 74 m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures);
75
76
72 } 77 }
73 78
74 public void AddRegion(Scene s) 79 public void AddRegion(Scene s)
75 { 80 {
76 m_scene = s; 81 m_scene = s;
82
77 } 83 }
78 84
79 public void RemoveRegion(Scene s) 85 public void RemoveRegion(Scene s)
80 { 86 {
87 s.EventManager.OnRegisterCaps -= RegisterCaps;
88 s.EventManager.OnNewPresence -= RegisterNewPresence;
89 s.EventManager.OnRemovePresence -= DeRegisterPresence;
90 m_BakedTextureModule = null;
91 m_scene = null;
81 } 92 }
82 93
94
95
83 public void RegionLoaded(Scene s) 96 public void RegionLoaded(Scene s)
84 { 97 {
85 m_scene.EventManager.OnRegisterCaps += RegisterCaps; 98 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
99 m_scene.EventManager.OnNewPresence += RegisterNewPresence;
100 m_scene.EventManager.OnRemovePresence += DeRegisterPresence;
101
102 }
103
104 private void DeRegisterPresence(UUID agentId)
105 {
106 ScenePresence presence = null;
107 if (m_scene.TryGetScenePresence(agentId, out presence))
108 {
109 presence.ControllingClient.OnSetAppearance -= CaptureAppearanceSettings;
110 }
111
112 }
113
114 private void RegisterNewPresence(ScenePresence presence)
115 {
116 presence.ControllingClient.OnSetAppearance += CaptureAppearanceSettings;
117
118 }
119
120 private void CaptureAppearanceSettings(IClientAPI remoteClient, Primitive.TextureEntry textureEntry, byte[] visualParams, Vector3 avSize, WearableCacheItem[] cacheItems)
121 {
122 int maxCacheitemsLoop = cacheItems.Length;
123 if (maxCacheitemsLoop > AvatarWearable.MAX_WEARABLES)
124 {
125 maxCacheitemsLoop = AvatarWearable.MAX_WEARABLES;
126 m_log.WarnFormat("[CACHEDBAKES]: Too Many Cache items Provided {0}, the max is {1}. Truncating!", cacheItems.Length, AvatarWearable.MAX_WEARABLES);
127 }
128
129 m_BakedTextureModule = m_scene.RequestModuleInterface<IBakedTextureModule>();
130 if (cacheItems.Length > 0)
131 {
132 m_log.Debug("[Cacheitems]: " + cacheItems.Length);
133 for (int iter = 0; iter < maxCacheitemsLoop; iter++)
134 {
135 m_log.Debug("[Cacheitems] {" + iter + "/" + cacheItems[iter].TextureIndex + "}: c-" + cacheItems[iter].CacheId + ", t-" +
136 cacheItems[iter].TextureID);
137 }
138
139 ScenePresence p = null;
140 if (m_scene.TryGetScenePresence(remoteClient.AgentId, out p))
141 {
142
143 WearableCacheItem[] existingitems = p.Appearance.WearableCacheItems;
144 if (existingitems == null)
145 {
146 if (m_BakedTextureModule != null)
147 {
148 WearableCacheItem[] savedcache = null;
149 try
150 {
151 if (p.Appearance.WearableCacheItemsDirty)
152 {
153 savedcache = m_BakedTextureModule.Get(p.UUID);
154 p.Appearance.WearableCacheItems = savedcache;
155 p.Appearance.WearableCacheItemsDirty = false;
156 }
157
158 }
159 /*
160 * The following Catch types DO NOT WORK with m_BakedTextureModule.Get
161 * it jumps to the General Packet Exception Handler if you don't catch Exception!
162 *
163 catch (System.Net.Sockets.SocketException)
164 {
165 cacheItems = null;
166 }
167 catch (WebException)
168 {
169 cacheItems = null;
170 }
171 catch (InvalidOperationException)
172 {
173 cacheItems = null;
174 } */
175 catch (Exception)
176 {
177 // The service logs a sufficient error message.
178 }
179
180
181 if (savedcache != null)
182 existingitems = savedcache;
183 }
184 }
185 // Existing items null means it's a fully new appearance
186 if (existingitems == null)
187 {
188
189 for (int i = 0; i < maxCacheitemsLoop; i++)
190 {
191 if (textureEntry.FaceTextures.Length > cacheItems[i].TextureIndex)
192 {
193 cacheItems[i].TextureID =
194 textureEntry.FaceTextures[cacheItems[i].TextureIndex].TextureID;
195 if (m_scene.AssetService != null)
196 cacheItems[i].TextureAsset =
197 m_scene.AssetService.GetCached(cacheItems[i].TextureID.ToString());
198 }
199 else
200 {
201 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);
202 }
203
204
205 }
206 }
207 else
208
209
210 {
211 // for each uploaded baked texture
212 for (int i = 0; i < maxCacheitemsLoop; i++)
213 {
214 if (textureEntry.FaceTextures.Length > cacheItems[i].TextureIndex)
215 {
216 cacheItems[i].TextureID =
217 textureEntry.FaceTextures[cacheItems[i].TextureIndex].TextureID;
218 }
219 else
220 {
221 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);
222 }
223 }
224
225 for (int i = 0; i < maxCacheitemsLoop; i++)
226 {
227 if (cacheItems[i].TextureAsset == null)
228 {
229 cacheItems[i].TextureAsset =
230 m_scene.AssetService.GetCached(cacheItems[i].TextureID.ToString());
231 }
232 }
233 }
234
235
236
237 p.Appearance.WearableCacheItems = cacheItems;
238
239
240
241 if (m_BakedTextureModule != null)
242 {
243 m_BakedTextureModule.Store(remoteClient.AgentId, cacheItems);
244 p.Appearance.WearableCacheItemsDirty = true;
245
246 }
247 }
248 }
86 } 249 }
87 250
88 public void PostInitialise() 251 public void PostInitialise()
89 { 252 {
90 } 253 }
91 254
255
256
92 public void Close() { } 257 public void Close() { }
93 258
94 public string Name { get { return "UploadBakedTextureModule"; } } 259 public string Name { get { return "UploadBakedTextureModule"; } }
@@ -100,15 +265,23 @@ namespace OpenSim.Region.ClientStack.Linden
100 265
101 public void RegisterCaps(UUID agentID, Caps caps) 266 public void RegisterCaps(UUID agentID, Caps caps)
102 { 267 {
268 UploadBakedTextureHandler avatarhandler = new UploadBakedTextureHandler(
269 caps, m_scene.AssetService, m_persistBakedTextures);
270
271
272
103 caps.RegisterHandler( 273 caps.RegisterHandler(
104 "UploadBakedTexture", 274 "UploadBakedTexture",
105 new RestStreamHandler( 275 new RestStreamHandler(
106 "POST", 276 "POST",
107 "/CAPS/" + caps.CapsObjectPath + m_uploadBakedTexturePath, 277 "/CAPS/" + caps.CapsObjectPath + m_uploadBakedTexturePath,
108 new UploadBakedTextureHandler( 278 avatarhandler.UploadBakedTexture,
109 caps, m_scene.AssetService, m_persistBakedTextures).UploadBakedTexture,
110 "UploadBakedTexture", 279 "UploadBakedTexture",
111 agentID.ToString())); 280 agentID.ToString()));
281
282
283
284
112 } 285 }
113 } 286 }
114} \ No newline at end of file 287} \ No newline at end of file
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs
index 6890f4a..04cd474 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs
@@ -27,18 +27,22 @@
27 27
28using System; 28using System;
29using System.Collections; 29using System.Collections;
30using System.Collections.Generic;
30using System.Reflection; 31using System.Reflection;
32using System.Threading;
31using log4net; 33using log4net;
32using Nini.Config; 34using Nini.Config;
33using Mono.Addins; 35using Mono.Addins;
34using OpenMetaverse; 36using OpenMetaverse;
35using OpenSim.Framework; 37using OpenSim.Framework;
38using OpenSim.Framework.Servers;
36using OpenSim.Framework.Servers.HttpServer; 39using OpenSim.Framework.Servers.HttpServer;
37using OpenSim.Region.Framework.Interfaces; 40using OpenSim.Region.Framework.Interfaces;
38using OpenSim.Region.Framework.Scenes; 41using OpenSim.Region.Framework.Scenes;
39using OpenSim.Services.Interfaces; 42using OpenSim.Services.Interfaces;
40using Caps = OpenSim.Framework.Capabilities.Caps; 43using Caps = OpenSim.Framework.Capabilities.Caps;
41using OpenSim.Capabilities.Handlers; 44using OpenSim.Capabilities.Handlers;
45using OpenSim.Framework.Monitoring;
42 46
43namespace OpenSim.Region.ClientStack.Linden 47namespace OpenSim.Region.ClientStack.Linden
44{ 48{
@@ -48,67 +52,72 @@ namespace OpenSim.Region.ClientStack.Linden
48 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "WebFetchInvDescModule")] 52 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "WebFetchInvDescModule")]
49 public class WebFetchInvDescModule : INonSharedRegionModule 53 public class WebFetchInvDescModule : INonSharedRegionModule
50 { 54 {
51// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 55 struct aPollRequest
56 {
57 public PollServiceInventoryEventArgs thepoll;
58 public UUID reqID;
59 public Hashtable request;
60 }
61
62 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
52 63
53 private Scene m_scene; 64 private Scene m_scene;
54 65
55 private IInventoryService m_InventoryService; 66 private IInventoryService m_InventoryService;
56 private ILibraryService m_LibraryService; 67 private ILibraryService m_LibraryService;
57 68
58 private bool m_Enabled; 69 private static WebFetchInvDescHandler m_webFetchHandler;
59 70
60 private string m_fetchInventoryDescendents2Url; 71 private Dictionary<UUID, string> m_capsDict = new Dictionary<UUID, string>();
61 private string m_webFetchInventoryDescendentsUrl; 72 private static Thread[] m_workerThreads = null;
62 73
63 private WebFetchInvDescHandler m_webFetchHandler; 74 private static OpenMetaverse.BlockingQueue<aPollRequest> m_queue =
75 new OpenMetaverse.BlockingQueue<aPollRequest>();
64 76
65 #region ISharedRegionModule Members 77 #region ISharedRegionModule Members
66 78
67 public void Initialise(IConfigSource source) 79 public void Initialise(IConfigSource source)
68 { 80 {
69 IConfig config = source.Configs["ClientStack.LindenCaps"];
70 if (config == null)
71 return;
72
73 m_fetchInventoryDescendents2Url = config.GetString("Cap_FetchInventoryDescendents2", string.Empty);
74 m_webFetchInventoryDescendentsUrl = config.GetString("Cap_WebFetchInventoryDescendents", string.Empty);
75
76 if (m_fetchInventoryDescendents2Url != string.Empty || m_webFetchInventoryDescendentsUrl != string.Empty)
77 {
78 m_Enabled = true;
79 }
80 } 81 }
81 82
82 public void AddRegion(Scene s) 83 public void AddRegion(Scene s)
83 { 84 {
84 if (!m_Enabled)
85 return;
86
87 m_scene = s; 85 m_scene = s;
88 } 86 }
89 87
90 public void RemoveRegion(Scene s) 88 public void RemoveRegion(Scene s)
91 { 89 {
92 if (!m_Enabled)
93 return;
94
95 m_scene.EventManager.OnRegisterCaps -= RegisterCaps; 90 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
91 m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps;
96 m_scene = null; 92 m_scene = null;
97 } 93 }
98 94
99 public void RegionLoaded(Scene s) 95 public void RegionLoaded(Scene s)
100 { 96 {
101 if (!m_Enabled)
102 return;
103
104 m_InventoryService = m_scene.InventoryService; 97 m_InventoryService = m_scene.InventoryService;
105 m_LibraryService = m_scene.LibraryService; 98 m_LibraryService = m_scene.LibraryService;
106 99
107 // We'll reuse the same handler for all requests. 100 // We'll reuse the same handler for all requests.
108 if (m_fetchInventoryDescendents2Url == "localhost" || m_webFetchInventoryDescendentsUrl == "localhost") 101 m_webFetchHandler = new WebFetchInvDescHandler(m_InventoryService, m_LibraryService);
109 m_webFetchHandler = new WebFetchInvDescHandler(m_InventoryService, m_LibraryService);
110 102
111 m_scene.EventManager.OnRegisterCaps += RegisterCaps; 103 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
104 m_scene.EventManager.OnDeregisterCaps += DeregisterCaps;
105
106 if (m_workerThreads == null)
107 {
108 m_workerThreads = new Thread[2];
109
110 for (uint i = 0; i < 2; i++)
111 {
112 m_workerThreads[i] = Watchdog.StartThread(DoInventoryRequests,
113 String.Format("InventoryWorkerThread{0}", i),
114 ThreadPriority.Normal,
115 false,
116 true,
117 null,
118 int.MaxValue);
119 }
120 }
112 } 121 }
113 122
114 public void PostInitialise() 123 public void PostInitialise()
@@ -126,43 +135,130 @@ namespace OpenSim.Region.ClientStack.Linden
126 135
127 #endregion 136 #endregion
128 137
129 private void RegisterCaps(UUID agentID, Caps caps) 138 ~WebFetchInvDescModule()
130 { 139 {
131 if (m_webFetchInventoryDescendentsUrl != "") 140 foreach (Thread t in m_workerThreads)
132 RegisterFetchCap(agentID, caps, "WebFetchInventoryDescendents", m_webFetchInventoryDescendentsUrl); 141 Watchdog.AbortThread(t.ManagedThreadId);
133
134 if (m_fetchInventoryDescendents2Url != "")
135 RegisterFetchCap(agentID, caps, "FetchInventoryDescendents2", m_fetchInventoryDescendents2Url);
136 } 142 }
137 143
138 private void RegisterFetchCap(UUID agentID, Caps caps, string capName, string url) 144 private class PollServiceInventoryEventArgs : PollServiceEventArgs
139 { 145 {
140 string capUrl; 146 private Dictionary<UUID, Hashtable> responses =
147 new Dictionary<UUID, Hashtable>();
148
149 public PollServiceInventoryEventArgs(UUID pId) :
150 base(null, null, null, null, pId, int.MaxValue)
151 {
152 HasEvents = (x, y) => { lock (responses) return responses.ContainsKey(x); };
153 GetEvents = (x, y) =>
154 {
155 lock (responses)
156 {
157 try
158 {
159 return responses[x];
160 }
161 finally
162 {
163 responses.Remove(x);
164 }
165 }
166 };
167
168 Request = (x, y) =>
169 {
170 aPollRequest reqinfo = new aPollRequest();
171 reqinfo.thepoll = this;
172 reqinfo.reqID = x;
173 reqinfo.request = y;
174
175 m_queue.Enqueue(reqinfo);
176 };
177
178 NoEvents = (x, y) =>
179 {
180/*
181 lock (requests)
182 {
183 Hashtable request = requests.Find(id => id["RequestID"].ToString() == x.ToString());
184 requests.Remove(request);
185 }
186*/
187 Hashtable response = new Hashtable();
188
189 response["int_response_code"] = 500;
190 response["str_response_string"] = "Script timeout";
191 response["content_type"] = "text/plain";
192 response["keepalive"] = false;
193 response["reusecontext"] = false;
194
195 return response;
196 };
197 }
141 198
142 if (url == "localhost") 199 public void Process(aPollRequest requestinfo)
143 { 200 {
144 capUrl = "/CAPS/" + UUID.Random(); 201 UUID requestID = requestinfo.reqID;
202
203 Hashtable response = new Hashtable();
204
205 response["int_response_code"] = 200;
206 response["content_type"] = "text/plain";
207 response["keepalive"] = false;
208 response["reusecontext"] = false;
145 209
146 IRequestHandler reqHandler 210 response["str_response_string"] = m_webFetchHandler.FetchInventoryDescendentsRequest(
147 = new RestStreamHandler( 211 requestinfo.request["body"].ToString(), String.Empty, String.Empty, null, null);
148 "POST",
149 capUrl,
150 m_webFetchHandler.FetchInventoryDescendentsRequest,
151 "FetchInventoryDescendents2",
152 agentID.ToString());
153 212
154 caps.RegisterHandler(capName, reqHandler); 213 lock (responses)
214 responses[requestID] = response;
155 } 215 }
156 else 216 }
217
218 private void RegisterCaps(UUID agentID, Caps caps)
219 {
220 string capUrl = "/CAPS/" + UUID.Random() + "/";
221
222 // Register this as a poll service
223 PollServiceInventoryEventArgs args = new PollServiceInventoryEventArgs(agentID);
224
225 args.Type = PollServiceEventArgs.EventType.Inventory;
226 MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args);
227
228 string hostName = m_scene.RegionInfo.ExternalHostName;
229 uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port;
230 string protocol = "http";
231
232 if (MainServer.Instance.UseSSL)
157 { 233 {
158 capUrl = url; 234 hostName = MainServer.Instance.SSLCommonName;
235 port = MainServer.Instance.SSLPort;
236 protocol = "https";
237 }
238 caps.RegisterHandler("FetchInventoryDescendents2", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl));
239
240 m_capsDict[agentID] = capUrl;
241 }
159 242
160 caps.RegisterHandler(capName, capUrl); 243 private void DeregisterCaps(UUID agentID, Caps caps)
244 {
245 string capUrl;
246
247 if (m_capsDict.TryGetValue(agentID, out capUrl))
248 {
249 MainServer.Instance.RemoveHTTPHandler("", capUrl);
250 m_capsDict.Remove(agentID);
161 } 251 }
252 }
162 253
163// m_log.DebugFormat( 254 private void DoInventoryRequests()
164// "[WEB FETCH INV DESC MODULE]: Registered capability {0} at {1} in region {2} for {3}", 255 {
165// capName, capUrl, m_scene.RegionInfo.RegionName, agentID); 256 while (true)
257 {
258 aPollRequest poolreq = m_queue.Dequeue();
259
260 poolreq.thepoll.Process(poolreq);
261 }
166 } 262 }
167 } 263 }
168} \ No newline at end of file 264}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs b/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs
index afbe56b..3995620 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs
@@ -234,6 +234,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
234 m_stopPacket = TexturePacketCount(); 234 m_stopPacket = TexturePacketCount();
235 } 235 }
236 236
237 //Give them at least two packets, to play nice with some broken viewers (SL also behaves this way)
238 if (m_stopPacket == 1 && m_layers[0].End > FIRST_PACKET_SIZE) m_stopPacket++;
239
237 m_currentPacket = StartPacket; 240 m_currentPacket = StartPacket;
238 } 241 }
239 } 242 }
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
index 504df40..465d76d 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
@@ -99,6 +99,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
99 public event AvatarPickerRequest OnAvatarPickerRequest; 99 public event AvatarPickerRequest OnAvatarPickerRequest;
100 public event StartAnim OnStartAnim; 100 public event StartAnim OnStartAnim;
101 public event StopAnim OnStopAnim; 101 public event StopAnim OnStopAnim;
102 public event ChangeAnim OnChangeAnim;
102 public event Action<IClientAPI> OnRequestAvatarsData; 103 public event Action<IClientAPI> OnRequestAvatarsData;
103 public event LinkObjects OnLinkObjects; 104 public event LinkObjects OnLinkObjects;
104 public event DelinkObjects OnDelinkObjects; 105 public event DelinkObjects OnDelinkObjects;
@@ -126,6 +127,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
126 public event RequestObjectPropertiesFamily OnRequestObjectPropertiesFamily; 127 public event RequestObjectPropertiesFamily OnRequestObjectPropertiesFamily;
127 public event UpdatePrimFlags OnUpdatePrimFlags; 128 public event UpdatePrimFlags OnUpdatePrimFlags;
128 public event UpdatePrimTexture OnUpdatePrimTexture; 129 public event UpdatePrimTexture OnUpdatePrimTexture;
130 public event ClientChangeObject onClientChangeObject;
129 public event UpdateVector OnUpdatePrimGroupPosition; 131 public event UpdateVector OnUpdatePrimGroupPosition;
130 public event UpdateVector OnUpdatePrimSinglePosition; 132 public event UpdateVector OnUpdatePrimSinglePosition;
131 public event UpdatePrimRotation OnUpdatePrimGroupRotation; 133 public event UpdatePrimRotation OnUpdatePrimGroupRotation;
@@ -159,6 +161,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
159 public event RequestTaskInventory OnRequestTaskInventory; 161 public event RequestTaskInventory OnRequestTaskInventory;
160 public event UpdateInventoryItem OnUpdateInventoryItem; 162 public event UpdateInventoryItem OnUpdateInventoryItem;
161 public event CopyInventoryItem OnCopyInventoryItem; 163 public event CopyInventoryItem OnCopyInventoryItem;
164 public event MoveItemsAndLeaveCopy OnMoveItemsAndLeaveCopy;
162 public event MoveInventoryItem OnMoveInventoryItem; 165 public event MoveInventoryItem OnMoveInventoryItem;
163 public event RemoveInventoryItem OnRemoveInventoryItem; 166 public event RemoveInventoryItem OnRemoveInventoryItem;
164 public event RemoveInventoryFolder OnRemoveInventoryFolder; 167 public event RemoveInventoryFolder OnRemoveInventoryFolder;
@@ -257,7 +260,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
257 public event ClassifiedInfoRequest OnClassifiedInfoRequest; 260 public event ClassifiedInfoRequest OnClassifiedInfoRequest;
258 public event ClassifiedInfoUpdate OnClassifiedInfoUpdate; 261 public event ClassifiedInfoUpdate OnClassifiedInfoUpdate;
259 public event ClassifiedDelete OnClassifiedDelete; 262 public event ClassifiedDelete OnClassifiedDelete;
260 public event ClassifiedDelete OnClassifiedGodDelete; 263 public event ClassifiedGodDelete OnClassifiedGodDelete;
261 public event EventNotificationAddRequest OnEventNotificationAddRequest; 264 public event EventNotificationAddRequest OnEventNotificationAddRequest;
262 public event EventNotificationRemoveRequest OnEventNotificationRemoveRequest; 265 public event EventNotificationRemoveRequest OnEventNotificationRemoveRequest;
263 public event EventGodDelete OnEventGodDelete; 266 public event EventGodDelete OnEventGodDelete;
@@ -288,10 +291,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
288 public event GroupVoteHistoryRequest OnGroupVoteHistoryRequest; 291 public event GroupVoteHistoryRequest OnGroupVoteHistoryRequest;
289 public event SimWideDeletesDelegate OnSimWideDeletes; 292 public event SimWideDeletesDelegate OnSimWideDeletes;
290 public event SendPostcard OnSendPostcard; 293 public event SendPostcard OnSendPostcard;
294 public event ChangeInventoryItemFlags OnChangeInventoryItemFlags;
291 public event MuteListEntryUpdate OnUpdateMuteListEntry; 295 public event MuteListEntryUpdate OnUpdateMuteListEntry;
292 public event MuteListEntryRemove OnRemoveMuteListEntry; 296 public event MuteListEntryRemove OnRemoveMuteListEntry;
293 public event GodlikeMessage onGodlikeMessage; 297 public event GodlikeMessage onGodlikeMessage;
294 public event GodUpdateRegionInfoUpdate OnGodUpdateRegionInfoUpdate; 298 public event GodUpdateRegionInfoUpdate OnGodUpdateRegionInfoUpdate;
299 public event GenericCall2 OnUpdateThrottles;
295 300
296 #endregion Events 301 #endregion Events
297 302
@@ -326,6 +331,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
326 private Prioritizer m_prioritizer; 331 private Prioritizer m_prioritizer;
327 private bool m_disableFacelights = false; 332 private bool m_disableFacelights = false;
328 333
334 private bool m_VelocityInterpolate = false;
335 private const uint MaxTransferBytesPerPacket = 600;
336
337
329 /// <value> 338 /// <value>
330 /// List used in construction of data blocks for an object update packet. This is to stop us having to 339 /// List used in construction of data blocks for an object update packet. This is to stop us having to
331 /// continually recreate it. 340 /// continually recreate it.
@@ -337,14 +346,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
337 /// thread servicing the m_primFullUpdates queue after a kill. If this happens the object persists as an 346 /// thread servicing the m_primFullUpdates queue after a kill. If this happens the object persists as an
338 /// ownerless phantom. 347 /// ownerless phantom.
339 /// 348 ///
340 /// All manipulation of this set has to occur under a lock 349 /// All manipulation of this set has to occur under an m_entityUpdates.SyncRoot lock
341 /// 350 ///
342 /// </value> 351 /// </value>
343 protected HashSet<uint> m_killRecord; 352// protected HashSet<uint> m_killRecord;
344 353
345// protected HashSet<uint> m_attachmentsSent; 354// protected HashSet<uint> m_attachmentsSent;
346 355
347 private int m_moneyBalance; 356 private int m_moneyBalance;
357 private bool m_deliverPackets = true;
348 private int m_animationSequenceNumber = 1; 358 private int m_animationSequenceNumber = 1;
349 private bool m_SendLogoutPacketWhenClosing = true; 359 private bool m_SendLogoutPacketWhenClosing = true;
350 360
@@ -391,6 +401,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
391 get { return m_startpos; } 401 get { return m_startpos; }
392 set { m_startpos = value; } 402 set { m_startpos = value; }
393 } 403 }
404 public bool DeliverPackets
405 {
406 get { return m_deliverPackets; }
407 set {
408 m_deliverPackets = value;
409 m_udpClient.m_deliverPackets = value;
410 }
411 }
394 public UUID AgentId { get { return m_agentId; } } 412 public UUID AgentId { get { return m_agentId; } }
395 public ISceneAgent SceneAgent { get; set; } 413 public ISceneAgent SceneAgent { get; set; }
396 public UUID ActiveGroupId { get { return m_activeGroupID; } } 414 public UUID ActiveGroupId { get { return m_activeGroupID; } }
@@ -442,6 +460,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
442 } 460 }
443 461
444 public bool SendLogoutPacketWhenClosing { set { m_SendLogoutPacketWhenClosing = value; } } 462 public bool SendLogoutPacketWhenClosing { set { m_SendLogoutPacketWhenClosing = value; } }
463
445 464
446 #endregion Properties 465 #endregion Properties
447 466
@@ -468,7 +487,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
468 m_entityUpdates = new PriorityQueue(m_scene.Entities.Count); 487 m_entityUpdates = new PriorityQueue(m_scene.Entities.Count);
469 m_entityProps = new PriorityQueue(m_scene.Entities.Count); 488 m_entityProps = new PriorityQueue(m_scene.Entities.Count);
470 m_fullUpdateDataBlocksBuilder = new List<ObjectUpdatePacket.ObjectDataBlock>(); 489 m_fullUpdateDataBlocksBuilder = new List<ObjectUpdatePacket.ObjectDataBlock>();
471 m_killRecord = new HashSet<uint>(); 490// m_killRecord = new HashSet<uint>();
472// m_attachmentsSent = new HashSet<uint>(); 491// m_attachmentsSent = new HashSet<uint>();
473 492
474 m_assetService = m_scene.RequestModuleInterface<IAssetService>(); 493 m_assetService = m_scene.RequestModuleInterface<IAssetService>();
@@ -498,12 +517,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
498 517
499 #region Client Methods 518 #region Client Methods
500 519
520
521 /// <summary>
522 /// Close down the client view
523 /// </summary>
501 public void Close() 524 public void Close()
502 { 525 {
503 Close(false); 526 Close(true, false);
504 } 527 }
505 528
506 public void Close(bool force) 529 public void Close(bool sendStop, bool force)
507 { 530 {
508 // We lock here to prevent race conditions between two threads calling close simultaneously (e.g. 531 // We lock here to prevent race conditions between two threads calling close simultaneously (e.g.
509 // a simultaneous relog just as a client is being closed out due to no packet ack from the old connection. 532 // a simultaneous relog just as a client is being closed out due to no packet ack from the old connection.
@@ -515,7 +538,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
515 return; 538 return;
516 539
517 IsActive = false; 540 IsActive = false;
518 CloseWithoutChecks(); 541 CloseWithoutChecks(sendStop);
519 } 542 }
520 } 543 }
521 544
@@ -528,12 +551,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
528 /// 551 ///
529 /// Callers must lock ClosingSyncLock before calling. 552 /// Callers must lock ClosingSyncLock before calling.
530 /// </remarks> 553 /// </remarks>
531 public void CloseWithoutChecks() 554 public void CloseWithoutChecks(bool sendStop)
532 { 555 {
533 m_log.DebugFormat( 556 m_log.DebugFormat(
534 "[CLIENT]: Close has been called for {0} attached to scene {1}", 557 "[CLIENT]: Close has been called for {0} attached to scene {1}",
535 Name, m_scene.RegionInfo.RegionName); 558 Name, m_scene.RegionInfo.RegionName);
536 559
560 if (sendStop)
561 {
562 // Send the STOP packet
563 DisableSimulatorPacket disable = (DisableSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.DisableSimulator);
564 OutPacket(disable, ThrottleOutPacketType.Unknown);
565 }
566
537 // Shutdown the image manager 567 // Shutdown the image manager
538 ImageManager.Close(); 568 ImageManager.Close();
539 569
@@ -556,6 +586,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
556 // Disable UDP handling for this client 586 // Disable UDP handling for this client
557 m_udpClient.Shutdown(); 587 m_udpClient.Shutdown();
558 588
589
559 //m_log.InfoFormat("[CLIENTVIEW] Memory pre GC {0}", System.GC.GetTotalMemory(false)); 590 //m_log.InfoFormat("[CLIENTVIEW] Memory pre GC {0}", System.GC.GetTotalMemory(false));
560 //GC.Collect(); 591 //GC.Collect();
561 //m_log.InfoFormat("[CLIENTVIEW] Memory post GC {0}", System.GC.GetTotalMemory(true)); 592 //m_log.InfoFormat("[CLIENTVIEW] Memory post GC {0}", System.GC.GetTotalMemory(true));
@@ -791,7 +822,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
791 handshake.RegionInfo3.ProductName = Util.StringToBytes256(regionInfo.RegionType); 822 handshake.RegionInfo3.ProductName = Util.StringToBytes256(regionInfo.RegionType);
792 handshake.RegionInfo3.ProductSKU = Utils.EmptyBytes; 823 handshake.RegionInfo3.ProductSKU = Utils.EmptyBytes;
793 824
794 OutPacket(handshake, ThrottleOutPacketType.Task); 825// OutPacket(handshake, ThrottleOutPacketType.Task);
826 // use same as MoveAgentIntoRegion (both should be task )
827 OutPacket(handshake, ThrottleOutPacketType.Unknown);
795 } 828 }
796 829
797 public void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look) 830 public void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look)
@@ -831,7 +864,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
831 reply.ChatData.OwnerID = ownerID; 864 reply.ChatData.OwnerID = ownerID;
832 reply.ChatData.SourceID = fromAgentID; 865 reply.ChatData.SourceID = fromAgentID;
833 866
834 OutPacket(reply, ThrottleOutPacketType.Task); 867 OutPacket(reply, ThrottleOutPacketType.Unknown);
835 } 868 }
836 869
837 /// <summary> 870 /// <summary>
@@ -1117,6 +1150,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1117 public virtual void SendLayerData(float[] map) 1150 public virtual void SendLayerData(float[] map)
1118 { 1151 {
1119 Util.FireAndForget(DoSendLayerData, map); 1152 Util.FireAndForget(DoSendLayerData, map);
1153
1154 // Send it sync, and async. It's not that much data
1155 // and it improves user experience just so much!
1156 DoSendLayerData(map);
1120 } 1157 }
1121 1158
1122 /// <summary> 1159 /// <summary>
@@ -1129,16 +1166,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1129 1166
1130 try 1167 try
1131 { 1168 {
1132 //for (int y = 0; y < 16; y++) 1169 for (int y = 0; y < 16; y++)
1133 //{ 1170 {
1134 // for (int x = 0; x < 16; x++) 1171 for (int x = 0; x < 16; x+=4)
1135 // { 1172 {
1136 // SendLayerData(x, y, map); 1173 SendLayerPacket(x, y, map);
1137 // } 1174 }
1138 //} 1175 }
1139
1140 // Send LayerData in a spiral pattern. Fun!
1141 SendLayerTopRight(map, 0, 0, 15, 15);
1142 } 1176 }
1143 catch (Exception e) 1177 catch (Exception e)
1144 { 1178 {
@@ -1146,51 +1180,35 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1146 } 1180 }
1147 } 1181 }
1148 1182
1149 private void SendLayerTopRight(float[] map, int x1, int y1, int x2, int y2)
1150 {
1151 // Row
1152 for (int i = x1; i <= x2; i++)
1153 SendLayerData(i, y1, map);
1154
1155 // Column
1156 for (int j = y1 + 1; j <= y2; j++)
1157 SendLayerData(x2, j, map);
1158
1159 if (x2 - x1 > 0)
1160 SendLayerBottomLeft(map, x1, y1 + 1, x2 - 1, y2);
1161 }
1162
1163 void SendLayerBottomLeft(float[] map, int x1, int y1, int x2, int y2)
1164 {
1165 // Row in reverse
1166 for (int i = x2; i >= x1; i--)
1167 SendLayerData(i, y2, map);
1168
1169 // Column in reverse
1170 for (int j = y2 - 1; j >= y1; j--)
1171 SendLayerData(x1, j, map);
1172
1173 if (x2 - x1 > 0)
1174 SendLayerTopRight(map, x1 + 1, y1, x2, y2 - 1);
1175 }
1176
1177 /// <summary> 1183 /// <summary>
1178 /// Sends a set of four patches (x, x+1, ..., x+3) to the client 1184 /// Sends a set of four patches (x, x+1, ..., x+3) to the client
1179 /// </summary> 1185 /// </summary>
1180 /// <param name="map">heightmap</param> 1186 /// <param name="map">heightmap</param>
1181 /// <param name="px">X coordinate for patches 0..12</param> 1187 /// <param name="px">X coordinate for patches 0..12</param>
1182 /// <param name="py">Y coordinate for patches 0..15</param> 1188 /// <param name="py">Y coordinate for patches 0..15</param>
1183 // private void SendLayerPacket(float[] map, int y, int x) 1189 private void SendLayerPacket(int x, int y, float[] map)
1184 // { 1190 {
1185 // int[] patches = new int[4]; 1191 int[] patches = new int[4];
1186 // patches[0] = x + 0 + y * 16; 1192 patches[0] = x + 0 + y * 16;
1187 // patches[1] = x + 1 + y * 16; 1193 patches[1] = x + 1 + y * 16;
1188 // patches[2] = x + 2 + y * 16; 1194 patches[2] = x + 2 + y * 16;
1189 // patches[3] = x + 3 + y * 16; 1195 patches[3] = x + 3 + y * 16;
1190 1196
1191 // Packet layerpack = LLClientView.TerrainManager.CreateLandPacket(map, patches); 1197 float[] heightmap = (map.Length == 65536) ?
1192 // OutPacket(layerpack, ThrottleOutPacketType.Land); 1198 map :
1193 // } 1199 LLHeightFieldMoronize(map);
1200
1201 try
1202 {
1203 Packet layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches);
1204 OutPacket(layerpack, ThrottleOutPacketType.Land);
1205 }
1206 catch
1207 {
1208 for (int px = x ; px < x + 4 ; px++)
1209 SendLayerData(px, y, map);
1210 }
1211 }
1194 1212
1195 /// <summary> 1213 /// <summary>
1196 /// Sends a specified patch to a client 1214 /// Sends a specified patch to a client
@@ -1210,7 +1228,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1210 LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches); 1228 LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches);
1211 layerpack.Header.Reliable = true; 1229 layerpack.Header.Reliable = true;
1212 1230
1213 OutPacket(layerpack, ThrottleOutPacketType.Land); 1231 OutPacket(layerpack, ThrottleOutPacketType.Task);
1214 } 1232 }
1215 catch (Exception e) 1233 catch (Exception e)
1216 { 1234 {
@@ -1573,7 +1591,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1573 1591
1574 public void SendKillObject(ulong regionHandle, List<uint> localIDs) 1592 public void SendKillObject(ulong regionHandle, List<uint> localIDs)
1575 { 1593 {
1576// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, localID, regionHandle); 1594// foreach (uint id in localIDs)
1595// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, id, regionHandle);
1577 1596
1578 KillObjectPacket kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject); 1597 KillObjectPacket kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject);
1579 // TODO: don't create new blocks if recycling an old packet 1598 // TODO: don't create new blocks if recycling an old packet
@@ -1595,17 +1614,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1595 // We MUST lock for both manipulating the kill record and sending the packet, in order to avoid a race 1614 // We MUST lock for both manipulating the kill record and sending the packet, in order to avoid a race
1596 // condition where a kill can be processed before an out-of-date update for the same object. 1615 // condition where a kill can be processed before an out-of-date update for the same object.
1597 // ProcessEntityUpdates() also takes the m_killRecord lock. 1616 // ProcessEntityUpdates() also takes the m_killRecord lock.
1598 lock (m_killRecord) 1617// lock (m_killRecord)
1599 { 1618// {
1600 foreach (uint localID in localIDs) 1619// foreach (uint localID in localIDs)
1601 m_killRecord.Add(localID); 1620// m_killRecord.Add(localID);
1602 1621
1603 // The throttle queue used here must match that being used for updates. Otherwise, there is a 1622 // The throttle queue used here must match that being used for updates. Otherwise, there is a
1604 // chance that a kill packet put on a separate queue will be sent to the client before an existing 1623 // chance that a kill packet put on a separate queue will be sent to the client before an existing
1605 // update packet on another queue. Receiving updates after kills results in unowned and undeletable 1624 // update packet on another queue. Receiving updates after kills results in unowned and undeletable
1606 // scene objects in a viewer until that viewer is relogged in. 1625 // scene objects in a viewer until that viewer is relogged in.
1607 OutPacket(kill, ThrottleOutPacketType.Task); 1626 OutPacket(kill, ThrottleOutPacketType.Task);
1608 } 1627// }
1609 } 1628 }
1610 } 1629 }
1611 1630
@@ -2063,9 +2082,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2063 OutPacket(bulkUpdate, ThrottleOutPacketType.Asset); 2082 OutPacket(bulkUpdate, ThrottleOutPacketType.Asset);
2064 } 2083 }
2065 2084
2066 /// <see>IClientAPI.SendInventoryItemCreateUpdate(InventoryItemBase)</see>
2067 public void SendInventoryItemCreateUpdate(InventoryItemBase Item, uint callbackId) 2085 public void SendInventoryItemCreateUpdate(InventoryItemBase Item, uint callbackId)
2068 { 2086 {
2087 SendInventoryItemCreateUpdate(Item, UUID.Zero, callbackId);
2088 }
2089
2090 /// <see>IClientAPI.SendInventoryItemCreateUpdate(InventoryItemBase)</see>
2091 public void SendInventoryItemCreateUpdate(InventoryItemBase Item, UUID transactionID, uint callbackId)
2092 {
2069 const uint FULL_MASK_PERMISSIONS = (uint)PermissionMask.All; 2093 const uint FULL_MASK_PERMISSIONS = (uint)PermissionMask.All;
2070 2094
2071 UpdateCreateInventoryItemPacket InventoryReply 2095 UpdateCreateInventoryItemPacket InventoryReply
@@ -2075,6 +2099,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2075 // TODO: don't create new blocks if recycling an old packet 2099 // TODO: don't create new blocks if recycling an old packet
2076 InventoryReply.AgentData.AgentID = AgentId; 2100 InventoryReply.AgentData.AgentID = AgentId;
2077 InventoryReply.AgentData.SimApproved = true; 2101 InventoryReply.AgentData.SimApproved = true;
2102 InventoryReply.AgentData.TransactionID = transactionID;
2078 InventoryReply.InventoryData = new UpdateCreateInventoryItemPacket.InventoryDataBlock[1]; 2103 InventoryReply.InventoryData = new UpdateCreateInventoryItemPacket.InventoryDataBlock[1];
2079 InventoryReply.InventoryData[0] = new UpdateCreateInventoryItemPacket.InventoryDataBlock(); 2104 InventoryReply.InventoryData[0] = new UpdateCreateInventoryItemPacket.InventoryDataBlock();
2080 InventoryReply.InventoryData[0].ItemID = Item.ID; 2105 InventoryReply.InventoryData[0].ItemID = Item.ID;
@@ -2144,16 +2169,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2144 replytask.InventoryData.TaskID = taskID; 2169 replytask.InventoryData.TaskID = taskID;
2145 replytask.InventoryData.Serial = serial; 2170 replytask.InventoryData.Serial = serial;
2146 replytask.InventoryData.Filename = fileName; 2171 replytask.InventoryData.Filename = fileName;
2147 OutPacket(replytask, ThrottleOutPacketType.Asset); 2172 OutPacket(replytask, ThrottleOutPacketType.Task);
2148 } 2173 }
2149 2174
2150 public void SendXferPacket(ulong xferID, uint packet, byte[] data) 2175 public void SendXferPacket(ulong xferID, uint packet, byte[] data, bool isTaskInventory)
2151 { 2176 {
2177 ThrottleOutPacketType type = ThrottleOutPacketType.Asset;
2178 if (isTaskInventory)
2179 type = ThrottleOutPacketType.Task;
2180
2152 SendXferPacketPacket sendXfer = (SendXferPacketPacket)PacketPool.Instance.GetPacket(PacketType.SendXferPacket); 2181 SendXferPacketPacket sendXfer = (SendXferPacketPacket)PacketPool.Instance.GetPacket(PacketType.SendXferPacket);
2153 sendXfer.XferID.ID = xferID; 2182 sendXfer.XferID.ID = xferID;
2154 sendXfer.XferID.Packet = packet; 2183 sendXfer.XferID.Packet = packet;
2155 sendXfer.DataPacket.Data = data; 2184 sendXfer.DataPacket.Data = data;
2156 OutPacket(sendXfer, ThrottleOutPacketType.Asset); 2185 OutPacket(sendXfer, type);
2157 } 2186 }
2158 2187
2159 public void SendAbortXferPacket(ulong xferID) 2188 public void SendAbortXferPacket(ulong xferID)
@@ -2335,6 +2364,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2335 OutPacket(sound, ThrottleOutPacketType.Task); 2364 OutPacket(sound, ThrottleOutPacketType.Task);
2336 } 2365 }
2337 2366
2367 public void SendTransferAbort(TransferRequestPacket transferRequest)
2368 {
2369 TransferAbortPacket abort = (TransferAbortPacket)PacketPool.Instance.GetPacket(PacketType.TransferAbort);
2370 abort.TransferInfo.TransferID = transferRequest.TransferInfo.TransferID;
2371 abort.TransferInfo.ChannelType = transferRequest.TransferInfo.ChannelType;
2372 m_log.Debug("[Assets] Aborting transfer; asset request failed");
2373 OutPacket(abort, ThrottleOutPacketType.Task);
2374 }
2375
2338 public void SendTriggeredSound(UUID soundID, UUID ownerID, UUID objectID, UUID parentID, ulong handle, Vector3 position, float gain) 2376 public void SendTriggeredSound(UUID soundID, UUID ownerID, UUID objectID, UUID parentID, ulong handle, Vector3 position, float gain)
2339 { 2377 {
2340 SoundTriggerPacket sound = (SoundTriggerPacket)PacketPool.Instance.GetPacket(PacketType.SoundTrigger); 2378 SoundTriggerPacket sound = (SoundTriggerPacket)PacketPool.Instance.GetPacket(PacketType.SoundTrigger);
@@ -2627,6 +2665,35 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2627 } 2665 }
2628 } 2666 }
2629 2667
2668 public void SendPartPhysicsProprieties(ISceneEntity entity)
2669 {
2670 SceneObjectPart part = (SceneObjectPart)entity;
2671 if (part != null && AgentId != UUID.Zero)
2672 {
2673 try
2674 {
2675 IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>();
2676 if (eq != null)
2677 {
2678 uint localid = part.LocalId;
2679 byte physshapetype = part.PhysicsShapeType;
2680 float density = part.Density;
2681 float friction = part.Friction;
2682 float bounce = part.Bounciness;
2683 float gravmod = part.GravityModifier;
2684
2685 eq.partPhysicsProperties(localid, physshapetype, density, friction, bounce, gravmod,AgentId);
2686 }
2687 }
2688 catch (Exception ex)
2689 {
2690 m_log.Error("Unable to send part Physics Proprieties - exception: " + ex.ToString());
2691 }
2692 part.UpdatePhysRequired = false;
2693 }
2694 }
2695
2696
2630 2697
2631 public void SendGroupNameReply(UUID groupLLUID, string GroupName) 2698 public void SendGroupNameReply(UUID groupLLUID, string GroupName)
2632 { 2699 {
@@ -2685,8 +2752,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2685 req.AssetInf.ID, req.AssetInf.Metadata.ContentType); 2752 req.AssetInf.ID, req.AssetInf.Metadata.ContentType);
2686 return; 2753 return;
2687 } 2754 }
2755 int WearableOut = 0;
2756 bool isWearable = false;
2757
2758 if (req.AssetInf != null)
2759 isWearable =
2760 ((AssetType) req.AssetInf.Type ==
2761 AssetType.Bodypart || (AssetType) req.AssetInf.Type == AssetType.Clothing);
2688 2762
2689 //m_log.Debug("sending asset " + req.RequestAssetID); 2763
2764 //m_log.Debug("sending asset " + req.RequestAssetID + ", iswearable: " + isWearable);
2765
2766
2767 //if (isWearable)
2768 // m_log.Debug((AssetType)req.AssetInf.Type);
2769
2690 TransferInfoPacket Transfer = new TransferInfoPacket(); 2770 TransferInfoPacket Transfer = new TransferInfoPacket();
2691 Transfer.TransferInfo.ChannelType = 2; 2771 Transfer.TransferInfo.ChannelType = 2;
2692 Transfer.TransferInfo.Status = 0; 2772 Transfer.TransferInfo.Status = 0;
@@ -2708,7 +2788,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2708 Transfer.TransferInfo.Size = req.AssetInf.Data.Length; 2788 Transfer.TransferInfo.Size = req.AssetInf.Data.Length;
2709 Transfer.TransferInfo.TransferID = req.TransferRequestID; 2789 Transfer.TransferInfo.TransferID = req.TransferRequestID;
2710 Transfer.Header.Zerocoded = true; 2790 Transfer.Header.Zerocoded = true;
2711 OutPacket(Transfer, ThrottleOutPacketType.Asset); 2791 OutPacket(Transfer, isWearable ? ThrottleOutPacketType.State : ThrottleOutPacketType.Asset);
2712 2792
2713 if (req.NumPackets == 1) 2793 if (req.NumPackets == 1)
2714 { 2794 {
@@ -2719,12 +2799,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2719 TransferPacket.TransferData.Data = req.AssetInf.Data; 2799 TransferPacket.TransferData.Data = req.AssetInf.Data;
2720 TransferPacket.TransferData.Status = 1; 2800 TransferPacket.TransferData.Status = 1;
2721 TransferPacket.Header.Zerocoded = true; 2801 TransferPacket.Header.Zerocoded = true;
2722 OutPacket(TransferPacket, ThrottleOutPacketType.Asset); 2802 OutPacket(TransferPacket, isWearable ? ThrottleOutPacketType.State : ThrottleOutPacketType.Asset);
2723 } 2803 }
2724 else 2804 else
2725 { 2805 {
2726 int processedLength = 0; 2806 int processedLength = 0;
2727 int maxChunkSize = Settings.MAX_PACKET_SIZE - 100; 2807// int maxChunkSize = Settings.MAX_PACKET_SIZE - 100;
2808
2809 int maxChunkSize = (int) MaxTransferBytesPerPacket;
2728 int packetNumber = 0; 2810 int packetNumber = 0;
2729 2811
2730 while (processedLength < req.AssetInf.Data.Length) 2812 while (processedLength < req.AssetInf.Data.Length)
@@ -2750,7 +2832,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2750 TransferPacket.TransferData.Status = 1; 2832 TransferPacket.TransferData.Status = 1;
2751 } 2833 }
2752 TransferPacket.Header.Zerocoded = true; 2834 TransferPacket.Header.Zerocoded = true;
2753 OutPacket(TransferPacket, ThrottleOutPacketType.Asset); 2835 OutPacket(TransferPacket, isWearable ? ThrottleOutPacketType.State : ThrottleOutPacketType.Asset);
2754 2836
2755 processedLength += chunkSize; 2837 processedLength += chunkSize;
2756 packetNumber++; 2838 packetNumber++;
@@ -2795,7 +2877,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2795 reply.Data.ParcelID = parcelID; 2877 reply.Data.ParcelID = parcelID;
2796 reply.Data.OwnerID = land.OwnerID; 2878 reply.Data.OwnerID = land.OwnerID;
2797 reply.Data.Name = Utils.StringToBytes(land.Name); 2879 reply.Data.Name = Utils.StringToBytes(land.Name);
2798 reply.Data.Desc = Utils.StringToBytes(land.Description); 2880 if (land != null && land.Description != null && land.Description != String.Empty)
2881 reply.Data.Desc = Utils.StringToBytes(land.Description.Substring(0, land.Description.Length > 254 ? 254: land.Description.Length));
2882 else
2883 reply.Data.Desc = new Byte[0];
2799 reply.Data.ActualArea = land.Area; 2884 reply.Data.ActualArea = land.Area;
2800 reply.Data.BillableArea = land.Area; // TODO: what is this? 2885 reply.Data.BillableArea = land.Area; // TODO: what is this?
2801 2886
@@ -3502,24 +3587,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3502 aw.WearableData = new AgentWearablesUpdatePacket.WearableDataBlock[count]; 3587 aw.WearableData = new AgentWearablesUpdatePacket.WearableDataBlock[count];
3503 AgentWearablesUpdatePacket.WearableDataBlock awb; 3588 AgentWearablesUpdatePacket.WearableDataBlock awb;
3504 int idx = 0; 3589 int idx = 0;
3505 for (int i = 0; i < wearables.Length; i++) 3590
3506 { 3591 for (int i = 0; i < wearables.Length; i++)
3507 for (int j = 0; j < wearables[i].Count; j++) 3592 {
3508 { 3593 for (int j = 0; j < wearables[i].Count; j++)
3509 awb = new AgentWearablesUpdatePacket.WearableDataBlock(); 3594 {
3510 awb.WearableType = (byte)i; 3595 awb = new AgentWearablesUpdatePacket.WearableDataBlock();
3511 awb.AssetID = wearables[i][j].AssetID; 3596 awb.WearableType = (byte) i;
3512 awb.ItemID = wearables[i][j].ItemID; 3597 awb.AssetID = wearables[i][j].AssetID;
3513 aw.WearableData[idx] = awb; 3598 awb.ItemID = wearables[i][j].ItemID;
3514 idx++; 3599 aw.WearableData[idx] = awb;
3515 3600 idx++;
3516// m_log.DebugFormat( 3601
3517// "[APPEARANCE]: Sending wearable item/asset {0} {1} (index {2}) for {3}", 3602 // m_log.DebugFormat(
3518// awb.ItemID, awb.AssetID, i, Name); 3603 // "[APPEARANCE]: Sending wearable item/asset {0} {1} (index {2}) for {3}",
3519 } 3604 // awb.ItemID, awb.AssetID, i, Name);
3520 } 3605 }
3606 }
3521 3607
3522 OutPacket(aw, ThrottleOutPacketType.Task); 3608 OutPacket(aw, ThrottleOutPacketType.State);
3523 } 3609 }
3524 3610
3525 public void SendAppearance(UUID agentID, byte[] visualParams, byte[] textureEntry) 3611 public void SendAppearance(UUID agentID, byte[] visualParams, byte[] textureEntry)
@@ -3530,7 +3616,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3530 3616
3531 AvatarAppearancePacket avp = (AvatarAppearancePacket)PacketPool.Instance.GetPacket(PacketType.AvatarAppearance); 3617 AvatarAppearancePacket avp = (AvatarAppearancePacket)PacketPool.Instance.GetPacket(PacketType.AvatarAppearance);
3532 // TODO: don't create new blocks if recycling an old packet 3618 // TODO: don't create new blocks if recycling an old packet
3533 avp.VisualParam = new AvatarAppearancePacket.VisualParamBlock[218]; 3619 avp.VisualParam = new AvatarAppearancePacket.VisualParamBlock[visualParams.Length];
3534 avp.ObjectData.TextureEntry = textureEntry; 3620 avp.ObjectData.TextureEntry = textureEntry;
3535 3621
3536 AvatarAppearancePacket.VisualParamBlock avblock = null; 3622 AvatarAppearancePacket.VisualParamBlock avblock = null;
@@ -3543,8 +3629,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3543 3629
3544 avp.Sender.IsTrial = false; 3630 avp.Sender.IsTrial = false;
3545 avp.Sender.ID = agentID; 3631 avp.Sender.ID = agentID;
3546 //m_log.DebugFormat("[CLIENT]: Sending appearance for {0} to {1}", agentID.ToString(), AgentId.ToString()); 3632 m_log.DebugFormat("[CLIENT]: Sending appearance for {0} to {1}", agentID.ToString(), AgentId.ToString());
3547 OutPacket(avp, ThrottleOutPacketType.Task); 3633 OutPacket(avp, ThrottleOutPacketType.State);
3548 } 3634 }
3549 3635
3550 public void SendAnimations(UUID[] animations, int[] seqs, UUID sourceAgentId, UUID[] objectIDs) 3636 public void SendAnimations(UUID[] animations, int[] seqs, UUID sourceAgentId, UUID[] objectIDs)
@@ -3660,7 +3746,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3660 /// </summary> 3746 /// </summary>
3661 public void SendEntityUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags) 3747 public void SendEntityUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags)
3662 { 3748 {
3663 //double priority = m_prioritizer.GetUpdatePriority(this, entity); 3749 if (entity is SceneObjectPart)
3750 {
3751 SceneObjectPart e = (SceneObjectPart)entity;
3752 SceneObjectGroup g = e.ParentGroup;
3753 if (g.RootPart.Shape.State > 30) // HUD
3754 if (g.OwnerID != AgentId)
3755 return; // Don't send updates for other people's HUDs
3756 }
3757
3664 uint priority = m_prioritizer.GetUpdatePriority(this, entity); 3758 uint priority = m_prioritizer.GetUpdatePriority(this, entity);
3665 3759
3666 lock (m_entityUpdates.SyncRoot) 3760 lock (m_entityUpdates.SyncRoot)
@@ -3727,27 +3821,74 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3727 3821
3728 // We must lock for both manipulating the kill record and sending the packet, in order to avoid a race 3822 // We must lock for both manipulating the kill record and sending the packet, in order to avoid a race
3729 // condition where a kill can be processed before an out-of-date update for the same object. 3823 // condition where a kill can be processed before an out-of-date update for the same object.
3730 lock (m_killRecord) 3824 float avgTimeDilation = 1.0f;
3825 IEntityUpdate iupdate;
3826 Int32 timeinqueue; // this is just debugging code & can be dropped later
3827
3828 while (updatesThisCall < maxUpdates)
3731 { 3829 {
3732 float avgTimeDilation = 1.0f; 3830 lock (m_entityUpdates.SyncRoot)
3733 IEntityUpdate iupdate; 3831 if (!m_entityUpdates.TryDequeue(out iupdate, out timeinqueue))
3734 Int32 timeinqueue; // this is just debugging code & can be dropped later 3832 break;
3833
3834 EntityUpdate update = (EntityUpdate)iupdate;
3835
3836 avgTimeDilation += update.TimeDilation;
3837 avgTimeDilation *= 0.5f;
3735 3838
3736 while (updatesThisCall < maxUpdates) 3839 if (update.Entity is SceneObjectPart)
3737 { 3840 {
3738 lock (m_entityUpdates.SyncRoot) 3841 SceneObjectPart part = (SceneObjectPart)update.Entity;
3739 if (!m_entityUpdates.TryDequeue(out iupdate, out timeinqueue))
3740 break;
3741 3842
3742 EntityUpdate update = (EntityUpdate)iupdate; 3843 if (part.ParentGroup.IsDeleted)
3743 3844 continue;
3744 avgTimeDilation += update.TimeDilation;
3745 avgTimeDilation *= 0.5f;
3746 3845
3747 if (update.Entity is SceneObjectPart) 3846 if (part.ParentGroup.IsAttachment)
3847 { // Someone else's HUD, why are we getting these?
3848 if (part.ParentGroup.OwnerID != AgentId &&
3849 part.ParentGroup.RootPart.Shape.State > 30)
3850 continue;
3851 ScenePresence sp;
3852 // Owner is not in the sim, don't update it to
3853 // anyone
3854 if (!m_scene.TryGetScenePresence(part.OwnerID, out sp))
3855 continue;
3856
3857 List<SceneObjectGroup> atts = sp.GetAttachments();
3858 bool found = false;
3859 foreach (SceneObjectGroup att in atts)
3860 {
3861 if (att == part.ParentGroup)
3862 {
3863 found = true;
3864 break;
3865 }
3866 }
3867
3868 // It's an attachment of a valid avatar, but
3869 // doesn't seem to be attached, skip
3870 if (!found)
3871 continue;
3872
3873 // On vehicle crossing, the attachments are received
3874 // while the avatar is still a child. Don't send
3875 // updates here because the LocalId has not yet
3876 // been updated and the viewer will derender the
3877 // attachments until the avatar becomes root.
3878 if (sp.IsChildAgent)
3879 continue;
3880
3881 // If the object is an attachment we don't want it to be in the kill
3882 // record. Else attaching from inworld and subsequently dropping
3883 // it will no longer work.
3884// lock (m_killRecord)
3885// {
3886// m_killRecord.Remove(part.LocalId);
3887// m_killRecord.Remove(part.ParentGroup.RootPart.LocalId);
3888// }
3889 }
3890 else
3748 { 3891 {
3749 SceneObjectPart part = (SceneObjectPart)update.Entity;
3750
3751 // Please do not remove this unless you can demonstrate on the OpenSim mailing list that a client 3892 // Please do not remove this unless you can demonstrate on the OpenSim mailing list that a client
3752 // will never receive an update after a prim kill. Even then, keeping the kill record may be a good 3893 // will never receive an update after a prim kill. Even then, keeping the kill record may be a good
3753 // safety measure. 3894 // safety measure.
@@ -3758,241 +3899,177 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3758 // 3899 //
3759 // This doesn't appear to apply to child prims - a client will happily ignore these updates 3900 // This doesn't appear to apply to child prims - a client will happily ignore these updates
3760 // after the root prim has been deleted. 3901 // after the root prim has been deleted.
3761 if (m_killRecord.Contains(part.LocalId)) 3902 //
3762 { 3903 // We ignore this for attachments because attaching something from inworld breaks unless we do.
3763 // m_log.WarnFormat( 3904// lock (m_killRecord)
3764 // "[CLIENT]: Preventing update for prim with local id {0} after client for user {1} told it was deleted", 3905// {
3765 // part.LocalId, Name); 3906// if (m_killRecord.Contains(part.LocalId))
3766 continue; 3907// continue;
3767 } 3908// if (m_killRecord.Contains(part.ParentGroup.RootPart.LocalId))
3768 3909// continue;
3769 if (part.ParentGroup.IsAttachment && m_disableFacelights) 3910// }
3911 }
3912
3913 if (part.ParentGroup.IsAttachment && m_disableFacelights)
3914 {
3915 if (part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand &&
3916 part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.RightHand)
3770 { 3917 {
3771 if (part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand && 3918 part.Shape.LightEntry = false;
3772 part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.RightHand)
3773 {
3774 part.Shape.LightEntry = false;
3775 }
3776 } 3919 }
3777 } 3920 }
3778 3921 }
3779 #region UpdateFlags to packet type conversion 3922
3780 3923 ++updatesThisCall;
3781 PrimUpdateFlags updateFlags = (PrimUpdateFlags)update.Flags; 3924
3782 3925 #region UpdateFlags to packet type conversion
3783 bool canUseCompressed = true; 3926
3784 bool canUseImproved = true; 3927 PrimUpdateFlags updateFlags = (PrimUpdateFlags)update.Flags;
3785 3928
3786 // Compressed object updates only make sense for LL primitives 3929 bool canUseCompressed = true;
3787 if (!(update.Entity is SceneObjectPart)) 3930 bool canUseImproved = true;
3931
3932 // Compressed object updates only make sense for LL primitives
3933 if (!(update.Entity is SceneObjectPart))
3934 {
3935 canUseCompressed = false;
3936 }
3937
3938 if (updateFlags.HasFlag(PrimUpdateFlags.FullUpdate))
3939 {
3940 canUseCompressed = false;
3941 canUseImproved = false;
3942 }
3943 else
3944 {
3945 if (updateFlags.HasFlag(PrimUpdateFlags.Velocity) ||
3946 updateFlags.HasFlag(PrimUpdateFlags.Acceleration) ||
3947 updateFlags.HasFlag(PrimUpdateFlags.CollisionPlane) ||
3948 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3788 { 3949 {
3789 canUseCompressed = false; 3950 canUseCompressed = false;
3790 } 3951 }
3791 3952
3792 if (updateFlags.HasFlag(PrimUpdateFlags.FullUpdate)) 3953 if (updateFlags.HasFlag(PrimUpdateFlags.PrimFlags) ||
3954 updateFlags.HasFlag(PrimUpdateFlags.ParentID) ||
3955 updateFlags.HasFlag(PrimUpdateFlags.Scale) ||
3956 updateFlags.HasFlag(PrimUpdateFlags.PrimData) ||
3957 updateFlags.HasFlag(PrimUpdateFlags.Text) ||
3958 updateFlags.HasFlag(PrimUpdateFlags.NameValue) ||
3959 updateFlags.HasFlag(PrimUpdateFlags.ExtraData) ||
3960 updateFlags.HasFlag(PrimUpdateFlags.TextureAnim) ||
3961 updateFlags.HasFlag(PrimUpdateFlags.Sound) ||
3962 updateFlags.HasFlag(PrimUpdateFlags.Particles) ||
3963 updateFlags.HasFlag(PrimUpdateFlags.Material) ||
3964 updateFlags.HasFlag(PrimUpdateFlags.ClickAction) ||
3965 updateFlags.HasFlag(PrimUpdateFlags.MediaURL) ||
3966 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3793 { 3967 {
3794 canUseCompressed = false;
3795 canUseImproved = false; 3968 canUseImproved = false;
3796 } 3969 }
3797 else 3970 }
3798 {
3799 if (updateFlags.HasFlag(PrimUpdateFlags.Velocity) ||
3800 updateFlags.HasFlag(PrimUpdateFlags.Acceleration) ||
3801 updateFlags.HasFlag(PrimUpdateFlags.CollisionPlane) ||
3802 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3803 {
3804 canUseCompressed = false;
3805 }
3806
3807 if (updateFlags.HasFlag(PrimUpdateFlags.PrimFlags) ||
3808 updateFlags.HasFlag(PrimUpdateFlags.ParentID) ||
3809 updateFlags.HasFlag(PrimUpdateFlags.Scale) ||
3810 updateFlags.HasFlag(PrimUpdateFlags.PrimData) ||
3811 updateFlags.HasFlag(PrimUpdateFlags.Text) ||
3812 updateFlags.HasFlag(PrimUpdateFlags.NameValue) ||
3813 updateFlags.HasFlag(PrimUpdateFlags.ExtraData) ||
3814 updateFlags.HasFlag(PrimUpdateFlags.TextureAnim) ||
3815 updateFlags.HasFlag(PrimUpdateFlags.Sound) ||
3816 updateFlags.HasFlag(PrimUpdateFlags.Particles) ||
3817 updateFlags.HasFlag(PrimUpdateFlags.Material) ||
3818 updateFlags.HasFlag(PrimUpdateFlags.ClickAction) ||
3819 updateFlags.HasFlag(PrimUpdateFlags.MediaURL) ||
3820 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3821 {
3822 canUseImproved = false;
3823 }
3824 }
3825
3826 #endregion UpdateFlags to packet type conversion
3827
3828 #region Block Construction
3829
3830 // TODO: Remove this once we can build compressed updates
3831 canUseCompressed = false;
3832 3971
3833 if (!canUseImproved && !canUseCompressed) 3972 #endregion UpdateFlags to packet type conversion
3834 {
3835 ObjectUpdatePacket.ObjectDataBlock updateBlock;
3836 3973
3837 if (update.Entity is ScenePresence) 3974 #region Block Construction
3838 {
3839 updateBlock = CreateAvatarUpdateBlock((ScenePresence)update.Entity);
3840 }
3841 else
3842 {
3843 SceneObjectPart part = (SceneObjectPart)update.Entity;
3844 updateBlock = CreatePrimUpdateBlock(part, AgentId);
3845
3846 // If the part has become a private hud since the update was scheduled then we do not
3847 // want to send it to other avatars.
3848 if (part.ParentGroup.IsAttachment
3849 && part.ParentGroup.HasPrivateAttachmentPoint
3850 && part.ParentGroup.AttachedAvatar != AgentId)
3851 continue;
3852
3853 // If the part has since been deleted, then drop the update. In the case of attachments,
3854 // this is to avoid spurious updates to other viewers since post-processing of attachments
3855 // has to change the IsAttachment flag for various reasons (which will end up in a pass
3856 // of the test above).
3857 //
3858 // Actual deletions (kills) happen in another method.
3859 if (part.ParentGroup.IsDeleted)
3860 continue;
3861 }
3862 3975
3863 objectUpdateBlocks.Value.Add(updateBlock); 3976 // TODO: Remove this once we can build compressed updates
3864 objectUpdates.Value.Add(update); 3977 canUseCompressed = false;
3865 }
3866 else if (!canUseImproved)
3867 {
3868 SceneObjectPart part = (SceneObjectPart)update.Entity;
3869 ObjectUpdateCompressedPacket.ObjectDataBlock compressedBlock
3870 = CreateCompressedUpdateBlock(part, updateFlags);
3871
3872 // If the part has since been deleted, then drop the update. In the case of attachments,
3873 // this is to avoid spurious updates to other viewers since post-processing of attachments
3874 // has to change the IsAttachment flag for various reasons (which will end up in a pass
3875 // of the test above).
3876 //
3877 // Actual deletions (kills) happen in another method.
3878 if (part.ParentGroup.IsDeleted)
3879 continue;
3880 3978
3881 compressedUpdateBlocks.Value.Add(compressedBlock); 3979 if (!canUseImproved && !canUseCompressed)
3882 compressedUpdates.Value.Add(update); 3980 {
3981 if (update.Entity is ScenePresence)
3982 {
3983 objectUpdateBlocks.Value.Add(CreateAvatarUpdateBlock((ScenePresence)update.Entity));
3883 } 3984 }
3884 else 3985 else
3885 { 3986 {
3886 if (update.Entity is ScenePresence && ((ScenePresence)update.Entity).UUID == AgentId) 3987 objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId));
3887 {
3888 // Self updates go into a special list
3889 terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
3890 terseAgentUpdates.Value.Add(update);
3891 }
3892 else
3893 {
3894 ImprovedTerseObjectUpdatePacket.ObjectDataBlock terseUpdateBlock
3895 = CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures));
3896
3897 // Everything else goes here
3898 if (update.Entity is SceneObjectPart)
3899 {
3900 SceneObjectPart part = (SceneObjectPart)update.Entity;
3901
3902 // If the part has become a private hud since the update was scheduled then we do not
3903 // want to send it to other avatars.
3904 if (part.ParentGroup.IsAttachment
3905 && part.ParentGroup.HasPrivateAttachmentPoint
3906 && part.ParentGroup.AttachedAvatar != AgentId)
3907 continue;
3908
3909 // If the part has since been deleted, then drop the update. In the case of attachments,
3910 // this is to avoid spurious updates to other viewers since post-processing of attachments
3911 // has to change the IsAttachment flag for various reasons (which will end up in a pass
3912 // of the test above).
3913 //
3914 // Actual deletions (kills) happen in another method.
3915 if (part.ParentGroup.IsDeleted)
3916 continue;
3917 }
3918
3919 terseUpdateBlocks.Value.Add(terseUpdateBlock);
3920 terseUpdates.Value.Add(update);
3921 }
3922 } 3988 }
3923
3924 ++updatesThisCall;
3925
3926 #endregion Block Construction
3927 } 3989 }
3928 3990 else if (!canUseImproved)
3929 #region Packet Sending
3930 ushort timeDilation = Utils.FloatToUInt16(avgTimeDilation, 0.0f, 1.0f);
3931
3932 if (terseAgentUpdateBlocks.IsValueCreated)
3933 { 3991 {
3934 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value; 3992 compressedUpdateBlocks.Value.Add(CreateCompressedUpdateBlock((SceneObjectPart)update.Entity, updateFlags));
3993 }
3994 else
3995 {
3996 if (update.Entity is ScenePresence && ((ScenePresence)update.Entity).UUID == AgentId)
3997 // Self updates go into a special list
3998 terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
3999 else
4000 // Everything else goes here
4001 terseUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
4002 }
3935 4003
3936 ImprovedTerseObjectUpdatePacket packet 4004 #endregion Block Construction
3937 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate); 4005 }
3938 4006
3939 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 4007 #region Packet Sending
3940 packet.RegionData.TimeDilation = timeDilation; 4008
3941 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; 4009 const float TIME_DILATION = 1.0f;
4010 ushort timeDilation = Utils.FloatToUInt16(avgTimeDilation, 0.0f, 1.0f);
4011
4012 if (terseAgentUpdateBlocks.IsValueCreated)
4013 {
4014 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value;
3942 4015
3943 for (int i = 0; i < blocks.Count; i++) 4016 ImprovedTerseObjectUpdatePacket packet
3944 packet.ObjectData[i] = blocks[i]; 4017 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate);
3945 // If any of the packets created from this call go unacknowledged, all of the updates will be resent 4018 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3946 OutPacket(packet, ThrottleOutPacketType.Unknown, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseAgentUpdates.Value, oPacket); }); 4019 packet.RegionData.TimeDilation = timeDilation;
3947 } 4020 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
3948 4021
3949 if (objectUpdateBlocks.IsValueCreated) 4022 for (int i = 0; i < blocks.Count; i++)
3950 { 4023 packet.ObjectData[i] = blocks[i];
3951 List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value;
3952
3953 ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate);
3954 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3955 packet.RegionData.TimeDilation = timeDilation;
3956 packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[blocks.Count];
3957
3958 for (int i = 0; i < blocks.Count; i++)
3959 packet.ObjectData[i] = blocks[i];
3960 // If any of the packets created from this call go unacknowledged, all of the updates will be resent
3961 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(objectUpdates.Value, oPacket); });
3962 }
3963
3964 if (compressedUpdateBlocks.IsValueCreated)
3965 {
3966 List<ObjectUpdateCompressedPacket.ObjectDataBlock> blocks = compressedUpdateBlocks.Value;
3967
3968 ObjectUpdateCompressedPacket packet = (ObjectUpdateCompressedPacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdateCompressed);
3969 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3970 packet.RegionData.TimeDilation = timeDilation;
3971 packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[blocks.Count];
3972
3973 for (int i = 0; i < blocks.Count; i++)
3974 packet.ObjectData[i] = blocks[i];
3975 // If any of the packets created from this call go unacknowledged, all of the updates will be resent
3976 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(compressedUpdates.Value, oPacket); });
3977 }
3978 4024
3979 if (terseUpdateBlocks.IsValueCreated) 4025 OutPacket(packet, ThrottleOutPacketType.Unknown, true);
3980 { 4026 }
3981 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;
3982
3983 ImprovedTerseObjectUpdatePacket packet
3984 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
3985 PacketType.ImprovedTerseObjectUpdate);
3986 4027
3987 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 4028 if (objectUpdateBlocks.IsValueCreated)
3988 packet.RegionData.TimeDilation = timeDilation; 4029 {
3989 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; 4030 List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value;
3990 4031
3991 for (int i = 0; i < blocks.Count; i++) 4032 ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate);
3992 packet.ObjectData[i] = blocks[i]; 4033 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3993 // If any of the packets created from this call go unacknowledged, all of the updates will be resent 4034 packet.RegionData.TimeDilation = timeDilation;
3994 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseUpdates.Value, oPacket); }); 4035 packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[blocks.Count];
3995 } 4036
4037 for (int i = 0; i < blocks.Count; i++)
4038 packet.ObjectData[i] = blocks[i];
4039
4040 OutPacket(packet, ThrottleOutPacketType.Task, true);
4041 }
4042
4043 if (compressedUpdateBlocks.IsValueCreated)
4044 {
4045 List<ObjectUpdateCompressedPacket.ObjectDataBlock> blocks = compressedUpdateBlocks.Value;
4046
4047 ObjectUpdateCompressedPacket packet = (ObjectUpdateCompressedPacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdateCompressed);
4048 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4049 packet.RegionData.TimeDilation = timeDilation;
4050 packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[blocks.Count];
4051
4052 for (int i = 0; i < blocks.Count; i++)
4053 packet.ObjectData[i] = blocks[i];
4054
4055 OutPacket(packet, ThrottleOutPacketType.Task, true);
4056 }
4057
4058 if (terseUpdateBlocks.IsValueCreated)
4059 {
4060 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;
4061
4062 ImprovedTerseObjectUpdatePacket packet
4063 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
4064 PacketType.ImprovedTerseObjectUpdate);
4065 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4066 packet.RegionData.TimeDilation = timeDilation;
4067 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
4068
4069 for (int i = 0; i < blocks.Count; i++)
4070 packet.ObjectData[i] = blocks[i];
4071
4072 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseUpdates.Value, oPacket); });
3996 } 4073 }
3997 4074
3998 #endregion Packet Sending 4075 #endregion Packet Sending
@@ -4285,11 +4362,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4285 4362
4286 // Pass in the delegate so that if this packet needs to be resent, we send the current properties 4363 // Pass in the delegate so that if this packet needs to be resent, we send the current properties
4287 // of the object rather than the properties when the packet was created 4364 // of the object rather than the properties when the packet was created
4288 OutPacket(packet, ThrottleOutPacketType.Task, true, 4365 // HACK : Remove intelligent resending until it's fixed in core
4289 delegate(OutgoingPacket oPacket) 4366 //OutPacket(packet, ThrottleOutPacketType.Task, true,
4290 { 4367 // delegate(OutgoingPacket oPacket)
4291 ResendPropertyUpdates(updates, oPacket); 4368 // {
4292 }); 4369 // ResendPropertyUpdates(updates, oPacket);
4370 // });
4371 OutPacket(packet, ThrottleOutPacketType.Task, true);
4293 4372
4294 // pbcnt += blocks.Count; 4373 // pbcnt += blocks.Count;
4295 // ppcnt++; 4374 // ppcnt++;
@@ -4315,11 +4394,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4315 // of the object rather than the properties when the packet was created 4394 // of the object rather than the properties when the packet was created
4316 List<ObjectPropertyUpdate> updates = new List<ObjectPropertyUpdate>(); 4395 List<ObjectPropertyUpdate> updates = new List<ObjectPropertyUpdate>();
4317 updates.Add(familyUpdates.Value[i]); 4396 updates.Add(familyUpdates.Value[i]);
4318 OutPacket(packet, ThrottleOutPacketType.Task, true, 4397 // HACK : Remove intelligent resending until it's fixed in core
4319 delegate(OutgoingPacket oPacket) 4398 //OutPacket(packet, ThrottleOutPacketType.Task, true,
4320 { 4399 // delegate(OutgoingPacket oPacket)
4321 ResendPropertyUpdates(updates, oPacket); 4400 // {
4322 }); 4401 // ResendPropertyUpdates(updates, oPacket);
4402 // });
4403 OutPacket(packet, ThrottleOutPacketType.Task, true);
4323 4404
4324 // fpcnt++; 4405 // fpcnt++;
4325 // fbcnt++; 4406 // fbcnt++;
@@ -4691,7 +4772,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4691 4772
4692 if (landData.SimwideArea > 0) 4773 if (landData.SimwideArea > 0)
4693 { 4774 {
4694 int simulatorCapacity = (int)(((float)landData.SimwideArea / 65536.0f) * (float)m_scene.RegionInfo.ObjectCapacity * (float)m_scene.RegionInfo.RegionSettings.ObjectBonus); 4775 int simulatorCapacity = (int)((long)landData.SimwideArea * (long)m_scene.RegionInfo.ObjectCapacity * (long)m_scene.RegionInfo.RegionSettings.ObjectBonus / 65536L);
4776 // Never report more than sim total capacity
4777 if (simulatorCapacity > m_scene.RegionInfo.ObjectCapacity)
4778 simulatorCapacity = m_scene.RegionInfo.ObjectCapacity;
4695 updateMessage.SimWideMaxPrims = simulatorCapacity; 4779 updateMessage.SimWideMaxPrims = simulatorCapacity;
4696 } 4780 }
4697 else 4781 else
@@ -4820,14 +4904,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4820 4904
4821 if (notifyCount > 0) 4905 if (notifyCount > 0)
4822 { 4906 {
4823 if (notifyCount > 32) 4907// if (notifyCount > 32)
4824 { 4908// {
4825 m_log.InfoFormat( 4909// m_log.InfoFormat(
4826 "[LAND]: More than {0} avatars own prims on this parcel. Only sending back details of first {0}" 4910// "[LAND]: More than {0} avatars own prims on this parcel. Only sending back details of first {0}"
4827 + " - a developer might want to investigate whether this is a hard limit", 32); 4911// + " - a developer might want to investigate whether this is a hard limit", 32);
4828 4912//
4829 notifyCount = 32; 4913// notifyCount = 32;
4830 } 4914// }
4831 4915
4832 ParcelObjectOwnersReplyPacket.DataBlock[] dataBlock 4916 ParcelObjectOwnersReplyPacket.DataBlock[] dataBlock
4833 = new ParcelObjectOwnersReplyPacket.DataBlock[notifyCount]; 4917 = new ParcelObjectOwnersReplyPacket.DataBlock[notifyCount];
@@ -4882,9 +4966,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4882 { 4966 {
4883 ScenePresence presence = (ScenePresence)entity; 4967 ScenePresence presence = (ScenePresence)entity;
4884 4968
4969 position = presence.OffsetPosition;
4970 rotation = presence.Rotation;
4971
4972 if (presence.ParentID != 0)
4973 {
4974 SceneObjectPart part = m_scene.GetSceneObjectPart(presence.ParentID);
4975 if (part != null && part != part.ParentGroup.RootPart)
4976 {
4977 position = part.OffsetPosition + presence.OffsetPosition * part.RotationOffset;
4978 rotation = part.RotationOffset * presence.Rotation;
4979 }
4980 }
4981
4885 attachPoint = 0; 4982 attachPoint = 0;
4886 collisionPlane = presence.CollisionPlane; 4983 collisionPlane = presence.CollisionPlane;
4887 position = presence.OffsetPosition;
4888 velocity = presence.Velocity; 4984 velocity = presence.Velocity;
4889 acceleration = Vector3.Zero; 4985 acceleration = Vector3.Zero;
4890 4986
@@ -4892,9 +4988,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4892 // in that direction, even though we don't model this on the server. Implementing this in the future 4988 // in that direction, even though we don't model this on the server. Implementing this in the future
4893 // may improve movement smoothness. 4989 // may improve movement smoothness.
4894// acceleration = new Vector3(1, 0, 0); 4990// acceleration = new Vector3(1, 0, 0);
4895 4991
4896 angularVelocity = Vector3.Zero; 4992 angularVelocity = Vector3.Zero;
4897 rotation = presence.Rotation;
4898 4993
4899 if (sendTexture) 4994 if (sendTexture)
4900 textureEntry = presence.Appearance.Texture.GetBytes(); 4995 textureEntry = presence.Appearance.Texture.GetBytes();
@@ -5001,13 +5096,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5001 5096
5002 protected ObjectUpdatePacket.ObjectDataBlock CreateAvatarUpdateBlock(ScenePresence data) 5097 protected ObjectUpdatePacket.ObjectDataBlock CreateAvatarUpdateBlock(ScenePresence data)
5003 { 5098 {
5099 Vector3 offsetPosition = data.OffsetPosition;
5100 Quaternion rotation = data.Rotation;
5101 uint parentID = data.ParentID;
5102
5103 if (parentID != 0)
5104 {
5105 SceneObjectPart part = m_scene.GetSceneObjectPart(parentID);
5106 if (part != null && part != part.ParentGroup.RootPart)
5107 {
5108 offsetPosition = part.OffsetPosition + data.OffsetPosition * part.RotationOffset;
5109 rotation = part.RotationOffset * data.Rotation;
5110 parentID = part.ParentGroup.RootPart.LocalId;
5111 }
5112 }
5113
5004 byte[] objectData = new byte[76]; 5114 byte[] objectData = new byte[76];
5005 5115
5006 data.CollisionPlane.ToBytes(objectData, 0); 5116 data.CollisionPlane.ToBytes(objectData, 0);
5007 data.OffsetPosition.ToBytes(objectData, 16); 5117 offsetPosition.ToBytes(objectData, 16);
5008// data.Velocity.ToBytes(objectData, 28); 5118// data.Velocity.ToBytes(objectData, 28);
5009// data.Acceleration.ToBytes(objectData, 40); 5119// data.Acceleration.ToBytes(objectData, 40);
5010 data.Rotation.ToBytes(objectData, 52); 5120 rotation.ToBytes(objectData, 52);
5011 //data.AngularVelocity.ToBytes(objectData, 64); 5121 //data.AngularVelocity.ToBytes(objectData, 64);
5012 5122
5013 ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock(); 5123 ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock();
@@ -5021,14 +5131,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5021 update.NameValue = Utils.StringToBytes("FirstName STRING RW SV " + data.Firstname + "\nLastName STRING RW SV " + 5131 update.NameValue = Utils.StringToBytes("FirstName STRING RW SV " + data.Firstname + "\nLastName STRING RW SV " +
5022 data.Lastname + "\nTitle STRING RW SV " + data.Grouptitle); 5132 data.Lastname + "\nTitle STRING RW SV " + data.Grouptitle);
5023 update.ObjectData = objectData; 5133 update.ObjectData = objectData;
5024 update.ParentID = data.ParentID; 5134 update.ParentID = parentID;
5025 update.PathCurve = 16; 5135 update.PathCurve = 16;
5026 update.PathScaleX = 100; 5136 update.PathScaleX = 100;
5027 update.PathScaleY = 100; 5137 update.PathScaleY = 100;
5028 update.PCode = (byte)PCode.Avatar; 5138 update.PCode = (byte)PCode.Avatar;
5029 update.ProfileCurve = 1; 5139 update.ProfileCurve = 1;
5030 update.PSBlock = Utils.EmptyBytes; 5140 update.PSBlock = Utils.EmptyBytes;
5031 update.Scale = new Vector3(0.45f, 0.6f, 1.9f); 5141 update.Scale = data.Appearance.AvatarSize;
5142// update.Scale.Z -= 0.2f;
5143
5032 update.Text = Utils.EmptyBytes; 5144 update.Text = Utils.EmptyBytes;
5033 update.TextColor = new byte[4]; 5145 update.TextColor = new byte[4];
5034 5146
@@ -5039,10 +5151,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5039 update.TextureEntry = Utils.EmptyBytes; 5151 update.TextureEntry = Utils.EmptyBytes;
5040// update.TextureEntry = (data.Appearance.Texture != null) ? data.Appearance.Texture.GetBytes() : Utils.EmptyBytes; 5152// update.TextureEntry = (data.Appearance.Texture != null) ? data.Appearance.Texture.GetBytes() : Utils.EmptyBytes;
5041 5153
5154/* all this flags seem related to prims and not avatars. This allow for wrong viewer side move of a avatar in prim edition mode (anv mantis 854)
5042 update.UpdateFlags = (uint)( 5155 update.UpdateFlags = (uint)(
5043 PrimFlags.Physics | PrimFlags.ObjectModify | PrimFlags.ObjectCopy | PrimFlags.ObjectAnyOwner | 5156 PrimFlags.Physics | PrimFlags.ObjectModify | PrimFlags.ObjectCopy | PrimFlags.ObjectAnyOwner |
5044 PrimFlags.ObjectYouOwner | PrimFlags.ObjectMove | PrimFlags.InventoryEmpty | PrimFlags.ObjectTransfer | 5157 PrimFlags.ObjectYouOwner | PrimFlags.ObjectMove | PrimFlags.InventoryEmpty | PrimFlags.ObjectTransfer |
5045 PrimFlags.ObjectOwnerModify); 5158 PrimFlags.ObjectOwnerModify);
5159*/
5160 update.UpdateFlags = 0;
5046 5161
5047 return update; 5162 return update;
5048 } 5163 }
@@ -5213,8 +5328,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5213 // If AgentUpdate is ever handled asynchronously, then we will also need to construct a new AgentUpdateArgs 5328 // If AgentUpdate is ever handled asynchronously, then we will also need to construct a new AgentUpdateArgs
5214 // for each AgentUpdate packet. 5329 // for each AgentUpdate packet.
5215 AddLocalPacketHandler(PacketType.AgentUpdate, HandleAgentUpdate, false); 5330 AddLocalPacketHandler(PacketType.AgentUpdate, HandleAgentUpdate, false);
5216 5331
5217 AddLocalPacketHandler(PacketType.ViewerEffect, HandleViewerEffect, false); 5332 AddLocalPacketHandler(PacketType.ViewerEffect, HandleViewerEffect, false);
5333 AddLocalPacketHandler(PacketType.VelocityInterpolateOff, HandleVelocityInterpolateOff, false);
5334 AddLocalPacketHandler(PacketType.VelocityInterpolateOn, HandleVelocityInterpolateOn, false);
5218 AddLocalPacketHandler(PacketType.AgentCachedTexture, HandleAgentTextureCached, false); 5335 AddLocalPacketHandler(PacketType.AgentCachedTexture, HandleAgentTextureCached, false);
5219 AddLocalPacketHandler(PacketType.MultipleObjectUpdate, HandleMultipleObjUpdate, false); 5336 AddLocalPacketHandler(PacketType.MultipleObjectUpdate, HandleMultipleObjUpdate, false);
5220 AddLocalPacketHandler(PacketType.MoneyTransferRequest, HandleMoneyTransferRequest, false); 5337 AddLocalPacketHandler(PacketType.MoneyTransferRequest, HandleMoneyTransferRequest, false);
@@ -5366,6 +5483,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5366 AddLocalPacketHandler(PacketType.TransferAbort, HandleTransferAbort, false); 5483 AddLocalPacketHandler(PacketType.TransferAbort, HandleTransferAbort, false);
5367 AddLocalPacketHandler(PacketType.MuteListRequest, HandleMuteListRequest, false); 5484 AddLocalPacketHandler(PacketType.MuteListRequest, HandleMuteListRequest, false);
5368 AddLocalPacketHandler(PacketType.UseCircuitCode, HandleUseCircuitCode); 5485 AddLocalPacketHandler(PacketType.UseCircuitCode, HandleUseCircuitCode);
5486 AddLocalPacketHandler(PacketType.CreateNewOutfitAttachments, HandleCreateNewOutfitAttachments);
5369 AddLocalPacketHandler(PacketType.AgentHeightWidth, HandleAgentHeightWidth, false); 5487 AddLocalPacketHandler(PacketType.AgentHeightWidth, HandleAgentHeightWidth, false);
5370 AddLocalPacketHandler(PacketType.InventoryDescendents, HandleInventoryDescendents); 5488 AddLocalPacketHandler(PacketType.InventoryDescendents, HandleInventoryDescendents);
5371 AddLocalPacketHandler(PacketType.DirPlacesQuery, HandleDirPlacesQuery); 5489 AddLocalPacketHandler(PacketType.DirPlacesQuery, HandleDirPlacesQuery);
@@ -5432,6 +5550,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5432 AddLocalPacketHandler(PacketType.GroupVoteHistoryRequest, HandleGroupVoteHistoryRequest); 5550 AddLocalPacketHandler(PacketType.GroupVoteHistoryRequest, HandleGroupVoteHistoryRequest);
5433 AddLocalPacketHandler(PacketType.SimWideDeletes, HandleSimWideDeletes); 5551 AddLocalPacketHandler(PacketType.SimWideDeletes, HandleSimWideDeletes);
5434 AddLocalPacketHandler(PacketType.SendPostcard, HandleSendPostcard); 5552 AddLocalPacketHandler(PacketType.SendPostcard, HandleSendPostcard);
5553 AddLocalPacketHandler(PacketType.ChangeInventoryItemFlags, HandleChangeInventoryItemFlags);
5435 5554
5436 AddGenericPacketHandler("autopilot", HandleAutopilot); 5555 AddGenericPacketHandler("autopilot", HandleAutopilot);
5437 } 5556 }
@@ -5470,6 +5589,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5470 (x.CameraLeftAxis != m_lastAgentUpdateArgs.CameraLeftAxis) || 5589 (x.CameraLeftAxis != m_lastAgentUpdateArgs.CameraLeftAxis) ||
5471 (x.CameraUpAxis != m_lastAgentUpdateArgs.CameraUpAxis) || 5590 (x.CameraUpAxis != m_lastAgentUpdateArgs.CameraUpAxis) ||
5472 (x.ControlFlags != m_lastAgentUpdateArgs.ControlFlags) || 5591 (x.ControlFlags != m_lastAgentUpdateArgs.ControlFlags) ||
5592 (x.ControlFlags != 0) ||
5473 (x.Far != m_lastAgentUpdateArgs.Far) || 5593 (x.Far != m_lastAgentUpdateArgs.Far) ||
5474 (x.Flags != m_lastAgentUpdateArgs.Flags) || 5594 (x.Flags != m_lastAgentUpdateArgs.Flags) ||
5475 (x.State != m_lastAgentUpdateArgs.State) || 5595 (x.State != m_lastAgentUpdateArgs.State) ||
@@ -5729,6 +5849,29 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5729 return true; 5849 return true;
5730 } 5850 }
5731 5851
5852 private bool HandleVelocityInterpolateOff(IClientAPI sender, Packet Pack)
5853 {
5854 VelocityInterpolateOffPacket p = (VelocityInterpolateOffPacket)Pack;
5855 if (p.AgentData.SessionID != SessionId ||
5856 p.AgentData.AgentID != AgentId)
5857 return true;
5858
5859 m_VelocityInterpolate = false;
5860 return true;
5861 }
5862
5863 private bool HandleVelocityInterpolateOn(IClientAPI sender, Packet Pack)
5864 {
5865 VelocityInterpolateOnPacket p = (VelocityInterpolateOnPacket)Pack;
5866 if (p.AgentData.SessionID != SessionId ||
5867 p.AgentData.AgentID != AgentId)
5868 return true;
5869
5870 m_VelocityInterpolate = true;
5871 return true;
5872 }
5873
5874
5732 private bool HandleAvatarPropertiesRequest(IClientAPI sender, Packet Pack) 5875 private bool HandleAvatarPropertiesRequest(IClientAPI sender, Packet Pack)
5733 { 5876 {
5734 AvatarPropertiesRequestPacket avatarProperties = (AvatarPropertiesRequestPacket)Pack; 5877 AvatarPropertiesRequestPacket avatarProperties = (AvatarPropertiesRequestPacket)Pack;
@@ -6149,17 +6292,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6149 // Temporarily protect ourselves from the mantis #951 failure. 6292 // Temporarily protect ourselves from the mantis #951 failure.
6150 // However, we could do this for several other handlers where a failure isn't terminal 6293 // However, we could do this for several other handlers where a failure isn't terminal
6151 // for the client session anyway, in order to protect ourselves against bad code in plugins 6294 // for the client session anyway, in order to protect ourselves against bad code in plugins
6295 Vector3 avSize = appear.AgentData.Size;
6152 try 6296 try
6153 { 6297 {
6154 byte[] visualparams = new byte[appear.VisualParam.Length]; 6298 byte[] visualparams = new byte[appear.VisualParam.Length];
6155 for (int i = 0; i < appear.VisualParam.Length; i++) 6299 for (int i = 0; i < appear.VisualParam.Length; i++)
6156 visualparams[i] = appear.VisualParam[i].ParamValue; 6300 visualparams[i] = appear.VisualParam[i].ParamValue;
6157 6301 //var b = appear.WearableData[0];
6302
6158 Primitive.TextureEntry te = null; 6303 Primitive.TextureEntry te = null;
6159 if (appear.ObjectData.TextureEntry.Length > 1) 6304 if (appear.ObjectData.TextureEntry.Length > 1)
6160 te = new Primitive.TextureEntry(appear.ObjectData.TextureEntry, 0, appear.ObjectData.TextureEntry.Length); 6305 te = new Primitive.TextureEntry(appear.ObjectData.TextureEntry, 0, appear.ObjectData.TextureEntry.Length);
6306
6307 WearableCacheItem[] cacheitems = new WearableCacheItem[appear.WearableData.Length];
6308 for (int i=0; i<appear.WearableData.Length;i++)
6309 cacheitems[i] = new WearableCacheItem(){CacheId = appear.WearableData[i].CacheID,TextureIndex=Convert.ToUInt32(appear.WearableData[i].TextureIndex)};
6161 6310
6162 handlerSetAppearance(sender, te, visualparams); 6311
6312
6313 handlerSetAppearance(sender, te, visualparams,avSize, cacheitems);
6163 } 6314 }
6164 catch (Exception e) 6315 catch (Exception e)
6165 { 6316 {
@@ -6368,6 +6519,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6368 { 6519 {
6369 handlerCompleteMovementToRegion(sender, true); 6520 handlerCompleteMovementToRegion(sender, true);
6370 } 6521 }
6522 else
6523 m_log.Debug("HandleCompleteAgentMovement NULL handler");
6524
6371 handlerCompleteMovementToRegion = null; 6525 handlerCompleteMovementToRegion = null;
6372 6526
6373 return true; 6527 return true;
@@ -6385,7 +6539,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6385 return true; 6539 return true;
6386 } 6540 }
6387 #endregion 6541 #endregion
6388 6542/*
6389 StartAnim handlerStartAnim = null; 6543 StartAnim handlerStartAnim = null;
6390 StopAnim handlerStopAnim = null; 6544 StopAnim handlerStopAnim = null;
6391 6545
@@ -6409,6 +6563,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6409 } 6563 }
6410 } 6564 }
6411 return true; 6565 return true;
6566*/
6567 ChangeAnim handlerChangeAnim = null;
6568
6569 for (int i = 0; i < AgentAni.AnimationList.Length; i++)
6570 {
6571 handlerChangeAnim = OnChangeAnim;
6572 if (handlerChangeAnim != null)
6573 {
6574 handlerChangeAnim(AgentAni.AnimationList[i].AnimID, AgentAni.AnimationList[i].StartAnim, false);
6575 }
6576 }
6577
6578 handlerChangeAnim = OnChangeAnim;
6579 if (handlerChangeAnim != null)
6580 {
6581 handlerChangeAnim(UUID.Zero, false, true);
6582 }
6583
6584 return true;
6412 } 6585 }
6413 6586
6414 private bool HandleAgentRequestSit(IClientAPI sender, Packet Pack) 6587 private bool HandleAgentRequestSit(IClientAPI sender, Packet Pack)
@@ -6633,6 +6806,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6633 #endregion 6806 #endregion
6634 6807
6635 m_udpClient.SetThrottles(atpack.Throttle.Throttles); 6808 m_udpClient.SetThrottles(atpack.Throttle.Throttles);
6809 GenericCall2 handler = OnUpdateThrottles;
6810 if (handler != null)
6811 {
6812 handler();
6813 }
6636 return true; 6814 return true;
6637 } 6815 }
6638 6816
@@ -7034,10 +7212,33 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7034 // 46,47,48 are special positions within the packet 7212 // 46,47,48 are special positions within the packet
7035 // This may change so perhaps we need a better way 7213 // This may change so perhaps we need a better way
7036 // of storing this (OMV.FlagUpdatePacket.UsePhysics,etc?) 7214 // of storing this (OMV.FlagUpdatePacket.UsePhysics,etc?)
7037 bool UsePhysics = (data[46] != 0) ? true : false; 7215 /*
7038 bool IsTemporary = (data[47] != 0) ? true : false; 7216 bool UsePhysics = (data[46] != 0) ? true : false;
7039 bool IsPhantom = (data[48] != 0) ? true : false; 7217 bool IsTemporary = (data[47] != 0) ? true : false;
7040 handlerUpdatePrimFlags(flags.AgentData.ObjectLocalID, UsePhysics, IsTemporary, IsPhantom, this); 7218 bool IsPhantom = (data[48] != 0) ? true : false;
7219 handlerUpdatePrimFlags(flags.AgentData.ObjectLocalID, UsePhysics, IsTemporary, IsPhantom, this);
7220 */
7221 bool UsePhysics = flags.AgentData.UsePhysics;
7222 bool IsPhantom = flags.AgentData.IsPhantom;
7223 bool IsTemporary = flags.AgentData.IsTemporary;
7224 ObjectFlagUpdatePacket.ExtraPhysicsBlock[] blocks = flags.ExtraPhysics;
7225 ExtraPhysicsData physdata = new ExtraPhysicsData();
7226
7227 if (blocks == null || blocks.Length == 0)
7228 {
7229 physdata.PhysShapeType = PhysShapeType.invalid;
7230 }
7231 else
7232 {
7233 ObjectFlagUpdatePacket.ExtraPhysicsBlock phsblock = blocks[0];
7234 physdata.PhysShapeType = (PhysShapeType)phsblock.PhysicsShapeType;
7235 physdata.Bounce = phsblock.Restitution;
7236 physdata.Density = phsblock.Density;
7237 physdata.Friction = phsblock.Friction;
7238 physdata.GravitationModifier = phsblock.GravityMultiplier;
7239 }
7240
7241 handlerUpdatePrimFlags(flags.AgentData.ObjectLocalID, UsePhysics, IsTemporary, IsPhantom, physdata, this);
7041 } 7242 }
7042 return true; 7243 return true;
7043 } 7244 }
@@ -7620,6 +7821,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7620 // surrounding scene 7821 // surrounding scene
7621 if ((ImageType)block.Type == ImageType.Baked) 7822 if ((ImageType)block.Type == ImageType.Baked)
7622 args.Priority *= 2.0f; 7823 args.Priority *= 2.0f;
7824 int wearableout = 0;
7623 7825
7624 ImageManager.EnqueueReq(args); 7826 ImageManager.EnqueueReq(args);
7625 } 7827 }
@@ -8638,16 +8840,61 @@ namespace OpenSim.Region.ClientStack.LindenUDP
8638 8840
8639 #region Parcel related packets 8841 #region Parcel related packets
8640 8842
8843 // acumulate several HandleRegionHandleRequest consecutive overlaping requests
8844 // to be done with minimal resources as possible
8845 // variables temporary here while in test
8846
8847 Queue<UUID> RegionHandleRequests = new Queue<UUID>();
8848 bool RegionHandleRequestsInService = false;
8849
8641 private bool HandleRegionHandleRequest(IClientAPI sender, Packet Pack) 8850 private bool HandleRegionHandleRequest(IClientAPI sender, Packet Pack)
8642 { 8851 {
8643 RegionHandleRequestPacket rhrPack = (RegionHandleRequestPacket)Pack; 8852 UUID currentUUID;
8644 8853
8645 RegionHandleRequest handlerRegionHandleRequest = OnRegionHandleRequest; 8854 RegionHandleRequest handlerRegionHandleRequest = OnRegionHandleRequest;
8646 if (handlerRegionHandleRequest != null) 8855
8856 if (handlerRegionHandleRequest == null)
8857 return true;
8858
8859 RegionHandleRequestPacket rhrPack = (RegionHandleRequestPacket)Pack;
8860
8861 lock (RegionHandleRequests)
8647 { 8862 {
8648 handlerRegionHandleRequest(this, rhrPack.RequestBlock.RegionID); 8863 if (RegionHandleRequestsInService)
8864 {
8865 // we are already busy doing a previus request
8866 // so enqueue it
8867 RegionHandleRequests.Enqueue(rhrPack.RequestBlock.RegionID);
8868 return true;
8869 }
8870
8871 // else do it
8872 currentUUID = rhrPack.RequestBlock.RegionID;
8873 RegionHandleRequestsInService = true;
8649 } 8874 }
8650 return true; 8875
8876 while (true)
8877 {
8878 handlerRegionHandleRequest(this, currentUUID);
8879
8880 lock (RegionHandleRequests)
8881 {
8882 // exit condition, nothing to do or closed
8883 // current code seems to assume we may loose the handler at anytime,
8884 // so keep checking it
8885 handlerRegionHandleRequest = OnRegionHandleRequest;
8886
8887 if (RegionHandleRequests.Count == 0 || !IsActive || handlerRegionHandleRequest == null)
8888 {
8889 RegionHandleRequests.Clear();
8890 RegionHandleRequestsInService = false;
8891 return true;
8892 }
8893 currentUUID = RegionHandleRequests.Dequeue();
8894 }
8895 }
8896
8897 return true; // actually unreached
8651 } 8898 }
8652 8899
8653 private bool HandleParcelInfoRequest(IClientAPI sender, Packet Pack) 8900 private bool HandleParcelInfoRequest(IClientAPI sender, Packet Pack)
@@ -9903,7 +10150,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9903 handlerUpdateMuteListEntry(this, UpdateMuteListEntry.MuteData.MuteID, 10150 handlerUpdateMuteListEntry(this, UpdateMuteListEntry.MuteData.MuteID,
9904 Utils.BytesToString(UpdateMuteListEntry.MuteData.MuteName), 10151 Utils.BytesToString(UpdateMuteListEntry.MuteData.MuteName),
9905 UpdateMuteListEntry.MuteData.MuteType, 10152 UpdateMuteListEntry.MuteData.MuteType,
9906 UpdateMuteListEntry.AgentData.AgentID); 10153 UpdateMuteListEntry.MuteData.MuteFlags);
9907 return true; 10154 return true;
9908 } 10155 }
9909 return false; 10156 return false;
@@ -9918,8 +10165,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9918 { 10165 {
9919 handlerRemoveMuteListEntry(this, 10166 handlerRemoveMuteListEntry(this,
9920 RemoveMuteListEntry.MuteData.MuteID, 10167 RemoveMuteListEntry.MuteData.MuteID,
9921 Utils.BytesToString(RemoveMuteListEntry.MuteData.MuteName), 10168 Utils.BytesToString(RemoveMuteListEntry.MuteData.MuteName));
9922 RemoveMuteListEntry.AgentData.AgentID);
9923 return true; 10169 return true;
9924 } 10170 }
9925 return false; 10171 return false;
@@ -9963,10 +10209,55 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9963 return false; 10209 return false;
9964 } 10210 }
9965 10211
10212 private bool HandleChangeInventoryItemFlags(IClientAPI client, Packet packet)
10213 {
10214 ChangeInventoryItemFlagsPacket ChangeInventoryItemFlags =
10215 (ChangeInventoryItemFlagsPacket)packet;
10216 ChangeInventoryItemFlags handlerChangeInventoryItemFlags = OnChangeInventoryItemFlags;
10217 if (handlerChangeInventoryItemFlags != null)
10218 {
10219 foreach(ChangeInventoryItemFlagsPacket.InventoryDataBlock b in ChangeInventoryItemFlags.InventoryData)
10220 handlerChangeInventoryItemFlags(this, b.ItemID, b.Flags);
10221 return true;
10222 }
10223 return false;
10224 }
10225
9966 private bool HandleUseCircuitCode(IClientAPI sender, Packet Pack) 10226 private bool HandleUseCircuitCode(IClientAPI sender, Packet Pack)
9967 { 10227 {
9968 return true; 10228 return true;
9969 } 10229 }
10230
10231 private bool HandleCreateNewOutfitAttachments(IClientAPI sender, Packet Pack)
10232 {
10233 CreateNewOutfitAttachmentsPacket packet = (CreateNewOutfitAttachmentsPacket)Pack;
10234
10235 #region Packet Session and User Check
10236 if (m_checkPackets)
10237 {
10238 if (packet.AgentData.SessionID != SessionId ||
10239 packet.AgentData.AgentID != AgentId)
10240 return true;
10241 }
10242 #endregion
10243 MoveItemsAndLeaveCopy handlerMoveItemsAndLeaveCopy = null;
10244 List<InventoryItemBase> items = new List<InventoryItemBase>();
10245 foreach (CreateNewOutfitAttachmentsPacket.ObjectDataBlock n in packet.ObjectData)
10246 {
10247 InventoryItemBase b = new InventoryItemBase();
10248 b.ID = n.OldItemID;
10249 b.Folder = n.OldFolderID;
10250 items.Add(b);
10251 }
10252
10253 handlerMoveItemsAndLeaveCopy = OnMoveItemsAndLeaveCopy;
10254 if (handlerMoveItemsAndLeaveCopy != null)
10255 {
10256 handlerMoveItemsAndLeaveCopy(this, items, packet.HeaderData.NewFolderID);
10257 }
10258
10259 return true;
10260 }
9970 10261
9971 private bool HandleAgentHeightWidth(IClientAPI sender, Packet Pack) 10262 private bool HandleAgentHeightWidth(IClientAPI sender, Packet Pack)
9972 { 10263 {
@@ -10393,6 +10684,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10393 groupProfileReply.GroupData.MaturePublish = d.MaturePublish; 10684 groupProfileReply.GroupData.MaturePublish = d.MaturePublish;
10394 groupProfileReply.GroupData.OwnerRole = d.OwnerRole; 10685 groupProfileReply.GroupData.OwnerRole = d.OwnerRole;
10395 10686
10687 Scene scene = (Scene)m_scene;
10688 if (scene.Permissions.IsGod(sender.AgentId) && (!sender.IsGroupMember(groupProfileRequest.GroupData.GroupID)))
10689 {
10690 ScenePresence p;
10691 if (scene.TryGetScenePresence(sender.AgentId, out p))
10692 {
10693 if (p.GodLevel >= 200)
10694 {
10695 groupProfileReply.GroupData.OpenEnrollment = true;
10696 groupProfileReply.GroupData.MembershipFee = 0;
10697 }
10698 }
10699 }
10700
10396 OutPacket(groupProfileReply, ThrottleOutPacketType.Task); 10701 OutPacket(groupProfileReply, ThrottleOutPacketType.Task);
10397 } 10702 }
10398 return true; 10703 return true;
@@ -10966,11 +11271,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10966 11271
10967 StartLure handlerStartLure = OnStartLure; 11272 StartLure handlerStartLure = OnStartLure;
10968 if (handlerStartLure != null) 11273 if (handlerStartLure != null)
10969 handlerStartLure(startLureRequest.Info.LureType, 11274 {
10970 Utils.BytesToString( 11275 for (int i = 0 ; i < startLureRequest.TargetData.Length ; i++)
10971 startLureRequest.Info.Message), 11276 {
10972 startLureRequest.TargetData[0].TargetID, 11277 handlerStartLure(startLureRequest.Info.LureType,
10973 this); 11278 Utils.BytesToString(
11279 startLureRequest.Info.Message),
11280 startLureRequest.TargetData[i].TargetID,
11281 this);
11282 }
11283 }
10974 return true; 11284 return true;
10975 } 11285 }
10976 private bool HandleTeleportLureRequest(IClientAPI sender, Packet Pack) 11286 private bool HandleTeleportLureRequest(IClientAPI sender, Packet Pack)
@@ -11084,10 +11394,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11084 } 11394 }
11085 #endregion 11395 #endregion
11086 11396
11087 ClassifiedDelete handlerClassifiedGodDelete = OnClassifiedGodDelete; 11397 ClassifiedGodDelete handlerClassifiedGodDelete = OnClassifiedGodDelete;
11088 if (handlerClassifiedGodDelete != null) 11398 if (handlerClassifiedGodDelete != null)
11089 handlerClassifiedGodDelete( 11399 handlerClassifiedGodDelete(
11090 classifiedGodDelete.Data.ClassifiedID, 11400 classifiedGodDelete.Data.ClassifiedID,
11401 classifiedGodDelete.Data.QueryID,
11091 this); 11402 this);
11092 return true; 11403 return true;
11093 } 11404 }
@@ -11400,6 +11711,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11400 11711
11401 if (cachedtex.AgentData.SessionID != SessionId) 11712 if (cachedtex.AgentData.SessionID != SessionId)
11402 return false; 11713 return false;
11714
11403 11715
11404 // TODO: don't create new blocks if recycling an old packet 11716 // TODO: don't create new blocks if recycling an old packet
11405 cachedresp.AgentData.AgentID = AgentId; 11717 cachedresp.AgentData.AgentID = AgentId;
@@ -11409,14 +11721,140 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11409 cachedresp.WearableData = 11721 cachedresp.WearableData =
11410 new AgentCachedTextureResponsePacket.WearableDataBlock[cachedtex.WearableData.Length]; 11722 new AgentCachedTextureResponsePacket.WearableDataBlock[cachedtex.WearableData.Length];
11411 11723
11412 for (int i = 0; i < cachedtex.WearableData.Length; i++) 11724 //IAvatarFactoryModule fac = m_scene.RequestModuleInterface<IAvatarFactoryModule>();
11725 // var item = fac.GetBakedTextureFaces(AgentId);
11726 //WearableCacheItem[] items = fac.GetCachedItems(AgentId);
11727
11728 IAssetService cache = m_scene.AssetService;
11729 IBakedTextureModule bakedTextureModule = m_scene.RequestModuleInterface<IBakedTextureModule>();
11730 //bakedTextureModule = null;
11731 int maxWearablesLoop = cachedtex.WearableData.Length;
11732 if (maxWearablesLoop > AvatarWearable.MAX_WEARABLES)
11733 maxWearablesLoop = AvatarWearable.MAX_WEARABLES;
11734
11735 if (bakedTextureModule != null && cache != null)
11413 { 11736 {
11414 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock(); 11737 // 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
11415 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex; 11738
11416 cachedresp.WearableData[i].TextureID = UUID.Zero; 11739 WearableCacheItem[] cacheItems = null;
11417 cachedresp.WearableData[i].HostName = new byte[0]; 11740 ScenePresence p = m_scene.GetScenePresence(AgentId);
11741 if (p.Appearance != null)
11742 if (p.Appearance.WearableCacheItems == null || p.Appearance.WearableCacheItemsDirty)
11743 {
11744 try
11745 {
11746 cacheItems = bakedTextureModule.Get(AgentId);
11747 p.Appearance.WearableCacheItems = cacheItems;
11748 p.Appearance.WearableCacheItemsDirty = false;
11749 }
11750
11751 /*
11752 * The following Catch types DO NOT WORK, it jumps to the General Packet Exception Handler if you don't catch Exception!
11753 *
11754 catch (System.Net.Sockets.SocketException)
11755 {
11756 cacheItems = null;
11757 }
11758 catch (WebException)
11759 {
11760 cacheItems = null;
11761 }
11762 catch (InvalidOperationException)
11763 {
11764 cacheItems = null;
11765 } */
11766 catch (Exception)
11767 {
11768 cacheItems = null;
11769 }
11770
11771 }
11772 else if (p.Appearance.WearableCacheItems != null)
11773 {
11774 cacheItems = p.Appearance.WearableCacheItems;
11775 }
11776
11777 if (cache != null && cacheItems != null)
11778 {
11779 foreach (WearableCacheItem item in cacheItems)
11780 {
11781
11782 if (cache.GetCached(item.TextureID.ToString()) == null)
11783 {
11784 item.TextureAsset.Temporary = true;
11785 cache.Store(item.TextureAsset);
11786 }
11787
11788
11789 }
11790 }
11791
11792 if (cacheItems != null)
11793 {
11794
11795 for (int i = 0; i < maxWearablesLoop; i++)
11796 {
11797 WearableCacheItem item =
11798 WearableCacheItem.SearchTextureIndex(cachedtex.WearableData[i].TextureIndex,cacheItems);
11799
11800 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
11801 cachedresp.WearableData[i].TextureIndex= cachedtex.WearableData[i].TextureIndex;
11802 cachedresp.WearableData[i].HostName = new byte[0];
11803 if (item != null && cachedtex.WearableData[i].ID == item.CacheId)
11804 {
11805
11806 cachedresp.WearableData[i].TextureID = item.TextureID;
11807 }
11808 else
11809 {
11810 cachedresp.WearableData[i].TextureID = UUID.Zero;
11811 }
11812 }
11813 }
11814 else
11815 {
11816 for (int i = 0; i < maxWearablesLoop; i++)
11817 {
11818 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
11819 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex;
11820 cachedresp.WearableData[i].TextureID = UUID.Zero;
11821 //UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46");
11822 cachedresp.WearableData[i].HostName = new byte[0];
11823 }
11824 }
11418 } 11825 }
11826 else
11827 {
11828 if (cache == null)
11829 {
11830 for (int i = 0; i < maxWearablesLoop; i++)
11831 {
11832 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
11833 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex;
11834 cachedresp.WearableData[i].TextureID = UUID.Zero;
11835 //UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46");
11836 cachedresp.WearableData[i].HostName = new byte[0];
11837 }
11838 }
11839 else
11840 {
11841 for (int i = 0; i < maxWearablesLoop; i++)
11842 {
11843 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
11844 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex;
11419 11845
11846
11847
11848 if (cache.GetCached(cachedresp.WearableData[i].TextureID.ToString()) == null)
11849 cachedresp.WearableData[i].TextureID = UUID.Zero;
11850 //UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46");
11851 else
11852 cachedresp.WearableData[i].TextureID = UUID.Zero;
11853 // UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46");
11854 cachedresp.WearableData[i].HostName = new byte[0];
11855 }
11856 }
11857 }
11420 cachedresp.Header.Zerocoded = true; 11858 cachedresp.Header.Zerocoded = true;
11421 OutPacket(cachedresp, ThrottleOutPacketType.Task); 11859 OutPacket(cachedresp, ThrottleOutPacketType.Task);
11422 11860
@@ -11453,209 +11891,147 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11453 } 11891 }
11454 else 11892 else
11455 { 11893 {
11456// m_log.DebugFormat( 11894 ClientChangeObject updatehandler = onClientChangeObject;
11457// "[CLIENT]: Processing block {0} type {1} for {2} {3}",
11458// i, block.Type, part.Name, part.LocalId);
11459 11895
11460// // Do this once since fetch parts creates a new array. 11896 if (updatehandler != null)
11461// SceneObjectPart[] parts = part.ParentGroup.Parts; 11897 {
11462// for (int j = 0; j < parts.Length; j++) 11898 ObjectChangeData udata = new ObjectChangeData();
11463// {
11464// part.StoreUndoState();
11465// parts[j].IgnoreUndoUpdate = true;
11466// }
11467 11899
11468 UpdatePrimGroupRotation handlerUpdatePrimGroupRotation; 11900 /*ubit from ll JIRA:
11901 * 0x01 position
11902 * 0x02 rotation
11903 * 0x04 scale
11904
11905 * 0x08 LINK_SET
11906 * 0x10 UNIFORM for scale
11907 */
11469 11908
11470 switch (block.Type) 11909 // translate to internal changes
11471 { 11910 // not all cases .. just the ones older code did
11472 case 1:
11473 Vector3 pos1 = new Vector3(block.Data, 0);
11474 11911
11475 UpdateVector handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; 11912 switch (block.Type)
11476 if (handlerUpdatePrimSinglePosition != null) 11913 {
11477 { 11914 case 1: //change position sp
11478 // m_log.Debug("new movement position is " + pos.X + " , " + pos.Y + " , " + pos.Z); 11915 udata.position = new Vector3(block.Data, 0);
11479 handlerUpdatePrimSinglePosition(localId, pos1, this);
11480 }
11481 break;
11482 11916
11483 case 2: 11917 udata.change = ObjectChangeType.primP;
11484 Quaternion rot1 = new Quaternion(block.Data, 0, true); 11918 updatehandler(localId, udata, this);
11919 break;
11485 11920
11486 UpdatePrimSingleRotation handlerUpdatePrimSingleRotation = OnUpdatePrimSingleRotation; 11921 case 2: // rotation sp
11487 if (handlerUpdatePrimSingleRotation != null) 11922 udata.rotation = new Quaternion(block.Data, 0, true);
11488 {
11489 // m_log.Info("new tab rotation is " + rot1.X + " , " + rot1.Y + " , " + rot1.Z + " , " + rot1.W);
11490 handlerUpdatePrimSingleRotation(localId, rot1, this);
11491 }
11492 break;
11493 11923
11494 case 3: 11924 udata.change = ObjectChangeType.primR;
11495 Vector3 rotPos = new Vector3(block.Data, 0); 11925 updatehandler(localId, udata, this);
11496 Quaternion rot2 = new Quaternion(block.Data, 12, true); 11926 break;
11497 11927
11498 UpdatePrimSingleRotationPosition handlerUpdatePrimSingleRotationPosition = OnUpdatePrimSingleRotationPosition; 11928 case 3: // position plus rotation
11499 if (handlerUpdatePrimSingleRotationPosition != null) 11929 udata.position = new Vector3(block.Data, 0);
11500 { 11930 udata.rotation = new Quaternion(block.Data, 12, true);
11501 // m_log.Debug("new mouse rotation position is " + rotPos.X + " , " + rotPos.Y + " , " + rotPos.Z);
11502 // m_log.Info("new mouse rotation is " + rot2.X + " , " + rot2.Y + " , " + rot2.Z + " , " + rot2.W);
11503 handlerUpdatePrimSingleRotationPosition(localId, rot2, rotPos, this);
11504 }
11505 break;
11506 11931
11507 case 4: 11932 udata.change = ObjectChangeType.primPR;
11508 case 20: 11933 updatehandler(localId, udata, this);
11509 Vector3 scale4 = new Vector3(block.Data, 0); 11934 break;
11510 11935
11511 UpdateVector handlerUpdatePrimScale = OnUpdatePrimScale; 11936 case 4: // scale sp
11512 if (handlerUpdatePrimScale != null) 11937 udata.scale = new Vector3(block.Data, 0);
11513 { 11938 udata.change = ObjectChangeType.primS;
11514 // m_log.Debug("new scale is " + scale4.X + " , " + scale4.Y + " , " + scale4.Z);
11515 handlerUpdatePrimScale(localId, scale4, this);
11516 }
11517 break;
11518 11939
11519 case 5: 11940 updatehandler(localId, udata, this);
11520 Vector3 scale1 = new Vector3(block.Data, 12); 11941 break;
11521 Vector3 pos11 = new Vector3(block.Data, 0);
11522 11942
11523 handlerUpdatePrimScale = OnUpdatePrimScale; 11943 case 0x14: // uniform scale sp
11524 if (handlerUpdatePrimScale != null) 11944 udata.scale = new Vector3(block.Data, 0);
11525 {
11526 // m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z);
11527 handlerUpdatePrimScale(localId, scale1, this);
11528 11945
11529 handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; 11946 udata.change = ObjectChangeType.primUS;
11530 if (handlerUpdatePrimSinglePosition != null) 11947 updatehandler(localId, udata, this);
11531 { 11948 break;
11532 handlerUpdatePrimSinglePosition(localId, pos11, this);
11533 }
11534 }
11535 break;
11536 11949
11537 case 9: 11950 case 5: // scale and position sp
11538 Vector3 pos2 = new Vector3(block.Data, 0); 11951 udata.position = new Vector3(block.Data, 0);
11952 udata.scale = new Vector3(block.Data, 12);
11539 11953
11540 UpdateVector handlerUpdateVector = OnUpdatePrimGroupPosition; 11954 udata.change = ObjectChangeType.primPS;
11955 updatehandler(localId, udata, this);
11956 break;
11541 11957
11542 if (handlerUpdateVector != null) 11958 case 0x15: //uniform scale and position
11543 { 11959 udata.position = new Vector3(block.Data, 0);
11544 handlerUpdateVector(localId, pos2, this); 11960 udata.scale = new Vector3(block.Data, 12);
11545 }
11546 break;
11547 11961
11548 case 10: 11962 udata.change = ObjectChangeType.primPUS;
11549 Quaternion rot3 = new Quaternion(block.Data, 0, true); 11963 updatehandler(localId, udata, this);
11964 break;
11550 11965
11551 UpdatePrimRotation handlerUpdatePrimRotation = OnUpdatePrimGroupRotation; 11966 // now group related (bit 4)
11552 if (handlerUpdatePrimRotation != null) 11967 case 9: //( 8 + 1 )group position
11553 { 11968 udata.position = new Vector3(block.Data, 0);
11554 // Console.WriteLine("new rotation is " + rot3.X + " , " + rot3.Y + " , " + rot3.Z + " , " + rot3.W);
11555 handlerUpdatePrimRotation(localId, rot3, this);
11556 }
11557 break;
11558 11969
11559 case 11: 11970 udata.change = ObjectChangeType.groupP;
11560 Vector3 pos3 = new Vector3(block.Data, 0); 11971 updatehandler(localId, udata, this);
11561 Quaternion rot4 = new Quaternion(block.Data, 12, true); 11972 break;
11562 11973
11563 handlerUpdatePrimGroupRotation = OnUpdatePrimGroupMouseRotation; 11974 case 0x0A: // (8 + 2) group rotation
11564 if (handlerUpdatePrimGroupRotation != null) 11975 udata.rotation = new Quaternion(block.Data, 0, true);
11565 {
11566 // m_log.Debug("new rotation position is " + pos.X + " , " + pos.Y + " , " + pos.Z);
11567 // m_log.Debug("new group mouse rotation is " + rot4.X + " , " + rot4.Y + " , " + rot4.Z + " , " + rot4.W);
11568 handlerUpdatePrimGroupRotation(localId, pos3, rot4, this);
11569 }
11570 break;
11571 case 12:
11572 case 28:
11573 Vector3 scale7 = new Vector3(block.Data, 0);
11574 11976
11575 UpdateVector handlerUpdatePrimGroupScale = OnUpdatePrimGroupScale; 11977 udata.change = ObjectChangeType.groupR;
11576 if (handlerUpdatePrimGroupScale != null) 11978 updatehandler(localId, udata, this);
11577 { 11979 break;
11578 // m_log.Debug("new scale is " + scale7.X + " , " + scale7.Y + " , " + scale7.Z);
11579 handlerUpdatePrimGroupScale(localId, scale7, this);
11580 }
11581 break;
11582 11980
11583 case 13: 11981 case 0x0B: //( 8 + 2 + 1) group rotation and position
11584 Vector3 scale2 = new Vector3(block.Data, 12); 11982 udata.position = new Vector3(block.Data, 0);
11585 Vector3 pos4 = new Vector3(block.Data, 0); 11983 udata.rotation = new Quaternion(block.Data, 12, true);
11586 11984
11587 handlerUpdatePrimScale = OnUpdatePrimScale; 11985 udata.change = ObjectChangeType.groupPR;
11588 if (handlerUpdatePrimScale != null) 11986 updatehandler(localId, udata, this);
11589 { 11987 break;
11590 //m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z);
11591 handlerUpdatePrimScale(localId, scale2, this);
11592 11988
11593 // Change the position based on scale (for bug number 246) 11989 case 0x0C: // (8 + 4) group scale
11594 handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; 11990 // only afects root prim and only sent by viewer editor object tab scaling
11595 // m_log.Debug("new movement position is " + pos.X + " , " + pos.Y + " , " + pos.Z); 11991 // mouse edition only allows uniform scaling
11596 if (handlerUpdatePrimSinglePosition != null) 11992 // SL MAY CHANGE THIS in viewers
11597 {
11598 handlerUpdatePrimSinglePosition(localId, pos4, this);
11599 }
11600 }
11601 break;
11602 11993
11603 case 29: 11994 udata.scale = new Vector3(block.Data, 0);
11604 Vector3 scale5 = new Vector3(block.Data, 12);
11605 Vector3 pos5 = new Vector3(block.Data, 0);
11606 11995
11607 handlerUpdatePrimGroupScale = OnUpdatePrimGroupScale; 11996 udata.change = ObjectChangeType.groupS;
11608 if (handlerUpdatePrimGroupScale != null) 11997 updatehandler(localId, udata, this);
11609 {
11610 // m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z);
11611 part.StoreUndoState(true);
11612 part.IgnoreUndoUpdate = true;
11613 handlerUpdatePrimGroupScale(localId, scale5, this);
11614 handlerUpdateVector = OnUpdatePrimGroupPosition;
11615 11998
11616 if (handlerUpdateVector != null) 11999 break;
11617 {
11618 handlerUpdateVector(localId, pos5, this);
11619 }
11620 12000
11621 part.IgnoreUndoUpdate = false; 12001 case 0x0D: //(8 + 4 + 1) group scale and position
11622 } 12002 // exception as above
11623 12003
11624 break; 12004 udata.position = new Vector3(block.Data, 0);
12005 udata.scale = new Vector3(block.Data, 12);
11625 12006
11626 case 21: 12007 udata.change = ObjectChangeType.groupPS;
11627 Vector3 scale6 = new Vector3(block.Data, 12); 12008 updatehandler(localId, udata, this);
11628 Vector3 pos6 = new Vector3(block.Data, 0); 12009 break;
11629 12010
11630 handlerUpdatePrimScale = OnUpdatePrimScale; 12011 case 0x1C: // (0x10 + 8 + 4 ) group scale UNIFORM
11631 if (handlerUpdatePrimScale != null) 12012 udata.scale = new Vector3(block.Data, 0);
11632 {
11633 part.StoreUndoState(false);
11634 part.IgnoreUndoUpdate = true;
11635 12013
11636 // m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z); 12014 udata.change = ObjectChangeType.groupUS;
11637 handlerUpdatePrimScale(localId, scale6, this); 12015 updatehandler(localId, udata, this);
11638 handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; 12016 break;
11639 if (handlerUpdatePrimSinglePosition != null)
11640 {
11641 handlerUpdatePrimSinglePosition(localId, pos6, this);
11642 }
11643 12017
11644 part.IgnoreUndoUpdate = false; 12018 case 0x1D: // (UNIFORM + GROUP + SCALE + POS)
11645 } 12019 udata.position = new Vector3(block.Data, 0);
11646 break; 12020 udata.scale = new Vector3(block.Data, 12);
11647 12021
11648 default: 12022 udata.change = ObjectChangeType.groupPUS;
11649 m_log.Debug("[CLIENT]: MultipleObjUpdate recieved an unknown packet type: " + (block.Type)); 12023 updatehandler(localId, udata, this);
11650 break; 12024 break;
12025
12026 default:
12027 m_log.Debug("[CLIENT]: MultipleObjUpdate recieved an unknown packet type: " + (block.Type));
12028 break;
12029 }
11651 } 12030 }
11652 12031
11653// for (int j = 0; j < parts.Length; j++)
11654// parts[j].IgnoreUndoUpdate = false;
11655 } 12032 }
11656 } 12033 }
11657 } 12034 }
11658
11659 return true; 12035 return true;
11660 } 12036 }
11661 12037
@@ -11716,9 +12092,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11716 public void SetChildAgentThrottle(byte[] throttles) 12092 public void SetChildAgentThrottle(byte[] throttles)
11717 { 12093 {
11718 m_udpClient.SetThrottles(throttles); 12094 m_udpClient.SetThrottles(throttles);
12095 GenericCall2 handler = OnUpdateThrottles;
12096 if (handler != null)
12097 {
12098 handler();
12099 }
11719 } 12100 }
11720 12101
11721 /// <summary> 12102 /// <summary>
12103 /// Sets the throttles from values supplied by the client
12104 /// </summary>
12105 /// <param name="throttles"></param>
12106 public void SetAgentThrottleSilent(int throttle, int setting)
12107 {
12108 m_udpClient.ForceThrottleSetting(throttle,setting);
12109 //m_udpClient.SetThrottles(throttles);
12110
12111 }
12112
12113
12114 /// <summary>
11722 /// Get the current throttles for this client as a packed byte array 12115 /// Get the current throttles for this client as a packed byte array
11723 /// </summary> 12116 /// </summary>
11724 /// <param name="multiplier">Unused</param> 12117 /// <param name="multiplier">Unused</param>
@@ -12105,7 +12498,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12105// "[LLCLIENTVIEW]: Received transfer request for {0} in {1} type {2} by {3}", 12498// "[LLCLIENTVIEW]: Received transfer request for {0} in {1} type {2} by {3}",
12106// requestID, taskID, (SourceType)sourceType, Name); 12499// requestID, taskID, (SourceType)sourceType, Name);
12107 12500
12501
12502 //Note, the bool returned from the below function is useless since it is always false.
12108 m_assetService.Get(requestID.ToString(), transferRequest, AssetReceived); 12503 m_assetService.Get(requestID.ToString(), transferRequest, AssetReceived);
12504
12109 } 12505 }
12110 12506
12111 /// <summary> 12507 /// <summary>
@@ -12171,7 +12567,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12171 /// <returns></returns> 12567 /// <returns></returns>
12172 private static int CalculateNumPackets(byte[] data) 12568 private static int CalculateNumPackets(byte[] data)
12173 { 12569 {
12174 const uint m_maxPacketSize = 600; 12570// const uint m_maxPacketSize = 600;
12571 uint m_maxPacketSize = MaxTransferBytesPerPacket;
12175 int numPackets = 1; 12572 int numPackets = 1;
12176 12573
12177 if (data == null) 12574 if (data == null)
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
index 8963756..f675377 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
@@ -158,6 +158,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
158 158
159 private int m_defaultRTO = 1000; // 1sec is the recommendation in the RFC 159 private int m_defaultRTO = 1000; // 1sec is the recommendation in the RFC
160 private int m_maxRTO = 60000; 160 private int m_maxRTO = 60000;
161 public bool m_deliverPackets = true;
161 162
162 /// <summary> 163 /// <summary>
163 /// Default constructor 164 /// Default constructor
@@ -440,6 +441,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
440 if (category >= 0 && category < m_packetOutboxes.Length) 441 if (category >= 0 && category < m_packetOutboxes.Length)
441 { 442 {
442 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue = m_packetOutboxes[category]; 443 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue = m_packetOutboxes[category];
444
445 if (m_deliverPackets == false)
446 {
447 queue.Enqueue(packet);
448 return true;
449 }
450
443 TokenBucket bucket = m_throttleCategories[category]; 451 TokenBucket bucket = m_throttleCategories[category];
444 452
445 // Don't send this packet if there is already a packet waiting in the queue 453 // Don't send this packet if there is already a packet waiting in the queue
@@ -489,7 +497,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
489 /// <returns>True if any packets were sent, otherwise false</returns> 497 /// <returns>True if any packets were sent, otherwise false</returns>
490 public bool DequeueOutgoing() 498 public bool DequeueOutgoing()
491 { 499 {
492 OutgoingPacket packet; 500 if (m_deliverPackets == false) return false;
501
502 OutgoingPacket packet = null;
493 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue; 503 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue;
494 TokenBucket bucket; 504 TokenBucket bucket;
495 bool packetSent = false; 505 bool packetSent = false;
@@ -521,32 +531,49 @@ namespace OpenSim.Region.ClientStack.LindenUDP
521 // No dequeued packet waiting to be sent, try to pull one off 531 // No dequeued packet waiting to be sent, try to pull one off
522 // this queue 532 // this queue
523 queue = m_packetOutboxes[i]; 533 queue = m_packetOutboxes[i];
524 if (queue.Dequeue(out packet)) 534 if (queue != null)
525 { 535 {
526 // A packet was pulled off the queue. See if we have 536 bool success = false;
527 // enough tokens in the bucket to send it out 537 try
528 if (bucket.RemoveTokens(packet.Buffer.DataLength))
529 { 538 {
530 // Send the packet 539 success = queue.Dequeue(out packet);
531 m_udpServer.SendPacketFinal(packet);
532 packetSent = true;
533 } 540 }
534 else 541 catch
535 { 542 {
536 // Save the dequeued packet for the next iteration 543 m_packetOutboxes[i] = new OpenSim.Framework.LocklessQueue<OutgoingPacket>();
537 m_nextPackets[i] = packet;
538 } 544 }
539 545 if (success)
540 // If the queue is empty after this dequeue, fire the queue 546 {
541 // empty callback now so it has a chance to fill before we 547 // A packet was pulled off the queue. See if we have
542 // get back here 548 // enough tokens in the bucket to send it out
543 if (queue.Count == 0) 549 if (bucket.RemoveTokens(packet.Buffer.DataLength))
550 {
551 // Send the packet
552 m_udpServer.SendPacketFinal(packet);
553 packetSent = true;
554 }
555 else
556 {
557 // Save the dequeued packet for the next iteration
558 m_nextPackets[i] = packet;
559 }
560
561 // If the queue is empty after this dequeue, fire the queue
562 // empty callback now so it has a chance to fill before we
563 // get back here
564 if (queue.Count == 0)
565 emptyCategories |= CategoryToFlag(i);
566 }
567 else
568 {
569 // No packets in this queue. Fire the queue empty callback
570 // if it has not been called recently
544 emptyCategories |= CategoryToFlag(i); 571 emptyCategories |= CategoryToFlag(i);
572 }
545 } 573 }
546 else 574 else
547 { 575 {
548 // No packets in this queue. Fire the queue empty callback 576 m_packetOutboxes[i] = new OpenSim.Framework.LocklessQueue<OutgoingPacket>();
549 // if it has not been called recently
550 emptyCategories |= CategoryToFlag(i); 577 emptyCategories |= CategoryToFlag(i);
551 } 578 }
552 } 579 }
@@ -655,6 +682,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
655 if (m_nextOnQueueEmpty == 0) 682 if (m_nextOnQueueEmpty == 0)
656 m_nextOnQueueEmpty = 1; 683 m_nextOnQueueEmpty = 1;
657 } 684 }
685 internal void ForceThrottleSetting(int throttle, int setting)
686 {
687 m_throttleCategories[throttle].RequestedDripRate = Math.Max(setting, LLUDPServer.MTU); ;
688 }
658 689
659 /// <summary> 690 /// <summary>
660 /// Converts a <seealso cref="ThrottleOutPacketType"/> integer to a 691 /// Converts a <seealso cref="ThrottleOutPacketType"/> integer to a
@@ -704,4 +735,4 @@ namespace OpenSim.Region.ClientStack.LindenUDP
704 } 735 }
705 } 736 }
706 } 737 }
707} \ No newline at end of file 738}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
index a7628d2..9a4abd4 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
@@ -126,7 +126,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
126 /// <summary>Handlers for incoming packets</summary> 126 /// <summary>Handlers for incoming packets</summary>
127 //PacketEventDictionary packetEvents = new PacketEventDictionary(); 127 //PacketEventDictionary packetEvents = new PacketEventDictionary();
128 /// <summary>Incoming packets that are awaiting handling</summary> 128 /// <summary>Incoming packets that are awaiting handling</summary>
129 private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>(); 129 //private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>();
130
131 private DoubleQueue<IncomingPacket> packetInbox = new DoubleQueue<IncomingPacket>();
130 132
131 /// <summary></summary> 133 /// <summary></summary>
132 //private UDPClientCollection m_clients = new UDPClientCollection(); 134 //private UDPClientCollection m_clients = new UDPClientCollection();
@@ -181,6 +183,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
181 /// <summary>Flag to signal when clients should send pings</summary> 183 /// <summary>Flag to signal when clients should send pings</summary>
182 protected bool m_sendPing; 184 protected bool m_sendPing;
183 185
186 private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>();
184 private Pool<IncomingPacket> m_incomingPacketPool; 187 private Pool<IncomingPacket> m_incomingPacketPool;
185 188
186 /// <summary> 189 /// <summary>
@@ -1093,21 +1096,46 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1093 1096
1094 #region Packet to Client Mapping 1097 #region Packet to Client Mapping
1095 1098
1096 // UseCircuitCode handling 1099 // If there is already a client for this endpoint, don't process UseCircuitCode
1097 if (packet.Type == PacketType.UseCircuitCode) 1100 IClientAPI client = null;
1101 if (!m_scene.TryGetClient(endPoint, out client) || !(client is LLClientView))
1098 { 1102 {
1099 // We need to copy the endpoint so that it doesn't get changed when another thread reuses the 1103 // UseCircuitCode handling
1100 // buffer. 1104 if (packet.Type == PacketType.UseCircuitCode)
1101 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet }; 1105 {
1106 // And if there is a UseCircuitCode pending, also drop it
1107 lock (m_pendingCache)
1108 {
1109 if (m_pendingCache.Contains(endPoint))
1110 return;
1102 1111
1103 Util.FireAndForget(HandleUseCircuitCode, array); 1112 m_pendingCache.AddOrUpdate(endPoint, new Queue<UDPPacketBuffer>(), 60);
1113 }
1104 1114
1105 return; 1115 // We need to copy the endpoint so that it doesn't get changed when another thread reuses the
1116 // buffer.
1117 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet };
1118
1119 Util.FireAndForget(HandleUseCircuitCode, array);
1120
1121 return;
1122 }
1123 }
1124
1125 // If this is a pending connection, enqueue, don't process yet
1126 lock (m_pendingCache)
1127 {
1128 Queue<UDPPacketBuffer> queue;
1129 if (m_pendingCache.TryGetValue(endPoint, out queue))
1130 {
1131 //m_log.DebugFormat("[LLUDPSERVER]: Enqueued a {0} packet into the pending queue", packet.Type);
1132 queue.Enqueue(buffer);
1133 return;
1134 }
1106 } 1135 }
1107 1136
1108 // Determine which agent this packet came from 1137 // Determine which agent this packet came from
1109 IClientAPI client; 1138 if (client == null || !(client is LLClientView))
1110 if (!m_scene.TryGetClient(endPoint, out client) || !(client is LLClientView))
1111 { 1139 {
1112 //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); 1140 //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName);
1113 return; 1141 return;
@@ -1116,7 +1144,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1116 udpClient = ((LLClientView)client).UDPClient; 1144 udpClient = ((LLClientView)client).UDPClient;
1117 1145
1118 if (!udpClient.IsConnected) 1146 if (!udpClient.IsConnected)
1147 {
1148// m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet for a unConnected client in " + m_scene.RegionInfo.RegionName);
1119 return; 1149 return;
1150 }
1120 1151
1121 #endregion Packet to Client Mapping 1152 #endregion Packet to Client Mapping
1122 1153
@@ -1246,7 +1277,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1246 incomingPacket = new IncomingPacket((LLClientView)client, packet); 1277 incomingPacket = new IncomingPacket((LLClientView)client, packet);
1247 } 1278 }
1248 1279
1249 packetInbox.Enqueue(incomingPacket); 1280 if (incomingPacket.Packet.Type == PacketType.AgentUpdate ||
1281 incomingPacket.Packet.Type == PacketType.ChatFromViewer)
1282 packetInbox.EnqueueHigh(incomingPacket);
1283 else
1284 packetInbox.EnqueueLow(incomingPacket);
1250 } 1285 }
1251 1286
1252 #region BinaryStats 1287 #region BinaryStats
@@ -1366,6 +1401,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1366 // We only want to send initial data to new clients, not ones which are being converted from child to root. 1401 // We only want to send initial data to new clients, not ones which are being converted from child to root.
1367 if (client != null) 1402 if (client != null)
1368 client.SceneAgent.SendInitialDataToMe(); 1403 client.SceneAgent.SendInitialDataToMe();
1404
1405 // Now we know we can handle more data
1406 Thread.Sleep(200);
1407
1408 // Obtain the queue and remove it from the cache
1409 Queue<UDPPacketBuffer> queue = null;
1410
1411 lock (m_pendingCache)
1412 {
1413 if (!m_pendingCache.TryGetValue(endPoint, out queue))
1414 {
1415 m_log.DebugFormat("[LLUDPSERVER]: Client created but no pending queue present");
1416 return;
1417 }
1418 m_pendingCache.Remove(endPoint);
1419 }
1420
1421 m_log.DebugFormat("[LLUDPSERVER]: Client created, processing pending queue, {0} entries", queue.Count);
1422
1423 // Reinject queued packets
1424 while(queue.Count > 0)
1425 {
1426 UDPPacketBuffer buf = queue.Dequeue();
1427 PacketReceived(buf);
1428 }
1429 queue = null;
1369 } 1430 }
1370 else 1431 else
1371 { 1432 {
@@ -1373,6 +1434,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1373 m_log.WarnFormat( 1434 m_log.WarnFormat(
1374 "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}", 1435 "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}",
1375 uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint); 1436 uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint);
1437 lock (m_pendingCache)
1438 m_pendingCache.Remove(endPoint);
1376 } 1439 }
1377 1440
1378 // m_log.DebugFormat( 1441 // m_log.DebugFormat(
@@ -1491,7 +1554,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1491 if (!client.SceneAgent.IsChildAgent) 1554 if (!client.SceneAgent.IsChildAgent)
1492 client.Kick("Simulator logged you out due to connection timeout"); 1555 client.Kick("Simulator logged you out due to connection timeout");
1493 1556
1494 client.CloseWithoutChecks(); 1557 client.CloseWithoutChecks(true);
1495 } 1558 }
1496 } 1559 }
1497 1560
@@ -1503,6 +1566,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1503 1566
1504 while (IsRunningInbound) 1567 while (IsRunningInbound)
1505 { 1568 {
1569 m_scene.ThreadAlive(1);
1506 try 1570 try
1507 { 1571 {
1508 IncomingPacket incomingPacket = null; 1572 IncomingPacket incomingPacket = null;
@@ -1550,6 +1614,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1550 1614
1551 while (base.IsRunningOutbound) 1615 while (base.IsRunningOutbound)
1552 { 1616 {
1617 m_scene.ThreadAlive(2);
1553 try 1618 try
1554 { 1619 {
1555 m_packetSent = false; 1620 m_packetSent = false;
@@ -1780,8 +1845,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1780 Packet packet = incomingPacket.Packet; 1845 Packet packet = incomingPacket.Packet;
1781 LLClientView client = incomingPacket.Client; 1846 LLClientView client = incomingPacket.Client;
1782 1847
1783 if (client.IsActive) 1848// if (client.IsActive)
1784 { 1849// {
1785 m_currentIncomingClient = client; 1850 m_currentIncomingClient = client;
1786 1851
1787 try 1852 try
@@ -1808,13 +1873,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1808 { 1873 {
1809 m_currentIncomingClient = null; 1874 m_currentIncomingClient = null;
1810 } 1875 }
1811 } 1876// }
1812 else 1877// else
1813 { 1878// {
1814 m_log.DebugFormat( 1879// m_log.DebugFormat(
1815 "[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}", 1880// "[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}",
1816 packet.Type, client.Name, m_scene.RegionInfo.RegionName); 1881// packet.Type, client.Name, m_scene.RegionInfo.RegionName);
1817 } 1882// }
1818 1883
1819 IncomingPacketsProcessed++; 1884 IncomingPacketsProcessed++;
1820 } 1885 }
@@ -1826,8 +1891,116 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1826 if (!client.IsLoggingOut) 1891 if (!client.IsLoggingOut)
1827 { 1892 {
1828 client.IsLoggingOut = true; 1893 client.IsLoggingOut = true;
1829 client.Close(); 1894 client.Close(false, false);
1895 }
1896 }
1897 }
1898
1899 internal class DoubleQueue<T> where T:class
1900 {
1901 private Queue<T> m_lowQueue = new Queue<T>();
1902 private Queue<T> m_highQueue = new Queue<T>();
1903
1904 private object m_syncRoot = new object();
1905 private Semaphore m_s = new Semaphore(0, 1);
1906
1907 public DoubleQueue()
1908 {
1909 }
1910
1911 public virtual int Count
1912 {
1913 get { return m_highQueue.Count + m_lowQueue.Count; }
1914 }
1915
1916 public virtual void Enqueue(T data)
1917 {
1918 Enqueue(m_lowQueue, data);
1919 }
1920
1921 public virtual void EnqueueLow(T data)
1922 {
1923 Enqueue(m_lowQueue, data);
1924 }
1925
1926 public virtual void EnqueueHigh(T data)
1927 {
1928 Enqueue(m_highQueue, data);
1929 }
1930
1931 private void Enqueue(Queue<T> q, T data)
1932 {
1933 lock (m_syncRoot)
1934 {
1935 m_lowQueue.Enqueue(data);
1936 m_s.WaitOne(0);
1937 m_s.Release();
1938 }
1939 }
1940
1941 public virtual T Dequeue()
1942 {
1943 return Dequeue(Timeout.Infinite);
1944 }
1945
1946 public virtual T Dequeue(int tmo)
1947 {
1948 return Dequeue(TimeSpan.FromMilliseconds(tmo));
1949 }
1950
1951 public virtual T Dequeue(TimeSpan wait)
1952 {
1953 T res = null;
1954
1955 if (!Dequeue(wait, ref res))
1956 return null;
1957
1958 return res;
1959 }
1960
1961 public bool Dequeue(int timeout, ref T res)
1962 {
1963 return Dequeue(TimeSpan.FromMilliseconds(timeout), ref res);
1964 }
1965
1966 public bool Dequeue(TimeSpan wait, ref T res)
1967 {
1968 if (!m_s.WaitOne(wait))
1969 return false;
1970
1971 lock (m_syncRoot)
1972 {
1973 if (m_highQueue.Count > 0)
1974 res = m_highQueue.Dequeue();
1975 else
1976 res = m_lowQueue.Dequeue();
1977
1978 if (m_highQueue.Count == 0 && m_lowQueue.Count == 0)
1979 return true;
1980
1981 try
1982 {
1983 m_s.Release();
1984 }
1985 catch
1986 {
1987 }
1988
1989 return true;
1990 }
1991 }
1992
1993 public virtual void Clear()
1994 {
1995
1996 lock (m_syncRoot)
1997 {
1998 // Make sure sem count is 0
1999 m_s.WaitOne(0);
2000
2001 m_lowQueue.Clear();
2002 m_highQueue.Clear();
1830 } 2003 }
1831 } 2004 }
1832 } 2005 }
1833} \ No newline at end of file 2006}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
index f143c32..7035e38 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
@@ -114,10 +114,6 @@ namespace OpenMetaverse
114 const int SIO_UDP_CONNRESET = -1744830452; 114 const int SIO_UDP_CONNRESET = -1744830452;
115 115
116 IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort); 116 IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort);
117
118 m_log.DebugFormat(
119 "[UDPBASE]: Binding UDP listener using internal IP address config {0}:{1}",
120 ipep.Address, ipep.Port);
121 117
122 m_udpSocket = new Socket( 118 m_udpSocket = new Socket(
123 AddressFamily.InterNetwork, 119 AddressFamily.InterNetwork,