aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/Linden/Caps
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden/Caps')
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs897
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/MeshCost.cs671
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs4
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs11
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs448
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs414
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs18
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs297
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs9
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs196
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs5
11 files changed, 2452 insertions, 518 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
index a46c24a..8241e07 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
@@ -26,6 +26,7 @@
26 */ 26 */
27 27
28using System; 28using System;
29using System.Timers;
29using System.Collections; 30using System.Collections;
30using System.Collections.Generic; 31using System.Collections.Generic;
31using System.IO; 32using System.IO;
@@ -54,14 +55,16 @@ using PermissionMask = OpenSim.Framework.PermissionMask;
54namespace OpenSim.Region.ClientStack.Linden 55namespace OpenSim.Region.ClientStack.Linden
55{ 56{
56 public delegate void UpLoadedAsset( 57 public delegate void UpLoadedAsset(
57 string assetName, string description, UUID assetID, UUID inventoryItem, UUID parentFolder, 58 string assetName, string description, UUID assetID, UUID inventoryItem, UUID parentFolder,
58 byte[] data, string inventoryType, string assetType); 59 byte[] data, string inventoryType, string assetType,
60 int cost, UUID texturesFolder, int nreqtextures, int nreqmeshs, int nreqinstances,
61 bool IsAtestUpload, ref string error);
59 62
60 public delegate UUID UpdateItem(UUID itemID, byte[] data); 63 public delegate UUID UpdateItem(UUID itemID, byte[] data);
61 64
62 public delegate void UpdateTaskScript(UUID itemID, UUID primID, bool isScriptRunning, byte[] data, ref ArrayList errors); 65 public delegate void UpdateTaskScript(UUID itemID, UUID primID, bool isScriptRunning, byte[] data, ref ArrayList errors);
63 66
64 public delegate void NewInventoryItem(UUID userID, InventoryItemBase item); 67 public delegate void NewInventoryItem(UUID userID, InventoryItemBase item, uint cost);
65 68
66 public delegate void NewAsset(AssetBase asset); 69 public delegate void NewAsset(AssetBase asset);
67 70
@@ -87,6 +90,7 @@ namespace OpenSim.Region.ClientStack.Linden
87 90
88 private Scene m_Scene; 91 private Scene m_Scene;
89 private Caps m_HostCapsObj; 92 private Caps m_HostCapsObj;
93 private ModelCost m_ModelCost;
90 94
91 private static readonly string m_requestPath = "0000/"; 95 private static readonly string m_requestPath = "0000/";
92 // private static readonly string m_mapLayerPath = "0001/"; 96 // private static readonly string m_mapLayerPath = "0001/";
@@ -98,7 +102,8 @@ namespace OpenSim.Region.ClientStack.Linden
98 private static readonly string m_copyFromNotecardPath = "0007/"; 102 private static readonly string m_copyFromNotecardPath = "0007/";
99 // private static readonly string m_remoteParcelRequestPath = "0009/";// This is in the LandManagementModule. 103 // private static readonly string m_remoteParcelRequestPath = "0009/";// This is in the LandManagementModule.
100 private static readonly string m_getObjectPhysicsDataPath = "0101/"; 104 private static readonly string m_getObjectPhysicsDataPath = "0101/";
101 /* 0102 - 0103 RESERVED */ 105 private static readonly string m_getObjectCostPath = "0102/";
106 private static readonly string m_ResourceCostSelectedPath = "0103/";
102 private static readonly string m_UpdateAgentInformationPath = "0500/"; 107 private static readonly string m_UpdateAgentInformationPath = "0500/";
103 108
104 // These are callbacks which will be setup by the scene so that we can update scene data when we 109 // These are callbacks which will be setup by the scene so that we can update scene data when we
@@ -114,12 +119,50 @@ namespace OpenSim.Region.ClientStack.Linden
114 private IAssetService m_assetService; 119 private IAssetService m_assetService;
115 private bool m_dumpAssetsToFile = false; 120 private bool m_dumpAssetsToFile = false;
116 private string m_regionName; 121 private string m_regionName;
122
117 private int m_levelUpload = 0; 123 private int m_levelUpload = 0;
118 124
125 private bool m_enableFreeTestUpload = false; // allows "TEST-" prefix hack
126 private bool m_ForceFreeTestUpload = false; // forces all uploads to be test
127
128 private bool m_enableModelUploadTextureToInventory = false; // place uploaded textures also in inventory
129 // may not be visible till relog
130
131 private bool m_RestrictFreeTestUploadPerms = false; // reduces also the permitions. Needs a creator defined!!
132 private UUID m_testAssetsCreatorID = UUID.Zero;
133
134 private float m_PrimScaleMin = 0.001f;
135
136 private enum FileAgentInventoryState : int
137 {
138 idle = 0,
139 processRequest = 1,
140 waitUpload = 2,
141 processUpload = 3
142 }
143 private FileAgentInventoryState m_FileAgentInventoryState = FileAgentInventoryState.idle;
144
119 public BunchOfCaps(Scene scene, Caps caps) 145 public BunchOfCaps(Scene scene, Caps caps)
120 { 146 {
121 m_Scene = scene; 147 m_Scene = scene;
122 m_HostCapsObj = caps; 148 m_HostCapsObj = caps;
149
150 // create a model upload cost provider
151 m_ModelCost = new ModelCost();
152 // tell it about scene object limits
153 m_ModelCost.NonPhysicalPrimScaleMax = m_Scene.m_maxNonphys;
154 m_ModelCost.PhysicalPrimScaleMax = m_Scene.m_maxPhys;
155
156// m_ModelCost.ObjectLinkedPartsMax = ??
157// m_ModelCost.PrimScaleMin = ??
158
159 m_PrimScaleMin = m_ModelCost.PrimScaleMin;
160 float modelTextureUploadFactor = m_ModelCost.ModelTextureCostFactor;
161 float modelUploadFactor = m_ModelCost.ModelMeshCostFactor;
162 float modelMinUploadCostFactor = m_ModelCost.ModelMinCostFactor;
163 float modelPrimCreationCost = m_ModelCost.primCreationCost;
164 float modelMeshByteCost = m_ModelCost.bytecost;
165
123 IConfigSource config = m_Scene.Config; 166 IConfigSource config = m_Scene.Config;
124 if (config != null) 167 if (config != null)
125 { 168 {
@@ -134,6 +177,37 @@ namespace OpenSim.Region.ClientStack.Linden
134 { 177 {
135 m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures); 178 m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures);
136 } 179 }
180 // economy for model upload
181 IConfig EconomyConfig = config.Configs["Economy"];
182 if (EconomyConfig != null)
183 {
184 modelUploadFactor = EconomyConfig.GetFloat("MeshModelUploadCostFactor", modelUploadFactor);
185 modelTextureUploadFactor = EconomyConfig.GetFloat("MeshModelUploadTextureCostFactor", modelTextureUploadFactor);
186 modelMinUploadCostFactor = EconomyConfig.GetFloat("MeshModelMinCostFactor", modelMinUploadCostFactor);
187 // next 2 are normalized so final cost is afected by modelUploadFactor above and normal cost
188 modelPrimCreationCost = EconomyConfig.GetFloat("ModelPrimCreationCost", modelPrimCreationCost);
189 modelMeshByteCost = EconomyConfig.GetFloat("ModelMeshByteCost", modelMeshByteCost);
190
191 m_enableModelUploadTextureToInventory = EconomyConfig.GetBoolean("MeshModelAllowTextureToInventory", m_enableModelUploadTextureToInventory);
192
193 m_RestrictFreeTestUploadPerms = EconomyConfig.GetBoolean("m_RestrictFreeTestUploadPerms", m_RestrictFreeTestUploadPerms);
194 m_enableFreeTestUpload = EconomyConfig.GetBoolean("AllowFreeTestUpload", m_enableFreeTestUpload);
195 m_ForceFreeTestUpload = EconomyConfig.GetBoolean("ForceFreeTestUpload", m_ForceFreeTestUpload);
196 string testcreator = EconomyConfig.GetString("TestAssetsCreatorID", "");
197 if (testcreator != "")
198 {
199 UUID id;
200 UUID.TryParse(testcreator, out id);
201 if (id != null)
202 m_testAssetsCreatorID = id;
203 }
204
205 m_ModelCost.ModelMeshCostFactor = modelUploadFactor;
206 m_ModelCost.ModelTextureCostFactor = modelTextureUploadFactor;
207 m_ModelCost.ModelMinCostFactor = modelMinUploadCostFactor;
208 m_ModelCost.primCreationCost = modelPrimCreationCost;
209 m_ModelCost.bytecost = modelMeshByteCost;
210 }
137 } 211 }
138 212
139 m_assetService = m_Scene.AssetService; 213 m_assetService = m_Scene.AssetService;
@@ -145,6 +219,8 @@ namespace OpenSim.Region.ClientStack.Linden
145 ItemUpdatedCall = m_Scene.CapsUpdateInventoryItemAsset; 219 ItemUpdatedCall = m_Scene.CapsUpdateInventoryItemAsset;
146 TaskScriptUpdatedCall = m_Scene.CapsUpdateTaskInventoryScriptAsset; 220 TaskScriptUpdatedCall = m_Scene.CapsUpdateTaskInventoryScriptAsset;
147 GetClient = m_Scene.SceneGraph.GetControllingClient; 221 GetClient = m_Scene.SceneGraph.GetControllingClient;
222
223 m_FileAgentInventoryState = FileAgentInventoryState.idle;
148 } 224 }
149 225
150 /// <summary> 226 /// <summary>
@@ -190,7 +266,6 @@ namespace OpenSim.Region.ClientStack.Linden
190 { 266 {
191 try 267 try
192 { 268 {
193 // I don't think this one works...
194 m_HostCapsObj.RegisterHandler( 269 m_HostCapsObj.RegisterHandler(
195 "NewFileAgentInventory", 270 "NewFileAgentInventory",
196 new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDAssetUploadResponse>( 271 new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDAssetUploadResponse>(
@@ -209,6 +284,10 @@ namespace OpenSim.Region.ClientStack.Linden
209 m_HostCapsObj.RegisterHandler("UpdateScriptAgent", req); 284 m_HostCapsObj.RegisterHandler("UpdateScriptAgent", req);
210 IRequestHandler getObjectPhysicsDataHandler = new RestStreamHandler("POST", capsBase + m_getObjectPhysicsDataPath, GetObjectPhysicsData); 285 IRequestHandler getObjectPhysicsDataHandler = new RestStreamHandler("POST", capsBase + m_getObjectPhysicsDataPath, GetObjectPhysicsData);
211 m_HostCapsObj.RegisterHandler("GetObjectPhysicsData", getObjectPhysicsDataHandler); 286 m_HostCapsObj.RegisterHandler("GetObjectPhysicsData", getObjectPhysicsDataHandler);
287 IRequestHandler getObjectCostHandler = new RestStreamHandler("POST", capsBase + m_getObjectCostPath, GetObjectCost);
288 m_HostCapsObj.RegisterHandler("GetObjectCost", getObjectCostHandler);
289 IRequestHandler ResourceCostSelectedHandler = new RestStreamHandler("POST", capsBase + m_ResourceCostSelectedPath, ResourceCostSelected);
290 m_HostCapsObj.RegisterHandler("ResourceCostSelected", ResourceCostSelectedHandler);
212 IRequestHandler UpdateAgentInformationHandler = new RestStreamHandler("POST", capsBase + m_UpdateAgentInformationPath, UpdateAgentInformation); 291 IRequestHandler UpdateAgentInformationHandler = new RestStreamHandler("POST", capsBase + m_UpdateAgentInformationPath, UpdateAgentInformation);
213 m_HostCapsObj.RegisterHandler("UpdateAgentInformation", UpdateAgentInformationHandler); 292 m_HostCapsObj.RegisterHandler("UpdateAgentInformation", UpdateAgentInformationHandler);
214 293
@@ -264,6 +343,9 @@ namespace OpenSim.Region.ClientStack.Linden
264 m_log.DebugFormat( 343 m_log.DebugFormat(
265 "[CAPS]: Received SEED caps request in {0} for agent {1}", m_regionName, m_HostCapsObj.AgentID); 344 "[CAPS]: Received SEED caps request in {0} for agent {1}", m_regionName, m_HostCapsObj.AgentID);
266 345
346 if (!m_HostCapsObj.WaitForActivation())
347 return string.Empty;
348
267 if (!m_Scene.CheckClient(m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint)) 349 if (!m_Scene.CheckClient(m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint))
268 { 350 {
269 m_log.WarnFormat( 351 m_log.WarnFormat(
@@ -404,62 +486,176 @@ namespace OpenSim.Region.ClientStack.Linden
404 //m_log.Debug("[CAPS]: NewAgentInventoryRequest Request is: " + llsdRequest.ToString()); 486 //m_log.Debug("[CAPS]: NewAgentInventoryRequest Request is: " + llsdRequest.ToString());
405 //m_log.Debug("asset upload request via CAPS" + llsdRequest.inventory_type + " , " + llsdRequest.asset_type); 487 //m_log.Debug("asset upload request via CAPS" + llsdRequest.inventory_type + " , " + llsdRequest.asset_type);
406 488
489 // start by getting the client
490 IClientAPI client = null;
491 m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client);
492
493 // check current state so we only have one service at a time
494 lock (m_ModelCost)
495 {
496 switch (m_FileAgentInventoryState)
497 {
498 case FileAgentInventoryState.processRequest:
499 case FileAgentInventoryState.processUpload:
500 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
501 resperror.message = "Uploader busy processing previus request";
502 resperror.identifier = UUID.Zero;
503
504 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
505 errorResponse.uploader = "";
506 errorResponse.state = "error";
507 errorResponse.error = resperror;
508 return errorResponse;
509 break;
510 case FileAgentInventoryState.waitUpload:
511 // todo stop current uploader server
512 break;
513 case FileAgentInventoryState.idle:
514 default:
515 break;
516 }
517
518 m_FileAgentInventoryState = FileAgentInventoryState.processRequest;
519 }
520
521 int cost = 0;
522 int nreqtextures = 0;
523 int nreqmeshs= 0;
524 int nreqinstances = 0;
525 bool IsAtestUpload = false;
526
527 string assetName = llsdRequest.name;
528
529 LLSDAssetUploadResponseData meshcostdata = new LLSDAssetUploadResponseData();
530
407 if (llsdRequest.asset_type == "texture" || 531 if (llsdRequest.asset_type == "texture" ||
408 llsdRequest.asset_type == "animation" || 532 llsdRequest.asset_type == "animation" ||
533 llsdRequest.asset_type == "mesh" ||
409 llsdRequest.asset_type == "sound") 534 llsdRequest.asset_type == "sound")
410 { 535 {
411 ScenePresence avatar = null; 536 ScenePresence avatar = null;
412 IClientAPI client = null;
413 m_Scene.TryGetScenePresence(m_HostCapsObj.AgentID, out avatar); 537 m_Scene.TryGetScenePresence(m_HostCapsObj.AgentID, out avatar);
414 538
415 // check user level 539 // check user level
416 if (avatar != null) 540 if (avatar != null)
417 { 541 {
418 client = avatar.ControllingClient;
419
420 if (avatar.UserLevel < m_levelUpload) 542 if (avatar.UserLevel < m_levelUpload)
421 { 543 {
422 if (client != null) 544 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
423 client.SendAgentAlertMessage("Unable to upload asset. Insufficient permissions.", false); 545 resperror.message = "Insufficient permissions to upload";
546 resperror.identifier = UUID.Zero;
424 547
425 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse(); 548 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
426 errorResponse.uploader = ""; 549 errorResponse.uploader = "";
427 errorResponse.state = "error"; 550 errorResponse.state = "error";
551 errorResponse.error = resperror;
552 lock (m_ModelCost)
553 m_FileAgentInventoryState = FileAgentInventoryState.idle;
428 return errorResponse; 554 return errorResponse;
429 } 555 }
430 } 556 }
431 557
432 // check funds 558 // check test upload and funds
433 if (client != null) 559 if (client != null)
434 { 560 {
435 IMoneyModule mm = m_Scene.RequestModuleInterface<IMoneyModule>(); 561 IMoneyModule mm = m_Scene.RequestModuleInterface<IMoneyModule>();
436 562
563 int baseCost = 0;
437 if (mm != null) 564 if (mm != null)
565 baseCost = mm.UploadCharge;
566
567 string warning = String.Empty;
568
569 if (llsdRequest.asset_type == "mesh")
438 { 570 {
439 if (!mm.UploadCovered(client.AgentId, mm.UploadCharge)) 571 string error;
572 int modelcost;
573
574 if (!m_ModelCost.MeshModelCost(llsdRequest.asset_resources, baseCost, out modelcost,
575 meshcostdata, out error, ref warning))
440 { 576 {
441 client.SendAgentAlertMessage("Unable to upload asset. Insufficient funds.", false); 577 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
578 resperror.message = error;
579 resperror.identifier = UUID.Zero;
442 580
443 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse(); 581 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
444 errorResponse.uploader = ""; 582 errorResponse.uploader = "";
445 errorResponse.state = "error"; 583 errorResponse.state = "error";
584 errorResponse.error = resperror;
585
586 lock (m_ModelCost)
587 m_FileAgentInventoryState = FileAgentInventoryState.idle;
446 return errorResponse; 588 return errorResponse;
447 } 589 }
590 cost = modelcost;
591 }
592 else
593 {
594 cost = baseCost;
595 }
596
597 if (cost > 0 && mm != null)
598 {
599 // check for test upload
600
601 if (m_ForceFreeTestUpload) // all are test
602 {
603 if (!(assetName.Length > 5 && assetName.StartsWith("TEST-"))) // has normal name lets change it
604 assetName = "TEST-" + assetName;
605
606 IsAtestUpload = true;
607 }
608
609 else if (m_enableFreeTestUpload) // only if prefixed with "TEST-"
610 {
611
612 IsAtestUpload = (assetName.Length > 5 && assetName.StartsWith("TEST-"));
613 }
614
615
616 if(IsAtestUpload) // let user know, still showing cost estimation
617 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";
618
619 // check funds
620 else
621 {
622 if (!mm.UploadCovered(client.AgentId, (int)cost))
623 {
624 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
625 resperror.message = "Insuficient funds";
626 resperror.identifier = UUID.Zero;
627
628 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
629 errorResponse.uploader = "";
630 errorResponse.state = "error";
631 errorResponse.error = resperror;
632 lock (m_ModelCost)
633 m_FileAgentInventoryState = FileAgentInventoryState.idle;
634 return errorResponse;
635 }
636 }
448 } 637 }
638
639 if (client != null && warning != String.Empty)
640 client.SendAgentAlertMessage(warning, true);
449 } 641 }
450 } 642 }
451 643
452 string assetName = llsdRequest.name;
453 string assetDes = llsdRequest.description; 644 string assetDes = llsdRequest.description;
454 string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath; 645 string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath;
455 UUID newAsset = UUID.Random(); 646 UUID newAsset = UUID.Random();
456 UUID newInvItem = UUID.Random(); 647 UUID newInvItem = UUID.Random();
457 UUID parentFolder = llsdRequest.folder_id; 648 UUID parentFolder = llsdRequest.folder_id;
458 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000"); 649 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000");
650 UUID texturesFolder = UUID.Zero;
651
652 if(!IsAtestUpload && m_enableModelUploadTextureToInventory)
653 texturesFolder = llsdRequest.texture_folder_id;
459 654
460 AssetUploader uploader = 655 AssetUploader uploader =
461 new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type, 656 new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type,
462 llsdRequest.asset_type, capsBase + uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile); 657 llsdRequest.asset_type, capsBase + uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile, cost,
658 texturesFolder, nreqtextures, nreqmeshs, nreqinstances, IsAtestUpload);
463 659
464 m_HostCapsObj.HttpListener.AddStreamHandler( 660 m_HostCapsObj.HttpListener.AddStreamHandler(
465 new BinaryStreamHandler( 661 new BinaryStreamHandler(
@@ -477,10 +673,22 @@ namespace OpenSim.Region.ClientStack.Linden
477 string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase + 673 string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase +
478 uploaderPath; 674 uploaderPath;
479 675
676
480 LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse(); 677 LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse();
481 uploadResponse.uploader = uploaderURL; 678 uploadResponse.uploader = uploaderURL;
482 uploadResponse.state = "upload"; 679 uploadResponse.state = "upload";
680 uploadResponse.upload_price = (int)cost;
681
682 if (llsdRequest.asset_type == "mesh")
683 {
684 uploadResponse.data = meshcostdata;
685 }
686
483 uploader.OnUpLoad += UploadCompleteHandler; 687 uploader.OnUpLoad += UploadCompleteHandler;
688
689 lock (m_ModelCost)
690 m_FileAgentInventoryState = FileAgentInventoryState.waitUpload;
691
484 return uploadResponse; 692 return uploadResponse;
485 } 693 }
486 694
@@ -492,8 +700,14 @@ namespace OpenSim.Region.ClientStack.Linden
492 /// <param name="data"></param> 700 /// <param name="data"></param>
493 public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID, 701 public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID,
494 UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType, 702 UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType,
495 string assetType) 703 string assetType, int cost,
704 UUID texturesFolder, int nreqtextures, int nreqmeshs, int nreqinstances,
705 bool IsAtestUpload, ref string error)
496 { 706 {
707
708 lock (m_ModelCost)
709 m_FileAgentInventoryState = FileAgentInventoryState.processUpload;
710
497 m_log.DebugFormat( 711 m_log.DebugFormat(
498 "[BUNCH OF CAPS]: Uploaded asset {0} for inventory item {1}, inv type {2}, asset type {3}", 712 "[BUNCH OF CAPS]: Uploaded asset {0} for inventory item {1}, inv type {2}, asset type {3}",
499 assetID, inventoryItem, inventoryType, assetType); 713 assetID, inventoryItem, inventoryType, assetType);
@@ -501,117 +715,247 @@ namespace OpenSim.Region.ClientStack.Linden
501 sbyte assType = 0; 715 sbyte assType = 0;
502 sbyte inType = 0; 716 sbyte inType = 0;
503 717
718 IClientAPI client = null;
719
720 UUID owner_id = m_HostCapsObj.AgentID;
721 UUID creatorID;
722
723 bool istest = IsAtestUpload && m_enableFreeTestUpload && (cost > 0);
724
725 bool restrictPerms = m_RestrictFreeTestUploadPerms && istest;
726
727 if (istest && m_testAssetsCreatorID != UUID.Zero)
728 creatorID = m_testAssetsCreatorID;
729 else
730 creatorID = owner_id;
731
732 string creatorIDstr = creatorID.ToString();
733
734 IMoneyModule mm = m_Scene.RequestModuleInterface<IMoneyModule>();
735 if (mm != null)
736 {
737 // make sure client still has enougth credit
738 if (!mm.UploadCovered(m_HostCapsObj.AgentID, (int)cost))
739 {
740 error = "Insufficient funds.";
741 return;
742 }
743 }
744
745 // strings to types
504 if (inventoryType == "sound") 746 if (inventoryType == "sound")
505 { 747 {
506 inType = 1; 748 inType = (sbyte)InventoryType.Sound;
507 assType = 1; 749 assType = (sbyte)AssetType.Sound;
508 } 750 }
509 else if (inventoryType == "animation") 751 else if (inventoryType == "animation")
510 { 752 {
511 inType = 19; 753 inType = (sbyte)InventoryType.Animation;
512 assType = 20; 754 assType = (sbyte)AssetType.Animation;
513 } 755 }
514 else if (inventoryType == "wearable") 756 else if (inventoryType == "wearable")
515 { 757 {
516 inType = 18; 758 inType = (sbyte)InventoryType.Wearable;
517 switch (assetType) 759 switch (assetType)
518 { 760 {
519 case "bodypart": 761 case "bodypart":
520 assType = 13; 762 assType = (sbyte)AssetType.Bodypart;
521 break; 763 break;
522 case "clothing": 764 case "clothing":
523 assType = 5; 765 assType = (sbyte)AssetType.Clothing;
524 break; 766 break;
525 } 767 }
526 } 768 }
527 else if (inventoryType == "object") 769 else if (inventoryType == "object")
528 { 770 {
529 inType = (sbyte)InventoryType.Object; 771 if (assetType == "mesh") // this code for now is for mesh models uploads only
530 assType = (sbyte)AssetType.Object;
531
532 List<Vector3> positions = new List<Vector3>();
533 List<Quaternion> rotations = new List<Quaternion>();
534 OSDMap request = (OSDMap)OSDParser.DeserializeLLSDXml(data);
535 OSDArray instance_list = (OSDArray)request["instance_list"];
536 OSDArray mesh_list = (OSDArray)request["mesh_list"];
537 OSDArray texture_list = (OSDArray)request["texture_list"];
538 SceneObjectGroup grp = null;
539
540 List<UUID> textures = new List<UUID>();
541 for (int i = 0; i < texture_list.Count; i++)
542 { 772 {
543 AssetBase textureAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Texture, ""); 773 inType = (sbyte)InventoryType.Object;
544 textureAsset.Data = texture_list[i].AsBinary(); 774 assType = (sbyte)AssetType.Object;
545 m_assetService.Store(textureAsset);
546 textures.Add(textureAsset.FullID);
547 }
548 775
549 for (int i = 0; i < mesh_list.Count; i++) 776 List<Vector3> positions = new List<Vector3>();
550 { 777 List<Quaternion> rotations = new List<Quaternion>();
551 PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateBox(); 778 OSDMap request = (OSDMap)OSDParser.DeserializeLLSDXml(data);
552 779
553 Primitive.TextureEntry textureEntry 780 // compare and get updated information
554 = new Primitive.TextureEntry(Primitive.TextureEntry.WHITE_TEXTURE);
555 OSDMap inner_instance_list = (OSDMap)instance_list[i];
556 781
557 OSDArray face_list = (OSDArray)inner_instance_list["face_list"]; 782 bool mismatchError = true;
558 for (uint face = 0; face < face_list.Count; face++) 783
784 while (mismatchError)
559 { 785 {
560 OSDMap faceMap = (OSDMap)face_list[(int)face]; 786 mismatchError = false;
561 Primitive.TextureEntryFace f = pbs.Textures.CreateFace(face); 787 }
562 if(faceMap.ContainsKey("fullbright"))
563 f.Fullbright = faceMap["fullbright"].AsBoolean();
564 if (faceMap.ContainsKey ("diffuse_color"))
565 f.RGBA = faceMap["diffuse_color"].AsColor4();
566 788
567 int textureNum = faceMap["image"].AsInteger(); 789 if (mismatchError)
568 float imagerot = faceMap["imagerot"].AsInteger(); 790 {
569 float offsets = (float)faceMap["offsets"].AsReal(); 791 error = "Upload and fee estimation information don't match";
570 float offsett = (float)faceMap["offsett"].AsReal(); 792 lock (m_ModelCost)
571 float scales = (float)faceMap["scales"].AsReal(); 793 m_FileAgentInventoryState = FileAgentInventoryState.idle;
572 float scalet = (float)faceMap["scalet"].AsReal();
573 794
574 if(imagerot != 0) 795 return;
575 f.Rotation = imagerot; 796 }
576 797
577 if(offsets != 0) 798 OSDArray instance_list = (OSDArray)request["instance_list"];
578 f.OffsetU = offsets; 799 OSDArray mesh_list = (OSDArray)request["mesh_list"];
800 OSDArray texture_list = (OSDArray)request["texture_list"];
801 SceneObjectGroup grp = null;
579 802
580 if (offsett != 0) 803 // create and store texture assets
581 f.OffsetV = offsett; 804 bool doTextInv = (!istest && m_enableModelUploadTextureToInventory &&
805 texturesFolder != UUID.Zero);
582 806
583 if (scales != 0)
584 f.RepeatU = scales;
585 807
586 if (scalet != 0) 808 List<UUID> textures = new List<UUID>();
587 f.RepeatV = scalet;
588 809
589 if (textures.Count > textureNum) 810
590 f.TextureID = textures[textureNum]; 811 if (doTextInv)
591 else 812 m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client);
592 f.TextureID = Primitive.TextureEntry.WHITE_TEXTURE;
593 813
594 textureEntry.FaceTextures[face] = f; 814 if(client == null) // don't put textures in inventory if there is no client
815 doTextInv = false;
816
817 for (int i = 0; i < texture_list.Count; i++)
818 {
819 AssetBase textureAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Texture, creatorIDstr);
820 textureAsset.Data = texture_list[i].AsBinary();
821 if (istest)
822 textureAsset.Local = true;
823 m_assetService.Store(textureAsset);
824 textures.Add(textureAsset.FullID);
825
826 if (doTextInv)
827 {
828 string name = assetName;
829 if (name.Length > 25)
830 name = name.Substring(0, 24);
831 name += "_Texture#" + i.ToString();
832 InventoryItemBase texitem = new InventoryItemBase();
833 texitem.Owner = m_HostCapsObj.AgentID;
834 texitem.CreatorId = creatorIDstr;
835 texitem.CreatorData = String.Empty;
836 texitem.ID = UUID.Random();
837 texitem.AssetID = textureAsset.FullID;
838 texitem.Description = "mesh model texture";
839 texitem.Name = name;
840 texitem.AssetType = (int)AssetType.Texture;
841 texitem.InvType = (int)InventoryType.Texture;
842 texitem.Folder = texturesFolder;
843
844 texitem.CurrentPermissions
845 = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer | PermissionMask.Export);
846
847 texitem.BasePermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export;
848 texitem.EveryOnePermissions = 0;
849 texitem.NextPermissions = (uint)PermissionMask.All;
850 texitem.CreationDate = Util.UnixTimeSinceEpoch();
851
852 m_Scene.AddInventoryItem(client, texitem);
853 texitem = null;
854 }
595 } 855 }
596 856
597 pbs.TextureEntry = textureEntry.GetBytes(); 857 // create and store meshs assets
858 List<UUID> meshAssets = new List<UUID>();
859 for (int i = 0; i < mesh_list.Count; i++)
860 {
861 AssetBase meshAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Mesh, creatorIDstr);
862 meshAsset.Data = mesh_list[i].AsBinary();
863 if (istest)
864 meshAsset.Local = true;
865 m_assetService.Store(meshAsset);
866 meshAssets.Add(meshAsset.FullID);
867 }
868
869 int skipedMeshs = 0;
870 // build prims from instances
871 for (int i = 0; i < instance_list.Count; i++)
872 {
873 OSDMap inner_instance_list = (OSDMap)instance_list[i];
874
875 // skip prims that are 2 small
876 Vector3 scale = inner_instance_list["scale"].AsVector3();
877
878 if (scale.X < m_PrimScaleMin || scale.Y < m_PrimScaleMin || scale.Z < m_PrimScaleMin)
879 {
880 skipedMeshs++;
881 continue;
882 }
883
884 PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateBox();
885
886 Primitive.TextureEntry textureEntry
887 = new Primitive.TextureEntry(Primitive.TextureEntry.WHITE_TEXTURE);
888
598 889
599 AssetBase meshAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Mesh, ""); 890 OSDArray face_list = (OSDArray)inner_instance_list["face_list"];
600 meshAsset.Data = mesh_list[i].AsBinary(); 891 for (uint face = 0; face < face_list.Count; face++)
601 m_assetService.Store(meshAsset); 892 {
893 OSDMap faceMap = (OSDMap)face_list[(int)face];
894 Primitive.TextureEntryFace f = pbs.Textures.CreateFace(face);
895 if (faceMap.ContainsKey("fullbright"))
896 f.Fullbright = faceMap["fullbright"].AsBoolean();
897 if (faceMap.ContainsKey("diffuse_color"))
898 f.RGBA = faceMap["diffuse_color"].AsColor4();
899
900 int textureNum = faceMap["image"].AsInteger();
901 float imagerot = faceMap["imagerot"].AsInteger();
902 float offsets = (float)faceMap["offsets"].AsReal();
903 float offsett = (float)faceMap["offsett"].AsReal();
904 float scales = (float)faceMap["scales"].AsReal();
905 float scalet = (float)faceMap["scalet"].AsReal();
906
907 if (imagerot != 0)
908 f.Rotation = imagerot;
909
910 if (offsets != 0)
911 f.OffsetU = offsets;
602 912
603 pbs.SculptEntry = true; 913 if (offsett != 0)
604 pbs.SculptTexture = meshAsset.FullID; 914 f.OffsetV = offsett;
605 pbs.SculptType = (byte)SculptType.Mesh;
606 pbs.SculptData = meshAsset.Data;
607 915
608 Vector3 position = inner_instance_list["position"].AsVector3(); 916 if (scales != 0)
609 Vector3 scale = inner_instance_list["scale"].AsVector3(); 917 f.RepeatU = scales;
610 Quaternion rotation = inner_instance_list["rotation"].AsQuaternion(); 918
919 if (scalet != 0)
920 f.RepeatV = scalet;
921
922 if (textures.Count > textureNum)
923 f.TextureID = textures[textureNum];
924 else
925 f.TextureID = Primitive.TextureEntry.WHITE_TEXTURE;
926
927 textureEntry.FaceTextures[face] = f;
928 }
929
930 pbs.TextureEntry = textureEntry.GetBytes();
931
932 bool hasmesh = false;
933 if (inner_instance_list.ContainsKey("mesh")) // seems to happen always but ...
934 {
935 int meshindx = inner_instance_list["mesh"].AsInteger();
936 if (meshAssets.Count > meshindx)
937 {
938 pbs.SculptEntry = true;
939 pbs.SculptType = (byte)SculptType.Mesh;
940 pbs.SculptTexture = meshAssets[meshindx]; // actual asset UUID after meshs suport introduction
941 // data will be requested from asset on rez (i hope)
942 hasmesh = true;
943 }
944 }
945
946 Vector3 position = inner_instance_list["position"].AsVector3();
947 Quaternion rotation = inner_instance_list["rotation"].AsQuaternion();
948
949 // for now viwers do send fixed defaults
950 // but this may change
951// int physicsShapeType = inner_instance_list["physics_shape_type"].AsInteger();
952 byte physicsShapeType = (byte)PhysShapeType.prim; // default for mesh is simple convex
953 if(hasmesh)
954 physicsShapeType = (byte) PhysShapeType.convex; // default for mesh is simple convex
955// int material = inner_instance_list["material"].AsInteger();
956 byte material = (byte)Material.Wood;
611 957
612// no longer used - begin ------------------------ 958// no longer used - begin ------------------------
613// int physicsShapeType = inner_instance_list["physics_shape_type"].AsInteger();
614// int material = inner_instance_list["material"].AsInteger();
615// int mesh = inner_instance_list["mesh"].AsInteger(); 959// int mesh = inner_instance_list["mesh"].AsInteger();
616 960
617// OSDMap permissions = (OSDMap)inner_instance_list["permissions"]; 961// OSDMap permissions = (OSDMap)inner_instance_list["permissions"];
@@ -626,24 +970,49 @@ namespace OpenSim.Region.ClientStack.Linden
626// UUID owner_id = permissions["owner_id"].AsUUID(); 970// UUID owner_id = permissions["owner_id"].AsUUID();
627// int owner_mask = permissions["owner_mask"].AsInteger(); 971// int owner_mask = permissions["owner_mask"].AsInteger();
628// no longer used - end ------------------------ 972// no longer used - end ------------------------
973
974
975 SceneObjectPart prim
976 = new SceneObjectPart(owner_id, pbs, position, Quaternion.Identity, Vector3.Zero);
977
978 prim.Scale = scale;
979 rotations.Add(rotation);
980 positions.Add(position);
981 prim.UUID = UUID.Random();
982 prim.CreatorID = creatorID;
983 prim.OwnerID = owner_id;
984 prim.GroupID = UUID.Zero;
985 prim.LastOwnerID = creatorID;
986 prim.CreationDate = Util.UnixTimeSinceEpoch();
987
988 if (grp == null)
989 prim.Name = assetName;
990 else
991 prim.Name = assetName + "#" + i.ToString();
629 992
630 UUID owner_id = m_HostCapsObj.AgentID; 993 prim.EveryoneMask = 0;
994 prim.GroupMask = 0;
631 995
632 SceneObjectPart prim 996 if (restrictPerms)
633 = new SceneObjectPart(owner_id, pbs, position, Quaternion.Identity, Vector3.Zero); 997 {
998 prim.BaseMask = (uint)(PermissionMask.Move | PermissionMask.Modify);
999 prim.OwnerMask = (uint)(PermissionMask.Move | PermissionMask.Modify);
1000 prim.NextOwnerMask = 0;
1001 }
1002 else
1003 {
1004 prim.BaseMask = (uint)PermissionMask.All | (uint)PermissionMask.Export;
1005 prim.OwnerMask = (uint)PermissionMask.All | (uint)PermissionMask.Export;
1006 prim.NextOwnerMask = (uint)PermissionMask.Transfer;
1007 }
1008
1009 if(istest)
1010 prim.Description = "For testing only. Other uses are prohibited";
1011 else
1012 prim.Description = "";
634 1013
635 prim.Scale = scale; 1014 prim.Material = material;
636 //prim.OffsetPosition = position; 1015 prim.PhysicsShapeType = physicsShapeType;
637 rotations.Add(rotation);
638 positions.Add(position);
639 prim.UUID = UUID.Random();
640 prim.CreatorID = owner_id;
641 prim.OwnerID = owner_id;
642 prim.GroupID = UUID.Zero;
643 prim.LastOwnerID = prim.OwnerID;
644 prim.CreationDate = Util.UnixTimeSinceEpoch();
645 prim.Name = assetName;
646 prim.Description = "";
647 1016
648// prim.BaseMask = (uint)base_mask; 1017// prim.BaseMask = (uint)base_mask;
649// prim.EveryoneMask = (uint)everyone_mask; 1018// prim.EveryoneMask = (uint)everyone_mask;
@@ -651,52 +1020,64 @@ namespace OpenSim.Region.ClientStack.Linden
651// prim.NextOwnerMask = (uint)next_owner_mask; 1020// prim.NextOwnerMask = (uint)next_owner_mask;
652// prim.OwnerMask = (uint)owner_mask; 1021// prim.OwnerMask = (uint)owner_mask;
653 1022
654 if (grp == null) 1023 if (grp == null)
655 grp = new SceneObjectGroup(prim); 1024 {
656 else 1025 grp = new SceneObjectGroup(prim);
657 grp.AddPart(prim); 1026 grp.LastOwnerID = creatorID;
658 } 1027 }
1028 else
1029 grp.AddPart(prim);
1030 }
659 1031
660 Vector3 rootPos = positions[0]; 1032 Vector3 rootPos = positions[0];
661 1033
662 if (grp.Parts.Length > 1) 1034 if (grp.Parts.Length > 1)
663 { 1035 {
664 // Fix first link number 1036 // Fix first link number
665 grp.RootPart.LinkNum++; 1037 grp.RootPart.LinkNum++;
666 1038
667 Quaternion rootRotConj = Quaternion.Conjugate(rotations[0]); 1039 Quaternion rootRotConj = Quaternion.Conjugate(rotations[0]);
668 Quaternion tmprot; 1040 Quaternion tmprot;
669 Vector3 offset; 1041 Vector3 offset;
670 1042
671 // fix children rotations and positions 1043 // fix children rotations and positions
672 for (int i = 1; i < rotations.Count; i++) 1044 for (int i = 1; i < rotations.Count; i++)
673 { 1045 {
674 tmprot = rotations[i]; 1046 tmprot = rotations[i];
675 tmprot = rootRotConj * tmprot; 1047 tmprot = rootRotConj * tmprot;
1048
1049 grp.Parts[i].RotationOffset = tmprot;
676 1050
677 grp.Parts[i].RotationOffset = tmprot; 1051 offset = positions[i] - rootPos;
678 1052
679 offset = positions[i] - rootPos; 1053 offset *= rootRotConj;
1054 grp.Parts[i].OffsetPosition = offset;
1055 }
680 1056
681 offset *= rootRotConj; 1057 grp.AbsolutePosition = rootPos;
682 grp.Parts[i].OffsetPosition = offset; 1058 grp.UpdateGroupRotationR(rotations[0]);
1059 }
1060 else
1061 {
1062 grp.AbsolutePosition = rootPos;
1063 grp.UpdateGroupRotationR(rotations[0]);
683 } 1064 }
684 1065
685 grp.AbsolutePosition = rootPos; 1066 data = ASCIIEncoding.ASCII.GetBytes(SceneObjectSerializer.ToOriginalXmlFormat(grp));
686 grp.UpdateGroupRotationR(rotations[0]);
687 } 1067 }
688 else 1068
1069 else // not a mesh model
689 { 1070 {
690 grp.AbsolutePosition = rootPos; 1071 m_log.ErrorFormat("[CAPS Asset Upload] got unsuported assetType for object upload");
691 grp.UpdateGroupRotationR(rotations[0]); 1072 return;
692 } 1073 }
693
694 data = ASCIIEncoding.ASCII.GetBytes(SceneObjectSerializer.ToOriginalXmlFormat(grp));
695 } 1074 }
696 1075
697 AssetBase asset; 1076 AssetBase asset;
698 asset = new AssetBase(assetID, assetName, assType, m_HostCapsObj.AgentID.ToString()); 1077 asset = new AssetBase(assetID, assetName, assType, creatorIDstr);
699 asset.Data = data; 1078 asset.Data = data;
1079 if (istest)
1080 asset.Local = true;
700 if (AddNewAsset != null) 1081 if (AddNewAsset != null)
701 AddNewAsset(asset); 1082 AddNewAsset(asset);
702 else if (m_assetService != null) 1083 else if (m_assetService != null)
@@ -704,11 +1085,17 @@ namespace OpenSim.Region.ClientStack.Linden
704 1085
705 InventoryItemBase item = new InventoryItemBase(); 1086 InventoryItemBase item = new InventoryItemBase();
706 item.Owner = m_HostCapsObj.AgentID; 1087 item.Owner = m_HostCapsObj.AgentID;
707 item.CreatorId = m_HostCapsObj.AgentID.ToString(); 1088 item.CreatorId = creatorIDstr;
708 item.CreatorData = String.Empty; 1089 item.CreatorData = String.Empty;
709 item.ID = inventoryItem; 1090 item.ID = inventoryItem;
710 item.AssetID = asset.FullID; 1091 item.AssetID = asset.FullID;
711 item.Description = assetDescription; 1092 if (istest)
1093 {
1094 item.Description = "For testing only. Other uses are prohibited";
1095 item.Flags = (uint) (InventoryItemFlags.SharedSingleReference);
1096 }
1097 else
1098 item.Description = assetDescription;
712 item.Name = assetName; 1099 item.Name = assetName;
713 item.AssetType = assType; 1100 item.AssetType = assType;
714 item.InvType = inType; 1101 item.InvType = inType;
@@ -716,18 +1103,56 @@ namespace OpenSim.Region.ClientStack.Linden
716 1103
717 // If we set PermissionMask.All then when we rez the item the next permissions will replace the current 1104 // If we set PermissionMask.All then when we rez the item the next permissions will replace the current
718 // (owner) permissions. This becomes a problem if next permissions are changed. 1105 // (owner) permissions. This becomes a problem if next permissions are changed.
719 item.CurrentPermissions
720 = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer | PermissionMask.Export);
721 1106
722 item.BasePermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export; 1107 if (restrictPerms)
723 item.EveryOnePermissions = 0; 1108 {
724 item.NextPermissions = (uint)PermissionMask.All; 1109 item.BasePermissions = (uint)(PermissionMask.Move | PermissionMask.Modify);
1110 item.CurrentPermissions = (uint)(PermissionMask.Move | PermissionMask.Modify);
1111 item.EveryOnePermissions = 0;
1112 item.NextPermissions = 0;
1113 }
1114 else
1115 {
1116 item.BasePermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export;
1117 item.CurrentPermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export;
1118 item.EveryOnePermissions = 0;
1119 item.NextPermissions = (uint)PermissionMask.Transfer;
1120 }
1121
725 item.CreationDate = Util.UnixTimeSinceEpoch(); 1122 item.CreationDate = Util.UnixTimeSinceEpoch();
726 1123
1124 m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client);
1125
727 if (AddNewInventoryItem != null) 1126 if (AddNewInventoryItem != null)
728 { 1127 {
729 AddNewInventoryItem(m_HostCapsObj.AgentID, item); 1128 if (istest)
1129 {
1130 m_Scene.AddInventoryItem(client, item);
1131/*
1132 AddNewInventoryItem(m_HostCapsObj.AgentID, item, 0);
1133 if (client != null)
1134 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);
1135 */
1136 }
1137 else
1138 {
1139 AddNewInventoryItem(m_HostCapsObj.AgentID, item, (uint)cost);
1140// if (client != null)
1141// {
1142// // let users see anything.. i don't so far
1143// string str;
1144// if (cost > 0)
1145// // dont remember where is money unit name to put here
1146// str = "Upload complete. charged " + cost.ToString() + "$";
1147// else
1148// str = "Upload complete";
1149// client.SendAgentAlertMessage(str, true);
1150// }
1151 }
730 } 1152 }
1153
1154 lock (m_ModelCost)
1155 m_FileAgentInventoryState = FileAgentInventoryState.idle;
731 } 1156 }
732 1157
733 /// <summary> 1158 /// <summary>
@@ -920,6 +1345,120 @@ namespace OpenSim.Region.ClientStack.Linden
920 return response; 1345 return response;
921 } 1346 }
922 1347
1348 public string GetObjectCost(string request, string path,
1349 string param, IOSHttpRequest httpRequest,
1350 IOSHttpResponse httpResponse)
1351 {
1352 OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request);
1353 OSDMap resp = new OSDMap();
1354
1355 OSDArray object_ids = (OSDArray)req["object_ids"];
1356
1357 for (int i = 0; i < object_ids.Count; i++)
1358 {
1359 UUID uuid = object_ids[i].AsUUID();
1360
1361 SceneObjectPart part = m_Scene.GetSceneObjectPart(uuid);
1362
1363 if (part != null)
1364 {
1365 SceneObjectGroup grp = part.ParentGroup;
1366 if (grp != null)
1367 {
1368 float linksetCost;
1369 float linksetPhysCost;
1370 float partCost;
1371 float partPhysCost;
1372
1373 grp.GetResourcesCosts(part, out linksetCost, out linksetPhysCost, out partCost, out partPhysCost);
1374
1375 OSDMap object_data = new OSDMap();
1376 object_data["linked_set_resource_cost"] = linksetCost;
1377 object_data["resource_cost"] = partCost;
1378 object_data["physics_cost"] = partPhysCost;
1379 object_data["linked_set_physics_cost"] = linksetPhysCost;
1380
1381 resp[uuid.ToString()] = object_data;
1382 }
1383 }
1384 }
1385
1386 string response = OSDParser.SerializeLLSDXmlString(resp);
1387 return response;
1388 }
1389
1390 public string ResourceCostSelected(string request, string path,
1391 string param, IOSHttpRequest httpRequest,
1392 IOSHttpResponse httpResponse)
1393 {
1394 OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request);
1395 OSDMap resp = new OSDMap();
1396
1397
1398 float phys=0;
1399 float stream=0;
1400 float simul=0;
1401
1402 if (req.ContainsKey("selected_roots"))
1403 {
1404 OSDArray object_ids = (OSDArray)req["selected_roots"];
1405
1406 // should go by SOG suming costs for all parts
1407 // ll v3 works ok with several objects select we get the list and adds ok
1408 // FS calls per object so results are wrong guess fs bug
1409 for (int i = 0; i < object_ids.Count; i++)
1410 {
1411 UUID uuid = object_ids[i].AsUUID();
1412 float Physc;
1413 float simulc;
1414 float streamc;
1415
1416 SceneObjectGroup grp = m_Scene.GetGroupByPrim(uuid);
1417 if (grp != null)
1418 {
1419 grp.GetSelectedCosts(out Physc, out streamc, out simulc);
1420 phys += Physc;
1421 stream += streamc;
1422 simul += simulc;
1423 }
1424 }
1425 }
1426 else if (req.ContainsKey("selected_prims"))
1427 {
1428 OSDArray object_ids = (OSDArray)req["selected_prims"];
1429
1430 // don't see in use in any of the 2 viewers
1431 // guess it should be for edit linked but... nothing
1432 // should go to SOP per part
1433 for (int i = 0; i < object_ids.Count; i++)
1434 {
1435 UUID uuid = object_ids[i].AsUUID();
1436
1437 SceneObjectPart part = m_Scene.GetSceneObjectPart(uuid);
1438 if (part != null)
1439 {
1440 phys += part.PhysicsCost;
1441 stream += part.StreamingCost;
1442 simul += part.SimulationCost;
1443 }
1444 }
1445 }
1446
1447 if (simul != 0)
1448 {
1449 OSDMap object_data = new OSDMap();
1450
1451 object_data["physics"] = phys;
1452 object_data["streaming"] = stream;
1453 object_data["simulation"] = simul;
1454
1455 resp["selected"] = object_data;
1456 }
1457
1458 string response = OSDParser.SerializeLLSDXmlString(resp);
1459 return response;
1460 }
1461
923 public string UpdateAgentInformation(string request, string path, 1462 public string UpdateAgentInformation(string request, string path,
924 string param, IOSHttpRequest httpRequest, 1463 string param, IOSHttpRequest httpRequest,
925 IOSHttpResponse httpResponse) 1464 IOSHttpResponse httpResponse)
@@ -939,6 +1478,10 @@ namespace OpenSim.Region.ClientStack.Linden
939 1478
940 public class AssetUploader 1479 public class AssetUploader
941 { 1480 {
1481 private static readonly ILog m_log =
1482 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
1483
1484
942 public event UpLoadedAsset OnUpLoad; 1485 public event UpLoadedAsset OnUpLoad;
943 private UpLoadedAsset handlerUpLoad = null; 1486 private UpLoadedAsset handlerUpLoad = null;
944 1487
@@ -953,10 +1496,21 @@ namespace OpenSim.Region.ClientStack.Linden
953 1496
954 private string m_invType = String.Empty; 1497 private string m_invType = String.Empty;
955 private string m_assetType = String.Empty; 1498 private string m_assetType = String.Empty;
1499 private int m_cost;
1500 private string m_error = String.Empty;
1501
1502 private Timer m_timeoutTimer = new Timer();
1503 private UUID m_texturesFolder;
1504 private int m_nreqtextures;
1505 private int m_nreqmeshs;
1506 private int m_nreqinstances;
1507 private bool m_IsAtestUpload;
956 1508
957 public AssetUploader(string assetName, string description, UUID assetID, UUID inventoryItem, 1509 public AssetUploader(string assetName, string description, UUID assetID, UUID inventoryItem,
958 UUID parentFolderID, string invType, string assetType, string path, 1510 UUID parentFolderID, string invType, string assetType, string path,
959 IHttpServer httpServer, bool dumpAssetsToFile) 1511 IHttpServer httpServer, bool dumpAssetsToFile,
1512 int totalCost, UUID texturesFolder, int nreqtextures, int nreqmeshs, int nreqinstances,
1513 bool IsAtestUpload)
960 { 1514 {
961 m_assetName = assetName; 1515 m_assetName = assetName;
962 m_assetDes = description; 1516 m_assetDes = description;
@@ -968,6 +1522,18 @@ namespace OpenSim.Region.ClientStack.Linden
968 m_assetType = assetType; 1522 m_assetType = assetType;
969 m_invType = invType; 1523 m_invType = invType;
970 m_dumpAssetsToFile = dumpAssetsToFile; 1524 m_dumpAssetsToFile = dumpAssetsToFile;
1525 m_cost = totalCost;
1526
1527 m_texturesFolder = texturesFolder;
1528 m_nreqtextures = nreqtextures;
1529 m_nreqmeshs = nreqmeshs;
1530 m_nreqinstances = nreqinstances;
1531 m_IsAtestUpload = IsAtestUpload;
1532
1533 m_timeoutTimer.Elapsed += TimedOut;
1534 m_timeoutTimer.Interval = 120000;
1535 m_timeoutTimer.AutoReset = false;
1536 m_timeoutTimer.Start();
971 } 1537 }
972 1538
973 /// <summary> 1539 /// <summary>
@@ -982,12 +1548,14 @@ namespace OpenSim.Region.ClientStack.Linden
982 UUID inv = inventoryItemID; 1548 UUID inv = inventoryItemID;
983 string res = String.Empty; 1549 string res = String.Empty;
984 LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete(); 1550 LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete();
1551/*
985 uploadComplete.new_asset = newAssetID.ToString(); 1552 uploadComplete.new_asset = newAssetID.ToString();
986 uploadComplete.new_inventory_item = inv; 1553 uploadComplete.new_inventory_item = inv;
987 uploadComplete.state = "complete"; 1554 uploadComplete.state = "complete";
988 1555
989 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete); 1556 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
990 1557*/
1558 m_timeoutTimer.Stop();
991 httpListener.RemoveStreamHandler("POST", uploaderPath); 1559 httpListener.RemoveStreamHandler("POST", uploaderPath);
992 1560
993 // TODO: probably make this a better set of extensions here 1561 // TODO: probably make this a better set of extensions here
@@ -1004,12 +1572,49 @@ namespace OpenSim.Region.ClientStack.Linden
1004 handlerUpLoad = OnUpLoad; 1572 handlerUpLoad = OnUpLoad;
1005 if (handlerUpLoad != null) 1573 if (handlerUpLoad != null)
1006 { 1574 {
1007 handlerUpLoad(m_assetName, m_assetDes, newAssetID, inv, parentFolder, data, m_invType, m_assetType); 1575 handlerUpLoad(m_assetName, m_assetDes, newAssetID, inv, parentFolder, data, m_invType, m_assetType,
1576 m_cost, m_texturesFolder, m_nreqtextures, m_nreqmeshs, m_nreqinstances, m_IsAtestUpload, ref m_error);
1577 }
1578 if (m_IsAtestUpload)
1579 {
1580 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
1581 resperror.message = "Upload SUCESSEFULL for testing purposes only. Other uses are prohibited. Item will not work after 48 hours or on other regions";
1582 resperror.identifier = inv;
1583
1584 uploadComplete.error = resperror;
1585 uploadComplete.state = "Upload4Testing";
1008 } 1586 }
1587 else
1588 {
1589 if (m_error == String.Empty)
1590 {
1591 uploadComplete.new_asset = newAssetID.ToString();
1592 uploadComplete.new_inventory_item = inv;
1593 // if (m_texturesFolder != UUID.Zero)
1594 // uploadComplete.new_texture_folder_id = m_texturesFolder;
1595 uploadComplete.state = "complete";
1596 }
1597 else
1598 {
1599 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
1600 resperror.message = m_error;
1601 resperror.identifier = inv;
1009 1602
1603 uploadComplete.error = resperror;
1604 uploadComplete.state = "failed";
1605 }
1606 }
1607
1608 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
1010 return res; 1609 return res;
1011 } 1610 }
1012 1611
1612 private void TimedOut(object sender, ElapsedEventArgs args)
1613 {
1614 m_log.InfoFormat("[CAPS]: Removing URL and handler for timed out mesh upload");
1615 httpListener.RemoveStreamHandler("POST", uploaderPath);
1616 }
1617
1013 ///Left this in and commented in case there are unforseen issues 1618 ///Left this in and commented in case there are unforseen issues
1014 //private void SaveAssetToFile(string filename, byte[] data) 1619 //private void SaveAssetToFile(string filename, byte[] data)
1015 //{ 1620 //{
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 e73a04a..eb40eb1 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
@@ -490,8 +490,8 @@ namespace OpenSim.Region.ClientStack.Linden
490 responsedata["content_type"] = "text/plain"; 490 responsedata["content_type"] = "text/plain";
491 responsedata["keepalive"] = false; 491 responsedata["keepalive"] = false;
492 responsedata["reusecontext"] = false; 492 responsedata["reusecontext"] = false;
493 responsedata["str_response_string"] = "Upstream error: "; 493 responsedata["str_response_string"] = "<llsd></llsd>";
494 responsedata["error_status_text"] = "Upstream error:"; 494 responsedata["error_status_text"] = "<llsd></llsd>";
495 responsedata["http_protocol_version"] = "HTTP/1.0"; 495 responsedata["http_protocol_version"] = "HTTP/1.0";
496 return responsedata; 496 return responsedata;
497 } 497 }
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs
index dab727f..7dcf137 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs
@@ -151,6 +151,12 @@ namespace OpenSim.Region.ClientStack.Linden
151 ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint, 151 ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint,
152 uint locationID, uint flags, string capsURL, UUID agentID) 152 uint locationID, uint flags, string capsURL, UUID agentID)
153 { 153 {
154 // not sure why flags get overwritten here
155 if ((flags & (uint)TeleportFlags.IsFlying) != 0)
156 flags = (uint)TeleportFlags.ViaLocation | (uint)TeleportFlags.IsFlying;
157 else
158 flags = (uint)TeleportFlags.ViaLocation;
159
154 OSDMap info = new OSDMap(); 160 OSDMap info = new OSDMap();
155 info.Add("AgentID", OSD.FromUUID(agentID)); 161 info.Add("AgentID", OSD.FromUUID(agentID));
156 info.Add("LocationID", OSD.FromInteger(4)); // TODO what is this? 162 info.Add("LocationID", OSD.FromInteger(4)); // TODO what is this?
@@ -159,7 +165,8 @@ namespace OpenSim.Region.ClientStack.Linden
159 info.Add("SimAccess", OSD.FromInteger(simAccess)); 165 info.Add("SimAccess", OSD.FromInteger(simAccess));
160 info.Add("SimIP", OSD.FromBinary(regionExternalEndPoint.Address.GetAddressBytes())); 166 info.Add("SimIP", OSD.FromBinary(regionExternalEndPoint.Address.GetAddressBytes()));
161 info.Add("SimPort", OSD.FromInteger(regionExternalEndPoint.Port)); 167 info.Add("SimPort", OSD.FromInteger(regionExternalEndPoint.Port));
162 info.Add("TeleportFlags", OSD.FromULong(1L << 4)); // AgentManager.TeleportFlags.ViaLocation 168// info.Add("TeleportFlags", OSD.FromULong(1L << 4)); // AgentManager.TeleportFlags.ViaLocation
169 info.Add("TeleportFlags", OSD.FromUInteger(flags));
163 170
164 OSDArray infoArr = new OSDArray(); 171 OSDArray infoArr = new OSDArray();
165 infoArr.Add(info); 172 infoArr.Add(info);
@@ -398,7 +405,7 @@ namespace OpenSim.Region.ClientStack.Linden
398 public static OSD partPhysicsProperties(uint localID, byte physhapetype, 405 public static OSD partPhysicsProperties(uint localID, byte physhapetype,
399 float density, float friction, float bounce, float gravmod) 406 float density, float friction, float bounce, float gravmod)
400 { 407 {
401 408
402 OSDMap physinfo = new OSDMap(6); 409 OSDMap physinfo = new OSDMap(6);
403 physinfo["LocalID"] = localID; 410 physinfo["LocalID"] = localID;
404 physinfo["Density"] = density; 411 physinfo["Density"] = density;
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs
index 8e1f63a..6ec1115 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs
@@ -27,11 +27,14 @@
27 27
28using System; 28using System;
29using System.Collections; 29using System.Collections;
30using System.Collections.Generic;
30using System.Collections.Specialized; 31using System.Collections.Specialized;
31using System.Reflection; 32using System.Reflection;
32using System.IO; 33using System.IO;
34using System.Threading;
33using System.Web; 35using System.Web;
34using Mono.Addins; 36using Mono.Addins;
37using OpenSim.Framework.Monitoring;
35using log4net; 38using log4net;
36using Nini.Config; 39using Nini.Config;
37using OpenMetaverse; 40using OpenMetaverse;
@@ -57,9 +60,45 @@ namespace OpenSim.Region.ClientStack.Linden
57 private IAssetService m_AssetService; 60 private IAssetService m_AssetService;
58 private bool m_Enabled = true; 61 private bool m_Enabled = true;
59 private string m_URL; 62 private string m_URL;
63
64 struct aPollRequest
65 {
66 public PollServiceMeshEventArgs thepoll;
67 public UUID reqID;
68 public Hashtable request;
69 }
70
71 public class aPollResponse
72 {
73 public Hashtable response;
74 public int bytes;
75 public int lod;
76 }
77
78
79 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
80
81 private static GetMeshHandler m_getMeshHandler;
82
83 private IAssetService m_assetService = null;
84
85 private Dictionary<UUID, string> m_capsDict = new Dictionary<UUID, string>();
86 private static Thread[] m_workerThreads = null;
87
88 private static OpenMetaverse.BlockingQueue<aPollRequest> m_queue =
89 new OpenMetaverse.BlockingQueue<aPollRequest>();
90
91 private Dictionary<UUID, PollServiceMeshEventArgs> m_pollservices = new Dictionary<UUID, PollServiceMeshEventArgs>();
60 92
61 #region Region Module interfaceBase Members 93 #region Region Module interfaceBase Members
62 94
95 ~GetMeshModule()
96 {
97 foreach (Thread t in m_workerThreads)
98 Watchdog.AbortThread(t.ManagedThreadId);
99
100 }
101
63 public Type ReplaceableInterface 102 public Type ReplaceableInterface
64 { 103 {
65 get { return null; } 104 get { return null; }
@@ -75,6 +114,7 @@ namespace OpenSim.Region.ClientStack.Linden
75 // Cap doesn't exist 114 // Cap doesn't exist
76 if (m_URL != string.Empty) 115 if (m_URL != string.Empty)
77 m_Enabled = true; 116 m_Enabled = true;
117
78 } 118 }
79 119
80 public void AddRegion(Scene pScene) 120 public void AddRegion(Scene pScene)
@@ -83,6 +123,8 @@ namespace OpenSim.Region.ClientStack.Linden
83 return; 123 return;
84 124
85 m_scene = pScene; 125 m_scene = pScene;
126
127 m_assetService = pScene.AssetService;
86 } 128 }
87 129
88 public void RemoveRegion(Scene scene) 130 public void RemoveRegion(Scene scene)
@@ -91,6 +133,9 @@ namespace OpenSim.Region.ClientStack.Linden
91 return; 133 return;
92 134
93 m_scene.EventManager.OnRegisterCaps -= RegisterCaps; 135 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
136 m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps;
137 m_scene.EventManager.OnThrottleUpdate -= ThrottleUpdate;
138
94 m_scene = null; 139 m_scene = null;
95 } 140 }
96 141
@@ -101,6 +146,27 @@ namespace OpenSim.Region.ClientStack.Linden
101 146
102 m_AssetService = m_scene.RequestModuleInterface<IAssetService>(); 147 m_AssetService = m_scene.RequestModuleInterface<IAssetService>();
103 m_scene.EventManager.OnRegisterCaps += RegisterCaps; 148 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
149 // We'll reuse the same handler for all requests.
150 m_getMeshHandler = new GetMeshHandler(m_assetService);
151 m_scene.EventManager.OnDeregisterCaps += DeregisterCaps;
152 m_scene.EventManager.OnThrottleUpdate += ThrottleUpdate;
153
154 if (m_workerThreads == null)
155 {
156 m_workerThreads = new Thread[2];
157
158 for (uint i = 0; i < 2; i++)
159 {
160 m_workerThreads[i] = Watchdog.StartThread(DoMeshRequests,
161 String.Format("MeshWorkerThread{0}", i),
162 ThreadPriority.Normal,
163 false,
164 false,
165 null,
166 int.MaxValue);
167 }
168 }
169
104 } 170 }
105 171
106 172
@@ -110,25 +176,212 @@ namespace OpenSim.Region.ClientStack.Linden
110 176
111 #endregion 177 #endregion
112 178
179 private void DoMeshRequests()
180 {
181 while (true)
182 {
183 aPollRequest poolreq = m_queue.Dequeue();
184
185 poolreq.thepoll.Process(poolreq);
186 }
187 }
188
189 // Now we know when the throttle is changed by the client in the case of a root agent or by a neighbor region in the case of a child agent.
190 public void ThrottleUpdate(ScenePresence p)
191 {
192 byte[] throttles = p.ControllingClient.GetThrottlesPacked(1);
193 UUID user = p.UUID;
194 int imagethrottle = ExtractTaskThrottle(throttles);
195 PollServiceMeshEventArgs args;
196 if (m_pollservices.TryGetValue(user, out args))
197 {
198 args.UpdateThrottle(imagethrottle, p);
199 }
200 }
201
202 private int ExtractTaskThrottle(byte[] pthrottles)
203 {
204
205 byte[] adjData;
206 int pos = 0;
207
208 if (!BitConverter.IsLittleEndian)
209 {
210 byte[] newData = new byte[7 * 4];
211 Buffer.BlockCopy(pthrottles, 0, newData, 0, 7 * 4);
212
213 for (int i = 0; i < 7; i++)
214 Array.Reverse(newData, i * 4, 4);
215
216 adjData = newData;
217 }
218 else
219 {
220 adjData = pthrottles;
221 }
222
223 // 0.125f converts from bits to bytes
224 //int resend = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
225 //pos += 4;
226 // int land = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
227 //pos += 4;
228 // int wind = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
229 // pos += 4;
230 // int cloud = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
231 // pos += 4;
232 pos += 16;
233 int task = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
234 // pos += 4;
235 //int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); //pos += 4;
236 //int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
237 return task;
238 }
239
240 private class PollServiceMeshEventArgs : PollServiceEventArgs
241 {
242 private List<Hashtable> requests =
243 new List<Hashtable>();
244 private Dictionary<UUID, aPollResponse> responses =
245 new Dictionary<UUID, aPollResponse>();
246
247 private Scene m_scene;
248 private MeshCapsDataThrottler m_throttler;
249 public PollServiceMeshEventArgs(UUID pId, Scene scene) :
250 base(null, null, null, null, pId, int.MaxValue)
251 {
252 m_scene = scene;
253 m_throttler = new MeshCapsDataThrottler(100000, 1400000, 10000, scene, pId);
254 // x is request id, y is userid
255 HasEvents = (x, y) =>
256 {
257 lock (responses)
258 {
259 bool ret = m_throttler.hasEvents(x, responses);
260 m_throttler.ProcessTime();
261 return ret;
262
263 }
264 };
265 GetEvents = (x, y) =>
266 {
267 lock (responses)
268 {
269 try
270 {
271 return responses[x].response;
272 }
273 finally
274 {
275 m_throttler.ProcessTime();
276 responses.Remove(x);
277 }
278 }
279 };
280 // x is request id, y is request data hashtable
281 Request = (x, y) =>
282 {
283 aPollRequest reqinfo = new aPollRequest();
284 reqinfo.thepoll = this;
285 reqinfo.reqID = x;
286 reqinfo.request = y;
287
288 m_queue.Enqueue(reqinfo);
289 };
290
291 // this should never happen except possible on shutdown
292 NoEvents = (x, y) =>
293 {
294 /*
295 lock (requests)
296 {
297 Hashtable request = requests.Find(id => id["RequestID"].ToString() == x.ToString());
298 requests.Remove(request);
299 }
300 */
301 Hashtable response = new Hashtable();
302
303 response["int_response_code"] = 500;
304 response["str_response_string"] = "Script timeout";
305 response["content_type"] = "text/plain";
306 response["keepalive"] = false;
307 response["reusecontext"] = false;
308
309 return response;
310 };
311 }
312
313 public void Process(aPollRequest requestinfo)
314 {
315 Hashtable response;
316
317 UUID requestID = requestinfo.reqID;
318
319 // If the avatar is gone, don't bother to get the texture
320 if (m_scene.GetScenePresence(Id) == null)
321 {
322 response = new Hashtable();
323
324 response["int_response_code"] = 500;
325 response["str_response_string"] = "Script timeout";
326 response["content_type"] = "text/plain";
327 response["keepalive"] = false;
328 response["reusecontext"] = false;
329
330 lock (responses)
331 responses[requestID] = new aPollResponse() { bytes = 0, response = response, lod = 0 };
332
333 return;
334 }
335
336 response = m_getMeshHandler.Handle(requestinfo.request);
337 lock (responses)
338 {
339 responses[requestID] = new aPollResponse()
340 {
341 bytes = (int)response["int_bytes"],
342 lod = (int)response["int_lod"],
343 response = response
344 };
345
346 }
347 m_throttler.ProcessTime();
348 }
349
350 internal void UpdateThrottle(int pimagethrottle, ScenePresence p)
351 {
352 m_throttler.UpdateThrottle(pimagethrottle, p);
353 }
354 }
113 355
114 public void RegisterCaps(UUID agentID, Caps caps) 356 public void RegisterCaps(UUID agentID, Caps caps)
115 { 357 {
116// UUID capID = UUID.Random(); 358// UUID capID = UUID.Random();
117
118 //caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture));
119 if (m_URL == "localhost") 359 if (m_URL == "localhost")
120 { 360 {
121// m_log.DebugFormat("[GETMESH]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName); 361 string capUrl = "/CAPS/" + UUID.Random() + "/";
122 GetMeshHandler gmeshHandler = new GetMeshHandler(m_AssetService); 362
123 IRequestHandler reqHandler 363 // Register this as a poll service
124 = new RestHTTPHandler( 364 PollServiceMeshEventArgs args = new PollServiceMeshEventArgs(agentID, m_scene);
125 "GET", 365
126 "/CAPS/" + UUID.Random(), 366 args.Type = PollServiceEventArgs.EventType.Mesh;
127 httpMethod => gmeshHandler.ProcessGetMesh(httpMethod, UUID.Zero, null), 367 MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args);
128 "GetMesh", 368
129 agentID.ToString()); 369 string hostName = m_scene.RegionInfo.ExternalHostName;
370 uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port;
371 string protocol = "http";
130 372
131 caps.RegisterHandler("GetMesh", reqHandler); 373 if (MainServer.Instance.UseSSL)
374 {
375 hostName = MainServer.Instance.SSLCommonName;
376 port = MainServer.Instance.SSLPort;
377 protocol = "https";
378 }
379 caps.RegisterHandler("GetMesh", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl));
380 m_pollservices[agentID] = args;
381 m_capsDict[agentID] = capUrl;
382
383
384
132 } 385 }
133 else 386 else
134 { 387 {
@@ -136,6 +389,177 @@ namespace OpenSim.Region.ClientStack.Linden
136 caps.RegisterHandler("GetMesh", m_URL); 389 caps.RegisterHandler("GetMesh", m_URL);
137 } 390 }
138 } 391 }
392 private void DeregisterCaps(UUID agentID, Caps caps)
393 {
394 string capUrl;
395 PollServiceMeshEventArgs args;
396 if (m_capsDict.TryGetValue(agentID, out capUrl))
397 {
398 MainServer.Instance.RemoveHTTPHandler("", capUrl);
399 m_capsDict.Remove(agentID);
400 }
401 if (m_pollservices.TryGetValue(agentID, out args))
402 {
403 m_pollservices.Remove(agentID);
404 }
405 }
406
407 internal sealed class MeshCapsDataThrottler
408 {
409
410 private volatile int currenttime = 0;
411 private volatile int lastTimeElapsed = 0;
412 private volatile int BytesSent = 0;
413 private int Lod3 = 0;
414 private int Lod2 = 0;
415 private int Lod1 = 0;
416 private int UserSetThrottle = 0;
417 private int UDPSetThrottle = 0;
418 private int CapSetThrottle = 0;
419 private float CapThrottleDistributon = 0.30f;
420 private readonly Scene m_scene;
421 private ThrottleOutPacketType Throttle;
422 private readonly UUID User;
423
424 public MeshCapsDataThrottler(int pBytes, int max, int min, Scene pScene, UUID puser)
425 {
426 ThrottleBytes = pBytes;
427 lastTimeElapsed = Util.EnvironmentTickCount();
428 Throttle = ThrottleOutPacketType.Task;
429 m_scene = pScene;
430 User = puser;
431 }
432
433
434 public bool hasEvents(UUID key, Dictionary<UUID, aPollResponse> responses)
435 {
436 const float ThirtyPercent = 0.30f;
437 const float FivePercent = 0.05f;
438 PassTime();
439 // Note, this is called IN LOCK
440 bool haskey = responses.ContainsKey(key);
441
442 if (responses.Count > 2)
443 {
444 SplitThrottle(ThirtyPercent);
445 }
446 else
447 {
448 SplitThrottle(FivePercent);
449 }
450
451 if (!haskey)
452 {
453 return false;
454 }
455 aPollResponse response;
456 if (responses.TryGetValue(key, out response))
457 {
458 float LOD3Over = (((ThrottleBytes*CapThrottleDistributon)%50000) + 1);
459 float LOD2Over = (((ThrottleBytes*CapThrottleDistributon)%10000) + 1);
460 // Normal
461 if (BytesSent + response.bytes <= ThrottleBytes)
462 {
463 BytesSent += response.bytes;
464
465 return true;
466 }
467 // Lod3 Over Throttle protection to keep things processing even when the throttle bandwidth is set too little.
468 else if (response.bytes > ThrottleBytes && Lod3 <= ((LOD3Over < 1)? 1: LOD3Over) )
469 {
470 Interlocked.Increment(ref Lod3);
471 BytesSent += response.bytes;
472
473 return true;
474 }
475 // Lod2 Over Throttle protection to keep things processing even when the throttle bandwidth is set too little.
476 else if (response.bytes > ThrottleBytes && Lod2 <= ((LOD2Over < 1) ? 1 : LOD2Over))
477 {
478 Interlocked.Increment(ref Lod2);
479 BytesSent += response.bytes;
480
481 return true;
482 }
483 else
484 {
485 return false;
486 }
487 }
488
489 return haskey;
490 }
491 public void SubtractBytes(int bytes,int lod)
492 {
493 BytesSent -= bytes;
494 }
495 private void SplitThrottle(float percentMultiplier)
496 {
497
498 if (CapThrottleDistributon != percentMultiplier) // don't switch it if it's already set at the % multipler
499 {
500 CapThrottleDistributon = percentMultiplier;
501 ScenePresence p;
502 if (m_scene.TryGetScenePresence(User, out p)) // If we don't get a user they're not here anymore.
503 {
504// AlterThrottle(UserSetThrottle, p);
505 UpdateThrottle(UserSetThrottle, p);
506 }
507 }
508 }
509
510 public void ProcessTime()
511 {
512 PassTime();
513 }
514
515
516 private void PassTime()
517 {
518 currenttime = Util.EnvironmentTickCount();
519 int timeElapsed = Util.EnvironmentTickCountSubtract(currenttime, lastTimeElapsed);
520 //processTimeBasedActions(responses);
521 if (currenttime - timeElapsed >= 1000)
522 {
523 lastTimeElapsed = Util.EnvironmentTickCount();
524 BytesSent -= ThrottleBytes;
525 if (BytesSent < 0) BytesSent = 0;
526 if (BytesSent < ThrottleBytes)
527 {
528 Lod3 = 0;
529 Lod2 = 0;
530 Lod1 = 0;
531 }
532 }
533 }
534 private void AlterThrottle(int setting, ScenePresence p)
535 {
536 p.ControllingClient.SetAgentThrottleSilent((int)Throttle,setting);
537 }
538
539 public int ThrottleBytes
540 {
541 get { return CapSetThrottle; }
542 set { CapSetThrottle = value; }
543 }
544
545 internal void UpdateThrottle(int pimagethrottle, ScenePresence p)
546 {
547 // Client set throttle !
548 UserSetThrottle = pimagethrottle;
549 CapSetThrottle = (int)(pimagethrottle*CapThrottleDistributon);
550// UDPSetThrottle = (int) (pimagethrottle*(100 - CapThrottleDistributon));
551
552 float udp = 1.0f - CapThrottleDistributon;
553 if(udp < 0.5f)
554 udp = 0.5f;
555 UDPSetThrottle = (int) ((float)pimagethrottle * udp);
556 if (CapSetThrottle < 4068)
557 CapSetThrottle = 4068; // at least two discovery mesh
558 p.ControllingClient.SetAgentThrottleSilent((int) Throttle, UDPSetThrottle);
559 ProcessTime();
560
561 }
562 }
139 563
140 } 564 }
141} 565}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs
index 13415f8..a42c96c 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,132 @@ namespace OpenSim.Region.ClientStack.Linden
54 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GetTextureModule")] 50 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GetTextureModule")]
55 public class GetTextureModule : INonSharedRegionModule 51 public class GetTextureModule : INonSharedRegionModule
56 { 52 {
57// private static readonly ILog m_log = 53
58// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 54 struct aPollRequest
59 55 {
56 public PollServiceTextureEventArgs thepoll;
57 public UUID reqID;
58 public Hashtable request;
59 public bool send503;
60 }
61
62 public class aPollResponse
63 {
64 public Hashtable response;
65 public int bytes;
66 }
67
68
69 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
70
60 private Scene m_scene; 71 private Scene m_scene;
61 private IAssetService m_assetService;
62 72
63 private bool m_Enabled = false; 73 private static GetTextureHandler m_getTextureHandler;
64 74
65 // TODO: Change this to a config option 75 private IAssetService m_assetService = null;
66 const string REDIRECT_URL = null;
67 76
68 private string m_URL; 77 private Dictionary<UUID, string> m_capsDict = new Dictionary<UUID, string>();
78 private static Thread[] m_workerThreads = null;
79
80 private static OpenMetaverse.BlockingQueue<aPollRequest> m_queue =
81 new OpenMetaverse.BlockingQueue<aPollRequest>();
82
83 private Dictionary<UUID,PollServiceTextureEventArgs> m_pollservices = new Dictionary<UUID,PollServiceTextureEventArgs>();
69 84
70 #region ISharedRegionModule Members 85 #region ISharedRegionModule Members
71 86
72 public void Initialise(IConfigSource source) 87 public void Initialise(IConfigSource source)
73 { 88 {
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 } 89 }
83 90
84 public void AddRegion(Scene s) 91 public void AddRegion(Scene s)
85 { 92 {
86 if (!m_Enabled)
87 return;
88
89 m_scene = s; 93 m_scene = s;
94 m_assetService = s.AssetService;
90 } 95 }
91 96
92 public void RemoveRegion(Scene s) 97 public void RemoveRegion(Scene s)
93 { 98 {
94 if (!m_Enabled)
95 return;
96
97 m_scene.EventManager.OnRegisterCaps -= RegisterCaps; 99 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
100 m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps;
101 m_scene.EventManager.OnThrottleUpdate -= ThrottleUpdate;
98 m_scene = null; 102 m_scene = null;
99 } 103 }
100 104
101 public void RegionLoaded(Scene s) 105 public void RegionLoaded(Scene s)
102 { 106 {
103 if (!m_Enabled) 107 // We'll reuse the same handler for all requests.
104 return; 108 m_getTextureHandler = new GetTextureHandler(m_assetService);
105 109
106 m_assetService = m_scene.RequestModuleInterface<IAssetService>();
107 m_scene.EventManager.OnRegisterCaps += RegisterCaps; 110 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
111 m_scene.EventManager.OnDeregisterCaps += DeregisterCaps;
112 m_scene.EventManager.OnThrottleUpdate += ThrottleUpdate;
113
114 if (m_workerThreads == null)
115 {
116 m_workerThreads = new Thread[2];
117
118 for (uint i = 0; i < 2; i++)
119 {
120 m_workerThreads[i] = Watchdog.StartThread(DoTextureRequests,
121 String.Format("TextureWorkerThread{0}", i),
122 ThreadPriority.Normal,
123 false,
124 false,
125 null,
126 int.MaxValue);
127 }
128 }
129 }
130 private int ExtractImageThrottle(byte[] pthrottles)
131 {
132
133 byte[] adjData;
134 int pos = 0;
135
136 if (!BitConverter.IsLittleEndian)
137 {
138 byte[] newData = new byte[7 * 4];
139 Buffer.BlockCopy(pthrottles, 0, newData, 0, 7 * 4);
140
141 for (int i = 0; i < 7; i++)
142 Array.Reverse(newData, i * 4, 4);
143
144 adjData = newData;
145 }
146 else
147 {
148 adjData = pthrottles;
149 }
150
151 // 0.125f converts from bits to bytes
152 //int resend = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
153 //pos += 4;
154 // int land = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
155 //pos += 4;
156 // int wind = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
157 // pos += 4;
158 // int cloud = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
159 // pos += 4;
160 // int task = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
161 // pos += 4;
162 pos = pos + 20;
163 int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); //pos += 4;
164 //int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
165 return texture;
166 }
167
168 // 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.
169 public void ThrottleUpdate(ScenePresence p)
170 {
171 byte[] throttles = p.ControllingClient.GetThrottlesPacked(1);
172 UUID user = p.UUID;
173 int imagethrottle = ExtractImageThrottle(throttles);
174 PollServiceTextureEventArgs args;
175 if (m_pollservices.TryGetValue(user,out args))
176 {
177 args.UpdateThrottle(imagethrottle);
178 }
108 } 179 }
109 180
110 public void PostInitialise() 181 public void PostInitialise()
@@ -122,24 +193,281 @@ namespace OpenSim.Region.ClientStack.Linden
122 193
123 #endregion 194 #endregion
124 195
125 public void RegisterCaps(UUID agentID, Caps caps) 196 ~GetTextureModule()
126 { 197 {
127 UUID capID = UUID.Random(); 198 foreach (Thread t in m_workerThreads)
199 Watchdog.AbortThread(t.ManagedThreadId);
128 200
129 //caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture)); 201 }
130 if (m_URL == "localhost") 202
203 private class PollServiceTextureEventArgs : PollServiceEventArgs
204 {
205 private List<Hashtable> requests =
206 new List<Hashtable>();
207 private Dictionary<UUID, aPollResponse> responses =
208 new Dictionary<UUID, aPollResponse>();
209
210 private Scene m_scene;
211 private CapsDataThrottler m_throttler = new CapsDataThrottler(100000, 1400000,10000);
212 public PollServiceTextureEventArgs(UUID pId, Scene scene) :
213 base(null, null, null, null, pId, int.MaxValue)
131 { 214 {
132// m_log.DebugFormat("[GETTEXTURE]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName); 215 m_scene = scene;
133 caps.RegisterHandler( 216 // x is request id, y is userid
134 "GetTexture", 217 HasEvents = (x, y) =>
135 new GetTextureHandler("/CAPS/" + capID + "/", m_assetService, "GetTexture", agentID.ToString())); 218 {
219 lock (responses)
220 {
221 bool ret = m_throttler.hasEvents(x, responses);
222 m_throttler.ProcessTime();
223 return ret;
224
225 }
226 };
227 GetEvents = (x, y) =>
228 {
229 lock (responses)
230 {
231 try
232 {
233 return responses[x].response;
234 }
235 finally
236 {
237 responses.Remove(x);
238 }
239 }
240 };
241 // x is request id, y is request data hashtable
242 Request = (x, y) =>
243 {
244 aPollRequest reqinfo = new aPollRequest();
245 reqinfo.thepoll = this;
246 reqinfo.reqID = x;
247 reqinfo.request = y;
248 reqinfo.send503 = false;
249
250 lock (responses)
251 {
252 if (responses.Count > 0)
253 {
254 if (m_queue.Count >= 4)
255 {
256 // Never allow more than 4 fetches to wait
257 reqinfo.send503 = true;
258 }
259 }
260 }
261 m_queue.Enqueue(reqinfo);
262 };
263
264 // this should never happen except possible on shutdown
265 NoEvents = (x, y) =>
266 {
267/*
268 lock (requests)
269 {
270 Hashtable request = requests.Find(id => id["RequestID"].ToString() == x.ToString());
271 requests.Remove(request);
272 }
273*/
274 Hashtable response = new Hashtable();
275
276 response["int_response_code"] = 500;
277 response["str_response_string"] = "Script timeout";
278 response["content_type"] = "text/plain";
279 response["keepalive"] = false;
280 response["reusecontext"] = false;
281
282 return response;
283 };
136 } 284 }
137 else 285
286 public void Process(aPollRequest requestinfo)
138 { 287 {
139// m_log.DebugFormat("[GETTEXTURE]: {0} in region {1}", m_URL, m_scene.RegionInfo.RegionName); 288 Hashtable response;
140 caps.RegisterHandler("GetTexture", m_URL); 289
290 UUID requestID = requestinfo.reqID;
291
292 if (requestinfo.send503)
293 {
294 response = new Hashtable();
295
296 response["int_response_code"] = 503;
297 response["str_response_string"] = "Throttled";
298 response["content_type"] = "text/plain";
299 response["keepalive"] = false;
300 response["reusecontext"] = false;
301
302 lock (responses)
303 responses[requestID] = new aPollResponse() {bytes = 0, response = response};
304
305 return;
306 }
307
308 // If the avatar is gone, don't bother to get the texture
309 if (m_scene.GetScenePresence(Id) == null)
310 {
311 response = new Hashtable();
312
313 response["int_response_code"] = 500;
314 response["str_response_string"] = "Script timeout";
315 response["content_type"] = "text/plain";
316 response["keepalive"] = false;
317 response["reusecontext"] = false;
318
319 lock (responses)
320 responses[requestID] = new aPollResponse() {bytes = 0, response = response};
321
322 return;
323 }
324
325 response = m_getTextureHandler.Handle(requestinfo.request);
326 lock (responses)
327 {
328 responses[requestID] = new aPollResponse()
329 {
330 bytes = (int) response["int_bytes"],
331 response = response
332 };
333
334 }
335 m_throttler.ProcessTime();
336 }
337
338 internal void UpdateThrottle(int pimagethrottle)
339 {
340 m_throttler.ThrottleBytes = pimagethrottle;
141 } 341 }
142 } 342 }
143 343
344 private void RegisterCaps(UUID agentID, Caps caps)
345 {
346 string capUrl = "/CAPS/" + UUID.Random() + "/";
347
348 // Register this as a poll service
349 PollServiceTextureEventArgs args = new PollServiceTextureEventArgs(agentID, m_scene);
350
351 args.Type = PollServiceEventArgs.EventType.Texture;
352 MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args);
353
354 string hostName = m_scene.RegionInfo.ExternalHostName;
355 uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port;
356 string protocol = "http";
357
358 if (MainServer.Instance.UseSSL)
359 {
360 hostName = MainServer.Instance.SSLCommonName;
361 port = MainServer.Instance.SSLPort;
362 protocol = "https";
363 }
364 caps.RegisterHandler("GetTexture", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl));
365 m_pollservices[agentID] = args;
366 m_capsDict[agentID] = capUrl;
367 }
368
369 private void DeregisterCaps(UUID agentID, Caps caps)
370 {
371 string capUrl;
372 PollServiceTextureEventArgs args;
373 if (m_capsDict.TryGetValue(agentID, out capUrl))
374 {
375 MainServer.Instance.RemoveHTTPHandler("", capUrl);
376 m_capsDict.Remove(agentID);
377 }
378 if (m_pollservices.TryGetValue(agentID, out args))
379 {
380 m_pollservices.Remove(agentID);
381 }
382 }
383
384 private void DoTextureRequests()
385 {
386 while (true)
387 {
388 aPollRequest poolreq = m_queue.Dequeue();
389
390 poolreq.thepoll.Process(poolreq);
391 }
392 }
393 internal sealed class CapsDataThrottler
394 {
395
396 private volatile int currenttime = 0;
397 private volatile int lastTimeElapsed = 0;
398 private volatile int BytesSent = 0;
399 private int oversizedImages = 0;
400 public CapsDataThrottler(int pBytes, int max, int min)
401 {
402 ThrottleBytes = pBytes;
403 lastTimeElapsed = Util.EnvironmentTickCount();
404 }
405 public bool hasEvents(UUID key, Dictionary<UUID, GetTextureModule.aPollResponse> responses)
406 {
407 PassTime();
408 // Note, this is called IN LOCK
409 bool haskey = responses.ContainsKey(key);
410 if (!haskey)
411 {
412 return false;
413 }
414 GetTextureModule.aPollResponse response;
415 if (responses.TryGetValue(key, out response))
416 {
417 // This is any error response
418 if (response.bytes == 0)
419 return true;
420
421 // Normal
422 if (BytesSent + response.bytes <= ThrottleBytes)
423 {
424 BytesSent += response.bytes;
425 //TimeBasedAction timeBasedAction = new TimeBasedAction { byteRemoval = response.bytes, requestId = key, timeMS = currenttime + 1000, unlockyn = false };
426 //m_actions.Add(timeBasedAction);
427 return true;
428 }
429 // Big textures
430 else if (response.bytes > ThrottleBytes && oversizedImages <= ((ThrottleBytes % 50000) + 1))
431 {
432 Interlocked.Increment(ref oversizedImages);
433 BytesSent += response.bytes;
434 //TimeBasedAction timeBasedAction = new TimeBasedAction { byteRemoval = response.bytes, requestId = key, timeMS = currenttime + (((response.bytes % ThrottleBytes)+1)*1000) , unlockyn = false };
435 //m_actions.Add(timeBasedAction);
436 return true;
437 }
438 else
439 {
440 return false;
441 }
442 }
443
444 return haskey;
445 }
446
447 public void ProcessTime()
448 {
449 PassTime();
450 }
451
452 private void PassTime()
453 {
454 currenttime = Util.EnvironmentTickCount();
455 int timeElapsed = Util.EnvironmentTickCountSubtract(currenttime, lastTimeElapsed);
456 //processTimeBasedActions(responses);
457 if (Util.EnvironmentTickCountSubtract(currenttime, timeElapsed) >= 1000)
458 {
459 lastTimeElapsed = Util.EnvironmentTickCount();
460 BytesSent -= ThrottleBytes;
461 if (BytesSent < 0) BytesSent = 0;
462 if (BytesSent < ThrottleBytes)
463 {
464 oversizedImages = 0;
465 }
466 }
467 }
468 public int ThrottleBytes;
469 }
144 } 470 }
471
472
145} 473}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs
index 45d33cd..1b68603 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs
@@ -129,15 +129,15 @@ namespace OpenSim.Region.ClientStack.Linden
129// m_log.DebugFormat("[MESH UPLOAD FLAG MODULE]: MeshUploadFlag request"); 129// m_log.DebugFormat("[MESH UPLOAD FLAG MODULE]: MeshUploadFlag request");
130 130
131 OSDMap data = new OSDMap(); 131 OSDMap data = new OSDMap();
132 ScenePresence sp = m_scene.GetScenePresence(agentID); 132// ScenePresence sp = m_scene.GetScenePresence(m_agentID);
133 data["username"] = sp.Firstname + "." + sp.Lastname; 133// data["username"] = sp.Firstname + "." + sp.Lastname;
134 data["display_name_next_update"] = new OSDDate(DateTime.Now); 134// data["display_name_next_update"] = new OSDDate(DateTime.Now);
135 data["legacy_first_name"] = sp.Firstname; 135// data["legacy_first_name"] = sp.Firstname;
136 data["mesh_upload_status"] = "valid"; 136 data["mesh_upload_status"] = "valid";
137 data["display_name"] = sp.Firstname + " " + sp.Lastname; 137// data["display_name"] = sp.Firstname + " " + sp.Lastname;
138 data["legacy_last_name"] = sp.Lastname; 138// data["legacy_last_name"] = sp.Lastname;
139 data["id"] = agentID; 139// data["id"] = m_agentID;
140 data["is_display_name_default"] = true; 140// data["is_display_name_default"] = true;
141 141
142 //Send back data 142 //Send back data
143 Hashtable responsedata = new Hashtable(); 143 Hashtable responsedata = new Hashtable();
@@ -148,4 +148,4 @@ namespace OpenSim.Region.ClientStack.Linden
148 return responsedata; 148 return responsedata;
149 } 149 }
150 } 150 }
151} \ No newline at end of file 151}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs
deleted file mode 100644
index f69a0bb..0000000
--- a/OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs
+++ /dev/null
@@ -1,297 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Specialized;
31using System.Reflection;
32using System.IO;
33using System.Web;
34using Mono.Addins;
35using log4net;
36using Nini.Config;
37using OpenMetaverse;
38using OpenMetaverse.StructuredData;
39using OpenSim.Framework;
40using OpenSim.Framework.Servers;
41using OpenSim.Framework.Servers.HttpServer;
42using OpenSim.Region.Framework.Interfaces;
43using OpenSim.Region.Framework.Scenes;
44using OpenSim.Services.Interfaces;
45using Caps = OpenSim.Framework.Capabilities.Caps;
46using OpenSim.Framework.Capabilities;
47using PermissionMask = OpenSim.Framework.PermissionMask;
48
49namespace OpenSim.Region.ClientStack.Linden
50{
51 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "NewFileAgentInventoryVariablePriceModule")]
52 public class NewFileAgentInventoryVariablePriceModule : INonSharedRegionModule
53 {
54// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
55
56 private Scene m_scene;
57// private IAssetService m_assetService;
58 private bool m_dumpAssetsToFile = false;
59 private bool m_enabled = true;
60 private int m_levelUpload = 0;
61
62 #region Region Module interfaceBase Members
63
64
65 public Type ReplaceableInterface
66 {
67 get { return null; }
68 }
69
70 public void Initialise(IConfigSource source)
71 {
72 IConfig meshConfig = source.Configs["Mesh"];
73 if (meshConfig == null)
74 return;
75
76 m_enabled = meshConfig.GetBoolean("AllowMeshUpload", true);
77 m_levelUpload = meshConfig.GetInt("LevelUpload", 0);
78 }
79
80 public void AddRegion(Scene pScene)
81 {
82 m_scene = pScene;
83 }
84
85 public void RemoveRegion(Scene scene)
86 {
87
88 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
89 m_scene = null;
90 }
91
92 public void RegionLoaded(Scene scene)
93 {
94
95// m_assetService = m_scene.RequestModuleInterface<IAssetService>();
96 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
97 }
98
99 #endregion
100
101
102 #region Region Module interface
103
104
105
106 public void Close() { }
107
108 public string Name { get { return "NewFileAgentInventoryVariablePriceModule"; } }
109
110
111 public void RegisterCaps(UUID agentID, Caps caps)
112 {
113 if(!m_enabled)
114 return;
115
116 UUID capID = UUID.Random();
117
118// m_log.Debug("[NEW FILE AGENT INVENTORY VARIABLE PRICE]: /CAPS/" + capID);
119 caps.RegisterHandler(
120 "NewFileAgentInventoryVariablePrice",
121 new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDNewFileAngentInventoryVariablePriceReplyResponse>(
122 "POST",
123 "/CAPS/" + capID.ToString(),
124 req => NewAgentInventoryRequest(req, agentID),
125 "NewFileAgentInventoryVariablePrice",
126 agentID.ToString()));
127 }
128
129 #endregion
130
131 public LLSDNewFileAngentInventoryVariablePriceReplyResponse NewAgentInventoryRequest(LLSDAssetUploadRequest llsdRequest, UUID agentID)
132 {
133 //TODO: The Mesh uploader uploads many types of content. If you're going to implement a Money based limit
134 // you need to be aware of this
135
136 //if (llsdRequest.asset_type == "texture" ||
137 // llsdRequest.asset_type == "animation" ||
138 // llsdRequest.asset_type == "sound")
139 // {
140 // check user level
141
142 ScenePresence avatar = null;
143 IClientAPI client = null;
144 m_scene.TryGetScenePresence(agentID, out avatar);
145
146 if (avatar != null)
147 {
148 client = avatar.ControllingClient;
149
150 if (avatar.UserLevel < m_levelUpload)
151 {
152 if (client != null)
153 client.SendAgentAlertMessage("Unable to upload asset. Insufficient permissions.", false);
154
155 LLSDNewFileAngentInventoryVariablePriceReplyResponse errorResponse = new LLSDNewFileAngentInventoryVariablePriceReplyResponse();
156 errorResponse.rsvp = "";
157 errorResponse.state = "error";
158 return errorResponse;
159 }
160 }
161
162 // check funds
163 IMoneyModule mm = m_scene.RequestModuleInterface<IMoneyModule>();
164
165 if (mm != null)
166 {
167 if (!mm.UploadCovered(agentID, mm.UploadCharge))
168 {
169 if (client != null)
170 client.SendAgentAlertMessage("Unable to upload asset. Insufficient funds.", false);
171
172 LLSDNewFileAngentInventoryVariablePriceReplyResponse errorResponse = new LLSDNewFileAngentInventoryVariablePriceReplyResponse();
173 errorResponse.rsvp = "";
174 errorResponse.state = "error";
175 return errorResponse;
176 }
177 }
178
179 // }
180
181 string assetName = llsdRequest.name;
182 string assetDes = llsdRequest.description;
183 string capsBase = "/CAPS/NewFileAgentInventoryVariablePrice/";
184 UUID newAsset = UUID.Random();
185 UUID newInvItem = UUID.Random();
186 UUID parentFolder = llsdRequest.folder_id;
187 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000") + "/";
188
189 AssetUploader uploader =
190 new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type,
191 llsdRequest.asset_type, capsBase + uploaderPath, MainServer.Instance, m_dumpAssetsToFile);
192
193 MainServer.Instance.AddStreamHandler(
194 new BinaryStreamHandler(
195 "POST",
196 capsBase + uploaderPath,
197 uploader.uploaderCaps,
198 "NewFileAgentInventoryVariablePrice",
199 agentID.ToString()));
200
201 string protocol = "http://";
202
203 if (MainServer.Instance.UseSSL)
204 protocol = "https://";
205
206 string uploaderURL = protocol + m_scene.RegionInfo.ExternalHostName + ":" + MainServer.Instance.Port.ToString() + capsBase +
207 uploaderPath;
208
209
210 LLSDNewFileAngentInventoryVariablePriceReplyResponse uploadResponse = new LLSDNewFileAngentInventoryVariablePriceReplyResponse();
211
212 uploadResponse.rsvp = uploaderURL;
213 uploadResponse.state = "upload";
214 uploadResponse.resource_cost = 0;
215 uploadResponse.upload_price = 0;
216
217 uploader.OnUpLoad += //UploadCompleteHandler;
218
219 delegate(
220 string passetName, string passetDescription, UUID passetID,
221 UUID pinventoryItem, UUID pparentFolder, byte[] pdata, string pinventoryType,
222 string passetType)
223 {
224 UploadCompleteHandler(passetName, passetDescription, passetID,
225 pinventoryItem, pparentFolder, pdata, pinventoryType,
226 passetType,agentID);
227 };
228
229 return uploadResponse;
230 }
231
232 public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID,
233 UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType,
234 string assetType,UUID AgentID)
235 {
236// m_log.DebugFormat(
237// "[NEW FILE AGENT INVENTORY VARIABLE PRICE MODULE]: Upload complete for {0}", inventoryItem);
238
239 sbyte assType = 0;
240 sbyte inType = 0;
241
242 if (inventoryType == "sound")
243 {
244 inType = 1;
245 assType = 1;
246 }
247 else if (inventoryType == "animation")
248 {
249 inType = 19;
250 assType = 20;
251 }
252 else if (inventoryType == "wearable")
253 {
254 inType = 18;
255 switch (assetType)
256 {
257 case "bodypart":
258 assType = 13;
259 break;
260 case "clothing":
261 assType = 5;
262 break;
263 }
264 }
265 else if (inventoryType == "mesh")
266 {
267 inType = (sbyte)InventoryType.Mesh;
268 assType = (sbyte)AssetType.Mesh;
269 }
270
271 AssetBase asset;
272 asset = new AssetBase(assetID, assetName, assType, AgentID.ToString());
273 asset.Data = data;
274
275 if (m_scene.AssetService != null)
276 m_scene.AssetService.Store(asset);
277
278 InventoryItemBase item = new InventoryItemBase();
279 item.Owner = AgentID;
280 item.CreatorId = AgentID.ToString();
281 item.ID = inventoryItem;
282 item.AssetID = asset.FullID;
283 item.Description = assetDescription;
284 item.Name = assetName;
285 item.AssetType = assType;
286 item.InvType = inType;
287 item.Folder = parentFolder;
288 item.CurrentPermissions
289 = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer);
290 item.BasePermissions = (uint)PermissionMask.All;
291 item.EveryOnePermissions = 0;
292 item.NextPermissions = (uint)PermissionMask.All;
293 item.CreationDate = Util.UnixTimeSinceEpoch();
294 m_scene.AddInventoryItem(item);
295 }
296 }
297}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs
index 69dd76f..79d56c4 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs
@@ -64,6 +64,8 @@ namespace OpenSim.Region.ClientStack.Linden
64 private Commands m_commands = new Commands(); 64 private Commands m_commands = new Commands();
65 public ICommands Commands { get { return m_commands; } } 65 public ICommands Commands { get { return m_commands; } }
66 66
67 public event ConsoleMessage OnConsoleMessage;
68
67 public void Initialise(IConfigSource source) 69 public void Initialise(IConfigSource source)
68 { 70 {
69 m_commands.AddCommand( "Help", false, "help", "help [<item>]", "Display help on a particular command or on a list of commands in a category", Help); 71 m_commands.AddCommand( "Help", false, "help", "help [<item>]", "Display help on a particular command or on a list of commands in a category", Help);
@@ -102,7 +104,7 @@ namespace OpenSim.Region.ClientStack.Linden
102 104
103 public void RegisterCaps(UUID agentID, Caps caps) 105 public void RegisterCaps(UUID agentID, Caps caps)
104 { 106 {
105 if (!m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(agentID)) 107 if (!m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(agentID) && !m_scene.Permissions.IsGod(agentID))
106 return; 108 return;
107 109
108 UUID capID = UUID.Random(); 110 UUID capID = UUID.Random();
@@ -118,6 +120,11 @@ namespace OpenSim.Region.ClientStack.Linden
118 OSD osd = OSD.FromString(message); 120 OSD osd = OSD.FromString(message);
119 121
120 m_eventQueue.Enqueue(EventQueueHelper.BuildEvent("SimConsoleResponse", osd), agentID); 122 m_eventQueue.Enqueue(EventQueueHelper.BuildEvent("SimConsoleResponse", osd), agentID);
123
124 ConsoleMessage handlerConsoleMessage = OnConsoleMessage;
125
126 if (handlerConsoleMessage != null)
127 handlerConsoleMessage( agentID, message);
121 } 128 }
122 129
123 public bool RunCommand(string command, UUID invokerID) 130 public bool RunCommand(string command, UUID invokerID)
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs
index 3b0ccd7..eca576d 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs
@@ -27,6 +27,7 @@
27 27
28using System; 28using System;
29using System.Collections; 29using System.Collections;
30using System.Collections.Generic;
30using System.Collections.Specialized; 31using System.Collections.Specialized;
31using System.Drawing; 32using System.Drawing;
32using System.Drawing.Imaging; 33using System.Drawing.Imaging;
@@ -53,8 +54,8 @@ namespace OpenSim.Region.ClientStack.Linden
53 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "UploadBakedTextureModule")] 54 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "UploadBakedTextureModule")]
54 public class UploadBakedTextureModule : INonSharedRegionModule 55 public class UploadBakedTextureModule : INonSharedRegionModule
55 { 56 {
56// private static readonly ILog m_log = 57 private static readonly ILog m_log =
57// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 58 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
58 59
59 /// <summary> 60 /// <summary>
60 /// For historical reasons this is fixed, but there 61 /// For historical reasons this is fixed, but there
@@ -64,31 +65,210 @@ namespace OpenSim.Region.ClientStack.Linden
64 private Scene m_scene; 65 private Scene m_scene;
65 private bool m_persistBakedTextures; 66 private bool m_persistBakedTextures;
66 67
68 private IBakedTextureModule m_BakedTextureModule;
69
67 public void Initialise(IConfigSource source) 70 public void Initialise(IConfigSource source)
68 { 71 {
69 IConfig appearanceConfig = source.Configs["Appearance"]; 72 IConfig appearanceConfig = source.Configs["Appearance"];
70 if (appearanceConfig != null) 73 if (appearanceConfig != null)
71 m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures); 74 m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures);
75
76
72 } 77 }
73 78
74 public void AddRegion(Scene s) 79 public void AddRegion(Scene s)
75 { 80 {
76 m_scene = s; 81 m_scene = s;
82
77 } 83 }
78 84
79 public void RemoveRegion(Scene s) 85 public void RemoveRegion(Scene s)
80 { 86 {
87 s.EventManager.OnRegisterCaps -= RegisterCaps;
88 s.EventManager.OnNewPresence -= RegisterNewPresence;
89 s.EventManager.OnRemovePresence -= DeRegisterPresence;
90 m_BakedTextureModule = null;
91 m_scene = null;
81 } 92 }
82 93
94
95
83 public void RegionLoaded(Scene s) 96 public void RegionLoaded(Scene s)
84 { 97 {
85 m_scene.EventManager.OnRegisterCaps += RegisterCaps; 98 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
99 m_scene.EventManager.OnNewPresence += RegisterNewPresence;
100 m_scene.EventManager.OnRemovePresence += DeRegisterPresence;
101
102 }
103
104 private void DeRegisterPresence(UUID agentId)
105 {
106 ScenePresence presence = null;
107 if (m_scene.TryGetScenePresence(agentId, out presence))
108 {
109 presence.ControllingClient.OnSetAppearance -= CaptureAppearanceSettings;
110 }
111
112 }
113
114 private void RegisterNewPresence(ScenePresence presence)
115 {
116 presence.ControllingClient.OnSetAppearance += CaptureAppearanceSettings;
117
118 }
119
120 private void CaptureAppearanceSettings(IClientAPI remoteClient, Primitive.TextureEntry textureEntry, byte[] visualParams, Vector3 avSize, WearableCacheItem[] cacheItems)
121 {
122 int maxCacheitemsLoop = cacheItems.Length;
123 if (maxCacheitemsLoop > AvatarWearable.MAX_WEARABLES)
124 {
125 maxCacheitemsLoop = AvatarWearable.MAX_WEARABLES;
126 m_log.WarnFormat("[CACHEDBAKES]: Too Many Cache items Provided {0}, the max is {1}. Truncating!", cacheItems.Length, AvatarWearable.MAX_WEARABLES);
127 }
128
129 m_BakedTextureModule = m_scene.RequestModuleInterface<IBakedTextureModule>();
130 if (cacheItems.Length > 0)
131 {
132 m_log.Debug("[Cacheitems]: " + cacheItems.Length);
133 for (int iter = 0; iter < maxCacheitemsLoop; iter++)
134 {
135 m_log.Debug("[Cacheitems] {" + iter + "/" + cacheItems[iter].TextureIndex + "}: c-" + cacheItems[iter].CacheId + ", t-" +
136 cacheItems[iter].TextureID);
137 }
138
139 ScenePresence p = null;
140 if (m_scene.TryGetScenePresence(remoteClient.AgentId, out p))
141 {
142
143 WearableCacheItem[] existingitems = p.Appearance.WearableCacheItems;
144 if (existingitems == null)
145 {
146 if (m_BakedTextureModule != null)
147 {
148 WearableCacheItem[] savedcache = null;
149 try
150 {
151 if (p.Appearance.WearableCacheItemsDirty)
152 {
153 savedcache = m_BakedTextureModule.Get(p.UUID);
154 p.Appearance.WearableCacheItems = savedcache;
155 p.Appearance.WearableCacheItemsDirty = false;
156 }
157
158 }
159 /*
160 * The following Catch types DO NOT WORK with m_BakedTextureModule.Get
161 * it jumps to the General Packet Exception Handler if you don't catch Exception!
162 *
163 catch (System.Net.Sockets.SocketException)
164 {
165 cacheItems = null;
166 }
167 catch (WebException)
168 {
169 cacheItems = null;
170 }
171 catch (InvalidOperationException)
172 {
173 cacheItems = null;
174 } */
175 catch (Exception)
176 {
177 // The service logs a sufficient error message.
178 }
179
180
181 if (savedcache != null)
182 existingitems = savedcache;
183 }
184 }
185 // Existing items null means it's a fully new appearance
186 if (existingitems == null)
187 {
188
189 for (int i = 0; i < maxCacheitemsLoop; i++)
190 {
191 if (textureEntry.FaceTextures.Length > cacheItems[i].TextureIndex)
192 {
193 Primitive.TextureEntryFace face = textureEntry.FaceTextures[cacheItems[i].TextureIndex];
194 if (face == null)
195 {
196 textureEntry.CreateFace(cacheItems[i].TextureIndex);
197 textureEntry.FaceTextures[cacheItems[i].TextureIndex].TextureID =
198 AppearanceManager.DEFAULT_AVATAR_TEXTURE;
199 continue;
200 }
201 cacheItems[i].TextureID =face.TextureID;
202 if (m_scene.AssetService != null)
203 cacheItems[i].TextureAsset =
204 m_scene.AssetService.GetCached(cacheItems[i].TextureID.ToString());
205 }
206 else
207 {
208 m_log.WarnFormat("[CACHEDBAKES]: Invalid Texture Index Provided, Texture doesn't exist or hasn't been uploaded yet {0}, the max is {1}. Skipping!", cacheItems[i].TextureIndex, textureEntry.FaceTextures.Length);
209 }
210
211
212 }
213 }
214 else
215
216
217 {
218 // for each uploaded baked texture
219 for (int i = 0; i < maxCacheitemsLoop; i++)
220 {
221 if (textureEntry.FaceTextures.Length > cacheItems[i].TextureIndex)
222 {
223 Primitive.TextureEntryFace face = textureEntry.FaceTextures[cacheItems[i].TextureIndex];
224 if (face == null)
225 {
226 textureEntry.CreateFace(cacheItems[i].TextureIndex);
227 textureEntry.FaceTextures[cacheItems[i].TextureIndex].TextureID =
228 AppearanceManager.DEFAULT_AVATAR_TEXTURE;
229 continue;
230 }
231 cacheItems[i].TextureID =
232 face.TextureID;
233 }
234 else
235 {
236 m_log.WarnFormat("[CACHEDBAKES]: Invalid Texture Index Provided, Texture doesn't exist or hasn't been uploaded yet {0}, the max is {1}. Skipping!", cacheItems[i].TextureIndex, textureEntry.FaceTextures.Length);
237 }
238 }
239
240 for (int i = 0; i < maxCacheitemsLoop; i++)
241 {
242 if (cacheItems[i].TextureAsset == null)
243 {
244 cacheItems[i].TextureAsset =
245 m_scene.AssetService.GetCached(cacheItems[i].TextureID.ToString());
246 }
247 }
248 }
249
250
251
252 p.Appearance.WearableCacheItems = cacheItems;
253
254
255
256 if (m_BakedTextureModule != null)
257 {
258 m_BakedTextureModule.Store(remoteClient.AgentId, cacheItems);
259 p.Appearance.WearableCacheItemsDirty = true;
260
261 }
262 }
263 }
86 } 264 }
87 265
88 public void PostInitialise() 266 public void PostInitialise()
89 { 267 {
90 } 268 }
91 269
270
271
92 public void Close() { } 272 public void Close() { }
93 273
94 public string Name { get { return "UploadBakedTextureModule"; } } 274 public string Name { get { return "UploadBakedTextureModule"; } }
@@ -100,15 +280,23 @@ namespace OpenSim.Region.ClientStack.Linden
100 280
101 public void RegisterCaps(UUID agentID, Caps caps) 281 public void RegisterCaps(UUID agentID, Caps caps)
102 { 282 {
283 UploadBakedTextureHandler avatarhandler = new UploadBakedTextureHandler(
284 caps, m_scene.AssetService, m_persistBakedTextures);
285
286
287
103 caps.RegisterHandler( 288 caps.RegisterHandler(
104 "UploadBakedTexture", 289 "UploadBakedTexture",
105 new RestStreamHandler( 290 new RestStreamHandler(
106 "POST", 291 "POST",
107 "/CAPS/" + caps.CapsObjectPath + m_uploadBakedTexturePath, 292 "/CAPS/" + caps.CapsObjectPath + m_uploadBakedTexturePath,
108 new UploadBakedTextureHandler( 293 avatarhandler.UploadBakedTexture,
109 caps, m_scene.AssetService, m_persistBakedTextures).UploadBakedTexture,
110 "UploadBakedTexture", 294 "UploadBakedTexture",
111 agentID.ToString())); 295 agentID.ToString()));
296
297
298
299
112 } 300 }
113 } 301 }
114} \ No newline at end of file 302} \ No newline at end of file
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs
index d1afff2..6fb6497 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs
@@ -35,7 +35,6 @@ using Nini.Config;
35using Mono.Addins; 35using Mono.Addins;
36using OpenMetaverse; 36using OpenMetaverse;
37using OpenSim.Framework; 37using OpenSim.Framework;
38using OpenSim.Framework.Monitoring;
39using OpenSim.Framework.Servers; 38using OpenSim.Framework.Servers;
40using OpenSim.Framework.Servers.HttpServer; 39using OpenSim.Framework.Servers.HttpServer;
41using OpenSim.Region.Framework.Interfaces; 40using OpenSim.Region.Framework.Interfaces;
@@ -44,6 +43,7 @@ using OpenSim.Framework.Capabilities;
44using OpenSim.Services.Interfaces; 43using OpenSim.Services.Interfaces;
45using Caps = OpenSim.Framework.Capabilities.Caps; 44using Caps = OpenSim.Framework.Capabilities.Caps;
46using OpenSim.Capabilities.Handlers; 45using OpenSim.Capabilities.Handlers;
46using OpenSim.Framework.Monitoring;
47using OpenMetaverse; 47using OpenMetaverse;
48using OpenMetaverse.StructuredData; 48using OpenMetaverse.StructuredData;
49 49
@@ -254,7 +254,8 @@ namespace OpenSim.Region.ClientStack.Linden
254 { 254 {
255 if (!reqinfo.folders.Contains(folderID)) 255 if (!reqinfo.folders.Contains(folderID))
256 { 256 {
257 //TODO: Port COF handling from Avination 257 if (sp.COF != UUID.Zero && sp.COF == folderID)
258 highPriority = true;
258 reqinfo.folders.Add(folderID); 259 reqinfo.folders.Add(folderID);
259 } 260 }
260 } 261 }