diff options
author | Robert Adams | 2015-09-08 04:54:16 -0700 |
---|---|---|
committer | Robert Adams | 2015-09-08 04:54:16 -0700 |
commit | e5367d822be9b05e74c859afe2d2956a3e95aa33 (patch) | |
tree | e904050a30715df587aa527d7f313755177726a7 /OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCombinerModule.cs | |
parent | add lost admin_reset_land method (diff) | |
parent | Deleted access control spec from [LoginService] section of standalone config.... (diff) | |
download | opensim-SC-e5367d822be9b05e74c859afe2d2956a3e95aa33.zip opensim-SC-e5367d822be9b05e74c859afe2d2956a3e95aa33.tar.gz opensim-SC-e5367d822be9b05e74c859afe2d2956a3e95aa33.tar.bz2 opensim-SC-e5367d822be9b05e74c859afe2d2956a3e95aa33.tar.xz |
Merge of ubitworkvarnew with opensim/master as of 20150905.
This integrates the OpenSim refactoring to make physics, etc into modules.
AVN physics hasn't been moved to new location.
Does not compile yet.
Merge branch 'osmaster' into mbworknew1
Diffstat (limited to 'OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCombinerModule.cs')
-rw-r--r-- | OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCombinerModule.cs | 878 |
1 files changed, 878 insertions, 0 deletions
diff --git a/OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCombinerModule.cs b/OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCombinerModule.cs new file mode 100644 index 0000000..98b0ae1 --- /dev/null +++ b/OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCombinerModule.cs | |||
@@ -0,0 +1,878 @@ | |||
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.Collections.Generic; | ||
30 | using System.Reflection; | ||
31 | using log4net; | ||
32 | using Nini.Config; | ||
33 | using OpenMetaverse; | ||
34 | using OpenSim.Framework; | ||
35 | using OpenSim.Framework.Client; | ||
36 | using OpenSim.Region.Framework.Interfaces; | ||
37 | using OpenSim.Region.Framework.Scenes; | ||
38 | using OpenSim.Framework.Console; | ||
39 | using OpenSim.Region.PhysicsModules.SharedBase; | ||
40 | using Mono.Addins; | ||
41 | |||
42 | namespace OpenSim.Region.RegionCombinerModule | ||
43 | { | ||
44 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "RegionCombinerModule")] | ||
45 | public class RegionCombinerModule : ISharedRegionModule, IRegionCombinerModule | ||
46 | { | ||
47 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
48 | // private static string LogHeader = "[REGION COMBINER MODULE]"; | ||
49 | |||
50 | public string Name | ||
51 | { | ||
52 | get { return "RegionCombinerModule"; } | ||
53 | } | ||
54 | |||
55 | public Type ReplaceableInterface | ||
56 | { | ||
57 | get { return null; } | ||
58 | } | ||
59 | |||
60 | /// <summary> | ||
61 | /// Is this module enabled? | ||
62 | /// </summary> | ||
63 | private bool m_combineContiguousRegions = false; | ||
64 | |||
65 | /// <summary> | ||
66 | /// This holds the root regions for the megaregions. | ||
67 | /// </summary> | ||
68 | /// <remarks> | ||
69 | /// Usually there is only ever one megaregion (and hence only one entry here). | ||
70 | /// </remarks> | ||
71 | private Dictionary<UUID, RegionConnections> m_regions = new Dictionary<UUID, RegionConnections>(); | ||
72 | |||
73 | /// <summary> | ||
74 | /// The scenes that comprise the megaregion. | ||
75 | /// </summary> | ||
76 | private Dictionary<UUID, Scene> m_startingScenes = new Dictionary<UUID, Scene>(); | ||
77 | |||
78 | public void Initialise(IConfigSource source) | ||
79 | { | ||
80 | IConfig myConfig = source.Configs["Startup"]; | ||
81 | m_combineContiguousRegions = myConfig.GetBoolean("CombineContiguousRegions", false); | ||
82 | |||
83 | MainConsole.Instance.Commands.AddCommand( | ||
84 | "RegionCombinerModule", false, "fix-phantoms", "fix-phantoms", | ||
85 | "Fixes phantom objects after an import to a megaregion or a change from a megaregion back to normal regions", | ||
86 | FixPhantoms); | ||
87 | } | ||
88 | |||
89 | public void Close() | ||
90 | { | ||
91 | } | ||
92 | |||
93 | public void AddRegion(Scene scene) | ||
94 | { | ||
95 | if (m_combineContiguousRegions) | ||
96 | scene.RegisterModuleInterface<IRegionCombinerModule>(this); | ||
97 | } | ||
98 | |||
99 | public void RemoveRegion(Scene scene) | ||
100 | { | ||
101 | lock (m_startingScenes) | ||
102 | m_startingScenes.Remove(scene.RegionInfo.originRegionID); | ||
103 | } | ||
104 | |||
105 | public void RegionLoaded(Scene scene) | ||
106 | { | ||
107 | lock (m_startingScenes) | ||
108 | m_startingScenes.Add(scene.RegionInfo.originRegionID, scene); | ||
109 | |||
110 | if (m_combineContiguousRegions) | ||
111 | { | ||
112 | RegionLoadedDoWork(scene); | ||
113 | |||
114 | scene.EventManager.OnNewPresence += NewPresence; | ||
115 | } | ||
116 | } | ||
117 | |||
118 | public bool IsRootForMegaregion(UUID regionId) | ||
119 | { | ||
120 | lock (m_regions) | ||
121 | return m_regions.ContainsKey(regionId); | ||
122 | } | ||
123 | |||
124 | public Vector2 GetSizeOfMegaregion(UUID regionId) | ||
125 | { | ||
126 | lock (m_regions) | ||
127 | { | ||
128 | if (m_regions.ContainsKey(regionId)) | ||
129 | { | ||
130 | RegionConnections rootConn = m_regions[regionId]; | ||
131 | |||
132 | return new Vector2((float)rootConn.XEnd, (float)rootConn.YEnd); | ||
133 | } | ||
134 | } | ||
135 | |||
136 | throw new Exception(string.Format("Region with id {0} not found", regionId)); | ||
137 | } | ||
138 | |||
139 | // Test to see if this postiion (relative to the region) is within the area covered | ||
140 | // by this megaregion. | ||
141 | public bool PositionIsInMegaregion(UUID currentRegion, int xx, int yy) | ||
142 | { | ||
143 | bool ret = false; | ||
144 | if (xx < 0 || yy < 0) | ||
145 | return ret; | ||
146 | |||
147 | foreach (RegionConnections rootRegion in m_regions.Values) | ||
148 | { | ||
149 | if (currentRegion == rootRegion.RegionId) | ||
150 | { | ||
151 | // The caller is in the root region so this is an easy test | ||
152 | if (xx < rootRegion.XEnd && yy < rootRegion.YEnd) | ||
153 | { | ||
154 | ret = true; | ||
155 | } | ||
156 | break; | ||
157 | } | ||
158 | else | ||
159 | { | ||
160 | // Maybe the caller is in one of the sub-regions | ||
161 | foreach (RegionData childRegion in rootRegion.ConnectedRegions) | ||
162 | { | ||
163 | if (currentRegion == childRegion.RegionId) | ||
164 | { | ||
165 | // This is a child. Diddle the offsets and check if in | ||
166 | Vector3 positionInMegaregion = childRegion.Offset; | ||
167 | positionInMegaregion.X += xx; | ||
168 | positionInMegaregion.Y += yy; | ||
169 | if (positionInMegaregion.X < rootRegion.XEnd && positionInMegaregion.Y < rootRegion.YEnd) | ||
170 | { | ||
171 | ret = true; | ||
172 | } | ||
173 | break; | ||
174 | } | ||
175 | } | ||
176 | } | ||
177 | } | ||
178 | |||
179 | return ret; | ||
180 | } | ||
181 | |||
182 | private void NewPresence(ScenePresence presence) | ||
183 | { | ||
184 | if (presence.IsChildAgent) | ||
185 | { | ||
186 | byte[] throttleData; | ||
187 | |||
188 | try | ||
189 | { | ||
190 | throttleData = presence.ControllingClient.GetThrottlesPacked(1); | ||
191 | } | ||
192 | catch (NotImplementedException) | ||
193 | { | ||
194 | return; | ||
195 | } | ||
196 | |||
197 | if (throttleData == null) | ||
198 | return; | ||
199 | |||
200 | if (throttleData.Length == 0) | ||
201 | return; | ||
202 | |||
203 | if (throttleData.Length != 28) | ||
204 | return; | ||
205 | |||
206 | byte[] adjData; | ||
207 | int pos = 0; | ||
208 | |||
209 | if (!BitConverter.IsLittleEndian) | ||
210 | { | ||
211 | byte[] newData = new byte[7 * 4]; | ||
212 | Buffer.BlockCopy(throttleData, 0, newData, 0, 7 * 4); | ||
213 | |||
214 | for (int i = 0; i < 7; i++) | ||
215 | Array.Reverse(newData, i * 4, 4); | ||
216 | |||
217 | adjData = newData; | ||
218 | } | ||
219 | else | ||
220 | { | ||
221 | adjData = throttleData; | ||
222 | } | ||
223 | |||
224 | // 0.125f converts from bits to bytes | ||
225 | int resend = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; | ||
226 | int land = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; | ||
227 | int wind = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; | ||
228 | int cloud = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; | ||
229 | int task = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; | ||
230 | int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; | ||
231 | int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); | ||
232 | // State is a subcategory of task that we allocate a percentage to | ||
233 | |||
234 | |||
235 | //int total = resend + land + wind + cloud + task + texture + asset; | ||
236 | |||
237 | byte[] data = new byte[7 * 4]; | ||
238 | int ii = 0; | ||
239 | |||
240 | Buffer.BlockCopy(Utils.FloatToBytes(resend), 0, data, ii, 4); ii += 4; | ||
241 | Buffer.BlockCopy(Utils.FloatToBytes(land * 50), 0, data, ii, 4); ii += 4; | ||
242 | Buffer.BlockCopy(Utils.FloatToBytes(wind), 0, data, ii, 4); ii += 4; | ||
243 | Buffer.BlockCopy(Utils.FloatToBytes(cloud), 0, data, ii, 4); ii += 4; | ||
244 | Buffer.BlockCopy(Utils.FloatToBytes(task), 0, data, ii, 4); ii += 4; | ||
245 | Buffer.BlockCopy(Utils.FloatToBytes(texture), 0, data, ii, 4); ii += 4; | ||
246 | Buffer.BlockCopy(Utils.FloatToBytes(asset), 0, data, ii, 4); | ||
247 | |||
248 | try | ||
249 | { | ||
250 | presence.ControllingClient.SetChildAgentThrottle(data); | ||
251 | } | ||
252 | catch (NotImplementedException) | ||
253 | { | ||
254 | return; | ||
255 | } | ||
256 | } | ||
257 | } | ||
258 | |||
259 | private void RegionLoadedDoWork(Scene scene) | ||
260 | { | ||
261 | /* | ||
262 | // For testing on a single instance | ||
263 | if (scene.RegionInfo.RegionLocX == 1004 && scene.RegionInfo.RegionLocY == 1000) | ||
264 | return; | ||
265 | // | ||
266 | */ | ||
267 | |||
268 | RegionConnections newConn = new RegionConnections(); | ||
269 | newConn.ConnectedRegions = new List<RegionData>(); | ||
270 | newConn.RegionScene = scene; | ||
271 | newConn.RegionLandChannel = scene.LandChannel; | ||
272 | newConn.RegionId = scene.RegionInfo.originRegionID; | ||
273 | newConn.X = scene.RegionInfo.RegionLocX; | ||
274 | newConn.Y = scene.RegionInfo.RegionLocY; | ||
275 | newConn.XEnd = scene.RegionInfo.RegionSizeX; | ||
276 | newConn.YEnd = scene.RegionInfo.RegionSizeX; | ||
277 | |||
278 | lock (m_regions) | ||
279 | { | ||
280 | bool connectedYN = false; | ||
281 | |||
282 | foreach (RegionConnections rootConn in m_regions.Values) | ||
283 | { | ||
284 | #region commented | ||
285 | /* | ||
286 | // If we're one region over +x +y | ||
287 | //xxy | ||
288 | //xxx | ||
289 | //xxx | ||
290 | if ((((int)conn.X * (int)Constants.RegionSize) + conn.XEnd | ||
291 | == (regionConnections.X * (int)Constants.RegionSize)) | ||
292 | && (((int)conn.Y * (int)Constants.RegionSize) - conn.YEnd | ||
293 | == (regionConnections.Y * (int)Constants.RegionSize))) | ||
294 | { | ||
295 | Vector3 offset = Vector3.Zero; | ||
296 | offset.X = (((regionConnections.X * (int) Constants.RegionSize)) - | ||
297 | ((conn.X * (int) Constants.RegionSize))); | ||
298 | offset.Y = (((regionConnections.Y * (int) Constants.RegionSize)) - | ||
299 | ((conn.Y * (int) Constants.RegionSize))); | ||
300 | |||
301 | Vector3 extents = Vector3.Zero; | ||
302 | extents.Y = regionConnections.YEnd + conn.YEnd; | ||
303 | extents.X = conn.XEnd + conn.XEnd; | ||
304 | |||
305 | m_log.DebugFormat("Scene: {0} to the northwest of Scene{1}. Offset: {2}. Extents:{3}", | ||
306 | conn.RegionScene.RegionInfo.RegionName, | ||
307 | regionConnections.RegionScene.RegionInfo.RegionName, | ||
308 | offset, extents); | ||
309 | |||
310 | scene.PhysicsScene.Combine(conn.RegionScene.PhysicsScene, offset, extents); | ||
311 | |||
312 | connectedYN = true; | ||
313 | break; | ||
314 | } | ||
315 | */ | ||
316 | |||
317 | /* | ||
318 | //If we're one region over x +y | ||
319 | //xxx | ||
320 | //xxx | ||
321 | //xyx | ||
322 | if ((((int)conn.X * (int)Constants.RegionSize) | ||
323 | == (regionConnections.X * (int)Constants.RegionSize)) | ||
324 | && (((int)conn.Y * (int)Constants.RegionSize) - conn.YEnd | ||
325 | == (regionConnections.Y * (int)Constants.RegionSize))) | ||
326 | { | ||
327 | Vector3 offset = Vector3.Zero; | ||
328 | offset.X = (((regionConnections.X * (int)Constants.RegionSize)) - | ||
329 | ((conn.X * (int)Constants.RegionSize))); | ||
330 | offset.Y = (((regionConnections.Y * (int)Constants.RegionSize)) - | ||
331 | ((conn.Y * (int)Constants.RegionSize))); | ||
332 | |||
333 | Vector3 extents = Vector3.Zero; | ||
334 | extents.Y = regionConnections.YEnd + conn.YEnd; | ||
335 | extents.X = conn.XEnd; | ||
336 | |||
337 | m_log.DebugFormat("Scene: {0} to the north of Scene{1}. Offset: {2}. Extents:{3}", | ||
338 | conn.RegionScene.RegionInfo.RegionName, | ||
339 | regionConnections.RegionScene.RegionInfo.RegionName, offset, extents); | ||
340 | |||
341 | scene.PhysicsScene.Combine(conn.RegionScene.PhysicsScene, offset, extents); | ||
342 | connectedYN = true; | ||
343 | break; | ||
344 | } | ||
345 | */ | ||
346 | |||
347 | /* | ||
348 | // If we're one region over -x +y | ||
349 | //xxx | ||
350 | //xxx | ||
351 | //yxx | ||
352 | if ((((int)conn.X * (int)Constants.RegionSize) - conn.XEnd | ||
353 | == (regionConnections.X * (int)Constants.RegionSize)) | ||
354 | && (((int)conn.Y * (int)Constants.RegionSize) - conn.YEnd | ||
355 | == (regionConnections.Y * (int)Constants.RegionSize))) | ||
356 | { | ||
357 | Vector3 offset = Vector3.Zero; | ||
358 | offset.X = (((regionConnections.X * (int)Constants.RegionSize)) - | ||
359 | ((conn.X * (int)Constants.RegionSize))); | ||
360 | offset.Y = (((regionConnections.Y * (int)Constants.RegionSize)) - | ||
361 | ((conn.Y * (int)Constants.RegionSize))); | ||
362 | |||
363 | Vector3 extents = Vector3.Zero; | ||
364 | extents.Y = regionConnections.YEnd + conn.YEnd; | ||
365 | extents.X = conn.XEnd + conn.XEnd; | ||
366 | |||
367 | m_log.DebugFormat("Scene: {0} to the northeast of Scene. Offset: {2}. Extents:{3}", | ||
368 | conn.RegionScene.RegionInfo.RegionName, | ||
369 | regionConnections.RegionScene.RegionInfo.RegionName, offset, extents); | ||
370 | |||
371 | scene.PhysicsScene.Combine(conn.RegionScene.PhysicsScene, offset, extents); | ||
372 | |||
373 | |||
374 | connectedYN = true; | ||
375 | break; | ||
376 | } | ||
377 | */ | ||
378 | |||
379 | /* | ||
380 | // If we're one region over -x y | ||
381 | //xxx | ||
382 | //yxx | ||
383 | //xxx | ||
384 | if ((((int)conn.X * (int)Constants.RegionSize) - conn.XEnd | ||
385 | == (regionConnections.X * (int)Constants.RegionSize)) | ||
386 | && (((int)conn.Y * (int)Constants.RegionSize) | ||
387 | == (regionConnections.Y * (int)Constants.RegionSize))) | ||
388 | { | ||
389 | Vector3 offset = Vector3.Zero; | ||
390 | offset.X = (((regionConnections.X * (int)Constants.RegionSize)) - | ||
391 | ((conn.X * (int)Constants.RegionSize))); | ||
392 | offset.Y = (((regionConnections.Y * (int)Constants.RegionSize)) - | ||
393 | ((conn.Y * (int)Constants.RegionSize))); | ||
394 | |||
395 | Vector3 extents = Vector3.Zero; | ||
396 | extents.Y = regionConnections.YEnd; | ||
397 | extents.X = conn.XEnd + conn.XEnd; | ||
398 | |||
399 | m_log.DebugFormat("Scene: {0} to the east of Scene{1} Offset: {2}. Extents:{3}", | ||
400 | conn.RegionScene.RegionInfo.RegionName, | ||
401 | regionConnections.RegionScene.RegionInfo.RegionName, offset, extents); | ||
402 | |||
403 | scene.PhysicsScene.Combine(conn.RegionScene.PhysicsScene, offset, extents); | ||
404 | |||
405 | connectedYN = true; | ||
406 | break; | ||
407 | } | ||
408 | */ | ||
409 | |||
410 | /* | ||
411 | // If we're one region over -x -y | ||
412 | //yxx | ||
413 | //xxx | ||
414 | //xxx | ||
415 | if ((((int)conn.X * (int)Constants.RegionSize) - conn.XEnd | ||
416 | == (regionConnections.X * (int)Constants.RegionSize)) | ||
417 | && (((int)conn.Y * (int)Constants.RegionSize) + conn.YEnd | ||
418 | == (regionConnections.Y * (int)Constants.RegionSize))) | ||
419 | { | ||
420 | Vector3 offset = Vector3.Zero; | ||
421 | offset.X = (((regionConnections.X * (int)Constants.RegionSize)) - | ||
422 | ((conn.X * (int)Constants.RegionSize))); | ||
423 | offset.Y = (((regionConnections.Y * (int)Constants.RegionSize)) - | ||
424 | ((conn.Y * (int)Constants.RegionSize))); | ||
425 | |||
426 | Vector3 extents = Vector3.Zero; | ||
427 | extents.Y = regionConnections.YEnd + conn.YEnd; | ||
428 | extents.X = conn.XEnd + conn.XEnd; | ||
429 | |||
430 | m_log.DebugFormat("Scene: {0} to the northeast of Scene{1} Offset: {2}. Extents:{3}", | ||
431 | conn.RegionScene.RegionInfo.RegionName, | ||
432 | regionConnections.RegionScene.RegionInfo.RegionName, offset, extents); | ||
433 | |||
434 | scene.PhysicsScene.Combine(conn.RegionScene.PhysicsScene, offset, extents); | ||
435 | |||
436 | connectedYN = true; | ||
437 | break; | ||
438 | } | ||
439 | */ | ||
440 | #endregion | ||
441 | |||
442 | |||
443 | // Check to see if this new region is adjacent to the root region. | ||
444 | // Note that we expect the regions to be combined from the root region outward | ||
445 | // thus the requirement for the ordering in the configuration files. | ||
446 | |||
447 | // If we're one region over +x y (i.e. root region is to the west) | ||
448 | //xxx | ||
449 | //xxy | ||
450 | //xxx | ||
451 | if (rootConn.PosX + rootConn.XEnd >= newConn.PosX && rootConn.PosY >= newConn.PosY) | ||
452 | { | ||
453 | connectedYN = DoWorkForOneRegionOverPlusXY(rootConn, newConn, scene); | ||
454 | break; | ||
455 | } | ||
456 | |||
457 | // If we're one region over x +y (i.e. root region is to the south) | ||
458 | //xyx | ||
459 | //xxx | ||
460 | //xxx | ||
461 | if (rootConn.PosX >= newConn.PosX && rootConn.PosY + rootConn.YEnd >= newConn.PosY) | ||
462 | { | ||
463 | connectedYN = DoWorkForOneRegionOverPlusXY(rootConn, newConn, scene); | ||
464 | break; | ||
465 | } | ||
466 | |||
467 | // If we're one region over +x +y (i.e. root region is to the south-west) | ||
468 | //xxy | ||
469 | //xxx | ||
470 | //xxx | ||
471 | if (rootConn.PosX + rootConn.XEnd >= newConn.PosX && rootConn.PosY + rootConn.YEnd >= newConn.PosY) | ||
472 | { | ||
473 | connectedYN = DoWorkForOneRegionOverPlusXY(rootConn, newConn, scene); | ||
474 | break; | ||
475 | } | ||
476 | } | ||
477 | |||
478 | // If !connectYN means that this region is a root region | ||
479 | if (!connectedYN) | ||
480 | { | ||
481 | DoWorkForRootRegion(newConn, scene); | ||
482 | } | ||
483 | } | ||
484 | } | ||
485 | |||
486 | private bool DoWorkForOneRegionOverPlusXY(RegionConnections rootConn, RegionConnections newConn, Scene scene) | ||
487 | { | ||
488 | // Offset (in meters) from the base of this region to the base of the root region. | ||
489 | Vector3 offset = Vector3.Zero; | ||
490 | offset.X = newConn.PosX - rootConn.PosX; | ||
491 | offset.Y = newConn.PosY - rootConn.PosY; | ||
492 | |||
493 | // The new total size of the region (in meters) | ||
494 | // We just extend the X and Y dimensions so the extent might temporarily include areas without regions. | ||
495 | Vector3 extents = Vector3.Zero; | ||
496 | extents.X = Math.Max(rootConn.XEnd, offset.X + newConn.RegionScene.RegionInfo.RegionSizeX); | ||
497 | extents.Y = Math.Max(rootConn.YEnd, offset.Y + newConn.RegionScene.RegionInfo.RegionSizeY); | ||
498 | |||
499 | rootConn.UpdateExtents(extents); | ||
500 | |||
501 | m_log.DebugFormat( | ||
502 | "[REGION COMBINER MODULE]: Root region {0} is to the west of region {1}, Offset: {2}, Extents: {3}", | ||
503 | rootConn.RegionScene.RegionInfo.RegionName, | ||
504 | newConn.RegionScene.RegionInfo.RegionName, offset, extents); | ||
505 | |||
506 | RegionData ConnectedRegion = new RegionData(); | ||
507 | ConnectedRegion.Offset = offset; | ||
508 | ConnectedRegion.RegionId = scene.RegionInfo.originRegionID; | ||
509 | ConnectedRegion.RegionScene = scene; | ||
510 | rootConn.ConnectedRegions.Add(ConnectedRegion); | ||
511 | |||
512 | // Inform root region Physics about the extents of this region | ||
513 | rootConn.RegionScene.PhysicsScene.Combine(null, Vector3.Zero, extents); | ||
514 | |||
515 | // Inform Child region that it needs to forward it's terrain to the root region | ||
516 | scene.PhysicsScene.Combine(rootConn.RegionScene.PhysicsScene, offset, Vector3.Zero); | ||
517 | |||
518 | // Reset Terrain.. since terrain loads before we get here, we need to load | ||
519 | // it again so it loads in the root region | ||
520 | scene.PhysicsScene.SetTerrain(scene.Heightmap.GetFloatsSerialised()); | ||
521 | |||
522 | // Create a client event forwarder and add this region's events to the root region. | ||
523 | if (rootConn.ClientEventForwarder != null) | ||
524 | rootConn.ClientEventForwarder.AddSceneToEventForwarding(scene); | ||
525 | |||
526 | return true; | ||
527 | } | ||
528 | |||
529 | /* | ||
530 | * 20140215 radams1: The border stuff was removed and the addition of regions to the mega-regions | ||
531 | * was generalized. These functions are not needed for the generalized solution but left for reference. | ||
532 | private bool DoWorkForOneRegionOverXPlusY(RegionConnections rootConn, RegionConnections newConn, Scene scene) | ||
533 | { | ||
534 | Vector3 offset = Vector3.Zero; | ||
535 | offset.X = newConn.PosX - rootConn.PosX; | ||
536 | offset.Y = newConn.PosY - rootConn.PosY; | ||
537 | |||
538 | Vector3 extents = Vector3.Zero; | ||
539 | extents.Y = newConn.YEnd + rootConn.YEnd; | ||
540 | extents.X = rootConn.XEnd; | ||
541 | rootConn.UpdateExtents(extents); | ||
542 | |||
543 | RegionData ConnectedRegion = new RegionData(); | ||
544 | ConnectedRegion.Offset = offset; | ||
545 | ConnectedRegion.RegionId = scene.RegionInfo.originRegionID; | ||
546 | ConnectedRegion.RegionScene = scene; | ||
547 | rootConn.ConnectedRegions.Add(ConnectedRegion); | ||
548 | |||
549 | m_log.DebugFormat( | ||
550 | "[REGION COMBINER MODULE]: Root region {0} is to the south of region {1}, Offset: {2}, Extents: {3}", | ||
551 | rootConn.RegionScene.RegionInfo.RegionName, | ||
552 | newConn.RegionScene.RegionInfo.RegionName, offset, extents); | ||
553 | |||
554 | rootConn.RegionScene.PhysicsScene.Combine(null, Vector3.Zero, extents); | ||
555 | scene.PhysicsScene.Combine(rootConn.RegionScene.PhysicsScene, offset, Vector3.Zero); | ||
556 | |||
557 | // Reset Terrain.. since terrain normally loads first. | ||
558 | //conn.RegionScene.PhysicsScene.SetTerrain(conn.RegionScene.Heightmap.GetFloatsSerialised()); | ||
559 | scene.PhysicsScene.SetTerrain(scene.Heightmap.GetFloatsSerialised()); | ||
560 | //conn.RegionScene.PhysicsScene.SetTerrain(conn.RegionScene.Heightmap.GetFloatsSerialised()); | ||
561 | |||
562 | if (rootConn.ClientEventForwarder != null) | ||
563 | rootConn.ClientEventForwarder.AddSceneToEventForwarding(scene); | ||
564 | |||
565 | return true; | ||
566 | } | ||
567 | |||
568 | private bool DoWorkForOneRegionOverPlusXPlusY(RegionConnections rootConn, RegionConnections newConn, Scene scene) | ||
569 | { | ||
570 | Vector3 offset = Vector3.Zero; | ||
571 | offset.X = newConn.PosX - rootConn.PosX; | ||
572 | offset.Y = newConn.PosY - rootConn.PosY; | ||
573 | |||
574 | Vector3 extents = Vector3.Zero; | ||
575 | |||
576 | // We do not want to inflate the extents for regions strictly to the NE of the root region, since this | ||
577 | // would double count regions strictly to the north and east that have already been added. | ||
578 | // extents.Y = regionConnections.YEnd + conn.YEnd; | ||
579 | // extents.X = regionConnections.XEnd + conn.XEnd; | ||
580 | // conn.UpdateExtents(extents); | ||
581 | |||
582 | extents.Y = rootConn.YEnd; | ||
583 | extents.X = rootConn.XEnd; | ||
584 | |||
585 | RegionData ConnectedRegion = new RegionData(); | ||
586 | ConnectedRegion.Offset = offset; | ||
587 | ConnectedRegion.RegionId = scene.RegionInfo.originRegionID; | ||
588 | ConnectedRegion.RegionScene = scene; | ||
589 | |||
590 | rootConn.ConnectedRegions.Add(ConnectedRegion); | ||
591 | |||
592 | m_log.DebugFormat( | ||
593 | "[REGION COMBINER MODULE]: Region {0} is to the southwest of Scene {1}, Offset: {2}, Extents: {3}", | ||
594 | rootConn.RegionScene.RegionInfo.RegionName, | ||
595 | newConn.RegionScene.RegionInfo.RegionName, offset, extents); | ||
596 | |||
597 | rootConn.RegionScene.PhysicsScene.Combine(null, Vector3.Zero, extents); | ||
598 | scene.PhysicsScene.Combine(rootConn.RegionScene.PhysicsScene, offset, Vector3.Zero); | ||
599 | |||
600 | // Reset Terrain.. since terrain normally loads first. | ||
601 | //conn.RegionScene.PhysicsScene.SetTerrain(conn.RegionScene.Heightmap.GetFloatsSerialised()); | ||
602 | scene.PhysicsScene.SetTerrain(scene.Heightmap.GetFloatsSerialised()); | ||
603 | //conn.RegionScene.PhysicsScene.SetTerrain(conn.RegionScene.Heightmap.GetFloatsSerialised()); | ||
604 | |||
605 | if (rootConn.ClientEventForwarder != null) | ||
606 | rootConn.ClientEventForwarder.AddSceneToEventForwarding(scene); | ||
607 | |||
608 | return true; | ||
609 | |||
610 | //scene.PhysicsScene.Combine(conn.RegionScene.PhysicsScene, offset,extents); | ||
611 | } | ||
612 | */ | ||
613 | |||
614 | private void DoWorkForRootRegion(RegionConnections rootConn, Scene scene) | ||
615 | { | ||
616 | m_log.DebugFormat("[REGION COMBINER MODULE]: Adding root region {0}", scene.RegionInfo.RegionName); | ||
617 | |||
618 | RegionData rdata = new RegionData(); | ||
619 | rdata.Offset = Vector3.Zero; | ||
620 | rdata.RegionId = scene.RegionInfo.originRegionID; | ||
621 | rdata.RegionScene = scene; | ||
622 | // save it's land channel | ||
623 | rootConn.RegionLandChannel = scene.LandChannel; | ||
624 | |||
625 | // Substitue our landchannel | ||
626 | RegionCombinerLargeLandChannel lnd = new RegionCombinerLargeLandChannel(rdata, scene.LandChannel, | ||
627 | rootConn.ConnectedRegions); | ||
628 | |||
629 | scene.LandChannel = lnd; | ||
630 | |||
631 | // Forward the permissions modules of each of the connected regions to the root region | ||
632 | lock (m_regions) | ||
633 | { | ||
634 | foreach (RegionData r in rootConn.ConnectedRegions) | ||
635 | { | ||
636 | ForwardPermissionRequests(rootConn, r.RegionScene); | ||
637 | } | ||
638 | |||
639 | // Create the root region's Client Event Forwarder | ||
640 | rootConn.ClientEventForwarder = new RegionCombinerClientEventForwarder(rootConn); | ||
641 | |||
642 | // Sets up the CoarseLocationUpdate forwarder for this root region | ||
643 | scene.EventManager.OnNewPresence += SetCoarseLocationDelegate; | ||
644 | |||
645 | // Adds this root region to a dictionary of regions that are connectable | ||
646 | m_regions.Add(scene.RegionInfo.originRegionID, rootConn); | ||
647 | } | ||
648 | } | ||
649 | |||
650 | private void SetCoarseLocationDelegate(ScenePresence presence) | ||
651 | { | ||
652 | presence.SetSendCoarseLocationMethod(SendCoarseLocationUpdates); | ||
653 | } | ||
654 | |||
655 | // This delegate was refactored for non-combined regions. | ||
656 | // This combined region version will not use the pre-compiled lists of locations and ids | ||
657 | private void SendCoarseLocationUpdates(UUID sceneId, ScenePresence presence, List<Vector3> coarseLocations, List<UUID> avatarUUIDs) | ||
658 | { | ||
659 | RegionConnections connectiondata = null; | ||
660 | lock (m_regions) | ||
661 | { | ||
662 | if (m_regions.ContainsKey(sceneId)) | ||
663 | connectiondata = m_regions[sceneId]; | ||
664 | else | ||
665 | return; | ||
666 | } | ||
667 | |||
668 | List<Vector3> CoarseLocations = new List<Vector3>(); | ||
669 | List<UUID> AvatarUUIDs = new List<UUID>(); | ||
670 | |||
671 | connectiondata.RegionScene.ForEachRootScenePresence(delegate(ScenePresence sp) | ||
672 | { | ||
673 | if (sp.UUID != presence.UUID) | ||
674 | { | ||
675 | CoarseLocations.Add(sp.AbsolutePosition); | ||
676 | AvatarUUIDs.Add(sp.UUID); | ||
677 | } | ||
678 | }); | ||
679 | |||
680 | DistributeCoarseLocationUpdates(CoarseLocations, AvatarUUIDs, connectiondata, presence); | ||
681 | } | ||
682 | |||
683 | private void DistributeCoarseLocationUpdates(List<Vector3> locations, List<UUID> uuids, | ||
684 | RegionConnections connectiondata, ScenePresence rootPresence) | ||
685 | { | ||
686 | RegionData[] rdata = connectiondata.ConnectedRegions.ToArray(); | ||
687 | //List<IClientAPI> clients = new List<IClientAPI>(); | ||
688 | Dictionary<Vector2, RegionCoarseLocationStruct> updates = new Dictionary<Vector2, RegionCoarseLocationStruct>(); | ||
689 | |||
690 | // Root Region entry | ||
691 | RegionCoarseLocationStruct rootupdatedata = new RegionCoarseLocationStruct(); | ||
692 | rootupdatedata.Locations = new List<Vector3>(); | ||
693 | rootupdatedata.Uuids = new List<UUID>(); | ||
694 | rootupdatedata.Offset = Vector2.Zero; | ||
695 | |||
696 | rootupdatedata.UserAPI = rootPresence.ControllingClient; | ||
697 | |||
698 | if (rootupdatedata.UserAPI != null) | ||
699 | updates.Add(Vector2.Zero, rootupdatedata); | ||
700 | |||
701 | //Each Region needs an entry or we will end up with dead minimap dots | ||
702 | foreach (RegionData regiondata in rdata) | ||
703 | { | ||
704 | Vector2 offset = new Vector2(regiondata.Offset.X, regiondata.Offset.Y); | ||
705 | RegionCoarseLocationStruct updatedata = new RegionCoarseLocationStruct(); | ||
706 | updatedata.Locations = new List<Vector3>(); | ||
707 | updatedata.Uuids = new List<UUID>(); | ||
708 | updatedata.Offset = offset; | ||
709 | |||
710 | if (offset == Vector2.Zero) | ||
711 | updatedata.UserAPI = rootPresence.ControllingClient; | ||
712 | else | ||
713 | updatedata.UserAPI = LocateUsersChildAgentIClientAPI(offset, rootPresence.UUID, rdata); | ||
714 | |||
715 | if (updatedata.UserAPI != null) | ||
716 | updates.Add(offset, updatedata); | ||
717 | } | ||
718 | |||
719 | // go over the locations and assign them to an IClientAPI | ||
720 | for (int i = 0; i < locations.Count; i++) | ||
721 | //{locations[i]/(int) Constants.RegionSize; | ||
722 | { | ||
723 | Vector3 pPosition = new Vector3((int)locations[i].X / (int)Constants.RegionSize, | ||
724 | (int)locations[i].Y / (int)Constants.RegionSize, locations[i].Z); | ||
725 | Vector2 offset = new Vector2(pPosition.X*(int) Constants.RegionSize, | ||
726 | pPosition.Y*(int) Constants.RegionSize); | ||
727 | |||
728 | if (!updates.ContainsKey(offset)) | ||
729 | { | ||
730 | // This shouldn't happen | ||
731 | RegionCoarseLocationStruct updatedata = new RegionCoarseLocationStruct(); | ||
732 | updatedata.Locations = new List<Vector3>(); | ||
733 | updatedata.Uuids = new List<UUID>(); | ||
734 | updatedata.Offset = offset; | ||
735 | |||
736 | if (offset == Vector2.Zero) | ||
737 | updatedata.UserAPI = rootPresence.ControllingClient; | ||
738 | else | ||
739 | updatedata.UserAPI = LocateUsersChildAgentIClientAPI(offset, rootPresence.UUID, rdata); | ||
740 | |||
741 | updates.Add(offset,updatedata); | ||
742 | } | ||
743 | |||
744 | updates[offset].Locations.Add(locations[i]); | ||
745 | updates[offset].Uuids.Add(uuids[i]); | ||
746 | } | ||
747 | |||
748 | // Send out the CoarseLocationupdates from their respective client connection based on where the avatar is | ||
749 | foreach (Vector2 offset in updates.Keys) | ||
750 | { | ||
751 | if (updates[offset].UserAPI != null) | ||
752 | { | ||
753 | updates[offset].UserAPI.SendCoarseLocationUpdate(updates[offset].Uuids,updates[offset].Locations); | ||
754 | } | ||
755 | } | ||
756 | } | ||
757 | |||
758 | /// <summary> | ||
759 | /// Locates a the Client of a particular region in an Array of RegionData based on offset | ||
760 | /// </summary> | ||
761 | /// <param name="offset"></param> | ||
762 | /// <param name="uUID"></param> | ||
763 | /// <param name="rdata"></param> | ||
764 | /// <returns>IClientAPI or null</returns> | ||
765 | private IClientAPI LocateUsersChildAgentIClientAPI(Vector2 offset, UUID uUID, RegionData[] rdata) | ||
766 | { | ||
767 | IClientAPI returnclient = null; | ||
768 | foreach (RegionData r in rdata) | ||
769 | { | ||
770 | if (r.Offset.X == offset.X && r.Offset.Y == offset.Y) | ||
771 | { | ||
772 | return r.RegionScene.SceneGraph.GetControllingClient(uUID); | ||
773 | } | ||
774 | } | ||
775 | |||
776 | return returnclient; | ||
777 | } | ||
778 | |||
779 | public void PostInitialise() | ||
780 | { | ||
781 | } | ||
782 | |||
783 | // /// <summary> | ||
784 | // /// TODO: | ||
785 | // /// </summary> | ||
786 | // /// <param name="rdata"></param> | ||
787 | // public void UnCombineRegion(RegionData rdata) | ||
788 | // { | ||
789 | // lock (m_regions) | ||
790 | // { | ||
791 | // if (m_regions.ContainsKey(rdata.RegionId)) | ||
792 | // { | ||
793 | // // uncombine root region and virtual regions | ||
794 | // } | ||
795 | // else | ||
796 | // { | ||
797 | // foreach (RegionConnections r in m_regions.Values) | ||
798 | // { | ||
799 | // foreach (RegionData rd in r.ConnectedRegions) | ||
800 | // { | ||
801 | // if (rd.RegionId == rdata.RegionId) | ||
802 | // { | ||
803 | // // uncombine virtual region | ||
804 | // } | ||
805 | // } | ||
806 | // } | ||
807 | // } | ||
808 | // } | ||
809 | // } | ||
810 | |||
811 | public void ForwardPermissionRequests(RegionConnections BigRegion, Scene VirtualRegion) | ||
812 | { | ||
813 | if (BigRegion.PermissionModule == null) | ||
814 | BigRegion.PermissionModule = new RegionCombinerPermissionModule(BigRegion.RegionScene); | ||
815 | |||
816 | VirtualRegion.Permissions.OnBypassPermissions += BigRegion.PermissionModule.BypassPermissions; | ||
817 | VirtualRegion.Permissions.OnSetBypassPermissions += BigRegion.PermissionModule.SetBypassPermissions; | ||
818 | VirtualRegion.Permissions.OnPropagatePermissions += BigRegion.PermissionModule.PropagatePermissions; | ||
819 | VirtualRegion.Permissions.OnGenerateClientFlags += BigRegion.PermissionModule.GenerateClientFlags; | ||
820 | VirtualRegion.Permissions.OnAbandonParcel += BigRegion.PermissionModule.CanAbandonParcel; | ||
821 | VirtualRegion.Permissions.OnReclaimParcel += BigRegion.PermissionModule.CanReclaimParcel; | ||
822 | VirtualRegion.Permissions.OnDeedParcel += BigRegion.PermissionModule.CanDeedParcel; | ||
823 | VirtualRegion.Permissions.OnDeedObject += BigRegion.PermissionModule.CanDeedObject; | ||
824 | VirtualRegion.Permissions.OnIsGod += BigRegion.PermissionModule.IsGod; | ||
825 | VirtualRegion.Permissions.OnDuplicateObject += BigRegion.PermissionModule.CanDuplicateObject; | ||
826 | VirtualRegion.Permissions.OnDeleteObject += BigRegion.PermissionModule.CanDeleteObject; //MAYBE FULLY IMPLEMENTED | ||
827 | VirtualRegion.Permissions.OnEditObject += BigRegion.PermissionModule.CanEditObject; //MAYBE FULLY IMPLEMENTED | ||
828 | VirtualRegion.Permissions.OnEditParcelProperties += BigRegion.PermissionModule.CanEditParcelProperties; //MAYBE FULLY IMPLEMENTED | ||
829 | VirtualRegion.Permissions.OnInstantMessage += BigRegion.PermissionModule.CanInstantMessage; | ||
830 | VirtualRegion.Permissions.OnInventoryTransfer += BigRegion.PermissionModule.CanInventoryTransfer; //NOT YET IMPLEMENTED | ||
831 | VirtualRegion.Permissions.OnIssueEstateCommand += BigRegion.PermissionModule.CanIssueEstateCommand; //FULLY IMPLEMENTED | ||
832 | VirtualRegion.Permissions.OnMoveObject += BigRegion.PermissionModule.CanMoveObject; //MAYBE FULLY IMPLEMENTED | ||
833 | VirtualRegion.Permissions.OnObjectEntry += BigRegion.PermissionModule.CanObjectEntry; | ||
834 | VirtualRegion.Permissions.OnReturnObjects += BigRegion.PermissionModule.CanReturnObjects; //NOT YET IMPLEMENTED | ||
835 | VirtualRegion.Permissions.OnRezObject += BigRegion.PermissionModule.CanRezObject; //MAYBE FULLY IMPLEMENTED | ||
836 | VirtualRegion.Permissions.OnRunConsoleCommand += BigRegion.PermissionModule.CanRunConsoleCommand; | ||
837 | VirtualRegion.Permissions.OnRunScript += BigRegion.PermissionModule.CanRunScript; //NOT YET IMPLEMENTED | ||
838 | VirtualRegion.Permissions.OnCompileScript += BigRegion.PermissionModule.CanCompileScript; | ||
839 | VirtualRegion.Permissions.OnSellParcel += BigRegion.PermissionModule.CanSellParcel; | ||
840 | VirtualRegion.Permissions.OnTakeObject += BigRegion.PermissionModule.CanTakeObject; | ||
841 | VirtualRegion.Permissions.OnTakeCopyObject += BigRegion.PermissionModule.CanTakeCopyObject; | ||
842 | VirtualRegion.Permissions.OnTerraformLand += BigRegion.PermissionModule.CanTerraformLand; | ||
843 | VirtualRegion.Permissions.OnLinkObject += BigRegion.PermissionModule.CanLinkObject; //NOT YET IMPLEMENTED | ||
844 | VirtualRegion.Permissions.OnDelinkObject += BigRegion.PermissionModule.CanDelinkObject; //NOT YET IMPLEMENTED | ||
845 | VirtualRegion.Permissions.OnBuyLand += BigRegion.PermissionModule.CanBuyLand; //NOT YET IMPLEMENTED | ||
846 | VirtualRegion.Permissions.OnViewNotecard += BigRegion.PermissionModule.CanViewNotecard; //NOT YET IMPLEMENTED | ||
847 | VirtualRegion.Permissions.OnViewScript += BigRegion.PermissionModule.CanViewScript; //NOT YET IMPLEMENTED | ||
848 | VirtualRegion.Permissions.OnEditNotecard += BigRegion.PermissionModule.CanEditNotecard; //NOT YET IMPLEMENTED | ||
849 | VirtualRegion.Permissions.OnEditScript += BigRegion.PermissionModule.CanEditScript; //NOT YET IMPLEMENTED | ||
850 | VirtualRegion.Permissions.OnCreateObjectInventory += BigRegion.PermissionModule.CanCreateObjectInventory; //NOT IMPLEMENTED HERE | ||
851 | VirtualRegion.Permissions.OnEditObjectInventory += BigRegion.PermissionModule.CanEditObjectInventory;//MAYBE FULLY IMPLEMENTED | ||
852 | VirtualRegion.Permissions.OnCopyObjectInventory += BigRegion.PermissionModule.CanCopyObjectInventory; //NOT YET IMPLEMENTED | ||
853 | VirtualRegion.Permissions.OnDeleteObjectInventory += BigRegion.PermissionModule.CanDeleteObjectInventory; //NOT YET IMPLEMENTED | ||
854 | VirtualRegion.Permissions.OnResetScript += BigRegion.PermissionModule.CanResetScript; | ||
855 | VirtualRegion.Permissions.OnCreateUserInventory += BigRegion.PermissionModule.CanCreateUserInventory; //NOT YET IMPLEMENTED | ||
856 | VirtualRegion.Permissions.OnCopyUserInventory += BigRegion.PermissionModule.CanCopyUserInventory; //NOT YET IMPLEMENTED | ||
857 | VirtualRegion.Permissions.OnEditUserInventory += BigRegion.PermissionModule.CanEditUserInventory; //NOT YET IMPLEMENTED | ||
858 | VirtualRegion.Permissions.OnDeleteUserInventory += BigRegion.PermissionModule.CanDeleteUserInventory; //NOT YET IMPLEMENTED | ||
859 | VirtualRegion.Permissions.OnTeleport += BigRegion.PermissionModule.CanTeleport; //NOT YET IMPLEMENTED | ||
860 | } | ||
861 | |||
862 | #region console commands | ||
863 | |||
864 | public void FixPhantoms(string module, string[] cmdparams) | ||
865 | { | ||
866 | List<Scene> scenes = new List<Scene>(m_startingScenes.Values); | ||
867 | |||
868 | foreach (Scene s in scenes) | ||
869 | { | ||
870 | MainConsole.Instance.OutputFormat("Fixing phantoms for {0}", s.RegionInfo.RegionName); | ||
871 | |||
872 | s.ForEachSOG(so => so.AbsolutePosition = so.AbsolutePosition); | ||
873 | } | ||
874 | } | ||
875 | |||
876 | #endregion | ||
877 | } | ||
878 | } | ||