diff options
-rw-r--r-- | OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RegionInfoCache.cs | 506 | ||||
-rw-r--r-- | OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | 85 |
2 files changed, 482 insertions, 109 deletions
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RegionInfoCache.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RegionInfoCache.cs index be8a9a2..4dc9033 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RegionInfoCache.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RegionInfoCache.cs | |||
@@ -26,6 +26,7 @@ | |||
26 | */ | 26 | */ |
27 | using System; | 27 | using System; |
28 | using System.Reflection; | 28 | using System.Reflection; |
29 | using System.Threading; | ||
29 | using System.Collections.Generic; | 30 | using System.Collections.Generic; |
30 | using OpenSim.Framework; | 31 | using OpenSim.Framework; |
31 | using OpenSim.Services.Interfaces; | 32 | using OpenSim.Services.Interfaces; |
@@ -37,54 +38,17 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid | |||
37 | { | 38 | { |
38 | public class RegionInfoCache | 39 | public class RegionInfoCache |
39 | { | 40 | { |
40 | private const double CACHE_EXPIRATION_SECONDS = 300.0; // 5 minutes | 41 | private const double CACHE_EXPIRATION_SECONDS = 120; // 2 minutes opensim regions change a lot |
41 | 42 | ||
42 | // private static readonly ILog m_log = | 43 | // private static readonly ILog m_log = |
43 | // LogManager.GetLogger( | 44 | // LogManager.GetLogger( |
44 | // MethodBase.GetCurrentMethod().DeclaringType); | 45 | // MethodBase.GetCurrentMethod().DeclaringType); |
45 | 46 | ||
46 | internal struct ScopedRegionUUID | 47 | private RegionsExpiringCache m_Cache; |
47 | { | ||
48 | public UUID m_scopeID; | ||
49 | public UUID m_regionID; | ||
50 | public ScopedRegionUUID(UUID scopeID, UUID regionID) | ||
51 | { | ||
52 | m_scopeID = scopeID; | ||
53 | m_regionID = regionID; | ||
54 | } | ||
55 | } | ||
56 | |||
57 | internal struct ScopedRegionName | ||
58 | { | ||
59 | public UUID m_scopeID; | ||
60 | public string m_name; | ||
61 | public ScopedRegionName(UUID scopeID, string name) | ||
62 | { | ||
63 | m_scopeID = scopeID; | ||
64 | m_name = name; | ||
65 | } | ||
66 | } | ||
67 | |||
68 | internal struct ScopedRegionPosition | ||
69 | { | ||
70 | public UUID m_scopeID; | ||
71 | public ulong m_regionHandle; | ||
72 | public ScopedRegionPosition(UUID scopeID, ulong handle) | ||
73 | { | ||
74 | m_scopeID = scopeID; | ||
75 | m_regionHandle = handle; | ||
76 | } | ||
77 | } | ||
78 | |||
79 | private ExpiringCache<ScopedRegionUUID, GridRegion> m_UUIDCache; | ||
80 | private ExpiringCache<ScopedRegionName, ScopedRegionUUID> m_NameCache; | ||
81 | private ExpiringCache<ScopedRegionPosition, GridRegion> m_PositionCache; | ||
82 | 48 | ||
83 | public RegionInfoCache() | 49 | public RegionInfoCache() |
84 | { | 50 | { |
85 | m_UUIDCache = new ExpiringCache<ScopedRegionUUID, GridRegion>(); | 51 | m_Cache = new RegionsExpiringCache(); |
86 | m_NameCache = new ExpiringCache<ScopedRegionName, ScopedRegionUUID>(); | ||
87 | m_PositionCache = new ExpiringCache<ScopedRegionPosition, GridRegion>(); | ||
88 | } | 52 | } |
89 | 53 | ||
90 | public void Cache(GridRegion rinfo) | 54 | public void Cache(GridRegion rinfo) |
@@ -101,18 +65,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid | |||
101 | if (rinfo == null) | 65 | if (rinfo == null) |
102 | return; | 66 | return; |
103 | 67 | ||
104 | ScopedRegionUUID id = new ScopedRegionUUID(scopeID,regionID); | 68 | m_Cache.AddOrUpdate(scopeID, rinfo, CACHE_EXPIRATION_SECONDS); |
105 | |||
106 | // Cache even null accounts | ||
107 | m_UUIDCache.AddOrUpdate(id, rinfo, CACHE_EXPIRATION_SECONDS); | ||
108 | if (rinfo != null) | ||
109 | { | ||
110 | ScopedRegionName name = new ScopedRegionName(scopeID,rinfo.RegionName); | ||
111 | m_NameCache.AddOrUpdate(name, id, CACHE_EXPIRATION_SECONDS); | ||
112 | |||
113 | ScopedRegionPosition pos = new ScopedRegionPosition(scopeID, rinfo.RegionHandle); | ||
114 | m_PositionCache.AddOrUpdate(pos, rinfo, CACHE_EXPIRATION_SECONDS); | ||
115 | } | ||
116 | } | 69 | } |
117 | 70 | ||
118 | public GridRegion Get(UUID scopeID, UUID regionID, out bool inCache) | 71 | public GridRegion Get(UUID scopeID, UUID regionID, out bool inCache) |
@@ -120,8 +73,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid | |||
120 | inCache = false; | 73 | inCache = false; |
121 | 74 | ||
122 | GridRegion rinfo = null; | 75 | GridRegion rinfo = null; |
123 | ScopedRegionUUID id = new ScopedRegionUUID(scopeID,regionID); | 76 | if (m_Cache.TryGetValue(scopeID, regionID, out rinfo)) |
124 | if (m_UUIDCache.TryGetValue(id, out rinfo)) | ||
125 | { | 77 | { |
126 | inCache = true; | 78 | inCache = true; |
127 | return rinfo; | 79 | return rinfo; |
@@ -135,8 +87,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid | |||
135 | inCache = false; | 87 | inCache = false; |
136 | 88 | ||
137 | GridRegion rinfo = null; | 89 | GridRegion rinfo = null; |
138 | ScopedRegionPosition pos = new ScopedRegionPosition(scopeID, handle); | 90 | if (m_Cache.TryGetValue(scopeID, handle, out rinfo)) |
139 | if (m_PositionCache.TryGetValue(pos, out rinfo)) | ||
140 | { | 91 | { |
141 | inCache = true; | 92 | inCache = true; |
142 | return rinfo; | 93 | return rinfo; |
@@ -145,25 +96,450 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid | |||
145 | return null; | 96 | return null; |
146 | } | 97 | } |
147 | 98 | ||
148 | |||
149 | public GridRegion Get(UUID scopeID, string name, out bool inCache) | 99 | public GridRegion Get(UUID scopeID, string name, out bool inCache) |
150 | { | 100 | { |
151 | inCache = false; | 101 | inCache = false; |
152 | 102 | ||
153 | ScopedRegionName sname = new ScopedRegionName(scopeID,name); | 103 | GridRegion rinfo = null; |
104 | if (m_Cache.TryGetValue(scopeID, name, out rinfo)) | ||
105 | { | ||
106 | inCache = true; | ||
107 | return rinfo; | ||
108 | } | ||
109 | |||
110 | return null; | ||
111 | } | ||
112 | } | ||
113 | |||
114 | |||
115 | // following code partialy adapted from lib OpenMetaverse | ||
116 | public class RegionKey : IComparable<RegionKey> | ||
117 | { | ||
118 | private UUID m_scopeID; | ||
119 | private UUID m_RegionID; | ||
120 | private DateTime m_expirationDate; | ||
121 | |||
122 | public RegionKey(UUID scopeID, UUID id) | ||
123 | { | ||
124 | m_scopeID = scopeID; | ||
125 | m_RegionID = id; | ||
126 | } | ||
127 | |||
128 | public UUID ScopeID | ||
129 | { | ||
130 | get { return m_scopeID; } | ||
131 | } | ||
132 | public DateTime ExpirationDate | ||
133 | { | ||
134 | get { return m_expirationDate; } | ||
135 | set { m_expirationDate = value; } | ||
136 | } | ||
137 | |||
138 | public int GetHaskCode() | ||
139 | { | ||
140 | int hash = m_scopeID.GetHashCode(); | ||
141 | hash += hash * 23 + m_RegionID.GetHashCode(); | ||
142 | return hash; | ||
143 | } | ||
144 | |||
145 | public int CompareTo(RegionKey other) | ||
146 | { | ||
147 | return GetHashCode().CompareTo(other.GetHashCode()); | ||
148 | } | ||
149 | } | ||
150 | |||
151 | public class RegionInfoByScope | ||
152 | { | ||
153 | private Dictionary<string, RegionKey> byname; | ||
154 | private Dictionary<ulong, RegionKey> byhandle; | ||
155 | |||
156 | public RegionInfoByScope() | ||
157 | { | ||
158 | byname = new Dictionary<string, RegionKey>(); | ||
159 | byhandle = new Dictionary<ulong, RegionKey>(); | ||
160 | } | ||
161 | |||
162 | public RegionInfoByScope(GridRegion region, RegionKey key) | ||
163 | { | ||
164 | byname = new Dictionary<string, RegionKey>(); | ||
165 | byhandle = new Dictionary<ulong, RegionKey>(); | ||
166 | |||
167 | byname[region.RegionName] = key; | ||
168 | byhandle[region.RegionHandle] = key; | ||
169 | } | ||
154 | 170 | ||
155 | ScopedRegionUUID id; | 171 | public void AddRegion(GridRegion region, RegionKey key) |
156 | if (m_NameCache.TryGetValue(sname, out id)) | 172 | { |
173 | if(byname == null) | ||
174 | byname = new Dictionary<string, RegionKey>(); | ||
175 | if(byhandle == null) | ||
176 | byhandle = new Dictionary<ulong, RegionKey>(); | ||
177 | |||
178 | byname[region.RegionName] = key; | ||
179 | byhandle[region.RegionHandle] = key; | ||
180 | } | ||
181 | |||
182 | public void RemoveRegion(GridRegion region) | ||
183 | { | ||
184 | if(byname != null) | ||
185 | byname.Remove(region.RegionName); | ||
186 | if(byhandle != null) | ||
187 | byhandle.Remove(region.RegionHandle); | ||
188 | } | ||
189 | |||
190 | public void Clear() | ||
191 | { | ||
192 | if(byname != null) | ||
193 | byname.Clear(); | ||
194 | if(byhandle != null) | ||
195 | byhandle.Clear(); | ||
196 | byname = null; | ||
197 | byhandle = null; | ||
198 | } | ||
199 | |||
200 | public RegionKey get(string name) | ||
201 | { | ||
202 | if(byname == null || !byname.ContainsKey(name)) | ||
203 | return null; | ||
204 | return byname[name]; | ||
205 | } | ||
206 | |||
207 | public RegionKey get(ulong handle) | ||
208 | { | ||
209 | if(byhandle == null || !byhandle.ContainsKey(handle)) | ||
210 | return null; | ||
211 | return byhandle[handle]; | ||
212 | } | ||
213 | |||
214 | public int Count() | ||
215 | { | ||
216 | if(byname == null) | ||
217 | return 0; | ||
218 | else | ||
219 | return byname.Count; | ||
220 | } | ||
221 | } | ||
222 | |||
223 | public sealed class RegionsExpiringCache | ||
224 | { | ||
225 | const double CACHE_PURGE_HZ = 60; | ||
226 | const int MAX_LOCK_WAIT = 5000; // milliseconds | ||
227 | |||
228 | /// <summary>For thread safety</summary> | ||
229 | object syncRoot = new object(); | ||
230 | /// <summary>For thread safety</summary> | ||
231 | object isPurging = new object(); | ||
232 | |||
233 | Dictionary<RegionKey, GridRegion> timedStorage = new Dictionary<RegionKey, GridRegion>(); | ||
234 | Dictionary<UUID, RegionInfoByScope> InfobyScope = new Dictionary<UUID, RegionInfoByScope>(); | ||
235 | private System.Timers.Timer timer = new System.Timers.Timer(TimeSpan.FromSeconds(CACHE_PURGE_HZ).TotalMilliseconds); | ||
236 | |||
237 | public RegionsExpiringCache() | ||
238 | { | ||
239 | timer.Elapsed += PurgeCache; | ||
240 | timer.Start(); | ||
241 | } | ||
242 | |||
243 | public bool Add(UUID scope, GridRegion region, double expirationSeconds) | ||
244 | { | ||
245 | if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT)) | ||
246 | throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms"); | ||
247 | |||
248 | RegionKey key = new RegionKey(scope , region.RegionID); | ||
249 | |||
250 | try | ||
157 | { | 251 | { |
158 | GridRegion rinfo = null; | 252 | if (timedStorage.ContainsKey(key)) |
159 | if (m_UUIDCache.TryGetValue(id, out rinfo)) | 253 | return false; |
254 | |||
255 | key.ExpirationDate = DateTime.UtcNow + TimeSpan.FromSeconds(expirationSeconds); | ||
256 | timedStorage.Add(key, region); | ||
257 | |||
258 | RegionInfoByScope ris = null; | ||
259 | if(!InfobyScope.TryGetValue(scope, out ris) || ris == null) | ||
160 | { | 260 | { |
161 | inCache = true; | 261 | ris = new RegionInfoByScope(region, key); |
162 | return rinfo; | 262 | InfobyScope[scope] = ris; |
163 | } | 263 | } |
264 | else | ||
265 | ris.AddRegion(region, key); | ||
266 | |||
267 | return true; | ||
164 | } | 268 | } |
269 | finally { Monitor.Exit(syncRoot);} | ||
270 | } | ||
271 | |||
272 | public bool AddOrUpdate(UUID scope, GridRegion region, double expirationSeconds) | ||
273 | { | ||
274 | if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT)) | ||
275 | throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms"); | ||
165 | 276 | ||
166 | return null; | 277 | try |
278 | { | ||
279 | RegionKey key = new RegionKey(scope, region.RegionID); | ||
280 | key.ExpirationDate = DateTime.UtcNow + TimeSpan.FromSeconds(expirationSeconds); | ||
281 | |||
282 | if (timedStorage.ContainsKey(key)) | ||
283 | { | ||
284 | timedStorage.Remove(key); | ||
285 | timedStorage.Add(key, region); | ||
286 | |||
287 | if(!InfobyScope.ContainsKey(scope)) | ||
288 | { | ||
289 | RegionInfoByScope ris = new RegionInfoByScope(region, key); | ||
290 | InfobyScope[scope] = ris; | ||
291 | } | ||
292 | return false; | ||
293 | } | ||
294 | else | ||
295 | { | ||
296 | timedStorage.Add(key, region); | ||
297 | RegionInfoByScope ris = null; | ||
298 | if(!InfobyScope.TryGetValue(scope, out ris) || ris == null) | ||
299 | { | ||
300 | ris = new RegionInfoByScope(region,key); | ||
301 | InfobyScope[scope] = ris; | ||
302 | } | ||
303 | else | ||
304 | ris.AddRegion(region,key); | ||
305 | return true; | ||
306 | } | ||
307 | } | ||
308 | finally { Monitor.Exit(syncRoot); } | ||
309 | } | ||
310 | |||
311 | public void Clear() | ||
312 | { | ||
313 | if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT)) | ||
314 | throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms"); | ||
315 | try | ||
316 | { | ||
317 | timedStorage.Clear(); | ||
318 | InfobyScope.Clear(); | ||
319 | } | ||
320 | finally { Monitor.Exit(syncRoot); } | ||
321 | } | ||
322 | |||
323 | public bool Contains(UUID scope, GridRegion region) | ||
324 | { | ||
325 | RegionKey key = new RegionKey(scope, region.RegionID); | ||
326 | return Contains(key); | ||
327 | } | ||
328 | |||
329 | public bool Contains(RegionKey key) | ||
330 | { | ||
331 | if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT)) | ||
332 | throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms"); | ||
333 | try | ||
334 | { | ||
335 | return timedStorage.ContainsKey(key); | ||
336 | } | ||
337 | finally { Monitor.Exit(syncRoot); } | ||
338 | } | ||
339 | |||
340 | public int Count | ||
341 | { | ||
342 | get | ||
343 | { | ||
344 | return timedStorage.Count; | ||
345 | } | ||
346 | } | ||
347 | |||
348 | public bool Remove(UUID scope, GridRegion region) | ||
349 | { | ||
350 | RegionKey key = new RegionKey(scope, region.RegionID); | ||
351 | |||
352 | if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT)) | ||
353 | throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms"); | ||
354 | try | ||
355 | { | ||
356 | if (timedStorage.ContainsKey(key)) | ||
357 | { | ||
358 | RegionInfoByScope ris = null; | ||
359 | if(InfobyScope.TryGetValue(scope, out ris) && ris != null) | ||
360 | { | ||
361 | GridRegion r = timedStorage[key]; | ||
362 | if(r != null) | ||
363 | ris.RemoveRegion(r); | ||
364 | if(ris.Count() == 0) | ||
365 | InfobyScope.Remove(scope); | ||
366 | } | ||
367 | timedStorage.Remove(key); | ||
368 | return true; | ||
369 | } | ||
370 | else | ||
371 | return false; | ||
372 | } | ||
373 | finally { Monitor.Exit(syncRoot); } | ||
374 | } | ||
375 | |||
376 | public bool TryGetValue(RegionKey key, out GridRegion value) | ||
377 | { | ||
378 | if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT)) | ||
379 | throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms"); | ||
380 | try | ||
381 | { | ||
382 | if (timedStorage.ContainsKey(key)) | ||
383 | { | ||
384 | value = timedStorage[key]; | ||
385 | return true; | ||
386 | } | ||
387 | } | ||
388 | finally { Monitor.Exit(syncRoot); } | ||
389 | |||
390 | value = null; | ||
391 | return false; | ||
392 | } | ||
393 | |||
394 | public bool TryGetValue(UUID scope, UUID id, out GridRegion value) | ||
395 | { | ||
396 | if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT)) | ||
397 | throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms"); | ||
398 | try | ||
399 | { | ||
400 | RegionKey rk = new RegionKey(scope, id); | ||
401 | if(timedStorage.ContainsKey(rk)) | ||
402 | { | ||
403 | value = timedStorage[rk]; | ||
404 | return true; | ||
405 | } | ||
406 | } | ||
407 | finally { Monitor.Exit(syncRoot); } | ||
408 | |||
409 | value = null; | ||
410 | return false; | ||
411 | } | ||
412 | |||
413 | public bool TryGetValue(UUID scope, string name, out GridRegion value) | ||
414 | { | ||
415 | if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT)) | ||
416 | throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms"); | ||
417 | try | ||
418 | { | ||
419 | value = null; | ||
420 | RegionInfoByScope ris = null; | ||
421 | if(!InfobyScope.TryGetValue(scope, out ris) || ris == null) | ||
422 | return false; | ||
423 | |||
424 | RegionKey key = ris.get(name); | ||
425 | if(key == null) | ||
426 | return false; | ||
427 | |||
428 | if(timedStorage.ContainsKey(key)) | ||
429 | { | ||
430 | value = timedStorage[key]; | ||
431 | return true; | ||
432 | } | ||
433 | } | ||
434 | finally { Monitor.Exit(syncRoot); } | ||
435 | |||
436 | return false; | ||
437 | } | ||
438 | |||
439 | public bool TryGetValue(UUID scope, ulong handle, out GridRegion value) | ||
440 | { | ||
441 | if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT)) | ||
442 | throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms"); | ||
443 | try | ||
444 | { | ||
445 | value = null; | ||
446 | RegionInfoByScope ris = null; | ||
447 | if(!InfobyScope.TryGetValue(scope, out ris) || ris == null) | ||
448 | return false; | ||
449 | |||
450 | RegionKey key = ris.get(handle); | ||
451 | if(key == null) | ||
452 | return false; | ||
453 | |||
454 | if(timedStorage.ContainsKey(key)) | ||
455 | { | ||
456 | value = timedStorage[key]; | ||
457 | return true; | ||
458 | } | ||
459 | } | ||
460 | finally { Monitor.Exit(syncRoot); } | ||
461 | |||
462 | value = null; | ||
463 | return false; | ||
464 | } | ||
465 | |||
466 | public bool Update(UUID scope, GridRegion region, double expirationSeconds) | ||
467 | { | ||
468 | if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT)) | ||
469 | throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms"); | ||
470 | |||
471 | RegionKey key = new RegionKey(scope, region.RegionID); | ||
472 | try | ||
473 | { | ||
474 | if (!timedStorage.ContainsKey(key)) | ||
475 | return false; | ||
476 | |||
477 | timedStorage.Remove(key); | ||
478 | key.ExpirationDate = DateTime.UtcNow + TimeSpan.FromSeconds(expirationSeconds); | ||
479 | timedStorage.Add(key, region); | ||
480 | return true; | ||
481 | } | ||
482 | finally { Monitor.Exit(syncRoot); } | ||
483 | } | ||
484 | |||
485 | /// <summary> | ||
486 | /// Purges expired objects from the cache. Called automatically by the purge timer. | ||
487 | /// </summary> | ||
488 | private void PurgeCache(object sender, System.Timers.ElapsedEventArgs e) | ||
489 | { | ||
490 | // Only let one thread purge at once - a buildup could cause a crash | ||
491 | // This could cause the purge to be delayed while there are lots of read/write ops | ||
492 | // happening on the cache | ||
493 | if (!Monitor.TryEnter(isPurging)) | ||
494 | return; | ||
495 | |||
496 | DateTime signalTime = DateTime.UtcNow; | ||
497 | |||
498 | try | ||
499 | { | ||
500 | // If we fail to acquire a lock on the synchronization root after MAX_LOCK_WAIT, skip this purge cycle | ||
501 | if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT)) | ||
502 | return; | ||
503 | try | ||
504 | { | ||
505 | OpenMetaverse.Lazy<List<object>> expiredItems = new OpenMetaverse.Lazy<List<object>>(); | ||
506 | |||
507 | foreach (RegionKey timedKey in timedStorage.Keys) | ||
508 | { | ||
509 | if (timedKey.ExpirationDate < signalTime) | ||
510 | { | ||
511 | // Mark the object for purge | ||
512 | expiredItems.Value.Add(timedKey); | ||
513 | } | ||
514 | else | ||
515 | { | ||
516 | break; | ||
517 | } | ||
518 | } | ||
519 | |||
520 | |||
521 | RegionInfoByScope ris; | ||
522 | if (expiredItems.IsValueCreated) | ||
523 | { | ||
524 | foreach (RegionKey key in expiredItems.Value) | ||
525 | { | ||
526 | ris = null; | ||
527 | if(InfobyScope.TryGetValue(key.ScopeID, out ris) && ris != null) | ||
528 | { | ||
529 | GridRegion r = timedStorage[key]; | ||
530 | if(r != null) | ||
531 | ris.RemoveRegion(r); | ||
532 | |||
533 | if(ris.Count() == 0) | ||
534 | InfobyScope.Remove(key.ScopeID); | ||
535 | } | ||
536 | timedStorage.Remove(key); | ||
537 | } | ||
538 | } | ||
539 | } | ||
540 | finally { Monitor.Exit(syncRoot); } | ||
541 | } | ||
542 | finally { Monitor.Exit(isPurging); } | ||
167 | } | 543 | } |
168 | } | 544 | } |
169 | } | 545 | } |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 6d2e2c8..fb35a54 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | |||
@@ -6394,64 +6394,61 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
6394 | { | 6394 | { |
6395 | m_host.AddScriptLPS(1); | 6395 | m_host.AddScriptLPS(1); |
6396 | 6396 | ||
6397 | // edge will be used to pass the Region Coordinates offset | 6397 | if(dir.x == 0.0 && dir.y == 0.0) |
6398 | // we want to check for a neighboring sim | 6398 | return 1; // SL wiki |
6399 | LSL_Vector edge = new LSL_Vector(0, 0, 0); | 6399 | |
6400 | float rsx = World.RegionInfo.RegionSizeX; | ||
6401 | float rsy = World.RegionInfo.RegionSizeY; | ||
6402 | |||
6403 | // can understand what sl does if position is not in region, so do something :) | ||
6404 | float px = (float)Util.Clamp(pos.x, 0.5, rsx - 0.5); | ||
6405 | float py = (float)Util.Clamp(pos.y, 0.5, rsy - 0.5); | ||
6406 | |||
6407 | float ex, ey; | ||
6400 | 6408 | ||
6401 | if (dir.x == 0) | 6409 | if (dir.x == 0) |
6402 | { | 6410 | { |
6403 | if (dir.y == 0) | 6411 | ex = px; |
6404 | { | 6412 | ey = dir.y > 0.0 ? rsy + 1.0f : -1.0f; |
6405 | // Direction vector is 0,0 so return | 6413 | } |
6406 | // false since we're staying in the sim | 6414 | else if(dir.y == 0.0f) |
6407 | return 0; | 6415 | { |
6408 | } | 6416 | ex = dir.x > 0 ? rsx + 1.0f : -1.0f; |
6409 | else | 6417 | ey = py; |
6410 | { | ||
6411 | // Y is the only valid direction | ||
6412 | edge.y = dir.y / Math.Abs(dir.y) * (World.RegionInfo.RegionSizeY / Constants.RegionSize); | ||
6413 | } | ||
6414 | } | 6418 | } |
6415 | else | 6419 | else |
6416 | { | 6420 | { |
6417 | LSL_Float mag; | 6421 | float dx = (float) dir.x; |
6418 | if (dir.x > 0) | 6422 | float dy = (float) dir.y; |
6419 | { | ||
6420 | mag = (World.RegionInfo.RegionSizeX - pos.x) / dir.x; | ||
6421 | } | ||
6422 | else | ||
6423 | { | ||
6424 | mag = (pos.x/dir.x); | ||
6425 | } | ||
6426 | 6423 | ||
6427 | mag = Math.Abs(mag); | 6424 | float t1 = dx * dx + dy * dy; |
6425 | dx /= t1; | ||
6426 | dy /= t1; | ||
6428 | 6427 | ||
6429 | edge.y = pos.y + (dir.y * mag); | 6428 | if(dx > 0) |
6430 | 6429 | t1 = (rsx + 1f - px)/dx; | |
6431 | if (edge.y > World.RegionInfo.RegionSizeY || edge.y < 0) | ||
6432 | { | ||
6433 | // Y goes out of bounds first | ||
6434 | edge.y = dir.y / Math.Abs(dir.y) * (World.RegionInfo.RegionSizeY / Constants.RegionSize); | ||
6435 | } | ||
6436 | else | 6430 | else |
6437 | { | 6431 | t1 = -(px + 1f)/dx; |
6438 | // X goes out of bounds first or its a corner exit | ||
6439 | edge.y = 0; | ||
6440 | edge.x = dir.x / Math.Abs(dir.x) * (World.RegionInfo.RegionSizeY / Constants.RegionSize); | ||
6441 | } | ||
6442 | } | ||
6443 | 6432 | ||
6444 | List<GridRegion> neighbors = World.GridService.GetNeighbours(World.RegionInfo.ScopeID, World.RegionInfo.RegionID); | ||
6445 | 6433 | ||
6446 | uint neighborX = World.RegionInfo.RegionLocX + (uint)edge.x; | 6434 | float t2; |
6447 | uint neighborY = World.RegionInfo.RegionLocY + (uint)edge.y; | 6435 | if(dy > 0) |
6436 | t2 = (rsy + 1f - py)/dy; | ||
6437 | else | ||
6438 | t2 = -(py + 1f)/dy; | ||
6448 | 6439 | ||
6449 | foreach (GridRegion sri in neighbors) | 6440 | if(t1 > t2) |
6450 | { | 6441 | t1 = t2; |
6451 | if (sri.RegionCoordX == neighborX && sri.RegionCoordY == neighborY) | 6442 | |
6452 | return 0; | 6443 | ex = px + t1 * dx; |
6444 | ey = py + t1 * dy; | ||
6453 | } | 6445 | } |
6454 | 6446 | ||
6447 | ex += World.RegionInfo.WorldLocX; | ||
6448 | ey += World.RegionInfo.WorldLocY; | ||
6449 | |||
6450 | if(World.GridService.GetRegionByPosition(World.RegionInfo.ScopeID, (int)ex, (int)ey) != null) | ||
6451 | return 0; | ||
6455 | return 1; | 6452 | return 1; |
6456 | } | 6453 | } |
6457 | 6454 | ||