diff options
Diffstat (limited to 'OpenSim/Region/OptionalModules/Materials')
-rw-r--r-- | OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs | 190 |
1 files changed, 167 insertions, 23 deletions
diff --git a/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs b/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs index 6cde92e..006b730 100644 --- a/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs +++ b/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs | |||
@@ -63,11 +63,16 @@ namespace OpenSim.Region.OptionalModules.Materials | |||
63 | 63 | ||
64 | public Type ReplaceableInterface { get { return null; } } | 64 | public Type ReplaceableInterface { get { return null; } } |
65 | 65 | ||
66 | IImprovedAssetCache m_cache; | ||
66 | private Scene m_scene = null; | 67 | private Scene m_scene = null; |
67 | private bool m_enabled = false; | 68 | private bool m_enabled = false; |
68 | private int m_maxMaterialsPerTransaction = 50; | 69 | private int m_maxMaterialsPerTransaction = 50; |
69 | 70 | ||
70 | public Dictionary<UUID, OSDMap> m_regionMaterials = new Dictionary<UUID, OSDMap>(); | 71 | public Dictionary<UUID, OSDMap> m_Materials = new Dictionary<UUID, OSDMap>(); |
72 | public Dictionary<UUID, int> m_MaterialsRefCount = new Dictionary<UUID, int>(); | ||
73 | |||
74 | private Dictionary<ulong, AssetBase> m_changes = new Dictionary<ulong, AssetBase>(); | ||
75 | private Dictionary<ulong, double> m_changesTime = new Dictionary<ulong, double>(); | ||
71 | 76 | ||
72 | public void Initialise(IConfigSource source) | 77 | public void Initialise(IConfigSource source) |
73 | { | 78 | { |
@@ -98,6 +103,56 @@ namespace OpenSim.Region.OptionalModules.Materials | |||
98 | m_scene = scene; | 103 | m_scene = scene; |
99 | m_scene.EventManager.OnRegisterCaps += OnRegisterCaps; | 104 | m_scene.EventManager.OnRegisterCaps += OnRegisterCaps; |
100 | m_scene.EventManager.OnObjectAddedToScene += EventManager_OnObjectAddedToScene; | 105 | m_scene.EventManager.OnObjectAddedToScene += EventManager_OnObjectAddedToScene; |
106 | m_scene.EventManager.OnBackup += EventManager_OnBackup; | ||
107 | } | ||
108 | |||
109 | private void EventManager_OnBackup(ISimulationDataService datastore, bool forcedBackup) | ||
110 | { | ||
111 | List<AssetBase> toStore; | ||
112 | List<ulong> hashlist; | ||
113 | |||
114 | |||
115 | lock (m_Materials) | ||
116 | { | ||
117 | if(m_changes.Count == 0) | ||
118 | return; | ||
119 | |||
120 | if(forcedBackup) | ||
121 | { | ||
122 | toStore = new List<AssetBase>(m_changes.Values); | ||
123 | m_changes.Clear(); | ||
124 | m_changesTime.Clear(); | ||
125 | } | ||
126 | else | ||
127 | { | ||
128 | toStore = new List<AssetBase>(); | ||
129 | hashlist = new List<ulong>(); | ||
130 | double storetime = Util.GetTimeStampMS() - 60000; | ||
131 | foreach(KeyValuePair<ulong,double> kvp in m_changesTime) | ||
132 | { | ||
133 | if(kvp.Value < storetime) | ||
134 | { | ||
135 | toStore.Add(m_changes[kvp.Key]); | ||
136 | hashlist.Add(kvp.Key); | ||
137 | } | ||
138 | } | ||
139 | foreach(ulong u in hashlist) | ||
140 | { | ||
141 | m_changesTime.Remove(u); | ||
142 | m_changes.Remove(u); | ||
143 | } | ||
144 | } | ||
145 | |||
146 | if(toStore.Count > 0) | ||
147 | Util.FireAndForget(delegate | ||
148 | { | ||
149 | foreach(AssetBase a in toStore) | ||
150 | { | ||
151 | a.Local = false; | ||
152 | m_scene.AssetService.Store(a); | ||
153 | } | ||
154 | }); | ||
155 | } | ||
101 | } | 156 | } |
102 | 157 | ||
103 | private void EventManager_OnObjectAddedToScene(SceneObjectGroup obj) | 158 | private void EventManager_OnObjectAddedToScene(SceneObjectGroup obj) |
@@ -145,12 +200,14 @@ namespace OpenSim.Region.OptionalModules.Materials | |||
145 | 200 | ||
146 | m_scene.EventManager.OnRegisterCaps -= OnRegisterCaps; | 201 | m_scene.EventManager.OnRegisterCaps -= OnRegisterCaps; |
147 | m_scene.EventManager.OnObjectAddedToScene -= EventManager_OnObjectAddedToScene; | 202 | m_scene.EventManager.OnObjectAddedToScene -= EventManager_OnObjectAddedToScene; |
203 | m_scene.EventManager.OnBackup -= EventManager_OnBackup; | ||
148 | } | 204 | } |
149 | 205 | ||
150 | public void RegionLoaded(Scene scene) | 206 | public void RegionLoaded(Scene scene) |
151 | { | 207 | { |
152 | if (!m_enabled) return; | 208 | if (!m_enabled) return; |
153 | 209 | ||
210 | m_cache = scene.RequestModuleInterface<IImprovedAssetCache>(); | ||
154 | ISimulatorFeaturesModule featuresModule = scene.RequestModuleInterface<ISimulatorFeaturesModule>(); | 211 | ISimulatorFeaturesModule featuresModule = scene.RequestModuleInterface<ISimulatorFeaturesModule>(); |
155 | if (featuresModule != null) | 212 | if (featuresModule != null) |
156 | featuresModule.OnSimulatorFeaturesRequest += OnSimulatorFeaturesRequest; | 213 | featuresModule.OnSimulatorFeaturesRequest += OnSimulatorFeaturesRequest; |
@@ -203,8 +260,17 @@ namespace OpenSim.Region.OptionalModules.Materials | |||
203 | { | 260 | { |
204 | try | 261 | try |
205 | { | 262 | { |
206 | lock (m_regionMaterials) | 263 | lock (m_Materials) |
207 | m_regionMaterials[matMap["ID"].AsUUID()] = (OSDMap)matMap["Material"]; | 264 | { |
265 | UUID id = matMap["ID"].AsUUID(); | ||
266 | if(m_Materials.ContainsKey(id)) | ||
267 | m_MaterialsRefCount[id]++; | ||
268 | else | ||
269 | { | ||
270 | m_Materials[id] = (OSDMap)matMap["Material"]; | ||
271 | m_MaterialsRefCount[id] = 1; | ||
272 | } | ||
273 | } | ||
208 | } | 274 | } |
209 | catch (Exception e) | 275 | catch (Exception e) |
210 | { | 276 | { |
@@ -252,16 +318,15 @@ namespace OpenSim.Region.OptionalModules.Materials | |||
252 | if (id == UUID.Zero) | 318 | if (id == UUID.Zero) |
253 | return; | 319 | return; |
254 | 320 | ||
255 | lock (m_regionMaterials) | 321 | lock (m_Materials) |
256 | { | 322 | { |
257 | if (m_regionMaterials.ContainsKey(id)) | 323 | if (m_Materials.ContainsKey(id)) |
324 | { | ||
325 | m_MaterialsRefCount[id]++; | ||
258 | return; | 326 | return; |
259 | 327 | } | |
260 | 328 | ||
261 | // get all asset so it gets into cache | ||
262 | AssetBase matAsset = m_scene.AssetService.Get(id.ToString()); | 329 | AssetBase matAsset = m_scene.AssetService.Get(id.ToString()); |
263 | |||
264 | // byte[] data = m_scene.AssetService.GetData(id.ToString()); | ||
265 | if (matAsset == null || matAsset.Data == null || matAsset.Data.Length == 0 ) | 330 | if (matAsset == null || matAsset.Data == null || matAsset.Data.Length == 0 ) |
266 | { | 331 | { |
267 | m_log.WarnFormat("[Materials]: Prim \"{0}\" ({1}) contains unknown material ID {2}", part.Name, part.UUID, id); | 332 | m_log.WarnFormat("[Materials]: Prim \"{0}\" ({1}) contains unknown material ID {2}", part.Name, part.UUID, id); |
@@ -280,7 +345,8 @@ namespace OpenSim.Region.OptionalModules.Materials | |||
280 | return; | 345 | return; |
281 | } | 346 | } |
282 | 347 | ||
283 | m_regionMaterials[id] = mat; | 348 | m_Materials[id] = mat; |
349 | m_MaterialsRefCount[id] = 1; | ||
284 | } | 350 | } |
285 | } | 351 | } |
286 | 352 | ||
@@ -309,13 +375,13 @@ namespace OpenSim.Region.OptionalModules.Materials | |||
309 | { | 375 | { |
310 | UUID id = new UUID(elem.AsBinary(), 0); | 376 | UUID id = new UUID(elem.AsBinary(), 0); |
311 | 377 | ||
312 | lock (m_regionMaterials) | 378 | lock (m_Materials) |
313 | { | 379 | { |
314 | if (m_regionMaterials.ContainsKey(id)) | 380 | if (m_Materials.ContainsKey(id)) |
315 | { | 381 | { |
316 | OSDMap matMap = new OSDMap(); | 382 | OSDMap matMap = new OSDMap(); |
317 | matMap["ID"] = OSD.FromBinary(id.GetBytes()); | 383 | matMap["ID"] = OSD.FromBinary(id.GetBytes()); |
318 | matMap["Material"] = m_regionMaterials[id]; | 384 | matMap["Material"] = m_Materials[id]; |
319 | respArr.Add(matMap); | 385 | respArr.Add(matMap); |
320 | } | 386 | } |
321 | else | 387 | else |
@@ -362,6 +428,7 @@ namespace OpenSim.Region.OptionalModules.Materials | |||
362 | 428 | ||
363 | OSDArray respArr = new OSDArray(); | 429 | OSDArray respArr = new OSDArray(); |
364 | 430 | ||
431 | HashSet<SceneObjectPart> parts = new HashSet<SceneObjectPart>(); | ||
365 | if (req.ContainsKey("Zipped")) | 432 | if (req.ContainsKey("Zipped")) |
366 | { | 433 | { |
367 | OSD osd = null; | 434 | OSD osd = null; |
@@ -426,7 +493,7 @@ namespace OpenSim.Region.OptionalModules.Materials | |||
426 | m_log.WarnFormat("[Materials]: Error in TextureEntry for SOP {0} {1}", sop.Name, sop.UUID); | 493 | m_log.WarnFormat("[Materials]: Error in TextureEntry for SOP {0} {1}", sop.Name, sop.UUID); |
427 | continue; | 494 | continue; |
428 | } | 495 | } |
429 | 496 | ||
430 | UUID id; | 497 | UUID id; |
431 | if (mat == null) | 498 | if (mat == null) |
432 | { | 499 | { |
@@ -435,15 +502,16 @@ namespace OpenSim.Region.OptionalModules.Materials | |||
435 | } | 502 | } |
436 | else | 503 | else |
437 | { | 504 | { |
438 | id = StoreMaterialAsAsset(agentID, mat, sop); | 505 | id = getNewID(mat); |
439 | } | 506 | } |
440 | 507 | ||
441 | int face = -1; | 508 | int face = -1; |
442 | 509 | UUID oldid = UUID.Zero; | |
443 | if (matsMap.ContainsKey("Face")) | 510 | if (matsMap.ContainsKey("Face")) |
444 | { | 511 | { |
445 | face = matsMap["Face"].AsInteger(); | 512 | face = matsMap["Face"].AsInteger(); |
446 | Primitive.TextureEntryFace faceEntry = te.CreateFace((uint)face); | 513 | Primitive.TextureEntryFace faceEntry = te.CreateFace((uint)face); |
514 | oldid = faceEntry.MaterialID; | ||
447 | faceEntry.MaterialID = id; | 515 | faceEntry.MaterialID = id; |
448 | } | 516 | } |
449 | else | 517 | else |
@@ -451,7 +519,10 @@ namespace OpenSim.Region.OptionalModules.Materials | |||
451 | if (te.DefaultTexture == null) | 519 | if (te.DefaultTexture == null) |
452 | m_log.WarnFormat("[Materials]: TextureEntry.DefaultTexture is null in {0} {1}", sop.Name, sop.UUID); | 520 | m_log.WarnFormat("[Materials]: TextureEntry.DefaultTexture is null in {0} {1}", sop.Name, sop.UUID); |
453 | else | 521 | else |
522 | { | ||
523 | oldid = te.DefaultTexture.MaterialID; | ||
454 | te.DefaultTexture.MaterialID = id; | 524 | te.DefaultTexture.MaterialID = id; |
525 | } | ||
455 | } | 526 | } |
456 | 527 | ||
457 | //m_log.DebugFormat("[Materials]: in \"{0}\" {1}, setting material ID for face {2} to {3}", sop.Name, sop.UUID, face, id); | 528 | //m_log.DebugFormat("[Materials]: in \"{0}\" {1}, setting material ID for face {2} to {3}", sop.Name, sop.UUID, face, id); |
@@ -459,11 +530,47 @@ namespace OpenSim.Region.OptionalModules.Materials | |||
459 | // We can't use sop.UpdateTextureEntry(te) because it filters, so do it manually | 530 | // We can't use sop.UpdateTextureEntry(te) because it filters, so do it manually |
460 | sop.Shape.TextureEntry = te.GetBytes(); | 531 | sop.Shape.TextureEntry = te.GetBytes(); |
461 | 532 | ||
462 | if (sop.ParentGroup != null) | 533 | lock(m_Materials) |
534 | { | ||
535 | if(oldid != UUID.Zero) | ||
536 | { | ||
537 | m_MaterialsRefCount[oldid]--; | ||
538 | if(m_MaterialsRefCount[oldid] <= 0) | ||
539 | { | ||
540 | m_Materials.Remove(oldid); | ||
541 | m_MaterialsRefCount.Remove(oldid); | ||
542 | m_cache.Expire(oldid.ToString()); | ||
543 | } | ||
544 | } | ||
545 | |||
546 | if(id != UUID.Zero) | ||
547 | { | ||
548 | AssetBase asset = CacheMaterialAsAsset(id, agentID, mat, sop); | ||
549 | if(asset != null) | ||
550 | { | ||
551 | ulong materialHash = (ulong)primLocalID << 32; | ||
552 | if(face < 0) | ||
553 | materialHash += 0xffffffff; | ||
554 | else | ||
555 | materialHash +=(ulong)face; | ||
556 | |||
557 | m_changes[materialHash] = asset; | ||
558 | m_changesTime[materialHash] = Util.GetTimeStampMS(); | ||
559 | } | ||
560 | } | ||
561 | } | ||
562 | |||
563 | if(!parts.Contains(sop)) | ||
564 | parts.Add(sop); | ||
565 | } | ||
566 | |||
567 | foreach(SceneObjectPart sop in parts) | ||
568 | { | ||
569 | if (sop.ParentGroup != null && !sop.ParentGroup.IsDeleted) | ||
463 | { | 570 | { |
464 | sop.TriggerScriptChangedEvent(Changed.TEXTURE); | 571 | sop.TriggerScriptChangedEvent(Changed.TEXTURE); |
465 | sop.ParentGroup.HasGroupChanged = true; | ||
466 | sop.ScheduleFullUpdate(); | 572 | sop.ScheduleFullUpdate(); |
573 | sop.ParentGroup.HasGroupChanged = true; | ||
467 | } | 574 | } |
468 | } | 575 | } |
469 | } | 576 | } |
@@ -491,6 +598,40 @@ namespace OpenSim.Region.OptionalModules.Materials | |||
491 | return response; | 598 | return response; |
492 | } | 599 | } |
493 | 600 | ||
601 | private UUID getNewID(OSDMap mat) | ||
602 | { | ||
603 | // ugly and done twice but keep compatibility for now | ||
604 | Byte[] data = System.Text.Encoding.ASCII.GetBytes(OSDParser.SerializeLLSDXmlString(mat)); | ||
605 | using (var md5 = MD5.Create()) | ||
606 | return new UUID(md5.ComputeHash(data), 0); | ||
607 | } | ||
608 | |||
609 | private AssetBase CacheMaterialAsAsset(UUID id, UUID agentID, OSDMap mat, SceneObjectPart sop) | ||
610 | { | ||
611 | AssetBase asset = null; | ||
612 | lock (m_Materials) | ||
613 | { | ||
614 | if (!m_Materials.ContainsKey(id)) | ||
615 | { | ||
616 | m_Materials[id] = mat; | ||
617 | m_MaterialsRefCount[id] = 1; | ||
618 | |||
619 | byte[] data = System.Text.Encoding.ASCII.GetBytes(OSDParser.SerializeLLSDXmlString(mat)); | ||
620 | |||
621 | // This asset might exist already, but it's ok to try to store it again | ||
622 | string name = "Material " + ChooseMaterialName(mat, sop); | ||
623 | name = name.Substring(0, Math.Min(64, name.Length)).Trim(); | ||
624 | asset = new AssetBase(id, name, (sbyte)OpenSimAssetType.Material, agentID.ToString()); | ||
625 | asset.Data = data; | ||
626 | asset.Local = true; | ||
627 | m_cache.Cache(asset); | ||
628 | } | ||
629 | else | ||
630 | m_MaterialsRefCount[id]++; | ||
631 | } | ||
632 | return asset; | ||
633 | } | ||
634 | |||
494 | private UUID StoreMaterialAsAsset(UUID agentID, OSDMap mat, SceneObjectPart sop) | 635 | private UUID StoreMaterialAsAsset(UUID agentID, OSDMap mat, SceneObjectPart sop) |
495 | { | 636 | { |
496 | UUID id; | 637 | UUID id; |
@@ -500,11 +641,12 @@ namespace OpenSim.Region.OptionalModules.Materials | |||
500 | using (var md5 = MD5.Create()) | 641 | using (var md5 = MD5.Create()) |
501 | id = new UUID(md5.ComputeHash(data), 0); | 642 | id = new UUID(md5.ComputeHash(data), 0); |
502 | 643 | ||
503 | lock (m_regionMaterials) | 644 | lock (m_Materials) |
504 | { | 645 | { |
505 | if (!m_regionMaterials.ContainsKey(id)) | 646 | if (!m_Materials.ContainsKey(id)) |
506 | { | 647 | { |
507 | m_regionMaterials[id] = mat; | 648 | m_Materials[id] = mat; |
649 | m_MaterialsRefCount[id] = 1; | ||
508 | 650 | ||
509 | // This asset might exist already, but it's ok to try to store it again | 651 | // This asset might exist already, but it's ok to try to store it again |
510 | string name = "Material " + ChooseMaterialName(mat, sop); | 652 | string name = "Material " + ChooseMaterialName(mat, sop); |
@@ -513,6 +655,8 @@ namespace OpenSim.Region.OptionalModules.Materials | |||
513 | asset.Data = data; | 655 | asset.Data = data; |
514 | m_scene.AssetService.Store(asset); | 656 | m_scene.AssetService.Store(asset); |
515 | } | 657 | } |
658 | else | ||
659 | m_MaterialsRefCount[id]++; | ||
516 | } | 660 | } |
517 | return id; | 661 | return id; |
518 | } | 662 | } |
@@ -554,9 +698,9 @@ namespace OpenSim.Region.OptionalModules.Materials | |||
554 | int matsCount = 0; | 698 | int matsCount = 0; |
555 | OSDArray allOsd = new OSDArray(); | 699 | OSDArray allOsd = new OSDArray(); |
556 | 700 | ||
557 | lock (m_regionMaterials) | 701 | lock (m_Materials) |
558 | { | 702 | { |
559 | foreach (KeyValuePair<UUID, OSDMap> kvp in m_regionMaterials) | 703 | foreach (KeyValuePair<UUID, OSDMap> kvp in m_Materials) |
560 | { | 704 | { |
561 | OSDMap matMap = new OSDMap(); | 705 | OSDMap matMap = new OSDMap(); |
562 | 706 | ||