diff options
Diffstat (limited to 'OpenSim/Region/CoreModules/Scripting')
11 files changed, 1616 insertions, 347 deletions
diff --git a/OpenSim/Region/CoreModules/Scripting/DynamicTexture/DynamicTexture.cs b/OpenSim/Region/CoreModules/Scripting/DynamicTexture/DynamicTexture.cs new file mode 100644 index 0000000..fce9490 --- /dev/null +++ b/OpenSim/Region/CoreModules/Scripting/DynamicTexture/DynamicTexture.cs | |||
@@ -0,0 +1,61 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Drawing; | ||
30 | using OpenSim.Region.Framework.Interfaces; | ||
31 | |||
32 | namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture | ||
33 | { | ||
34 | public class DynamicTexture : IDynamicTexture | ||
35 | { | ||
36 | public string InputCommands { get; private set; } | ||
37 | public Uri InputUri { get; private set; } | ||
38 | public string InputParams { get; private set; } | ||
39 | public byte[] Data { get; private set; } | ||
40 | public Size Size { get; private set; } | ||
41 | public bool IsReuseable { get; private set; } | ||
42 | |||
43 | public DynamicTexture(string inputCommands, string inputParams, byte[] data, Size size, bool isReuseable) | ||
44 | { | ||
45 | InputCommands = inputCommands; | ||
46 | InputParams = inputParams; | ||
47 | Data = data; | ||
48 | Size = size; | ||
49 | IsReuseable = isReuseable; | ||
50 | } | ||
51 | |||
52 | public DynamicTexture(Uri inputUri, string inputParams, byte[] data, Size size, bool isReuseable) | ||
53 | { | ||
54 | InputUri = inputUri; | ||
55 | InputParams = inputParams; | ||
56 | Data = data; | ||
57 | Size = size; | ||
58 | IsReuseable = isReuseable; | ||
59 | } | ||
60 | } | ||
61 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/CoreModules/Scripting/DynamicTexture/DynamicTextureModule.cs b/OpenSim/Region/CoreModules/Scripting/DynamicTexture/DynamicTextureModule.cs index 18bd018..9d77b19 100644 --- a/OpenSim/Region/CoreModules/Scripting/DynamicTexture/DynamicTextureModule.cs +++ b/OpenSim/Region/CoreModules/Scripting/DynamicTexture/DynamicTextureModule.cs | |||
@@ -37,18 +37,36 @@ using OpenSim.Region.Framework.Interfaces; | |||
37 | using OpenSim.Region.Framework.Scenes; | 37 | using OpenSim.Region.Framework.Scenes; |
38 | using log4net; | 38 | using log4net; |
39 | using System.Reflection; | 39 | using System.Reflection; |
40 | using Mono.Addins; | ||
40 | 41 | ||
41 | namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture | 42 | namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture |
42 | { | 43 | { |
43 | public class DynamicTextureModule : IRegionModule, IDynamicTextureManager | 44 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DynamicTextureModule")] |
45 | public class DynamicTextureModule : ISharedRegionModule, IDynamicTextureManager | ||
44 | { | 46 | { |
45 | //private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 47 | // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
46 | 48 | ||
47 | private const int ALL_SIDES = -1; | 49 | private const int ALL_SIDES = -1; |
48 | 50 | ||
49 | public const int DISP_EXPIRE = 1; | 51 | public const int DISP_EXPIRE = 1; |
50 | public const int DISP_TEMP = 2; | 52 | public const int DISP_TEMP = 2; |
51 | 53 | ||
54 | /// <summary> | ||
55 | /// If true then where possible dynamic textures are reused. | ||
56 | /// </summary> | ||
57 | public bool ReuseTextures { get; set; } | ||
58 | |||
59 | /// <summary> | ||
60 | /// If false, then textures which have a low data size are not reused when ReuseTextures = true. | ||
61 | /// </summary> | ||
62 | /// <remarks> | ||
63 | /// LL viewers 3.3.4 and before appear to not fully render textures pulled from the viewer cache if those | ||
64 | /// textures have a relatively high pixel surface but a small data size. Typically, this appears to happen | ||
65 | /// if the data size is smaller than the viewer's discard level 2 size estimate. So if this is setting is | ||
66 | /// false, textures smaller than the calculation in IsSizeReuseable are always regenerated rather than reused | ||
67 | /// to work around this problem.</remarks> | ||
68 | public bool ReuseLowDataTextures { get; set; } | ||
69 | |||
52 | private Dictionary<UUID, Scene> RegisteredScenes = new Dictionary<UUID, Scene>(); | 70 | private Dictionary<UUID, Scene> RegisteredScenes = new Dictionary<UUID, Scene>(); |
53 | 71 | ||
54 | private Dictionary<string, IDynamicTextureRender> RenderPlugins = | 72 | private Dictionary<string, IDynamicTextureRender> RenderPlugins = |
@@ -56,6 +74,25 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture | |||
56 | 74 | ||
57 | private Dictionary<UUID, DynamicTextureUpdater> Updaters = new Dictionary<UUID, DynamicTextureUpdater>(); | 75 | private Dictionary<UUID, DynamicTextureUpdater> Updaters = new Dictionary<UUID, DynamicTextureUpdater>(); |
58 | 76 | ||
77 | /// <summary> | ||
78 | /// Record dynamic textures that we can reuse for a given data and parameter combination rather than | ||
79 | /// regenerate. | ||
80 | /// </summary> | ||
81 | /// <remarks> | ||
82 | /// Key is string.Format("{0}{1}", data | ||
83 | /// </remarks> | ||
84 | private Cache m_reuseableDynamicTextures; | ||
85 | |||
86 | /// <summary> | ||
87 | /// This constructor is only here because of the Unit Tests... | ||
88 | /// Don't use it. | ||
89 | /// </summary> | ||
90 | public DynamicTextureModule() | ||
91 | { | ||
92 | m_reuseableDynamicTextures = new Cache(CacheMedium.Memory, CacheStrategy.Conservative); | ||
93 | m_reuseableDynamicTextures.DefaultTTL = new TimeSpan(24, 0, 0); | ||
94 | } | ||
95 | |||
59 | #region IDynamicTextureManager Members | 96 | #region IDynamicTextureManager Members |
60 | 97 | ||
61 | public void RegisterRender(string handleType, IDynamicTextureRender render) | 98 | public void RegisterRender(string handleType, IDynamicTextureRender render) |
@@ -69,17 +106,17 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture | |||
69 | /// <summary> | 106 | /// <summary> |
70 | /// Called by code which actually renders the dynamic texture to supply texture data. | 107 | /// Called by code which actually renders the dynamic texture to supply texture data. |
71 | /// </summary> | 108 | /// </summary> |
72 | /// <param name="id"></param> | 109 | /// <param name="updaterId"></param> |
73 | /// <param name="data"></param> | 110 | /// <param name="texture"></param> |
74 | public void ReturnData(UUID id, byte[] data) | 111 | public void ReturnData(UUID updaterId, IDynamicTexture texture) |
75 | { | 112 | { |
76 | DynamicTextureUpdater updater = null; | 113 | DynamicTextureUpdater updater = null; |
77 | 114 | ||
78 | lock (Updaters) | 115 | lock (Updaters) |
79 | { | 116 | { |
80 | if (Updaters.ContainsKey(id)) | 117 | if (Updaters.ContainsKey(updaterId)) |
81 | { | 118 | { |
82 | updater = Updaters[id]; | 119 | updater = Updaters[updaterId]; |
83 | } | 120 | } |
84 | } | 121 | } |
85 | 122 | ||
@@ -88,7 +125,16 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture | |||
88 | if (RegisteredScenes.ContainsKey(updater.SimUUID)) | 125 | if (RegisteredScenes.ContainsKey(updater.SimUUID)) |
89 | { | 126 | { |
90 | Scene scene = RegisteredScenes[updater.SimUUID]; | 127 | Scene scene = RegisteredScenes[updater.SimUUID]; |
91 | updater.DataReceived(data, scene); | 128 | UUID newTextureID = updater.DataReceived(texture.Data, scene); |
129 | |||
130 | if (ReuseTextures | ||
131 | && !updater.BlendWithOldTexture | ||
132 | && texture.IsReuseable | ||
133 | && (ReuseLowDataTextures || IsDataSizeReuseable(texture))) | ||
134 | { | ||
135 | m_reuseableDynamicTextures.Store( | ||
136 | GenerateReusableTextureKey(texture.InputCommands, texture.InputParams), newTextureID); | ||
137 | } | ||
92 | } | 138 | } |
93 | } | 139 | } |
94 | 140 | ||
@@ -104,6 +150,27 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture | |||
104 | } | 150 | } |
105 | } | 151 | } |
106 | 152 | ||
153 | /// <summary> | ||
154 | /// Determines whether the texture is reuseable based on its data size. | ||
155 | /// </summary> | ||
156 | /// <remarks> | ||
157 | /// This is a workaround for a viewer bug where very small data size textures relative to their pixel size | ||
158 | /// are not redisplayed properly when pulled from cache. The calculation here is based on the typical discard | ||
159 | /// level of 2, a 'rate' of 0.125 and 4 components (which makes for a factor of 0.5). | ||
160 | /// </remarks> | ||
161 | /// <returns></returns> | ||
162 | private bool IsDataSizeReuseable(IDynamicTexture texture) | ||
163 | { | ||
164 | // Console.WriteLine("{0} {1}", texture.Size.Width, texture.Size.Height); | ||
165 | int discardLevel2DataThreshold = (int)Math.Ceiling((texture.Size.Width >> 2) * (texture.Size.Height >> 2) * 0.5); | ||
166 | |||
167 | // m_log.DebugFormat( | ||
168 | // "[DYNAMIC TEXTURE MODULE]: Discard level 2 threshold {0}, texture data length {1}", | ||
169 | // discardLevel2DataThreshold, texture.Data.Length); | ||
170 | |||
171 | return discardLevel2DataThreshold < texture.Data.Length; | ||
172 | } | ||
173 | |||
107 | public UUID AddDynamicTextureURL(UUID simID, UUID primID, string contentType, string url, | 174 | public UUID AddDynamicTextureURL(UUID simID, UUID primID, string contentType, string url, |
108 | string extraParams, int updateTimer) | 175 | string extraParams, int updateTimer) |
109 | { | 176 | { |
@@ -167,22 +234,61 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture | |||
167 | public UUID AddDynamicTextureData(UUID simID, UUID primID, string contentType, string data, | 234 | public UUID AddDynamicTextureData(UUID simID, UUID primID, string contentType, string data, |
168 | string extraParams, int updateTimer, bool SetBlending, int disp, byte AlphaValue, int face) | 235 | string extraParams, int updateTimer, bool SetBlending, int disp, byte AlphaValue, int face) |
169 | { | 236 | { |
170 | if (RenderPlugins.ContainsKey(contentType)) | 237 | if (!RenderPlugins.ContainsKey(contentType)) |
238 | return UUID.Zero; | ||
239 | |||
240 | Scene scene; | ||
241 | RegisteredScenes.TryGetValue(simID, out scene); | ||
242 | |||
243 | if (scene == null) | ||
244 | return UUID.Zero; | ||
245 | |||
246 | SceneObjectPart part = scene.GetSceneObjectPart(primID); | ||
247 | |||
248 | if (part == null) | ||
249 | return UUID.Zero; | ||
250 | |||
251 | // If we want to reuse dynamic textures then we have to ignore any request from the caller to expire | ||
252 | // them. | ||
253 | if (ReuseTextures) | ||
254 | disp = disp & ~DISP_EXPIRE; | ||
255 | |||
256 | DynamicTextureUpdater updater = new DynamicTextureUpdater(); | ||
257 | updater.SimUUID = simID; | ||
258 | updater.PrimID = primID; | ||
259 | updater.ContentType = contentType; | ||
260 | updater.BodyData = data; | ||
261 | updater.UpdateTimer = updateTimer; | ||
262 | updater.UpdaterID = UUID.Random(); | ||
263 | updater.Params = extraParams; | ||
264 | updater.BlendWithOldTexture = SetBlending; | ||
265 | updater.FrontAlpha = AlphaValue; | ||
266 | updater.Face = face; | ||
267 | updater.Url = "Local image"; | ||
268 | updater.Disp = disp; | ||
269 | |||
270 | object objReusableTextureUUID = null; | ||
271 | |||
272 | if (ReuseTextures && !updater.BlendWithOldTexture) | ||
171 | { | 273 | { |
172 | DynamicTextureUpdater updater = new DynamicTextureUpdater(); | 274 | string reuseableTextureKey = GenerateReusableTextureKey(data, extraParams); |
173 | updater.SimUUID = simID; | 275 | objReusableTextureUUID = m_reuseableDynamicTextures.Get(reuseableTextureKey); |
174 | updater.PrimID = primID; | ||
175 | updater.ContentType = contentType; | ||
176 | updater.BodyData = data; | ||
177 | updater.UpdateTimer = updateTimer; | ||
178 | updater.UpdaterID = UUID.Random(); | ||
179 | updater.Params = extraParams; | ||
180 | updater.BlendWithOldTexture = SetBlending; | ||
181 | updater.FrontAlpha = AlphaValue; | ||
182 | updater.Face = face; | ||
183 | updater.Url = "Local image"; | ||
184 | updater.Disp = disp; | ||
185 | 276 | ||
277 | if (objReusableTextureUUID != null) | ||
278 | { | ||
279 | // If something else has removed this temporary asset from the cache, detect and invalidate | ||
280 | // our cached uuid. | ||
281 | if (scene.AssetService.GetMetadata(objReusableTextureUUID.ToString()) == null) | ||
282 | { | ||
283 | m_reuseableDynamicTextures.Invalidate(reuseableTextureKey); | ||
284 | objReusableTextureUUID = null; | ||
285 | } | ||
286 | } | ||
287 | } | ||
288 | |||
289 | // We cannot reuse a dynamic texture if the data is going to be blended with something already there. | ||
290 | if (objReusableTextureUUID == null) | ||
291 | { | ||
186 | lock (Updaters) | 292 | lock (Updaters) |
187 | { | 293 | { |
188 | if (!Updaters.ContainsKey(updater.UpdaterID)) | 294 | if (!Updaters.ContainsKey(updater.UpdaterID)) |
@@ -191,11 +297,29 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture | |||
191 | } | 297 | } |
192 | } | 298 | } |
193 | 299 | ||
300 | // m_log.DebugFormat( | ||
301 | // "[DYNAMIC TEXTURE MODULE]: Requesting generation of new dynamic texture for {0} in {1}", | ||
302 | // part.Name, part.ParentGroup.Scene.Name); | ||
303 | |||
194 | RenderPlugins[contentType].AsyncConvertData(updater.UpdaterID, data, extraParams); | 304 | RenderPlugins[contentType].AsyncConvertData(updater.UpdaterID, data, extraParams); |
195 | return updater.UpdaterID; | ||
196 | } | 305 | } |
197 | 306 | else | |
198 | return UUID.Zero; | 307 | { |
308 | // m_log.DebugFormat( | ||
309 | // "[DYNAMIC TEXTURE MODULE]: Reusing cached texture {0} for {1} in {2}", | ||
310 | // objReusableTextureUUID, part.Name, part.ParentGroup.Scene.Name); | ||
311 | |||
312 | // No need to add to updaters as the texture is always the same. Not that this functionality | ||
313 | // apppears to be implemented anyway. | ||
314 | updater.UpdatePart(part, (UUID)objReusableTextureUUID); | ||
315 | } | ||
316 | |||
317 | return updater.UpdaterID; | ||
318 | } | ||
319 | |||
320 | private string GenerateReusableTextureKey(string data, string extraParams) | ||
321 | { | ||
322 | return string.Format("{0}{1}", data, extraParams); | ||
199 | } | 323 | } |
200 | 324 | ||
201 | public void GetDrawStringSize(string contentType, string text, string fontName, int fontSize, | 325 | public void GetDrawStringSize(string contentType, string text, string fontName, int fontSize, |
@@ -211,9 +335,29 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture | |||
211 | 335 | ||
212 | #endregion | 336 | #endregion |
213 | 337 | ||
214 | #region IRegionModule Members | 338 | #region ISharedRegionModule Members |
215 | 339 | ||
216 | public void Initialise(Scene scene, IConfigSource config) | 340 | public void Initialise(IConfigSource config) |
341 | { | ||
342 | IConfig texturesConfig = config.Configs["Textures"]; | ||
343 | if (texturesConfig != null) | ||
344 | { | ||
345 | ReuseTextures = texturesConfig.GetBoolean("ReuseDynamicTextures", false); | ||
346 | ReuseLowDataTextures = texturesConfig.GetBoolean("ReuseDynamicLowDataTextures", false); | ||
347 | |||
348 | if (ReuseTextures) | ||
349 | { | ||
350 | m_reuseableDynamicTextures = new Cache(CacheMedium.Memory, CacheStrategy.Conservative); | ||
351 | m_reuseableDynamicTextures.DefaultTTL = new TimeSpan(24, 0, 0); | ||
352 | } | ||
353 | } | ||
354 | } | ||
355 | |||
356 | public void PostInitialise() | ||
357 | { | ||
358 | } | ||
359 | |||
360 | public void AddRegion(Scene scene) | ||
217 | { | 361 | { |
218 | if (!RegisteredScenes.ContainsKey(scene.RegionInfo.RegionID)) | 362 | if (!RegisteredScenes.ContainsKey(scene.RegionInfo.RegionID)) |
219 | { | 363 | { |
@@ -222,8 +366,14 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture | |||
222 | } | 366 | } |
223 | } | 367 | } |
224 | 368 | ||
225 | public void PostInitialise() | 369 | public void RegionLoaded(Scene scene) |
370 | { | ||
371 | } | ||
372 | |||
373 | public void RemoveRegion(Scene scene) | ||
226 | { | 374 | { |
375 | if (RegisteredScenes.ContainsKey(scene.RegionInfo.RegionID)) | ||
376 | RegisteredScenes.Remove(scene.RegionInfo.RegionID); | ||
227 | } | 377 | } |
228 | 378 | ||
229 | public void Close() | 379 | public void Close() |
@@ -235,9 +385,9 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture | |||
235 | get { return "DynamicTextureModule"; } | 385 | get { return "DynamicTextureModule"; } |
236 | } | 386 | } |
237 | 387 | ||
238 | public bool IsSharedModule | 388 | public Type ReplaceableInterface |
239 | { | 389 | { |
240 | get { return true; } | 390 | get { return null; } |
241 | } | 391 | } |
242 | 392 | ||
243 | #endregion | 393 | #endregion |
@@ -269,9 +419,60 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture | |||
269 | } | 419 | } |
270 | 420 | ||
271 | /// <summary> | 421 | /// <summary> |
422 | /// Update the given part with the new texture. | ||
423 | /// </summary> | ||
424 | /// <returns> | ||
425 | /// The old texture UUID. | ||
426 | /// </returns> | ||
427 | public UUID UpdatePart(SceneObjectPart part, UUID textureID) | ||
428 | { | ||
429 | UUID oldID; | ||
430 | |||
431 | lock (part) | ||
432 | { | ||
433 | // mostly keep the values from before | ||
434 | Primitive.TextureEntry tmptex = part.Shape.Textures; | ||
435 | |||
436 | // FIXME: Need to return the appropriate ID if only a single face is replaced. | ||
437 | oldID = tmptex.DefaultTexture.TextureID; | ||
438 | |||
439 | if (Face == ALL_SIDES) | ||
440 | { | ||
441 | oldID = tmptex.DefaultTexture.TextureID; | ||
442 | tmptex.DefaultTexture.TextureID = textureID; | ||
443 | } | ||
444 | else | ||
445 | { | ||
446 | try | ||
447 | { | ||
448 | Primitive.TextureEntryFace texface = tmptex.CreateFace((uint)Face); | ||
449 | texface.TextureID = textureID; | ||
450 | tmptex.FaceTextures[Face] = texface; | ||
451 | } | ||
452 | catch (Exception) | ||
453 | { | ||
454 | tmptex.DefaultTexture.TextureID = textureID; | ||
455 | } | ||
456 | } | ||
457 | |||
458 | // I'm pretty sure we always want to force this to true | ||
459 | // I'm pretty sure noone whats to set fullbright true if it wasn't true before. | ||
460 | // tmptex.DefaultTexture.Fullbright = true; | ||
461 | |||
462 | part.UpdateTextureEntry(tmptex.GetBytes()); | ||
463 | } | ||
464 | |||
465 | return oldID; | ||
466 | } | ||
467 | |||
468 | /// <summary> | ||
272 | /// Called once new texture data has been received for this updater. | 469 | /// Called once new texture data has been received for this updater. |
273 | /// </summary> | 470 | /// </summary> |
274 | public void DataReceived(byte[] data, Scene scene) | 471 | /// <param name="data"></param> |
472 | /// <param name="scene"></param> | ||
473 | /// <param name="isReuseable">True if the data given is reuseable.</param> | ||
474 | /// <returns>The asset UUID given to the incoming data.</returns> | ||
475 | public UUID DataReceived(byte[] data, Scene scene) | ||
275 | { | 476 | { |
276 | SceneObjectPart part = scene.GetSceneObjectPart(PrimID); | 477 | SceneObjectPart part = scene.GetSceneObjectPart(PrimID); |
277 | 478 | ||
@@ -281,7 +482,8 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture | |||
281 | String.Format("DynamicTextureModule: Error preparing image using URL {0}", Url); | 482 | String.Format("DynamicTextureModule: Error preparing image using URL {0}", Url); |
282 | scene.SimChat(Utils.StringToBytes(msg), ChatTypeEnum.Say, | 483 | scene.SimChat(Utils.StringToBytes(msg), ChatTypeEnum.Say, |
283 | 0, part.ParentGroup.RootPart.AbsolutePosition, part.Name, part.UUID, false); | 484 | 0, part.ParentGroup.RootPart.AbsolutePosition, part.Name, part.UUID, false); |
284 | return; | 485 | |
486 | return UUID.Zero; | ||
285 | } | 487 | } |
286 | 488 | ||
287 | byte[] assetData = null; | 489 | byte[] assetData = null; |
@@ -319,56 +521,29 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture | |||
319 | IJ2KDecoder cacheLayerDecode = scene.RequestModuleInterface<IJ2KDecoder>(); | 521 | IJ2KDecoder cacheLayerDecode = scene.RequestModuleInterface<IJ2KDecoder>(); |
320 | if (cacheLayerDecode != null) | 522 | if (cacheLayerDecode != null) |
321 | { | 523 | { |
322 | cacheLayerDecode.Decode(asset.FullID, asset.Data); | 524 | if (!cacheLayerDecode.Decode(asset.FullID, asset.Data)) |
323 | cacheLayerDecode = null; | 525 | m_log.WarnFormat( |
526 | "[DYNAMIC TEXTURE MODULE]: Decoding of dynamically generated asset {0} for {1} in {2} failed", | ||
527 | asset.ID, part.Name, part.ParentGroup.Scene.Name); | ||
324 | } | 528 | } |
325 | 529 | ||
326 | UUID oldID = UUID.Zero; | 530 | UUID oldID = UpdatePart(part, asset.FullID); |
327 | |||
328 | lock (part) | ||
329 | { | ||
330 | // mostly keep the values from before | ||
331 | Primitive.TextureEntry tmptex = part.Shape.Textures; | ||
332 | |||
333 | // remove the old asset from the cache | ||
334 | oldID = tmptex.DefaultTexture.TextureID; | ||
335 | |||
336 | if (Face == ALL_SIDES) | ||
337 | { | ||
338 | tmptex.DefaultTexture.TextureID = asset.FullID; | ||
339 | } | ||
340 | else | ||
341 | { | ||
342 | try | ||
343 | { | ||
344 | Primitive.TextureEntryFace texface = tmptex.CreateFace((uint)Face); | ||
345 | texface.TextureID = asset.FullID; | ||
346 | tmptex.FaceTextures[Face] = texface; | ||
347 | } | ||
348 | catch (Exception) | ||
349 | { | ||
350 | tmptex.DefaultTexture.TextureID = asset.FullID; | ||
351 | } | ||
352 | } | ||
353 | |||
354 | // I'm pretty sure we always want to force this to true | ||
355 | // I'm pretty sure noone whats to set fullbright true if it wasn't true before. | ||
356 | // tmptex.DefaultTexture.Fullbright = true; | ||
357 | |||
358 | part.UpdateTextureEntry(tmptex.GetBytes()); | ||
359 | } | ||
360 | 531 | ||
361 | if (oldID != UUID.Zero && ((Disp & DISP_EXPIRE) != 0)) | 532 | if (oldID != UUID.Zero && ((Disp & DISP_EXPIRE) != 0)) |
362 | { | 533 | { |
363 | if (oldAsset == null) oldAsset = scene.AssetService.Get(oldID.ToString()); | 534 | if (oldAsset == null) |
535 | oldAsset = scene.AssetService.Get(oldID.ToString()); | ||
536 | |||
364 | if (oldAsset != null) | 537 | if (oldAsset != null) |
365 | { | 538 | { |
366 | if (oldAsset.Temporary == true) | 539 | if (oldAsset.Temporary) |
367 | { | 540 | { |
368 | scene.AssetService.Delete(oldID.ToString()); | 541 | scene.AssetService.Delete(oldID.ToString()); |
369 | } | 542 | } |
370 | } | 543 | } |
371 | } | 544 | } |
545 | |||
546 | return asset.FullID; | ||
372 | } | 547 | } |
373 | 548 | ||
374 | private byte[] BlendTextures(byte[] frontImage, byte[] backImage, bool setNewAlpha, byte newAlpha) | 549 | private byte[] BlendTextures(byte[] frontImage, byte[] backImage, bool setNewAlpha, byte newAlpha) |
diff --git a/OpenSim/Region/CoreModules/Scripting/EMailModules/EmailModule.cs b/OpenSim/Region/CoreModules/Scripting/EMailModules/EmailModule.cs index e91e8b9..d943b20 100644 --- a/OpenSim/Region/CoreModules/Scripting/EMailModules/EmailModule.cs +++ b/OpenSim/Region/CoreModules/Scripting/EMailModules/EmailModule.cs | |||
@@ -37,10 +37,12 @@ using OpenMetaverse; | |||
37 | using OpenSim.Framework; | 37 | using OpenSim.Framework; |
38 | using OpenSim.Region.Framework.Interfaces; | 38 | using OpenSim.Region.Framework.Interfaces; |
39 | using OpenSim.Region.Framework.Scenes; | 39 | using OpenSim.Region.Framework.Scenes; |
40 | using Mono.Addins; | ||
40 | 41 | ||
41 | namespace OpenSim.Region.CoreModules.Scripting.EmailModules | 42 | namespace OpenSim.Region.CoreModules.Scripting.EmailModules |
42 | { | 43 | { |
43 | public class EmailModule : IRegionModule, IEmailModule | 44 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "EmailModule")] |
45 | public class EmailModule : ISharedRegionModule, IEmailModule | ||
44 | { | 46 | { |
45 | // | 47 | // |
46 | // Log | 48 | // Log |
@@ -72,31 +74,9 @@ namespace OpenSim.Region.CoreModules.Scripting.EmailModules | |||
72 | 74 | ||
73 | private bool m_Enabled = false; | 75 | private bool m_Enabled = false; |
74 | 76 | ||
75 | public void InsertEmail(UUID to, Email email) | 77 | #region ISharedRegionModule |
76 | { | ||
77 | // It's tempting to create the queue here. Don't; objects which have | ||
78 | // not yet called GetNextEmail should have no queue, and emails to them | ||
79 | // should be silently dropped. | ||
80 | |||
81 | lock (m_MailQueues) | ||
82 | { | ||
83 | if (m_MailQueues.ContainsKey(to)) | ||
84 | { | ||
85 | if (m_MailQueues[to].Count >= m_MaxQueueSize) | ||
86 | { | ||
87 | // fail silently | ||
88 | return; | ||
89 | } | ||
90 | |||
91 | lock (m_MailQueues[to]) | ||
92 | { | ||
93 | m_MailQueues[to].Add(email); | ||
94 | } | ||
95 | } | ||
96 | } | ||
97 | } | ||
98 | 78 | ||
99 | public void Initialise(Scene scene, IConfigSource config) | 79 | public void Initialise(IConfigSource config) |
100 | { | 80 | { |
101 | m_Config = config; | 81 | m_Config = config; |
102 | IConfig SMTPConfig; | 82 | IConfig SMTPConfig; |
@@ -129,36 +109,44 @@ namespace OpenSim.Region.CoreModules.Scripting.EmailModules | |||
129 | SMTP_SERVER_PORT = SMTPConfig.GetInt("SMTP_SERVER_PORT", SMTP_SERVER_PORT); | 109 | SMTP_SERVER_PORT = SMTPConfig.GetInt("SMTP_SERVER_PORT", SMTP_SERVER_PORT); |
130 | SMTP_SERVER_LOGIN = SMTPConfig.GetString("SMTP_SERVER_LOGIN", SMTP_SERVER_LOGIN); | 110 | SMTP_SERVER_LOGIN = SMTPConfig.GetString("SMTP_SERVER_LOGIN", SMTP_SERVER_LOGIN); |
131 | SMTP_SERVER_PASSWORD = SMTPConfig.GetString("SMTP_SERVER_PASSWORD", SMTP_SERVER_PASSWORD); | 111 | SMTP_SERVER_PASSWORD = SMTPConfig.GetString("SMTP_SERVER_PASSWORD", SMTP_SERVER_PASSWORD); |
132 | m_MaxEmailSize = SMTPConfig.GetInt("email_max_size", m_MaxEmailSize); | 112 | m_MaxEmailSize = SMTPConfig.GetInt("email_max_size", m_MaxEmailSize); |
133 | } | 113 | } |
134 | catch (Exception e) | 114 | catch (Exception e) |
135 | { | 115 | { |
136 | m_log.Error("[EMAIL] DefaultEmailModule not configured: "+ e.Message); | 116 | m_log.Error("[EMAIL] DefaultEmailModule not configured: " + e.Message); |
137 | m_Enabled = false; | 117 | m_Enabled = false; |
138 | return; | 118 | return; |
139 | } | 119 | } |
140 | 120 | ||
141 | // It's a go! | 121 | } |
142 | if (m_Enabled) | 122 | |
123 | public void AddRegion(Scene scene) | ||
124 | { | ||
125 | if (!m_Enabled) | ||
126 | return; | ||
127 | |||
128 | // It's a go! | ||
129 | lock (m_Scenes) | ||
143 | { | 130 | { |
144 | lock (m_Scenes) | 131 | // Claim the interface slot |
145 | { | 132 | scene.RegisterModuleInterface<IEmailModule>(this); |
146 | // Claim the interface slot | ||
147 | scene.RegisterModuleInterface<IEmailModule>(this); | ||
148 | 133 | ||
149 | // Add to scene list | 134 | // Add to scene list |
150 | if (m_Scenes.ContainsKey(scene.RegionInfo.RegionHandle)) | 135 | if (m_Scenes.ContainsKey(scene.RegionInfo.RegionHandle)) |
151 | { | 136 | { |
152 | m_Scenes[scene.RegionInfo.RegionHandle] = scene; | 137 | m_Scenes[scene.RegionInfo.RegionHandle] = scene; |
153 | } | 138 | } |
154 | else | 139 | else |
155 | { | 140 | { |
156 | m_Scenes.Add(scene.RegionInfo.RegionHandle, scene); | 141 | m_Scenes.Add(scene.RegionInfo.RegionHandle, scene); |
157 | } | ||
158 | } | 142 | } |
159 | |||
160 | m_log.Info("[EMAIL] Activated DefaultEmailModule"); | ||
161 | } | 143 | } |
144 | |||
145 | m_log.Info("[EMAIL] Activated DefaultEmailModule"); | ||
146 | } | ||
147 | |||
148 | public void RemoveRegion(Scene scene) | ||
149 | { | ||
162 | } | 150 | } |
163 | 151 | ||
164 | public void PostInitialise() | 152 | public void PostInitialise() |
@@ -174,9 +162,39 @@ namespace OpenSim.Region.CoreModules.Scripting.EmailModules | |||
174 | get { return "DefaultEmailModule"; } | 162 | get { return "DefaultEmailModule"; } |
175 | } | 163 | } |
176 | 164 | ||
177 | public bool IsSharedModule | 165 | public Type ReplaceableInterface |
166 | { | ||
167 | get { return null; } | ||
168 | } | ||
169 | |||
170 | public void RegionLoaded(Scene scene) | ||
178 | { | 171 | { |
179 | get { return true; } | 172 | } |
173 | |||
174 | #endregion | ||
175 | |||
176 | public void InsertEmail(UUID to, Email email) | ||
177 | { | ||
178 | // It's tempting to create the queue here. Don't; objects which have | ||
179 | // not yet called GetNextEmail should have no queue, and emails to them | ||
180 | // should be silently dropped. | ||
181 | |||
182 | lock (m_MailQueues) | ||
183 | { | ||
184 | if (m_MailQueues.ContainsKey(to)) | ||
185 | { | ||
186 | if (m_MailQueues[to].Count >= m_MaxQueueSize) | ||
187 | { | ||
188 | // fail silently | ||
189 | return; | ||
190 | } | ||
191 | |||
192 | lock (m_MailQueues[to]) | ||
193 | { | ||
194 | m_MailQueues[to].Add(email); | ||
195 | } | ||
196 | } | ||
197 | } | ||
180 | } | 198 | } |
181 | 199 | ||
182 | private bool IsLocal(UUID objectID) | 200 | private bool IsLocal(UUID objectID) |
diff --git a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs index 9dac6b9..a0ae203 100644 --- a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs +++ b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs | |||
@@ -41,6 +41,7 @@ using OpenSim.Framework.Servers; | |||
41 | using OpenSim.Framework.Servers.HttpServer; | 41 | using OpenSim.Framework.Servers.HttpServer; |
42 | using OpenSim.Region.Framework.Interfaces; | 42 | using OpenSim.Region.Framework.Interfaces; |
43 | using OpenSim.Region.Framework.Scenes; | 43 | using OpenSim.Region.Framework.Scenes; |
44 | using Mono.Addins; | ||
44 | 45 | ||
45 | /***************************************************** | 46 | /***************************************************** |
46 | * | 47 | * |
@@ -87,7 +88,8 @@ using OpenSim.Region.Framework.Scenes; | |||
87 | 88 | ||
88 | namespace OpenSim.Region.CoreModules.Scripting.HttpRequest | 89 | namespace OpenSim.Region.CoreModules.Scripting.HttpRequest |
89 | { | 90 | { |
90 | public class HttpRequestModule : IRegionModule, IHttpRequestModule | 91 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "HttpRequestModule")] |
92 | public class HttpRequestModule : ISharedRegionModule, IHttpRequestModule | ||
91 | { | 93 | { |
92 | private object HttpListLock = new object(); | 94 | private object HttpListLock = new object(); |
93 | private int httpTimeout = 30000; | 95 | private int httpTimeout = 30000; |
@@ -270,24 +272,38 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest | |||
270 | 272 | ||
271 | #endregion | 273 | #endregion |
272 | 274 | ||
273 | #region IRegionModule Members | 275 | #region ISharedRegionModule Members |
274 | 276 | ||
275 | public void Initialise(Scene scene, IConfigSource config) | 277 | public void Initialise(IConfigSource config) |
276 | { | 278 | { |
277 | m_scene = scene; | ||
278 | |||
279 | m_scene.RegisterModuleInterface<IHttpRequestModule>(this); | ||
280 | |||
281 | m_proxyurl = config.Configs["Startup"].GetString("HttpProxy"); | 279 | m_proxyurl = config.Configs["Startup"].GetString("HttpProxy"); |
282 | m_proxyexcepts = config.Configs["Startup"].GetString("HttpProxyExceptions"); | 280 | m_proxyexcepts = config.Configs["Startup"].GetString("HttpProxyExceptions"); |
283 | 281 | ||
284 | m_pendingRequests = new Dictionary<UUID, HttpRequestClass>(); | 282 | m_pendingRequests = new Dictionary<UUID, HttpRequestClass>(); |
285 | } | 283 | } |
286 | 284 | ||
285 | public void AddRegion(Scene scene) | ||
286 | { | ||
287 | m_scene = scene; | ||
288 | |||
289 | m_scene.RegisterModuleInterface<IHttpRequestModule>(this); | ||
290 | } | ||
291 | |||
292 | public void RemoveRegion(Scene scene) | ||
293 | { | ||
294 | scene.UnregisterModuleInterface<IHttpRequestModule>(this); | ||
295 | if (scene == m_scene) | ||
296 | m_scene = null; | ||
297 | } | ||
298 | |||
287 | public void PostInitialise() | 299 | public void PostInitialise() |
288 | { | 300 | { |
289 | } | 301 | } |
290 | 302 | ||
303 | public void RegionLoaded(Scene scene) | ||
304 | { | ||
305 | } | ||
306 | |||
291 | public void Close() | 307 | public void Close() |
292 | { | 308 | { |
293 | } | 309 | } |
@@ -297,9 +313,9 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest | |||
297 | get { return m_name; } | 313 | get { return m_name; } |
298 | } | 314 | } |
299 | 315 | ||
300 | public bool IsSharedModule | 316 | public Type ReplaceableInterface |
301 | { | 317 | { |
302 | get { return true; } | 318 | get { return null; } |
303 | } | 319 | } |
304 | 320 | ||
305 | #endregion | 321 | #endregion |
diff --git a/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs b/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs index 56221aa..da59eab 100644 --- a/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs +++ b/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs | |||
@@ -31,6 +31,7 @@ using System.Collections.Generic; | |||
31 | using System.Collections; | 31 | using System.Collections; |
32 | using System.Reflection; | 32 | using System.Reflection; |
33 | using log4net; | 33 | using log4net; |
34 | using Mono.Addins; | ||
34 | using Nini.Config; | 35 | using Nini.Config; |
35 | using OpenMetaverse; | 36 | using OpenMetaverse; |
36 | using OpenSim.Framework; | 37 | using OpenSim.Framework; |
@@ -58,6 +59,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp | |||
58 | public string body; | 59 | public string body; |
59 | public int responseCode; | 60 | public int responseCode; |
60 | public string responseBody; | 61 | public string responseBody; |
62 | public string responseType = "text/plain"; | ||
61 | //public ManualResetEvent ev; | 63 | //public ManualResetEvent ev; |
62 | public bool requestDone; | 64 | public bool requestDone; |
63 | public int startTime; | 65 | public int startTime; |
@@ -65,6 +67,10 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp | |||
65 | public string uri; | 67 | public string uri; |
66 | } | 68 | } |
67 | 69 | ||
70 | /// <summary> | ||
71 | /// This module provides external URLs for in-world scripts. | ||
72 | /// </summary> | ||
73 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "UrlModule")] | ||
68 | public class UrlModule : ISharedRegionModule, IUrlModule | 74 | public class UrlModule : ISharedRegionModule, IUrlModule |
69 | { | 75 | { |
70 | private static readonly ILog m_log = | 76 | private static readonly ILog m_log = |
@@ -270,6 +276,22 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp | |||
270 | } | 276 | } |
271 | } | 277 | } |
272 | 278 | ||
279 | public void HttpContentType(UUID request, string type) | ||
280 | { | ||
281 | lock (m_UrlMap) | ||
282 | { | ||
283 | if (m_RequestMap.ContainsKey(request)) | ||
284 | { | ||
285 | UrlData urlData = m_RequestMap[request]; | ||
286 | urlData.requests[request].responseType = type; | ||
287 | } | ||
288 | else | ||
289 | { | ||
290 | m_log.Info("[HttpRequestHandler] There is no http-in request with id " + request.ToString()); | ||
291 | } | ||
292 | } | ||
293 | } | ||
294 | |||
273 | public void HttpResponse(UUID request, int status, string body) | 295 | public void HttpResponse(UUID request, int status, string body) |
274 | { | 296 | { |
275 | lock (m_RequestMap) | 297 | lock (m_RequestMap) |
diff --git a/OpenSim/Region/CoreModules/Scripting/LoadImageURL/LoadImageURLModule.cs b/OpenSim/Region/CoreModules/Scripting/LoadImageURL/LoadImageURLModule.cs index 6f83948..65737fa 100644 --- a/OpenSim/Region/CoreModules/Scripting/LoadImageURL/LoadImageURLModule.cs +++ b/OpenSim/Region/CoreModules/Scripting/LoadImageURL/LoadImageURLModule.cs | |||
@@ -32,14 +32,17 @@ using System.Net; | |||
32 | using Nini.Config; | 32 | using Nini.Config; |
33 | using OpenMetaverse; | 33 | using OpenMetaverse; |
34 | using OpenMetaverse.Imaging; | 34 | using OpenMetaverse.Imaging; |
35 | using OpenSim.Region.CoreModules.Scripting.DynamicTexture; | ||
35 | using OpenSim.Region.Framework.Interfaces; | 36 | using OpenSim.Region.Framework.Interfaces; |
36 | using OpenSim.Region.Framework.Scenes; | 37 | using OpenSim.Region.Framework.Scenes; |
37 | using log4net; | 38 | using log4net; |
38 | using System.Reflection; | 39 | using System.Reflection; |
40 | using Mono.Addins; | ||
39 | 41 | ||
40 | namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL | 42 | namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL |
41 | { | 43 | { |
42 | public class LoadImageURLModule : IRegionModule, IDynamicTextureRender | 44 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "LoadImageURLModule")] |
45 | public class LoadImageURLModule : ISharedRegionModule, IDynamicTextureRender | ||
43 | { | 46 | { |
44 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 47 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
45 | 48 | ||
@@ -67,12 +70,18 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL | |||
67 | return true; | 70 | return true; |
68 | } | 71 | } |
69 | 72 | ||
70 | public byte[] ConvertUrl(string url, string extraParams) | 73 | // public bool AlwaysIdenticalConversion(string bodyData, string extraParams) |
74 | // { | ||
75 | // // We don't support conversion of body data. | ||
76 | // return false; | ||
77 | // } | ||
78 | |||
79 | public IDynamicTexture ConvertUrl(string url, string extraParams) | ||
71 | { | 80 | { |
72 | return null; | 81 | return null; |
73 | } | 82 | } |
74 | 83 | ||
75 | public byte[] ConvertStream(Stream data, string extraParams) | 84 | public IDynamicTexture ConvertData(string bodyData, string extraParams) |
76 | { | 85 | { |
77 | return null; | 86 | return null; |
78 | } | 87 | } |
@@ -97,22 +106,32 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL | |||
97 | 106 | ||
98 | #endregion | 107 | #endregion |
99 | 108 | ||
100 | #region IRegionModule Members | 109 | #region ISharedRegionModule Members |
101 | 110 | ||
102 | public void Initialise(Scene scene, IConfigSource config) | 111 | public void Initialise(IConfigSource config) |
103 | { | 112 | { |
104 | if (m_scene == null) | ||
105 | { | ||
106 | m_scene = scene; | ||
107 | } | ||
108 | |||
109 | m_proxyurl = config.Configs["Startup"].GetString("HttpProxy"); | 113 | m_proxyurl = config.Configs["Startup"].GetString("HttpProxy"); |
110 | m_proxyexcepts = config.Configs["Startup"].GetString("HttpProxyExceptions"); | 114 | m_proxyexcepts = config.Configs["Startup"].GetString("HttpProxyExceptions"); |
111 | } | 115 | } |
112 | 116 | ||
113 | public void PostInitialise() | 117 | public void PostInitialise() |
114 | { | 118 | { |
115 | if (m_scene != null) | 119 | } |
120 | |||
121 | public void AddRegion(Scene scene) | ||
122 | { | ||
123 | if (m_scene == null) | ||
124 | m_scene = scene; | ||
125 | |||
126 | } | ||
127 | |||
128 | public void RemoveRegion(Scene scene) | ||
129 | { | ||
130 | } | ||
131 | |||
132 | public void RegionLoaded(Scene scene) | ||
133 | { | ||
134 | if (m_textureManager == null && m_scene == scene) | ||
116 | { | 135 | { |
117 | m_textureManager = m_scene.RequestModuleInterface<IDynamicTextureManager>(); | 136 | m_textureManager = m_scene.RequestModuleInterface<IDynamicTextureManager>(); |
118 | if (m_textureManager != null) | 137 | if (m_textureManager != null) |
@@ -131,9 +150,9 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL | |||
131 | get { return m_name; } | 150 | get { return m_name; } |
132 | } | 151 | } |
133 | 152 | ||
134 | public bool IsSharedModule | 153 | public Type ReplaceableInterface |
135 | { | 154 | { |
136 | get { return true; } | 155 | get { return null; } |
137 | } | 156 | } |
138 | 157 | ||
139 | #endregion | 158 | #endregion |
@@ -165,11 +184,17 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL | |||
165 | 184 | ||
166 | private void HttpRequestReturn(IAsyncResult result) | 185 | private void HttpRequestReturn(IAsyncResult result) |
167 | { | 186 | { |
187 | if (m_textureManager == null) | ||
188 | { | ||
189 | m_log.WarnFormat("[LOADIMAGEURLMODULE]: No texture manager. Can't function."); | ||
190 | return; | ||
191 | } | ||
168 | 192 | ||
169 | RequestState state = (RequestState) result.AsyncState; | 193 | RequestState state = (RequestState) result.AsyncState; |
170 | WebRequest request = (WebRequest) state.Request; | 194 | WebRequest request = (WebRequest) state.Request; |
171 | Stream stream = null; | 195 | Stream stream = null; |
172 | byte[] imageJ2000 = new byte[0]; | 196 | byte[] imageJ2000 = new byte[0]; |
197 | Size newSize = new Size(0, 0); | ||
173 | 198 | ||
174 | try | 199 | try |
175 | { | 200 | { |
@@ -182,37 +207,43 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL | |||
182 | try | 207 | try |
183 | { | 208 | { |
184 | Bitmap image = new Bitmap(stream); | 209 | Bitmap image = new Bitmap(stream); |
185 | Size newsize; | ||
186 | 210 | ||
187 | // TODO: make this a bit less hard coded | 211 | // TODO: make this a bit less hard coded |
188 | if ((image.Height < 64) && (image.Width < 64)) | 212 | if ((image.Height < 64) && (image.Width < 64)) |
189 | { | 213 | { |
190 | newsize = new Size(32, 32); | 214 | newSize.Width = 32; |
215 | newSize.Height = 32; | ||
191 | } | 216 | } |
192 | else if ((image.Height < 128) && (image.Width < 128)) | 217 | else if ((image.Height < 128) && (image.Width < 128)) |
193 | { | 218 | { |
194 | newsize = new Size(64, 64); | 219 | newSize.Width = 64; |
220 | newSize.Height = 64; | ||
195 | } | 221 | } |
196 | else if ((image.Height < 256) && (image.Width < 256)) | 222 | else if ((image.Height < 256) && (image.Width < 256)) |
197 | { | 223 | { |
198 | newsize = new Size(128, 128); | 224 | newSize.Width = 128; |
225 | newSize.Height = 128; | ||
199 | } | 226 | } |
200 | else if ((image.Height < 512 && image.Width < 512)) | 227 | else if ((image.Height < 512 && image.Width < 512)) |
201 | { | 228 | { |
202 | newsize = new Size(256, 256); | 229 | newSize.Width = 256; |
230 | newSize.Height = 256; | ||
203 | } | 231 | } |
204 | else if ((image.Height < 1024 && image.Width < 1024)) | 232 | else if ((image.Height < 1024 && image.Width < 1024)) |
205 | { | 233 | { |
206 | newsize = new Size(512, 512); | 234 | newSize.Width = 512; |
235 | newSize.Height = 512; | ||
207 | } | 236 | } |
208 | else | 237 | else |
209 | { | 238 | { |
210 | newsize = new Size(1024, 1024); | 239 | newSize.Width = 1024; |
240 | newSize.Height = 1024; | ||
211 | } | 241 | } |
212 | 242 | ||
213 | Bitmap resize = new Bitmap(image, newsize); | 243 | using (Bitmap resize = new Bitmap(image, newSize)) |
214 | 244 | { | |
215 | imageJ2000 = OpenJPEG.EncodeFromImage(resize, true); | 245 | imageJ2000 = OpenJPEG.EncodeFromImage(resize, true); |
246 | } | ||
216 | } | 247 | } |
217 | catch (Exception) | 248 | catch (Exception) |
218 | { | 249 | { |
@@ -227,7 +258,6 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL | |||
227 | } | 258 | } |
228 | catch (WebException) | 259 | catch (WebException) |
229 | { | 260 | { |
230 | |||
231 | } | 261 | } |
232 | finally | 262 | finally |
233 | { | 263 | { |
@@ -236,9 +266,14 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL | |||
236 | stream.Close(); | 266 | stream.Close(); |
237 | } | 267 | } |
238 | } | 268 | } |
239 | m_log.DebugFormat("[LOADIMAGEURLMODULE] Returning {0} bytes of image data for request {1}", | 269 | |
270 | m_log.DebugFormat("[LOADIMAGEURLMODULE]: Returning {0} bytes of image data for request {1}", | ||
240 | imageJ2000.Length, state.RequestID); | 271 | imageJ2000.Length, state.RequestID); |
241 | m_textureManager.ReturnData(state.RequestID, imageJ2000); | 272 | |
273 | m_textureManager.ReturnData( | ||
274 | state.RequestID, | ||
275 | new OpenSim.Region.CoreModules.Scripting.DynamicTexture.DynamicTexture( | ||
276 | request.RequestUri, null, imageJ2000, newSize, false)); | ||
242 | } | 277 | } |
243 | 278 | ||
244 | #region Nested type: RequestState | 279 | #region Nested type: RequestState |
diff --git a/OpenSim/Region/CoreModules/Scripting/ScriptModuleComms/ScriptModuleCommsModule.cs b/OpenSim/Region/CoreModules/Scripting/ScriptModuleComms/ScriptModuleCommsModule.cs new file mode 100644 index 0000000..f6e1d39 --- /dev/null +++ b/OpenSim/Region/CoreModules/Scripting/ScriptModuleComms/ScriptModuleCommsModule.cs | |||
@@ -0,0 +1,383 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Reflection; | ||
30 | using System.Collections.Generic; | ||
31 | using Nini.Config; | ||
32 | using log4net; | ||
33 | using OpenSim.Framework; | ||
34 | using OpenSim.Region.Framework.Interfaces; | ||
35 | using OpenSim.Region.Framework.Scenes; | ||
36 | using Mono.Addins; | ||
37 | using OpenMetaverse; | ||
38 | using System.Linq; | ||
39 | using System.Linq.Expressions; | ||
40 | |||
41 | namespace OpenSim.Region.CoreModules.Scripting.ScriptModuleComms | ||
42 | { | ||
43 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "ScriptModuleCommsModule")] | ||
44 | class ScriptModuleCommsModule : INonSharedRegionModule, IScriptModuleComms | ||
45 | { | ||
46 | private static readonly ILog m_log = | ||
47 | LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
48 | |||
49 | private Dictionary<string,object> m_constants = new Dictionary<string,object>(); | ||
50 | |||
51 | #region ScriptInvocation | ||
52 | protected class ScriptInvocationData | ||
53 | { | ||
54 | public Delegate ScriptInvocationDelegate { get; private set; } | ||
55 | public string FunctionName { get; private set; } | ||
56 | public Type[] TypeSignature { get; private set; } | ||
57 | public Type ReturnType { get; private set; } | ||
58 | |||
59 | public ScriptInvocationData(string fname, Delegate fn, Type[] callsig, Type returnsig) | ||
60 | { | ||
61 | FunctionName = fname; | ||
62 | ScriptInvocationDelegate = fn; | ||
63 | TypeSignature = callsig; | ||
64 | ReturnType = returnsig; | ||
65 | } | ||
66 | } | ||
67 | |||
68 | private Dictionary<string,ScriptInvocationData> m_scriptInvocation = new Dictionary<string,ScriptInvocationData>(); | ||
69 | #endregion | ||
70 | |||
71 | private IScriptModule m_scriptModule = null; | ||
72 | public event ScriptCommand OnScriptCommand; | ||
73 | |||
74 | #region RegionModuleInterface | ||
75 | public void Initialise(IConfigSource config) | ||
76 | { | ||
77 | } | ||
78 | |||
79 | public void AddRegion(Scene scene) | ||
80 | { | ||
81 | scene.RegisterModuleInterface<IScriptModuleComms>(this); | ||
82 | } | ||
83 | |||
84 | public void RemoveRegion(Scene scene) | ||
85 | { | ||
86 | } | ||
87 | |||
88 | public void RegionLoaded(Scene scene) | ||
89 | { | ||
90 | m_scriptModule = scene.RequestModuleInterface<IScriptModule>(); | ||
91 | |||
92 | if (m_scriptModule != null) | ||
93 | m_log.Info("[MODULE COMMANDS]: Script engine found, module active"); | ||
94 | } | ||
95 | |||
96 | public string Name | ||
97 | { | ||
98 | get { return "ScriptModuleCommsModule"; } | ||
99 | } | ||
100 | |||
101 | public Type ReplaceableInterface | ||
102 | { | ||
103 | get { return null; } | ||
104 | } | ||
105 | |||
106 | public void Close() | ||
107 | { | ||
108 | } | ||
109 | #endregion | ||
110 | |||
111 | #region ScriptModuleComms | ||
112 | |||
113 | public void RaiseEvent(UUID script, string id, string module, string command, string k) | ||
114 | { | ||
115 | ScriptCommand c = OnScriptCommand; | ||
116 | |||
117 | if (c == null) | ||
118 | return; | ||
119 | |||
120 | c(script, id, module, command, k); | ||
121 | } | ||
122 | |||
123 | public void DispatchReply(UUID script, int code, string text, string k) | ||
124 | { | ||
125 | if (m_scriptModule == null) | ||
126 | return; | ||
127 | |||
128 | Object[] args = new Object[] {-1, code, text, k}; | ||
129 | |||
130 | m_scriptModule.PostScriptEvent(script, "link_message", args); | ||
131 | } | ||
132 | |||
133 | private static MethodInfo GetMethodInfoFromType(Type target, string meth, bool searchInstanceMethods) | ||
134 | { | ||
135 | BindingFlags getMethodFlags = | ||
136 | BindingFlags.NonPublic | BindingFlags.Public; | ||
137 | |||
138 | if (searchInstanceMethods) | ||
139 | getMethodFlags |= BindingFlags.Instance; | ||
140 | else | ||
141 | getMethodFlags |= BindingFlags.Static; | ||
142 | |||
143 | return target.GetMethod(meth, getMethodFlags); | ||
144 | } | ||
145 | |||
146 | public void RegisterScriptInvocation(object target, string meth) | ||
147 | { | ||
148 | MethodInfo mi = GetMethodInfoFromType(target.GetType(), meth, true); | ||
149 | if (mi == null) | ||
150 | { | ||
151 | m_log.WarnFormat("[MODULE COMMANDS] Failed to register method {0}", meth); | ||
152 | return; | ||
153 | } | ||
154 | |||
155 | RegisterScriptInvocation(target, mi); | ||
156 | } | ||
157 | |||
158 | public void RegisterScriptInvocation(object target, string[] meth) | ||
159 | { | ||
160 | foreach (string m in meth) | ||
161 | RegisterScriptInvocation(target, m); | ||
162 | } | ||
163 | |||
164 | public void RegisterScriptInvocation(object target, MethodInfo mi) | ||
165 | { | ||
166 | m_log.DebugFormat("[MODULE COMMANDS] Register method {0} from type {1}", mi.Name, (target is Type) ? ((Type)target).Name : target.GetType().Name); | ||
167 | |||
168 | Type delegateType; | ||
169 | List<Type> typeArgs = mi.GetParameters() | ||
170 | .Select(p => p.ParameterType) | ||
171 | .ToList(); | ||
172 | |||
173 | if (mi.ReturnType == typeof(void)) | ||
174 | { | ||
175 | delegateType = Expression.GetActionType(typeArgs.ToArray()); | ||
176 | } | ||
177 | else | ||
178 | { | ||
179 | typeArgs.Add(mi.ReturnType); | ||
180 | delegateType = Expression.GetFuncType(typeArgs.ToArray()); | ||
181 | } | ||
182 | |||
183 | Delegate fcall; | ||
184 | if (!(target is Type)) | ||
185 | fcall = Delegate.CreateDelegate(delegateType, target, mi); | ||
186 | else | ||
187 | fcall = Delegate.CreateDelegate(delegateType, (Type)target, mi.Name); | ||
188 | |||
189 | lock (m_scriptInvocation) | ||
190 | { | ||
191 | ParameterInfo[] parameters = fcall.Method.GetParameters(); | ||
192 | if (parameters.Length < 2) // Must have two UUID params | ||
193 | return; | ||
194 | |||
195 | // Hide the first two parameters | ||
196 | Type[] parmTypes = new Type[parameters.Length - 2]; | ||
197 | for (int i = 2; i < parameters.Length; i++) | ||
198 | parmTypes[i - 2] = parameters[i].ParameterType; | ||
199 | m_scriptInvocation[fcall.Method.Name] = new ScriptInvocationData(fcall.Method.Name, fcall, parmTypes, fcall.Method.ReturnType); | ||
200 | } | ||
201 | } | ||
202 | |||
203 | public void RegisterScriptInvocation(Type target, string[] methods) | ||
204 | { | ||
205 | foreach (string method in methods) | ||
206 | { | ||
207 | MethodInfo mi = GetMethodInfoFromType(target, method, false); | ||
208 | if (mi == null) | ||
209 | m_log.WarnFormat("[MODULE COMMANDS] Failed to register method {0}", method); | ||
210 | else | ||
211 | RegisterScriptInvocation(target, mi); | ||
212 | } | ||
213 | } | ||
214 | |||
215 | public void RegisterScriptInvocations(IRegionModuleBase target) | ||
216 | { | ||
217 | foreach(MethodInfo method in target.GetType().GetMethods( | ||
218 | BindingFlags.Public | BindingFlags.Instance | | ||
219 | BindingFlags.Static)) | ||
220 | { | ||
221 | if(method.GetCustomAttributes( | ||
222 | typeof(ScriptInvocationAttribute), true).Any()) | ||
223 | { | ||
224 | if(method.IsStatic) | ||
225 | RegisterScriptInvocation(target.GetType(), method); | ||
226 | else | ||
227 | RegisterScriptInvocation(target, method); | ||
228 | } | ||
229 | } | ||
230 | } | ||
231 | |||
232 | public Delegate[] GetScriptInvocationList() | ||
233 | { | ||
234 | List<Delegate> ret = new List<Delegate>(); | ||
235 | |||
236 | lock (m_scriptInvocation) | ||
237 | { | ||
238 | foreach (ScriptInvocationData d in m_scriptInvocation.Values) | ||
239 | ret.Add(d.ScriptInvocationDelegate); | ||
240 | } | ||
241 | return ret.ToArray(); | ||
242 | } | ||
243 | |||
244 | public string LookupModInvocation(string fname) | ||
245 | { | ||
246 | lock (m_scriptInvocation) | ||
247 | { | ||
248 | ScriptInvocationData sid; | ||
249 | if (m_scriptInvocation.TryGetValue(fname,out sid)) | ||
250 | { | ||
251 | if (sid.ReturnType == typeof(string)) | ||
252 | return "modInvokeS"; | ||
253 | else if (sid.ReturnType == typeof(int)) | ||
254 | return "modInvokeI"; | ||
255 | else if (sid.ReturnType == typeof(float)) | ||
256 | return "modInvokeF"; | ||
257 | else if (sid.ReturnType == typeof(UUID)) | ||
258 | return "modInvokeK"; | ||
259 | else if (sid.ReturnType == typeof(OpenMetaverse.Vector3)) | ||
260 | return "modInvokeV"; | ||
261 | else if (sid.ReturnType == typeof(OpenMetaverse.Quaternion)) | ||
262 | return "modInvokeR"; | ||
263 | else if (sid.ReturnType == typeof(object[])) | ||
264 | return "modInvokeL"; | ||
265 | |||
266 | m_log.WarnFormat("[MODULE COMMANDS] failed to find match for {0} with return type {1}",fname,sid.ReturnType.Name); | ||
267 | } | ||
268 | } | ||
269 | |||
270 | return null; | ||
271 | } | ||
272 | |||
273 | public Delegate LookupScriptInvocation(string fname) | ||
274 | { | ||
275 | lock (m_scriptInvocation) | ||
276 | { | ||
277 | ScriptInvocationData sid; | ||
278 | if (m_scriptInvocation.TryGetValue(fname,out sid)) | ||
279 | return sid.ScriptInvocationDelegate; | ||
280 | } | ||
281 | |||
282 | return null; | ||
283 | } | ||
284 | |||
285 | public Type[] LookupTypeSignature(string fname) | ||
286 | { | ||
287 | lock (m_scriptInvocation) | ||
288 | { | ||
289 | ScriptInvocationData sid; | ||
290 | if (m_scriptInvocation.TryGetValue(fname,out sid)) | ||
291 | return sid.TypeSignature; | ||
292 | } | ||
293 | |||
294 | return null; | ||
295 | } | ||
296 | |||
297 | public Type LookupReturnType(string fname) | ||
298 | { | ||
299 | lock (m_scriptInvocation) | ||
300 | { | ||
301 | ScriptInvocationData sid; | ||
302 | if (m_scriptInvocation.TryGetValue(fname,out sid)) | ||
303 | return sid.ReturnType; | ||
304 | } | ||
305 | |||
306 | return null; | ||
307 | } | ||
308 | |||
309 | public object InvokeOperation(UUID hostid, UUID scriptid, string fname, params object[] parms) | ||
310 | { | ||
311 | List<object> olist = new List<object>(); | ||
312 | olist.Add(hostid); | ||
313 | olist.Add(scriptid); | ||
314 | foreach (object o in parms) | ||
315 | olist.Add(o); | ||
316 | Delegate fn = LookupScriptInvocation(fname); | ||
317 | return fn.DynamicInvoke(olist.ToArray()); | ||
318 | } | ||
319 | |||
320 | /// <summary> | ||
321 | /// Operation to for a region module to register a constant to be used | ||
322 | /// by the script engine | ||
323 | /// </summary> | ||
324 | public void RegisterConstant(string cname, object value) | ||
325 | { | ||
326 | m_log.DebugFormat("[MODULE COMMANDS] register constant <{0}> with value {1}",cname,value.ToString()); | ||
327 | lock (m_constants) | ||
328 | { | ||
329 | m_constants.Add(cname,value); | ||
330 | } | ||
331 | } | ||
332 | |||
333 | public void RegisterConstants(IRegionModuleBase target) | ||
334 | { | ||
335 | foreach (FieldInfo field in target.GetType().GetFields( | ||
336 | BindingFlags.Public | BindingFlags.Static | | ||
337 | BindingFlags.Instance)) | ||
338 | { | ||
339 | if (field.GetCustomAttributes( | ||
340 | typeof(ScriptConstantAttribute), true).Any()) | ||
341 | { | ||
342 | RegisterConstant(field.Name, field.GetValue(target)); | ||
343 | } | ||
344 | } | ||
345 | } | ||
346 | |||
347 | /// <summary> | ||
348 | /// Operation to check for a registered constant | ||
349 | /// </summary> | ||
350 | public object LookupModConstant(string cname) | ||
351 | { | ||
352 | // m_log.DebugFormat("[MODULE COMMANDS] lookup constant <{0}>",cname); | ||
353 | |||
354 | lock (m_constants) | ||
355 | { | ||
356 | object value = null; | ||
357 | if (m_constants.TryGetValue(cname,out value)) | ||
358 | return value; | ||
359 | } | ||
360 | |||
361 | return null; | ||
362 | } | ||
363 | |||
364 | /// <summary> | ||
365 | /// Get all registered constants | ||
366 | /// </summary> | ||
367 | public Dictionary<string, object> GetConstants() | ||
368 | { | ||
369 | Dictionary<string, object> ret = new Dictionary<string, object>(); | ||
370 | |||
371 | lock (m_constants) | ||
372 | { | ||
373 | foreach (KeyValuePair<string, object> kvp in m_constants) | ||
374 | ret[kvp.Key] = kvp.Value; | ||
375 | } | ||
376 | |||
377 | return ret; | ||
378 | } | ||
379 | |||
380 | #endregion | ||
381 | |||
382 | } | ||
383 | } | ||
diff --git a/OpenSim/Region/CoreModules/Scripting/VectorRender/Tests/VectorRenderModuleTests.cs b/OpenSim/Region/CoreModules/Scripting/VectorRender/Tests/VectorRenderModuleTests.cs index 9787c8c..41baccc 100644 --- a/OpenSim/Region/CoreModules/Scripting/VectorRender/Tests/VectorRenderModuleTests.cs +++ b/OpenSim/Region/CoreModules/Scripting/VectorRender/Tests/VectorRenderModuleTests.cs | |||
@@ -45,31 +45,292 @@ using OpenSim.Tests.Common.Mock; | |||
45 | namespace OpenSim.Region.CoreModules.Scripting.VectorRender.Tests | 45 | namespace OpenSim.Region.CoreModules.Scripting.VectorRender.Tests |
46 | { | 46 | { |
47 | [TestFixture] | 47 | [TestFixture] |
48 | public class VectorRenderModuleTests | 48 | public class VectorRenderModuleTests : OpenSimTestCase |
49 | { | 49 | { |
50 | Scene m_scene; | ||
51 | DynamicTextureModule m_dtm; | ||
52 | VectorRenderModule m_vrm; | ||
53 | |||
54 | private void SetupScene(bool reuseTextures) | ||
55 | { | ||
56 | m_scene = new SceneHelpers().SetupScene(); | ||
57 | |||
58 | m_dtm = new DynamicTextureModule(); | ||
59 | m_dtm.ReuseTextures = reuseTextures; | ||
60 | // m_dtm.ReuseLowDataTextures = reuseTextures; | ||
61 | |||
62 | m_vrm = new VectorRenderModule(); | ||
63 | |||
64 | SceneHelpers.SetupSceneModules(m_scene, m_dtm, m_vrm); | ||
65 | } | ||
66 | |||
50 | [Test] | 67 | [Test] |
51 | public void TestDraw() | 68 | public void TestDraw() |
52 | { | 69 | { |
53 | TestHelpers.InMethod(); | 70 | TestHelpers.InMethod(); |
54 | 71 | ||
55 | Scene scene = new SceneHelpers().SetupScene(); | 72 | SetupScene(false); |
56 | DynamicTextureModule dtm = new DynamicTextureModule(); | 73 | SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene); |
57 | VectorRenderModule vrm = new VectorRenderModule(); | ||
58 | SceneHelpers.SetupSceneModules(scene, dtm, vrm); | ||
59 | |||
60 | SceneObjectGroup so = SceneHelpers.AddSceneObject(scene); | ||
61 | UUID originalTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID; | 74 | UUID originalTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID; |
62 | 75 | ||
63 | dtm.AddDynamicTextureData( | 76 | m_dtm.AddDynamicTextureData( |
64 | scene.RegionInfo.RegionID, | 77 | m_scene.RegionInfo.RegionID, |
65 | so.UUID, | 78 | so.UUID, |
66 | vrm.GetContentType(), | 79 | m_vrm.GetContentType(), |
67 | "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World;", | 80 | "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World;", |
68 | "", | 81 | "", |
69 | 0); | 82 | 0); |
70 | 83 | ||
84 | Assert.That(originalTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID)); | ||
85 | } | ||
86 | |||
87 | [Test] | ||
88 | public void TestRepeatSameDraw() | ||
89 | { | ||
90 | TestHelpers.InMethod(); | ||
91 | |||
92 | string dtText = "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World;"; | ||
93 | |||
94 | SetupScene(false); | ||
95 | SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene); | ||
96 | |||
97 | m_dtm.AddDynamicTextureData( | ||
98 | m_scene.RegionInfo.RegionID, | ||
99 | so.UUID, | ||
100 | m_vrm.GetContentType(), | ||
101 | dtText, | ||
102 | "", | ||
103 | 0); | ||
104 | |||
105 | UUID firstDynamicTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID; | ||
106 | |||
107 | m_dtm.AddDynamicTextureData( | ||
108 | m_scene.RegionInfo.RegionID, | ||
109 | so.UUID, | ||
110 | m_vrm.GetContentType(), | ||
111 | dtText, | ||
112 | "", | ||
113 | 0); | ||
114 | |||
115 | Assert.That(firstDynamicTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID)); | ||
116 | } | ||
117 | |||
118 | [Test] | ||
119 | public void TestRepeatSameDrawDifferentExtraParams() | ||
120 | { | ||
121 | TestHelpers.InMethod(); | ||
122 | |||
123 | string dtText = "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World;"; | ||
124 | |||
125 | SetupScene(false); | ||
126 | SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene); | ||
127 | |||
128 | m_dtm.AddDynamicTextureData( | ||
129 | m_scene.RegionInfo.RegionID, | ||
130 | so.UUID, | ||
131 | m_vrm.GetContentType(), | ||
132 | dtText, | ||
133 | "", | ||
134 | 0); | ||
135 | |||
136 | UUID firstDynamicTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID; | ||
137 | |||
138 | m_dtm.AddDynamicTextureData( | ||
139 | m_scene.RegionInfo.RegionID, | ||
140 | so.UUID, | ||
141 | m_vrm.GetContentType(), | ||
142 | dtText, | ||
143 | "alpha:250", | ||
144 | 0); | ||
145 | |||
146 | Assert.That(firstDynamicTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID)); | ||
147 | } | ||
148 | |||
149 | [Test] | ||
150 | public void TestRepeatSameDrawContainingImage() | ||
151 | { | ||
152 | TestHelpers.InMethod(); | ||
153 | |||
154 | string dtText | ||
155 | = "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World; Image http://localhost/shouldnotexist.png"; | ||
156 | |||
157 | SetupScene(false); | ||
158 | SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene); | ||
159 | |||
160 | m_dtm.AddDynamicTextureData( | ||
161 | m_scene.RegionInfo.RegionID, | ||
162 | so.UUID, | ||
163 | m_vrm.GetContentType(), | ||
164 | dtText, | ||
165 | "", | ||
166 | 0); | ||
167 | |||
168 | UUID firstDynamicTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID; | ||
169 | |||
170 | m_dtm.AddDynamicTextureData( | ||
171 | m_scene.RegionInfo.RegionID, | ||
172 | so.UUID, | ||
173 | m_vrm.GetContentType(), | ||
174 | dtText, | ||
175 | "", | ||
176 | 0); | ||
177 | |||
178 | Assert.That(firstDynamicTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID)); | ||
179 | } | ||
180 | |||
181 | [Test] | ||
182 | public void TestDrawReusingTexture() | ||
183 | { | ||
184 | TestHelpers.InMethod(); | ||
185 | |||
186 | SetupScene(true); | ||
187 | SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene); | ||
188 | UUID originalTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID; | ||
189 | |||
190 | m_dtm.AddDynamicTextureData( | ||
191 | m_scene.RegionInfo.RegionID, | ||
192 | so.UUID, | ||
193 | m_vrm.GetContentType(), | ||
194 | "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World;", | ||
195 | "", | ||
196 | 0); | ||
71 | 197 | ||
72 | Assert.That(originalTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID)); | 198 | Assert.That(originalTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID)); |
73 | } | 199 | } |
200 | |||
201 | [Test] | ||
202 | public void TestRepeatSameDrawReusingTexture() | ||
203 | { | ||
204 | TestHelpers.InMethod(); | ||
205 | // TestHelpers.EnableLogging(); | ||
206 | |||
207 | string dtText = "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World;"; | ||
208 | |||
209 | SetupScene(true); | ||
210 | SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene); | ||
211 | |||
212 | m_dtm.AddDynamicTextureData( | ||
213 | m_scene.RegionInfo.RegionID, | ||
214 | so.UUID, | ||
215 | m_vrm.GetContentType(), | ||
216 | dtText, | ||
217 | "", | ||
218 | 0); | ||
219 | |||
220 | UUID firstDynamicTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID; | ||
221 | |||
222 | m_dtm.AddDynamicTextureData( | ||
223 | m_scene.RegionInfo.RegionID, | ||
224 | so.UUID, | ||
225 | m_vrm.GetContentType(), | ||
226 | dtText, | ||
227 | "", | ||
228 | 0); | ||
229 | |||
230 | Assert.That(firstDynamicTextureID, Is.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID)); | ||
231 | } | ||
232 | |||
233 | /// <summary> | ||
234 | /// Test a low data dynamically generated texture such that it is treated as a low data texture that causes | ||
235 | /// problems for current viewers. | ||
236 | /// </summary> | ||
237 | /// <remarks> | ||
238 | /// As we do not set DynamicTextureModule.ReuseLowDataTextures = true in this test, it should not reuse the | ||
239 | /// texture | ||
240 | /// </remarks> | ||
241 | [Test] | ||
242 | public void TestRepeatSameDrawLowDataTexture() | ||
243 | { | ||
244 | TestHelpers.InMethod(); | ||
245 | // TestHelpers.EnableLogging(); | ||
246 | |||
247 | string dtText = "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World;"; | ||
248 | |||
249 | SetupScene(true); | ||
250 | SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene); | ||
251 | |||
252 | m_dtm.AddDynamicTextureData( | ||
253 | m_scene.RegionInfo.RegionID, | ||
254 | so.UUID, | ||
255 | m_vrm.GetContentType(), | ||
256 | dtText, | ||
257 | "1024", | ||
258 | 0); | ||
259 | |||
260 | UUID firstDynamicTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID; | ||
261 | |||
262 | m_dtm.AddDynamicTextureData( | ||
263 | m_scene.RegionInfo.RegionID, | ||
264 | so.UUID, | ||
265 | m_vrm.GetContentType(), | ||
266 | dtText, | ||
267 | "1024", | ||
268 | 0); | ||
269 | |||
270 | Assert.That(firstDynamicTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID)); | ||
271 | } | ||
272 | |||
273 | [Test] | ||
274 | public void TestRepeatSameDrawDifferentExtraParamsReusingTexture() | ||
275 | { | ||
276 | TestHelpers.InMethod(); | ||
277 | |||
278 | string dtText = "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World;"; | ||
279 | |||
280 | SetupScene(true); | ||
281 | SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene); | ||
282 | |||
283 | m_dtm.AddDynamicTextureData( | ||
284 | m_scene.RegionInfo.RegionID, | ||
285 | so.UUID, | ||
286 | m_vrm.GetContentType(), | ||
287 | dtText, | ||
288 | "", | ||
289 | 0); | ||
290 | |||
291 | UUID firstDynamicTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID; | ||
292 | |||
293 | m_dtm.AddDynamicTextureData( | ||
294 | m_scene.RegionInfo.RegionID, | ||
295 | so.UUID, | ||
296 | m_vrm.GetContentType(), | ||
297 | dtText, | ||
298 | "alpha:250", | ||
299 | 0); | ||
300 | |||
301 | Assert.That(firstDynamicTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID)); | ||
302 | } | ||
303 | |||
304 | [Test] | ||
305 | public void TestRepeatSameDrawContainingImageReusingTexture() | ||
306 | { | ||
307 | TestHelpers.InMethod(); | ||
308 | |||
309 | string dtText | ||
310 | = "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World; Image http://localhost/shouldnotexist.png"; | ||
311 | |||
312 | SetupScene(true); | ||
313 | SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene); | ||
314 | |||
315 | m_dtm.AddDynamicTextureData( | ||
316 | m_scene.RegionInfo.RegionID, | ||
317 | so.UUID, | ||
318 | m_vrm.GetContentType(), | ||
319 | dtText, | ||
320 | "", | ||
321 | 0); | ||
322 | |||
323 | UUID firstDynamicTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID; | ||
324 | |||
325 | m_dtm.AddDynamicTextureData( | ||
326 | m_scene.RegionInfo.RegionID, | ||
327 | so.UUID, | ||
328 | m_vrm.GetContentType(), | ||
329 | dtText, | ||
330 | "", | ||
331 | 0); | ||
332 | |||
333 | Assert.That(firstDynamicTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID)); | ||
334 | } | ||
74 | } | 335 | } |
75 | } \ No newline at end of file | 336 | } \ No newline at end of file |
diff --git a/OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs b/OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs index 8b2f2f8..f395441 100644 --- a/OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs +++ b/OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs | |||
@@ -30,26 +30,35 @@ using System.Drawing; | |||
30 | using System.Drawing.Imaging; | 30 | using System.Drawing.Imaging; |
31 | using System.Globalization; | 31 | using System.Globalization; |
32 | using System.IO; | 32 | using System.IO; |
33 | using System.Linq; | ||
33 | using System.Net; | 34 | using System.Net; |
34 | using Nini.Config; | 35 | using Nini.Config; |
35 | using OpenMetaverse; | 36 | using OpenMetaverse; |
36 | using OpenMetaverse.Imaging; | 37 | using OpenMetaverse.Imaging; |
38 | using OpenSim.Region.CoreModules.Scripting.DynamicTexture; | ||
37 | using OpenSim.Region.Framework.Interfaces; | 39 | using OpenSim.Region.Framework.Interfaces; |
38 | using OpenSim.Region.Framework.Scenes; | 40 | using OpenSim.Region.Framework.Scenes; |
39 | using log4net; | 41 | using log4net; |
40 | using System.Reflection; | 42 | using System.Reflection; |
43 | using Mono.Addins; | ||
41 | 44 | ||
42 | //using Cairo; | 45 | //using Cairo; |
43 | 46 | ||
44 | namespace OpenSim.Region.CoreModules.Scripting.VectorRender | 47 | namespace OpenSim.Region.CoreModules.Scripting.VectorRender |
45 | { | 48 | { |
46 | public class VectorRenderModule : IRegionModule, IDynamicTextureRender | 49 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "VectorRenderModule")] |
50 | public class VectorRenderModule : ISharedRegionModule, IDynamicTextureRender | ||
47 | { | 51 | { |
52 | // These fields exist for testing purposes, please do not remove. | ||
53 | // private static bool s_flipper; | ||
54 | // private static byte[] s_asset1Data; | ||
55 | // private static byte[] s_asset2Data; | ||
56 | |||
48 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 57 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
49 | 58 | ||
50 | private string m_name = "VectorRenderModule"; | ||
51 | private Scene m_scene; | 59 | private Scene m_scene; |
52 | private IDynamicTextureManager m_textureManager; | 60 | private IDynamicTextureManager m_textureManager; |
61 | |||
53 | private Graphics m_graph; | 62 | private Graphics m_graph; |
54 | private string m_fontName = "Arial"; | 63 | private string m_fontName = "Arial"; |
55 | 64 | ||
@@ -61,12 +70,12 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender | |||
61 | 70 | ||
62 | public string GetContentType() | 71 | public string GetContentType() |
63 | { | 72 | { |
64 | return ("vector"); | 73 | return "vector"; |
65 | } | 74 | } |
66 | 75 | ||
67 | public string GetName() | 76 | public string GetName() |
68 | { | 77 | { |
69 | return m_name; | 78 | return Name; |
70 | } | 79 | } |
71 | 80 | ||
72 | public bool SupportsAsynchronous() | 81 | public bool SupportsAsynchronous() |
@@ -74,14 +83,20 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender | |||
74 | return true; | 83 | return true; |
75 | } | 84 | } |
76 | 85 | ||
77 | public byte[] ConvertUrl(string url, string extraParams) | 86 | // public bool AlwaysIdenticalConversion(string bodyData, string extraParams) |
87 | // { | ||
88 | // string[] lines = GetLines(bodyData); | ||
89 | // return lines.Any((str, r) => str.StartsWith("Image")); | ||
90 | // } | ||
91 | |||
92 | public IDynamicTexture ConvertUrl(string url, string extraParams) | ||
78 | { | 93 | { |
79 | return null; | 94 | return null; |
80 | } | 95 | } |
81 | 96 | ||
82 | public byte[] ConvertStream(Stream data, string extraParams) | 97 | public IDynamicTexture ConvertData(string bodyData, string extraParams) |
83 | { | 98 | { |
84 | return null; | 99 | return Draw(bodyData, extraParams); |
85 | } | 100 | } |
86 | 101 | ||
87 | public bool AsyncConvertUrl(UUID id, string url, string extraParams) | 102 | public bool AsyncConvertUrl(UUID id, string url, string extraParams) |
@@ -91,78 +106,101 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender | |||
91 | 106 | ||
92 | public bool AsyncConvertData(UUID id, string bodyData, string extraParams) | 107 | public bool AsyncConvertData(UUID id, string bodyData, string extraParams) |
93 | { | 108 | { |
94 | Draw(bodyData, id, extraParams); | 109 | if (m_textureManager == null) |
110 | { | ||
111 | m_log.Warn("[VECTORRENDERMODULE]: No texture manager. Can't function"); | ||
112 | return false; | ||
113 | } | ||
114 | // XXX: This isn't actually being done asynchronously! | ||
115 | m_textureManager.ReturnData(id, ConvertData(bodyData, extraParams)); | ||
116 | |||
95 | return true; | 117 | return true; |
96 | } | 118 | } |
97 | 119 | ||
98 | public void GetDrawStringSize(string text, string fontName, int fontSize, | 120 | public void GetDrawStringSize(string text, string fontName, int fontSize, |
99 | out double xSize, out double ySize) | 121 | out double xSize, out double ySize) |
100 | { | 122 | { |
101 | using (Font myFont = new Font(fontName, fontSize)) | 123 | lock (this) |
102 | { | 124 | { |
103 | SizeF stringSize = new SizeF(); | 125 | using (Font myFont = new Font(fontName, fontSize)) |
104 | lock (m_graph) | ||
105 | { | 126 | { |
106 | stringSize = m_graph.MeasureString(text, myFont); | 127 | SizeF stringSize = new SizeF(); |
107 | xSize = stringSize.Width; | 128 | |
108 | ySize = stringSize.Height; | 129 | // XXX: This lock may be unnecessary. |
130 | lock (m_graph) | ||
131 | { | ||
132 | stringSize = m_graph.MeasureString(text, myFont); | ||
133 | xSize = stringSize.Width; | ||
134 | ySize = stringSize.Height; | ||
135 | } | ||
109 | } | 136 | } |
110 | } | 137 | } |
111 | } | 138 | } |
112 | 139 | ||
113 | #endregion | 140 | #endregion |
114 | 141 | ||
115 | #region IRegionModule Members | 142 | #region ISharedRegionModule Members |
116 | 143 | ||
117 | public void Initialise(Scene scene, IConfigSource config) | 144 | public void Initialise(IConfigSource config) |
118 | { | 145 | { |
119 | if (m_scene == null) | ||
120 | { | ||
121 | m_scene = scene; | ||
122 | } | ||
123 | |||
124 | if (m_graph == null) | ||
125 | { | ||
126 | // We won't dispose of these explicitly since this module is only removed when the entire simulator | ||
127 | // is shut down. | ||
128 | Bitmap bitmap = new Bitmap(1024, 1024, PixelFormat.Format32bppArgb); | ||
129 | m_graph = Graphics.FromImage(bitmap); | ||
130 | } | ||
131 | |||
132 | IConfig cfg = config.Configs["VectorRender"]; | 146 | IConfig cfg = config.Configs["VectorRender"]; |
133 | if (null != cfg) | 147 | if (null != cfg) |
134 | { | 148 | { |
135 | m_fontName = cfg.GetString("font_name", m_fontName); | 149 | m_fontName = cfg.GetString("font_name", m_fontName); |
136 | } | 150 | } |
137 | m_log.DebugFormat("[VECTORRENDERMODULE]: using font \"{0}\" for text rendering.", m_fontName); | 151 | m_log.DebugFormat("[VECTORRENDERMODULE]: using font \"{0}\" for text rendering.", m_fontName); |
152 | |||
153 | // We won't dispose of these explicitly since this module is only removed when the entire simulator | ||
154 | // is shut down. | ||
155 | Bitmap bitmap = new Bitmap(1024, 1024, PixelFormat.Format32bppArgb); | ||
156 | m_graph = Graphics.FromImage(bitmap); | ||
138 | } | 157 | } |
139 | 158 | ||
140 | public void PostInitialise() | 159 | public void PostInitialise() |
141 | { | 160 | { |
142 | m_textureManager = m_scene.RequestModuleInterface<IDynamicTextureManager>(); | 161 | } |
143 | if (m_textureManager != null) | 162 | |
163 | public void AddRegion(Scene scene) | ||
164 | { | ||
165 | if (m_scene == null) | ||
144 | { | 166 | { |
145 | m_textureManager.RegisterRender(GetContentType(), this); | 167 | m_scene = scene; |
146 | } | 168 | } |
147 | } | 169 | } |
148 | 170 | ||
171 | public void RegionLoaded(Scene scene) | ||
172 | { | ||
173 | if (m_textureManager == null && m_scene == scene) | ||
174 | { | ||
175 | m_textureManager = m_scene.RequestModuleInterface<IDynamicTextureManager>(); | ||
176 | if (m_textureManager != null) | ||
177 | { | ||
178 | m_textureManager.RegisterRender(GetContentType(), this); | ||
179 | } | ||
180 | } | ||
181 | } | ||
182 | |||
183 | public void RemoveRegion(Scene scene) | ||
184 | { | ||
185 | } | ||
186 | |||
149 | public void Close() | 187 | public void Close() |
150 | { | 188 | { |
151 | } | 189 | } |
152 | 190 | ||
153 | public string Name | 191 | public string Name |
154 | { | 192 | { |
155 | get { return m_name; } | 193 | get { return "VectorRenderModule"; } |
156 | } | 194 | } |
157 | 195 | ||
158 | public bool IsSharedModule | 196 | public Type ReplaceableInterface |
159 | { | 197 | { |
160 | get { return true; } | 198 | get { return null; } |
161 | } | 199 | } |
162 | 200 | ||
163 | #endregion | 201 | #endregion |
164 | 202 | ||
165 | private void Draw(string data, UUID id, string extraParams) | 203 | private IDynamicTexture Draw(string data, string extraParams) |
166 | { | 204 | { |
167 | // We need to cater for old scripts that didnt use extraParams neatly, they use either an integer size which represents both width and height, or setalpha | 205 | // We need to cater for old scripts that didnt use extraParams neatly, they use either an integer size which represents both width and height, or setalpha |
168 | // we will now support multiple comma seperated params in the form width:256,height:512,alpha:255 | 206 | // we will now support multiple comma seperated params in the form width:256,height:512,alpha:255 |
@@ -305,40 +343,57 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender | |||
305 | 343 | ||
306 | Bitmap bitmap = null; | 344 | Bitmap bitmap = null; |
307 | Graphics graph = null; | 345 | Graphics graph = null; |
346 | bool reuseable = false; | ||
308 | 347 | ||
309 | try | 348 | try |
310 | { | 349 | { |
311 | if (alpha == 256) | 350 | // XXX: In testing, it appears that if multiple threads dispose of separate GDI+ objects simultaneously, |
312 | bitmap = new Bitmap(width, height, PixelFormat.Format32bppRgb); | 351 | // the native malloc heap can become corrupted, possibly due to a double free(). This may be due to |
313 | else | 352 | // bugs in the underlying libcairo used by mono's libgdiplus.dll on Linux/OSX. These problems were |
314 | bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb); | 353 | // seen with both libcario 1.10.2-6.1ubuntu3 and 1.8.10-2ubuntu1. They go away if disposal is perfomed |
315 | 354 | // under lock. | |
316 | graph = Graphics.FromImage(bitmap); | 355 | lock (this) |
317 | |||
318 | // this is really just to save people filling the | ||
319 | // background color in their scripts, only do when fully opaque | ||
320 | if (alpha >= 255) | ||
321 | { | 356 | { |
322 | using (SolidBrush bgFillBrush = new SolidBrush(bgColor)) | 357 | if (alpha == 256) |
358 | bitmap = new Bitmap(width, height, PixelFormat.Format32bppRgb); | ||
359 | else | ||
360 | bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb); | ||
361 | |||
362 | graph = Graphics.FromImage(bitmap); | ||
363 | |||
364 | // this is really just to save people filling the | ||
365 | // background color in their scripts, only do when fully opaque | ||
366 | if (alpha >= 255) | ||
323 | { | 367 | { |
324 | graph.FillRectangle(bgFillBrush, 0, 0, width, height); | 368 | using (SolidBrush bgFillBrush = new SolidBrush(bgColor)) |
369 | { | ||
370 | graph.FillRectangle(bgFillBrush, 0, 0, width, height); | ||
371 | } | ||
325 | } | 372 | } |
326 | } | 373 | |
327 | 374 | for (int w = 0; w < bitmap.Width; w++) | |
328 | for (int w = 0; w < bitmap.Width; w++) | ||
329 | { | ||
330 | if (alpha <= 255) | ||
331 | { | 375 | { |
332 | for (int h = 0; h < bitmap.Height; h++) | 376 | if (alpha <= 255) |
333 | { | 377 | { |
334 | bitmap.SetPixel(w, h, Color.FromArgb(alpha, bitmap.GetPixel(w, h))); | 378 | for (int h = 0; h < bitmap.Height; h++) |
379 | { | ||
380 | bitmap.SetPixel(w, h, Color.FromArgb(alpha, bitmap.GetPixel(w, h))); | ||
381 | } | ||
335 | } | 382 | } |
336 | } | 383 | } |
384 | |||
385 | GDIDraw(data, graph, altDataDelim, out reuseable); | ||
337 | } | 386 | } |
338 | 387 | ||
339 | GDIDraw(data, graph, altDataDelim); | ||
340 | |||
341 | byte[] imageJ2000 = new byte[0]; | 388 | byte[] imageJ2000 = new byte[0]; |
389 | |||
390 | // This code exists for testing purposes, please do not remove. | ||
391 | // if (s_flipper) | ||
392 | // imageJ2000 = s_asset1Data; | ||
393 | // else | ||
394 | // imageJ2000 = s_asset2Data; | ||
395 | // | ||
396 | // s_flipper = !s_flipper; | ||
342 | 397 | ||
343 | try | 398 | try |
344 | { | 399 | { |
@@ -351,15 +406,24 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender | |||
351 | e.Message, e.StackTrace); | 406 | e.Message, e.StackTrace); |
352 | } | 407 | } |
353 | 408 | ||
354 | m_textureManager.ReturnData(id, imageJ2000); | 409 | return new OpenSim.Region.CoreModules.Scripting.DynamicTexture.DynamicTexture( |
410 | data, extraParams, imageJ2000, new Size(width, height), reuseable); | ||
355 | } | 411 | } |
356 | finally | 412 | finally |
357 | { | 413 | { |
358 | if (graph != null) | 414 | // XXX: In testing, it appears that if multiple threads dispose of separate GDI+ objects simultaneously, |
359 | graph.Dispose(); | 415 | // the native malloc heap can become corrupted, possibly due to a double free(). This may be due to |
360 | 416 | // bugs in the underlying libcairo used by mono's libgdiplus.dll on Linux/OSX. These problems were | |
361 | if (bitmap != null) | 417 | // seen with both libcario 1.10.2-6.1ubuntu3 and 1.8.10-2ubuntu1. They go away if disposal is perfomed |
362 | bitmap.Dispose(); | 418 | // under lock. |
419 | lock (this) | ||
420 | { | ||
421 | if (graph != null) | ||
422 | graph.Dispose(); | ||
423 | |||
424 | if (bitmap != null) | ||
425 | bitmap.Dispose(); | ||
426 | } | ||
363 | } | 427 | } |
364 | } | 428 | } |
365 | 429 | ||
@@ -418,8 +482,21 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender | |||
418 | } | 482 | } |
419 | */ | 483 | */ |
420 | 484 | ||
421 | private void GDIDraw(string data, Graphics graph, char dataDelim) | 485 | /// <summary> |
486 | /// Split input data into discrete command lines. | ||
487 | /// </summary> | ||
488 | /// <returns></returns> | ||
489 | /// <param name='data'></param> | ||
490 | /// <param name='dataDelim'></param> | ||
491 | private string[] GetLines(string data, char dataDelim) | ||
492 | { | ||
493 | char[] lineDelimiter = { dataDelim }; | ||
494 | return data.Split(lineDelimiter); | ||
495 | } | ||
496 | |||
497 | private void GDIDraw(string data, Graphics graph, char dataDelim, out bool reuseable) | ||
422 | { | 498 | { |
499 | reuseable = true; | ||
423 | Point startPoint = new Point(0, 0); | 500 | Point startPoint = new Point(0, 0); |
424 | Point endPoint = new Point(0, 0); | 501 | Point endPoint = new Point(0, 0); |
425 | Pen drawPen = null; | 502 | Pen drawPen = null; |
@@ -434,11 +511,9 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender | |||
434 | myFont = new Font(fontName, fontSize); | 511 | myFont = new Font(fontName, fontSize); |
435 | myBrush = new SolidBrush(Color.Black); | 512 | myBrush = new SolidBrush(Color.Black); |
436 | 513 | ||
437 | char[] lineDelimiter = {dataDelim}; | ||
438 | char[] partsDelimiter = {','}; | 514 | char[] partsDelimiter = {','}; |
439 | string[] lines = data.Split(lineDelimiter); | ||
440 | 515 | ||
441 | foreach (string line in lines) | 516 | foreach (string line in GetLines(data, dataDelim)) |
442 | { | 517 | { |
443 | string nextLine = line.Trim(); | 518 | string nextLine = line.Trim(); |
444 | //replace with switch, or even better, do some proper parsing | 519 | //replace with switch, or even better, do some proper parsing |
@@ -469,6 +544,10 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender | |||
469 | } | 544 | } |
470 | else if (nextLine.StartsWith("Image")) | 545 | else if (nextLine.StartsWith("Image")) |
471 | { | 546 | { |
547 | // We cannot reuse any generated texture involving fetching an image via HTTP since that image | ||
548 | // can change. | ||
549 | reuseable = false; | ||
550 | |||
472 | float x = 0; | 551 | float x = 0; |
473 | float y = 0; | 552 | float y = 0; |
474 | GetParams(partsDelimiter, ref nextLine, 5, ref x, ref y); | 553 | GetParams(partsDelimiter, ref nextLine, 5, ref x, ref y); |
diff --git a/OpenSim/Region/CoreModules/Scripting/WorldComm/WorldCommModule.cs b/OpenSim/Region/CoreModules/Scripting/WorldComm/WorldCommModule.cs index 07bb291..87a0537 100644 --- a/OpenSim/Region/CoreModules/Scripting/WorldComm/WorldCommModule.cs +++ b/OpenSim/Region/CoreModules/Scripting/WorldComm/WorldCommModule.cs | |||
@@ -28,8 +28,13 @@ | |||
28 | using System; | 28 | using System; |
29 | using System.Collections; | 29 | using System.Collections; |
30 | using System.Collections.Generic; | 30 | using System.Collections.Generic; |
31 | using System.Text.RegularExpressions; | ||
32 | |||
31 | using Nini.Config; | 33 | using Nini.Config; |
34 | using Mono.Addins; | ||
35 | |||
32 | using OpenMetaverse; | 36 | using OpenMetaverse; |
37 | |||
33 | using OpenSim.Framework; | 38 | using OpenSim.Framework; |
34 | using OpenSim.Region.Framework.Interfaces; | 39 | using OpenSim.Region.Framework.Interfaces; |
35 | using OpenSim.Region.Framework.Scenes; | 40 | using OpenSim.Region.Framework.Scenes; |
@@ -85,7 +90,8 @@ using OpenSim.Region.Framework.Scenes; | |||
85 | 90 | ||
86 | namespace OpenSim.Region.CoreModules.Scripting.WorldComm | 91 | namespace OpenSim.Region.CoreModules.Scripting.WorldComm |
87 | { | 92 | { |
88 | public class WorldCommModule : IRegionModule, IWorldComm | 93 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "WorldCommModule")] |
94 | public class WorldCommModule : IWorldComm, INonSharedRegionModule | ||
89 | { | 95 | { |
90 | // private static readonly ILog m_log = | 96 | // private static readonly ILog m_log = |
91 | // LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 97 | // LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
@@ -100,9 +106,9 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm | |||
100 | private int m_saydistance = 20; | 106 | private int m_saydistance = 20; |
101 | private int m_shoutdistance = 100; | 107 | private int m_shoutdistance = 100; |
102 | 108 | ||
103 | #region IRegionModule Members | 109 | #region INonSharedRegionModule Members |
104 | 110 | ||
105 | public void Initialise(Scene scene, IConfigSource config) | 111 | public void Initialise(IConfigSource config) |
106 | { | 112 | { |
107 | // wrap this in a try block so that defaults will work if | 113 | // wrap this in a try block so that defaults will work if |
108 | // the config file doesn't specify otherwise. | 114 | // the config file doesn't specify otherwise. |
@@ -110,29 +116,49 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm | |||
110 | int maxhandles = 64; | 116 | int maxhandles = 64; |
111 | try | 117 | try |
112 | { | 118 | { |
113 | m_whisperdistance = config.Configs["Chat"].GetInt("whisper_distance", m_whisperdistance); | 119 | m_whisperdistance = config.Configs["Chat"].GetInt( |
114 | m_saydistance = config.Configs["Chat"].GetInt("say_distance", m_saydistance); | 120 | "whisper_distance", m_whisperdistance); |
115 | m_shoutdistance = config.Configs["Chat"].GetInt("shout_distance", m_shoutdistance); | 121 | m_saydistance = config.Configs["Chat"].GetInt( |
116 | maxlisteners = config.Configs["LL-Functions"].GetInt("max_listens_per_region", maxlisteners); | 122 | "say_distance", m_saydistance); |
117 | maxhandles = config.Configs["LL-Functions"].GetInt("max_listens_per_script", maxhandles); | 123 | m_shoutdistance = config.Configs["Chat"].GetInt( |
124 | "shout_distance", m_shoutdistance); | ||
125 | maxlisteners = config.Configs["LL-Functions"].GetInt( | ||
126 | "max_listens_per_region", maxlisteners); | ||
127 | maxhandles = config.Configs["LL-Functions"].GetInt( | ||
128 | "max_listens_per_script", maxhandles); | ||
118 | } | 129 | } |
119 | catch (Exception) | 130 | catch (Exception) |
120 | { | 131 | { |
121 | } | 132 | } |
122 | if (maxlisteners < 1) maxlisteners = int.MaxValue; | 133 | if (maxlisteners < 1) maxlisteners = int.MaxValue; |
123 | if (maxhandles < 1) maxhandles = int.MaxValue; | 134 | if (maxhandles < 1) maxhandles = int.MaxValue; |
135 | m_listenerManager = new ListenerManager(maxlisteners, maxhandles); | ||
136 | m_pendingQ = new Queue(); | ||
137 | m_pending = Queue.Synchronized(m_pendingQ); | ||
138 | } | ||
124 | 139 | ||
140 | public void PostInitialise() | ||
141 | { | ||
142 | } | ||
143 | |||
144 | public void AddRegion(Scene scene) | ||
145 | { | ||
125 | m_scene = scene; | 146 | m_scene = scene; |
126 | m_scene.RegisterModuleInterface<IWorldComm>(this); | 147 | m_scene.RegisterModuleInterface<IWorldComm>(this); |
127 | m_listenerManager = new ListenerManager(maxlisteners, maxhandles); | ||
128 | m_scene.EventManager.OnChatFromClient += DeliverClientMessage; | 148 | m_scene.EventManager.OnChatFromClient += DeliverClientMessage; |
129 | m_scene.EventManager.OnChatBroadcast += DeliverClientMessage; | 149 | m_scene.EventManager.OnChatBroadcast += DeliverClientMessage; |
130 | m_pendingQ = new Queue(); | ||
131 | m_pending = Queue.Synchronized(m_pendingQ); | ||
132 | } | 150 | } |
133 | 151 | ||
134 | public void PostInitialise() | 152 | public void RegionLoaded(Scene scene) { } |
153 | |||
154 | public void RemoveRegion(Scene scene) | ||
135 | { | 155 | { |
156 | if (scene != m_scene) | ||
157 | return; | ||
158 | |||
159 | m_scene.UnregisterModuleInterface<IWorldComm>(this); | ||
160 | m_scene.EventManager.OnChatBroadcast -= DeliverClientMessage; | ||
161 | m_scene.EventManager.OnChatBroadcast -= DeliverClientMessage; | ||
136 | } | 162 | } |
137 | 163 | ||
138 | public void Close() | 164 | public void Close() |
@@ -144,10 +170,7 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm | |||
144 | get { return "WorldCommModule"; } | 170 | get { return "WorldCommModule"; } |
145 | } | 171 | } |
146 | 172 | ||
147 | public bool IsSharedModule | 173 | public Type ReplaceableInterface { get { return null; } } |
148 | { | ||
149 | get { return false; } | ||
150 | } | ||
151 | 174 | ||
152 | #endregion | 175 | #endregion |
153 | 176 | ||
@@ -172,12 +195,42 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm | |||
172 | /// <param name="hostID">UUID of the SceneObjectPart</param> | 195 | /// <param name="hostID">UUID of the SceneObjectPart</param> |
173 | /// <param name="channel">channel to listen on</param> | 196 | /// <param name="channel">channel to listen on</param> |
174 | /// <param name="name">name to filter on</param> | 197 | /// <param name="name">name to filter on</param> |
175 | /// <param name="id">key to filter on (user given, could be totally faked)</param> | 198 | /// <param name="id"> |
199 | /// key to filter on (user given, could be totally faked) | ||
200 | /// </param> | ||
201 | /// <param name="msg">msg to filter on</param> | ||
202 | /// <returns>number of the scripts handle</returns> | ||
203 | public int Listen(uint localID, UUID itemID, UUID hostID, int channel, | ||
204 | string name, UUID id, string msg) | ||
205 | { | ||
206 | return m_listenerManager.AddListener(localID, itemID, hostID, | ||
207 | channel, name, id, msg); | ||
208 | } | ||
209 | |||
210 | /// <summary> | ||
211 | /// Create a listen event callback with the specified filters. | ||
212 | /// The parameters localID,itemID are needed to uniquely identify | ||
213 | /// the script during 'peek' time. Parameter hostID is needed to | ||
214 | /// determine the position of the script. | ||
215 | /// </summary> | ||
216 | /// <param name="localID">localID of the script engine</param> | ||
217 | /// <param name="itemID">UUID of the script engine</param> | ||
218 | /// <param name="hostID">UUID of the SceneObjectPart</param> | ||
219 | /// <param name="channel">channel to listen on</param> | ||
220 | /// <param name="name">name to filter on</param> | ||
221 | /// <param name="id"> | ||
222 | /// key to filter on (user given, could be totally faked) | ||
223 | /// </param> | ||
176 | /// <param name="msg">msg to filter on</param> | 224 | /// <param name="msg">msg to filter on</param> |
225 | /// <param name="regexBitfield"> | ||
226 | /// Bitfield indicating which strings should be processed as regex. | ||
227 | /// </param> | ||
177 | /// <returns>number of the scripts handle</returns> | 228 | /// <returns>number of the scripts handle</returns> |
178 | public int Listen(uint localID, UUID itemID, UUID hostID, int channel, string name, UUID id, string msg) | 229 | public int Listen(uint localID, UUID itemID, UUID hostID, int channel, |
230 | string name, UUID id, string msg, int regexBitfield) | ||
179 | { | 231 | { |
180 | return m_listenerManager.AddListener(localID, itemID, hostID, channel, name, id, msg); | 232 | return m_listenerManager.AddListener(localID, itemID, hostID, |
233 | channel, name, id, msg, regexBitfield); | ||
181 | } | 234 | } |
182 | 235 | ||
183 | /// <summary> | 236 | /// <summary> |
@@ -226,7 +279,7 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm | |||
226 | 279 | ||
227 | if ((source = m_scene.GetSceneObjectPart(id)) != null) | 280 | if ((source = m_scene.GetSceneObjectPart(id)) != null) |
228 | position = source.AbsolutePosition; | 281 | position = source.AbsolutePosition; |
229 | else if ((avatar = m_scene.GetScenePresence(id)) != null) | 282 | else if ((avatar = m_scene.GetScenePresence(id)) != null) |
230 | position = avatar.AbsolutePosition; | 283 | position = avatar.AbsolutePosition; |
231 | else if (ChatTypeEnum.Region == type) | 284 | else if (ChatTypeEnum.Region == type) |
232 | position = CenterOfRegion; | 285 | position = CenterOfRegion; |
@@ -249,7 +302,8 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm | |||
249 | /// <param name="name">name of sender (object or avatar)</param> | 302 | /// <param name="name">name of sender (object or avatar)</param> |
250 | /// <param name="id">key of sender (object or avatar)</param> | 303 | /// <param name="id">key of sender (object or avatar)</param> |
251 | /// <param name="msg">msg to sent</param> | 304 | /// <param name="msg">msg to sent</param> |
252 | public void DeliverMessage(ChatTypeEnum type, int channel, string name, UUID id, string msg, Vector3 position) | 305 | public void DeliverMessage(ChatTypeEnum type, int channel, |
306 | string name, UUID id, string msg, Vector3 position) | ||
253 | { | 307 | { |
254 | // m_log.DebugFormat("[WorldComm] got[2] type {0}, channel {1}, name {2}, id {3}, msg {4}", | 308 | // m_log.DebugFormat("[WorldComm] got[2] type {0}, channel {1}, name {2}, id {3}, msg {4}", |
255 | // type, channel, name, id, msg); | 309 | // type, channel, name, id, msg); |
@@ -257,17 +311,21 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm | |||
257 | // Determine which listen event filters match the given set of arguments, this results | 311 | // Determine which listen event filters match the given set of arguments, this results |
258 | // in a limited set of listeners, each belonging a host. If the host is in range, add them | 312 | // in a limited set of listeners, each belonging a host. If the host is in range, add them |
259 | // to the pending queue. | 313 | // to the pending queue. |
260 | foreach (ListenerInfo li in m_listenerManager.GetListeners(UUID.Zero, channel, name, id, msg)) | 314 | foreach (ListenerInfo li |
315 | in m_listenerManager.GetListeners(UUID.Zero, channel, | ||
316 | name, id, msg)) | ||
261 | { | 317 | { |
262 | // Dont process if this message is from yourself! | 318 | // Dont process if this message is from yourself! |
263 | if (li.GetHostID().Equals(id)) | 319 | if (li.GetHostID().Equals(id)) |
264 | continue; | 320 | continue; |
265 | 321 | ||
266 | SceneObjectPart sPart = m_scene.GetSceneObjectPart(li.GetHostID()); | 322 | SceneObjectPart sPart = m_scene.GetSceneObjectPart( |
323 | li.GetHostID()); | ||
267 | if (sPart == null) | 324 | if (sPart == null) |
268 | continue; | 325 | continue; |
269 | 326 | ||
270 | double dis = Util.GetDistanceTo(sPart.AbsolutePosition, position); | 327 | double dis = Util.GetDistanceTo(sPart.AbsolutePosition, |
328 | position); | ||
271 | switch (type) | 329 | switch (type) |
272 | { | 330 | { |
273 | case ChatTypeEnum.Whisper: | 331 | case ChatTypeEnum.Whisper: |
@@ -326,7 +384,7 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm | |||
326 | if (channel == 0) | 384 | if (channel == 0) |
327 | { | 385 | { |
328 | // Channel 0 goes to viewer ONLY | 386 | // Channel 0 goes to viewer ONLY |
329 | m_scene.SimChat(Utils.StringToBytes(msg), ChatTypeEnum.Broadcast, 0, pos, name, id, false, false, target); | 387 | m_scene.SimChat(Utils.StringToBytes(msg), ChatTypeEnum.Broadcast, 0, pos, name, id, target, false, false); |
330 | return true; | 388 | return true; |
331 | } | 389 | } |
332 | 390 | ||
@@ -369,11 +427,12 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm | |||
369 | if (li.GetHostID().Equals(id)) | 427 | if (li.GetHostID().Equals(id)) |
370 | continue; | 428 | continue; |
371 | 429 | ||
372 | SceneObjectPart sPart = m_scene.GetSceneObjectPart(li.GetHostID()); | 430 | SceneObjectPart sPart = m_scene.GetSceneObjectPart( |
431 | li.GetHostID()); | ||
373 | if (sPart == null) | 432 | if (sPart == null) |
374 | continue; | 433 | continue; |
375 | 434 | ||
376 | if ( li.GetHostID().Equals(target)) | 435 | if (li.GetHostID().Equals(target)) |
377 | { | 436 | { |
378 | QueueMessage(new ListenerInfo(li, name, id, msg)); | 437 | QueueMessage(new ListenerInfo(li, name, id, msg)); |
379 | break; | 438 | break; |
@@ -427,9 +486,15 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm | |||
427 | private void DeliverClientMessage(Object sender, OSChatMessage e) | 486 | private void DeliverClientMessage(Object sender, OSChatMessage e) |
428 | { | 487 | { |
429 | if (null != e.Sender) | 488 | if (null != e.Sender) |
430 | DeliverMessage(e.Type, e.Channel, e.Sender.Name, e.Sender.AgentId, e.Message, e.Position); | 489 | { |
490 | DeliverMessage(e.Type, e.Channel, e.Sender.Name, | ||
491 | e.Sender.AgentId, e.Message, e.Position); | ||
492 | } | ||
431 | else | 493 | else |
432 | DeliverMessage(e.Type, e.Channel, e.From, UUID.Zero, e.Message, e.Position); | 494 | { |
495 | DeliverMessage(e.Type, e.Channel, e.From, UUID.Zero, | ||
496 | e.Message, e.Position); | ||
497 | } | ||
433 | } | 498 | } |
434 | 499 | ||
435 | public Object[] GetSerializationData(UUID itemID) | 500 | public Object[] GetSerializationData(UUID itemID) |
@@ -446,7 +511,8 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm | |||
446 | 511 | ||
447 | public class ListenerManager | 512 | public class ListenerManager |
448 | { | 513 | { |
449 | private Dictionary<int, List<ListenerInfo>> m_listeners = new Dictionary<int, List<ListenerInfo>>(); | 514 | private Dictionary<int, List<ListenerInfo>> m_listeners = |
515 | new Dictionary<int, List<ListenerInfo>>(); | ||
450 | private int m_maxlisteners; | 516 | private int m_maxlisteners; |
451 | private int m_maxhandles; | 517 | private int m_maxhandles; |
452 | private int m_curlisteners; | 518 | private int m_curlisteners; |
@@ -470,15 +536,25 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm | |||
470 | m_curlisteners = 0; | 536 | m_curlisteners = 0; |
471 | } | 537 | } |
472 | 538 | ||
473 | public int AddListener(uint localID, UUID itemID, UUID hostID, int channel, string name, UUID id, string msg) | 539 | public int AddListener(uint localID, UUID itemID, UUID hostID, |
540 | int channel, string name, UUID id, string msg) | ||
541 | { | ||
542 | return AddListener(localID, itemID, hostID, channel, name, id, | ||
543 | msg, 0); | ||
544 | } | ||
545 | |||
546 | public int AddListener(uint localID, UUID itemID, UUID hostID, | ||
547 | int channel, string name, UUID id, string msg, | ||
548 | int regexBitfield) | ||
474 | { | 549 | { |
475 | // do we already have a match on this particular filter event? | 550 | // do we already have a match on this particular filter event? |
476 | List<ListenerInfo> coll = GetListeners(itemID, channel, name, id, msg); | 551 | List<ListenerInfo> coll = GetListeners(itemID, channel, name, id, |
552 | msg); | ||
477 | 553 | ||
478 | if (coll.Count > 0) | 554 | if (coll.Count > 0) |
479 | { | 555 | { |
480 | // special case, called with same filter settings, return same handle | 556 | // special case, called with same filter settings, return same |
481 | // (2008-05-02, tested on 1.21.1 server, still holds) | 557 | // handle (2008-05-02, tested on 1.21.1 server, still holds) |
482 | return coll[0].GetHandle(); | 558 | return coll[0].GetHandle(); |
483 | } | 559 | } |
484 | 560 | ||
@@ -490,16 +566,19 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm | |||
490 | 566 | ||
491 | if (newHandle > 0) | 567 | if (newHandle > 0) |
492 | { | 568 | { |
493 | ListenerInfo li = new ListenerInfo(newHandle, localID, itemID, hostID, channel, name, id, msg); | 569 | ListenerInfo li = new ListenerInfo(newHandle, localID, |
570 | itemID, hostID, channel, name, id, msg, | ||
571 | regexBitfield); | ||
494 | 572 | ||
495 | List<ListenerInfo> listeners; | 573 | List<ListenerInfo> listeners; |
496 | if (!m_listeners.TryGetValue(channel,out listeners)) | 574 | if (!m_listeners.TryGetValue( |
497 | { | 575 | channel, out listeners)) |
498 | listeners = new List<ListenerInfo>(); | 576 | { |
499 | m_listeners.Add(channel, listeners); | 577 | listeners = new List<ListenerInfo>(); |
500 | } | 578 | m_listeners.Add(channel, listeners); |
501 | listeners.Add(li); | 579 | } |
502 | m_curlisteners++; | 580 | listeners.Add(li); |
581 | m_curlisteners++; | ||
503 | 582 | ||
504 | return newHandle; | 583 | return newHandle; |
505 | } | 584 | } |
@@ -512,11 +591,13 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm | |||
512 | { | 591 | { |
513 | lock (m_listeners) | 592 | lock (m_listeners) |
514 | { | 593 | { |
515 | foreach (KeyValuePair<int,List<ListenerInfo>> lis in m_listeners) | 594 | foreach (KeyValuePair<int, List<ListenerInfo>> lis |
595 | in m_listeners) | ||
516 | { | 596 | { |
517 | foreach (ListenerInfo li in lis.Value) | 597 | foreach (ListenerInfo li in lis.Value) |
518 | { | 598 | { |
519 | if (li.GetItemID().Equals(itemID) && li.GetHandle().Equals(handle)) | 599 | if (li.GetItemID().Equals(itemID) && |
600 | li.GetHandle().Equals(handle)) | ||
520 | { | 601 | { |
521 | lis.Value.Remove(li); | 602 | lis.Value.Remove(li); |
522 | if (lis.Value.Count == 0) | 603 | if (lis.Value.Count == 0) |
@@ -539,13 +620,15 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm | |||
539 | 620 | ||
540 | lock (m_listeners) | 621 | lock (m_listeners) |
541 | { | 622 | { |
542 | foreach (KeyValuePair<int,List<ListenerInfo>> lis in m_listeners) | 623 | foreach (KeyValuePair<int, List<ListenerInfo>> lis |
624 | in m_listeners) | ||
543 | { | 625 | { |
544 | foreach (ListenerInfo li in lis.Value) | 626 | foreach (ListenerInfo li in lis.Value) |
545 | { | 627 | { |
546 | if (li.GetItemID().Equals(itemID)) | 628 | if (li.GetItemID().Equals(itemID)) |
547 | { | 629 | { |
548 | // store them first, else the enumerated bails on us | 630 | // store them first, else the enumerated bails on |
631 | // us | ||
549 | removedListeners.Add(li); | 632 | removedListeners.Add(li); |
550 | } | 633 | } |
551 | } | 634 | } |
@@ -572,11 +655,13 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm | |||
572 | { | 655 | { |
573 | lock (m_listeners) | 656 | lock (m_listeners) |
574 | { | 657 | { |
575 | foreach (KeyValuePair<int,List<ListenerInfo>> lis in m_listeners) | 658 | foreach (KeyValuePair<int, List<ListenerInfo>> lis |
659 | in m_listeners) | ||
576 | { | 660 | { |
577 | foreach (ListenerInfo li in lis.Value) | 661 | foreach (ListenerInfo li in lis.Value) |
578 | { | 662 | { |
579 | if (li.GetItemID().Equals(itemID) && li.GetHandle() == handle) | 663 | if (li.GetItemID().Equals(itemID) && |
664 | li.GetHandle() == handle) | ||
580 | { | 665 | { |
581 | li.Activate(); | 666 | li.Activate(); |
582 | // only one, bail out | 667 | // only one, bail out |
@@ -591,11 +676,13 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm | |||
591 | { | 676 | { |
592 | lock (m_listeners) | 677 | lock (m_listeners) |
593 | { | 678 | { |
594 | foreach (KeyValuePair<int,List<ListenerInfo>> lis in m_listeners) | 679 | foreach (KeyValuePair<int, List<ListenerInfo>> lis |
680 | in m_listeners) | ||
595 | { | 681 | { |
596 | foreach (ListenerInfo li in lis.Value) | 682 | foreach (ListenerInfo li in lis.Value) |
597 | { | 683 | { |
598 | if (li.GetItemID().Equals(itemID) && li.GetHandle() == handle) | 684 | if (li.GetItemID().Equals(itemID) && |
685 | li.GetHandle() == handle) | ||
599 | { | 686 | { |
600 | li.Deactivate(); | 687 | li.Deactivate(); |
601 | // only one, bail out | 688 | // only one, bail out |
@@ -606,19 +693,24 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm | |||
606 | } | 693 | } |
607 | } | 694 | } |
608 | 695 | ||
609 | // non-locked access, since its always called in the context of the lock | 696 | /// <summary> |
697 | /// non-locked access, since its always called in the context of the | ||
698 | /// lock | ||
699 | /// </summary> | ||
700 | /// <param name="itemID"></param> | ||
701 | /// <returns></returns> | ||
610 | private int GetNewHandle(UUID itemID) | 702 | private int GetNewHandle(UUID itemID) |
611 | { | 703 | { |
612 | List<int> handles = new List<int>(); | 704 | List<int> handles = new List<int>(); |
613 | 705 | ||
614 | // build a list of used keys for this specific itemID... | 706 | // build a list of used keys for this specific itemID... |
615 | foreach (KeyValuePair<int,List<ListenerInfo>> lis in m_listeners) | 707 | foreach (KeyValuePair<int, List<ListenerInfo>> lis in m_listeners) |
616 | { | 708 | { |
617 | foreach (ListenerInfo li in lis.Value) | 709 | foreach (ListenerInfo li in lis.Value) |
618 | { | 710 | { |
619 | if (li.GetItemID().Equals(itemID)) | 711 | if (li.GetItemID().Equals(itemID)) |
620 | handles.Add(li.GetHandle()); | 712 | handles.Add(li.GetHandle()); |
621 | } | 713 | } |
622 | } | 714 | } |
623 | 715 | ||
624 | // Note: 0 is NOT a valid handle for llListen() to return | 716 | // Note: 0 is NOT a valid handle for llListen() to return |
@@ -631,17 +723,46 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm | |||
631 | return -1; | 723 | return -1; |
632 | } | 724 | } |
633 | 725 | ||
634 | // Theres probably a more clever and efficient way to | 726 | /// These are duplicated from ScriptBaseClass |
635 | // do this, maybe with regex. | 727 | /// http://opensimulator.org/mantis/view.php?id=6106#c21945 |
636 | // PM2008: Ha, one could even be smart and define a specialized Enumerator. | 728 | #region Constants for the bitfield parameter of osListenRegex |
637 | public List<ListenerInfo> GetListeners(UUID itemID, int channel, string name, UUID id, string msg) | 729 | |
730 | /// <summary> | ||
731 | /// process name parameter as regex | ||
732 | /// </summary> | ||
733 | public const int OS_LISTEN_REGEX_NAME = 0x1; | ||
734 | |||
735 | /// <summary> | ||
736 | /// process message parameter as regex | ||
737 | /// </summary> | ||
738 | public const int OS_LISTEN_REGEX_MESSAGE = 0x2; | ||
739 | |||
740 | #endregion | ||
741 | |||
742 | /// <summary> | ||
743 | /// Get listeners matching the input parameters. | ||
744 | /// </summary> | ||
745 | /// <remarks> | ||
746 | /// Theres probably a more clever and efficient way to do this, maybe | ||
747 | /// with regex. | ||
748 | /// PM2008: Ha, one could even be smart and define a specialized | ||
749 | /// Enumerator. | ||
750 | /// </remarks> | ||
751 | /// <param name="itemID"></param> | ||
752 | /// <param name="channel"></param> | ||
753 | /// <param name="name"></param> | ||
754 | /// <param name="id"></param> | ||
755 | /// <param name="msg"></param> | ||
756 | /// <returns></returns> | ||
757 | public List<ListenerInfo> GetListeners(UUID itemID, int channel, | ||
758 | string name, UUID id, string msg) | ||
638 | { | 759 | { |
639 | List<ListenerInfo> collection = new List<ListenerInfo>(); | 760 | List<ListenerInfo> collection = new List<ListenerInfo>(); |
640 | 761 | ||
641 | lock (m_listeners) | 762 | lock (m_listeners) |
642 | { | 763 | { |
643 | List<ListenerInfo> listeners; | 764 | List<ListenerInfo> listeners; |
644 | if (!m_listeners.TryGetValue(channel,out listeners)) | 765 | if (!m_listeners.TryGetValue(channel, out listeners)) |
645 | { | 766 | { |
646 | return collection; | 767 | return collection; |
647 | } | 768 | } |
@@ -652,11 +773,15 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm | |||
652 | { | 773 | { |
653 | continue; | 774 | continue; |
654 | } | 775 | } |
655 | if (!itemID.Equals(UUID.Zero) && !li.GetItemID().Equals(itemID)) | 776 | if (!itemID.Equals(UUID.Zero) && |
777 | !li.GetItemID().Equals(itemID)) | ||
656 | { | 778 | { |
657 | continue; | 779 | continue; |
658 | } | 780 | } |
659 | if (li.GetName().Length > 0 && !li.GetName().Equals(name)) | 781 | if (li.GetName().Length > 0 && ( |
782 | ((li.RegexBitfield & OS_LISTEN_REGEX_NAME) != OS_LISTEN_REGEX_NAME && !li.GetName().Equals(name)) || | ||
783 | ((li.RegexBitfield & OS_LISTEN_REGEX_NAME) == OS_LISTEN_REGEX_NAME && !Regex.IsMatch(name, li.GetName())) | ||
784 | )) | ||
660 | { | 785 | { |
661 | continue; | 786 | continue; |
662 | } | 787 | } |
@@ -664,7 +789,10 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm | |||
664 | { | 789 | { |
665 | continue; | 790 | continue; |
666 | } | 791 | } |
667 | if (li.GetMessage().Length > 0 && !li.GetMessage().Equals(msg)) | 792 | if (li.GetMessage().Length > 0 && ( |
793 | ((li.RegexBitfield & OS_LISTEN_REGEX_MESSAGE) != OS_LISTEN_REGEX_MESSAGE && !li.GetMessage().Equals(msg)) || | ||
794 | ((li.RegexBitfield & OS_LISTEN_REGEX_MESSAGE) == OS_LISTEN_REGEX_MESSAGE && !Regex.IsMatch(msg, li.GetMessage())) | ||
795 | )) | ||
668 | { | 796 | { |
669 | continue; | 797 | continue; |
670 | } | 798 | } |
@@ -697,10 +825,13 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm | |||
697 | { | 825 | { |
698 | int idx = 0; | 826 | int idx = 0; |
699 | Object[] item = new Object[6]; | 827 | Object[] item = new Object[6]; |
828 | int dataItemLength = 6; | ||
700 | 829 | ||
701 | while (idx < data.Length) | 830 | while (idx < data.Length) |
702 | { | 831 | { |
703 | Array.Copy(data, idx, item, 0, 6); | 832 | dataItemLength = (idx + 7 == data.Length || (idx + 7 < data.Length && data[idx + 7] is bool)) ? 7 : 6; |
833 | item = new Object[dataItemLength]; | ||
834 | Array.Copy(data, idx, item, 0, dataItemLength); | ||
704 | 835 | ||
705 | ListenerInfo info = | 836 | ListenerInfo info = |
706 | ListenerInfo.FromData(localID, itemID, hostID, item); | 837 | ListenerInfo.FromData(localID, itemID, hostID, item); |
@@ -708,39 +839,98 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm | |||
708 | lock (m_listeners) | 839 | lock (m_listeners) |
709 | { | 840 | { |
710 | if (!m_listeners.ContainsKey((int)item[2])) | 841 | if (!m_listeners.ContainsKey((int)item[2])) |
711 | m_listeners.Add((int)item[2], new List<ListenerInfo>()); | 842 | { |
843 | m_listeners.Add((int)item[2], | ||
844 | new List<ListenerInfo>()); | ||
845 | } | ||
712 | m_listeners[(int)item[2]].Add(info); | 846 | m_listeners[(int)item[2]].Add(info); |
713 | } | 847 | } |
714 | 848 | ||
715 | idx+=6; | 849 | idx += dataItemLength; |
716 | } | 850 | } |
717 | } | 851 | } |
718 | } | 852 | } |
719 | 853 | ||
720 | public class ListenerInfo: IWorldCommListenerInfo | 854 | public class ListenerInfo : IWorldCommListenerInfo |
721 | { | 855 | { |
722 | private bool m_active; // Listener is active or not | 856 | /// <summary> |
723 | private int m_handle; // Assigned handle of this listener | 857 | /// Listener is active or not |
724 | private uint m_localID; // Local ID from script engine | 858 | /// </summary> |
725 | private UUID m_itemID; // ID of the host script engine | 859 | private bool m_active; |
726 | private UUID m_hostID; // ID of the host/scene part | 860 | |
727 | private int m_channel; // Channel | 861 | /// <summary> |
728 | private UUID m_id; // ID to filter messages from | 862 | /// Assigned handle of this listener |
729 | private string m_name; // Object name to filter messages from | 863 | /// </summary> |
730 | private string m_message; // The message | 864 | private int m_handle; |
865 | |||
866 | /// <summary> | ||
867 | /// Local ID from script engine | ||
868 | /// </summary> | ||
869 | private uint m_localID; | ||
870 | |||
871 | /// <summary> | ||
872 | /// ID of the host script engine | ||
873 | /// </summary> | ||
874 | private UUID m_itemID; | ||
875 | |||
876 | /// <summary> | ||
877 | /// ID of the host/scene part | ||
878 | /// </summary> | ||
879 | private UUID m_hostID; | ||
880 | |||
881 | /// <summary> | ||
882 | /// Channel | ||
883 | /// </summary> | ||
884 | private int m_channel; | ||
885 | |||
886 | /// <summary> | ||
887 | /// ID to filter messages from | ||
888 | /// </summary> | ||
889 | private UUID m_id; | ||
890 | |||
891 | /// <summary> | ||
892 | /// Object name to filter messages from | ||
893 | /// </summary> | ||
894 | private string m_name; | ||
895 | |||
896 | /// <summary> | ||
897 | /// The message | ||
898 | /// </summary> | ||
899 | private string m_message; | ||
900 | |||
901 | public ListenerInfo(int handle, uint localID, UUID ItemID, | ||
902 | UUID hostID, int channel, string name, UUID id, | ||
903 | string message) | ||
904 | { | ||
905 | Initialise(handle, localID, ItemID, hostID, channel, name, id, | ||
906 | message, 0); | ||
907 | } | ||
731 | 908 | ||
732 | public ListenerInfo(int handle, uint localID, UUID ItemID, UUID hostID, int channel, string name, UUID id, string message) | 909 | public ListenerInfo(int handle, uint localID, UUID ItemID, |
910 | UUID hostID, int channel, string name, UUID id, | ||
911 | string message, int regexBitfield) | ||
733 | { | 912 | { |
734 | Initialise(handle, localID, ItemID, hostID, channel, name, id, message); | 913 | Initialise(handle, localID, ItemID, hostID, channel, name, id, |
914 | message, regexBitfield); | ||
735 | } | 915 | } |
736 | 916 | ||
737 | public ListenerInfo(ListenerInfo li, string name, UUID id, string message) | 917 | public ListenerInfo(ListenerInfo li, string name, UUID id, |
918 | string message) | ||
738 | { | 919 | { |
739 | Initialise(li.m_handle, li.m_localID, li.m_itemID, li.m_hostID, li.m_channel, name, id, message); | 920 | Initialise(li.m_handle, li.m_localID, li.m_itemID, li.m_hostID, |
921 | li.m_channel, name, id, message, 0); | ||
740 | } | 922 | } |
741 | 923 | ||
742 | private void Initialise(int handle, uint localID, UUID ItemID, UUID hostID, int channel, string name, | 924 | public ListenerInfo(ListenerInfo li, string name, UUID id, |
743 | UUID id, string message) | 925 | string message, int regexBitfield) |
926 | { | ||
927 | Initialise(li.m_handle, li.m_localID, li.m_itemID, li.m_hostID, | ||
928 | li.m_channel, name, id, message, regexBitfield); | ||
929 | } | ||
930 | |||
931 | private void Initialise(int handle, uint localID, UUID ItemID, | ||
932 | UUID hostID, int channel, string name, UUID id, | ||
933 | string message, int regexBitfield) | ||
744 | { | 934 | { |
745 | m_active = true; | 935 | m_active = true; |
746 | m_handle = handle; | 936 | m_handle = handle; |
@@ -751,11 +941,12 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm | |||
751 | m_name = name; | 941 | m_name = name; |
752 | m_id = id; | 942 | m_id = id; |
753 | m_message = message; | 943 | m_message = message; |
944 | RegexBitfield = regexBitfield; | ||
754 | } | 945 | } |
755 | 946 | ||
756 | public Object[] GetSerializationData() | 947 | public Object[] GetSerializationData() |
757 | { | 948 | { |
758 | Object[] data = new Object[6]; | 949 | Object[] data = new Object[7]; |
759 | 950 | ||
760 | data[0] = m_active; | 951 | data[0] = m_active; |
761 | data[1] = m_handle; | 952 | data[1] = m_handle; |
@@ -763,16 +954,22 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm | |||
763 | data[3] = m_name; | 954 | data[3] = m_name; |
764 | data[4] = m_id; | 955 | data[4] = m_id; |
765 | data[5] = m_message; | 956 | data[5] = m_message; |
957 | data[6] = RegexBitfield; | ||
766 | 958 | ||
767 | return data; | 959 | return data; |
768 | } | 960 | } |
769 | 961 | ||
770 | public static ListenerInfo FromData(uint localID, UUID ItemID, UUID hostID, Object[] data) | 962 | public static ListenerInfo FromData(uint localID, UUID ItemID, |
963 | UUID hostID, Object[] data) | ||
771 | { | 964 | { |
772 | ListenerInfo linfo = new ListenerInfo((int)data[1], localID, | 965 | ListenerInfo linfo = new ListenerInfo((int)data[1], localID, |
773 | ItemID, hostID, (int)data[2], (string)data[3], | 966 | ItemID, hostID, (int)data[2], (string)data[3], |
774 | (UUID)data[4], (string)data[5]); | 967 | (UUID)data[4], (string)data[5]); |
775 | linfo.m_active=(bool)data[0]; | 968 | linfo.m_active = (bool)data[0]; |
969 | if (data.Length >= 7) | ||
970 | { | ||
971 | linfo.RegexBitfield = (int)data[6]; | ||
972 | } | ||
776 | 973 | ||
777 | return linfo; | 974 | return linfo; |
778 | } | 975 | } |
@@ -831,5 +1028,7 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm | |||
831 | { | 1028 | { |
832 | return m_id; | 1029 | return m_id; |
833 | } | 1030 | } |
1031 | |||
1032 | public int RegexBitfield { get; private set; } | ||
834 | } | 1033 | } |
835 | } | 1034 | } |
diff --git a/OpenSim/Region/CoreModules/Scripting/XMLRPC/XMLRPCModule.cs b/OpenSim/Region/CoreModules/Scripting/XMLRPC/XMLRPCModule.cs index 0003af2..385f5ad 100644 --- a/OpenSim/Region/CoreModules/Scripting/XMLRPC/XMLRPCModule.cs +++ b/OpenSim/Region/CoreModules/Scripting/XMLRPC/XMLRPCModule.cs | |||
@@ -40,6 +40,7 @@ using OpenSim.Framework.Servers; | |||
40 | using OpenSim.Framework.Servers.HttpServer; | 40 | using OpenSim.Framework.Servers.HttpServer; |
41 | using OpenSim.Region.Framework.Interfaces; | 41 | using OpenSim.Region.Framework.Interfaces; |
42 | using OpenSim.Region.Framework.Scenes; | 42 | using OpenSim.Region.Framework.Scenes; |
43 | using Mono.Addins; | ||
43 | 44 | ||
44 | /***************************************************** | 45 | /***************************************************** |
45 | * | 46 | * |
@@ -76,7 +77,8 @@ using OpenSim.Region.Framework.Scenes; | |||
76 | 77 | ||
77 | namespace OpenSim.Region.CoreModules.Scripting.XMLRPC | 78 | namespace OpenSim.Region.CoreModules.Scripting.XMLRPC |
78 | { | 79 | { |
79 | public class XMLRPCModule : IRegionModule, IXMLRPC | 80 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "XMLRPCModule")] |
81 | public class XMLRPCModule : ISharedRegionModule, IXMLRPC | ||
80 | { | 82 | { |
81 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 83 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
82 | 84 | ||
@@ -86,6 +88,10 @@ namespace OpenSim.Region.CoreModules.Scripting.XMLRPC | |||
86 | private Dictionary<UUID, RPCChannelInfo> m_openChannels; | 88 | private Dictionary<UUID, RPCChannelInfo> m_openChannels; |
87 | private Dictionary<UUID, SendRemoteDataRequest> m_pendingSRDResponses; | 89 | private Dictionary<UUID, SendRemoteDataRequest> m_pendingSRDResponses; |
88 | private int m_remoteDataPort = 0; | 90 | private int m_remoteDataPort = 0; |
91 | public int Port | ||
92 | { | ||
93 | get { return m_remoteDataPort; } | ||
94 | } | ||
89 | 95 | ||
90 | private Dictionary<UUID, RPCRequestInfo> m_rpcPending; | 96 | private Dictionary<UUID, RPCRequestInfo> m_rpcPending; |
91 | private Dictionary<UUID, RPCRequestInfo> m_rpcPendingResponses; | 97 | private Dictionary<UUID, RPCRequestInfo> m_rpcPendingResponses; |
@@ -94,34 +100,24 @@ namespace OpenSim.Region.CoreModules.Scripting.XMLRPC | |||
94 | private int RemoteReplyScriptWait = 300; | 100 | private int RemoteReplyScriptWait = 300; |
95 | private object XMLRPCListLock = new object(); | 101 | private object XMLRPCListLock = new object(); |
96 | 102 | ||
97 | #region IRegionModule Members | 103 | #region ISharedRegionModule Members |
98 | 104 | ||
99 | public void Initialise(Scene scene, IConfigSource config) | 105 | public void Initialise(IConfigSource config) |
100 | { | 106 | { |
101 | // We need to create these early because the scripts might be calling | 107 | // We need to create these early because the scripts might be calling |
102 | // But since this gets called for every region, we need to make sure they | 108 | // But since this gets called for every region, we need to make sure they |
103 | // get called only one time (or we lose any open channels) | 109 | // get called only one time (or we lose any open channels) |
104 | if (null == m_openChannels) | 110 | m_openChannels = new Dictionary<UUID, RPCChannelInfo>(); |
105 | { | 111 | m_rpcPending = new Dictionary<UUID, RPCRequestInfo>(); |
106 | m_openChannels = new Dictionary<UUID, RPCChannelInfo>(); | 112 | m_rpcPendingResponses = new Dictionary<UUID, RPCRequestInfo>(); |
107 | m_rpcPending = new Dictionary<UUID, RPCRequestInfo>(); | 113 | m_pendingSRDResponses = new Dictionary<UUID, SendRemoteDataRequest>(); |
108 | m_rpcPendingResponses = new Dictionary<UUID, RPCRequestInfo>(); | ||
109 | m_pendingSRDResponses = new Dictionary<UUID, SendRemoteDataRequest>(); | ||
110 | 114 | ||
111 | try | 115 | try |
112 | { | 116 | { |
113 | m_remoteDataPort = config.Configs["XMLRPC"].GetInt("XmlRpcPort", m_remoteDataPort); | 117 | m_remoteDataPort = config.Configs["XMLRPC"].GetInt("XmlRpcPort", m_remoteDataPort); |
114 | } | ||
115 | catch (Exception) | ||
116 | { | ||
117 | } | ||
118 | } | 118 | } |
119 | 119 | catch (Exception) | |
120 | if (!m_scenes.Contains(scene)) | ||
121 | { | 120 | { |
122 | m_scenes.Add(scene); | ||
123 | |||
124 | scene.RegisterModuleInterface<IXMLRPC>(this); | ||
125 | } | 121 | } |
126 | } | 122 | } |
127 | 123 | ||
@@ -131,32 +127,56 @@ namespace OpenSim.Region.CoreModules.Scripting.XMLRPC | |||
131 | { | 127 | { |
132 | // Start http server | 128 | // Start http server |
133 | // Attach xmlrpc handlers | 129 | // Attach xmlrpc handlers |
134 | // m_log.InfoFormat( | 130 | // m_log.InfoFormat( |
135 | // "[XML RPC MODULE]: Starting up XMLRPC Server on port {0} for llRemoteData commands.", | 131 | // "[XML RPC MODULE]: Starting up XMLRPC Server on port {0} for llRemoteData commands.", |
136 | // m_remoteDataPort); | 132 | // m_remoteDataPort); |
137 | 133 | ||
138 | IHttpServer httpServer = MainServer.GetHttpServer((uint)m_remoteDataPort); | 134 | IHttpServer httpServer = MainServer.GetHttpServer((uint)m_remoteDataPort); |
139 | httpServer.AddXmlRPCHandler("llRemoteData", XmlRpcRemoteData); | 135 | httpServer.AddXmlRPCHandler("llRemoteData", XmlRpcRemoteData); |
140 | } | 136 | } |
141 | } | 137 | } |
142 | 138 | ||
143 | public void Close() | 139 | public void AddRegion(Scene scene) |
140 | { | ||
141 | if (!IsEnabled()) | ||
142 | return; | ||
143 | |||
144 | if (!m_scenes.Contains(scene)) | ||
145 | { | ||
146 | m_scenes.Add(scene); | ||
147 | |||
148 | scene.RegisterModuleInterface<IXMLRPC>(this); | ||
149 | } | ||
150 | } | ||
151 | |||
152 | public void RegionLoaded(Scene scene) | ||
144 | { | 153 | { |
145 | } | 154 | } |
146 | 155 | ||
147 | public string Name | 156 | public void RemoveRegion(Scene scene) |
148 | { | 157 | { |
149 | get { return m_name; } | 158 | if (!IsEnabled()) |
159 | return; | ||
160 | |||
161 | if (m_scenes.Contains(scene)) | ||
162 | { | ||
163 | scene.UnregisterModuleInterface<IXMLRPC>(this); | ||
164 | m_scenes.Remove(scene); | ||
165 | } | ||
150 | } | 166 | } |
151 | 167 | ||
152 | public bool IsSharedModule | 168 | public void Close() |
153 | { | 169 | { |
154 | get { return true; } | ||
155 | } | 170 | } |
156 | 171 | ||
157 | public int Port | 172 | public string Name |
158 | { | 173 | { |
159 | get { return m_remoteDataPort; } | 174 | get { return m_name; } |
175 | } | ||
176 | |||
177 | public Type ReplaceableInterface | ||
178 | { | ||
179 | get { return null; } | ||
160 | } | 180 | } |
161 | 181 | ||
162 | #endregion | 182 | #endregion |