aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/CoreModules/Framework
diff options
context:
space:
mode:
authorDavid Walter Seikel2016-11-03 21:44:39 +1000
committerDavid Walter Seikel2016-11-03 21:44:39 +1000
commit134f86e8d5c414409631b25b8c6f0ee45fbd8631 (patch)
tree216b89d3fb89acfb81be1e440c25c41ab09fa96d /OpenSim/Region/CoreModules/Framework
parentMore changing to production grid. Double oops. (diff)
downloadopensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.zip
opensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.gz
opensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.bz2
opensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.xz
Initial update to OpenSim 0.8.2.1 source code.
Diffstat (limited to 'OpenSim/Region/CoreModules/Framework')
-rw-r--r--OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs419
-rw-r--r--OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs124
-rw-r--r--OpenSim/Region/CoreModules/Framework/DynamicAttributes/DOExampleModule.cs139
-rw-r--r--OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs2058
-rw-r--r--OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs148
-rw-r--r--OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs290
-rw-r--r--OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs224
-rw-r--r--OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs198
-rw-r--r--OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs359
-rw-r--r--OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/HGAssetMapperTests.cs146
-rw-r--r--OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs7
-rw-r--r--OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs6
-rw-r--r--OpenSim/Region/CoreModules/Framework/Library/LocalInventoryService.cs48
-rw-r--r--OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs46
-rw-r--r--OpenSim/Region/CoreModules/Framework/Search/BasicSearchModule.cs199
-rw-r--r--OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs256
-rw-r--r--OpenSim/Region/CoreModules/Framework/Statistics/Logging/BinaryLoggingModule.cs2
-rwxr-xr-xOpenSim/Region/CoreModules/Framework/Statistics/Logging/LogWriter.cs170
-rw-r--r--OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs19
-rw-r--r--OpenSim/Region/CoreModules/Framework/UserManagement/Tests/HGUserManagementModuleTests.cs75
-rw-r--r--OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs619
21 files changed, 4043 insertions, 1509 deletions
diff --git a/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs b/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs
index 8329af0..817ef85 100644
--- a/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs
@@ -28,6 +28,7 @@
28using System; 28using System;
29using System.Collections; 29using System.Collections;
30using System.Collections.Generic; 30using System.Collections.Generic;
31using System.Linq;
31using System.Reflection; 32using System.Reflection;
32using System.Text; 33using System.Text;
33using log4net; 34using log4net;
@@ -37,6 +38,7 @@ using OpenMetaverse;
37using OpenSim.Framework; 38using OpenSim.Framework;
38using OpenSim.Framework.Console; 39using OpenSim.Framework.Console;
39using OpenSim.Framework.Servers; 40using OpenSim.Framework.Servers;
41using OpenSim.Framework.Servers.HttpServer;
40using OpenSim.Region.Framework.Interfaces; 42using OpenSim.Region.Framework.Interfaces;
41using OpenSim.Region.Framework.Scenes; 43using OpenSim.Region.Framework.Scenes;
42using Caps=OpenSim.Framework.Capabilities.Caps; 44using Caps=OpenSim.Framework.Capabilities.Caps;
@@ -57,8 +59,9 @@ namespace OpenSim.Region.CoreModules.Framework
57 /// </summary> 59 /// </summary>
58 protected Dictionary<UUID, Caps> m_capsObjects = new Dictionary<UUID, Caps>(); 60 protected Dictionary<UUID, Caps> m_capsObjects = new Dictionary<UUID, Caps>();
59 61
60 protected Dictionary<UUID, string> capsPaths = new Dictionary<UUID, string>(); 62 protected Dictionary<UUID, string> m_capsPaths = new Dictionary<UUID, string>();
61 protected Dictionary<UUID, Dictionary<ulong, string>> childrenSeeds 63
64 protected Dictionary<UUID, Dictionary<ulong, string>> m_childrenSeeds
62 = new Dictionary<UUID, Dictionary<ulong, string>>(); 65 = new Dictionary<UUID, Dictionary<ulong, string>>();
63 66
64 public void Initialise(IConfigSource source) 67 public void Initialise(IConfigSource source)
@@ -70,9 +73,24 @@ namespace OpenSim.Region.CoreModules.Framework
70 m_scene = scene; 73 m_scene = scene;
71 m_scene.RegisterModuleInterface<ICapabilitiesModule>(this); 74 m_scene.RegisterModuleInterface<ICapabilitiesModule>(this);
72 75
73 MainConsole.Instance.Commands.AddCommand("Comms", false, "show caps", 76 MainConsole.Instance.Commands.AddCommand(
74 "show caps", 77 "Comms", false, "show caps list",
75 "Shows all registered capabilities for users", HandleShowCapsCommand); 78 "show caps list",
79 "Shows list of registered capabilities for users.", HandleShowCapsListCommand);
80
81 MainConsole.Instance.Commands.AddCommand(
82 "Comms", false, "show caps stats by user",
83 "show caps stats by user [<first-name> <last-name>]",
84 "Shows statistics on capabilities use by user.",
85 "If a user name is given, then prints a detailed breakdown of caps use ordered by number of requests received.",
86 HandleShowCapsStatsByUserCommand);
87
88 MainConsole.Instance.Commands.AddCommand(
89 "Comms", false, "show caps stats by cap",
90 "show caps stats by cap [<cap-name>]",
91 "Shows statistics on capabilities use by capability.",
92 "If a capability name is given, then prints a detailed breakdown of use by each user.",
93 HandleShowCapsStatsByCapCommand);
76 } 94 }
77 95
78 public void RegionLoaded(Scene scene) 96 public void RegionLoaded(Scene scene)
@@ -105,35 +123,43 @@ namespace OpenSim.Region.CoreModules.Framework
105 if (m_scene.RegionInfo.EstateSettings.IsBanned(agentId)) 123 if (m_scene.RegionInfo.EstateSettings.IsBanned(agentId))
106 return; 124 return;
107 125
126 Caps caps;
108 String capsObjectPath = GetCapsPath(agentId); 127 String capsObjectPath = GetCapsPath(agentId);
109 128
110 if (m_capsObjects.ContainsKey(agentId)) 129 lock (m_capsObjects)
111 { 130 {
112 Caps oldCaps = m_capsObjects[agentId]; 131 if (m_capsObjects.ContainsKey(agentId))
113 132 {
114 m_log.DebugFormat( 133 Caps oldCaps = m_capsObjects[agentId];
115 "[CAPS]: Recreating caps for agent {0}. Old caps path {1}, new caps path {2}. ", 134
116 agentId, oldCaps.CapsObjectPath, capsObjectPath); 135 //m_log.WarnFormat(
117 // This should not happen. The caller code is confused. We need to fix that. 136 // "[CAPS]: Recreating caps for agent {0} in region {1}. Old caps path {2}, new caps path {3}. ",
118 // CAPs can never be reregistered, or the client will be confused. 137 // agentId, m_scene.RegionInfo.RegionName, oldCaps.CapsObjectPath, capsObjectPath);
119 // Hence this return here. 138 }
120 //return;
121 }
122 139
123 Caps caps = new Caps(MainServer.Instance, m_scene.RegionInfo.ExternalHostName, 140// m_log.DebugFormat(
124 (MainServer.Instance == null) ? 0: MainServer.Instance.Port, 141// "[CAPS]: Adding capabilities for agent {0} in {1} with path {2}",
125 capsObjectPath, agentId, m_scene.RegionInfo.RegionName); 142// agentId, m_scene.RegionInfo.RegionName, capsObjectPath);
126 143
127 m_capsObjects[agentId] = caps; 144 caps = new Caps(MainServer.Instance, m_scene.RegionInfo.ExternalHostName,
145 (MainServer.Instance == null) ? 0: MainServer.Instance.Port,
146 capsObjectPath, agentId, m_scene.RegionInfo.RegionName);
147
148 m_capsObjects[agentId] = caps;
149 }
128 150
129 m_scene.EventManager.TriggerOnRegisterCaps(agentId, caps); 151 m_scene.EventManager.TriggerOnRegisterCaps(agentId, caps);
130 } 152 }
131 153
132 public void RemoveCaps(UUID agentId) 154 public void RemoveCaps(UUID agentId)
133 { 155 {
134 if (childrenSeeds.ContainsKey(agentId)) 156 m_log.DebugFormat("[CAPS]: Remove caps for agent {0} in region {1}", agentId, m_scene.RegionInfo.RegionName);
157 lock (m_childrenSeeds)
135 { 158 {
136 childrenSeeds.Remove(agentId); 159 if (m_childrenSeeds.ContainsKey(agentId))
160 {
161 m_childrenSeeds.Remove(agentId);
162 }
137 } 163 }
138 164
139 lock (m_capsObjects) 165 lock (m_capsObjects)
@@ -168,16 +194,22 @@ namespace OpenSim.Region.CoreModules.Framework
168 194
169 public void SetAgentCapsSeeds(AgentCircuitData agent) 195 public void SetAgentCapsSeeds(AgentCircuitData agent)
170 { 196 {
171 capsPaths[agent.AgentID] = agent.CapsPath; 197 lock (m_capsPaths)
172 childrenSeeds[agent.AgentID] 198 m_capsPaths[agent.AgentID] = agent.CapsPath;
173 = ((agent.ChildrenCapSeeds == null) ? new Dictionary<ulong, string>() : agent.ChildrenCapSeeds); 199
200 lock (m_childrenSeeds)
201 m_childrenSeeds[agent.AgentID]
202 = ((agent.ChildrenCapSeeds == null) ? new Dictionary<ulong, string>() : agent.ChildrenCapSeeds);
174 } 203 }
175 204
176 public string GetCapsPath(UUID agentId) 205 public string GetCapsPath(UUID agentId)
177 { 206 {
178 if (capsPaths.ContainsKey(agentId)) 207 lock (m_capsPaths)
179 { 208 {
180 return capsPaths[agentId]; 209 if (m_capsPaths.ContainsKey(agentId))
210 {
211 return m_capsPaths[agentId];
212 }
181 } 213 }
182 214
183 return null; 215 return null;
@@ -186,17 +218,24 @@ namespace OpenSim.Region.CoreModules.Framework
186 public Dictionary<ulong, string> GetChildrenSeeds(UUID agentID) 218 public Dictionary<ulong, string> GetChildrenSeeds(UUID agentID)
187 { 219 {
188 Dictionary<ulong, string> seeds = null; 220 Dictionary<ulong, string> seeds = null;
189 if (childrenSeeds.TryGetValue(agentID, out seeds)) 221
190 return seeds; 222 lock (m_childrenSeeds)
223 if (m_childrenSeeds.TryGetValue(agentID, out seeds))
224 return seeds;
225
191 return new Dictionary<ulong, string>(); 226 return new Dictionary<ulong, string>();
192 } 227 }
193 228
194 public void DropChildSeed(UUID agentID, ulong handle) 229 public void DropChildSeed(UUID agentID, ulong handle)
195 { 230 {
196 Dictionary<ulong, string> seeds; 231 Dictionary<ulong, string> seeds;
197 if (childrenSeeds.TryGetValue(agentID, out seeds)) 232
233 lock (m_childrenSeeds)
198 { 234 {
199 seeds.Remove(handle); 235 if (m_childrenSeeds.TryGetValue(agentID, out seeds))
236 {
237 seeds.Remove(handle);
238 }
200 } 239 }
201 } 240 }
202 241
@@ -204,53 +243,327 @@ namespace OpenSim.Region.CoreModules.Framework
204 { 243 {
205 Dictionary<ulong, string> seeds; 244 Dictionary<ulong, string> seeds;
206 string returnval; 245 string returnval;
207 if (childrenSeeds.TryGetValue(agentID, out seeds)) 246
247 lock (m_childrenSeeds)
208 { 248 {
209 if (seeds.TryGetValue(handle, out returnval)) 249 if (m_childrenSeeds.TryGetValue(agentID, out seeds))
210 return returnval; 250 {
251 if (seeds.TryGetValue(handle, out returnval))
252 return returnval;
253 }
211 } 254 }
255
212 return null; 256 return null;
213 } 257 }
214 258
215 public void SetChildrenSeed(UUID agentID, Dictionary<ulong, string> seeds) 259 public void SetChildrenSeed(UUID agentID, Dictionary<ulong, string> seeds)
216 { 260 {
217 //m_log.DebugFormat(" !!! Setting child seeds in {0} to {1}", m_scene.RegionInfo.RegionName, seeds.Count); 261 //m_log.DebugFormat(" !!! Setting child seeds in {0} to {1}", m_scene.RegionInfo.RegionName, seeds.Count);
218 childrenSeeds[agentID] = seeds; 262
263 lock (m_childrenSeeds)
264 m_childrenSeeds[agentID] = seeds;
219 } 265 }
220 266
221 public void DumpChildrenSeeds(UUID agentID) 267 public void DumpChildrenSeeds(UUID agentID)
222 { 268 {
223 m_log.Info("================ ChildrenSeed "+m_scene.RegionInfo.RegionName+" ================"); 269 m_log.Info("================ ChildrenSeed "+m_scene.RegionInfo.RegionName+" ================");
224 foreach (KeyValuePair<ulong, string> kvp in childrenSeeds[agentID]) 270
271 lock (m_childrenSeeds)
272 {
273 foreach (KeyValuePair<ulong, string> kvp in m_childrenSeeds[agentID])
274 {
275 uint x, y;
276 Util.RegionHandleToRegionLoc(kvp.Key, out x, out y);
277 m_log.Info(" >> "+x+", "+y+": "+kvp.Value);
278 }
279 }
280 }
281
282 private void HandleShowCapsListCommand(string module, string[] cmdParams)
283 {
284 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
285 return;
286
287 StringBuilder capsReport = new StringBuilder();
288 capsReport.AppendFormat("Region {0}:\n", m_scene.RegionInfo.RegionName);
289
290 lock (m_capsObjects)
225 { 291 {
226 uint x, y; 292 foreach (KeyValuePair<UUID, Caps> kvp in m_capsObjects)
227 Utils.LongToUInts(kvp.Key, out x, out y); 293 {
228 x = x / Constants.RegionSize; 294 capsReport.AppendFormat("** User {0}:\n", kvp.Key);
229 y = y / Constants.RegionSize; 295 Caps caps = kvp.Value;
230 m_log.Info(" >> "+x+", "+y+": "+kvp.Value); 296
297 for (IDictionaryEnumerator kvp2 = caps.CapsHandlers.GetCapsDetails(false, null).GetEnumerator(); kvp2.MoveNext(); )
298 {
299 Uri uri = new Uri(kvp2.Value.ToString());
300 capsReport.AppendFormat(m_showCapsCommandFormat, kvp2.Key, uri.PathAndQuery);
301 }
302
303 foreach (KeyValuePair<string, PollServiceEventArgs> kvp2 in caps.GetPollHandlers())
304 capsReport.AppendFormat(m_showCapsCommandFormat, kvp2.Key, kvp2.Value.Url);
305
306 foreach (KeyValuePair<string, string> kvp3 in caps.ExternalCapsHandlers)
307 capsReport.AppendFormat(m_showCapsCommandFormat, kvp3.Key, kvp3.Value);
308 }
231 } 309 }
310
311 MainConsole.Instance.Output(capsReport.ToString());
232 } 312 }
233 313
234 private void HandleShowCapsCommand(string module, string[] cmdparams) 314 private void HandleShowCapsStatsByCapCommand(string module, string[] cmdParams)
235 { 315 {
236 StringBuilder caps = new StringBuilder(); 316 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
237 caps.AppendFormat("Region {0}:\n", m_scene.RegionInfo.RegionName); 317 return;
318
319 if (cmdParams.Length != 5 && cmdParams.Length != 6)
320 {
321 MainConsole.Instance.Output("Usage: show caps stats by cap [<cap-name>]");
322 return;
323 }
324
325 StringBuilder sb = new StringBuilder();
326 sb.AppendFormat("Region {0}:\n", m_scene.Name);
327
328 if (cmdParams.Length == 5)
329 {
330 BuildSummaryStatsByCapReport(sb);
331 }
332 else if (cmdParams.Length == 6)
333 {
334 BuildDetailedStatsByCapReport(sb, cmdParams[5]);
335 }
336
337 MainConsole.Instance.Output(sb.ToString());
338 }
339
340 private void BuildDetailedStatsByCapReport(StringBuilder sb, string capName)
341 {
342 sb.AppendFormat("Capability name {0}\n", capName);
343
344 ConsoleDisplayTable cdt = new ConsoleDisplayTable();
345 cdt.AddColumn("User Name", 34);
346 cdt.AddColumn("Req Received", 12);
347 cdt.AddColumn("Req Handled", 12);
348 cdt.Indent = 2;
349
350 Dictionary<string, int> receivedStats = new Dictionary<string, int>();
351 Dictionary<string, int> handledStats = new Dictionary<string, int>();
352
353 m_scene.ForEachScenePresence(
354 sp =>
355 {
356 Caps caps = m_scene.CapsModule.GetCapsForUser(sp.UUID);
238 357
239 foreach (KeyValuePair<UUID, Caps> kvp in m_capsObjects) 358 if (caps == null)
359 return;
360
361 Dictionary<string, IRequestHandler> capsHandlers = caps.CapsHandlers.GetCapsHandlers();
362
363 IRequestHandler reqHandler;
364 if (capsHandlers.TryGetValue(capName, out reqHandler))
365 {
366 receivedStats[sp.Name] = reqHandler.RequestsReceived;
367 handledStats[sp.Name] = reqHandler.RequestsHandled;
368 }
369 else
370 {
371 PollServiceEventArgs pollHandler = null;
372 if (caps.TryGetPollHandler(capName, out pollHandler))
373 {
374 receivedStats[sp.Name] = pollHandler.RequestsReceived;
375 handledStats[sp.Name] = pollHandler.RequestsHandled;
376 }
377 }
378 }
379 );
380
381 foreach (KeyValuePair<string, int> kvp in receivedStats.OrderByDescending(kp => kp.Value))
240 { 382 {
241 caps.AppendFormat("** User {0}:\n", kvp.Key); 383 cdt.AddRow(kvp.Key, kvp.Value, handledStats[kvp.Key]);
384 }
385
386 sb.Append(cdt.ToString());
387 }
388
389 private void BuildSummaryStatsByCapReport(StringBuilder sb)
390 {
391 ConsoleDisplayTable cdt = new ConsoleDisplayTable();
392 cdt.AddColumn("Name", 34);
393 cdt.AddColumn("Req Received", 12);
394 cdt.AddColumn("Req Handled", 12);
395 cdt.Indent = 2;
396
397 Dictionary<string, int> receivedStats = new Dictionary<string, int>();
398 Dictionary<string, int> handledStats = new Dictionary<string, int>();
242 399
243 for (IDictionaryEnumerator kvp2 = kvp.Value.CapsHandlers.GetCapsDetails(false).GetEnumerator(); kvp2.MoveNext(); ) 400 m_scene.ForEachScenePresence(
401 sp =>
244 { 402 {
245 Uri uri = new Uri(kvp2.Value.ToString()); 403 Caps caps = m_scene.CapsModule.GetCapsForUser(sp.UUID);
246 caps.AppendFormat(m_showCapsCommandFormat, kvp2.Key, uri.PathAndQuery); 404
405 if (caps == null)
406 return;
407
408 foreach (IRequestHandler reqHandler in caps.CapsHandlers.GetCapsHandlers().Values)
409 {
410 string reqName = reqHandler.Name ?? "";
411
412 if (!receivedStats.ContainsKey(reqName))
413 {
414 receivedStats[reqName] = reqHandler.RequestsReceived;
415 handledStats[reqName] = reqHandler.RequestsHandled;
416 }
417 else
418 {
419 receivedStats[reqName] += reqHandler.RequestsReceived;
420 handledStats[reqName] += reqHandler.RequestsHandled;
421 }
422 }
423
424 foreach (KeyValuePair<string, PollServiceEventArgs> kvp in caps.GetPollHandlers())
425 {
426 string name = kvp.Key;
427 PollServiceEventArgs pollHandler = kvp.Value;
428
429 if (!receivedStats.ContainsKey(name))
430 {
431 receivedStats[name] = pollHandler.RequestsReceived;
432 handledStats[name] = pollHandler.RequestsHandled;
433 }
434 else
435 {
436 receivedStats[name] += pollHandler.RequestsReceived;
437 handledStats[name] += pollHandler.RequestsHandled;
438 }
439 }
247 } 440 }
441 );
442
443 foreach (KeyValuePair<string, int> kvp in receivedStats.OrderByDescending(kp => kp.Value))
444 cdt.AddRow(kvp.Key, kvp.Value, handledStats[kvp.Key]);
445
446 sb.Append(cdt.ToString());
447 }
448
449 private void HandleShowCapsStatsByUserCommand(string module, string[] cmdParams)
450 {
451 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
452 return;
453
454 if (cmdParams.Length != 5 && cmdParams.Length != 7)
455 {
456 MainConsole.Instance.Output("Usage: show caps stats by user [<first-name> <last-name>]");
457 return;
458 }
459
460 StringBuilder sb = new StringBuilder();
461 sb.AppendFormat("Region {0}:\n", m_scene.Name);
462
463 if (cmdParams.Length == 5)
464 {
465 BuildSummaryStatsByUserReport(sb);
466 }
467 else if (cmdParams.Length == 7)
468 {
469 string firstName = cmdParams[5];
470 string lastName = cmdParams[6];
471
472 ScenePresence sp = m_scene.GetScenePresence(firstName, lastName);
473
474 if (sp == null)
475 return;
248 476
249 foreach (KeyValuePair<string, string> kvp3 in kvp.Value.ExternalCapsHandlers) 477 BuildDetailedStatsByUserReport(sb, sp);
250 caps.AppendFormat(m_showCapsCommandFormat, kvp3.Key, kvp3.Value);
251 } 478 }
252 479
253 MainConsole.Instance.Output(caps.ToString()); 480 MainConsole.Instance.Output(sb.ToString());
481 }
482
483 private void BuildDetailedStatsByUserReport(StringBuilder sb, ScenePresence sp)
484 {
485 sb.AppendFormat("Avatar name {0}, type {1}\n", sp.Name, sp.IsChildAgent ? "child" : "root");
486
487 ConsoleDisplayTable cdt = new ConsoleDisplayTable();
488 cdt.AddColumn("Cap Name", 34);
489 cdt.AddColumn("Req Received", 12);
490 cdt.AddColumn("Req Handled", 12);
491 cdt.Indent = 2;
492
493 Caps caps = m_scene.CapsModule.GetCapsForUser(sp.UUID);
494
495 if (caps == null)
496 return;
497
498 List<CapTableRow> capRows = new List<CapTableRow>();
499
500 foreach (IRequestHandler reqHandler in caps.CapsHandlers.GetCapsHandlers().Values)
501 capRows.Add(new CapTableRow(reqHandler.Name, reqHandler.RequestsReceived, reqHandler.RequestsHandled));
502
503 foreach (KeyValuePair<string, PollServiceEventArgs> kvp in caps.GetPollHandlers())
504 capRows.Add(new CapTableRow(kvp.Key, kvp.Value.RequestsReceived, kvp.Value.RequestsHandled));
505
506 foreach (CapTableRow ctr in capRows.OrderByDescending(ctr => ctr.RequestsReceived))
507 cdt.AddRow(ctr.Name, ctr.RequestsReceived, ctr.RequestsHandled);
508
509 sb.Append(cdt.ToString());
510 }
511
512 private void BuildSummaryStatsByUserReport(StringBuilder sb)
513 {
514 ConsoleDisplayTable cdt = new ConsoleDisplayTable();
515 cdt.AddColumn("Name", 32);
516 cdt.AddColumn("Type", 5);
517 cdt.AddColumn("Req Received", 12);
518 cdt.AddColumn("Req Handled", 12);
519 cdt.Indent = 2;
520
521 m_scene.ForEachScenePresence(
522 sp =>
523 {
524 Caps caps = m_scene.CapsModule.GetCapsForUser(sp.UUID);
525
526 if (caps == null)
527 return;
528
529 Dictionary<string, IRequestHandler> capsHandlers = caps.CapsHandlers.GetCapsHandlers();
530
531 int totalRequestsReceived = 0;
532 int totalRequestsHandled = 0;
533
534 foreach (IRequestHandler reqHandler in capsHandlers.Values)
535 {
536 totalRequestsReceived += reqHandler.RequestsReceived;
537 totalRequestsHandled += reqHandler.RequestsHandled;
538 }
539
540 Dictionary<string, PollServiceEventArgs> capsPollHandlers = caps.GetPollHandlers();
541
542 foreach (PollServiceEventArgs handler in capsPollHandlers.Values)
543 {
544 totalRequestsReceived += handler.RequestsReceived;
545 totalRequestsHandled += handler.RequestsHandled;
546 }
547
548 cdt.AddRow(sp.Name, sp.IsChildAgent ? "child" : "root", totalRequestsReceived, totalRequestsHandled);
549 }
550 );
551
552 sb.Append(cdt.ToString());
553 }
554
555 private class CapTableRow
556 {
557 public string Name { get; set; }
558 public int RequestsReceived { get; set; }
559 public int RequestsHandled { get; set; }
560
561 public CapTableRow(string name, int requestsReceived, int requestsHandled)
562 {
563 Name = name;
564 RequestsReceived = requestsReceived;
565 RequestsHandled = requestsHandled;
566 }
254 } 567 }
255 } 568 }
256} 569} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs b/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs
new file mode 100644
index 0000000..0c632b1
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs
@@ -0,0 +1,124 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using log4net;
32using Mono.Addins;
33using Nini.Config;
34using OpenMetaverse;
35using OpenMetaverse.Packets;
36using OpenMetaverse.StructuredData;
37using OpenSim.Framework;
38using OpenSim.Region.Framework;
39using OpenSim.Region.Framework.Interfaces;
40using OpenSim.Region.Framework.Scenes;
41
42namespace OpenSim.Region.CoreModules.Framework.DynamicAttributes.DAExampleModule
43{
44 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DAExampleModule")]
45 public class DAExampleModule : INonSharedRegionModule
46 {
47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48
49 private readonly bool ENABLED = false; // enable for testing
50
51 public const string Namespace = "Example";
52 public const string StoreName = "DA";
53
54 protected Scene m_scene;
55 protected IDialogModule m_dialogMod;
56
57 public string Name { get { return "DAExample Module"; } }
58 public Type ReplaceableInterface { get { return null; } }
59
60 public void Initialise(IConfigSource source) {}
61
62 public void AddRegion(Scene scene)
63 {
64 if (ENABLED)
65 {
66 m_scene = scene;
67 m_scene.EventManager.OnSceneGroupMove += OnSceneGroupMove;
68 m_dialogMod = m_scene.RequestModuleInterface<IDialogModule>();
69
70 m_log.DebugFormat("[DA EXAMPLE MODULE]: Added region {0}", m_scene.Name);
71 }
72 }
73
74 public void RemoveRegion(Scene scene)
75 {
76 if (ENABLED)
77 {
78 m_scene.EventManager.OnSceneGroupMove -= OnSceneGroupMove;
79 }
80 }
81
82 public void RegionLoaded(Scene scene) {}
83
84 public void Close()
85 {
86 RemoveRegion(m_scene);
87 }
88
89 protected bool OnSceneGroupMove(UUID groupId, Vector3 delta)
90 {
91 OSDMap attrs = null;
92 SceneObjectPart sop = m_scene.GetSceneObjectPart(groupId);
93
94 if (sop == null)
95 return true;
96
97 if (!sop.DynAttrs.TryGetStore(Namespace, StoreName, out attrs))
98 attrs = new OSDMap();
99
100 OSDInteger newValue;
101
102 // We have to lock on the entire dynamic attributes map to avoid race conditions with serialization code.
103 lock (sop.DynAttrs)
104 {
105 if (!attrs.ContainsKey("moves"))
106 newValue = new OSDInteger(1);
107 else
108 newValue = new OSDInteger(attrs["moves"].AsInteger() + 1);
109
110 attrs["moves"] = newValue;
111
112 sop.DynAttrs.SetStore(Namespace, StoreName, attrs);
113 }
114
115 sop.ParentGroup.HasGroupChanged = true;
116
117 string msg = string.Format("{0} {1} moved {2} times", sop.Name, sop.UUID, newValue);
118 m_log.DebugFormat("[DA EXAMPLE MODULE]: {0}", msg);
119 m_dialogMod.SendGeneralAlert(msg);
120
121 return true;
122 }
123 }
124} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DOExampleModule.cs b/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DOExampleModule.cs
new file mode 100644
index 0000000..166a994
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DOExampleModule.cs
@@ -0,0 +1,139 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using log4net;
32using Mono.Addins;
33using Nini.Config;
34using OpenMetaverse;
35using OpenMetaverse.Packets;
36using OpenMetaverse.StructuredData;
37using OpenSim.Framework;
38using OpenSim.Region.Framework;
39using OpenSim.Region.CoreModules.Framework.DynamicAttributes.DAExampleModule;
40using OpenSim.Region.Framework.Interfaces;
41using OpenSim.Region.Framework.Scenes;
42
43namespace OpenSim.Region.Framework.DynamicAttributes.DOExampleModule
44{
45 /// <summary>
46 /// Example module for experimenting with and demonstrating dynamic object ideas.
47 /// </summary>
48 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DOExampleModule")]
49 public class DOExampleModule : INonSharedRegionModule
50 {
51 public class MyObject
52 {
53 public int Moves { get; set; }
54
55 public MyObject(int moves)
56 {
57 Moves = moves;
58 }
59 }
60
61 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
62
63 private static readonly bool ENABLED = false; // enable for testing
64
65 private Scene m_scene;
66 private IDialogModule m_dialogMod;
67
68 public string Name { get { return "DO"; } }
69 public Type ReplaceableInterface { get { return null; } }
70
71 public void Initialise(IConfigSource source) {}
72
73 public void AddRegion(Scene scene)
74 {
75 if (ENABLED)
76 {
77 m_scene = scene;
78 m_scene.EventManager.OnObjectAddedToScene += OnObjectAddedToScene;
79 m_scene.EventManager.OnSceneGroupMove += OnSceneGroupMove;
80 m_dialogMod = m_scene.RequestModuleInterface<IDialogModule>();
81 }
82 }
83
84 public void RemoveRegion(Scene scene)
85 {
86 if (ENABLED)
87 {
88 m_scene.EventManager.OnSceneGroupMove -= OnSceneGroupMove;
89 }
90 }
91
92 public void RegionLoaded(Scene scene) {}
93
94 public void Close()
95 {
96 RemoveRegion(m_scene);
97 }
98
99 private void OnObjectAddedToScene(SceneObjectGroup so)
100 {
101 SceneObjectPart rootPart = so.RootPart;
102
103 OSDMap attrs;
104
105 int movesSoFar = 0;
106
107// Console.WriteLine("Here for {0}", so.Name);
108
109 if (rootPart.DynAttrs.TryGetStore(DAExampleModule.Namespace, DAExampleModule.StoreName, out attrs))
110 {
111 movesSoFar = attrs["moves"].AsInteger();
112
113 m_log.DebugFormat(
114 "[DO EXAMPLE MODULE]: Found saved moves {0} for {1} in {2}", movesSoFar, so.Name, m_scene.Name);
115 }
116
117 rootPart.DynObjs.Add(DAExampleModule.Namespace, Name, new MyObject(movesSoFar));
118 }
119
120 private bool OnSceneGroupMove(UUID groupId, Vector3 delta)
121 {
122 SceneObjectGroup so = m_scene.GetSceneObjectGroup(groupId);
123
124 if (so == null)
125 return true;
126
127 object rawObj = so.RootPart.DynObjs.Get(Name);
128
129 if (rawObj != null)
130 {
131 MyObject myObj = (MyObject)rawObj;
132
133 m_dialogMod.SendGeneralAlert(string.Format("{0} {1} moved {2} times", so.Name, so.UUID, ++myObj.Moves));
134 }
135
136 return true;
137 }
138 }
139} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
index c43edd2..a2417c4 100644
--- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
@@ -33,9 +33,10 @@ using System.Threading;
33using OpenSim.Framework; 33using OpenSim.Framework;
34using OpenSim.Framework.Capabilities; 34using OpenSim.Framework.Capabilities;
35using OpenSim.Framework.Client; 35using OpenSim.Framework.Client;
36using OpenSim.Framework.Monitoring;
36using OpenSim.Region.Framework.Interfaces; 37using OpenSim.Region.Framework.Interfaces;
37using OpenSim.Region.Framework.Scenes; 38using OpenSim.Region.Framework.Scenes;
38using OpenSim.Region.Physics.Manager; 39using OpenSim.Region.PhysicsModules.SharedBase;
39using OpenSim.Services.Interfaces; 40using OpenSim.Services.Interfaces;
40 41
41using GridRegion = OpenSim.Services.Interfaces.GridRegion; 42using GridRegion = OpenSim.Services.Interfaces.GridRegion;
@@ -51,15 +52,61 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
51 public class EntityTransferModule : INonSharedRegionModule, IEntityTransferModule 52 public class EntityTransferModule : INonSharedRegionModule, IEntityTransferModule
52 { 53 {
53 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 54 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
55 private static readonly string LogHeader = "[ENTITY TRANSFER MODULE]";
54 56
57 public const int DefaultMaxTransferDistance = 4095;
55 public const bool WaitForAgentArrivedAtDestinationDefault = true; 58 public const bool WaitForAgentArrivedAtDestinationDefault = true;
56 59
57 /// <summary> 60 /// <summary>
61 /// The maximum distance, in standard region units (256m) that an agent is allowed to transfer.
62 /// </summary>
63 public int MaxTransferDistance { get; set; }
64
65 /// <summary>
58 /// If true then on a teleport, the source region waits for a callback from the destination region. If 66 /// If true then on a teleport, the source region waits for a callback from the destination region. If
59 /// a callback fails to arrive within a set time then the user is pulled back into the source region. 67 /// a callback fails to arrive within a set time then the user is pulled back into the source region.
60 /// </summary> 68 /// </summary>
61 public bool WaitForAgentArrivedAtDestination { get; set; } 69 public bool WaitForAgentArrivedAtDestination { get; set; }
62 70
71 /// <summary>
72 /// If true then we ask the viewer to disable teleport cancellation and ignore teleport requests.
73 /// </summary>
74 /// <remarks>
75 /// This is useful in situations where teleport is very likely to always succeed and we want to avoid a
76 /// situation where avatars can be come 'stuck' due to a failed teleport cancellation. Unfortunately, the
77 /// nature of the teleport protocol makes it extremely difficult (maybe impossible) to make teleport
78 /// cancellation consistently suceed.
79 /// </remarks>
80 public bool DisableInterRegionTeleportCancellation { get; set; }
81
82 /// <summary>
83 /// Number of times inter-region teleport was attempted.
84 /// </summary>
85 private Stat m_interRegionTeleportAttempts;
86
87 /// <summary>
88 /// Number of times inter-region teleport was aborted (due to simultaneous client logout).
89 /// </summary>
90 private Stat m_interRegionTeleportAborts;
91
92 /// <summary>
93 /// Number of times inter-region teleport was successfully cancelled by the client.
94 /// </summary>
95 private Stat m_interRegionTeleportCancels;
96
97 /// <summary>
98 /// Number of times inter-region teleport failed due to server/client/network problems (e.g. viewer failed to
99 /// connect with destination region).
100 /// </summary>
101 /// <remarks>
102 /// This is not necessarily a problem for this simulator - in open-grid/hg conditions, viewer connectivity to
103 /// destination simulator is unknown.
104 /// </remarks>
105 private Stat m_interRegionTeleportFailures;
106
107 protected string m_ThisHomeURI;
108 protected string m_GatekeeperURI;
109
63 protected bool m_Enabled = false; 110 protected bool m_Enabled = false;
64 111
65 public Scene Scene { get; private set; } 112 public Scene Scene { get; private set; }
@@ -70,10 +117,56 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
70 /// </summary> 117 /// </summary>
71 private EntityTransferStateMachine m_entityTransferStateMachine; 118 private EntityTransferStateMachine m_entityTransferStateMachine;
72 119
73 private ExpiringCache<UUID, ExpiringCache<ulong, DateTime>> m_bannedRegions = 120 // For performance, we keed a cached of banned regions so we don't keep going
74 new ExpiringCache<UUID, ExpiringCache<ulong, DateTime>>(); 121 // to the grid service.
122 private class BannedRegionCache
123 {
124 private ExpiringCache<UUID, ExpiringCache<ulong, DateTime>> m_bannedRegions =
125 new ExpiringCache<UUID, ExpiringCache<ulong, DateTime>>();
126 ExpiringCache<ulong, DateTime> m_idCache;
127 DateTime m_banUntil;
128 public BannedRegionCache()
129 {
130 }
131 // Return 'true' if there is a valid ban entry for this agent in this region
132 public bool IfBanned(ulong pRegionHandle, UUID pAgentID)
133 {
134 bool ret = false;
135 if (m_bannedRegions.TryGetValue(pAgentID, out m_idCache))
136 {
137 if (m_idCache.TryGetValue(pRegionHandle, out m_banUntil))
138 {
139 if (DateTime.Now < m_banUntil)
140 {
141 ret = true;
142 }
143 }
144 }
145 return ret;
146 }
147 // Add this agent in this region as a banned person
148 public void Add(ulong pRegionHandle, UUID pAgentID)
149 {
150 if (!m_bannedRegions.TryGetValue(pAgentID, out m_idCache))
151 {
152 m_idCache = new ExpiringCache<ulong, DateTime>();
153 m_bannedRegions.Add(pAgentID, m_idCache, TimeSpan.FromSeconds(45));
154 }
155 m_idCache.Add(pRegionHandle, DateTime.Now + TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(15));
156 }
157 // Remove the agent from the region's banned list
158 public void Remove(ulong pRegionHandle, UUID pAgentID)
159 {
160 if (m_bannedRegions.TryGetValue(pAgentID, out m_idCache))
161 {
162 m_idCache.Remove(pRegionHandle);
163 }
164 }
165 }
166 private BannedRegionCache m_bannedRegionCache = new BannedRegionCache();
75 167
76 private IEventQueue m_eqModule; 168 private IEventQueue m_eqModule;
169 private IRegionCombinerModule m_regionCombinerModule;
77 170
78 #region ISharedRegionModule 171 #region ISharedRegionModule
79 172
@@ -107,11 +200,32 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
107 /// <param name="source"></param> 200 /// <param name="source"></param>
108 protected virtual void InitialiseCommon(IConfigSource source) 201 protected virtual void InitialiseCommon(IConfigSource source)
109 { 202 {
203 IConfig hypergridConfig = source.Configs["Hypergrid"];
204 if (hypergridConfig != null)
205 {
206 m_ThisHomeURI = hypergridConfig.GetString("HomeURI", string.Empty);
207 if (m_ThisHomeURI != string.Empty && !m_ThisHomeURI.EndsWith("/"))
208 m_ThisHomeURI += '/';
209
210 m_GatekeeperURI = hypergridConfig.GetString("GatekeeperURI", string.Empty);
211 if (m_GatekeeperURI != string.Empty && !m_GatekeeperURI.EndsWith("/"))
212 m_GatekeeperURI += '/';
213 }
214
110 IConfig transferConfig = source.Configs["EntityTransfer"]; 215 IConfig transferConfig = source.Configs["EntityTransfer"];
111 if (transferConfig != null) 216 if (transferConfig != null)
112 { 217 {
218 DisableInterRegionTeleportCancellation
219 = transferConfig.GetBoolean("DisableInterRegionTeleportCancellation", false);
220
113 WaitForAgentArrivedAtDestination 221 WaitForAgentArrivedAtDestination
114 = transferConfig.GetBoolean("wait_for_callback", WaitForAgentArrivedAtDestinationDefault); 222 = transferConfig.GetBoolean("wait_for_callback", WaitForAgentArrivedAtDestinationDefault);
223
224 MaxTransferDistance = transferConfig.GetInt("max_distance", DefaultMaxTransferDistance);
225 }
226 else
227 {
228 MaxTransferDistance = DefaultMaxTransferDistance;
115 } 229 }
116 230
117 m_entityTransferStateMachine = new EntityTransferStateMachine(this); 231 m_entityTransferStateMachine = new EntityTransferStateMachine(this);
@@ -130,19 +244,87 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
130 244
131 Scene = scene; 245 Scene = scene;
132 246
247 m_interRegionTeleportAttempts =
248 new Stat(
249 "InterRegionTeleportAttempts",
250 "Number of inter-region teleports attempted.",
251 "This does not count attempts which failed due to pre-conditions (e.g. target simulator refused access).\n"
252 + "You can get successfully teleports by subtracting aborts, cancels and teleport failures from this figure.",
253 "",
254 "entitytransfer",
255 Scene.Name,
256 StatType.Push,
257 null,
258 StatVerbosity.Debug);
259
260 m_interRegionTeleportAborts =
261 new Stat(
262 "InterRegionTeleportAborts",
263 "Number of inter-region teleports aborted due to client actions.",
264 "The chief action is simultaneous logout whilst teleporting.",
265 "",
266 "entitytransfer",
267 Scene.Name,
268 StatType.Push,
269 null,
270 StatVerbosity.Debug);
271
272 m_interRegionTeleportCancels =
273 new Stat(
274 "InterRegionTeleportCancels",
275 "Number of inter-region teleports cancelled by the client.",
276 null,
277 "",
278 "entitytransfer",
279 Scene.Name,
280 StatType.Push,
281 null,
282 StatVerbosity.Debug);
283
284 m_interRegionTeleportFailures =
285 new Stat(
286 "InterRegionTeleportFailures",
287 "Number of inter-region teleports that failed due to server/client/network issues.",
288 "This number may not be very helpful in open-grid/hg situations as the network connectivity/quality of destinations is uncontrollable.",
289 "",
290 "entitytransfer",
291 Scene.Name,
292 StatType.Push,
293 null,
294 StatVerbosity.Debug);
295
296 StatsManager.RegisterStat(m_interRegionTeleportAttempts);
297 StatsManager.RegisterStat(m_interRegionTeleportAborts);
298 StatsManager.RegisterStat(m_interRegionTeleportCancels);
299 StatsManager.RegisterStat(m_interRegionTeleportFailures);
300
133 scene.RegisterModuleInterface<IEntityTransferModule>(this); 301 scene.RegisterModuleInterface<IEntityTransferModule>(this);
134 scene.EventManager.OnNewClient += OnNewClient; 302 scene.EventManager.OnNewClient += OnNewClient;
135 } 303 }
136 304
137 protected virtual void OnNewClient(IClientAPI client) 305 protected virtual void OnNewClient(IClientAPI client)
138 { 306 {
139 client.OnTeleportHomeRequest += TeleportHome; 307 client.OnTeleportHomeRequest += TriggerTeleportHome;
140 client.OnTeleportLandmarkRequest += RequestTeleportLandmark; 308 client.OnTeleportLandmarkRequest += RequestTeleportLandmark;
309
310 if (!DisableInterRegionTeleportCancellation)
311 client.OnTeleportCancel += OnClientCancelTeleport;
312
313 client.OnConnectionClosed += OnConnectionClosed;
141 } 314 }
142 315
143 public virtual void Close() {} 316 public virtual void Close() {}
144 317
145 public virtual void RemoveRegion(Scene scene) {} 318 public virtual void RemoveRegion(Scene scene)
319 {
320 if (m_Enabled)
321 {
322 StatsManager.DeregisterStat(m_interRegionTeleportAttempts);
323 StatsManager.DeregisterStat(m_interRegionTeleportAborts);
324 StatsManager.DeregisterStat(m_interRegionTeleportCancels);
325 StatsManager.DeregisterStat(m_interRegionTeleportFailures);
326 }
327 }
146 328
147 public virtual void RegionLoaded(Scene scene) 329 public virtual void RegionLoaded(Scene scene)
148 { 330 {
@@ -150,12 +332,32 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
150 return; 332 return;
151 333
152 m_eqModule = Scene.RequestModuleInterface<IEventQueue>(); 334 m_eqModule = Scene.RequestModuleInterface<IEventQueue>();
335 m_regionCombinerModule = Scene.RequestModuleInterface<IRegionCombinerModule>();
153 } 336 }
154 337
155 #endregion 338 #endregion
156 339
157 #region Agent Teleports 340 #region Agent Teleports
158 341
342 private void OnConnectionClosed(IClientAPI client)
343 {
344 if (client.IsLoggingOut && m_entityTransferStateMachine.UpdateInTransit(client.AgentId, AgentTransferState.Aborting))
345 {
346 m_log.DebugFormat(
347 "[ENTITY TRANSFER MODULE]: Aborted teleport request from {0} in {1} due to simultaneous logout",
348 client.Name, Scene.Name);
349 }
350 }
351
352 private void OnClientCancelTeleport(IClientAPI client)
353 {
354 m_entityTransferStateMachine.UpdateInTransit(client.AgentId, AgentTransferState.Cancelling);
355
356 m_log.DebugFormat(
357 "[ENTITY TRANSFER MODULE]: Received teleport cancel request from {0} in {1}", client.Name, Scene.Name);
358 }
359
360 // Attempt to teleport the ScenePresence to the specified position in the specified region (spec'ed by its handle).
159 public void Teleport(ScenePresence sp, ulong regionHandle, Vector3 position, Vector3 lookAt, uint teleportFlags) 361 public void Teleport(ScenePresence sp, ulong regionHandle, Vector3 position, Vector3 lookAt, uint teleportFlags)
160 { 362 {
161 if (sp.Scene.Permissions.IsGridGod(sp.UUID)) 363 if (sp.Scene.Permissions.IsGridGod(sp.UUID))
@@ -167,13 +369,26 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
167 if (!sp.Scene.Permissions.CanTeleport(sp.UUID)) 369 if (!sp.Scene.Permissions.CanTeleport(sp.UUID))
168 return; 370 return;
169 371
170 // Reset animations; the viewer does that in teleports.
171 sp.Animator.ResetAnimations();
172
173 string destinationRegionName = "(not found)"; 372 string destinationRegionName = "(not found)";
174 373
374 // Record that this agent is in transit so that we can prevent simultaneous requests and do later detection
375 // of whether the destination region completes the teleport.
376 if (!m_entityTransferStateMachine.SetInTransit(sp.UUID))
377 {
378 m_log.DebugFormat(
379 "[ENTITY TRANSFER MODULE]: Ignoring teleport request of {0} {1} to {2}@{3} - agent is already in transit.",
380 sp.Name, sp.UUID, position, regionHandle);
381
382 sp.ControllingClient.SendTeleportFailed("Previous teleport process incomplete. Please retry shortly.");
383
384 return;
385 }
386
175 try 387 try
176 { 388 {
389 // Reset animations; the viewer does that in teleports.
390 sp.Animator.ResetAnimations();
391
177 if (regionHandle == sp.Scene.RegionInfo.RegionHandle) 392 if (regionHandle == sp.Scene.RegionInfo.RegionHandle)
178 { 393 {
179 destinationRegionName = sp.Scene.RegionInfo.RegionName; 394 destinationRegionName = sp.Scene.RegionInfo.RegionName;
@@ -182,12 +397,17 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
182 } 397 }
183 else // Another region possibly in another simulator 398 else // Another region possibly in another simulator
184 { 399 {
185 GridRegion finalDestination; 400 GridRegion finalDestination = null;
186 TeleportAgentToDifferentRegion( 401 try
187 sp, regionHandle, position, lookAt, teleportFlags, out finalDestination); 402 {
188 403 TeleportAgentToDifferentRegion(
189 if (finalDestination != null) 404 sp, regionHandle, position, lookAt, teleportFlags, out finalDestination);
190 destinationRegionName = finalDestination.RegionName; 405 }
406 finally
407 {
408 if (finalDestination != null)
409 destinationRegionName = finalDestination.RegionName;
410 }
191 } 411 }
192 } 412 }
193 catch (Exception e) 413 catch (Exception e)
@@ -197,11 +417,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
197 sp.Name, sp.AbsolutePosition, sp.Scene.RegionInfo.RegionName, position, destinationRegionName, 417 sp.Name, sp.AbsolutePosition, sp.Scene.RegionInfo.RegionName, position, destinationRegionName,
198 e.Message, e.StackTrace); 418 e.Message, e.StackTrace);
199 419
200 // Make sure that we clear the in-transit flag so that future teleport attempts don't always fail.
201 m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
202
203 sp.ControllingClient.SendTeleportFailed("Internal error"); 420 sp.ControllingClient.SendTeleportFailed("Internal error");
204 } 421 }
422 finally
423 {
424 m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
425 }
205 } 426 }
206 427
207 /// <summary> 428 /// <summary>
@@ -210,30 +431,21 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
210 /// <param name="sp"></param> 431 /// <param name="sp"></param>
211 /// <param name="position"></param> 432 /// <param name="position"></param>
212 /// <param name="lookAt"></param> 433 /// <param name="lookAt"></param>
213 /// <param name="teleportFlags"></param 434 /// <param name="teleportFlags"></param>
214 private void TeleportAgentWithinRegion(ScenePresence sp, Vector3 position, Vector3 lookAt, uint teleportFlags) 435 private void TeleportAgentWithinRegion(ScenePresence sp, Vector3 position, Vector3 lookAt, uint teleportFlags)
215 { 436 {
216 m_log.DebugFormat( 437 m_log.DebugFormat(
217 "[ENTITY TRANSFER MODULE]: Teleport for {0} to {1} within {2}", 438 "[ENTITY TRANSFER MODULE]: Teleport for {0} to {1} within {2}",
218 sp.Name, position, sp.Scene.RegionInfo.RegionName); 439 sp.Name, position, sp.Scene.RegionInfo.RegionName);
219 440
220 if (!m_entityTransferStateMachine.SetInTransit(sp.UUID))
221 {
222 m_log.DebugFormat(
223 "[ENTITY TRANSFER MODULE]: Ignoring within region teleport request of {0} {1} to {2} - agent is already in transit.",
224 sp.Name, sp.UUID, position);
225
226 return;
227 }
228
229 // Teleport within the same region 441 // Teleport within the same region
230 if (IsOutsideRegion(sp.Scene, position) || position.Z < 0) 442 if (!sp.Scene.PositionIsInCurrentRegion(position) || position.Z < 0)
231 { 443 {
232 Vector3 emergencyPos = new Vector3(128, 128, 128); 444 Vector3 emergencyPos = new Vector3(128, 128, 128);
233 445
234 m_log.WarnFormat( 446 m_log.WarnFormat(
235 "[ENTITY TRANSFER MODULE]: RequestTeleportToLocation() was given an illegal position of {0} for avatar {1}, {2}. Substituting {3}", 447 "[ENTITY TRANSFER MODULE]: RequestTeleportToLocation() was given an illegal position of {0} for avatar {1}, {2} in {3}. Substituting {4}",
236 position, sp.Name, sp.UUID, emergencyPos); 448 position, sp.Name, sp.UUID, Scene.Name, emergencyPos);
237 449
238 position = emergencyPos; 450 position = emergencyPos;
239 } 451 }
@@ -243,10 +455,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
243 float posZLimit = 22; 455 float posZLimit = 22;
244 456
245 // TODO: Check other Scene HeightField 457 // TODO: Check other Scene HeightField
246 if (position.X > 0 && position.X <= (int)Constants.RegionSize && position.Y > 0 && position.Y <= (int)Constants.RegionSize) 458 posZLimit = (float)sp.Scene.Heightmap[(int)position.X, (int)position.Y];
247 {
248 posZLimit = (float)sp.Scene.Heightmap[(int)position.X, (int)position.Y];
249 }
250 459
251 float newPosZ = posZLimit + localAVHeight; 460 float newPosZ = posZLimit + localAVHeight;
252 if (posZLimit >= (position.Z - (localAVHeight / 2)) && !(Single.IsInfinity(newPosZ) || Single.IsNaN(newPosZ))) 461 if (posZLimit >= (position.Z - (localAVHeight / 2)) && !(Single.IsInfinity(newPosZ) || Single.IsNaN(newPosZ)))
@@ -254,11 +463,15 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
254 position.Z = newPosZ; 463 position.Z = newPosZ;
255 } 464 }
256 465
466 if (sp.Flying)
467 teleportFlags |= (uint)TeleportFlags.IsFlying;
468
257 m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring); 469 m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring);
258 470
259 sp.ControllingClient.SendTeleportStart(teleportFlags); 471 sp.ControllingClient.SendTeleportStart(teleportFlags);
260 472
261 sp.ControllingClient.SendLocalTeleport(position, lookAt, teleportFlags); 473 sp.ControllingClient.SendLocalTeleport(position, lookAt, teleportFlags);
474 sp.TeleportFlags = (Constants.TeleportFlags)teleportFlags;
262 sp.Velocity = Vector3.Zero; 475 sp.Velocity = Vector3.Zero;
263 sp.Teleport(position); 476 sp.Teleport(position);
264 477
@@ -270,7 +483,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
270 } 483 }
271 484
272 m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); 485 m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp);
273 m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
274 } 486 }
275 487
276 /// <summary> 488 /// <summary>
@@ -286,21 +498,23 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
286 ScenePresence sp, ulong regionHandle, Vector3 position, 498 ScenePresence sp, ulong regionHandle, Vector3 position,
287 Vector3 lookAt, uint teleportFlags, out GridRegion finalDestination) 499 Vector3 lookAt, uint teleportFlags, out GridRegion finalDestination)
288 { 500 {
289 uint x = 0, y = 0; 501 // Get destination region taking into account that the address could be an offset
290 Utils.LongToUInts(regionHandle, out x, out y); 502 // region inside a varregion.
291 GridRegion reg = Scene.GridService.GetRegionByPosition(sp.Scene.RegionInfo.ScopeID, (int)x, (int)y); 503 GridRegion reg = GetTeleportDestinationRegion(sp.Scene.GridService, sp.Scene.RegionInfo.ScopeID, regionHandle, ref position);
292 504
293 if (reg != null) 505 if (reg != null)
294 { 506 {
295 finalDestination = GetFinalDestination(reg); 507 string homeURI = Scene.GetAgentHomeURI(sp.ControllingClient.AgentId);
508
509 string message;
510 finalDestination = GetFinalDestination(reg, sp.ControllingClient.AgentId, homeURI, out message);
296 511
297 if (finalDestination == null) 512 if (finalDestination == null)
298 { 513 {
299 m_log.WarnFormat( 514 m_log.WarnFormat( "{0} Final destination is having problems. Unable to teleport {1} {2}: {3}",
300 "[ENTITY TRANSFER MODULE]: Final destination is having problems. Unable to teleport {0} {1}", 515 LogHeader, sp.Name, sp.UUID, message);
301 sp.Name, sp.UUID);
302 516
303 sp.ControllingClient.SendTeleportFailed("Problem at destination"); 517 sp.ControllingClient.SendTeleportFailed(message);
304 return; 518 return;
305 } 519 }
306 520
@@ -321,10 +535,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
321 return; 535 return;
322 } 536 }
323 537
538 if (message != null)
539 sp.ControllingClient.SendAgentAlertMessage(message, true);
540
324 // 541 //
325 // This is it 542 // This is it
326 // 543 //
327 DoTeleport(sp, reg, finalDestination, position, lookAt, teleportFlags); 544 DoTeleportInternal(sp, reg, finalDestination, position, lookAt, teleportFlags);
328 // 545 //
329 // 546 //
330 // 547 //
@@ -339,12 +556,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
339 556
340 // and set the map-tile to '(Offline)' 557 // and set the map-tile to '(Offline)'
341 uint regX, regY; 558 uint regX, regY;
342 Utils.LongToUInts(regionHandle, out regX, out regY); 559 Util.RegionHandleToRegionLoc(regionHandle, out regX, out regY);
343 560
344 MapBlockData block = new MapBlockData(); 561 MapBlockData block = new MapBlockData();
345 block.X = (ushort)(regX / Constants.RegionSize); 562 block.X = (ushort)regX;
346 block.Y = (ushort)(regY / Constants.RegionSize); 563 block.Y = (ushort)regY;
347 block.Access = 254; // == not there 564 block.Access = (byte)SimAccess.Down;
348 565
349 List<MapBlockData> blocks = new List<MapBlockData>(); 566 List<MapBlockData> blocks = new List<MapBlockData>();
350 blocks.Add(block); 567 blocks.Add(block);
@@ -352,6 +569,31 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
352 } 569 }
353 } 570 }
354 571
572 // The teleport address could be an address in a subregion of a larger varregion.
573 // Find the real base region and adjust the teleport location to account for the
574 // larger region.
575 private GridRegion GetTeleportDestinationRegion(IGridService gridService, UUID scope, ulong regionHandle, ref Vector3 position)
576 {
577 uint x = 0, y = 0;
578 Util.RegionHandleToWorldLoc(regionHandle, out x, out y);
579
580 // Compute the world location we're teleporting to
581 double worldX = (double)x + position.X;
582 double worldY = (double)y + position.Y;
583
584 // Find the region that contains the position
585 GridRegion reg = GetRegionContainingWorldLocation(gridService, scope, worldX, worldY);
586
587 if (reg != null)
588 {
589 // modify the position for the offset into the actual region returned
590 position.X += x - reg.RegionLocX;
591 position.Y += y - reg.RegionLocY;
592 }
593
594 return reg;
595 }
596
355 // Nothing to validate here 597 // Nothing to validate here
356 protected virtual bool ValidateGenericConditions(ScenePresence sp, GridRegion reg, GridRegion finalDestination, uint teleportFlags, out string reason) 598 protected virtual bool ValidateGenericConditions(ScenePresence sp, GridRegion reg, GridRegion finalDestination, uint teleportFlags, out string reason)
357 { 599 {
@@ -359,6 +601,32 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
359 return true; 601 return true;
360 } 602 }
361 603
604 /// <summary>
605 /// Determines whether this instance is within the max transfer distance.
606 /// </summary>
607 /// <param name="sourceRegion"></param>
608 /// <param name="destRegion"></param>
609 /// <returns>
610 /// <c>true</c> if this instance is within max transfer distance; otherwise, <c>false</c>.
611 /// </returns>
612 private bool IsWithinMaxTeleportDistance(RegionInfo sourceRegion, GridRegion destRegion)
613 {
614 if(MaxTransferDistance == 0)
615 return true;
616
617// m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Source co-ords are x={0} y={1}", curRegionX, curRegionY);
618//
619// m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Final dest is x={0} y={1} {2}@{3}",
620// destRegionX, destRegionY, finalDestination.RegionID, finalDestination.ServerURI);
621
622 // Insanely, RegionLoc on RegionInfo is the 256m map co-ord whilst GridRegion.RegionLoc is the raw meters position.
623 return Math.Abs(sourceRegion.RegionLocX - destRegion.RegionCoordX) <= MaxTransferDistance
624 && Math.Abs(sourceRegion.RegionLocY - destRegion.RegionCoordY) <= MaxTransferDistance;
625 }
626
627 /// <summary>
628 /// Wraps DoTeleportInternal() and manages the transfer state.
629 /// </summary>
362 public void DoTeleport( 630 public void DoTeleport(
363 ScenePresence sp, GridRegion reg, GridRegion finalDestination, 631 ScenePresence sp, GridRegion reg, GridRegion finalDestination,
364 Vector3 position, Vector3 lookAt, uint teleportFlags) 632 Vector3 position, Vector3 lookAt, uint teleportFlags)
@@ -370,18 +638,45 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
370 m_log.DebugFormat( 638 m_log.DebugFormat(
371 "[ENTITY TRANSFER MODULE]: Ignoring teleport request of {0} {1} to {2} ({3}) {4}/{5} - agent is already in transit.", 639 "[ENTITY TRANSFER MODULE]: Ignoring teleport request of {0} {1} to {2} ({3}) {4}/{5} - agent is already in transit.",
372 sp.Name, sp.UUID, reg.ServerURI, finalDestination.ServerURI, finalDestination.RegionName, position); 640 sp.Name, sp.UUID, reg.ServerURI, finalDestination.ServerURI, finalDestination.RegionName, position);
373 641 sp.ControllingClient.SendTeleportFailed("Agent is already in transit.");
374 return; 642 return;
375 } 643 }
644
645 try
646 {
647 DoTeleportInternal(sp, reg, finalDestination, position, lookAt, teleportFlags);
648 }
649 catch (Exception e)
650 {
651 m_log.ErrorFormat(
652 "[ENTITY TRANSFER MODULE]: Exception on teleport of {0} from {1}@{2} to {3}@{4}: {5}{6}",
653 sp.Name, sp.AbsolutePosition, sp.Scene.RegionInfo.RegionName, position, finalDestination.RegionName,
654 e.Message, e.StackTrace);
376 655
377 if (reg == null || finalDestination == null) 656 sp.ControllingClient.SendTeleportFailed("Internal error");
657 }
658 finally
378 { 659 {
379 sp.ControllingClient.SendTeleportFailed("Unable to locate destination");
380 m_entityTransferStateMachine.ResetFromTransit(sp.UUID); 660 m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
661 }
662 }
381 663
664 /// <summary>
665 /// Teleports the agent to another region.
666 /// This method doesn't manage the transfer state; the caller must do that.
667 /// </summary>
668 private void DoTeleportInternal(
669 ScenePresence sp, GridRegion reg, GridRegion finalDestination,
670 Vector3 position, Vector3 lookAt, uint teleportFlags)
671 {
672 if (reg == null || finalDestination == null)
673 {
674 sp.ControllingClient.SendTeleportFailed("Unable to locate destination");
382 return; 675 return;
383 } 676 }
384 677
678 string homeURI = Scene.GetAgentHomeURI(sp.ControllingClient.AgentId);
679
385 m_log.DebugFormat( 680 m_log.DebugFormat(
386 "[ENTITY TRANSFER MODULE]: Teleporting {0} {1} from {2} to {3} ({4}) {5}/{6}", 681 "[ENTITY TRANSFER MODULE]: Teleporting {0} {1} from {2} to {3} ({4}) {5}/{6}",
387 sp.Name, sp.UUID, sp.Scene.RegionInfo.RegionName, 682 sp.Name, sp.UUID, sp.Scene.RegionInfo.RegionName,
@@ -389,10 +684,21 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
389 684
390 RegionInfo sourceRegion = sp.Scene.RegionInfo; 685 RegionInfo sourceRegion = sp.Scene.RegionInfo;
391 686
392 uint newRegionX = (uint)(reg.RegionHandle >> 40); 687 if (!IsWithinMaxTeleportDistance(sourceRegion, finalDestination))
393 uint newRegionY = (((uint)(reg.RegionHandle)) >> 8); 688 {
394 uint oldRegionX = (uint)(sp.Scene.RegionInfo.RegionHandle >> 40); 689 sp.ControllingClient.SendTeleportFailed(
395 uint oldRegionY = (((uint)(sp.Scene.RegionInfo.RegionHandle)) >> 8); 690 string.Format(
691 "Can't teleport to {0} ({1},{2}) from {3} ({4},{5}), destination is more than {6} regions way",
692 finalDestination.RegionName, finalDestination.RegionCoordX, finalDestination.RegionCoordY,
693 sourceRegion.RegionName, sourceRegion.RegionLocX, sourceRegion.RegionLocY,
694 MaxTransferDistance));
695
696 return;
697 }
698
699 uint newRegionX, newRegionY, oldRegionX, oldRegionY;
700 Util.RegionHandleToRegionLoc(reg.RegionHandle, out newRegionX, out newRegionY);
701 Util.RegionHandleToRegionLoc(sp.Scene.RegionInfo.RegionHandle, out oldRegionX, out oldRegionY);
396 702
397 ulong destinationHandle = finalDestination.RegionHandle; 703 ulong destinationHandle = finalDestination.RegionHandle;
398 704
@@ -400,11 +706,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
400 // This may be a costly operation. The reg.ExternalEndPoint field is not a passive field, 706 // This may be a costly operation. The reg.ExternalEndPoint field is not a passive field,
401 // it's actually doing a lot of work. 707 // it's actually doing a lot of work.
402 IPEndPoint endPoint = finalDestination.ExternalEndPoint; 708 IPEndPoint endPoint = finalDestination.ExternalEndPoint;
403 709 if (endPoint == null || endPoint.Address == null)
404 if (endPoint.Address == null)
405 { 710 {
406 sp.ControllingClient.SendTeleportFailed("Remote Region appears to be down"); 711 sp.ControllingClient.SendTeleportFailed("Remote Region appears to be down");
407 m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
408 712
409 return; 713 return;
410 } 714 }
@@ -412,35 +716,41 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
412 if (!sp.ValidateAttachments()) 716 if (!sp.ValidateAttachments())
413 m_log.DebugFormat( 717 m_log.DebugFormat(
414 "[ENTITY TRANSFER MODULE]: Failed validation of all attachments for teleport of {0} from {1} to {2}. Continuing.", 718 "[ENTITY TRANSFER MODULE]: Failed validation of all attachments for teleport of {0} from {1} to {2}. Continuing.",
415 sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName); 719 sp.Name, sp.Scene.Name, finalDestination.RegionName);
416
417// if (!sp.ValidateAttachments())
418// {
419// sp.ControllingClient.SendTeleportFailed("Inconsistent attachment state");
420// return;
421// }
422 720
423 string reason; 721 string reason;
424 string version; 722 EntityTransferContext ctx = new EntityTransferContext();
723
425 if (!Scene.SimulationService.QueryAccess( 724 if (!Scene.SimulationService.QueryAccess(
426 finalDestination, sp.ControllingClient.AgentId, Vector3.Zero, out version, out reason)) 725 finalDestination, sp.ControllingClient.AgentId, homeURI, true, position, sp.Scene.GetFormatsOffered(), ctx, out reason))
427 { 726 {
428 sp.ControllingClient.SendTeleportFailed(reason); 727 sp.ControllingClient.SendTeleportFailed(reason);
429 m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
430 728
431 m_log.DebugFormat( 729 m_log.DebugFormat(
432 "[ENTITY TRANSFER MODULE]: {0} was stopped from teleporting from {1} to {2} because {3}", 730 "[ENTITY TRANSFER MODULE]: {0} was stopped from teleporting from {1} to {2} because: {3}",
433 sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName, reason); 731 sp.Name, sp.Scene.Name, finalDestination.RegionName, reason);
434 732
435 return; 733 return;
436 } 734 }
437 735
438 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Destination is running version {0}", version); 736 // Before this point, teleport 'failure' is due to checkable pre-conditions such as whether the target
737 // simulator can be found and is explicitly prepared to allow access. Therefore, we will not count these
738 // as server attempts.
739 m_interRegionTeleportAttempts.Value++;
740
741 m_log.DebugFormat(
742 "[ENTITY TRANSFER MODULE]: {0} transfer protocol version to {1} is {2} / {3}",
743 sp.Scene.Name, finalDestination.RegionName, ctx.OutboundVersion, ctx.InboundVersion);
439 744
440 // Fixing a bug where teleporting while sitting results in the avatar ending up removed from 745 // Fixing a bug where teleporting while sitting results in the avatar ending up removed from
441 // both regions 746 // both regions
442 if (sp.ParentID != (uint)0) 747 if (sp.ParentID != (uint)0)
443 sp.StandUp(); 748 sp.StandUp();
749 else if (sp.Flying)
750 teleportFlags |= (uint)TeleportFlags.IsFlying;
751
752 if (DisableInterRegionTeleportCancellation)
753 teleportFlags |= (uint)TeleportFlags.DisableCancel;
444 754
445 // At least on LL 3.3.4, this is not strictly necessary - a teleport will succeed without sending this to 755 // At least on LL 3.3.4, this is not strictly necessary - a teleport will succeed without sending this to
446 // the viewer. However, it might mean that the viewer does not see the black teleport screen (untested). 756 // the viewer. However, it might mean that the viewer does not see the black teleport screen (untested).
@@ -454,13 +764,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
454 // once we reach here... 764 // once we reach here...
455 //avatar.Scene.RemoveCapsHandler(avatar.UUID); 765 //avatar.Scene.RemoveCapsHandler(avatar.UUID);
456 766
457 string capsPath = String.Empty;
458
459 AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode); 767 AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode);
460 AgentCircuitData agentCircuit = sp.ControllingClient.RequestClientInfo(); 768 AgentCircuitData agentCircuit = sp.ControllingClient.RequestClientInfo();
461 agentCircuit.startpos = position; 769 agentCircuit.startpos = position;
462 agentCircuit.child = true; 770 agentCircuit.child = true;
463 agentCircuit.Appearance = sp.Appearance; 771 agentCircuit.Appearance = new AvatarAppearance();
772 agentCircuit.Appearance.PackLegacyWearables = true;
464 if (currentAgentCircuit != null) 773 if (currentAgentCircuit != null)
465 { 774 {
466 agentCircuit.ServiceURLs = currentAgentCircuit.ServiceURLs; 775 agentCircuit.ServiceURLs = currentAgentCircuit.ServiceURLs;
@@ -471,23 +780,66 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
471 agentCircuit.Id0 = currentAgentCircuit.Id0; 780 agentCircuit.Id0 = currentAgentCircuit.Id0;
472 } 781 }
473 782
474 if (NeedsNewAgent(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY)) 783 // if (NeedsNewAgent(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY))
784 float dist = (float)Math.Max(sp.Scene.DefaultDrawDistance,
785 (float)Math.Max(sp.Scene.RegionInfo.RegionSizeX, sp.Scene.RegionInfo.RegionSizeY));
786 if (NeedsNewAgent(dist, oldRegionX, newRegionX, oldRegionY, newRegionY))
475 { 787 {
476 // brand new agent, let's create a new caps seed 788 // brand new agent, let's create a new caps seed
477 agentCircuit.CapsPath = CapsUtil.GetRandomCapsObjectPath(); 789 agentCircuit.CapsPath = CapsUtil.GetRandomCapsObjectPath();
478 } 790 }
479 791
480 // Let's create an agent there if one doesn't exist yet. 792 // We're going to fallback to V1 if the destination gives us anything smaller than 0.2
793 if (ctx.OutboundVersion >= 0.2f)
794 TransferAgent_V2(sp, agentCircuit, reg, finalDestination, endPoint, teleportFlags, oldRegionX, newRegionX, oldRegionY, newRegionY, ctx, out reason);
795 else
796 TransferAgent_V1(sp, agentCircuit, reg, finalDestination, endPoint, teleportFlags, oldRegionX, newRegionX, oldRegionY, newRegionY, ctx, out reason);
797 }
798
799 private void TransferAgent_V1(ScenePresence sp, AgentCircuitData agentCircuit, GridRegion reg, GridRegion finalDestination,
800 IPEndPoint endPoint, uint teleportFlags, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY, EntityTransferContext ctx, out string reason)
801 {
802 ulong destinationHandle = finalDestination.RegionHandle;
803 AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode);
804
805 m_log.DebugFormat(
806 "[ENTITY TRANSFER MODULE]: Using TP V1 for {0} going from {1} to {2}",
807 sp.Name, Scene.Name, finalDestination.RegionName);
808
809 // Let's create an agent there if one doesn't exist yet.
810 // NOTE: logout will always be false for a non-HG teleport.
481 bool logout = false; 811 bool logout = false;
482 if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason, out logout)) 812 if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason, out logout))
483 { 813 {
484 sp.ControllingClient.SendTeleportFailed(String.Format("Teleport refused: {0}", reason)); 814 m_interRegionTeleportFailures.Value++;
485 m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
486 815
487 m_log.DebugFormat( 816 m_log.DebugFormat(
488 "[ENTITY TRANSFER MODULE]: Teleport of {0} from {1} to {2} was refused because {3}", 817 "[ENTITY TRANSFER MODULE]: Teleport of {0} from {1} to {2} was refused because {3}",
489 sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName, reason); 818 sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName, reason);
490 819
820 sp.ControllingClient.SendTeleportFailed(reason);
821
822 return;
823 }
824
825 if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Cancelling)
826 {
827 m_interRegionTeleportCancels.Value++;
828
829 m_log.DebugFormat(
830 "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after CreateAgent on client request",
831 sp.Name, finalDestination.RegionName, sp.Scene.Name);
832
833 return;
834 }
835 else if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
836 {
837 m_interRegionTeleportAborts.Value++;
838
839 m_log.DebugFormat(
840 "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after CreateAgent due to previous client close.",
841 sp.Name, finalDestination.RegionName, sp.Scene.Name);
842
491 return; 843 return;
492 } 844 }
493 845
@@ -497,9 +849,16 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
497 // OK, it got this agent. Let's close some child agents 849 // OK, it got this agent. Let's close some child agents
498 sp.CloseChildAgents(newRegionX, newRegionY); 850 sp.CloseChildAgents(newRegionX, newRegionY);
499 851
500 IClientIPEndpoint ipepClient; 852 IClientIPEndpoint ipepClient;
501 if (NeedsNewAgent(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY)) 853 string capsPath = String.Empty;
854 float dist = (float)Math.Max(sp.Scene.DefaultDrawDistance,
855 (float)Math.Max(sp.Scene.RegionInfo.RegionSizeX, sp.Scene.RegionInfo.RegionSizeY));
856 if (NeedsNewAgent(dist, oldRegionX, newRegionX, oldRegionY, newRegionY))
502 { 857 {
858 m_log.DebugFormat(
859 "[ENTITY TRANSFER MODULE]: Determined that region {0} at {1},{2} needs new child agent for incoming agent {3} from {4}",
860 finalDestination.RegionName, newRegionX, newRegionY, sp.Name, Scene.Name);
861
503 //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Creating agent..."); 862 //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Creating agent...");
504 #region IP Translation for NAT 863 #region IP Translation for NAT
505 // Uses ipepClient above 864 // Uses ipepClient above
@@ -512,21 +871,30 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
512 871
513 if (m_eqModule != null) 872 if (m_eqModule != null)
514 { 873 {
515 m_eqModule.EnableSimulator(destinationHandle, endPoint, sp.UUID); 874 // The EnableSimulator message makes the client establish a connection with the destination
516 875 // simulator by sending the initial UseCircuitCode UDP packet to the destination containing the
517 // ES makes the client send a UseCircuitCode message to the destination, 876 // correct circuit code.
518 // which triggers a bunch of things there. 877 m_eqModule.EnableSimulator(destinationHandle, endPoint, sp.UUID,
519 // So let's wait 878 finalDestination.RegionSizeX, finalDestination.RegionSizeY);
879 m_log.DebugFormat("{0} Sent EnableSimulator. regName={1}, size=<{2},{3}>", LogHeader,
880 finalDestination.RegionName, finalDestination.RegionSizeX, finalDestination.RegionSizeY);
881
882 // XXX: Is this wait necessary? We will always end up waiting on UpdateAgent for the destination
883 // simulator to confirm that it has established communication with the viewer.
520 Thread.Sleep(200); 884 Thread.Sleep(200);
521 885
522 // At least on LL 3.3.4 for teleports between different regions on the same simulator this appears 886 // At least on LL 3.3.4 for teleports between different regions on the same simulator this appears
523 // unnecessary - teleport will succeed and SEED caps will be requested without it (though possibly 887 // unnecessary - teleport will succeed and SEED caps will be requested without it (though possibly
524 // only on TeleportFinish). This is untested for region teleport between different simulators 888 // only on TeleportFinish). This is untested for region teleport between different simulators
525 // though this probably also works. 889 // though this probably also works.
526 m_eqModule.EstablishAgentCommunication(sp.UUID, endPoint, capsPath); 890 m_eqModule.EstablishAgentCommunication(sp.UUID, endPoint, capsPath, finalDestination.RegionHandle,
891 finalDestination.RegionSizeX, finalDestination.RegionSizeY);
527 } 892 }
528 else 893 else
529 { 894 {
895 // XXX: This is a little misleading since we're information the client of its avatar destination,
896 // which may or may not be a neighbour region of the source region. This path is probably little
897 // used anyway (with EQ being the one used). But it is currently being used for test code.
530 sp.ControllingClient.InformClientOfNeighbour(destinationHandle, endPoint); 898 sp.ControllingClient.InformClientOfNeighbour(destinationHandle, endPoint);
531 } 899 }
532 } 900 }
@@ -539,31 +907,77 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
539 // Let's send a full update of the agent. This is a synchronous call. 907 // Let's send a full update of the agent. This is a synchronous call.
540 AgentData agent = new AgentData(); 908 AgentData agent = new AgentData();
541 sp.CopyTo(agent); 909 sp.CopyTo(agent);
542 agent.Position = position; 910 if (ctx.OutboundVersion < 0.5f)
911 agent.Appearance.PackLegacyWearables = true;
912 agent.Position = agentCircuit.startpos;
543 SetCallbackURL(agent, sp.Scene.RegionInfo); 913 SetCallbackURL(agent, sp.Scene.RegionInfo);
544 914
545 //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Updating agent...");
546 915
916 // We will check for an abort before UpdateAgent since UpdateAgent will require an active viewer to
917 // establish th econnection to the destination which makes it return true.
918 if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
919 {
920 m_interRegionTeleportAborts.Value++;
921
922 m_log.DebugFormat(
923 "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} before UpdateAgent",
924 sp.Name, finalDestination.RegionName, sp.Scene.Name);
925
926 return;
927 }
928
929 // A common teleport failure occurs when we can send CreateAgent to the
930 // destination region but the viewer cannot establish the connection (e.g. due to network issues between
931 // the viewer and the destination). In this case, UpdateAgent timesout after 10 seconds, although then
932 // there's a further 10 second wait whilst we attempt to tell the destination to delete the agent in Fail().
547 if (!UpdateAgent(reg, finalDestination, agent, sp)) 933 if (!UpdateAgent(reg, finalDestination, agent, sp))
548 { 934 {
549 // Region doesn't take it 935 if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
936 {
937 m_interRegionTeleportAborts.Value++;
938
939 m_log.DebugFormat(
940 "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after UpdateAgent due to previous client close.",
941 sp.Name, finalDestination.RegionName, sp.Scene.Name);
942
943 return;
944 }
945
550 m_log.WarnFormat( 946 m_log.WarnFormat(
551 "[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1} from {2}. Returning avatar to source region.", 947 "[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1}. Keeping avatar in {2}",
552 sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); 948 sp.Name, finalDestination.RegionName, sp.Scene.Name);
553 949
554 Fail(sp, finalDestination, logout); 950 Fail(sp, finalDestination, logout, currentAgentCircuit.SessionID.ToString(), "Connection between viewer and destination region could not be established.");
555 return; 951 return;
556 } 952 }
557 953
558 sp.ControllingClient.SendTeleportProgress(teleportFlags | (uint)TeleportFlags.DisableCancel, "sending_dest"); 954 if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Cancelling)
955 {
956 m_interRegionTeleportCancels.Value++;
957
958 m_log.DebugFormat(
959 "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after UpdateAgent on client request",
960 sp.Name, finalDestination.RegionName, sp.Scene.Name);
961
962 CleanupFailedInterRegionTeleport(sp, currentAgentCircuit.SessionID.ToString(), finalDestination);
963
964 return;
965 }
559 966
560 m_log.DebugFormat( 967 m_log.DebugFormat(
561 "[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} from {1} to {2}", 968 "[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} from {1} to {2}",
562 capsPath, sp.Scene.RegionInfo.RegionName, sp.Name); 969 capsPath, sp.Scene.RegionInfo.RegionName, sp.Name);
563 970
971 // We need to set this here to avoid an unlikely race condition when teleporting to a neighbour simulator,
972 // where that neighbour simulator could otherwise request a child agent create on the source which then
973 // closes our existing agent which is still signalled as root.
974 sp.IsChildAgent = true;
975
976 // OK, send TPFinish to the client, so that it starts the process of contacting the destination region
564 if (m_eqModule != null) 977 if (m_eqModule != null)
565 { 978 {
566 m_eqModule.TeleportFinishEvent(destinationHandle, 13, endPoint, 0, teleportFlags, capsPath, sp.UUID); 979 m_eqModule.TeleportFinishEvent(destinationHandle, 13, endPoint, 0, teleportFlags, capsPath, sp.UUID,
980 finalDestination.RegionSizeX, finalDestination.RegionSizeY);
567 } 981 }
568 else 982 else
569 { 983 {
@@ -571,31 +985,43 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
571 teleportFlags, capsPath); 985 teleportFlags, capsPath);
572 } 986 }
573 987
574 // Let's set this to true tentatively. This does not trigger OnChildAgent
575 sp.IsChildAgent = true;
576
577 // TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which 988 // TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which
578 // trigers a whole shebang of things there, including MakeRoot. So let's wait for confirmation 989 // trigers a whole shebang of things there, including MakeRoot. So let's wait for confirmation
579 // that the client contacted the destination before we close things here. 990 // that the client contacted the destination before we close things here.
580 if (!m_entityTransferStateMachine.WaitForAgentArrivedAtDestination(sp.UUID)) 991 if (!m_entityTransferStateMachine.WaitForAgentArrivedAtDestination(sp.UUID))
581 { 992 {
993 if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
994 {
995 m_interRegionTeleportAborts.Value++;
996
997 m_log.DebugFormat(
998 "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after WaitForAgentArrivedAtDestination due to previous client close.",
999 sp.Name, finalDestination.RegionName, sp.Scene.Name);
1000
1001 return;
1002 }
1003
582 m_log.WarnFormat( 1004 m_log.WarnFormat(
583 "[ENTITY TRANSFER MODULE]: Teleport of {0} to {1} from {2} failed due to no callback from destination region. Returning avatar to source region.", 1005 "[ENTITY TRANSFER MODULE]: Teleport of {0} to {1} from {2} failed due to no callback from destination region. Returning avatar to source region.",
584 sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); 1006 sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName);
585 1007
586 Fail(sp, finalDestination, logout); 1008 Fail(sp, finalDestination, logout, currentAgentCircuit.SessionID.ToString(), "Destination region did not signal teleport completion.");
1009
587 return; 1010 return;
588 } 1011 }
589 1012
590 m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); 1013 m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp);
591 1014
1015/*
1016 // TODO: This may be 0.6. Check if still needed
592 // For backwards compatibility 1017 // For backwards compatibility
593 if (version == "Unknown" || version == string.Empty) 1018 if (version == 0f)
594 { 1019 {
595 // CrossAttachmentsIntoNewRegion is a synchronous call. We shouldn't need to wait after it 1020 // CrossAttachmentsIntoNewRegion is a synchronous call. We shouldn't need to wait after it
596 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Old simulator, sending attachments one by one..."); 1021 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Old simulator, sending attachments one by one...");
597 CrossAttachmentsIntoNewRegion(finalDestination, sp, true); 1022 CrossAttachmentsIntoNewRegion(finalDestination, sp, true);
598 } 1023 }
1024*/
599 1025
600 // May need to logout or other cleanup 1026 // May need to logout or other cleanup
601 AgentHasMovedAway(sp, logout); 1027 AgentHasMovedAway(sp, logout);
@@ -606,12 +1032,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
606 // Now let's make it officially a child agent 1032 // Now let's make it officially a child agent
607 sp.MakeChildAgent(); 1033 sp.MakeChildAgent();
608 1034
609// sp.Scene.CleanDroppedAttachments();
610
611 // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone 1035 // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone
612 1036
613 if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) 1037 if (NeedsClosing(sp.Scene.DefaultDrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg))
614 { 1038 {
1039 if (!sp.Scene.IncomingPreCloseClient(sp))
1040 return;
1041
615 // We need to delay here because Imprudence viewers, unlike v1 or v3, have a short (<200ms, <500ms) delay before 1042 // We need to delay here because Imprudence viewers, unlike v1 or v3, have a short (<200ms, <500ms) delay before
616 // they regard the new region as the current region after receiving the AgentMovementComplete 1043 // they regard the new region as the current region after receiving the AgentMovementComplete
617 // response. If close is sent before then, it will cause the viewer to quit instead. 1044 // response. If close is sent before then, it will cause the viewer to quit instead.
@@ -620,51 +1047,243 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
620 // an agent cannot teleport back to this region if it has teleported away. 1047 // an agent cannot teleport back to this region if it has teleported away.
621 Thread.Sleep(2000); 1048 Thread.Sleep(2000);
622 1049
623 sp.Scene.IncomingCloseAgent(sp.UUID, false); 1050 sp.Scene.CloseAgent(sp.UUID, false);
624 } 1051 }
625 else 1052 else
626 { 1053 {
627 // now we have a child agent in this region. 1054 // now we have a child agent in this region.
628 sp.Reset(); 1055 sp.Reset();
629 } 1056 }
1057 }
630 1058
631 // Commented pending deletion since this method no longer appears to do anything at all 1059 private void TransferAgent_V2(ScenePresence sp, AgentCircuitData agentCircuit, GridRegion reg, GridRegion finalDestination,
632// // REFACTORING PROBLEM. Well, not a problem, but this method is HORRIBLE! 1060 IPEndPoint endPoint, uint teleportFlags, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY, EntityTransferContext ctx, out string reason)
633// if (sp.Scene.NeedSceneCacheClear(sp.UUID)) 1061 {
634// { 1062 ulong destinationHandle = finalDestination.RegionHandle;
635// m_log.DebugFormat( 1063 AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode);
636// "[ENTITY TRANSFER MODULE]: User {0} is going to another region, profile cache removed", 1064
637// sp.UUID); 1065 // Let's create an agent there if one doesn't exist yet.
638// } 1066 // NOTE: logout will always be false for a non-HG teleport.
1067 bool logout = false;
1068 if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason, out logout))
1069 {
1070 m_interRegionTeleportFailures.Value++;
1071
1072 m_log.DebugFormat(
1073 "[ENTITY TRANSFER MODULE]: Teleport of {0} from {1} to {2} was refused because {3}",
1074 sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName, reason);
1075
1076 sp.ControllingClient.SendTeleportFailed(reason);
1077
1078 return;
1079 }
1080
1081 if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Cancelling)
1082 {
1083 m_interRegionTeleportCancels.Value++;
1084
1085 m_log.DebugFormat(
1086 "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after CreateAgent on client request",
1087 sp.Name, finalDestination.RegionName, sp.Scene.Name);
1088
1089 return;
1090 }
1091 else if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
1092 {
1093 m_interRegionTeleportAborts.Value++;
1094
1095 m_log.DebugFormat(
1096 "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after CreateAgent due to previous client close.",
1097 sp.Name, finalDestination.RegionName, sp.Scene.Name);
1098
1099 return;
1100 }
1101
1102 // Past this point we have to attempt clean up if the teleport fails, so update transfer state.
1103 m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring);
1104
1105 IClientIPEndpoint ipepClient;
1106 string capsPath = String.Empty;
1107 float dist = (float)Math.Max(sp.Scene.DefaultDrawDistance,
1108 (float)Math.Max(sp.Scene.RegionInfo.RegionSizeX, sp.Scene.RegionInfo.RegionSizeY));
1109 if (NeedsNewAgent(dist, oldRegionX, newRegionX, oldRegionY, newRegionY))
1110 {
1111 m_log.DebugFormat(
1112 "[ENTITY TRANSFER MODULE]: Determined that region {0} at {1},{2} needs new child agent for agent {3} from {4}",
1113 finalDestination.RegionName, newRegionX, newRegionY, sp.Name, Scene.Name);
1114
1115 //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Creating agent...");
1116 #region IP Translation for NAT
1117 // Uses ipepClient above
1118 if (sp.ClientView.TryGet(out ipepClient))
1119 {
1120 endPoint.Address = NetworkUtil.GetIPFor(ipepClient.EndPoint, endPoint.Address);
1121 }
1122 #endregion
1123 capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath);
1124 }
1125 else
1126 {
1127 agentCircuit.CapsPath = sp.Scene.CapsModule.GetChildSeed(sp.UUID, reg.RegionHandle);
1128 capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath);
1129 }
1130
1131 // We need to set this here to avoid an unlikely race condition when teleporting to a neighbour simulator,
1132 // where that neighbour simulator could otherwise request a child agent create on the source which then
1133 // closes our existing agent which is still signalled as root.
1134 //sp.IsChildAgent = true;
1135
1136 // New protocol: send TP Finish directly, without prior ES or EAC. That's what happens in the Linden grid
1137 if (m_eqModule != null)
1138 m_eqModule.TeleportFinishEvent(destinationHandle, 13, endPoint, 0, teleportFlags, capsPath, sp.UUID,
1139 finalDestination.RegionSizeX, finalDestination.RegionSizeY);
1140 else
1141 sp.ControllingClient.SendRegionTeleport(destinationHandle, 13, endPoint, 4,
1142 teleportFlags, capsPath);
1143
1144 m_log.DebugFormat(
1145 "[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} from {1} to {2}",
1146 capsPath, sp.Scene.RegionInfo.RegionName, sp.Name);
1147
1148 // Let's send a full update of the agent.
1149 AgentData agent = new AgentData();
1150 sp.CopyTo(agent);
1151 if (ctx.OutboundVersion < 0.5f)
1152 agent.Appearance.PackLegacyWearables = true;
1153 agent.Position = agentCircuit.startpos;
1154 agent.SenderWantsToWaitForRoot = true;
1155 //SetCallbackURL(agent, sp.Scene.RegionInfo);
1156
1157 // Reset the do not close flag. This must be done before the destination opens child connections (here
1158 // triggered by UpdateAgent) to avoid race conditions. However, we also want to reset it as late as possible
1159 // to avoid a situation where an unexpectedly early call to Scene.NewUserConnection() wrongly results
1160 // in no close.
1161 sp.DoNotCloseAfterTeleport = false;
1162
1163 // Send the Update. If this returns true, we know the client has contacted the destination
1164 // via CompleteMovementIntoRegion, so we can let go.
1165 // If it returns false, something went wrong, and we need to abort.
1166 if (!UpdateAgent(reg, finalDestination, agent, sp))
1167 {
1168 if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
1169 {
1170 m_interRegionTeleportAborts.Value++;
1171
1172 m_log.DebugFormat(
1173 "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after UpdateAgent due to previous client close.",
1174 sp.Name, finalDestination.RegionName, sp.Scene.Name);
1175
1176 return;
1177 }
1178
1179 m_log.WarnFormat(
1180 "[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1}. Keeping avatar in {2}",
1181 sp.Name, finalDestination.RegionName, sp.Scene.Name);
1182
1183 Fail(sp, finalDestination, logout, currentAgentCircuit.SessionID.ToString(), "Connection between viewer and destination region could not be established.");
1184 return;
1185 }
1186
1187 m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp);
1188
1189 // Need to signal neighbours whether child agents may need closing irrespective of whether this
1190 // one needed closing. We also need to close child agents as quickly as possible to avoid complicated
1191 // race conditions with rapid agent releporting (e.g. from A1 to a non-neighbour B, back
1192 // to a neighbour A2 then off to a non-neighbour C). Closing child agents any later requires complex
1193 // distributed checks to avoid problems in rapid reteleporting scenarios and where child agents are
1194 // abandoned without proper close by viewer but then re-used by an incoming connection.
1195 sp.CloseChildAgents(newRegionX, newRegionY);
1196
1197 // May need to logout or other cleanup
1198 AgentHasMovedAway(sp, logout);
1199
1200 // Well, this is it. The agent is over there.
1201 KillEntity(sp.Scene, sp.LocalId);
639 1202
640 m_entityTransferStateMachine.ResetFromTransit(sp.UUID); 1203 // Now let's make it officially a child agent
1204 sp.MakeChildAgent();
1205
1206 // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone
1207 if (NeedsClosing(sp.Scene.DefaultDrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg))
1208 {
1209 if (!sp.Scene.IncomingPreCloseClient(sp))
1210 return;
1211
1212 // RED ALERT!!!!
1213 // PLEASE DO NOT DECREASE THIS WAIT TIME UNDER ANY CIRCUMSTANCES.
1214 // THE VIEWERS SEEM TO NEED SOME TIME AFTER RECEIVING MoveAgentIntoRegion
1215 // BEFORE THEY SETTLE IN THE NEW REGION.
1216 // DECREASING THE WAIT TIME HERE WILL EITHER RESULT IN A VIEWER CRASH OR
1217 // IN THE AVIE BEING PLACED IN INFINITY FOR A COUPLE OF SECONDS.
1218 Thread.Sleep(15000);
1219
1220 // OK, it got this agent. Let's close everything
1221 // If we shouldn't close the agent due to some other region renewing the connection
1222 // then this will be handled in IncomingCloseAgent under lock conditions
1223 m_log.DebugFormat(
1224 "[ENTITY TRANSFER MODULE]: Closing agent {0} in {1} after teleport", sp.Name, Scene.Name);
1225
1226 sp.Scene.CloseAgent(sp.UUID, false);
1227 }
1228 else
1229 {
1230 // now we have a child agent in this region.
1231 sp.Reset();
1232 }
641 } 1233 }
642 1234
643 protected virtual void Fail(ScenePresence sp, GridRegion finalDestination, bool logout) 1235 /// <summary>
1236 /// Clean up an inter-region teleport that did not complete, either because of simulator failure or cancellation.
1237 /// </summary>
1238 /// <remarks>
1239 /// All operations here must be idempotent so that we can call this method at any point in the teleport process
1240 /// up until we send the TeleportFinish event quene event to the viewer.
1241 /// <remarks>
1242 /// <param name='sp'> </param>
1243 /// <param name='finalDestination'></param>
1244 protected virtual void CleanupFailedInterRegionTeleport(ScenePresence sp, string auth_token, GridRegion finalDestination)
644 { 1245 {
645 m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); 1246 m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp);
646 1247
647 // Client never contacted destination. Let's restore everything back 1248 if (sp.IsChildAgent) // We had set it to child before attempted TP (V1)
648 sp.ControllingClient.SendTeleportFailed("Problems connecting to destination."); 1249 {
1250 sp.IsChildAgent = false;
1251 ReInstantiateScripts(sp);
649 1252
650 // Fail. Reset it back 1253 EnableChildAgents(sp);
651 sp.IsChildAgent = false; 1254 }
652 ReInstantiateScripts(sp); 1255 // Finally, kill the agent we just created at the destination.
1256 // XXX: Possibly this should be done asynchronously.
1257 Scene.SimulationService.CloseAgent(finalDestination, sp.UUID, auth_token);
1258 }
653 1259
654 EnableChildAgents(sp); 1260 /// <summary>
1261 /// Signal that the inter-region teleport failed and perform cleanup.
1262 /// </summary>
1263 /// <param name='sp'></param>
1264 /// <param name='finalDestination'></param>
1265 /// <param name='logout'></param>
1266 /// <param name='reason'>Human readable reason for teleport failure. Will be sent to client.</param>
1267 protected virtual void Fail(ScenePresence sp, GridRegion finalDestination, bool logout, string auth_code, string reason)
1268 {
1269 CleanupFailedInterRegionTeleport(sp, auth_code, finalDestination);
655 1270
656 // Finally, kill the agent we just created at the destination. 1271 m_interRegionTeleportFailures.Value++;
657 Scene.SimulationService.CloseAgent(finalDestination, sp.UUID);
658 1272
659 sp.Scene.EventManager.TriggerTeleportFail(sp.ControllingClient, logout); 1273 sp.ControllingClient.SendTeleportFailed(
1274 string.Format(
1275 "Problems connecting to destination {0}, reason: {1}", finalDestination.RegionName, reason));
660 1276
661 m_entityTransferStateMachine.ResetFromTransit(sp.UUID); 1277 sp.Scene.EventManager.TriggerTeleportFail(sp.ControllingClient, logout);
662 } 1278 }
663 1279
664 protected virtual bool CreateAgent(ScenePresence sp, GridRegion reg, GridRegion finalDestination, AgentCircuitData agentCircuit, uint teleportFlags, out string reason, out bool logout) 1280 protected virtual bool CreateAgent(ScenePresence sp, GridRegion reg, GridRegion finalDestination, AgentCircuitData agentCircuit, uint teleportFlags, out string reason, out bool logout)
665 { 1281 {
1282 GridRegion source = new GridRegion(Scene.RegionInfo);
1283 source.RawServerURI = m_GatekeeperURI;
1284
666 logout = false; 1285 logout = false;
667 bool success = Scene.SimulationService.CreateAgent(finalDestination, agentCircuit, teleportFlags, out reason); 1286 bool success = Scene.SimulationService.CreateAgent(source, finalDestination, agentCircuit, teleportFlags, out reason);
668 1287
669 if (success) 1288 if (success)
670 sp.Scene.EventManager.TriggerTeleportStart(sp.ControllingClient, reg, finalDestination, teleportFlags, logout); 1289 sp.Scene.EventManager.TriggerTeleportStart(sp.ControllingClient, reg, finalDestination, teleportFlags, logout);
@@ -702,14 +1321,32 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
702 scene.SendKillObject(new List<uint> { localID }); 1321 scene.SendKillObject(new List<uint> { localID });
703 } 1322 }
704 1323
705 protected virtual GridRegion GetFinalDestination(GridRegion region) 1324 protected virtual GridRegion GetFinalDestination(GridRegion region, UUID agentID, string agentHomeURI, out string message)
706 { 1325 {
1326 message = null;
707 return region; 1327 return region;
708 } 1328 }
709 1329
1330 // This returns 'true' if the new region already has a child agent for our
1331 // incoming agent. The implication is that, if 'false', we have to create the
1332 // child and then teleport into the region.
710 protected virtual bool NeedsNewAgent(float drawdist, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY) 1333 protected virtual bool NeedsNewAgent(float drawdist, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY)
711 { 1334 {
712 return Util.IsOutsideView(drawdist, oldRegionX, newRegionX, oldRegionY, newRegionY); 1335 if (m_regionCombinerModule != null && m_regionCombinerModule.IsRootForMegaregion(Scene.RegionInfo.RegionID))
1336 {
1337 Vector2 swCorner, neCorner;
1338 GetMegaregionViewRange(out swCorner, out neCorner);
1339
1340 m_log.DebugFormat(
1341 "[ENTITY TRANSFER MODULE]: Megaregion view of {0} is from {1} to {2} with new agent check for {3},{4}",
1342 Scene.Name, swCorner, neCorner, newRegionX, newRegionY);
1343
1344 return !(newRegionX >= swCorner.X && newRegionX <= neCorner.X && newRegionY >= swCorner.Y && newRegionY <= neCorner.Y);
1345 }
1346 else
1347 {
1348 return Util.IsOutsideView(drawdist, oldRegionX, newRegionX, oldRegionY, newRegionY);
1349 }
713 } 1350 }
714 1351
715 protected virtual bool NeedsClosing(float drawdist, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY, GridRegion reg) 1352 protected virtual bool NeedsClosing(float drawdist, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY, GridRegion reg)
@@ -717,20 +1354,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
717 return Util.IsOutsideView(drawdist, oldRegionX, newRegionX, oldRegionY, newRegionY); 1354 return Util.IsOutsideView(drawdist, oldRegionX, newRegionX, oldRegionY, newRegionY);
718 } 1355 }
719 1356
720 protected virtual bool IsOutsideRegion(Scene s, Vector3 pos)
721 {
722 if (s.TestBorderCross(pos, Cardinals.N))
723 return true;
724 if (s.TestBorderCross(pos, Cardinals.S))
725 return true;
726 if (s.TestBorderCross(pos, Cardinals.E))
727 return true;
728 if (s.TestBorderCross(pos, Cardinals.W))
729 return true;
730
731 return false;
732 }
733
734 #endregion 1357 #endregion
735 1358
736 #region Landmark Teleport 1359 #region Landmark Teleport
@@ -758,7 +1381,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
758 1381
759 #region Teleport Home 1382 #region Teleport Home
760 1383
761 public virtual void TeleportHome(UUID id, IClientAPI client) 1384 public virtual void TriggerTeleportHome(UUID id, IClientAPI client)
1385 {
1386 TeleportHome(id, client);
1387 }
1388
1389 public virtual bool TeleportHome(UUID id, IClientAPI client)
762 { 1390 {
763 m_log.DebugFormat( 1391 m_log.DebugFormat(
764 "[ENTITY TRANSFER MODULE]: Request to teleport {0} {1} home", client.Name, client.AgentId); 1392 "[ENTITY TRANSFER MODULE]: Request to teleport {0} {1} home", client.Name, client.AgentId);
@@ -768,12 +1396,20 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
768 1396
769 if (uinfo != null) 1397 if (uinfo != null)
770 { 1398 {
1399 if (uinfo.HomeRegionID == UUID.Zero)
1400 {
1401 // can't find the Home region: Tell viewer and abort
1402 m_log.ErrorFormat("{0} No grid user info found for {1} {2}. Cannot send home.",
1403 LogHeader, client.Name, client.AgentId);
1404 client.SendTeleportFailed("You don't have a home position set.");
1405 return false;
1406 }
771 GridRegion regionInfo = Scene.GridService.GetRegionByUUID(UUID.Zero, uinfo.HomeRegionID); 1407 GridRegion regionInfo = Scene.GridService.GetRegionByUUID(UUID.Zero, uinfo.HomeRegionID);
772 if (regionInfo == null) 1408 if (regionInfo == null)
773 { 1409 {
774 // can't find the Home region: Tell viewer and abort 1410 // can't find the Home region: Tell viewer and abort
775 client.SendTeleportFailed("Your home region could not be found."); 1411 client.SendTeleportFailed("Your home region could not be found.");
776 return; 1412 return false;
777 } 1413 }
778 1414
779 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Home region of {0} is {1} ({2}-{3})", 1415 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Home region of {0} is {1} ({2}-{3})",
@@ -783,13 +1419,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
783 ((Scene)(client.Scene)).RequestTeleportLocation( 1419 ((Scene)(client.Scene)).RequestTeleportLocation(
784 client, regionInfo.RegionHandle, uinfo.HomePosition, uinfo.HomeLookAt, 1420 client, regionInfo.RegionHandle, uinfo.HomePosition, uinfo.HomeLookAt,
785 (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaHome)); 1421 (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaHome));
1422 return true;
786 } 1423 }
787 else 1424 else
788 { 1425 {
789 m_log.ErrorFormat( 1426 // can't find the Home region: Tell viewer and abort
790 "[ENTITY TRANSFER MODULE]: No grid user information found for {0} {1}. Cannot send home.", 1427 client.SendTeleportFailed("Your home region could not be found.");
791 client.Name, client.AgentId);
792 } 1428 }
1429 return false;
793 } 1430 }
794 1431
795 #endregion 1432 #endregion
@@ -797,230 +1434,112 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
797 1434
798 #region Agent Crossings 1435 #region Agent Crossings
799 1436
800 public bool Cross(ScenePresence agent, bool isFlying) 1437 // Given a position relative to the current region (which has previously been tested to
1438 // see that it is actually outside the current region), find the new region that the
1439 // point is actually in.
1440 // Returns the coordinates and information of the new region or 'null' of it doesn't exist.
1441 public GridRegion GetDestination(Scene scene, UUID agentID, Vector3 pos,
1442 EntityTransferContext ctx, out Vector3 newpos, out string failureReason)
801 { 1443 {
802 Scene scene = agent.Scene; 1444 newpos = pos;
803 Vector3 pos = agent.AbsolutePosition; 1445 failureReason = string.Empty;
804 Vector3 newpos = new Vector3(pos.X, pos.Y, pos.Z); 1446 string homeURI = scene.GetAgentHomeURI(agentID);
805 uint neighbourx = scene.RegionInfo.RegionLocX;
806 uint neighboury = scene.RegionInfo.RegionLocY;
807 const float boundaryDistance = 1.7f;
808 Vector3 northCross = new Vector3(0, boundaryDistance, 0);
809 Vector3 southCross = new Vector3(0, -1 * boundaryDistance, 0);
810 Vector3 eastCross = new Vector3(boundaryDistance, 0, 0);
811 Vector3 westCross = new Vector3(-1 * boundaryDistance, 0, 0);
812
813 // distance into new region to place avatar
814 const float enterDistance = 0.5f;
815 1447
816 if (scene.TestBorderCross(pos + westCross, Cardinals.W)) 1448// m_log.DebugFormat(
817 { 1449// "[ENTITY TRANSFER MODULE]: Crossing agent {0} at pos {1} in {2}", agent.Name, pos, scene.Name);
818 if (scene.TestBorderCross(pos + northCross, Cardinals.N))
819 {
820 Border b = scene.GetCrossedBorder(pos + northCross, Cardinals.N);
821 neighboury += (uint)(int)(b.BorderLine.Z / (int)Constants.RegionSize);
822 }
823 else if (scene.TestBorderCross(pos + southCross, Cardinals.S))
824 {
825 Border b = scene.GetCrossedBorder(pos + southCross, Cardinals.S);
826 if (b.TriggerRegionX == 0 && b.TriggerRegionY == 0)
827 {
828 neighboury--;
829 newpos.Y = Constants.RegionSize - enterDistance;
830 }
831 else
832 {
833 agent.IsInTransit = true;
834
835 neighboury = b.TriggerRegionY;
836 neighbourx = b.TriggerRegionX;
837
838 Vector3 newposition = pos;
839 newposition.X += (scene.RegionInfo.RegionLocX - neighbourx) * Constants.RegionSize;
840 newposition.Y += (scene.RegionInfo.RegionLocY - neighboury) * Constants.RegionSize;
841 agent.ControllingClient.SendAgentAlertMessage(
842 String.Format("Moving you to region {0},{1}", neighbourx, neighboury), false);
843 InformClientToInitateTeleportToLocation(agent, neighbourx, neighboury, newposition, scene);
844 return true;
845 }
846 }
847
848 Border ba = scene.GetCrossedBorder(pos + westCross, Cardinals.W);
849 if (ba.TriggerRegionX == 0 && ba.TriggerRegionY == 0)
850 {
851 neighbourx--;
852 newpos.X = Constants.RegionSize - enterDistance;
853 }
854 else
855 {
856 agent.IsInTransit = true;
857 1450
858 neighboury = ba.TriggerRegionY; 1451 // Compute world location of the object's position
859 neighbourx = ba.TriggerRegionX; 1452 double presenceWorldX = (double)scene.RegionInfo.WorldLocX + pos.X;
1453 double presenceWorldY = (double)scene.RegionInfo.WorldLocY + pos.Y;
860 1454
861 Vector3 newposition = pos; 1455 // Call the grid service to lookup the region containing the new position.
862 newposition.X += (scene.RegionInfo.RegionLocX - neighbourx) * Constants.RegionSize; 1456 GridRegion neighbourRegion = GetRegionContainingWorldLocation(scene.GridService, scene.RegionInfo.ScopeID,
863 newposition.Y += (scene.RegionInfo.RegionLocY - neighboury) * Constants.RegionSize; 1457 presenceWorldX, presenceWorldY,
864 agent.ControllingClient.SendAgentAlertMessage( 1458 Math.Max(scene.RegionInfo.RegionSizeX, scene.RegionInfo.RegionSizeY));
865 String.Format("Moving you to region {0},{1}", neighbourx, neighboury), false);
866 InformClientToInitateTeleportToLocation(agent, neighbourx, neighboury, newposition, scene);
867 1459
868 return true; 1460 if (neighbourRegion != null)
869 }
870
871 }
872 else if (scene.TestBorderCross(pos + eastCross, Cardinals.E))
873 { 1461 {
874 Border b = scene.GetCrossedBorder(pos + eastCross, Cardinals.E); 1462 // Compute the entity's position relative to the new region
875 neighbourx += (uint)(int)(b.BorderLine.Z / (int)Constants.RegionSize); 1463 newpos = new Vector3((float)(presenceWorldX - (double)neighbourRegion.RegionLocX),
876 newpos.X = enterDistance; 1464 (float)(presenceWorldY - (double)neighbourRegion.RegionLocY),
1465 pos.Z);
877 1466
878 if (scene.TestBorderCross(pos + southCross, Cardinals.S)) 1467 if (m_bannedRegionCache.IfBanned(neighbourRegion.RegionHandle, agentID))
879 {
880 Border ba = scene.GetCrossedBorder(pos + southCross, Cardinals.S);
881 if (ba.TriggerRegionX == 0 && ba.TriggerRegionY == 0)
882 {
883 neighboury--;
884 newpos.Y = Constants.RegionSize - enterDistance;
885 }
886 else
887 {
888 agent.IsInTransit = true;
889
890 neighboury = ba.TriggerRegionY;
891 neighbourx = ba.TriggerRegionX;
892 Vector3 newposition = pos;
893 newposition.X += (scene.RegionInfo.RegionLocX - neighbourx) * Constants.RegionSize;
894 newposition.Y += (scene.RegionInfo.RegionLocY - neighboury) * Constants.RegionSize;
895 agent.ControllingClient.SendAgentAlertMessage(
896 String.Format("Moving you to region {0},{1}", neighbourx, neighboury), false);
897 InformClientToInitateTeleportToLocation(agent, neighbourx, neighboury, newposition, scene);
898 return true;
899 }
900 }
901 else if (scene.TestBorderCross(pos + northCross, Cardinals.N))
902 { 1468 {
903 Border c = scene.GetCrossedBorder(pos + northCross, Cardinals.N); 1469 failureReason = "Cannot region cross into banned parcel";
904 neighboury += (uint)(int)(c.BorderLine.Z / (int)Constants.RegionSize); 1470 neighbourRegion = null;
905 newpos.Y = enterDistance;
906 }
907 }
908 else if (scene.TestBorderCross(pos + southCross, Cardinals.S))
909 {
910 Border b = scene.GetCrossedBorder(pos + southCross, Cardinals.S);
911 if (b.TriggerRegionX == 0 && b.TriggerRegionY == 0)
912 {
913 neighboury--;
914 newpos.Y = Constants.RegionSize - enterDistance;
915 } 1471 }
916 else 1472 else
917 { 1473 {
918 agent.IsInTransit = true; 1474 // If not banned, make sure this agent is not in the list.
919 1475 m_bannedRegionCache.Remove(neighbourRegion.RegionHandle, agentID);
920 neighboury = b.TriggerRegionY;
921 neighbourx = b.TriggerRegionX;
922 Vector3 newposition = pos;
923 newposition.X += (scene.RegionInfo.RegionLocX - neighbourx) * Constants.RegionSize;
924 newposition.Y += (scene.RegionInfo.RegionLocY - neighboury) * Constants.RegionSize;
925 agent.ControllingClient.SendAgentAlertMessage(
926 String.Format("Moving you to region {0},{1}", neighbourx, neighboury), false);
927 InformClientToInitateTeleportToLocation(agent, neighbourx, neighboury, newposition, scene);
928 return true;
929 } 1476 }
930 }
931 else if (scene.TestBorderCross(pos + northCross, Cardinals.N))
932 {
933 Border b = scene.GetCrossedBorder(pos + northCross, Cardinals.N);
934 neighboury += (uint)(int)(b.BorderLine.Z / (int)Constants.RegionSize);
935 newpos.Y = enterDistance;
936 }
937
938 /*
939
940 if (pos.X < boundaryDistance) //West
941 {
942 neighbourx--;
943 newpos.X = Constants.RegionSize - enterDistance;
944 }
945 else if (pos.X > Constants.RegionSize - boundaryDistance) // East
946 {
947 neighbourx++;
948 newpos.X = enterDistance;
949 }
950 1477
951 if (pos.Y < boundaryDistance) // South 1478 // Check to see if we have access to the target region.
952 { 1479 if (neighbourRegion != null
953 neighboury--; 1480 && !scene.SimulationService.QueryAccess(neighbourRegion, agentID, homeURI, false, newpos, scene.GetFormatsOffered(), ctx, out failureReason))
954 newpos.Y = Constants.RegionSize - enterDistance;
955 }
956 else if (pos.Y > Constants.RegionSize - boundaryDistance) // North
957 {
958 neighboury++;
959 newpos.Y = enterDistance;
960 }
961 */
962
963 ulong neighbourHandle = Utils.UIntsToLong((uint)(neighbourx * Constants.RegionSize), (uint)(neighboury * Constants.RegionSize));
964
965 int x = (int)(neighbourx * Constants.RegionSize), y = (int)(neighboury * Constants.RegionSize);
966
967 ExpiringCache<ulong, DateTime> r;
968 DateTime banUntil;
969
970 if (m_bannedRegions.TryGetValue(agent.ControllingClient.AgentId, out r))
971 {
972 if (r.TryGetValue(neighbourHandle, out banUntil))
973 { 1481 {
974 if (DateTime.Now < banUntil) 1482 // remember banned
975 return false; 1483 m_bannedRegionCache.Add(neighbourRegion.RegionHandle, agentID);
976 r.Remove(neighbourHandle); 1484 neighbourRegion = null;
977 } 1485 }
978 } 1486 }
979 else 1487 else
980 { 1488 {
981 r = null; 1489 // The destination region just doesn't exist
1490 failureReason = "Cannot cross into non-existent region";
982 } 1491 }
983 1492
984 GridRegion neighbourRegion = scene.GridService.GetRegionByPosition(scene.RegionInfo.ScopeID, (int)x, (int)y); 1493 if (neighbourRegion == null)
1494 m_log.DebugFormat("{0} GetDestination: region not found. Old region name={1} at <{2},{3}> of size <{4},{5}>. Old pos={6}",
1495 LogHeader, scene.RegionInfo.RegionName,
1496 scene.RegionInfo.RegionLocX, scene.RegionInfo.RegionLocY,
1497 scene.RegionInfo.RegionSizeX, scene.RegionInfo.RegionSizeY,
1498 pos);
1499 else
1500 m_log.DebugFormat("{0} GetDestination: new region={1} at <{2},{3}> of size <{4},{5}>, newpos=<{6},{7}>",
1501 LogHeader, neighbourRegion.RegionName,
1502 neighbourRegion.RegionLocX, neighbourRegion.RegionLocY, neighbourRegion.RegionSizeX, neighbourRegion.RegionSizeY,
1503 newpos.X, newpos.Y);
985 1504
986 string reason; 1505 return neighbourRegion;
987 string version; 1506 }
988 if (!scene.SimulationService.QueryAccess(neighbourRegion, agent.ControllingClient.AgentId, newpos, out version, out reason))
989 {
990 agent.ControllingClient.SendAlertMessage("Cannot region cross into banned parcel");
991 if (r == null)
992 {
993 r = new ExpiringCache<ulong, DateTime>();
994 r.Add(neighbourHandle, DateTime.Now + TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(15));
995 1507
996 m_bannedRegions.Add(agent.ControllingClient.AgentId, r, TimeSpan.FromSeconds(45)); 1508 public bool Cross(ScenePresence agent, bool isFlying)
997 } 1509 {
998 else 1510 Vector3 newpos;
999 { 1511 EntityTransferContext ctx = new EntityTransferContext();
1000 r.Add(neighbourHandle, DateTime.Now + TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(15)); 1512 string failureReason;
1001 } 1513
1514 GridRegion neighbourRegion = GetDestination(agent.Scene, agent.UUID, agent.AbsolutePosition,
1515 ctx, out newpos, out failureReason);
1516 if (neighbourRegion == null)
1517 {
1518 agent.ControllingClient.SendAlertMessage(failureReason);
1002 return false; 1519 return false;
1003 } 1520 }
1004 1521
1005 agent.IsInTransit = true; 1522 agent.IsInTransit = true;
1006 1523
1007 CrossAgentToNewRegionDelegate d = CrossAgentToNewRegionAsync; 1524 CrossAgentToNewRegionDelegate d = CrossAgentToNewRegionAsync;
1008 d.BeginInvoke(agent, newpos, neighbourx, neighboury, neighbourRegion, isFlying, version, CrossAgentToNewRegionCompleted, d); 1525 d.BeginInvoke(agent, newpos, neighbourRegion, isFlying, ctx, CrossAgentToNewRegionCompleted, d);
1526
1527 Scene.EventManager.TriggerCrossAgentToNewRegion(agent, isFlying, neighbourRegion);
1009 1528
1010 return true; 1529 return true;
1011 } 1530 }
1012 1531
1013 1532
1014 public delegate void InformClientToInitateTeleportToLocationDelegate(ScenePresence agent, uint regionX, uint regionY, 1533 public delegate void InformClientToInitiateTeleportToLocationDelegate(ScenePresence agent, uint regionX, uint regionY,
1015 Vector3 position, 1534 Vector3 position,
1016 Scene initiatingScene); 1535 Scene initiatingScene);
1017 1536
1018 private void InformClientToInitateTeleportToLocation(ScenePresence agent, uint regionX, uint regionY, Vector3 position, Scene initiatingScene) 1537 private void InformClientToInitiateTeleportToLocation(ScenePresence agent, uint regionX, uint regionY, Vector3 position, Scene initiatingScene)
1019 { 1538 {
1020 1539
1021 // This assumes that we know what our neighbours are. 1540 // This assumes that we know what our neighbours are.
1022 1541
1023 InformClientToInitateTeleportToLocationDelegate d = InformClientToInitiateTeleportToLocationAsync; 1542 InformClientToInitiateTeleportToLocationDelegate d = InformClientToInitiateTeleportToLocationAsync;
1024 d.BeginInvoke(agent, regionX, regionY, position, initiatingScene, 1543 d.BeginInvoke(agent, regionX, regionY, position, initiatingScene,
1025 InformClientToInitiateTeleportToLocationCompleted, 1544 InformClientToInitiateTeleportToLocationCompleted,
1026 d); 1545 d);
@@ -1030,16 +1549,24 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1030 Scene initiatingScene) 1549 Scene initiatingScene)
1031 { 1550 {
1032 Thread.Sleep(10000); 1551 Thread.Sleep(10000);
1033 1552
1553 m_log.DebugFormat(
1554 "[ENTITY TRANSFER MODULE]: Auto-reteleporting {0} to correct megaregion location {1},{2},{3} from {4}",
1555 agent.Name, regionX, regionY, position, initiatingScene.Name);
1556
1557 agent.Scene.RequestTeleportLocation(
1558 agent.ControllingClient,
1559 Util.RegionLocToHandle(regionX, regionY),
1560 position,
1561 agent.Lookat,
1562 (uint)Constants.TeleportFlags.ViaLocation);
1563
1564 /*
1034 IMessageTransferModule im = initiatingScene.RequestModuleInterface<IMessageTransferModule>(); 1565 IMessageTransferModule im = initiatingScene.RequestModuleInterface<IMessageTransferModule>();
1035 if (im != null) 1566 if (im != null)
1036 { 1567 {
1037 UUID gotoLocation = Util.BuildFakeParcelID( 1568 UUID gotoLocation = Util.BuildFakeParcelID(
1038 Util.UIntsToLong( 1569 Util.RegionLocToHandle(regionX, regionY),
1039 (regionX *
1040 (uint)Constants.RegionSize),
1041 (regionY *
1042 (uint)Constants.RegionSize)),
1043 (uint)(int)position.X, 1570 (uint)(int)position.X,
1044 (uint)(int)position.Y, 1571 (uint)(int)position.Y,
1045 (uint)(int)position.Z); 1572 (uint)(int)position.Z);
@@ -1065,53 +1592,73 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1065 }); 1592 });
1066 1593
1067 } 1594 }
1595 */
1068 } 1596 }
1069 1597
1070 private void InformClientToInitiateTeleportToLocationCompleted(IAsyncResult iar) 1598 private void InformClientToInitiateTeleportToLocationCompleted(IAsyncResult iar)
1071 { 1599 {
1072 InformClientToInitateTeleportToLocationDelegate icon = 1600 InformClientToInitiateTeleportToLocationDelegate icon =
1073 (InformClientToInitateTeleportToLocationDelegate)iar.AsyncState; 1601 (InformClientToInitiateTeleportToLocationDelegate)iar.AsyncState;
1074 icon.EndInvoke(iar); 1602 icon.EndInvoke(iar);
1075 } 1603 }
1076 1604
1077 public delegate ScenePresence CrossAgentToNewRegionDelegate(ScenePresence agent, Vector3 pos, uint neighbourx, uint neighboury, GridRegion neighbourRegion, bool isFlying, string version); 1605 public bool CrossAgentToNewRegionPrep(ScenePresence agent, GridRegion neighbourRegion)
1606 {
1607 if (neighbourRegion == null)
1608 return false;
1609
1610 m_entityTransferStateMachine.SetInTransit(agent.UUID);
1611
1612 agent.RemoveFromPhysicalScene();
1613
1614 return true;
1615 }
1078 1616
1079 /// <summary> 1617 /// <summary>
1080 /// This Closes child agents on neighbouring regions 1618 /// This Closes child agents on neighbouring regions
1081 /// Calls an asynchronous method to do so.. so it doesn't lag the sim. 1619 /// Calls an asynchronous method to do so.. so it doesn't lag the sim.
1082 /// </summary> 1620 /// </summary>
1083 protected ScenePresence CrossAgentToNewRegionAsync( 1621 public ScenePresence CrossAgentToNewRegionAsync(
1084 ScenePresence agent, Vector3 pos, uint neighbourx, uint neighboury, GridRegion neighbourRegion, 1622 ScenePresence agent, Vector3 pos, GridRegion neighbourRegion,
1085 bool isFlying, string version) 1623 bool isFlying, EntityTransferContext ctx)
1086 { 1624 {
1087 if (neighbourRegion == null)
1088 return agent;
1089
1090 try 1625 try
1091 { 1626 {
1092 m_entityTransferStateMachine.SetInTransit(agent.UUID); 1627 m_log.DebugFormat("{0}: CrossAgentToNewRegionAsync: new region={1} at <{2},{3}>. newpos={4}",
1628 LogHeader, neighbourRegion.RegionName, neighbourRegion.RegionLocX, neighbourRegion.RegionLocY, pos);
1093 1629
1094 ulong neighbourHandle = Utils.UIntsToLong((uint)(neighbourx * Constants.RegionSize), (uint)(neighboury * Constants.RegionSize)); 1630 if (!CrossAgentToNewRegionPrep(agent, neighbourRegion))
1095 1631 {
1096 m_log.DebugFormat( 1632 m_log.DebugFormat("{0}: CrossAgentToNewRegionAsync: prep failed. Resetting transfer state", LogHeader);
1097 "[ENTITY TRANSFER MODULE]: Crossing agent {0} {1} to {2}-{3} running version {4}", 1633 m_entityTransferStateMachine.ResetFromTransit(agent.UUID);
1098 agent.Firstname, agent.Lastname, neighbourx, neighboury, version); 1634 }
1099
1100 Scene m_scene = agent.Scene;
1101 1635
1102 if (!agent.ValidateAttachments()) 1636 if (!CrossAgentIntoNewRegionMain(agent, pos, neighbourRegion, isFlying, ctx))
1103 m_log.DebugFormat( 1637 {
1104 "[ENTITY TRANSFER MODULE]: Failed validation of all attachments for region crossing of {0} from {1} to {2}. Continuing.", 1638 m_log.DebugFormat("{0}: CrossAgentToNewRegionAsync: cross main failed. Resetting transfer state", LogHeader);
1105 agent.Name, agent.Scene.RegionInfo.RegionName, neighbourRegion.RegionName); 1639 m_entityTransferStateMachine.ResetFromTransit(agent.UUID);
1640 }
1106 1641
1107 pos = pos + agent.Velocity; 1642 CrossAgentToNewRegionPost(agent, pos, neighbourRegion, isFlying, ctx);
1108 Vector3 vel2 = new Vector3(agent.Velocity.X, agent.Velocity.Y, 0); 1643 }
1644 catch (Exception e)
1645 {
1646 m_log.Error(string.Format("{0}: CrossAgentToNewRegionAsync: failed with exception ", LogHeader), e);
1647 }
1109 1648
1110 agent.RemoveFromPhysicalScene(); 1649 return agent;
1650 }
1111 1651
1652 public bool CrossAgentIntoNewRegionMain(ScenePresence agent, Vector3 pos, GridRegion neighbourRegion, bool isFlying, EntityTransferContext ctx)
1653 {
1654 try
1655 {
1112 AgentData cAgent = new AgentData(); 1656 AgentData cAgent = new AgentData();
1113 agent.CopyTo(cAgent); 1657 agent.CopyTo(cAgent);
1658 if (ctx.OutboundVersion < 0.5f)
1659 cAgent.Appearance.PackLegacyWearables = true;
1114 cAgent.Position = pos; 1660 cAgent.Position = pos;
1661
1115 if (isFlying) 1662 if (isFlying)
1116 cAgent.ControlFlags |= (uint)AgentManager.ControlFlags.AGENT_CONTROL_FLY; 1663 cAgent.ControlFlags |= (uint)AgentManager.ControlFlags.AGENT_CONTROL_FLY;
1117 1664
@@ -1121,102 +1668,121 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1121 // Beyond this point, extra cleanup is needed beyond removing transit state 1668 // Beyond this point, extra cleanup is needed beyond removing transit state
1122 m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.Transferring); 1669 m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.Transferring);
1123 1670
1124 if (!m_scene.SimulationService.UpdateAgent(neighbourRegion, cAgent)) 1671 if (!agent.Scene.SimulationService.UpdateAgent(neighbourRegion, cAgent))
1125 { 1672 {
1126 // region doesn't take it 1673 // region doesn't take it
1127 m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.CleaningUp); 1674 m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.CleaningUp);
1128 1675
1676 m_log.WarnFormat(
1677 "[ENTITY TRANSFER MODULE]: Region {0} would not accept update for agent {1} on cross attempt. Returning to original region.",
1678 neighbourRegion.RegionName, agent.Name);
1679
1129 ReInstantiateScripts(agent); 1680 ReInstantiateScripts(agent);
1130 agent.AddToPhysicalScene(isFlying); 1681 agent.AddToPhysicalScene(isFlying);
1131 m_entityTransferStateMachine.ResetFromTransit(agent.UUID);
1132 1682
1133 return agent; 1683 return false;
1134 } 1684 }
1135 1685
1136 //AgentCircuitData circuitdata = m_controllingClient.RequestClientInfo(); 1686 }
1137 agent.ControllingClient.RequestClientInfo(); 1687 catch (Exception e)
1688 {
1689 m_log.ErrorFormat(
1690 "[ENTITY TRANSFER MODULE]: Problem crossing user {0} to new region {1} from {2}. Exception {3}{4}",
1691 agent.Name, neighbourRegion.RegionName, agent.Scene.RegionInfo.RegionName, e.Message, e.StackTrace);
1692
1693 // TODO: Might be worth attempting other restoration here such as reinstantiation of scripts, etc.
1694 return false;
1695 }
1138 1696
1139 //m_log.Debug("BEFORE CROSS"); 1697 return true;
1140 //Scene.DumpChildrenSeeds(UUID); 1698 }
1141 //DumpKnownRegions();
1142 string agentcaps;
1143 if (!agent.KnownRegions.TryGetValue(neighbourRegion.RegionHandle, out agentcaps))
1144 {
1145 m_log.ErrorFormat("[ENTITY TRANSFER MODULE]: No ENTITY TRANSFER MODULE information for region handle {0}, exiting CrossToNewRegion.",
1146 neighbourRegion.RegionHandle);
1147 return agent;
1148 }
1149 // No turning back
1150 agent.IsChildAgent = true;
1151 1699
1152 string capsPath = neighbourRegion.ServerURI + CapsUtil.GetCapsSeedPath(agentcaps); 1700 public void CrossAgentToNewRegionPost(ScenePresence agent, Vector3 pos, GridRegion neighbourRegion,
1701 bool isFlying, EntityTransferContext ctx)
1702 {
1703 agent.ControllingClient.RequestClientInfo();
1153 1704
1154 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} to client {1}", capsPath, agent.UUID); 1705 string agentcaps;
1706 if (!agent.KnownRegions.TryGetValue(neighbourRegion.RegionHandle, out agentcaps))
1707 {
1708 m_log.ErrorFormat("[ENTITY TRANSFER MODULE]: No ENTITY TRANSFER MODULE information for region handle {0}, exiting CrossToNewRegion.",
1709 neighbourRegion.RegionHandle);
1710 return;
1711 }
1155 1712
1156 if (m_eqModule != null) 1713 // No turning back
1157 { 1714 agent.IsChildAgent = true;
1158 m_eqModule.CrossRegion( 1715
1159 neighbourHandle, pos, vel2 /* agent.Velocity */, neighbourRegion.ExternalEndPoint, 1716 string capsPath = neighbourRegion.ServerURI + CapsUtil.GetCapsSeedPath(agentcaps);
1160 capsPath, agent.UUID, agent.ControllingClient.SessionId);
1161 }
1162 else
1163 {
1164 agent.ControllingClient.CrossRegion(neighbourHandle, pos, agent.Velocity, neighbourRegion.ExternalEndPoint,
1165 capsPath);
1166 }
1167 1717
1168 // SUCCESS! 1718 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} to client {1}", capsPath, agent.UUID);
1169 m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.ReceivedAtDestination);
1170 1719
1171 // Unlike a teleport, here we do not wait for the destination region to confirm the receipt. 1720 Vector3 vel2 = new Vector3(agent.Velocity.X, agent.Velocity.Y, 0);
1172 m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.CleaningUp);
1173 1721
1174 agent.MakeChildAgent(); 1722 if (m_eqModule != null)
1723 {
1724 m_eqModule.CrossRegion(
1725 neighbourRegion.RegionHandle, pos + agent.Velocity, vel2 /* agent.Velocity */,
1726 neighbourRegion.ExternalEndPoint,
1727 capsPath, agent.UUID, agent.ControllingClient.SessionId,
1728 neighbourRegion.RegionSizeX, neighbourRegion.RegionSizeY);
1729 }
1730 else
1731 {
1732 m_log.ErrorFormat("{0} Using old CrossRegion packet. Varregion will not work!!", LogHeader);
1733 agent.ControllingClient.CrossRegion(neighbourRegion.RegionHandle, pos + agent.Velocity, agent.Velocity, neighbourRegion.ExternalEndPoint,
1734 capsPath);
1735 }
1175 1736
1176 // FIXME: Possibly this should occur lower down after other commands to close other agents, 1737 // SUCCESS!
1177 // but not sure yet what the side effects would be. 1738 m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.ReceivedAtDestination);
1178 m_entityTransferStateMachine.ResetFromTransit(agent.UUID);
1179 1739
1180 // now we have a child agent in this region. Request all interesting data about other (root) agents 1740 // Unlike a teleport, here we do not wait for the destination region to confirm the receipt.
1181 agent.SendOtherAgentsAvatarDataToMe(); 1741 m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.CleaningUp);
1182 agent.SendOtherAgentsAppearanceToMe();
1183 1742
1184 // Backwards compatibility. Best effort 1743 agent.MakeChildAgent();
1185 if (version == "Unknown" || version == string.Empty)
1186 {
1187 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: neighbor with old version, passing attachments one by one...");
1188 Thread.Sleep(3000); // wait a little now that we're not waiting for the callback
1189 CrossAttachmentsIntoNewRegion(neighbourRegion, agent, true);
1190 }
1191 1744
1192 // Next, let's close the child agent connections that are too far away. 1745 // FIXME: Possibly this should occur lower down after other commands to close other agents,
1193 agent.CloseChildAgents(neighbourx, neighboury); 1746 // but not sure yet what the side effects would be.
1747 m_entityTransferStateMachine.ResetFromTransit(agent.UUID);
1194 1748
1195 AgentHasMovedAway(agent, false); 1749 // now we have a child agent in this region. Request all interesting data about other (root) agents
1750 agent.SendOtherAgentsAvatarDataToClient();
1751 agent.SendOtherAgentsAppearanceToClient();
1196 1752
1197// // the user may change their profile information in other region, 1753 // TODO: Check since what version this wasn't needed anymore. May be as old as 0.6
1198// // so the userinfo in UserProfileCache is not reliable any more, delete it 1754/*
1199// // REFACTORING PROBLEM. Well, not a problem, but this method is HORRIBLE! 1755 // Backwards compatibility. Best effort
1200// if (agent.Scene.NeedSceneCacheClear(agent.UUID)) 1756 if (version == 0f)
1201// {
1202// m_log.DebugFormat(
1203// "[ENTITY TRANSFER MODULE]: User {0} is going to another region", agent.UUID);
1204// }
1205
1206 //m_log.Debug("AFTER CROSS");
1207 //Scene.DumpChildrenSeeds(UUID);
1208 //DumpKnownRegions();
1209 }
1210 catch (Exception e)
1211 { 1757 {
1212 m_log.ErrorFormat( 1758 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: neighbor with old version, passing attachments one by one...");
1213 "[ENTITY TRANSFER MODULE]: Problem crossing user {0} to new region {1} from {2}. Exception {3}{4}", 1759 Thread.Sleep(3000); // wait a little now that we're not waiting for the callback
1214 agent.Name, neighbourRegion.RegionName, agent.Scene.RegionInfo.RegionName, e.Message, e.StackTrace); 1760 CrossAttachmentsIntoNewRegion(neighbourRegion, agent, true);
1215
1216 // TODO: Might be worth attempting other restoration here such as reinstantiation of scripts, etc.
1217 } 1761 }
1762*/
1763 // Next, let's close the child agent connections that are too far away.
1764 uint neighbourx;
1765 uint neighboury;
1766 Util.RegionHandleToRegionLoc(neighbourRegion.RegionHandle, out neighbourx, out neighboury);
1218 1767
1219 return agent; 1768 agent.CloseChildAgents(neighbourx, neighboury);
1769
1770 AgentHasMovedAway(agent, false);
1771
1772 // the user may change their profile information in other region,
1773 // so the userinfo in UserProfileCache is not reliable any more, delete it
1774 // REFACTORING PROBLEM. Well, not a problem, but this method is HORRIBLE!
1775// if (agent.Scene.NeedSceneCacheClear(agent.UUID))
1776// {
1777// m_log.DebugFormat(
1778// "[ENTITY TRANSFER MODULE]: User {0} is going to another region", agent.UUID);
1779// }
1780
1781 //m_log.Debug("AFTER CROSS");
1782 //Scene.DumpChildrenSeeds(UUID);
1783 //DumpKnownRegions();
1784
1785 return;
1220 } 1786 }
1221 1787
1222 private void CrossAgentToNewRegionCompleted(IAsyncResult iar) 1788 private void CrossAgentToNewRegionCompleted(IAsyncResult iar)
@@ -1256,7 +1822,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1256 agent.InventoryFolder = UUID.Zero; 1822 agent.InventoryFolder = UUID.Zero;
1257 agent.startpos = new Vector3(128, 128, 70); 1823 agent.startpos = new Vector3(128, 128, 70);
1258 agent.child = true; 1824 agent.child = true;
1259 agent.Appearance = sp.Appearance; 1825 agent.Appearance = new AvatarAppearance();
1826 agent.Appearance.PackLegacyWearables = true;
1260 agent.CapsPath = CapsUtil.GetRandomCapsObjectPath(); 1827 agent.CapsPath = CapsUtil.GetRandomCapsObjectPath();
1261 1828
1262 agent.ChildrenCapSeeds = new Dictionary<ulong, string>(sp.Scene.CapsModule.GetChildrenSeeds(sp.UUID)); 1829 agent.ChildrenCapSeeds = new Dictionary<ulong, string>(sp.Scene.CapsModule.GetChildrenSeeds(sp.UUID));
@@ -1270,7 +1837,15 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1270 //foreach (ulong h in agent.ChildrenCapSeeds.Keys) 1837 //foreach (ulong h in agent.ChildrenCapSeeds.Keys)
1271 // m_log.DebugFormat("[XXX] --> {0}", h); 1838 // m_log.DebugFormat("[XXX] --> {0}", h);
1272 //m_log.DebugFormat("[XXX] Adding {0}", region.RegionHandle); 1839 //m_log.DebugFormat("[XXX] Adding {0}", region.RegionHandle);
1273 agent.ChildrenCapSeeds.Add(region.RegionHandle, agent.CapsPath); 1840 if (agent.ChildrenCapSeeds.ContainsKey(region.RegionHandle))
1841 {
1842 m_log.WarnFormat(
1843 "[ENTITY TRANSFER]: Overwriting caps seed {0} with {1} for region {2} (handle {3}) for {4} in {5}",
1844 agent.ChildrenCapSeeds[region.RegionHandle], agent.CapsPath,
1845 region.RegionName, region.RegionHandle, sp.Name, Scene.Name);
1846 }
1847
1848 agent.ChildrenCapSeeds[region.RegionHandle] = agent.CapsPath;
1274 1849
1275 if (sp.Scene.CapsModule != null) 1850 if (sp.Scene.CapsModule != null)
1276 { 1851 {
@@ -1287,10 +1862,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1287 agent.Id0 = currentAgentCircuit.Id0; 1862 agent.Id0 = currentAgentCircuit.Id0;
1288 } 1863 }
1289 1864
1290 InformClientOfNeighbourDelegate d = InformClientOfNeighbourAsync; 1865 IPEndPoint external = region.ExternalEndPoint;
1291 d.BeginInvoke(sp, agent, region, region.ExternalEndPoint, true, 1866 if (external != null)
1867 {
1868 InformClientOfNeighbourDelegate d = InformClientOfNeighbourAsync;
1869 d.BeginInvoke(sp, agent, region, external, true,
1292 InformClientOfNeighbourCompleted, 1870 InformClientOfNeighbourCompleted,
1293 d); 1871 d);
1872 }
1294 } 1873 }
1295 #endregion 1874 #endregion
1296 1875
@@ -1310,7 +1889,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1310 1889
1311 if (m_regionInfo != null) 1890 if (m_regionInfo != null)
1312 { 1891 {
1313 neighbours = RequestNeighbours(sp, m_regionInfo.RegionLocX, m_regionInfo.RegionLocY); 1892 neighbours = GetNeighbours(sp, m_regionInfo.RegionLocX, m_regionInfo.RegionLocY);
1314 } 1893 }
1315 else 1894 else
1316 { 1895 {
@@ -1336,10 +1915,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1336 List<ulong> newRegions = NewNeighbours(neighbourHandles, previousRegionNeighbourHandles); 1915 List<ulong> newRegions = NewNeighbours(neighbourHandles, previousRegionNeighbourHandles);
1337 List<ulong> oldRegions = OldNeighbours(neighbourHandles, previousRegionNeighbourHandles); 1916 List<ulong> oldRegions = OldNeighbours(neighbourHandles, previousRegionNeighbourHandles);
1338 1917
1339 //Dump("Current Neighbors", neighbourHandles); 1918// Dump("Current Neighbors", neighbourHandles);
1340 //Dump("Previous Neighbours", previousRegionNeighbourHandles); 1919// Dump("Previous Neighbours", previousRegionNeighbourHandles);
1341 //Dump("New Neighbours", newRegions); 1920// Dump("New Neighbours", newRegions);
1342 //Dump("Old Neighbours", oldRegions); 1921// Dump("Old Neighbours", oldRegions);
1343 1922
1344 /// Update the scene presence's known regions here on this region 1923 /// Update the scene presence's known regions here on this region
1345 sp.DropOldNeighbours(oldRegions); 1924 sp.DropOldNeighbours(oldRegions);
@@ -1347,8 +1926,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1347 /// Collect as many seeds as possible 1926 /// Collect as many seeds as possible
1348 Dictionary<ulong, string> seeds; 1927 Dictionary<ulong, string> seeds;
1349 if (sp.Scene.CapsModule != null) 1928 if (sp.Scene.CapsModule != null)
1350 seeds 1929 seeds = new Dictionary<ulong, string>(sp.Scene.CapsModule.GetChildrenSeeds(sp.UUID));
1351 = new Dictionary<ulong, string>(sp.Scene.CapsModule.GetChildrenSeeds(sp.UUID));
1352 else 1930 else
1353 seeds = new Dictionary<ulong, string>(); 1931 seeds = new Dictionary<ulong, string>();
1354 1932
@@ -1368,7 +1946,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1368 agent.InventoryFolder = UUID.Zero; 1946 agent.InventoryFolder = UUID.Zero;
1369 agent.startpos = sp.AbsolutePosition + CalculateOffset(sp, neighbour); 1947 agent.startpos = sp.AbsolutePosition + CalculateOffset(sp, neighbour);
1370 agent.child = true; 1948 agent.child = true;
1371 agent.Appearance = sp.Appearance; 1949 agent.Appearance = new AvatarAppearance();
1950 agent.Appearance.PackLegacyWearables = true;
1372 if (currentAgentCircuit != null) 1951 if (currentAgentCircuit != null)
1373 { 1952 {
1374 agent.ServiceURLs = currentAgentCircuit.ServiceURLs; 1953 agent.ServiceURLs = currentAgentCircuit.ServiceURLs;
@@ -1418,6 +1997,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1418 newAgent = true; 1997 newAgent = true;
1419 else 1998 else
1420 newAgent = false; 1999 newAgent = false;
2000// continue;
1421 2001
1422 if (neighbour.RegionHandle != sp.Scene.RegionInfo.RegionHandle) 2002 if (neighbour.RegionHandle != sp.Scene.RegionInfo.RegionHandle)
1423 { 2003 {
@@ -1464,15 +2044,195 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1464 } 2044 }
1465 } 2045 }
1466 2046
2047 // Computes the difference between two region bases.
2048 // Returns a vector of world coordinates (meters) from base of first region to the second.
2049 // The first region is the home region of the passed scene presence.
1467 Vector3 CalculateOffset(ScenePresence sp, GridRegion neighbour) 2050 Vector3 CalculateOffset(ScenePresence sp, GridRegion neighbour)
1468 { 2051 {
1469 int rRegionX = (int)sp.Scene.RegionInfo.RegionLocX; 2052 /*
1470 int rRegionY = (int)sp.Scene.RegionInfo.RegionLocY; 2053 int rRegionX = (int)sp.Scene.RegionInfo.LegacyRegionLocX;
2054 int rRegionY = (int)sp.Scene.RegionInfo.LegacyRegionLocY;
1471 int tRegionX = neighbour.RegionLocX / (int)Constants.RegionSize; 2055 int tRegionX = neighbour.RegionLocX / (int)Constants.RegionSize;
1472 int tRegionY = neighbour.RegionLocY / (int)Constants.RegionSize; 2056 int tRegionY = neighbour.RegionLocY / (int)Constants.RegionSize;
1473 int shiftx = (rRegionX - tRegionX) * (int)Constants.RegionSize; 2057 int shiftx = (rRegionX - tRegionX) * (int)Constants.RegionSize;
1474 int shifty = (rRegionY - tRegionY) * (int)Constants.RegionSize; 2058 int shifty = (rRegionY - tRegionY) * (int)Constants.RegionSize;
1475 return new Vector3(shiftx, shifty, 0f); 2059 return new Vector3(shiftx, shifty, 0f);
2060 */
2061 return new Vector3( sp.Scene.RegionInfo.WorldLocX - neighbour.RegionLocX,
2062 sp.Scene.RegionInfo.WorldLocY - neighbour.RegionLocY,
2063 0f);
2064 }
2065
2066 public GridRegion GetRegionContainingWorldLocation(IGridService pGridService, UUID pScopeID, double px, double py)
2067 {
2068 // Since we don't know how big the regions could be, we have to search a very large area
2069 // to find possible regions.
2070 return GetRegionContainingWorldLocation(pGridService, pScopeID, px, py, Constants.MaximumRegionSize);
2071 }
2072
2073 #region NotFoundLocationCache class
2074 // A collection of not found locations to make future lookups 'not found' lookups quick.
2075 // A simple expiring cache that keeps not found locations for some number of seconds.
2076 // A 'not found' location is presumed to be anywhere in the minimum sized region that
2077 // contains that point. A conservitive estimate.
2078 private class NotFoundLocationCache
2079 {
2080 private struct NotFoundLocation
2081 {
2082 public double minX, maxX, minY, maxY;
2083 public DateTime expireTime;
2084 }
2085 private List<NotFoundLocation> m_notFoundLocations = new List<NotFoundLocation>();
2086 public NotFoundLocationCache()
2087 {
2088 }
2089 // Add an area to the list of 'not found' places. The area is the snapped region
2090 // area around the added point.
2091 public void Add(double pX, double pY)
2092 {
2093 lock (m_notFoundLocations)
2094 {
2095 if (!LockedContains(pX, pY))
2096 {
2097 NotFoundLocation nfl = new NotFoundLocation();
2098 // A not found location is not found for at least a whole region sized area
2099 nfl.minX = pX - (pX % (double)Constants.RegionSize);
2100 nfl.minY = pY - (pY % (double)Constants.RegionSize);
2101 nfl.maxX = nfl.minX + (double)Constants.RegionSize;
2102 nfl.maxY = nfl.minY + (double)Constants.RegionSize;
2103 nfl.expireTime = DateTime.Now + TimeSpan.FromSeconds(30);
2104 m_notFoundLocations.Add(nfl);
2105 }
2106 }
2107
2108 }
2109 // Test to see of this point is in any of the 'not found' areas.
2110 // Return 'true' if the point is found inside the 'not found' areas.
2111 public bool Contains(double pX, double pY)
2112 {
2113 bool ret = false;
2114 lock (m_notFoundLocations)
2115 ret = LockedContains(pX, pY);
2116 return ret;
2117 }
2118 private bool LockedContains(double pX, double pY)
2119 {
2120 bool ret = false;
2121 this.DoExpiration();
2122 foreach (NotFoundLocation nfl in m_notFoundLocations)
2123 {
2124 if (pX >= nfl.minX && pX < nfl.maxX && pY >= nfl.minY && pY < nfl.maxY)
2125 {
2126 ret = true;
2127 break;
2128 }
2129 }
2130 return ret;
2131 }
2132 private void DoExpiration()
2133 {
2134 List<NotFoundLocation> m_toRemove = null;
2135 DateTime now = DateTime.Now;
2136 foreach (NotFoundLocation nfl in m_notFoundLocations)
2137 {
2138 if (nfl.expireTime < now)
2139 {
2140 if (m_toRemove == null)
2141 m_toRemove = new List<NotFoundLocation>();
2142 m_toRemove.Add(nfl);
2143 }
2144 }
2145 if (m_toRemove != null)
2146 {
2147 foreach (NotFoundLocation nfl in m_toRemove)
2148 m_notFoundLocations.Remove(nfl);
2149 m_toRemove.Clear();
2150 }
2151 }
2152 }
2153 #endregion // NotFoundLocationCache class
2154 private NotFoundLocationCache m_notFoundLocationCache = new NotFoundLocationCache();
2155
2156 // Given a world position (fractional meter coordinate), get the GridRegion info for
2157 // the region containing that point.
2158 // Someday this should be a method on GridService.
2159 // 'pSizeHint' is the size of the source region but since the destination point can be anywhere
2160 // the size of the target region is unknown thus the search area might have to be very large.
2161 // Return 'null' if no such region exists.
2162 public GridRegion GetRegionContainingWorldLocation(IGridService pGridService, UUID pScopeID,
2163 double px, double py, uint pSizeHint)
2164 {
2165 m_log.DebugFormat("{0} GetRegionContainingWorldLocation: query, loc=<{1},{2}>", LogHeader, px, py);
2166 GridRegion ret = null;
2167 const double fudge = 2.0;
2168
2169 // One problem with this routine is negative results. That is, this can be called lots of times
2170 // for regions that don't exist. m_notFoundLocationCache remembers 'not found' results so they
2171 // will be quick 'not found's next time.
2172 // NotFoundLocationCache is an expiring cache so it will eventually forget about 'not found' and
2173 // thus re-ask the GridService about the location.
2174 if (m_notFoundLocationCache.Contains(px, py))
2175 {
2176 m_log.DebugFormat("{0} GetRegionContainingWorldLocation: Not found via cache. loc=<{1},{2}>", LogHeader, px, py);
2177 return null;
2178 }
2179
2180 // As an optimization, since most regions will be legacy sized regions (256x256), first try to get
2181 // the region at the appropriate legacy region location.
2182 uint possibleX = (uint)Math.Floor(px);
2183 possibleX -= possibleX % Constants.RegionSize;
2184 uint possibleY = (uint)Math.Floor(py);
2185 possibleY -= possibleY % Constants.RegionSize;
2186 ret = pGridService.GetRegionByPosition(pScopeID, (int)possibleX, (int)possibleY);
2187 if (ret != null)
2188 {
2189 m_log.DebugFormat("{0} GetRegionContainingWorldLocation: Found region using legacy size. rloc=<{1},{2}>. Rname={3}",
2190 LogHeader, possibleX, possibleY, ret.RegionName);
2191 }
2192
2193 if (ret == null)
2194 {
2195 // If the simple lookup failed, search the larger area for a region that contains this point
2196 double range = (double)pSizeHint + fudge;
2197 while (ret == null && range <= (Constants.MaximumRegionSize + Constants.RegionSize))
2198 {
2199 // Get from the grid service a list of regions that might contain this point.
2200 // The region origin will be in the zero direction so only subtract the range.
2201 List<GridRegion> possibleRegions = pGridService.GetRegionRange(pScopeID,
2202 (int)(px - range), (int)(px),
2203 (int)(py - range), (int)(py));
2204 m_log.DebugFormat("{0} GetRegionContainingWorldLocation: possibleRegions cnt={1}, range={2}",
2205 LogHeader, possibleRegions.Count, range);
2206 if (possibleRegions != null && possibleRegions.Count > 0)
2207 {
2208 // If we found some regions, check to see if the point is within
2209 foreach (GridRegion gr in possibleRegions)
2210 {
2211 m_log.DebugFormat("{0} GetRegionContainingWorldLocation: possibleRegion nm={1}, regionLoc=<{2},{3}>, regionSize=<{4},{5}>",
2212 LogHeader, gr.RegionName, gr.RegionLocX, gr.RegionLocY, gr.RegionSizeX, gr.RegionSizeY);
2213 if (px >= (double)gr.RegionLocX && px < (double)(gr.RegionLocX + gr.RegionSizeX)
2214 && py >= (double)gr.RegionLocY && py < (double)(gr.RegionLocY + gr.RegionSizeY))
2215 {
2216 // Found a region that contains the point
2217 ret = gr;
2218 m_log.DebugFormat("{0} GetRegionContainingWorldLocation: found. RegionName={1}", LogHeader, ret.RegionName);
2219 break;
2220 }
2221 }
2222 }
2223 // Larger search area for next time around if not found
2224 range *= 2;
2225 }
2226 }
2227
2228 if (ret == null)
2229 {
2230 // remember this location was not found so we can quickly not find it next time
2231 m_notFoundLocationCache.Add(px, py);
2232 m_log.DebugFormat("{0} GetRegionContainingWorldLocation: Not found. Remembering loc=<{1},{2}>", LogHeader, px, py);
2233 }
2234
2235 return ret;
1476 } 2236 }
1477 2237
1478 private void InformClientOfNeighbourCompleted(IAsyncResult iar) 2238 private void InformClientOfNeighbourCompleted(IAsyncResult iar)
@@ -1500,7 +2260,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1500 Thread.Sleep(500); 2260 Thread.Sleep(500);
1501 2261
1502 Scene scene = sp.Scene; 2262 Scene scene = sp.Scene;
1503 2263
1504 m_log.DebugFormat( 2264 m_log.DebugFormat(
1505 "[ENTITY TRANSFER MODULE]: Informing {0} {1} about neighbour {2} {3} at ({4},{5})", 2265 "[ENTITY TRANSFER MODULE]: Informing {0} {1} about neighbour {2} {3} at ({4},{5})",
1506 sp.Name, sp.UUID, reg.RegionName, endPoint, reg.RegionCoordX, reg.RegionCoordY); 2266 sp.Name, sp.UUID, reg.RegionName, endPoint, reg.RegionCoordX, reg.RegionCoordY);
@@ -1509,7 +2269,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1509 2269
1510 string reason = String.Empty; 2270 string reason = String.Empty;
1511 2271
1512 bool regionAccepted = scene.SimulationService.CreateAgent(reg, a, (uint)TeleportFlags.Default, out reason); 2272 bool regionAccepted = scene.SimulationService.CreateAgent(null, reg, a, (uint)TeleportFlags.Default, out reason);
1513 2273
1514 if (regionAccepted && newAgent) 2274 if (regionAccepted && newAgent)
1515 { 2275 {
@@ -1523,12 +2283,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1523 } 2283 }
1524 #endregion 2284 #endregion
1525 2285
1526 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: {0} is sending {1} EnableSimulator for neighbour region {2} @ {3} " + 2286 m_log.DebugFormat("{0} {1} is sending {2} EnableSimulator for neighbour region {3}(loc=<{4},{5}>,siz=<{6},{7}>) " +
1527 "and EstablishAgentCommunication with seed cap {4}", 2287 "and EstablishAgentCommunication with seed cap {8}", LogHeader,
1528 scene.RegionInfo.RegionName, sp.Name, reg.RegionName, reg.RegionHandle, capsPath); 2288 scene.RegionInfo.RegionName, sp.Name,
2289 reg.RegionName, reg.RegionLocX, reg.RegionLocY, reg.RegionSizeX, reg.RegionSizeY , capsPath);
1529 2290
1530 m_eqModule.EnableSimulator(reg.RegionHandle, endPoint, sp.UUID); 2291 m_eqModule.EnableSimulator(reg.RegionHandle, endPoint, sp.UUID, reg.RegionSizeX, reg.RegionSizeY);
1531 m_eqModule.EstablishAgentCommunication(sp.UUID, endPoint, capsPath); 2292 m_eqModule.EstablishAgentCommunication(sp.UUID, endPoint, capsPath, reg.RegionHandle, reg.RegionSizeX, reg.RegionSizeY);
1532 } 2293 }
1533 else 2294 else
1534 { 2295 {
@@ -1546,68 +2307,86 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1546 } 2307 }
1547 2308
1548 /// <summary> 2309 /// <summary>
1549 /// Return the list of regions that are considered to be neighbours to the given scene. 2310 /// Gets the range considered in view of this megaregion (assuming this is a megaregion).
2311 /// </summary>
2312 /// <remarks>Expressed in 256m units</remarks>
2313 /// <param name='swCorner'></param>
2314 /// <param name='neCorner'></param>
2315 private void GetMegaregionViewRange(out Vector2 swCorner, out Vector2 neCorner)
2316 {
2317 Vector2 extent = Vector2.Zero;
2318
2319 if (m_regionCombinerModule != null)
2320 {
2321 Vector2 megaRegionSize = m_regionCombinerModule.GetSizeOfMegaregion(Scene.RegionInfo.RegionID);
2322 extent.X = (float)Util.WorldToRegionLoc((uint)megaRegionSize.X);
2323 extent.Y = (float)Util.WorldToRegionLoc((uint)megaRegionSize.Y);
2324 }
2325
2326 swCorner.X = Scene.RegionInfo.RegionLocX - 1;
2327 swCorner.Y = Scene.RegionInfo.RegionLocY - 1;
2328 neCorner.X = Scene.RegionInfo.RegionLocX + extent.X;
2329 neCorner.Y = Scene.RegionInfo.RegionLocY + extent.Y;
2330 }
2331
2332 /// <summary>
2333 /// Return the list of online regions that are considered to be neighbours to the given scene.
1550 /// </summary> 2334 /// </summary>
1551 /// <param name="pScene"></param> 2335 /// <param name="avatar"></param>
1552 /// <param name="pRegionLocX"></param> 2336 /// <param name="pRegionLocX"></param>
1553 /// <param name="pRegionLocY"></param> 2337 /// <param name="pRegionLocY"></param>
1554 /// <returns></returns> 2338 /// <returns></returns>
1555 protected List<GridRegion> RequestNeighbours(ScenePresence avatar, uint pRegionLocX, uint pRegionLocY) 2339 protected List<GridRegion> GetNeighbours(ScenePresence avatar, uint pRegionLocX, uint pRegionLocY)
1556 { 2340 {
1557 Scene pScene = avatar.Scene; 2341 Scene pScene = avatar.Scene;
1558 RegionInfo m_regionInfo = pScene.RegionInfo; 2342 RegionInfo m_regionInfo = pScene.RegionInfo;
1559 2343 List<GridRegion> neighbours;
1560 Border[] northBorders = pScene.NorthBorders.ToArray();
1561 Border[] southBorders = pScene.SouthBorders.ToArray();
1562 Border[] eastBorders = pScene.EastBorders.ToArray();
1563 Border[] westBorders = pScene.WestBorders.ToArray();
1564 2344
1565 // Leaving this as a "megaregions" computation vs "non-megaregions" computation; it isn't 2345 // Leaving this as a "megaregions" computation vs "non-megaregions" computation; it isn't
1566 // clear what should be done with a "far view" given that megaregions already extended the 2346 // clear what should be done with a "far view" given that megaregions already extended the
1567 // view to include everything in the megaregion 2347 // view to include everything in the megaregion
1568 if (northBorders.Length <= 1 && southBorders.Length <= 1 && eastBorders.Length <= 1 && westBorders.Length <= 1) 2348 if (m_regionCombinerModule == null || !m_regionCombinerModule.IsRootForMegaregion(Scene.RegionInfo.RegionID))
1569 { 2349 {
1570 int dd = avatar.DrawDistance < Constants.RegionSize ? (int)Constants.RegionSize : (int)avatar.DrawDistance; 2350 // The area to check is as big as the current region.
1571 2351 // We presume all adjacent regions are the same size as this region.
1572 int startX = (int)pRegionLocX * (int)Constants.RegionSize - dd + (int)(Constants.RegionSize/2); 2352 uint dd = Math.Max((uint)avatar.Scene.DefaultDrawDistance,
1573 int startY = (int)pRegionLocY * (int)Constants.RegionSize - dd + (int)(Constants.RegionSize/2); 2353 Math.Max(Scene.RegionInfo.RegionSizeX, Scene.RegionInfo.RegionSizeY));
1574 2354
1575 int endX = (int)pRegionLocX * (int)Constants.RegionSize + dd + (int)(Constants.RegionSize/2); 2355 uint startX = Util.RegionToWorldLoc(pRegionLocX) - dd + Constants.RegionSize/2;
1576 int endY = (int)pRegionLocY * (int)Constants.RegionSize + dd + (int)(Constants.RegionSize/2); 2356 uint startY = Util.RegionToWorldLoc(pRegionLocY) - dd + Constants.RegionSize/2;
1577 2357
1578 List<GridRegion> neighbours = 2358 uint endX = Util.RegionToWorldLoc(pRegionLocX) + dd + Constants.RegionSize/2;
1579 avatar.Scene.GridService.GetRegionRange(m_regionInfo.ScopeID, startX, endX, startY, endY); 2359 uint endY = Util.RegionToWorldLoc(pRegionLocY) + dd + Constants.RegionSize/2;
1580 2360
1581 neighbours.RemoveAll(delegate(GridRegion r) { return r.RegionID == m_regionInfo.RegionID; }); 2361 neighbours
1582 return neighbours; 2362 = avatar.Scene.GridService.GetRegionRange(
2363 m_regionInfo.ScopeID, (int)startX, (int)endX, (int)startY, (int)endY);
1583 } 2364 }
1584 else 2365 else
1585 { 2366 {
1586 Vector2 extent = Vector2.Zero; 2367 Vector2 swCorner, neCorner;
1587 for (int i = 0; i < eastBorders.Length; i++) 2368 GetMegaregionViewRange(out swCorner, out neCorner);
1588 {
1589 extent.X = (eastBorders[i].BorderLine.Z > extent.X) ? eastBorders[i].BorderLine.Z : extent.X;
1590 }
1591 for (int i = 0; i < northBorders.Length; i++)
1592 {
1593 extent.Y = (northBorders[i].BorderLine.Z > extent.Y) ? northBorders[i].BorderLine.Z : extent.Y;
1594 }
1595 2369
1596 // Loss of fraction on purpose 2370 neighbours
1597 extent.X = ((int)extent.X / (int)Constants.RegionSize) + 1; 2371 = pScene.GridService.GetRegionRange(
1598 extent.Y = ((int)extent.Y / (int)Constants.RegionSize) + 1; 2372 m_regionInfo.ScopeID,
1599 2373 (int)Util.RegionToWorldLoc((uint)swCorner.X), (int)Util.RegionToWorldLoc((uint)neCorner.X),
1600 int startX = (int)(pRegionLocX - 1) * (int)Constants.RegionSize; 2374 (int)Util.RegionToWorldLoc((uint)swCorner.Y), (int)Util.RegionToWorldLoc((uint)neCorner.Y));
1601 int startY = (int)(pRegionLocY - 1) * (int)Constants.RegionSize; 2375 }
1602 2376
1603 int endX = ((int)pRegionLocX + (int)extent.X) * (int)Constants.RegionSize; 2377// neighbours.ForEach(
1604 int endY = ((int)pRegionLocY + (int)extent.Y) * (int)Constants.RegionSize; 2378// n =>
2379// m_log.DebugFormat(
2380// "[ENTITY TRANSFER MODULE]: Region flags for {0} as seen by {1} are {2}",
2381// n.RegionName, Scene.Name, n.RegionFlags != null ? n.RegionFlags.ToString() : "not present"));
1605 2382
1606 List<GridRegion> neighbours = pScene.GridService.GetRegionRange(m_regionInfo.ScopeID, startX, endX, startY, endY); 2383 // The r.RegionFlags == null check only needs to be made for simulators before 2015-01-14 (pre 0.8.1).
1607 neighbours.RemoveAll(delegate(GridRegion r) { return r.RegionID == m_regionInfo.RegionID; }); 2384 neighbours.RemoveAll(
2385 r =>
2386 r.RegionID == m_regionInfo.RegionID
2387 || (r.RegionFlags != null && (r.RegionFlags & OpenSim.Framework.RegionFlags.RegionOnline) == 0));
1608 2388
1609 return neighbours; 2389 return neighbours;
1610 }
1611 } 2390 }
1612 2391
1613 private List<ulong> NewNeighbours(List<ulong> currentNeighbours, List<ulong> previousNeighbours) 2392 private List<ulong> NewNeighbours(List<ulong> currentNeighbours, List<ulong> previousNeighbours)
@@ -1665,10 +2444,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1665 /// Move the given scene object into a new region depending on which region its absolute position has moved 2444 /// Move the given scene object into a new region depending on which region its absolute position has moved
1666 /// into. 2445 /// into.
1667 /// 2446 ///
1668 /// This method locates the new region handle and offsets the prim position for the new region 2447 /// Using the objects new world location, ask the grid service for a the new region and adjust the prim
2448 /// position to be relative to the new region.
1669 /// </summary> 2449 /// </summary>
1670 /// <param name="attemptedPosition">the attempted out of region position of the scene object</param>
1671 /// <param name="grp">the scene object that we're crossing</param> 2450 /// <param name="grp">the scene object that we're crossing</param>
2451 /// <param name="attemptedPosition">the attempted out of region position of the scene object. This position is
2452 /// relative to the region the object currently is in.</param>
2453 /// <param name="silent">if 'true', the deletion of the client from the region is not broadcast to the clients</param>
1672 public void Cross(SceneObjectGroup grp, Vector3 attemptedPosition, bool silent) 2454 public void Cross(SceneObjectGroup grp, Vector3 attemptedPosition, bool silent)
1673 { 2455 {
1674 if (grp == null) 2456 if (grp == null)
@@ -1694,204 +2476,49 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1694 return; 2476 return;
1695 } 2477 }
1696 2478
1697 int thisx = (int)scene.RegionInfo.RegionLocX; 2479 // Remember the old group position in case the region lookup fails so position can be restored.
1698 int thisy = (int)scene.RegionInfo.RegionLocY; 2480 Vector3 oldGroupPosition = grp.RootPart.GroupPosition;
1699 Vector3 EastCross = new Vector3(0.1f, 0, 0);
1700 Vector3 WestCross = new Vector3(-0.1f, 0, 0);
1701 Vector3 NorthCross = new Vector3(0, 0.1f, 0);
1702 Vector3 SouthCross = new Vector3(0, -0.1f, 0);
1703
1704
1705 // use this if no borders were crossed!
1706 ulong newRegionHandle
1707 = Util.UIntsToLong((uint)((thisx) * Constants.RegionSize),
1708 (uint)((thisy) * Constants.RegionSize));
1709
1710 Vector3 pos = attemptedPosition;
1711
1712 int changeX = 1;
1713 int changeY = 1;
1714
1715 if (scene.TestBorderCross(attemptedPosition + WestCross, Cardinals.W))
1716 {
1717 if (scene.TestBorderCross(attemptedPosition + SouthCross, Cardinals.S))
1718 {
1719
1720 Border crossedBorderx = scene.GetCrossedBorder(attemptedPosition + WestCross, Cardinals.W);
1721
1722 if (crossedBorderx.BorderLine.Z > 0)
1723 {
1724 pos.X = ((pos.X + crossedBorderx.BorderLine.Z));
1725 changeX = (int)(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize);
1726 }
1727 else
1728 pos.X = ((pos.X + Constants.RegionSize));
1729
1730 Border crossedBordery = scene.GetCrossedBorder(attemptedPosition + SouthCross, Cardinals.S);
1731 //(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize)
1732
1733 if (crossedBordery.BorderLine.Z > 0)
1734 {
1735 pos.Y = ((pos.Y + crossedBordery.BorderLine.Z));
1736 changeY = (int)(crossedBordery.BorderLine.Z / (int)Constants.RegionSize);
1737 }
1738 else
1739 pos.Y = ((pos.Y + Constants.RegionSize));
1740
1741
1742
1743 newRegionHandle
1744 = Util.UIntsToLong((uint)((thisx - changeX) * Constants.RegionSize),
1745 (uint)((thisy - changeY) * Constants.RegionSize));
1746 // x - 1
1747 // y - 1
1748 }
1749 else if (scene.TestBorderCross(attemptedPosition + NorthCross, Cardinals.N))
1750 {
1751 Border crossedBorderx = scene.GetCrossedBorder(attemptedPosition + WestCross, Cardinals.W);
1752
1753 if (crossedBorderx.BorderLine.Z > 0)
1754 {
1755 pos.X = ((pos.X + crossedBorderx.BorderLine.Z));
1756 changeX = (int)(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize);
1757 }
1758 else
1759 pos.X = ((pos.X + Constants.RegionSize));
1760
1761
1762 Border crossedBordery = scene.GetCrossedBorder(attemptedPosition + SouthCross, Cardinals.S);
1763 //(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize)
1764
1765 if (crossedBordery.BorderLine.Z > 0)
1766 {
1767 pos.Y = ((pos.Y + crossedBordery.BorderLine.Z));
1768 changeY = (int)(crossedBordery.BorderLine.Z / (int)Constants.RegionSize);
1769 }
1770 else
1771 pos.Y = ((pos.Y + Constants.RegionSize));
1772
1773 newRegionHandle
1774 = Util.UIntsToLong((uint)((thisx - changeX) * Constants.RegionSize),
1775 (uint)((thisy + changeY) * Constants.RegionSize));
1776 // x - 1
1777 // y + 1
1778 }
1779 else
1780 {
1781 Border crossedBorderx = scene.GetCrossedBorder(attemptedPosition + WestCross, Cardinals.W);
1782
1783 if (crossedBorderx.BorderLine.Z > 0)
1784 {
1785 pos.X = ((pos.X + crossedBorderx.BorderLine.Z));
1786 changeX = (int)(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize);
1787 }
1788 else
1789 pos.X = ((pos.X + Constants.RegionSize));
1790
1791 newRegionHandle
1792 = Util.UIntsToLong((uint)((thisx - changeX) * Constants.RegionSize),
1793 (uint)(thisy * Constants.RegionSize));
1794 // x - 1
1795 }
1796 }
1797 else if (scene.TestBorderCross(attemptedPosition + EastCross, Cardinals.E))
1798 {
1799 if (scene.TestBorderCross(attemptedPosition + SouthCross, Cardinals.S))
1800 {
1801
1802 pos.X = ((pos.X - Constants.RegionSize));
1803 Border crossedBordery = scene.GetCrossedBorder(attemptedPosition + SouthCross, Cardinals.S);
1804 //(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize)
1805
1806 if (crossedBordery.BorderLine.Z > 0)
1807 {
1808 pos.Y = ((pos.Y + crossedBordery.BorderLine.Z));
1809 changeY = (int)(crossedBordery.BorderLine.Z / (int)Constants.RegionSize);
1810 }
1811 else
1812 pos.Y = ((pos.Y + Constants.RegionSize));
1813
1814 2481
1815 newRegionHandle 2482 // Compute the absolute position of the object.
1816 = Util.UIntsToLong((uint)((thisx + changeX) * Constants.RegionSize), 2483 double objectWorldLocX = (double)scene.RegionInfo.WorldLocX + attemptedPosition.X;
1817 (uint)((thisy - changeY) * Constants.RegionSize)); 2484 double objectWorldLocY = (double)scene.RegionInfo.WorldLocY + attemptedPosition.Y;
1818 // x + 1
1819 // y - 1
1820 }
1821 else if (scene.TestBorderCross(attemptedPosition + NorthCross, Cardinals.N))
1822 {
1823 pos.X = ((pos.X - Constants.RegionSize));
1824 pos.Y = ((pos.Y - Constants.RegionSize));
1825 newRegionHandle
1826 = Util.UIntsToLong((uint)((thisx + changeX) * Constants.RegionSize),
1827 (uint)((thisy + changeY) * Constants.RegionSize));
1828 // x + 1
1829 // y + 1
1830 }
1831 else
1832 {
1833 pos.X = ((pos.X - Constants.RegionSize));
1834 newRegionHandle
1835 = Util.UIntsToLong((uint)((thisx + changeX) * Constants.RegionSize),
1836 (uint)(thisy * Constants.RegionSize));
1837 // x + 1
1838 }
1839 }
1840 else if (scene.TestBorderCross(attemptedPosition + SouthCross, Cardinals.S))
1841 {
1842 Border crossedBordery = scene.GetCrossedBorder(attemptedPosition + SouthCross, Cardinals.S);
1843 //(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize)
1844 2485
1845 if (crossedBordery.BorderLine.Z > 0) 2486 // Ask the grid service for the region that contains the passed address
1846 { 2487 GridRegion destination = GetRegionContainingWorldLocation(scene.GridService, scene.RegionInfo.ScopeID,
1847 pos.Y = ((pos.Y + crossedBordery.BorderLine.Z)); 2488 objectWorldLocX, objectWorldLocY);
1848 changeY = (int)(crossedBordery.BorderLine.Z / (int)Constants.RegionSize);
1849 }
1850 else
1851 pos.Y = ((pos.Y + Constants.RegionSize));
1852 2489
1853 newRegionHandle 2490 Vector3 pos = Vector3.Zero;
1854 = Util.UIntsToLong((uint)(thisx * Constants.RegionSize), (uint)((thisy - changeY) * Constants.RegionSize)); 2491 if (destination != null)
1855 // y - 1
1856 }
1857 else if (scene.TestBorderCross(attemptedPosition + NorthCross, Cardinals.N))
1858 { 2492 {
1859 2493 // Adjust the object's relative position from the old region (attemptedPosition)
1860 pos.Y = ((pos.Y - Constants.RegionSize)); 2494 // to be relative to the new region (pos).
1861 newRegionHandle 2495 pos = new Vector3( (float)(objectWorldLocX - (double)destination.RegionLocX),
1862 = Util.UIntsToLong((uint)(thisx * Constants.RegionSize), (uint)((thisy + changeY) * Constants.RegionSize)); 2496 (float)(objectWorldLocY - (double)destination.RegionLocY),
1863 // y + 1 2497 attemptedPosition.Z);
1864 } 2498 }
1865 2499
1866 // Offset the positions for the new region across the border
1867 Vector3 oldGroupPosition = grp.RootPart.GroupPosition;
1868
1869 // If we fail to cross the border, then reset the position of the scene object on that border.
1870 uint x = 0, y = 0;
1871 Utils.LongToUInts(newRegionHandle, out x, out y);
1872 GridRegion destination = scene.GridService.GetRegionByPosition(scene.RegionInfo.ScopeID, (int)x, (int)y);
1873
1874 if (destination == null || !CrossPrimGroupIntoNewRegion(destination, pos, grp, silent)) 2500 if (destination == null || !CrossPrimGroupIntoNewRegion(destination, pos, grp, silent))
1875 { 2501 {
1876 m_log.InfoFormat("[ENTITY TRANSFER MODULE] cross region transfer failed for object {0}",grp.UUID); 2502 m_log.InfoFormat("[ENTITY TRANSFER MODULE] cross region transfer failed for object {0}", grp.UUID);
1877 2503
1878 // We are going to move the object back to the old position so long as the old position 2504 // We are going to move the object back to the old position so long as the old position
1879 // is in the region 2505 // is in the region
1880 oldGroupPosition.X = Util.Clamp<float>(oldGroupPosition.X,1.0f,(float)Constants.RegionSize-1); 2506 oldGroupPosition.X = Util.Clamp<float>(oldGroupPosition.X, 1.0f, (float)(scene.RegionInfo.RegionSizeX - 1));
1881 oldGroupPosition.Y = Util.Clamp<float>(oldGroupPosition.Y,1.0f,(float)Constants.RegionSize-1); 2507 oldGroupPosition.Y = Util.Clamp<float>(oldGroupPosition.Y, 1.0f, (float)(scene.RegionInfo.RegionSizeY - 1));
1882 oldGroupPosition.Z = Util.Clamp<float>(oldGroupPosition.Z,1.0f,4096.0f); 2508 oldGroupPosition.Z = Util.Clamp<float>(oldGroupPosition.Z, 1.0f, Constants.RegionHeight);
1883 2509
1884 grp.RootPart.GroupPosition = oldGroupPosition; 2510 grp.AbsolutePosition = oldGroupPosition;
2511 grp.Velocity = Vector3.Zero;
2512 if (grp.RootPart.PhysActor != null)
2513 grp.RootPart.PhysActor.CrossingFailure();
1885 2514
1886 // Need to turn off the physics flags, otherwise the object will continue to attempt to 2515 if (grp.RootPart.KeyframeMotion != null)
1887 // move out of the region creating an infinite loop of failed attempts to cross 2516 grp.RootPart.KeyframeMotion.CrossingFailure();
1888 grp.UpdatePrimFlags(grp.RootPart.LocalId,false,grp.IsTemporary,grp.IsPhantom,false);
1889 2517
1890 grp.ScheduleGroupForFullUpdate(); 2518 grp.ScheduleGroupForFullUpdate();
1891 } 2519 }
1892 } 2520 }
1893 2521
1894
1895 /// <summary> 2522 /// <summary>
1896 /// Move the given scene object into a new region 2523 /// Move the given scene object into a new region
1897 /// </summary> 2524 /// </summary>
@@ -1942,17 +2569,30 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1942 grp, e); 2569 grp, e);
1943 } 2570 }
1944 } 2571 }
2572/*
2573 * done on caller ( not in attachments crossing for now)
1945 else 2574 else
1946 { 2575 {
2576
1947 if (!grp.IsDeleted) 2577 if (!grp.IsDeleted)
1948 { 2578 {
1949 PhysicsActor pa = grp.RootPart.PhysActor; 2579 PhysicsActor pa = grp.RootPart.PhysActor;
1950 if (pa != null) 2580 if (pa != null)
2581 {
1951 pa.CrossingFailure(); 2582 pa.CrossingFailure();
2583 if (grp.RootPart.KeyframeMotion != null)
2584 {
2585 // moved to KeyframeMotion.CrossingFailure
2586// grp.RootPart.Velocity = Vector3.Zero;
2587 grp.RootPart.KeyframeMotion.CrossingFailure();
2588// grp.SendGroupRootTerseUpdate();
2589 }
2590 }
1952 } 2591 }
1953 2592
1954 m_log.ErrorFormat("[ENTITY TRANSFER MODULE]: Prim crossing failed for {0}", grp); 2593 m_log.ErrorFormat("[ENTITY TRANSFER MODULE]: Prim crossing failed for {0}", grp);
1955 } 2594 }
2595 */
1956 } 2596 }
1957 else 2597 else
1958 { 2598 {
@@ -2007,7 +2647,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
2007 2647
2008 public bool IsInTransit(UUID id) 2648 public bool IsInTransit(UUID id)
2009 { 2649 {
2010 return m_entityTransferStateMachine.IsInTransit(id); 2650 return m_entityTransferStateMachine.GetAgentTransferState(id) != null;
2011 } 2651 }
2012 2652
2013 protected void ReInstantiateScripts(ScenePresence sp) 2653 protected void ReInstantiateScripts(ScenePresence sp)
@@ -2036,5 +2676,69 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
2036 } 2676 }
2037 #endregion 2677 #endregion
2038 2678
2679 public virtual bool HandleIncomingSceneObject(SceneObjectGroup so, Vector3 newPosition)
2680 {
2681 // If the user is banned, we won't let any of their objects
2682 // enter. Period.
2683 //
2684 if (Scene.RegionInfo.EstateSettings.IsBanned(so.OwnerID))
2685 {
2686 m_log.DebugFormat(
2687 "[ENTITY TRANSFER MODULE]: Denied prim crossing of {0} {1} into {2} for banned avatar {3}",
2688 so.Name, so.UUID, Scene.Name, so.OwnerID);
2689
2690 return false;
2691 }
2692
2693 if (newPosition != Vector3.Zero)
2694 so.RootPart.GroupPosition = newPosition;
2695
2696 if (!Scene.AddSceneObject(so))
2697 {
2698 m_log.DebugFormat(
2699 "[ENTITY TRANSFER MODULE]: Problem adding scene object {0} {1} into {2} ",
2700 so.Name, so.UUID, Scene.Name);
2701
2702 return false;
2703 }
2704
2705 if (!so.IsAttachment)
2706 {
2707 // FIXME: It would be better to never add the scene object at all rather than add it and then delete
2708 // it
2709 if (!Scene.Permissions.CanObjectEntry(so.UUID, true, so.AbsolutePosition))
2710 {
2711 // Deny non attachments based on parcel settings
2712 //
2713 m_log.Info("[ENTITY TRANSFER MODULE]: Denied prim crossing because of parcel settings");
2714
2715 Scene.DeleteSceneObject(so, false);
2716
2717 return false;
2718 }
2719
2720 // For attachments, we need to wait until the agent is root
2721 // before we restart the scripts, or else some functions won't work.
2722 so.RootPart.ParentGroup.CreateScriptInstances(
2723 0, false, Scene.DefaultScriptEngine, GetStateSource(so));
2724
2725 so.ResumeScripts();
2726
2727 if (so.RootPart.KeyframeMotion != null)
2728 so.RootPart.KeyframeMotion.UpdateSceneObject(so);
2729 }
2730
2731 return true;
2732 }
2733
2734 private int GetStateSource(SceneObjectGroup sog)
2735 {
2736 ScenePresence sp = Scene.GetScenePresence(sog.OwnerID);
2737
2738 if (sp != null)
2739 return sp.GetStateSource();
2740
2741 return 2; // StateSource.PrimCrossing
2742 }
2039 } 2743 }
2040} \ No newline at end of file 2744}
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs
index d0cab49..a3109e0 100644
--- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs
+++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs
@@ -38,7 +38,7 @@ using OpenSim.Framework.Capabilities;
38using OpenSim.Framework.Client; 38using OpenSim.Framework.Client;
39using OpenSim.Region.Framework.Interfaces; 39using OpenSim.Region.Framework.Interfaces;
40using OpenSim.Region.Framework.Scenes; 40using OpenSim.Region.Framework.Scenes;
41using OpenSim.Region.Physics.Manager; 41using OpenSim.Region.PhysicsModules.SharedBase;
42using OpenSim.Services.Interfaces; 42using OpenSim.Services.Interfaces;
43using GridRegion = OpenSim.Services.Interfaces.GridRegion; 43using GridRegion = OpenSim.Services.Interfaces.GridRegion;
44 44
@@ -51,10 +51,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
51 /// This is a state machine. 51 /// This is a state machine.
52 /// 52 ///
53 /// [Entry] => Preparing 53 /// [Entry] => Preparing
54 /// Preparing => { Transferring || CleaningUp || [Exit] } 54 /// Preparing => { Transferring || Cancelling || CleaningUp || Aborting || [Exit] }
55 /// Transferring => { ReceivedAtDestination || CleaningUp } 55 /// Transferring => { ReceivedAtDestination || Cancelling || CleaningUp || Aborting }
56 /// ReceivedAtDestination => CleaningUp 56 /// Cancelling => CleaningUp || Aborting
57 /// ReceivedAtDestination => CleaningUp || Aborting
57 /// CleaningUp => [Exit] 58 /// CleaningUp => [Exit]
59 /// Aborting => [Exit]
58 /// 60 ///
59 /// In other words, agents normally travel throwing Preparing => Transferring => ReceivedAtDestination => CleaningUp 61 /// In other words, agents normally travel throwing Preparing => Transferring => ReceivedAtDestination => CleaningUp
60 /// However, any state can transition to CleaningUp if the teleport has failed. 62 /// However, any state can transition to CleaningUp if the teleport has failed.
@@ -64,7 +66,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
64 Preparing, // The agent is being prepared for transfer 66 Preparing, // The agent is being prepared for transfer
65 Transferring, // The agent is in the process of being transferred to a destination 67 Transferring, // The agent is in the process of being transferred to a destination
66 ReceivedAtDestination, // The destination has notified us that the agent has been successfully received 68 ReceivedAtDestination, // The destination has notified us that the agent has been successfully received
67 CleaningUp // The agent is being changed to child/removed after a transfer 69 CleaningUp, // The agent is being changed to child/removed after a transfer
70 Cancelling, // The user has cancelled the teleport but we have yet to act upon this.
71 Aborting // The transfer is aborting. Unlike Cancelling, no compensating actions should be performed
68 } 72 }
69 73
70 /// <summary> 74 /// <summary>
@@ -73,6 +77,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
73 public class EntityTransferStateMachine 77 public class EntityTransferStateMachine
74 { 78 {
75 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 79 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
80 private static readonly string LogHeader = "[ENTITY TRANSFER STATE MACHINE]";
76 81
77 /// <summary> 82 /// <summary>
78 /// If true then on a teleport, the source region waits for a callback from the destination region. If 83 /// If true then on a teleport, the source region waits for a callback from the destination region. If
@@ -96,6 +101,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
96 /// <returns>true if the agent was not already in transit, false if it was</returns> 101 /// <returns>true if the agent was not already in transit, false if it was</returns>
97 internal bool SetInTransit(UUID id) 102 internal bool SetInTransit(UUID id)
98 { 103 {
104 m_log.DebugFormat("{0} SetInTransit. agent={1}, newState=Preparing", LogHeader, id);
99 lock (m_agentsInTransit) 105 lock (m_agentsInTransit)
100 { 106 {
101 if (!m_agentsInTransit.ContainsKey(id)) 107 if (!m_agentsInTransit.ContainsKey(id))
@@ -115,42 +121,117 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
115 /// <param name='newState'></param> 121 /// <param name='newState'></param>
116 /// <returns></returns> 122 /// <returns></returns>
117 /// <exception cref='Exception'>Illegal transitions will throw an Exception</exception> 123 /// <exception cref='Exception'>Illegal transitions will throw an Exception</exception>
118 internal void UpdateInTransit(UUID id, AgentTransferState newState) 124 internal bool UpdateInTransit(UUID id, AgentTransferState newState)
119 { 125 {
126 m_log.DebugFormat("{0} UpdateInTransit. agent={1}, newState={2}", LogHeader, id, newState);
127
128 bool transitionOkay = false;
129
130 // We don't want to throw an exception on cancel since this can come it at any time.
131 bool failIfNotOkay = true;
132
133 // Should be a failure message if failure is not okay.
134 string failureMessage = null;
135
136 AgentTransferState? oldState = null;
137
120 lock (m_agentsInTransit) 138 lock (m_agentsInTransit)
121 { 139 {
122 // Illegal to try and update an agent that's not actually in transit. 140 // Illegal to try and update an agent that's not actually in transit.
123 if (!m_agentsInTransit.ContainsKey(id)) 141 if (!m_agentsInTransit.ContainsKey(id))
124 throw new Exception( 142 {
125 string.Format( 143 if (newState != AgentTransferState.Cancelling && newState != AgentTransferState.Aborting)
126 "Agent with ID {0} is not registered as in transit in {1}", 144 failureMessage = string.Format(
127 id, m_mod.Scene.RegionInfo.RegionName)); 145 "Agent with ID {0} is not registered as in transit in {1}",
128 146 id, m_mod.Scene.RegionInfo.RegionName);
129 AgentTransferState oldState = m_agentsInTransit[id]; 147 else
148 failIfNotOkay = false;
149 }
150 else
151 {
152 oldState = m_agentsInTransit[id];
130 153
131 bool transitionOkay = false; 154 if (newState == AgentTransferState.Aborting)
155 {
156 transitionOkay = true;
157 }
158 else if (newState == AgentTransferState.CleaningUp && oldState != AgentTransferState.CleaningUp)
159 {
160 transitionOkay = true;
161 }
162 else if (newState == AgentTransferState.Transferring && oldState == AgentTransferState.Preparing)
163 {
164 transitionOkay = true;
165 }
166 else if (newState == AgentTransferState.ReceivedAtDestination && oldState == AgentTransferState.Transferring)
167 {
168 transitionOkay = true;
169 }
170 else
171 {
172 if (newState == AgentTransferState.Cancelling
173 && (oldState == AgentTransferState.Preparing || oldState == AgentTransferState.Transferring))
174 {
175 transitionOkay = true;
176 }
177 else
178 {
179 failIfNotOkay = false;
180 }
181 }
132 182
133 if (newState == AgentTransferState.CleaningUp && oldState != AgentTransferState.CleaningUp) 183 if (!transitionOkay)
134 transitionOkay = true; 184 failureMessage
135 else if (newState == AgentTransferState.Transferring && oldState == AgentTransferState.Preparing) 185 = string.Format(
136 transitionOkay = true; 186 "Agent with ID {0} is not allowed to move from old transit state {1} to new state {2} in {3}",
137 else if (newState == AgentTransferState.ReceivedAtDestination && oldState == AgentTransferState.Transferring) 187 id, oldState, newState, m_mod.Scene.RegionInfo.RegionName);
138 transitionOkay = true; 188 }
139 189
140 if (transitionOkay) 190 if (transitionOkay)
191 {
141 m_agentsInTransit[id] = newState; 192 m_agentsInTransit[id] = newState;
142 else 193
143 throw new Exception( 194// m_log.DebugFormat(
144 string.Format( 195// "[ENTITY TRANSFER STATE MACHINE]: Changed agent with id {0} from state {1} to {2} in {3}",
145 "Agent with ID {0} is not allowed to move from old transit state {1} to new state {2} in {3}", 196// id, oldState, newState, m_mod.Scene.Name);
146 id, oldState, newState, m_mod.Scene.RegionInfo.RegionName)); 197 }
198 else if (failIfNotOkay)
199 {
200 m_log.DebugFormat("{0} UpdateInTransit. Throwing transition failure = {1}", LogHeader, failureMessage);
201 throw new Exception(failureMessage);
202 }
203// else
204// {
205// if (oldState != null)
206// m_log.DebugFormat(
207// "[ENTITY TRANSFER STATE MACHINE]: Ignored change of agent with id {0} from state {1} to {2} in {3}",
208// id, oldState, newState, m_mod.Scene.Name);
209// else
210// m_log.DebugFormat(
211// "[ENTITY TRANSFER STATE MACHINE]: Ignored change of agent with id {0} to state {1} in {2} since agent not in transit",
212// id, newState, m_mod.Scene.Name);
213// }
147 } 214 }
215
216 return transitionOkay;
148 } 217 }
149 218
150 internal bool IsInTransit(UUID id) 219 /// <summary>
220 /// Gets the current agent transfer state.
221 /// </summary>
222 /// <returns>Null if the agent is not in transit</returns>
223 /// <param name='id'>
224 /// Identifier.
225 /// </param>
226 internal AgentTransferState? GetAgentTransferState(UUID id)
151 { 227 {
152 lock (m_agentsInTransit) 228 lock (m_agentsInTransit)
153 return m_agentsInTransit.ContainsKey(id); 229 {
230 if (!m_agentsInTransit.ContainsKey(id))
231 return null;
232 else
233 return m_agentsInTransit[id];
234 }
154 } 235 }
155 236
156 /// <summary> 237 /// <summary>
@@ -203,14 +284,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
203 284
204 lock (m_agentsInTransit) 285 lock (m_agentsInTransit)
205 { 286 {
206 if (!IsInTransit(id)) 287 AgentTransferState? currentState = GetAgentTransferState(id);
288
289 if (currentState == null)
207 throw new Exception( 290 throw new Exception(
208 string.Format( 291 string.Format(
209 "Asked to wait for destination callback for agent with ID {0} in {1} but agent is not in transit", 292 "Asked to wait for destination callback for agent with ID {0} in {1} but agent is not in transit",
210 id, m_mod.Scene.RegionInfo.RegionName)); 293 id, m_mod.Scene.RegionInfo.RegionName));
211 294
212 AgentTransferState currentState = m_agentsInTransit[id];
213
214 if (currentState != AgentTransferState.Transferring && currentState != AgentTransferState.ReceivedAtDestination) 295 if (currentState != AgentTransferState.Transferring && currentState != AgentTransferState.ReceivedAtDestination)
215 throw new Exception( 296 throw new Exception(
216 string.Format( 297 string.Format(
@@ -222,8 +303,15 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
222 303
223 // There should be no race condition here since no other code should be removing the agent transfer or 304 // There should be no race condition here since no other code should be removing the agent transfer or
224 // changing the state to another other than Transferring => ReceivedAtDestination. 305 // changing the state to another other than Transferring => ReceivedAtDestination.
225 while (m_agentsInTransit[id] != AgentTransferState.ReceivedAtDestination && count-- > 0) 306
307 while (count-- > 0)
226 { 308 {
309 lock (m_agentsInTransit)
310 {
311 if (m_agentsInTransit[id] == AgentTransferState.ReceivedAtDestination)
312 break;
313 }
314
227// m_log.Debug(" >>> Waiting... " + count); 315// m_log.Debug(" >>> Waiting... " + count);
228 Thread.Sleep(100); 316 Thread.Sleep(100);
229 } 317 }
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs
index b188741..fa23590 100644
--- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs
@@ -1,4 +1,4 @@
1/* 1/*
2 * Copyright (c) Contributors, http://opensimulator.org/ 2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 * 4 *
@@ -31,6 +31,7 @@ using System.Reflection;
31 31
32using OpenSim.Framework; 32using OpenSim.Framework;
33using OpenSim.Framework.Client; 33using OpenSim.Framework.Client;
34using OpenSim.Framework.Monitoring;
34using OpenSim.Region.Framework.Interfaces; 35using OpenSim.Region.Framework.Interfaces;
35using OpenSim.Region.Framework.Scenes; 36using OpenSim.Region.Framework.Scenes;
36using OpenSim.Services.Connectors.Hypergrid; 37using OpenSim.Services.Connectors.Hypergrid;
@@ -55,6 +56,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
55 private int m_levelHGTeleport = 0; 56 private int m_levelHGTeleport = 0;
56 57
57 private GatekeeperServiceConnector m_GatekeeperConnector; 58 private GatekeeperServiceConnector m_GatekeeperConnector;
59 private IUserAgentService m_UAS;
58 60
59 protected bool m_RestrictAppearanceAbroad; 61 protected bool m_RestrictAppearanceAbroad;
60 protected string m_AccountName; 62 protected string m_AccountName;
@@ -109,6 +111,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
109 } 111 }
110 } 112 }
111 113
114 /// <summary>
115 /// Used for processing analysis of incoming attachments in a controlled fashion.
116 /// </summary>
117 private JobEngine m_incomingSceneObjectEngine;
118
112 #region ISharedRegionModule 119 #region ISharedRegionModule
113 120
114 public override string Name 121 public override string Name
@@ -152,39 +159,33 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
152 if (m_Enabled) 159 if (m_Enabled)
153 { 160 {
154 scene.RegisterModuleInterface<IUserAgentVerificationModule>(this); 161 scene.RegisterModuleInterface<IUserAgentVerificationModule>(this);
155 scene.EventManager.OnIncomingSceneObject += OnIncomingSceneObject; 162 //scene.EventManager.OnIncomingSceneObject += OnIncomingSceneObject;
156 } 163
157 } 164 m_incomingSceneObjectEngine
158 165 = new JobEngine(
159 void OnIncomingSceneObject(SceneObjectGroup so) 166 string.Format("HG Incoming Scene Object Engine ({0})", scene.Name),
160 { 167 "HG INCOMING SCENE OBJECT ENGINE");
161 if (!so.IsAttachment) 168
162 return; 169 StatsManager.RegisterStat(
163 170 new Stat(
164 if (so.Scene.UserManagementModule.IsLocalGridUser(so.AttachedAvatar)) 171 "HGIncomingAttachmentsWaiting",
165 return; 172 "Number of incoming attachments waiting for processing.",
166 173 "",
167 // foreign user 174 "",
168 AgentCircuitData aCircuit = so.Scene.AuthenticateHandler.GetAgentCircuitData(so.AttachedAvatar); 175 "entitytransfer",
169 if (aCircuit != null && (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0) 176 Name,
170 { 177 StatType.Pull,
171 if (aCircuit.ServiceURLs != null && aCircuit.ServiceURLs.ContainsKey("AssetServerURI")) 178 MeasuresOfInterest.None,
172 { 179 stat => stat.Value = m_incomingSceneObjectEngine.JobsWaiting,
173 string url = aCircuit.ServiceURLs["AssetServerURI"].ToString(); 180 StatVerbosity.Debug));
174 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Incoming attachement {0} for HG user {1} with asset server {2}", so.Name, so.AttachedAvatar, url); 181
175 Dictionary<UUID, AssetType> ids = new Dictionary<UUID, AssetType>(); 182 m_incomingSceneObjectEngine.Start();
176 HGUuidGatherer uuidGatherer = new HGUuidGatherer(so.Scene.AssetService, url);
177 uuidGatherer.GatherAssetUuids(so, ids);
178
179 foreach (KeyValuePair<UUID, AssetType> kvp in ids)
180 uuidGatherer.FetchAsset(kvp.Key);
181 }
182 } 183 }
183 } 184 }
184 185
185 protected override void OnNewClient(IClientAPI client) 186 protected override void OnNewClient(IClientAPI client)
186 { 187 {
187 client.OnTeleportHomeRequest += TeleportHome; 188 client.OnTeleportHomeRequest += TriggerTeleportHome;
188 client.OnTeleportLandmarkRequest += RequestTeleportLandmark; 189 client.OnTeleportLandmarkRequest += RequestTeleportLandmark;
189 client.OnConnectionClosed += new Action<IClientAPI>(OnConnectionClosed); 190 client.OnConnectionClosed += new Action<IClientAPI>(OnConnectionClosed);
190 } 191 }
@@ -194,34 +195,44 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
194 base.RegionLoaded(scene); 195 base.RegionLoaded(scene);
195 196
196 if (m_Enabled) 197 if (m_Enabled)
198 {
197 m_GatekeeperConnector = new GatekeeperServiceConnector(scene.AssetService); 199 m_GatekeeperConnector = new GatekeeperServiceConnector(scene.AssetService);
200 m_UAS = scene.RequestModuleInterface<IUserAgentService>();
201 if (m_UAS == null)
202 m_UAS = new UserAgentServiceConnector(m_ThisHomeURI);
203
204 }
198 } 205 }
199 206
200 public override void RemoveRegion(Scene scene) 207 public override void RemoveRegion(Scene scene)
201 { 208 {
202 base.AddRegion(scene); 209 base.RemoveRegion(scene);
203 210
204 if (m_Enabled) 211 if (m_Enabled)
212 {
205 scene.UnregisterModuleInterface<IUserAgentVerificationModule>(this); 213 scene.UnregisterModuleInterface<IUserAgentVerificationModule>(this);
214 m_incomingSceneObjectEngine.Stop();
215 }
206 } 216 }
207 217
208 #endregion 218 #endregion
209 219
210 #region HG overrides of IEntiryTransferModule 220 #region HG overrides of IEntityTransferModule
211 221
212 protected override GridRegion GetFinalDestination(GridRegion region) 222 protected override GridRegion GetFinalDestination(GridRegion region, UUID agentID, string agentHomeURI, out string message)
213 { 223 {
214 int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, region.RegionID); 224 int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, region.RegionID);
215 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: region {0} flags: {1}", region.RegionName, flags); 225 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: region {0} flags: {1}", region.RegionName, flags);
226 message = null;
216 227
217 if ((flags & (int)OpenSim.Framework.RegionFlags.Hyperlink) != 0) 228 if ((flags & (int)OpenSim.Framework.RegionFlags.Hyperlink) != 0)
218 { 229 {
219 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Destination region is hyperlink"); 230 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Destination region is hyperlink");
220 GridRegion real_destination = m_GatekeeperConnector.GetHyperlinkRegion(region, region.RegionID); 231 GridRegion real_destination = m_GatekeeperConnector.GetHyperlinkRegion(region, region.RegionID, agentID, agentHomeURI, out message);
221 if (real_destination != null) 232 if (real_destination != null)
222 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: GetFinalDestination serveruri -> {0}", real_destination.ServerURI); 233 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: GetFinalDestination: ServerURI={0}", real_destination.ServerURI);
223 else 234 else
224 m_log.WarnFormat("[HG ENTITY TRANSFER MODULE]: GetHyperlinkRegion to Gatekeeper {0} failed", region.ServerURI); 235 m_log.WarnFormat("[HG ENTITY TRANSFER MODULE]: GetHyperlinkRegion of region {0} from Gatekeeper {1} failed: {2}", region.RegionID, region.ServerURI, message);
225 return real_destination; 236 return real_destination;
226 } 237 }
227 238
@@ -272,12 +283,21 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
272 if (agentCircuit.ServiceURLs.ContainsKey("HomeURI")) 283 if (agentCircuit.ServiceURLs.ContainsKey("HomeURI"))
273 { 284 {
274 string userAgentDriver = agentCircuit.ServiceURLs["HomeURI"].ToString(); 285 string userAgentDriver = agentCircuit.ServiceURLs["HomeURI"].ToString();
275 IUserAgentService connector = new UserAgentServiceConnector(userAgentDriver); 286 IUserAgentService connector;
276 bool success = connector.LoginAgentToGrid(agentCircuit, reg, finalDestination, out reason); 287
288 if (userAgentDriver.Equals(m_ThisHomeURI) && m_UAS != null)
289 connector = m_UAS;
290 else
291 connector = new UserAgentServiceConnector(userAgentDriver);
292
293 GridRegion source = new GridRegion(Scene.RegionInfo);
294 source.RawServerURI = m_GatekeeperURI;
295
296 bool success = connector.LoginAgentToGrid(source, agentCircuit, reg, finalDestination, false, out reason);
277 logout = success; // flag for later logout from this grid; this is an HG TP 297 logout = success; // flag for later logout from this grid; this is an HG TP
278 298
279 if (success) 299 if (success)
280 sp.Scene.EventManager.TriggerTeleportStart(sp.ControllingClient, reg, finalDestination, teleportFlags, logout); 300 Scene.EventManager.TriggerTeleportStart(sp.ControllingClient, reg, finalDestination, teleportFlags, logout);
281 301
282 return success; 302 return success;
283 } 303 }
@@ -409,7 +429,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
409 // return base.UpdateAgent(reg, finalDestination, agentData, sp); 429 // return base.UpdateAgent(reg, finalDestination, agentData, sp);
410 //} 430 //}
411 431
412 public override void TeleportHome(UUID id, IClientAPI client) 432 public override void TriggerTeleportHome(UUID id, IClientAPI client)
433 {
434 TeleportHome(id, client);
435 }
436
437 public override bool TeleportHome(UUID id, IClientAPI client)
413 { 438 {
414 m_log.DebugFormat( 439 m_log.DebugFormat(
415 "[ENTITY TRANSFER MODULE]: Request to teleport {0} {1} home", client.Name, client.AgentId); 440 "[ENTITY TRANSFER MODULE]: Request to teleport {0} {1} home", client.Name, client.AgentId);
@@ -420,8 +445,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
420 { 445 {
421 // local grid user 446 // local grid user
422 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: User is local"); 447 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: User is local");
423 base.TeleportHome(id, client); 448 return base.TeleportHome(id, client);
424 return;
425 } 449 }
426 450
427 // Foreign user wants to go home 451 // Foreign user wants to go home
@@ -431,17 +455,27 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
431 { 455 {
432 client.SendTeleportFailed("Your information has been lost"); 456 client.SendTeleportFailed("Your information has been lost");
433 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Unable to locate agent's gateway information"); 457 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Unable to locate agent's gateway information");
434 return; 458 return false;
435 } 459 }
436 460
437 IUserAgentService userAgentService = new UserAgentServiceConnector(aCircuit.ServiceURLs["HomeURI"].ToString()); 461 IUserAgentService userAgentService = new UserAgentServiceConnector(aCircuit.ServiceURLs["HomeURI"].ToString());
438 Vector3 position = Vector3.UnitY, lookAt = Vector3.UnitY; 462 Vector3 position = Vector3.UnitY, lookAt = Vector3.UnitY;
439 GridRegion finalDestination = userAgentService.GetHomeRegion(aCircuit.AgentID, out position, out lookAt); 463
464 GridRegion finalDestination = null;
465 try
466 {
467 finalDestination = userAgentService.GetHomeRegion(aCircuit.AgentID, out position, out lookAt);
468 }
469 catch (Exception e)
470 {
471 m_log.Debug("[HG ENTITY TRANSFER MODULE]: GetHomeRegion call failed ", e);
472 }
473
440 if (finalDestination == null) 474 if (finalDestination == null)
441 { 475 {
442 client.SendTeleportFailed("Your home region could not be found"); 476 client.SendTeleportFailed("Your home region could not be found");
443 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Agent's home region not found"); 477 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Agent's home region not found");
444 return; 478 return false;
445 } 479 }
446 480
447 ScenePresence sp = ((Scene)(client.Scene)).GetScenePresence(client.AgentId); 481 ScenePresence sp = ((Scene)(client.Scene)).GetScenePresence(client.AgentId);
@@ -449,7 +483,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
449 { 483 {
450 client.SendTeleportFailed("Internal error"); 484 client.SendTeleportFailed("Internal error");
451 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Agent not found in the scene where it is supposed to be"); 485 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Agent not found in the scene where it is supposed to be");
452 return; 486 return false;
453 } 487 }
454 488
455 GridRegion homeGatekeeper = MakeRegion(aCircuit); 489 GridRegion homeGatekeeper = MakeRegion(aCircuit);
@@ -460,6 +494,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
460 DoTeleport( 494 DoTeleport(
461 sp, homeGatekeeper, finalDestination, 495 sp, homeGatekeeper, finalDestination,
462 position, lookAt, (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaHome)); 496 position, lookAt, (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaHome));
497 return true;
463 } 498 }
464 499
465 /// <summary> 500 /// <summary>
@@ -484,35 +519,174 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
484 // Local region? 519 // Local region?
485 if (info != null) 520 if (info != null)
486 { 521 {
487 ((Scene)(remoteClient.Scene)).RequestTeleportLocation(remoteClient, info.RegionHandle, lm.Position, 522 Scene.RequestTeleportLocation(
523 remoteClient, info.RegionHandle, lm.Position,
488 Vector3.Zero, (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaLandmark)); 524 Vector3.Zero, (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaLandmark));
489
490 return;
491 } 525 }
492 else 526 else
493 { 527 {
494 // Foreign region 528 // Foreign region
495 Scene scene = (Scene)(remoteClient.Scene);
496 GatekeeperServiceConnector gConn = new GatekeeperServiceConnector(); 529 GatekeeperServiceConnector gConn = new GatekeeperServiceConnector();
497 GridRegion gatekeeper = new GridRegion(); 530 GridRegion gatekeeper = new GridRegion();
498 gatekeeper.ServerURI = lm.Gatekeeper; 531 gatekeeper.ServerURI = lm.Gatekeeper;
499 GridRegion finalDestination = gConn.GetHyperlinkRegion(gatekeeper, new UUID(lm.RegionID)); 532 string homeURI = Scene.GetAgentHomeURI(remoteClient.AgentId);
533
534 string message;
535 GridRegion finalDestination = gConn.GetHyperlinkRegion(gatekeeper, new UUID(lm.RegionID), remoteClient.AgentId, homeURI, out message);
500 536
501 if (finalDestination != null) 537 if (finalDestination != null)
502 { 538 {
503 ScenePresence sp = scene.GetScenePresence(remoteClient.AgentId); 539 ScenePresence sp = Scene.GetScenePresence(remoteClient.AgentId);
504 IEntityTransferModule transferMod = scene.RequestModuleInterface<IEntityTransferModule>();
505 540
506 if (transferMod != null && sp != null) 541 if (sp != null)
507 transferMod.DoTeleport( 542 {
543 if (message != null)
544 sp.ControllingClient.SendAgentAlertMessage(message, true);
545
546 // Validate assorted conditions
547 string reason = string.Empty;
548 if (!ValidateGenericConditions(sp, gatekeeper, finalDestination, 0, out reason))
549 {
550 sp.ControllingClient.SendTeleportFailed(reason);
551 return;
552 }
553
554 DoTeleport(
508 sp, gatekeeper, finalDestination, lm.Position, Vector3.UnitX, 555 sp, gatekeeper, finalDestination, lm.Position, Vector3.UnitX,
509 (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaLandmark)); 556 (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaLandmark));
557 }
558 }
559 else
560 {
561 remoteClient.SendTeleportFailed(message);
510 } 562 }
511 563
512 } 564 }
565 }
566
567 private void RemoveIncomingSceneObjectJobs(string commonIdToRemove)
568 {
569 List<JobEngine.Job> jobsToReinsert = new List<JobEngine.Job>();
570 int jobsRemoved = 0;
513 571
514 // can't find the region: Tell viewer and abort 572 JobEngine.Job job;
515 remoteClient.SendTeleportFailed("The teleport destination could not be found."); 573 while ((job = m_incomingSceneObjectEngine.RemoveNextJob()) != null)
574 {
575 if (job.CommonId != commonIdToRemove)
576 jobsToReinsert.Add(job);
577 else
578 jobsRemoved++;
579 }
580
581 m_log.DebugFormat(
582 "[HG ENTITY TRANSFER]: Removing {0} jobs with common ID {1} and reinserting {2} other jobs",
583 jobsRemoved, commonIdToRemove, jobsToReinsert.Count);
584
585 if (jobsToReinsert.Count > 0)
586 {
587 foreach (JobEngine.Job jobToReinsert in jobsToReinsert)
588 m_incomingSceneObjectEngine.QueueJob(jobToReinsert);
589 }
590 }
591
592 public override bool HandleIncomingSceneObject(SceneObjectGroup so, Vector3 newPosition)
593 {
594 // FIXME: We must make it so that we can use SOG.IsAttachment here. At the moment it is always null!
595 if (!so.IsAttachmentCheckFull())
596 return base.HandleIncomingSceneObject(so, newPosition);
597
598 // Equally, we can't use so.AttachedAvatar here.
599 if (so.OwnerID == UUID.Zero || Scene.UserManagementModule.IsLocalGridUser(so.OwnerID))
600 return base.HandleIncomingSceneObject(so, newPosition);
601
602 // foreign user
603 AgentCircuitData aCircuit = Scene.AuthenticateHandler.GetAgentCircuitData(so.OwnerID);
604 if (aCircuit != null)
605 {
606 if ((aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) == 0)
607 {
608 // We have already pulled the necessary attachments from the source grid.
609 base.HandleIncomingSceneObject(so, newPosition);
610 }
611 else
612 {
613 if (aCircuit.ServiceURLs != null && aCircuit.ServiceURLs.ContainsKey("AssetServerURI"))
614 {
615 m_incomingSceneObjectEngine.QueueJob(
616 string.Format("HG UUID Gather for attachment {0} for {1}", so.Name, aCircuit.Name),
617 () =>
618 {
619 string url = aCircuit.ServiceURLs["AssetServerURI"].ToString();
620 // m_log.DebugFormat(
621 // "[HG ENTITY TRANSFER MODULE]: Incoming attachment {0} for HG user {1} with asset service {2}",
622 // so.Name, so.AttachedAvatar, url);
623
624 IDictionary<UUID, sbyte> ids = new Dictionary<UUID, sbyte>();
625 HGUuidGatherer uuidGatherer
626 = new HGUuidGatherer(Scene.AssetService, url, ids);
627 uuidGatherer.AddForInspection(so);
628
629 while (!uuidGatherer.Complete)
630 {
631 int tickStart = Util.EnvironmentTickCount();
632
633 UUID? nextUuid = uuidGatherer.NextUuidToInspect;
634 uuidGatherer.GatherNext();
635
636 // m_log.DebugFormat(
637 // "[HG ENTITY TRANSFER]: Gathered attachment asset uuid {0} for object {1} for HG user {2} took {3} ms with asset service {4}",
638 // nextUuid, so.Name, so.OwnerID, Util.EnvironmentTickCountSubtract(tickStart), url);
639
640 int ticksElapsed = Util.EnvironmentTickCountSubtract(tickStart);
641
642 if (ticksElapsed > 30000)
643 {
644 m_log.WarnFormat(
645 "[HG ENTITY TRANSFER]: Removing incoming scene object jobs for HG user {0} as gather of {1} from {2} took {3} ms to respond (> {4} ms)",
646 so.OwnerID, so.Name, url, ticksElapsed, 30000);
647
648 RemoveIncomingSceneObjectJobs(so.OwnerID.ToString());
649
650 return;
651 }
652 }
653
654 // m_log.DebugFormat(
655 // "[HG ENTITY TRANSFER]: Fetching {0} assets for attachment {1} for HG user {2} with asset service {3}",
656 // ids.Count, so.Name, so.OwnerID, url);
657
658 foreach (KeyValuePair<UUID, sbyte> kvp in ids)
659 {
660 int tickStart = Util.EnvironmentTickCount();
661
662 uuidGatherer.FetchAsset(kvp.Key);
663
664 int ticksElapsed = Util.EnvironmentTickCountSubtract(tickStart);
665
666 if (ticksElapsed > 30000)
667 {
668 m_log.WarnFormat(
669 "[HG ENTITY TRANSFER]: Removing incoming scene object jobs for HG user {0} as fetch of {1} from {2} took {3} ms to respond (> {4} ms)",
670 so.OwnerID, kvp.Key, url, ticksElapsed, 30000);
671
672 RemoveIncomingSceneObjectJobs(so.OwnerID.ToString());
673
674 return;
675 }
676 }
677
678 base.HandleIncomingSceneObject(so, newPosition);
679
680 // m_log.DebugFormat(
681 // "[HG ENTITY TRANSFER MODULE]: Completed incoming attachment {0} for HG user {1} with asset server {2}",
682 // so.Name, so.OwnerID, url);
683 },
684 so.OwnerID.ToString());
685 }
686 }
687 }
688
689 return true;
516 } 690 }
517 691
518 #endregion 692 #endregion
@@ -549,12 +723,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
549 if (uMan != null && uMan.IsLocalGridUser(obj.AgentId)) 723 if (uMan != null && uMan.IsLocalGridUser(obj.AgentId))
550 { 724 {
551 // local grid user 725 // local grid user
726 m_UAS.LogoutAgent(obj.AgentId, obj.SessionId);
552 return; 727 return;
553 } 728 }
554 729
555 AgentCircuitData aCircuit = ((Scene)(obj.Scene)).AuthenticateHandler.GetAgentCircuitData(obj.CircuitCode); 730 AgentCircuitData aCircuit = ((Scene)(obj.Scene)).AuthenticateHandler.GetAgentCircuitData(obj.CircuitCode);
556 731 if (aCircuit != null && aCircuit.ServiceURLs != null && aCircuit.ServiceURLs.ContainsKey("HomeURI"))
557 if (aCircuit.ServiceURLs.ContainsKey("HomeURI"))
558 { 732 {
559 string url = aCircuit.ServiceURLs["HomeURI"].ToString(); 733 string url = aCircuit.ServiceURLs["HomeURI"].ToString();
560 IUserAgentService security = new UserAgentServiceConnector(url); 734 IUserAgentService security = new UserAgentServiceConnector(url);
diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs
index 7871eda..f54298c 100644
--- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs
+++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs
@@ -35,6 +35,7 @@ using System.Xml;
35using log4net; 35using log4net;
36using OpenMetaverse; 36using OpenMetaverse;
37using OpenSim.Framework; 37using OpenSim.Framework;
38using OpenSim.Framework.Serialization.External;
38 39
39using OpenSim.Region.Framework.Scenes; 40using OpenSim.Region.Framework.Scenes;
40using OpenSim.Region.Framework.Scenes.Serialization; 41using OpenSim.Region.Framework.Scenes.Serialization;
@@ -73,6 +74,9 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
73 74
74 private AssetMetadata FetchMetadata(string url, UUID assetID) 75 private AssetMetadata FetchMetadata(string url, UUID assetID)
75 { 76 {
77 if (string.IsNullOrEmpty(url))
78 return null;
79
76 if (!url.EndsWith("/") && !url.EndsWith("=")) 80 if (!url.EndsWith("/") && !url.EndsWith("="))
77 url = url + "/"; 81 url = url + "/";
78 82
@@ -92,6 +96,9 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
92 AssetBase asset = m_scene.AssetService.Get(assetID.ToString()); 96 AssetBase asset = m_scene.AssetService.Get(assetID.ToString());
93 if (asset == null) 97 if (asset == null)
94 { 98 {
99 if (string.IsNullOrEmpty(url))
100 return null;
101
95 if (!url.EndsWith("/") && !url.EndsWith("=")) 102 if (!url.EndsWith("/") && !url.EndsWith("="))
96 url = url + "/"; 103 url = url + "/";
97 104
@@ -109,45 +116,47 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
109 116
110 public bool PostAsset(string url, AssetBase asset) 117 public bool PostAsset(string url, AssetBase asset)
111 { 118 {
112 if (asset != null) 119 if (string.IsNullOrEmpty(url))
113 { 120 return false;
114 if (!url.EndsWith("/") && !url.EndsWith("="))
115 url = url + "/";
116 121
117 bool success = true; 122 if (!url.EndsWith("/") && !url.EndsWith("="))
118 // See long comment in AssetCache.AddAsset 123 url = url + "/";
119 if (!asset.Temporary || asset.Local)
120 {
121 // We need to copy the asset into a new asset, because
122 // we need to set its ID to be URL+UUID, so that the
123 // HGAssetService dispatches it to the remote grid.
124 // It's not pretty, but the best that can be done while
125 // not having a global naming infrastructure
126 AssetBase asset1 = new AssetBase(asset.FullID, asset.Name, asset.Type, asset.Metadata.CreatorID);
127 Copy(asset, asset1);
128 asset1.ID = url + asset.ID;
129
130 AdjustIdentifiers(asset1.Metadata);
131 if (asset1.Metadata.Type == (sbyte)AssetType.Object)
132 asset1.Data = AdjustIdentifiers(asset.Data);
133 else
134 asset1.Data = asset.Data;
135 124
136 string id = m_scene.AssetService.Store(asset1); 125 if (asset == null)
137 if (id == string.Empty) 126 {
138 { 127 m_log.Warn("[HG ASSET MAPPER]: Tried to post asset to remote server, but asset not in local cache.");
139 m_log.DebugFormat("[HG ASSET MAPPER]: Asset server {0} did not accept {1}", url, asset.ID); 128 return false;
140 success = false;
141 }
142 else
143 m_log.DebugFormat("[HG ASSET MAPPER]: Posted copy of asset {0} from local asset server to {1}", asset1.ID, url);
144 }
145 return success;
146 } 129 }
130
131 // See long comment in AssetCache.AddAsset
132 if (asset.Temporary || asset.Local)
133 return true;
134
135 // We need to copy the asset into a new asset, because
136 // we need to set its ID to be URL+UUID, so that the
137 // HGAssetService dispatches it to the remote grid.
138 // It's not pretty, but the best that can be done while
139 // not having a global naming infrastructure
140 AssetBase asset1 = new AssetBase(asset.FullID, asset.Name, asset.Type, asset.Metadata.CreatorID);
141 Copy(asset, asset1);
142 asset1.ID = url + asset.ID;
143
144 AdjustIdentifiers(asset1.Metadata);
145 if (asset1.Metadata.Type == (sbyte)AssetType.Object)
146 asset1.Data = AdjustIdentifiers(asset.Data);
147 else 147 else
148 m_log.Warn("[HG ASSET MAPPER]: Tried to post asset to remote server, but asset not in local cache."); 148 asset1.Data = asset.Data;
149 149
150 return false; 150 string id = m_scene.AssetService.Store(asset1);
151 if (String.IsNullOrEmpty(id))
152 {
153 m_log.DebugFormat("[HG ASSET MAPPER]: Asset server {0} did not accept {1}", url, asset.ID);
154 return false;
155 }
156 else {
157 m_log.DebugFormat("[HG ASSET MAPPER]: Posted copy of asset {0} from local asset server to {1}", asset1.ID, url);
158 return true;
159 }
151 } 160 }
152 161
153 private void Copy(AssetBase from, AssetBase to) 162 private void Copy(AssetBase from, AssetBase to)
@@ -165,7 +174,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
165 174
166 private void AdjustIdentifiers(AssetMetadata meta) 175 private void AdjustIdentifiers(AssetMetadata meta)
167 { 176 {
168 if (meta.CreatorID != null && meta.CreatorID != string.Empty) 177 if (!string.IsNullOrEmpty(meta.CreatorID))
169 { 178 {
170 UUID uuid = UUID.Zero; 179 UUID uuid = UUID.Zero;
171 UUID.TryParse(meta.CreatorID, out uuid); 180 UUID.TryParse(meta.CreatorID, out uuid);
@@ -181,49 +190,10 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
181 return Utils.StringToBytes(RewriteSOP(xml)); 190 return Utils.StringToBytes(RewriteSOP(xml));
182 } 191 }
183 192
184 protected string RewriteSOP(string xml) 193 protected string RewriteSOP(string xmlData)
185 { 194 {
186 XmlDocument doc = new XmlDocument(); 195// Console.WriteLine("Input XML [{0}]", xmlData);
187 doc.LoadXml(xml); 196 return ExternalRepresentationUtils.RewriteSOP(xmlData, m_scene.Name, m_HomeURI, m_scene.UserAccountService, m_scene.RegionInfo.ScopeID);
188 XmlNodeList sops = doc.GetElementsByTagName("SceneObjectPart");
189
190 foreach (XmlNode sop in sops)
191 {
192 UserAccount creator = null;
193 bool hasCreatorData = false;
194 XmlNodeList nodes = sop.ChildNodes;
195 foreach (XmlNode node in nodes)
196 {
197 if (node.Name == "CreatorID")
198 {
199 UUID uuid = UUID.Zero;
200 UUID.TryParse(node.InnerText, out uuid);
201 creator = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, uuid);
202 }
203 if (node.Name == "CreatorData" && node.InnerText != null && node.InnerText != string.Empty)
204 hasCreatorData = true;
205
206 //if (node.Name == "OwnerID")
207 //{
208 // UserAccount owner = GetUser(node.InnerText);
209 // if (owner != null)
210 // node.InnerText = m_ProfileServiceURL + "/" + node.InnerText + "/" + owner.FirstName + " " + owner.LastName;
211 //}
212 }
213
214 if (!hasCreatorData && creator != null)
215 {
216 XmlElement creatorData = doc.CreateElement("CreatorData");
217 creatorData.InnerText = m_HomeURI + ";" + creator.FirstName + " " + creator.LastName;
218 sop.AppendChild(creatorData);
219 }
220 }
221
222 using (StringWriter wr = new StringWriter())
223 {
224 doc.Save(wr);
225 return wr.ToString();
226 }
227 197
228 } 198 }
229 199
@@ -251,12 +221,13 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
251 221
252 // The act of gathering UUIDs downloads some assets from the remote server 222 // The act of gathering UUIDs downloads some assets from the remote server
253 // but not all... 223 // but not all...
254 Dictionary<UUID, AssetType> ids = new Dictionary<UUID, AssetType>();
255 HGUuidGatherer uuidGatherer = new HGUuidGatherer(m_scene.AssetService, userAssetURL); 224 HGUuidGatherer uuidGatherer = new HGUuidGatherer(m_scene.AssetService, userAssetURL);
256 uuidGatherer.GatherAssetUuids(assetID, (AssetType)meta.Type, ids); 225 uuidGatherer.AddForInspection(assetID);
257 m_log.DebugFormat("[HG ASSET MAPPER]: Preparing to get {0} assets", ids.Count); 226 uuidGatherer.GatherAll();
227
228 m_log.DebugFormat("[HG ASSET MAPPER]: Preparing to get {0} assets", uuidGatherer.GatheredUuids.Count);
258 bool success = true; 229 bool success = true;
259 foreach (UUID uuid in ids.Keys) 230 foreach (UUID uuid in uuidGatherer.GatheredUuids.Keys)
260 if (FetchAsset(userAssetURL, uuid) == null) 231 if (FetchAsset(userAssetURL, uuid) == null)
261 success = false; 232 success = false;
262 233
@@ -267,39 +238,92 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
267 m_log.DebugFormat("[HG ASSET MAPPER]: Successfully got item {0} from asset server {1}", assetID, userAssetURL); 238 m_log.DebugFormat("[HG ASSET MAPPER]: Successfully got item {0} from asset server {1}", assetID, userAssetURL);
268 } 239 }
269 240
270
271 public void Post(UUID assetID, UUID ownerID, string userAssetURL) 241 public void Post(UUID assetID, UUID ownerID, string userAssetURL)
272 { 242 {
273 // Post the item from the local AssetCache onto the remote asset server 243 m_log.DebugFormat("[HG ASSET MAPPER]: Starting to send asset {0} with children to asset server {1}", assetID, userAssetURL);
274 // and place an entry in m_assetMap 244
245 // Find all the embedded assets
275 246
276 m_log.Debug("[HG ASSET MAPPER]: Posting object " + assetID + " to asset server " + userAssetURL);
277 AssetBase asset = m_scene.AssetService.Get(assetID.ToString()); 247 AssetBase asset = m_scene.AssetService.Get(assetID.ToString());
278 if (asset != null) 248 if (asset == null)
249 {
250 m_log.DebugFormat("[HG ASSET MAPPER]: Something wrong with asset {0}, it could not be found", assetID);
251 return;
252 }
253
254 HGUuidGatherer uuidGatherer = new HGUuidGatherer(m_scene.AssetService, string.Empty);
255 uuidGatherer.AddForInspection(asset.FullID);
256 uuidGatherer.GatherAll();
257
258 // Check which assets already exist in the destination server
259
260 string url = userAssetURL;
261 if (!url.EndsWith("/") && !url.EndsWith("="))
262 url = url + "/";
263
264 string[] remoteAssetIDs = new string[uuidGatherer.GatheredUuids.Count];
265 int i = 0;
266 foreach (UUID id in uuidGatherer.GatheredUuids.Keys)
267 remoteAssetIDs[i++] = url + id.ToString();
268
269 bool[] exist = m_scene.AssetService.AssetsExist(remoteAssetIDs);
270
271 var existSet = new HashSet<string>();
272 i = 0;
273 foreach (UUID id in uuidGatherer.GatheredUuids.Keys)
274 {
275 if (exist[i])
276 existSet.Add(id.ToString());
277 ++i;
278 }
279
280 // Send only those assets which don't already exist in the destination server
281
282 bool success = true;
283
284 foreach (UUID uuid in uuidGatherer.GatheredUuids.Keys)
279 { 285 {
280 Dictionary<UUID, AssetType> ids = new Dictionary<UUID, AssetType>(); 286 if (!existSet.Contains(uuid.ToString()))
281 HGUuidGatherer uuidGatherer = new HGUuidGatherer(m_scene.AssetService, string.Empty);
282 uuidGatherer.GatherAssetUuids(asset.FullID, (AssetType)asset.Type, ids);
283 bool success = false;
284 foreach (UUID uuid in ids.Keys)
285 { 287 {
286 asset = m_scene.AssetService.Get(uuid.ToString()); 288 asset = m_scene.AssetService.Get(uuid.ToString());
287 if (asset == null) 289 if (asset == null)
290 {
288 m_log.DebugFormat("[HG ASSET MAPPER]: Could not find asset {0}", uuid); 291 m_log.DebugFormat("[HG ASSET MAPPER]: Could not find asset {0}", uuid);
292 }
289 else 293 else
290 success = PostAsset(userAssetURL, asset); 294 {
295 try
296 {
297 success &= PostAsset(userAssetURL, asset);
298 }
299 catch (Exception e)
300 {
301 m_log.Error(
302 string.Format(
303 "[HG ASSET MAPPER]: Failed to post asset {0} (type {1}, length {2}) referenced from {3} to {4} with exception ",
304 asset.ID, asset.Type, asset.Data.Length, assetID, userAssetURL),
305 e);
306
307 // For debugging purposes for now we will continue to throw the exception up the stack as was already happening. However, after
308 // debugging we may want to simply report the failure if we can tell this is due to a failure
309 // with a particular asset and not a destination network failure where all asset posts will fail (and
310 // generate large amounts of log spam).
311 throw e;
312 }
313 }
291 } 314 }
292
293 // maybe all pieces got there...
294 if (!success)
295 m_log.DebugFormat("[HG ASSET MAPPER]: Problems posting item {0} to asset server {1}", assetID, userAssetURL);
296 else 315 else
297 m_log.DebugFormat("[HG ASSET MAPPER]: Successfully posted item {0} to asset server {1}", assetID, userAssetURL); 316 {
298 317 m_log.DebugFormat(
318 "[HG ASSET MAPPER]: Didn't post asset {0} referenced from {1} because it already exists in asset server {2}",
319 uuid, assetID, userAssetURL);
320 }
299 } 321 }
300 else
301 m_log.DebugFormat("[HG ASSET MAPPER]: Something wrong with asset {0}, it could not be found", assetID);
302 322
323 if (!success)
324 m_log.DebugFormat("[HG ASSET MAPPER]: Problems sending asset {0} with children to asset server {1}", assetID, userAssetURL);
325 else
326 m_log.DebugFormat("[HG ASSET MAPPER]: Successfully sent asset {0} with children to asset server {1}", assetID, userAssetURL);
303 } 327 }
304 328
305 #endregion 329 #endregion
diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs
index 964efda..582b267 100644
--- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs
@@ -62,6 +62,17 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
62 private string m_ThisGatekeeper; 62 private string m_ThisGatekeeper;
63 private bool m_RestrictInventoryAccessAbroad; 63 private bool m_RestrictInventoryAccessAbroad;
64 64
65 private bool m_bypassPermissions = true;
66
67 // This simple check makes it possible to support grids in which all the simulators
68 // share all central services of the Robust server EXCEPT assets. In other words,
69 // grids where the simulators' assets are kept in one DB and the users' inventory assets
70 // are kept on another. When users rez items from inventory or take objects from world,
71 // an HG-like asset copy takes place between the 2 servers, the world asset server and
72 // the user's asset server.
73 private bool m_CheckSeparateAssets = false;
74 private string m_LocalAssetsURL = string.Empty;
75
65// private bool m_Initialized = false; 76// private bool m_Initialized = false;
66 77
67 #region INonSharedRegionModule 78 #region INonSharedRegionModule
@@ -88,16 +99,26 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
88 IConfig thisModuleConfig = source.Configs["HGInventoryAccessModule"]; 99 IConfig thisModuleConfig = source.Configs["HGInventoryAccessModule"];
89 if (thisModuleConfig != null) 100 if (thisModuleConfig != null)
90 { 101 {
91 // legacy configuration [obsolete] 102 m_HomeURI = Util.GetConfigVarFromSections<string>(source, "HomeURI",
92 m_HomeURI = thisModuleConfig.GetString("ProfileServerURI", string.Empty); 103 new string[] { "Startup", "Hypergrid", "HGInventoryAccessModule" }, String.Empty);
93 // preferred 104 m_ThisGatekeeper = Util.GetConfigVarFromSections<string>(source, "GatekeeperURI",
94 m_HomeURI = thisModuleConfig.GetString("HomeURI", m_HomeURI); 105 new string[] { "Startup", "Hypergrid", "HGInventoryAccessModule" }, String.Empty);
106 // Legacy. Renove soon!
107 m_ThisGatekeeper = thisModuleConfig.GetString("Gatekeeper", m_ThisGatekeeper);
108
95 m_OutboundPermission = thisModuleConfig.GetBoolean("OutboundPermission", true); 109 m_OutboundPermission = thisModuleConfig.GetBoolean("OutboundPermission", true);
96 m_ThisGatekeeper = thisModuleConfig.GetString("Gatekeeper", string.Empty);
97 m_RestrictInventoryAccessAbroad = thisModuleConfig.GetBoolean("RestrictInventoryAccessAbroad", true); 110 m_RestrictInventoryAccessAbroad = thisModuleConfig.GetBoolean("RestrictInventoryAccessAbroad", true);
111 m_CheckSeparateAssets = thisModuleConfig.GetBoolean("CheckSeparateAssets", false);
112 m_LocalAssetsURL = thisModuleConfig.GetString("RegionHGAssetServerURI", string.Empty);
113 m_LocalAssetsURL = m_LocalAssetsURL.Trim(new char[] { '/' });
114
98 } 115 }
99 else 116 else
100 m_log.Warn("[HG INVENTORY ACCESS MODULE]: HGInventoryAccessModule configs not found. ProfileServerURI not set!"); 117 m_log.Warn("[HG INVENTORY ACCESS MODULE]: HGInventoryAccessModule configs not found. ProfileServerURI not set!");
118
119 m_bypassPermissions = !Util.GetConfigVarFromSections<bool>(source, "serverside_object_permissions",
120 new string[] { "Startup", "Permissions" }, true);
121
101 } 122 }
102 } 123 }
103 } 124 }
@@ -109,9 +130,14 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
109 130
110 base.AddRegion(scene); 131 base.AddRegion(scene);
111 m_assMapper = new HGAssetMapper(scene, m_HomeURI); 132 m_assMapper = new HGAssetMapper(scene, m_HomeURI);
112 scene.EventManager.OnNewInventoryItemUploadComplete += UploadInventoryItem; 133 scene.EventManager.OnNewInventoryItemUploadComplete += PostInventoryAsset;
113 scene.EventManager.OnTeleportStart += TeleportStart; 134 scene.EventManager.OnTeleportStart += TeleportStart;
114 scene.EventManager.OnTeleportFail += TeleportFail; 135 scene.EventManager.OnTeleportFail += TeleportFail;
136
137 // We're fgoing to enforce some stricter permissions if Outbound is false
138 scene.Permissions.OnTakeObject += CanTakeObject;
139 scene.Permissions.OnTakeCopyObject += CanTakeObject;
140 scene.Permissions.OnTransferUserInventory += OnTransferUserInventory;
115 } 141 }
116 142
117 #endregion 143 #endregion
@@ -133,7 +159,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
133 if (sp is ScenePresence) 159 if (sp is ScenePresence)
134 { 160 {
135 AgentCircuitData aCircuit = ((ScenePresence)sp).Scene.AuthenticateHandler.GetAgentCircuitData(client.AgentId); 161 AgentCircuitData aCircuit = ((ScenePresence)sp).Scene.AuthenticateHandler.GetAgentCircuitData(client.AgentId);
136 if ((aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0) 162 if (aCircuit != null && (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0)
137 { 163 {
138 if (m_RestrictInventoryAccessAbroad) 164 if (m_RestrictInventoryAccessAbroad)
139 { 165 {
@@ -183,8 +209,11 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
183 } 209 }
184 } 210 }
185 211
186 public void UploadInventoryItem(UUID avatarID, UUID assetID, string name, int userlevel) 212 public void PostInventoryAsset(UUID avatarID, AssetType type, UUID assetID, string name, int userlevel)
187 { 213 {
214 if (type == AssetType.Link)
215 return;
216
188 string userAssetServer = string.Empty; 217 string userAssetServer = string.Empty;
189 if (IsForeignUser(avatarID, out userAssetServer) && userAssetServer != string.Empty && m_OutboundPermission) 218 if (IsForeignUser(avatarID, out userAssetServer) && userAssetServer != string.Empty && m_OutboundPermission)
190 { 219 {
@@ -219,18 +248,32 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
219 { 248 {
220 UUID newAssetID = base.CapsUpdateInventoryItemAsset(remoteClient, itemID, data); 249 UUID newAssetID = base.CapsUpdateInventoryItemAsset(remoteClient, itemID, data);
221 250
222 UploadInventoryItem(remoteClient.AgentId, newAssetID, "", 0); 251 PostInventoryAsset(remoteClient.AgentId, AssetType.Unknown, newAssetID, "", 0);
223 252
224 return newAssetID; 253 return newAssetID;
225 } 254 }
226 255
256 ///
257 /// UpdateInventoryItemAsset
258 ///
259 public override bool UpdateInventoryItemAsset(UUID ownerID, InventoryItemBase item, AssetBase asset)
260 {
261 if (base.UpdateInventoryItemAsset(ownerID, item, asset))
262 {
263 PostInventoryAsset(ownerID, (AssetType)asset.Type, asset.FullID, asset.Name, 0);
264 return true;
265 }
266
267 return false;
268 }
269
227 /// 270 ///
228 /// Used in DeleteToInventory 271 /// Used in DeleteToInventory
229 /// 272 ///
230 protected override void ExportAsset(UUID agentID, UUID assetID) 273 protected override void ExportAsset(UUID agentID, UUID assetID)
231 { 274 {
232 if (!assetID.Equals(UUID.Zero)) 275 if (!assetID.Equals(UUID.Zero))
233 UploadInventoryItem(agentID, assetID, "", 0); 276 PostInventoryAsset(agentID, AssetType.Unknown, assetID, "", 0);
234 else 277 else
235 m_log.Debug("[HGScene]: Scene.Inventory did not create asset"); 278 m_log.Debug("[HGScene]: Scene.Inventory did not create asset");
236 } 279 }
@@ -242,7 +285,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
242 UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection, 285 UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection,
243 bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment) 286 bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment)
244 { 287 {
245 m_log.DebugFormat("[HGScene] RezObject itemID={0} fromTaskID={1}", itemID, fromTaskID); 288 m_log.DebugFormat("[HGScene]: RezObject itemID={0} fromTaskID={1}", itemID, fromTaskID);
246 289
247 //if (fromTaskID.Equals(UUID.Zero)) 290 //if (fromTaskID.Equals(UUID.Zero))
248 //{ 291 //{
@@ -268,50 +311,98 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
268 SceneObjectGroup sog = base.RezObject(remoteClient, itemID, RayEnd, RayStart, RayTargetID, BypassRayCast, RayEndIsIntersection, 311 SceneObjectGroup sog = base.RezObject(remoteClient, itemID, RayEnd, RayStart, RayTargetID, BypassRayCast, RayEndIsIntersection,
269 RezSelected, RemoveItem, fromTaskID, attachment); 312 RezSelected, RemoveItem, fromTaskID, attachment);
270 313
271 if (sog == null)
272 remoteClient.SendAgentAlertMessage("Unable to rez: problem accessing inventory or locating assets", false);
273
274 return sog; 314 return sog;
275 315
276 } 316 }
277 317
278 public override void TransferInventoryAssets(InventoryItemBase item, UUID sender, UUID receiver) 318 public override void TransferInventoryAssets(InventoryItemBase item, UUID sender, UUID receiver)
279 { 319 {
280 string userAssetServer = string.Empty; 320 string senderAssetServer = string.Empty;
281 if (IsForeignUser(sender, out userAssetServer) && userAssetServer != string.Empty) 321 string receiverAssetServer = string.Empty;
282 m_assMapper.Get(item.AssetID, sender, userAssetServer); 322 bool isForeignSender, isForeignReceiver;
323 isForeignSender = IsForeignUser(sender, out senderAssetServer);
324 isForeignReceiver = IsForeignUser(receiver, out receiverAssetServer);
325
326 // They're both local. Nothing to do.
327 if (!isForeignSender && !isForeignReceiver)
328 return;
329
330 // At least one of them is foreign.
331 // If both users have the same asset server, no need to transfer the asset
332 if (senderAssetServer.Equals(receiverAssetServer))
333 {
334 m_log.DebugFormat("[HGScene]: Asset transfer between foreign users, but they have the same server. No transfer.");
335 return;
336 }
337
338 if (isForeignSender && senderAssetServer != string.Empty)
339 m_assMapper.Get(item.AssetID, sender, senderAssetServer);
283 340
284 if (IsForeignUser(receiver, out userAssetServer) && userAssetServer != string.Empty && m_OutboundPermission) 341 if (isForeignReceiver && receiverAssetServer != string.Empty && m_OutboundPermission)
285 m_assMapper.Post(item.AssetID, receiver, userAssetServer); 342 m_assMapper.Post(item.AssetID, receiver, receiverAssetServer);
286 } 343 }
287 344
288 public override bool IsForeignUser(UUID userID, out string assetServerURL) 345 public override bool IsForeignUser(UUID userID, out string assetServerURL)
289 { 346 {
290 assetServerURL = string.Empty; 347 assetServerURL = string.Empty;
291 348
292 if (UserManagementModule != null && !UserManagementModule.IsLocalGridUser(userID)) 349 if (UserManagementModule != null)
293 { // foreign 350 {
294 ScenePresence sp = null; 351 if (!m_CheckSeparateAssets)
295 if (m_Scene.TryGetScenePresence(userID, out sp))
296 { 352 {
297 AgentCircuitData aCircuit = m_Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode); 353 if (!UserManagementModule.IsLocalGridUser(userID))
298 if (aCircuit.ServiceURLs.ContainsKey("AssetServerURI")) 354 { // foreign
299 { 355 ScenePresence sp = null;
300 assetServerURL = aCircuit.ServiceURLs["AssetServerURI"].ToString(); 356 if (m_Scene.TryGetScenePresence(userID, out sp))
301 assetServerURL = assetServerURL.Trim(new char[] { '/' }); 357 {
358 AgentCircuitData aCircuit = m_Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode);
359 if (aCircuit != null && aCircuit.ServiceURLs != null && aCircuit.ServiceURLs.ContainsKey("AssetServerURI"))
360 {
361 assetServerURL = aCircuit.ServiceURLs["AssetServerURI"].ToString();
362 assetServerURL = assetServerURL.Trim(new char[] { '/' });
363 }
364 }
365 else
366 {
367 assetServerURL = UserManagementModule.GetUserServerURL(userID, "AssetServerURI");
368 assetServerURL = assetServerURL.Trim(new char[] { '/' });
369 }
370 return true;
302 } 371 }
303 } 372 }
304 else 373 else
305 { 374 {
306 assetServerURL = UserManagementModule.GetUserServerURL(userID, "AssetServerURI"); 375 if (IsLocalInventoryAssetsUser(userID, out assetServerURL))
307 assetServerURL = assetServerURL.Trim(new char[] { '/' }); 376 {
377 m_log.DebugFormat("[HGScene]: user {0} has local assets {1}", userID, assetServerURL);
378 return false;
379 }
380 else
381 {
382 m_log.DebugFormat("[HGScene]: user {0} has foreign assets {1}", userID, assetServerURL);
383 return true;
384 }
308 } 385 }
309 return true;
310 } 386 }
311
312 return false; 387 return false;
313 } 388 }
314 389
390 private bool IsLocalInventoryAssetsUser(UUID uuid, out string assetsURL)
391 {
392 assetsURL = UserManagementModule.GetUserServerURL(uuid, "AssetServerURI");
393 if (assetsURL == string.Empty)
394 {
395 AgentCircuitData agent = m_Scene.AuthenticateHandler.GetAgentCircuitData(uuid);
396 if (agent != null)
397 {
398 assetsURL = agent.ServiceURLs["AssetServerURI"].ToString();
399 assetsURL = assetsURL.Trim(new char[] { '/' });
400 }
401 }
402 return m_LocalAssetsURL.Equals(assetsURL);
403 }
404
405
315 protected override InventoryItemBase GetItem(UUID agentID, UUID itemID) 406 protected override InventoryItemBase GetItem(UUID agentID, UUID itemID)
316 { 407 {
317 InventoryItemBase item = base.GetItem(agentID, itemID); 408 InventoryItemBase item = base.GetItem(agentID, itemID);
@@ -346,7 +437,15 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
346 InventoryFolderBase root = m_Scene.InventoryService.GetRootFolder(client.AgentId); 437 InventoryFolderBase root = m_Scene.InventoryService.GetRootFolder(client.AgentId);
347 InventoryCollection content = m_Scene.InventoryService.GetFolderContent(client.AgentId, root.ID); 438 InventoryCollection content = m_Scene.InventoryService.GetFolderContent(client.AgentId, root.ID);
348 439
349 inv.SendBulkUpdateInventory(content.Folders.ToArray(), content.Items.ToArray()); 440 List<InventoryFolderBase> keep = new List<InventoryFolderBase>();
441
442 foreach (InventoryFolderBase f in content.Folders)
443 {
444 if (f.Name != "My Suitcase" && f.Name != "Current Outfit")
445 keep.Add(f);
446 }
447
448 inv.SendBulkUpdateInventory(keep.ToArray(), content.Items.ToArray());
350 } 449 }
351 } 450 }
352 } 451 }
@@ -379,7 +478,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
379 478
380 foreach (InventoryFolderBase f in content.Folders) 479 foreach (InventoryFolderBase f in content.Folders)
381 { 480 {
382 if (f.Name != "My Suitcase") 481 if (f.Name != "My Suitcase" && f.Name != "Current Outfit")
383 { 482 {
384 f.Name = f.Name + " (Unavailable)"; 483 f.Name = f.Name + " (Unavailable)";
385 keep.Add(f); 484 keep.Add(f);
@@ -404,5 +503,36 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
404 } 503 }
405 504
406 #endregion 505 #endregion
506
507 #region Permissions
508
509 private bool CanTakeObject(UUID objectID, UUID stealer, Scene scene)
510 {
511 if (m_bypassPermissions) return true;
512
513 if (!m_OutboundPermission && !UserManagementModule.IsLocalGridUser(stealer))
514 {
515 SceneObjectGroup sog = null;
516 if (m_Scene.TryGetSceneObjectGroup(objectID, out sog) && sog.OwnerID == stealer)
517 return true;
518
519 return false;
520 }
521
522 return true;
523 }
524
525 private bool OnTransferUserInventory(UUID itemID, UUID userID, UUID recipientID)
526 {
527 if (m_bypassPermissions) return true;
528
529 if (!m_OutboundPermission && !UserManagementModule.IsLocalGridUser(recipientID))
530 return false;
531
532 return true;
533 }
534
535
536 #endregion
407 } 537 }
408} \ No newline at end of file 538} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs
index 8b7c16e..5a9efb8 100644
--- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs
@@ -47,6 +47,7 @@ using OpenMetaverse;
47using log4net; 47using log4net;
48using Nini.Config; 48using Nini.Config;
49using Mono.Addins; 49using Mono.Addins;
50using PermissionMask = OpenSim.Framework.PermissionMask;
50 51
51namespace OpenSim.Region.CoreModules.Framework.InventoryAccess 52namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
52{ 53{
@@ -202,7 +203,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
202 m_Scene.AssetService.Store(asset); 203 m_Scene.AssetService.Store(asset);
203 m_Scene.CreateNewInventoryItem( 204 m_Scene.CreateNewInventoryItem(
204 remoteClient, remoteClient.AgentId.ToString(), string.Empty, folderID, 205 remoteClient, remoteClient.AgentId.ToString(), string.Empty, folderID,
205 name, description, 0, callbackID, asset, invType, nextOwnerMask, creationDate); 206 name, description, 0, callbackID, asset.FullID, asset.Type, invType, nextOwnerMask, creationDate);
206 } 207 }
207 else 208 else
208 { 209 {
@@ -259,7 +260,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
259 return UUID.Zero; 260 return UUID.Zero;
260 } 261 }
261 262
262 remoteClient.SendAgentAlertMessage("Notecard saved", false); 263 remoteClient.SendAlertMessage("Notecard saved");
263 } 264 }
264 else if ((InventoryType)item.InvType == InventoryType.LSL) 265 else if ((InventoryType)item.InvType == InventoryType.LSL)
265 { 266 {
@@ -269,7 +270,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
269 return UUID.Zero; 270 return UUID.Zero;
270 } 271 }
271 272
272 remoteClient.SendAgentAlertMessage("Script saved", false); 273 remoteClient.SendAlertMessage("Script saved");
273 } 274 }
274 275
275 AssetBase asset = 276 AssetBase asset =
@@ -291,7 +292,34 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
291 292
292 return UUID.Zero; 293 return UUID.Zero;
293 } 294 }
294 295
296 public virtual bool UpdateInventoryItemAsset(UUID ownerID, InventoryItemBase item, AssetBase asset)
297 {
298 if (item != null && item.Owner == ownerID && asset != null)
299 {
300// m_log.DebugFormat(
301// "[INVENTORY ACCESS MODULE]: Updating item {0} {1} with new asset {2}",
302// item.Name, item.ID, asset.ID);
303
304 item.AssetID = asset.FullID;
305 item.Description = asset.Description;
306 item.Name = asset.Name;
307 item.AssetType = asset.Type;
308 item.InvType = (int)InventoryType.Object;
309
310 m_Scene.AssetService.Store(asset);
311 m_Scene.InventoryService.UpdateItem(item);
312
313 return true;
314 }
315 else
316 {
317 m_log.ErrorFormat("[INVENTORY ACCESS MODULE]: Given invalid item for inventory update: {0}",
318 (item == null || asset == null? "null item or asset" : "wrong owner"));
319 return false;
320 }
321 }
322
295 public virtual List<InventoryItemBase> CopyToInventory( 323 public virtual List<InventoryItemBase> CopyToInventory(
296 DeRezAction action, UUID folderID, 324 DeRezAction action, UUID folderID,
297 List<SceneObjectGroup> objectGroups, IClientAPI remoteClient, bool asAttachment) 325 List<SceneObjectGroup> objectGroups, IClientAPI remoteClient, bool asAttachment)
@@ -352,23 +380,32 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
352 bool asAttachment) 380 bool asAttachment)
353 { 381 {
354 CoalescedSceneObjects coa = new CoalescedSceneObjects(UUID.Zero); 382 CoalescedSceneObjects coa = new CoalescedSceneObjects(UUID.Zero);
355 Dictionary<UUID, Vector3> originalPositions = new Dictionary<UUID, Vector3>(); 383// Dictionary<UUID, Vector3> originalPositions = new Dictionary<UUID, Vector3>();
384
385 Dictionary<SceneObjectGroup, KeyframeMotion> group2Keyframe = new Dictionary<SceneObjectGroup, KeyframeMotion>();
356 386
357 foreach (SceneObjectGroup objectGroup in objlist) 387 foreach (SceneObjectGroup objectGroup in objlist)
358 { 388 {
359 Vector3 inventoryStoredPosition = new Vector3 389 if (objectGroup.RootPart.KeyframeMotion != null)
360 (((objectGroup.AbsolutePosition.X > (int)Constants.RegionSize) 390 {
361 ? 250 391 objectGroup.RootPart.KeyframeMotion.Pause();
362 : objectGroup.AbsolutePosition.X) 392 group2Keyframe.Add(objectGroup, objectGroup.RootPart.KeyframeMotion);
363 , 393 objectGroup.RootPart.KeyframeMotion = null;
364 (objectGroup.AbsolutePosition.Y > (int)Constants.RegionSize) 394 }
365 ? 250
366 : objectGroup.AbsolutePosition.Y,
367 objectGroup.AbsolutePosition.Z);
368
369 originalPositions[objectGroup.UUID] = objectGroup.AbsolutePosition;
370 395
371 objectGroup.AbsolutePosition = inventoryStoredPosition; 396// Vector3 inventoryStoredPosition = new Vector3
397// (((objectGroup.AbsolutePosition.X > (int)Constants.RegionSize)
398// ? 250
399// : objectGroup.AbsolutePosition.X)
400// ,
401// (objectGroup.AbsolutePosition.Y > (int)Constants.RegionSize)
402// ? 250
403// : objectGroup.AbsolutePosition.Y,
404// objectGroup.AbsolutePosition.Z);
405//
406// originalPositions[objectGroup.UUID] = objectGroup.AbsolutePosition;
407//
408// objectGroup.AbsolutePosition = inventoryStoredPosition;
372 409
373 // Make sure all bits but the ones we want are clear 410 // Make sure all bits but the ones we want are clear
374 // on take. 411 // on take.
@@ -377,7 +414,8 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
377 objectGroup.RootPart.NextOwnerMask &= 414 objectGroup.RootPart.NextOwnerMask &=
378 ((uint)PermissionMask.Copy | 415 ((uint)PermissionMask.Copy |
379 (uint)PermissionMask.Transfer | 416 (uint)PermissionMask.Transfer |
380 (uint)PermissionMask.Modify); 417 (uint)PermissionMask.Modify |
418 (uint)PermissionMask.Export);
381 objectGroup.RootPart.NextOwnerMask |= 419 objectGroup.RootPart.NextOwnerMask |=
382 (uint)PermissionMask.Move; 420 (uint)PermissionMask.Move;
383 421
@@ -395,9 +433,9 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
395 else 433 else
396 itemXml = SceneObjectSerializer.ToOriginalXmlFormat(objlist[0], !asAttachment); 434 itemXml = SceneObjectSerializer.ToOriginalXmlFormat(objlist[0], !asAttachment);
397 435
398 // Restore the position of each group now that it has been stored to inventory. 436// // Restore the position of each group now that it has been stored to inventory.
399 foreach (SceneObjectGroup objectGroup in objlist) 437// foreach (SceneObjectGroup objectGroup in objlist)
400 objectGroup.AbsolutePosition = originalPositions[objectGroup.UUID]; 438// objectGroup.AbsolutePosition = originalPositions[objectGroup.UUID];
401 439
402 InventoryItemBase item = CreateItemForObject(action, remoteClient, objlist[0], folderID); 440 InventoryItemBase item = CreateItemForObject(action, remoteClient, objlist[0], folderID);
403 441
@@ -407,17 +445,28 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
407 445
408 if (item == null) 446 if (item == null)
409 return null; 447 return null;
448
449 item.CreatorId = objlist[0].RootPart.CreatorID.ToString();
450 item.CreatorData = objlist[0].RootPart.CreatorData;
410 451
411 // Can't know creator is the same, so null it in inventory
412 if (objlist.Count > 1) 452 if (objlist.Count > 1)
413 { 453 {
414 item.CreatorId = UUID.Zero.ToString();
415 item.Flags = (uint)InventoryItemFlags.ObjectHasMultipleItems; 454 item.Flags = (uint)InventoryItemFlags.ObjectHasMultipleItems;
455
456 // If the objects have different creators then don't specify a creator at all
457 foreach (SceneObjectGroup objectGroup in objlist)
458 {
459 if ((objectGroup.RootPart.CreatorID.ToString() != item.CreatorId)
460 || (objectGroup.RootPart.CreatorData.ToString() != item.CreatorData))
461 {
462 item.CreatorId = UUID.Zero.ToString();
463 item.CreatorData = string.Empty;
464 break;
465 }
466 }
416 } 467 }
417 else 468 else
418 { 469 {
419 item.CreatorId = objlist[0].RootPart.CreatorID.ToString();
420 item.CreatorData = objlist[0].RootPart.CreatorData;
421 item.SaleType = objlist[0].RootPart.ObjectSaleType; 470 item.SaleType = objlist[0].RootPart.ObjectSaleType;
422 item.SalePrice = objlist[0].RootPart.SalePrice; 471 item.SalePrice = objlist[0].RootPart.SalePrice;
423 } 472 }
@@ -438,13 +487,13 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
438 } 487 }
439 else 488 else
440 { 489 {
441 AddPermissions(item, objlist[0], objlist, remoteClient);
442
443 item.CreationDate = Util.UnixTimeSinceEpoch(); 490 item.CreationDate = Util.UnixTimeSinceEpoch();
444 item.Description = asset.Description; 491 item.Description = asset.Description;
445 item.Name = asset.Name; 492 item.Name = asset.Name;
446 item.AssetType = asset.Type; 493 item.AssetType = asset.Type;
447 494
495 AddPermissions(item, objlist[0], objlist, remoteClient);
496
448 m_Scene.AddInventoryItem(item); 497 m_Scene.AddInventoryItem(item);
449 498
450 if (remoteClient != null && item.Owner == remoteClient.AgentId) 499 if (remoteClient != null && item.Owner == remoteClient.AgentId)
@@ -461,6 +510,13 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
461 } 510 }
462 } 511 }
463 512
513 // Restore KeyframeMotion
514 foreach (SceneObjectGroup objectGroup in group2Keyframe.Keys)
515 {
516 objectGroup.RootPart.KeyframeMotion = group2Keyframe[objectGroup];
517 objectGroup.RootPart.KeyframeMotion.Start();
518 }
519
464 // This is a hook to do some per-asset post-processing for subclasses that need that 520 // This is a hook to do some per-asset post-processing for subclasses that need that
465 if (remoteClient != null) 521 if (remoteClient != null)
466 ExportAsset(remoteClient.AgentId, asset.FullID); 522 ExportAsset(remoteClient.AgentId, asset.FullID);
@@ -485,49 +541,65 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
485 InventoryItemBase item, SceneObjectGroup so, List<SceneObjectGroup> objsForEffectivePermissions, 541 InventoryItemBase item, SceneObjectGroup so, List<SceneObjectGroup> objsForEffectivePermissions,
486 IClientAPI remoteClient) 542 IClientAPI remoteClient)
487 { 543 {
488 uint effectivePerms = (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify | PermissionMask.Move) | 7; 544 uint effectivePerms = (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify | PermissionMask.Move | PermissionMask.Export) | 7;
545 uint allObjectsNextOwnerPerms = 0x7fffffff;
546 uint allObjectsEveryOnePerms = 0x7fffffff;
547 uint allObjectsGroupPerms = 0x7fffffff;
548
489 foreach (SceneObjectGroup grp in objsForEffectivePermissions) 549 foreach (SceneObjectGroup grp in objsForEffectivePermissions)
550 {
490 effectivePerms &= grp.GetEffectivePermissions(); 551 effectivePerms &= grp.GetEffectivePermissions();
552 allObjectsNextOwnerPerms &= grp.RootPart.NextOwnerMask;
553 allObjectsEveryOnePerms &= grp.RootPart.EveryoneMask;
554 allObjectsGroupPerms &= grp.RootPart.GroupMask;
555 }
491 effectivePerms |= (uint)PermissionMask.Move; 556 effectivePerms |= (uint)PermissionMask.Move;
492 557
558 //PermissionsUtil.LogPermissions(item.Name, "Before AddPermissions", item.BasePermissions, item.CurrentPermissions, item.NextPermissions);
559
493 if (remoteClient != null && (remoteClient.AgentId != so.RootPart.OwnerID) && m_Scene.Permissions.PropagatePermissions()) 560 if (remoteClient != null && (remoteClient.AgentId != so.RootPart.OwnerID) && m_Scene.Permissions.PropagatePermissions())
494 { 561 {
562 // Changing ownership, so apply the "Next Owner" permissions to all of the
563 // inventory item's permissions.
564
495 uint perms = effectivePerms; 565 uint perms = effectivePerms;
496 uint nextPerms = (perms & 7) << 13; 566 PermissionsUtil.ApplyFoldedPermissions(effectivePerms, ref perms);
497 if ((nextPerms & (uint)PermissionMask.Copy) == 0) 567
498 perms &= ~(uint)PermissionMask.Copy; 568 item.BasePermissions = perms & allObjectsNextOwnerPerms;
499 if ((nextPerms & (uint)PermissionMask.Transfer) == 0)
500 perms &= ~(uint)PermissionMask.Transfer;
501 if ((nextPerms & (uint)PermissionMask.Modify) == 0)
502 perms &= ~(uint)PermissionMask.Modify;
503
504 item.BasePermissions = perms & so.RootPart.NextOwnerMask;
505 item.CurrentPermissions = item.BasePermissions; 569 item.CurrentPermissions = item.BasePermissions;
506 item.NextPermissions = perms & so.RootPart.NextOwnerMask; 570 item.NextPermissions = perms & allObjectsNextOwnerPerms;
507 item.EveryOnePermissions = so.RootPart.EveryoneMask & so.RootPart.NextOwnerMask; 571 item.EveryOnePermissions = allObjectsEveryOnePerms & allObjectsNextOwnerPerms;
508 item.GroupPermissions = so.RootPart.GroupMask & so.RootPart.NextOwnerMask; 572 item.GroupPermissions = allObjectsGroupPerms & allObjectsNextOwnerPerms;
509 573
510 // Magic number badness. Maybe this deserves an enum. 574 // apply next owner perms on rez
511 // bit 4 (16) is the "Slam" bit, it means treat as passed 575 item.CurrentPermissions |= SceneObjectGroup.SLAM;
512 // and apply next owner perms on rez
513 item.CurrentPermissions |= 16; // Slam!
514 } 576 }
515 else 577 else
516 { 578 {
579 // Not changing ownership.
580 // In this case we apply the permissions in the object's items ONLY to the inventory
581 // item's "Next Owner" permissions, but NOT to its "Current", "Base", etc. permissions.
582 // E.g., if the object contains a No-Transfer item then the item's "Next Owner"
583 // permissions are also No-Transfer.
584 PermissionsUtil.ApplyFoldedPermissions(effectivePerms, ref allObjectsNextOwnerPerms);
585
517 item.BasePermissions = effectivePerms; 586 item.BasePermissions = effectivePerms;
518 item.CurrentPermissions = effectivePerms; 587 item.CurrentPermissions = effectivePerms;
519 item.NextPermissions = so.RootPart.NextOwnerMask & effectivePerms; 588 item.NextPermissions = allObjectsNextOwnerPerms & effectivePerms;
520 item.EveryOnePermissions = so.RootPart.EveryoneMask & effectivePerms; 589 item.EveryOnePermissions = allObjectsEveryOnePerms & effectivePerms;
521 item.GroupPermissions = so.RootPart.GroupMask & effectivePerms; 590 item.GroupPermissions = allObjectsGroupPerms & effectivePerms;
522 591
523 item.CurrentPermissions &= 592 item.CurrentPermissions &=
524 ((uint)PermissionMask.Copy | 593 ((uint)PermissionMask.Copy |
525 (uint)PermissionMask.Transfer | 594 (uint)PermissionMask.Transfer |
526 (uint)PermissionMask.Modify | 595 (uint)PermissionMask.Modify |
527 (uint)PermissionMask.Move | 596 (uint)PermissionMask.Move |
597 (uint)PermissionMask.Export |
528 7); // Preserve folded permissions 598 7); // Preserve folded permissions
529 } 599 }
530 600
601 //PermissionsUtil.LogPermissions(item.Name, "After AddPermissions", item.BasePermissions, item.CurrentPermissions, item.NextPermissions);
602
531 return item; 603 return item;
532 } 604 }
533 605
@@ -542,6 +614,10 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
542 protected InventoryItemBase CreateItemForObject( 614 protected InventoryItemBase CreateItemForObject(
543 DeRezAction action, IClientAPI remoteClient, SceneObjectGroup so, UUID folderID) 615 DeRezAction action, IClientAPI remoteClient, SceneObjectGroup so, UUID folderID)
544 { 616 {
617// m_log.DebugFormat(
618// "[BASIC INVENTORY ACCESS MODULE]: Creating item for object {0} {1} for folder {2}, action {3}",
619// so.Name, so.UUID, folderID, action);
620//
545 // Get the user info of the item destination 621 // Get the user info of the item destination
546 // 622 //
547 UUID userID = UUID.Zero; 623 UUID userID = UUID.Zero;
@@ -619,18 +695,18 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
619 if (remoteClient == null || 695 if (remoteClient == null ||
620 so.OwnerID != remoteClient.AgentId) 696 so.OwnerID != remoteClient.AgentId)
621 { 697 {
622 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.LostAndFoundFolder); 698 folder = m_Scene.InventoryService.GetFolderForType(userID, FolderType.LostAndFound);
623 } 699 }
624 else 700 else
625 { 701 {
626 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.TrashFolder); 702 folder = m_Scene.InventoryService.GetFolderForType(userID, FolderType.Trash);
627 } 703 }
628 } 704 }
629 else if (action == DeRezAction.Return) 705 else if (action == DeRezAction.Return)
630 { 706 {
631 // Dump to lost + found unconditionally 707 // Dump to lost + found unconditionally
632 // 708 //
633 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.LostAndFoundFolder); 709 folder = m_Scene.InventoryService.GetFolderForType(userID, FolderType.LostAndFound);
634 } 710 }
635 711
636 if (folderID == UUID.Zero && folder == null) 712 if (folderID == UUID.Zero && folder == null)
@@ -639,21 +715,22 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
639 { 715 {
640 // Deletes go to trash by default 716 // Deletes go to trash by default
641 // 717 //
642 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.TrashFolder); 718 folder = m_Scene.InventoryService.GetFolderForType(userID, FolderType.Trash);
643 } 719 }
644 else 720 else
645 { 721 {
646 if (remoteClient == null || so.OwnerID != remoteClient.AgentId) 722 if (remoteClient == null || so.RootPart.OwnerID != remoteClient.AgentId)
647 { 723 {
648 // Taking copy of another person's item. Take to 724 // Taking copy of another person's item. Take to
649 // Objects folder. 725 // Objects folder.
650 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.Object); 726 folder = m_Scene.InventoryService.GetFolderForType(userID, FolderType.Object);
727 so.FromFolderID = UUID.Zero;
651 } 728 }
652 else 729 else
653 { 730 {
654 // Catch all. Use lost & found 731 // Catch all. Use lost & found
655 // 732 //
656 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.LostAndFoundFolder); 733 folder = m_Scene.InventoryService.GetFolderForType(userID, FolderType.LostAndFound);
657 } 734 }
658 } 735 }
659 } 736 }
@@ -663,10 +740,16 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
663 // 740 //
664 if (action == DeRezAction.Take || action == DeRezAction.TakeCopy) 741 if (action == DeRezAction.Take || action == DeRezAction.TakeCopy)
665 { 742 {
666 if (so.FromFolderID != UUID.Zero && userID == remoteClient.AgentId) 743 if (so.FromFolderID != UUID.Zero && so.RootPart.OwnerID == remoteClient.AgentId)
667 { 744 {
668 InventoryFolderBase f = new InventoryFolderBase(so.FromFolderID, userID); 745 InventoryFolderBase f = new InventoryFolderBase(so.FromFolderID, userID);
669 folder = m_Scene.InventoryService.GetFolder(f); 746 folder = m_Scene.InventoryService.GetFolder(f);
747
748 if(folder.Type == 14 || folder.Type == 16)
749 {
750 // folder.Type = 6;
751 folder = m_Scene.InventoryService.GetFolderForType(userID, FolderType.Object);
752 }
670 } 753 }
671 } 754 }
672 755
@@ -722,7 +805,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
722 UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection, 805 UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection,
723 bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment) 806 bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment)
724 { 807 {
725 AssetBase rezAsset = m_Scene.AssetService.Get(assetID.ToString()); 808 AssetBase rezAsset = m_Scene.AssetService.Get(assetID.ToString());
726 809
727 if (rezAsset == null) 810 if (rezAsset == null)
728 { 811 {
@@ -731,12 +814,14 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
731 m_log.WarnFormat( 814 m_log.WarnFormat(
732 "[InventoryAccessModule]: Could not find asset {0} for item {1} {2} for {3} in RezObject()", 815 "[InventoryAccessModule]: Could not find asset {0} for item {1} {2} for {3} in RezObject()",
733 assetID, item.Name, item.ID, remoteClient.Name); 816 assetID, item.Name, item.ID, remoteClient.Name);
817 remoteClient.SendAgentAlertMessage(string.Format("Unable to rez: could not find asset {0} for item {1}.", assetID, item.Name), false);
734 } 818 }
735 else 819 else
736 { 820 {
737 m_log.WarnFormat( 821 m_log.WarnFormat(
738 "[INVENTORY ACCESS MODULE]: Could not find asset {0} for {1} in RezObject()", 822 "[INVENTORY ACCESS MODULE]: Could not find asset {0} for {1} in RezObject()",
739 assetID, remoteClient.Name); 823 assetID, remoteClient.Name);
824 remoteClient.SendAgentAlertMessage(string.Format("Unable to rez: could not find asset {0}.", assetID), false);
740 } 825 }
741 826
742 return null; 827 return null;
@@ -744,67 +829,34 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
744 829
745 SceneObjectGroup group = null; 830 SceneObjectGroup group = null;
746 831
747 string xmlData = Utils.BytesToString(rezAsset.Data); 832 List<SceneObjectGroup> objlist;
748 List<SceneObjectGroup> objlist = new List<SceneObjectGroup>(); 833 List<Vector3> veclist;
749 List<Vector3> veclist = new List<Vector3>(); 834 Vector3 bbox;
835 float offsetHeight;
750 byte bRayEndIsIntersection = (byte)(RayEndIsIntersection ? 1 : 0); 836 byte bRayEndIsIntersection = (byte)(RayEndIsIntersection ? 1 : 0);
751 Vector3 pos; 837 Vector3 pos;
752 838
753 XmlDocument doc = new XmlDocument(); 839 bool single
754 doc.LoadXml(xmlData); 840 = m_Scene.GetObjectsToRez(
755 XmlElement e = (XmlElement)doc.SelectSingleNode("/CoalescedObject"); 841 rezAsset.Data, attachment, out objlist, out veclist, out bbox, out offsetHeight);
756 if (e == null || attachment) // Single
757 {
758 SceneObjectGroup g = SceneObjectSerializer.FromOriginalXmlFormat(xmlData);
759
760 objlist.Add(g);
761 veclist.Add(new Vector3(0, 0, 0));
762 842
763 float offsetHeight = 0; 843 if (single)
844 {
764 pos = m_Scene.GetNewRezLocation( 845 pos = m_Scene.GetNewRezLocation(
765 RayStart, RayEnd, RayTargetID, Quaternion.Identity, 846 RayStart, RayEnd, RayTargetID, Quaternion.Identity,
766 BypassRayCast, bRayEndIsIntersection, true, g.GetAxisAlignedBoundingBox(out offsetHeight), false); 847 BypassRayCast, bRayEndIsIntersection, true, bbox, false);
767 pos.Z += offsetHeight; 848 pos.Z += offsetHeight;
768 } 849 }
769 else 850 else
770 { 851 {
771 XmlElement coll = (XmlElement)e;
772 float bx = Convert.ToSingle(coll.GetAttribute("x"));
773 float by = Convert.ToSingle(coll.GetAttribute("y"));
774 float bz = Convert.ToSingle(coll.GetAttribute("z"));
775 Vector3 bbox = new Vector3(bx, by, bz);
776
777 pos = m_Scene.GetNewRezLocation(RayStart, RayEnd, 852 pos = m_Scene.GetNewRezLocation(RayStart, RayEnd,
778 RayTargetID, Quaternion.Identity, 853 RayTargetID, Quaternion.Identity,
779 BypassRayCast, bRayEndIsIntersection, true, 854 BypassRayCast, bRayEndIsIntersection, true,
780 bbox, false); 855 bbox, false);
781
782 pos -= bbox / 2; 856 pos -= bbox / 2;
783
784 XmlNodeList groups = e.SelectNodes("SceneObjectGroup");
785 foreach (XmlNode n in groups)
786 {
787 SceneObjectGroup g = SceneObjectSerializer.FromOriginalXmlFormat(n.OuterXml);
788
789 objlist.Add(g);
790 XmlElement el = (XmlElement)n;
791
792 string rawX = el.GetAttribute("offsetx");
793 string rawY = el.GetAttribute("offsety");
794 string rawZ = el.GetAttribute("offsetz");
795//
796// m_log.DebugFormat(
797// "[INVENTORY ACCESS MODULE]: Converting coalesced object {0} offset <{1}, {2}, {3}>",
798// g.Name, rawX, rawY, rawZ);
799
800 float x = Convert.ToSingle(rawX);
801 float y = Convert.ToSingle(rawY);
802 float z = Convert.ToSingle(rawZ);
803 veclist.Add(new Vector3(x, y, z));
804 }
805 } 857 }
806 858
807 if (item != null && !DoPreRezWhenFromItem(remoteClient, item, objlist, pos, attachment)) 859 if (item != null && !DoPreRezWhenFromItem(remoteClient, item, objlist, pos, veclist, attachment))
808 return null; 860 return null;
809 861
810 for (int i = 0; i < objlist.Count; i++) 862 for (int i = 0; i < objlist.Count; i++)
@@ -823,11 +875,23 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
823 m_log.Debug("[INVENTORY ACCESS MODULE]: Object has UUID.Zero! Position 3"); 875 m_log.Debug("[INVENTORY ACCESS MODULE]: Object has UUID.Zero! Position 3");
824 } 876 }
825 877
826 foreach (SceneObjectPart part in group.Parts) 878 // if this was previously an attachment and is now being rezzed,
879 // save the old attachment info.
880 if (group.IsAttachment == false && group.RootPart.Shape.State != 0)
827 { 881 {
828 // Make the rezzer the owner, as this is not necessarily set correctly in the serialized asset. 882 group.RootPart.AttachedPos = group.AbsolutePosition;
829 part.LastOwnerID = part.OwnerID; 883 group.RootPart.Shape.LastAttachPoint = (byte)group.AttachmentPoint;
830 part.OwnerID = remoteClient.AgentId; 884 }
885
886 if (item == null)
887 {
888 // Change ownership. Normally this is done in DoPreRezWhenFromItem(), but in this case we must do it here.
889 foreach (SceneObjectPart part in group.Parts)
890 {
891 // Make the rezzer the owner, as this is not necessarily set correctly in the serialized asset.
892 part.LastOwnerID = part.OwnerID;
893 part.OwnerID = remoteClient.AgentId;
894 }
831 } 895 }
832 896
833 if (!attachment) 897 if (!attachment)
@@ -855,7 +919,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
855 // one full update during the attachment 919 // one full update during the attachment
856 // process causes some clients to fail to display the 920 // process causes some clients to fail to display the
857 // attachment properly. 921 // attachment properly.
858 m_Scene.AddNewSceneObject(group, true, false); 922 m_Scene.AddNewSceneObject(group, !attachment, false);
859 923
860 // if attachment we set it's asset id so object updates 924 // if attachment we set it's asset id so object updates
861 // can reflect that, if not, we set it's position in world. 925 // can reflect that, if not, we set it's position in world.
@@ -902,10 +966,15 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
902 /// <param name="item"></param> 966 /// <param name="item"></param>
903 /// <param name="objlist"></param> 967 /// <param name="objlist"></param>
904 /// <param name="pos"></param> 968 /// <param name="pos"></param>
969 /// <param name="veclist">
970 /// List of vector position adjustments for a coalesced objects. For ordinary objects
971 /// this list will contain just Vector3.Zero. The order of adjustments must match the order of objlist
972 /// </param>
905 /// <param name="isAttachment"></param> 973 /// <param name="isAttachment"></param>
906 /// <returns>true if we can processed with rezzing, false if we need to abort</returns> 974 /// <returns>true if we can processed with rezzing, false if we need to abort</returns>
907 private bool DoPreRezWhenFromItem( 975 private bool DoPreRezWhenFromItem(
908 IClientAPI remoteClient, InventoryItemBase item, List<SceneObjectGroup> objlist, Vector3 pos, bool isAttachment) 976 IClientAPI remoteClient, InventoryItemBase item, List<SceneObjectGroup> objlist,
977 Vector3 pos, List<Vector3> veclist, bool isAttachment)
909 { 978 {
910 UUID fromUserInventoryItemId = UUID.Zero; 979 UUID fromUserInventoryItemId = UUID.Zero;
911 980
@@ -928,28 +997,29 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
928 } 997 }
929 } 998 }
930 999
931 int primcount = 0; 1000 for (int i = 0; i < objlist.Count; i++)
932 foreach (SceneObjectGroup g in objlist)
933 primcount += g.PrimCount;
934
935 if (!m_Scene.Permissions.CanRezObject(
936 primcount, remoteClient.AgentId, pos)
937 && !isAttachment)
938 { 1001 {
939 // The client operates in no fail mode. It will 1002 SceneObjectGroup g = objlist[i];
940 // have already removed the item from the folder
941 // if it's no copy.
942 // Put it back if it's not an attachment
943 //
944 if (((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0) && (!isAttachment))
945 remoteClient.SendBulkUpdateInventory(item);
946 1003
947 ILandObject land = m_Scene.LandChannel.GetLandObject(pos.X, pos.Y); 1004 if (!m_Scene.Permissions.CanRezObject(
948 remoteClient.SendAlertMessage(string.Format( 1005 g.PrimCount, remoteClient.AgentId, pos + veclist[i])
949 "Can't rez object '{0}' at <{1:F3}, {2:F3}, {3:F3}> on parcel '{4}' in region {5}.", 1006 && !isAttachment)
950 item.Name, pos.X, pos.Y, pos.Z, land != null ? land.LandData.Name : "Unknown", m_Scene.RegionInfo.RegionName)); 1007 {
1008 // The client operates in no fail mode. It will
1009 // have already removed the item from the folder
1010 // if it's no copy.
1011 // Put it back if it's not an attachment
1012 //
1013 if (((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0) && (!isAttachment))
1014 remoteClient.SendBulkUpdateInventory(item);
951 1015
952 return false; 1016 ILandObject land = m_Scene.LandChannel.GetLandObject(pos.X, pos.Y);
1017 remoteClient.SendAlertMessage(string.Format(
1018 "Can't rez object '{0}' at <{1:F3}, {2:F3}, {3:F3}> on parcel '{4}' in region {5}.",
1019 item.Name, pos.X, pos.Y, pos.Z, land != null ? land.LandData.Name : "Unknown", m_Scene.Name));
1020
1021 return false;
1022 }
953 } 1023 }
954 1024
955 for (int i = 0; i < objlist.Count; i++) 1025 for (int i = 0; i < objlist.Count; i++)
@@ -977,44 +1047,19 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
977// "[INVENTORY ACCESS MODULE]: rootPart.OwnedID {0}, item.Owner {1}, item.CurrentPermissions {2:X}", 1047// "[INVENTORY ACCESS MODULE]: rootPart.OwnedID {0}, item.Owner {1}, item.CurrentPermissions {2:X}",
978// rootPart.OwnerID, item.Owner, item.CurrentPermissions); 1048// rootPart.OwnerID, item.Owner, item.CurrentPermissions);
979 1049
980 if ((rootPart.OwnerID != item.Owner) || 1050 if ((rootPart.OwnerID != item.Owner) || (item.CurrentPermissions & SceneObjectGroup.SLAM) != 0)
981 (item.CurrentPermissions & 16) != 0)
982 { 1051 {
983 //Need to kill the for sale here 1052 //Need to kill the for sale here
984 rootPart.ObjectSaleType = 0; 1053 rootPart.ObjectSaleType = 0;
985 rootPart.SalePrice = 10; 1054 rootPart.SalePrice = 10;
986
987 if (m_Scene.Permissions.PropagatePermissions())
988 {
989 foreach (SceneObjectPart part in so.Parts)
990 {
991 if ((item.Flags & (uint)InventoryItemFlags.ObjectHasMultipleItems) == 0)
992 {
993 part.EveryoneMask = item.EveryOnePermissions;
994 part.NextOwnerMask = item.NextPermissions;
995 }
996 part.GroupMask = 0; // DO NOT propagate here
997 }
998
999 so.ApplyNextOwnerPermissions();
1000 }
1001 } 1055 }
1002 1056
1003 foreach (SceneObjectPart part in so.Parts) 1057 foreach (SceneObjectPart part in so.Parts)
1004 { 1058 {
1005 part.FromUserInventoryItemID = fromUserInventoryItemId; 1059 part.FromUserInventoryItemID = fromUserInventoryItemId;
1006 1060 part.ApplyPermissionsOnRez(item, true, m_Scene);
1007 if ((part.OwnerID != item.Owner) ||
1008 (item.CurrentPermissions & 16) != 0)
1009 {
1010 part.Inventory.ChangeInventoryOwner(item.Owner);
1011 part.GroupMask = 0; // DO NOT propagate here
1012 }
1013
1014 part.EveryoneMask = item.EveryOnePermissions;
1015 part.NextOwnerMask = item.NextPermissions;
1016 } 1061 }
1017 1062
1018 rootPart.TrimPermissions(); 1063 rootPart.TrimPermissions();
1019 1064
1020 if (isAttachment) 1065 if (isAttachment)
@@ -1150,4 +1195,4 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
1150 1195
1151 #endregion 1196 #endregion
1152 } 1197 }
1153} \ No newline at end of file 1198}
diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/HGAssetMapperTests.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/HGAssetMapperTests.cs
new file mode 100644
index 0000000..007ff63
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/HGAssetMapperTests.cs
@@ -0,0 +1,146 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Threading;
30using System.Xml;
31using Nini.Config;
32using NUnit.Framework;
33using OpenMetaverse;
34using OpenSim.Framework;
35using OpenSim.Region.CoreModules.Framework.InventoryAccess;
36using OpenSim.Region.Framework.Scenes;
37using OpenSim.Region.ScriptEngine.XEngine;
38using OpenSim.Services.Interfaces;
39using OpenSim.Tests.Common;
40
41namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests
42{
43 [TestFixture]
44 public class HGAssetMapperTests : OpenSimTestCase
45 {
46 [Test]
47 public void TestPostAssetRewrite()
48 {
49 TestHelpers.InMethod();
50// TestHelpers.EnableLogging();
51
52 XEngine xengine = new OpenSim.Region.ScriptEngine.XEngine.XEngine();
53 xengine.DebugLevel = 1;
54
55 IniConfigSource configSource = new IniConfigSource();
56
57 IConfig startupConfig = configSource.AddConfig("Startup");
58 startupConfig.Set("DefaultScriptEngine", "XEngine");
59
60 IConfig xEngineConfig = configSource.AddConfig("XEngine");
61 xEngineConfig.Set("Enabled", "true");
62 xEngineConfig.Set("StartDelay", "0");
63 xEngineConfig.Set("AppDomainLoading", "false");
64
65 string homeUrl = "http://hg.HomeTestPostAssetRewriteGrid.com";
66 string foreignUrl = "http://hg.ForeignTestPostAssetRewriteGrid.com";
67 int soIdTail = 0x1;
68 UUID assetId = TestHelpers.ParseTail(0x10);
69 UUID userId = TestHelpers.ParseTail(0x100);
70 UUID sceneId = TestHelpers.ParseTail(0x1000);
71 string userFirstName = "TestPostAsset";
72 string userLastName = "Rewrite";
73 int soPartsCount = 3;
74
75 Scene scene = new SceneHelpers().SetupScene("TestPostAssetRewriteScene", sceneId, 1000, 1000, configSource);
76 SceneHelpers.SetupSceneModules(scene, configSource, xengine);
77 scene.StartScripts();
78
79 HGAssetMapper hgam = new HGAssetMapper(scene, homeUrl);
80 UserAccount ua
81 = UserAccountHelpers.CreateUserWithInventory(scene, userFirstName, userLastName, userId, "password");
82
83 SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, soPartsCount, ua.PrincipalID, "part", soIdTail);
84 RezScript(
85 scene, so.UUID, "default { state_entry() { llSay(0, \"Hello World\"); } }", "item1", ua.PrincipalID);
86
87 AssetBase asset = AssetHelpers.CreateAsset(assetId, so);
88 asset.CreatorID = foreignUrl;
89 hgam.PostAsset(foreignUrl, asset);
90
91 // Check transformed asset.
92 AssetBase ncAssetGet = scene.AssetService.Get(assetId.ToString());
93 Assert.AreEqual(foreignUrl, ncAssetGet.CreatorID);
94 string xmlData = Utils.BytesToString(ncAssetGet.Data);
95 XmlDocument ncAssetGetXmlDoc = new XmlDocument();
96 ncAssetGetXmlDoc.LoadXml(xmlData);
97
98// Console.WriteLine(ncAssetGetXmlDoc.OuterXml);
99
100 XmlNodeList creatorDataNodes = ncAssetGetXmlDoc.GetElementsByTagName("CreatorData");
101
102 Assert.AreEqual(soPartsCount, creatorDataNodes.Count);
103 //Console.WriteLine("creatorDataNodes {0}", creatorDataNodes.Count);
104
105 foreach (XmlNode creatorDataNode in creatorDataNodes)
106 {
107 Assert.AreEqual(
108 string.Format("{0};{1} {2}", homeUrl, ua.FirstName, ua.LastName), creatorDataNode.InnerText);
109 }
110
111 // Check that saved script nodes have attributes
112 XmlNodeList savedScriptStateNodes = ncAssetGetXmlDoc.GetElementsByTagName("SavedScriptState");
113
114 Assert.AreEqual(1, savedScriptStateNodes.Count);
115 Assert.AreEqual(1, savedScriptStateNodes[0].Attributes.Count);
116 XmlNode uuidAttribute = savedScriptStateNodes[0].Attributes.GetNamedItem("UUID");
117 Assert.NotNull(uuidAttribute);
118 // XXX: To check the actual UUID attribute we would have to do some work to retreive the UUID of the task
119 // item created earlier.
120 }
121
122 private void RezScript(Scene scene, UUID soId, string script, string itemName, UUID userId)
123 {
124 InventoryItemBase itemTemplate = new InventoryItemBase();
125 // itemTemplate.ID = itemId;
126 itemTemplate.Name = itemName;
127 itemTemplate.Folder = soId;
128 itemTemplate.InvType = (int)InventoryType.LSL;
129
130 // XXX: Ultimately it would be better to be able to directly manipulate the script engine to rez a script
131 // immediately for tests rather than chunter through it's threaded mechanisms.
132 AutoResetEvent chatEvent = new AutoResetEvent(false);
133
134 scene.EventManager.OnChatFromWorld += (s, c) =>
135 {
136// Console.WriteLine("Got chat [{0}]", c.Message);
137 chatEvent.Set();
138 };
139
140 scene.RezNewScript(userId, itemTemplate, script);
141
142// Console.WriteLine("HERE");
143 Assert.IsTrue(chatEvent.WaitOne(60000), "Chat event in HGAssetMapperTests.RezScript not received");
144 }
145 }
146} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs
index ac25a93..1d91165 100644
--- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs
+++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs
@@ -37,14 +37,12 @@ using OpenSim.Data;
37using OpenSim.Framework; 37using OpenSim.Framework;
38using OpenSim.Framework.Serialization; 38using OpenSim.Framework.Serialization;
39using OpenSim.Framework.Serialization.External; 39using OpenSim.Framework.Serialization.External;
40using OpenSim.Framework.Communications;
41using OpenSim.Region.CoreModules.Avatar.Inventory.Archiver; 40using OpenSim.Region.CoreModules.Avatar.Inventory.Archiver;
42using OpenSim.Region.CoreModules.Framework.InventoryAccess; 41using OpenSim.Region.CoreModules.Framework.InventoryAccess;
43using OpenSim.Region.Framework.Scenes; 42using OpenSim.Region.Framework.Scenes;
44using OpenSim.Region.Framework.Scenes.Serialization; 43using OpenSim.Region.Framework.Scenes.Serialization;
45using OpenSim.Services.Interfaces; 44using OpenSim.Services.Interfaces;
46using OpenSim.Tests.Common; 45using OpenSim.Tests.Common;
47using OpenSim.Tests.Common.Mock;
48 46
49namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests 47namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests
50{ 48{
@@ -109,8 +107,9 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests
109 item1.AssetID = asset1.FullID; 107 item1.AssetID = asset1.FullID;
110 item1.ID = item1Id; 108 item1.ID = item1Id;
111 InventoryFolderBase objsFolder 109 InventoryFolderBase objsFolder
112 = InventoryArchiveUtils.FindFolderByPath(m_scene.InventoryService, m_userId, "Objects")[0]; 110 = InventoryArchiveUtils.FindFoldersByPath(m_scene.InventoryService, m_userId, "Objects")[0];
113 item1.Folder = objsFolder.ID; 111 item1.Folder = objsFolder.ID;
112 item1.Flags |= (uint)InventoryItemFlags.ObjectHasMultipleItems;
114 m_scene.AddInventoryItem(item1); 113 m_scene.AddInventoryItem(item1);
115 114
116 SceneObjectGroup so 115 SceneObjectGroup so
@@ -159,7 +158,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests
159 item1.AssetID = asset1.FullID; 158 item1.AssetID = asset1.FullID;
160 item1.ID = item1Id; 159 item1.ID = item1Id;
161 InventoryFolderBase objsFolder 160 InventoryFolderBase objsFolder
162 = InventoryArchiveUtils.FindFolderByPath(m_scene.InventoryService, m_userId, "Objects")[0]; 161 = InventoryArchiveUtils.FindFoldersByPath(m_scene.InventoryService, m_userId, "Objects")[0];
163 item1.Folder = objsFolder.ID; 162 item1.Folder = objsFolder.ID;
164 m_scene.AddInventoryItem(item1); 163 m_scene.AddInventoryItem(item1);
165 164
diff --git a/OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs b/OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs
index ec22146..862f0b7 100644
--- a/OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs
@@ -30,7 +30,6 @@ using System.IO;
30using System.Reflection; 30using System.Reflection;
31 31
32using OpenSim.Framework; 32using OpenSim.Framework;
33using OpenSim.Framework.Communications;
34 33
35using OpenSim.Region.CoreModules.Avatar.Inventory.Archiver; 34using OpenSim.Region.CoreModules.Avatar.Inventory.Archiver;
36using OpenSim.Region.Framework; 35using OpenSim.Region.Framework;
@@ -43,6 +42,7 @@ using OpenMetaverse;
43using log4net; 42using log4net;
44using Mono.Addins; 43using Mono.Addins;
45using Nini.Config; 44using Nini.Config;
45using PermissionMask = OpenSim.Framework.PermissionMask;
46 46
47namespace OpenSim.Region.CoreModules.Framework.Library 47namespace OpenSim.Region.CoreModules.Framework.Library
48{ 48{
@@ -175,7 +175,7 @@ namespace OpenSim.Region.CoreModules.Framework.Library
175 m_log.InfoFormat("[LIBRARY MODULE]: Loading library archive {0} ({1})...", iarFileName, simpleName); 175 m_log.InfoFormat("[LIBRARY MODULE]: Loading library archive {0} ({1})...", iarFileName, simpleName);
176 simpleName = GetInventoryPathFromName(simpleName); 176 simpleName = GetInventoryPathFromName(simpleName);
177 177
178 InventoryArchiveReadRequest archread = new InventoryArchiveReadRequest(m_MockScene, uinfo, simpleName, iarFileName, false); 178 InventoryArchiveReadRequest archread = new InventoryArchiveReadRequest(m_MockScene.InventoryService, m_MockScene.AssetService, m_MockScene.UserAccountService, uinfo, simpleName, iarFileName, false);
179 try 179 try
180 { 180 {
181 HashSet<InventoryNodeBase> nodes = archread.Execute(); 181 HashSet<InventoryNodeBase> nodes = archread.Execute();
@@ -184,7 +184,7 @@ namespace OpenSim.Region.CoreModules.Framework.Library
184 // didn't find the subfolder with the given name; place it on the top 184 // didn't find the subfolder with the given name; place it on the top
185 m_log.InfoFormat("[LIBRARY MODULE]: Didn't find {0} in library. Placing archive on the top level", simpleName); 185 m_log.InfoFormat("[LIBRARY MODULE]: Didn't find {0} in library. Placing archive on the top level", simpleName);
186 archread.Close(); 186 archread.Close();
187 archread = new InventoryArchiveReadRequest(m_MockScene, uinfo, "/", iarFileName, false); 187 archread = new InventoryArchiveReadRequest(m_MockScene.InventoryService, m_MockScene.AssetService, m_MockScene.UserAccountService, uinfo, "/", iarFileName, false);
188 archread.Execute(); 188 archread.Execute();
189 } 189 }
190 190
diff --git a/OpenSim/Region/CoreModules/Framework/Library/LocalInventoryService.cs b/OpenSim/Region/CoreModules/Framework/Library/LocalInventoryService.cs
index 49589fd..e1e1838 100644
--- a/OpenSim/Region/CoreModules/Framework/Library/LocalInventoryService.cs
+++ b/OpenSim/Region/CoreModules/Framework/Library/LocalInventoryService.cs
@@ -65,7 +65,7 @@ namespace OpenSim.Region.CoreModules.Framework.Library
65 { 65 {
66 InventoryFolderImpl folder = null; 66 InventoryFolderImpl folder = null;
67 InventoryCollection inv = new InventoryCollection(); 67 InventoryCollection inv = new InventoryCollection();
68 inv.UserID = m_Library.Owner; 68 inv.OwnerID = m_Library.Owner;
69 69
70 if (folderID != m_Library.ID) 70 if (folderID != m_Library.ID)
71 { 71 {
@@ -87,6 +87,34 @@ namespace OpenSim.Region.CoreModules.Framework.Library
87 return inv; 87 return inv;
88 } 88 }
89 89
90 public virtual InventoryCollection[] GetMultipleFoldersContent(UUID principalID, UUID[] folderIDs)
91 {
92 InventoryCollection[] invColl = new InventoryCollection[folderIDs.Length];
93 int i = 0;
94 foreach (UUID fid in folderIDs)
95 {
96 invColl[i++] = GetFolderContent(principalID, fid);
97 }
98
99 return invColl;
100 }
101
102 public virtual InventoryItemBase[] GetMultipleItems(UUID principalID, UUID[] itemIDs)
103 {
104 InventoryItemBase[] itemColl = new InventoryItemBase[itemIDs.Length];
105 int i = 0;
106 InventoryItemBase item = new InventoryItemBase();
107 item.Owner = principalID;
108 foreach (UUID fid in itemIDs)
109 {
110 item.ID = fid;
111 itemColl[i++] = GetItem(item);
112 }
113
114 return itemColl;
115 }
116
117
90 /// <summary> 118 /// <summary>
91 /// Add a new folder to the user's inventory 119 /// Add a new folder to the user's inventory
92 /// </summary> 120 /// </summary>
@@ -142,28 +170,12 @@ namespace OpenSim.Region.CoreModules.Framework.Library
142 public List<InventoryFolderBase> GetInventorySkeleton(UUID userId) { return null; } 170 public List<InventoryFolderBase> GetInventorySkeleton(UUID userId) { return null; }
143 171
144 /// <summary> 172 /// <summary>
145 /// Synchronous inventory fetch.
146 /// </summary>
147 /// <param name="userID"></param>
148 /// <returns></returns>
149 public InventoryCollection GetUserInventory(UUID userID) { return null; }
150
151 /// <summary>
152 /// Request the inventory for a user. This is an asynchronous operation that will call the callback when the
153 /// inventory has been received
154 /// </summary>
155 /// <param name="userID"></param>
156 /// <param name="callback"></param>
157 public void GetUserInventory(UUID userID, InventoryReceiptCallback callback) { }
158
159
160 /// <summary>
161 /// Gets the user folder for the given folder-type 173 /// Gets the user folder for the given folder-type
162 /// </summary> 174 /// </summary>
163 /// <param name="userID"></param> 175 /// <param name="userID"></param>
164 /// <param name="type"></param> 176 /// <param name="type"></param>
165 /// <returns></returns> 177 /// <returns></returns>
166 public InventoryFolderBase GetFolderForType(UUID userID, AssetType type) { return null; } 178 public InventoryFolderBase GetFolderForType(UUID userID, FolderType type) { return null; }
167 179
168 180
169 /// <summary> 181 /// <summary>
diff --git a/OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs b/OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs
index d84460a..64feec1 100644
--- a/OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs
@@ -33,6 +33,7 @@ using log4net;
33using Nini.Config; 33using Nini.Config;
34using OpenMetaverse; 34using OpenMetaverse;
35using OpenSim.Framework; 35using OpenSim.Framework;
36using OpenSim.Framework.Monitoring;
36using OpenSim.Framework.Servers; 37using OpenSim.Framework.Servers;
37using OpenSim.Region.CoreModules.Framework.Monitoring.Alerts; 38using OpenSim.Region.CoreModules.Framework.Monitoring.Alerts;
38using OpenSim.Region.CoreModules.Framework.Monitoring.Monitors; 39using OpenSim.Region.CoreModules.Framework.Monitoring.Monitors;
@@ -100,6 +101,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
100 "/monitorstats/" + Uri.EscapeDataString(m_scene.RegionInfo.RegionName), StatsPage); 101 "/monitorstats/" + Uri.EscapeDataString(m_scene.RegionInfo.RegionName), StatsPage);
101 102
102 AddMonitors(); 103 AddMonitors();
104 RegisterStatsManagerRegionStatistics();
103 } 105 }
104 106
105 public void RemoveRegion(Scene scene) 107 public void RemoveRegion(Scene scene)
@@ -109,6 +111,9 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
109 111
110 MainServer.Instance.RemoveHTTPHandler("GET", "/monitorstats/" + m_scene.RegionInfo.RegionID); 112 MainServer.Instance.RemoveHTTPHandler("GET", "/monitorstats/" + m_scene.RegionInfo.RegionID);
111 MainServer.Instance.RemoveHTTPHandler("GET", "/monitorstats/" + Uri.EscapeDataString(m_scene.RegionInfo.RegionName)); 113 MainServer.Instance.RemoveHTTPHandler("GET", "/monitorstats/" + Uri.EscapeDataString(m_scene.RegionInfo.RegionName));
114
115 UnRegisterStatsManagerRegionStatistics();
116
112 m_scene = null; 117 m_scene = null;
113 } 118 }
114 119
@@ -399,6 +404,45 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
399 { 404 {
400 m_log.Error("[Monitor] " + reporter.Name + " for " + m_scene.RegionInfo.RegionName + " reports " + reason + " (Fatal: " + fatal + ")"); 405 m_log.Error("[Monitor] " + reporter.Name + " for " + m_scene.RegionInfo.RegionName + " reports " + reason + " (Fatal: " + fatal + ")");
401 } 406 }
407
408 private List<Stat> registeredStats = new List<Stat>();
409 private void MakeStat(string pName, string pUnitName, Action<Stat> act)
410 {
411 Stat tempStat = new Stat(pName, pName, pName, pUnitName, "scene", m_scene.RegionInfo.RegionName, StatType.Pull, act, StatVerbosity.Info);
412 StatsManager.RegisterStat(tempStat);
413 registeredStats.Add(tempStat);
414 }
415 private void RegisterStatsManagerRegionStatistics()
416 {
417 MakeStat("RootAgents", "avatars", (s) => { s.Value = m_scene.SceneGraph.GetRootAgentCount(); });
418 MakeStat("ChildAgents", "avatars", (s) => { s.Value = m_scene.SceneGraph.GetChildAgentCount(); });
419 MakeStat("TotalPrims", "objects", (s) => { s.Value = m_scene.SceneGraph.GetTotalObjectsCount(); });
420 MakeStat("ActivePrims", "objects", (s) => { s.Value = m_scene.SceneGraph.GetActiveObjectsCount(); });
421 MakeStat("ActiveScripts", "scripts", (s) => { s.Value = m_scene.SceneGraph.GetActiveScriptsCount(); });
422
423 MakeStat("TimeDilation", "sec/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[0]; });
424 MakeStat("SimFPS", "fps", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[1]; });
425 MakeStat("PhysicsFPS", "fps", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[2]; });
426 MakeStat("AgentUpdates", "updates/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[3]; });
427 MakeStat("FrameTime", "ms/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[8]; });
428 MakeStat("NetTime", "ms/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[9]; });
429 MakeStat("OtherTime", "ms/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[12]; });
430 MakeStat("PhysicsTime", "ms/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[10]; });
431 MakeStat("AgentTime", "ms/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[16]; });
432 MakeStat("ImageTime", "ms/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[11]; });
433 MakeStat("ScriptLines", "lines/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[20]; });
434 MakeStat("SimSpareMS", "ms/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[21]; });
435 }
436
437 private void UnRegisterStatsManagerRegionStatistics()
438 {
439 foreach (Stat stat in registeredStats)
440 {
441 StatsManager.DeregisterStat(stat);
442 stat.Dispose();
443 }
444 registeredStats.Clear();
445 }
402 446
403 } 447 }
404} 448} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/Framework/Search/BasicSearchModule.cs b/OpenSim/Region/CoreModules/Framework/Search/BasicSearchModule.cs
new file mode 100644
index 0000000..3849996
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Framework/Search/BasicSearchModule.cs
@@ -0,0 +1,199 @@
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 */
27using System;
28using System.Collections.Generic;
29using System.IO;
30using System.Reflection;
31using System.Threading;
32
33using OpenSim.Framework;
34using OpenSim.Framework.Console;
35using OpenSim.Framework.Monitoring;
36using OpenSim.Region.ClientStack.LindenUDP;
37using OpenSim.Region.Framework;
38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes;
40using OpenSim.Services.Interfaces;
41using OpenSim.Services.Connectors.Hypergrid;
42
43using OpenMetaverse;
44using OpenMetaverse.Packets;
45using log4net;
46using Nini.Config;
47using Mono.Addins;
48
49using DirFindFlags = OpenMetaverse.DirectoryManager.DirFindFlags;
50
51namespace OpenSim.Region.CoreModules.Framework.Search
52{
53 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "BasicSearchModule")]
54 public class BasicSearchModule : ISharedRegionModule
55 {
56 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
57
58 protected bool m_Enabled;
59 protected List<Scene> m_Scenes = new List<Scene>();
60
61 private IGroupsModule m_GroupsService = null;
62
63 #region ISharedRegionModule
64
65 public void Initialise(IConfigSource config)
66 {
67 string umanmod = config.Configs["Modules"].GetString("SearchModule", Name);
68 if (umanmod == Name)
69 {
70 m_Enabled = true;
71 m_log.DebugFormat("[BASIC SEARCH MODULE]: {0} is enabled", Name);
72 }
73 }
74
75 public bool IsSharedModule
76 {
77 get { return true; }
78 }
79
80 public virtual string Name
81 {
82 get { return "BasicSearchModule"; }
83 }
84
85 public Type ReplaceableInterface
86 {
87 get { return null; }
88 }
89
90 public void AddRegion(Scene scene)
91 {
92 if (m_Enabled)
93 {
94 m_Scenes.Add(scene);
95
96 scene.EventManager.OnMakeRootAgent += new Action<ScenePresence>(EventManager_OnMakeRootAgent);
97 scene.EventManager.OnMakeChildAgent += new EventManager.OnMakeChildAgentDelegate(EventManager_OnMakeChildAgent);
98 }
99 }
100
101 public void RemoveRegion(Scene scene)
102 {
103 if (m_Enabled)
104 {
105 m_Scenes.Remove(scene);
106
107 scene.EventManager.OnMakeRootAgent -= new Action<ScenePresence>(EventManager_OnMakeRootAgent);
108 scene.EventManager.OnMakeChildAgent -= new EventManager.OnMakeChildAgentDelegate(EventManager_OnMakeChildAgent);
109 }
110 }
111
112 public void RegionLoaded(Scene s)
113 {
114 if (!m_Enabled)
115 return;
116
117 if (m_GroupsService == null)
118 {
119 m_GroupsService = s.RequestModuleInterface<IGroupsModule>();
120
121 // No Groups Service Connector, then group search won't work...
122 if (m_GroupsService == null)
123 m_log.Warn("[BASIC SEARCH MODULE]: Could not get IGroupsModule");
124 }
125 }
126
127 public void PostInitialise()
128 {
129 }
130
131 public void Close()
132 {
133 m_Scenes.Clear();
134 }
135
136 #endregion ISharedRegionModule
137
138
139 #region Event Handlers
140
141 void EventManager_OnMakeRootAgent(ScenePresence sp)
142 {
143 sp.ControllingClient.OnDirFindQuery += OnDirFindQuery;
144 }
145
146 void EventManager_OnMakeChildAgent(ScenePresence sp)
147 {
148 sp.ControllingClient.OnDirFindQuery -= OnDirFindQuery;
149 }
150
151 void OnDirFindQuery(IClientAPI remoteClient, UUID queryID, string queryText, uint queryFlags, int queryStart)
152 {
153 queryText = queryText.Trim();
154
155 if (((DirFindFlags)queryFlags & DirFindFlags.People) == DirFindFlags.People)
156 {
157 if (string.IsNullOrEmpty(queryText))
158 remoteClient.SendDirPeopleReply(queryID, new DirPeopleReplyData[0]);
159
160 List<UserAccount> accounts = m_Scenes[0].UserAccountService.GetUserAccounts(m_Scenes[0].RegionInfo.ScopeID, queryText);
161 DirPeopleReplyData[] hits = new DirPeopleReplyData[accounts.Count];
162 int i = 0;
163 foreach (UserAccount acc in accounts)
164 {
165 DirPeopleReplyData d = new DirPeopleReplyData();
166 d.agentID = acc.PrincipalID;
167 d.firstName = acc.FirstName;
168 d.lastName = acc.LastName;
169 d.online = false;
170
171 hits[i++] = d;
172 }
173
174 // TODO: This currently ignores pretty much all the query flags including Mature and sort order
175 remoteClient.SendDirPeopleReply(queryID, hits);
176 }
177 else if (((DirFindFlags)queryFlags & DirFindFlags.Groups) == DirFindFlags.Groups)
178 {
179 if (m_GroupsService == null)
180 {
181 m_log.Warn("[BASIC SEARCH MODULE]: Groups service is not available. Unable to search groups.");
182 remoteClient.SendAlertMessage("Groups search is not enabled");
183 return;
184 }
185
186 if (string.IsNullOrEmpty(queryText))
187 remoteClient.SendDirGroupsReply(queryID, new DirGroupsReplyData[0]);
188
189 // TODO: This currently ignores pretty much all the query flags including Mature and sort order
190 remoteClient.SendDirGroupsReply(queryID, m_GroupsService.FindGroups(remoteClient, queryText).ToArray());
191 }
192
193 }
194
195 #endregion Event Handlers
196
197 }
198
199}
diff --git a/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs b/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs
new file mode 100644
index 0000000..3abacbd
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs
@@ -0,0 +1,256 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using System.Threading;
32using log4net;
33using Mono.Addins;
34using Nini.Config;
35using OpenMetaverse;
36using OpenSim.Framework;
37using OpenSim.Region.Framework.Interfaces;
38using OpenSim.Framework.Monitoring;
39using OpenSim.Region.Framework.Scenes;
40using GridRegion = OpenSim.Services.Interfaces.GridRegion;
41
42namespace OpenSim.Region.CoreModules.Framework
43{
44 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GridServiceThrottleModule")]
45 public class ServiceThrottleModule : ISharedRegionModule, IServiceThrottleModule
46 {
47 private static readonly ILog m_log = LogManager.GetLogger(
48 MethodBase.GetCurrentMethod().DeclaringType);
49
50 private readonly List<Scene> m_scenes = new List<Scene>();
51 private System.Timers.Timer m_timer = new System.Timers.Timer();
52
53 private Queue<Action> m_RequestQueue = new Queue<Action>();
54 private Dictionary<string, List<string>> m_Pending = new Dictionary<string, List<string>>();
55 private int m_Interval;
56
57 #region ISharedRegionModule
58
59 public void Initialise(IConfigSource config)
60 {
61 m_Interval = Util.GetConfigVarFromSections<int>(config, "Interval", new string[] { "ServiceThrottle" }, 5000);
62
63 m_timer = new System.Timers.Timer();
64 m_timer.AutoReset = false;
65 m_timer.Enabled = true;
66 m_timer.Interval = 15000; // 15 secs at first
67 m_timer.Elapsed += ProcessQueue;
68 m_timer.Start();
69
70 //WorkManager.StartThread(
71 // ProcessQueue,
72 // "GridServiceRequestThread",
73 // ThreadPriority.BelowNormal,
74 // true,
75 // false);
76 }
77
78 public void AddRegion(Scene scene)
79 {
80 lock (m_scenes)
81 {
82 m_scenes.Add(scene);
83 scene.RegisterModuleInterface<IServiceThrottleModule>(this);
84 scene.EventManager.OnNewClient += OnNewClient;
85 scene.EventManager.OnMakeRootAgent += OnMakeRootAgent;
86 }
87 }
88
89 public void RegionLoaded(Scene scene)
90 {
91 }
92
93 public void RemoveRegion(Scene scene)
94 {
95 lock (m_scenes)
96 {
97 m_scenes.Remove(scene);
98 scene.EventManager.OnNewClient -= OnNewClient;
99 }
100 }
101
102 public void PostInitialise()
103 {
104 }
105
106 public void Close()
107 {
108 }
109
110 public string Name
111 {
112 get { return "ServiceThrottleModule"; }
113 }
114
115 public Type ReplaceableInterface
116 {
117 get { return null; }
118 }
119
120 #endregion ISharedRegionMOdule
121
122 #region Events
123
124 void OnNewClient(IClientAPI client)
125 {
126 client.OnRegionHandleRequest += OnRegionHandleRequest;
127 }
128
129 void OnMakeRootAgent(ScenePresence obj)
130 {
131 lock (m_timer)
132 {
133 if (!m_timer.Enabled)
134 {
135 m_timer.Interval = m_Interval;
136 m_timer.Enabled = true;
137 m_timer.Start();
138 }
139 }
140 }
141
142 public void OnRegionHandleRequest(IClientAPI client, UUID regionID)
143 {
144 //m_log.DebugFormat("[SERVICE THROTTLE]: RegionHandleRequest {0}", regionID);
145 ulong handle = 0;
146 if (IsLocalRegionHandle(regionID, out handle))
147 {
148 client.SendRegionHandle(regionID, handle);
149 return;
150 }
151
152 Action action = delegate
153 {
154 GridRegion r = m_scenes[0].GridService.GetRegionByUUID(UUID.Zero, regionID);
155
156 if (r != null && r.RegionHandle != 0)
157 client.SendRegionHandle(regionID, r.RegionHandle);
158 };
159
160 Enqueue("region", regionID.ToString(), action);
161 }
162
163 #endregion Events
164
165 #region IServiceThrottleModule
166
167 public void Enqueue(string category, string itemid, Action continuation)
168 {
169 lock (m_RequestQueue)
170 {
171 if (m_Pending.ContainsKey(category))
172 {
173 if (m_Pending[category].Contains(itemid))
174 // Don't enqueue, it's already pending
175 return;
176 }
177 else
178 m_Pending.Add(category, new List<string>());
179
180 m_Pending[category].Add(itemid);
181
182 m_RequestQueue.Enqueue(delegate
183 {
184 lock (m_RequestQueue)
185 m_Pending[category].Remove(itemid);
186
187 continuation();
188 });
189 }
190 }
191
192 #endregion IServiceThrottleModule
193
194 #region Process Continuation Queue
195
196 private void ProcessQueue(object sender, System.Timers.ElapsedEventArgs e)
197 {
198 //m_log.DebugFormat("[YYY]: Process queue with {0} continuations", m_RequestQueue.Count);
199
200 while (m_RequestQueue.Count > 0)
201 {
202 Action continuation = null;
203 lock (m_RequestQueue)
204 continuation = m_RequestQueue.Dequeue();
205
206 if (continuation != null)
207 continuation();
208 }
209
210 if (AreThereRootAgents())
211 {
212 lock (m_timer)
213 {
214 m_timer.Interval = 1000; // 1 sec
215 m_timer.Enabled = true;
216 m_timer.Start();
217 }
218 }
219 else
220 lock (m_timer)
221 m_timer.Enabled = false;
222
223 }
224
225 #endregion Process Continuation Queue
226
227 #region Misc
228
229 private bool IsLocalRegionHandle(UUID regionID, out ulong regionHandle)
230 {
231 regionHandle = 0;
232 foreach (Scene s in m_scenes)
233 if (s.RegionInfo.RegionID == regionID)
234 {
235 regionHandle = s.RegionInfo.RegionHandle;
236 return true;
237 }
238 return false;
239 }
240
241 private bool AreThereRootAgents()
242 {
243 foreach (Scene s in m_scenes)
244 {
245 foreach (ScenePresence sp in s.GetScenePresences())
246 if (!sp.IsChildAgent)
247 return true;
248 }
249
250 return false;
251 }
252
253 #endregion Misc
254 }
255
256}
diff --git a/OpenSim/Region/CoreModules/Framework/Statistics/Logging/BinaryLoggingModule.cs b/OpenSim/Region/CoreModules/Framework/Statistics/Logging/BinaryLoggingModule.cs
index fb74cc6..f3436d1 100644
--- a/OpenSim/Region/CoreModules/Framework/Statistics/Logging/BinaryLoggingModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/Statistics/Logging/BinaryLoggingModule.cs
@@ -57,7 +57,7 @@ namespace OpenSim.Region.CoreModules.Framework.Statistics.Logging
57 try 57 try
58 { 58 {
59 IConfig statConfig = source.Configs["Statistics.Binary"]; 59 IConfig statConfig = source.Configs["Statistics.Binary"];
60 if (statConfig.Contains("enabled") && statConfig.GetBoolean("enabled")) 60 if (statConfig != null && statConfig.Contains("enabled") && statConfig.GetBoolean("enabled"))
61 { 61 {
62 if (statConfig.Contains("collect_region_stats")) 62 if (statConfig.Contains("collect_region_stats"))
63 { 63 {
diff --git a/OpenSim/Region/CoreModules/Framework/Statistics/Logging/LogWriter.cs b/OpenSim/Region/CoreModules/Framework/Statistics/Logging/LogWriter.cs
deleted file mode 100755
index fd8d5e3..0000000
--- a/OpenSim/Region/CoreModules/Framework/Statistics/Logging/LogWriter.cs
+++ /dev/null
@@ -1,170 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.IO;
30using System.Text;
31using log4net;
32
33namespace OpenSim.Region.CoreModules.Framework.Statistics.Logging
34{
35 /// <summary>
36 /// Class for writing a high performance, high volume log file.
37 /// Sometimes, to debug, one has a high volume logging to do and the regular
38 /// log file output is not appropriate.
39 /// Create a new instance with the parameters needed and
40 /// call Write() to output a line. Call Close() when finished.
41 /// If created with no parameters, it will not log anything.
42 /// </summary>
43 public class LogWriter : IDisposable
44 {
45 public bool Enabled { get; private set; }
46
47 private string m_logDirectory = ".";
48 private int m_logMaxFileTimeMin = 5; // 5 minutes
49 public String LogFileHeader { get; set; }
50
51 private StreamWriter m_logFile = null;
52 private TimeSpan m_logFileLife;
53 private DateTime m_logFileEndTime;
54 private Object m_logFileWriteLock = new Object();
55
56 // set externally when debugging. If let 'null', this does not write any error messages.
57 public ILog ErrorLogger = null;
58 private string LogHeader = "[LOG WRITER]";
59
60 /// <summary>
61 /// Create a log writer that will not write anything. Good for when not enabled
62 /// but the write statements are still in the code.
63 /// </summary>
64 public LogWriter()
65 {
66 Enabled = false;
67 m_logFile = null;
68 }
69
70 /// <summary>
71 /// Create a log writer instance.
72 /// </summary>
73 /// <param name="dir">The directory to create the log file in. May be 'null' for default.</param>
74 /// <param name="headr">The characters that begin the log file name. May be 'null' for default.</param>
75 /// <param name="maxFileTime">Maximum age of a log file in minutes. If zero, will set default.</param>
76 public LogWriter(string dir, string headr, int maxFileTime)
77 {
78 m_logDirectory = dir == null ? "." : dir;
79
80 LogFileHeader = headr == null ? "log-" : headr;
81
82 m_logMaxFileTimeMin = maxFileTime;
83 if (m_logMaxFileTimeMin < 1)
84 m_logMaxFileTimeMin = 5;
85
86 m_logFileLife = new TimeSpan(0, m_logMaxFileTimeMin, 0);
87 m_logFileEndTime = DateTime.Now + m_logFileLife;
88
89 Enabled = true;
90 }
91
92 public void Dispose()
93 {
94 this.Close();
95 }
96
97 public void Close()
98 {
99 Enabled = false;
100 if (m_logFile != null)
101 {
102 m_logFile.Close();
103 m_logFile.Dispose();
104 m_logFile = null;
105 }
106 }
107
108 public void Write(string line, params object[] args)
109 {
110 if (!Enabled) return;
111 Write(String.Format(line, args));
112 }
113
114 public void Flush()
115 {
116 if (!Enabled) return;
117 if (m_logFile != null)
118 {
119 m_logFile.Flush();
120 }
121 }
122
123 public void Write(string line)
124 {
125 if (!Enabled) return;
126 try
127 {
128 lock (m_logFileWriteLock)
129 {
130 DateTime now = DateTime.Now;
131 if (m_logFile == null || now > m_logFileEndTime)
132 {
133 if (m_logFile != null)
134 {
135 m_logFile.Close();
136 m_logFile.Dispose();
137 m_logFile = null;
138 }
139
140 // First log file or time has expired, start writing to a new log file
141 m_logFileEndTime = now + m_logFileLife;
142 string path = (m_logDirectory.Length > 0 ? m_logDirectory
143 + System.IO.Path.DirectorySeparatorChar.ToString() : "")
144 + String.Format("{0}{1}.log", LogFileHeader, now.ToString("yyyyMMddHHmmss"));
145 m_logFile = new StreamWriter(File.Open(path, FileMode.Append, FileAccess.Write));
146 }
147 if (m_logFile != null)
148 {
149 StringBuilder buff = new StringBuilder(line.Length + 25);
150 buff.Append(now.ToString("yyyyMMddHHmmssfff"));
151 // buff.Append(now.ToString("yyyyMMddHHmmss"));
152 buff.Append(",");
153 buff.Append(line);
154 buff.Append("\r\n");
155 m_logFile.Write(buff.ToString());
156 }
157 }
158 }
159 catch (Exception e)
160 {
161 if (ErrorLogger != null)
162 {
163 ErrorLogger.ErrorFormat("{0}: FAILURE WRITING TO LOGFILE: {1}", LogHeader, e);
164 }
165 Enabled = false;
166 }
167 return;
168 }
169 }
170}
diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs
index 4ef57fe..7b89c2c 100644
--- a/OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs
@@ -50,16 +50,15 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
50 { 50 {
51 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 51 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
52 52
53
54 #region ISharedRegionModule 53 #region ISharedRegionModule
55 54
56 public new void Initialise(IConfigSource config) 55 public new void Initialise(IConfigSource config)
57 { 56 {
58 string umanmod = config.Configs["Modules"].GetString("UserManagementModule", base.Name); 57 string umanmod = config.Configs["Modules"].GetString("UserManagementModule", null);
59 if (umanmod == Name) 58 if (umanmod == Name)
60 { 59 {
61 m_Enabled = true; 60 m_Enabled = true;
62 RegisterConsoleCmds(); 61 Init();
63 m_log.DebugFormat("[USER MANAGEMENT MODULE]: {0} is enabled", Name); 62 m_log.DebugFormat("[USER MANAGEMENT MODULE]: {0} is enabled", Name);
64 } 63 }
65 } 64 }
@@ -71,7 +70,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
71 70
72 #endregion ISharedRegionModule 71 #endregion ISharedRegionModule
73 72
74 protected override void AddAdditionalUsers(UUID avatarID, string query, List<UserData> users) 73 protected override void AddAdditionalUsers(string query, List<UserData> users)
75 { 74 {
76 if (query.Contains("@")) // First.Last@foo.com, maybe? 75 if (query.Contains("@")) // First.Last@foo.com, maybe?
77 { 76 {
@@ -131,7 +130,17 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
131 } 130 }
132 131
133 UserAgentServiceConnector uasConn = new UserAgentServiceConnector(uriStr); 132 UserAgentServiceConnector uasConn = new UserAgentServiceConnector(uriStr);
134 UUID userID = uasConn.GetUUID(names[0], names[1]); 133
134 UUID userID = UUID.Zero;
135 try
136 {
137 userID = uasConn.GetUUID(names[0], names[1]);
138 }
139 catch (Exception e)
140 {
141 m_log.Debug("[USER MANAGEMENT MODULE]: GetUUID call failed ", e);
142 }
143
135 if (!userID.Equals(UUID.Zero)) 144 if (!userID.Equals(UUID.Zero))
136 { 145 {
137 UserData ud = new UserData(); 146 UserData ud = new UserData();
diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/Tests/HGUserManagementModuleTests.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/Tests/HGUserManagementModuleTests.cs
new file mode 100644
index 0000000..4e3b7e5
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Framework/UserManagement/Tests/HGUserManagementModuleTests.cs
@@ -0,0 +1,75 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using Nini.Config;
30using NUnit.Framework;
31using OpenMetaverse;
32using OpenSim.Framework;
33using OpenSim.Region.CoreModules.Framework.UserManagement;
34using OpenSim.Tests.Common;
35
36namespace OpenSim.Region.CoreModules.Framework.UserManagement.Tests
37{
38 [TestFixture]
39 public class HGUserManagementModuleTests : OpenSimTestCase
40 {
41 /// <summary>
42 /// Test that a new HG agent (i.e. one without a user account) has their name cached in the UMM upon creation.
43 /// </summary>
44 [Test]
45 public void TestCachedUserNameForNewAgent()
46 {
47 TestHelpers.InMethod();
48// TestHelpers.EnableLogging();
49
50 HGUserManagementModule hgumm = new HGUserManagementModule();
51 UUID userId = TestHelpers.ParseStem("11");
52 string firstName = "Fred";
53 string lastName = "Astaire";
54 string homeUri = "example.com";
55
56 IConfigSource config = new IniConfigSource();
57 config.AddConfig("Modules");
58 config.Configs["Modules"].Set("UserManagementModule", hgumm.Name);
59
60 SceneHelpers sceneHelpers = new SceneHelpers();
61 TestScene scene = sceneHelpers.SetupScene();
62 SceneHelpers.SetupSceneModules(scene, config, hgumm);
63
64 AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId);
65 acd.firstname = firstName;
66 acd.lastname = lastName;
67 acd.ServiceURLs["HomeURI"] = "http://" + homeUri;
68
69 SceneHelpers.AddScenePresence(scene, acd);
70
71 string name = hgumm.GetUserName(userId);
72 Assert.That(name, Is.EqualTo(string.Format("{0}.{1} @{2}", firstName, lastName, homeUri)));
73 }
74 }
75} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs
index 77e8b00..7ecbd26 100644
--- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs
@@ -28,9 +28,11 @@ using System;
28using System.Collections.Generic; 28using System.Collections.Generic;
29using System.IO; 29using System.IO;
30using System.Reflection; 30using System.Reflection;
31using System.Threading;
31 32
32using OpenSim.Framework; 33using OpenSim.Framework;
33using OpenSim.Framework.Console; 34using OpenSim.Framework.Console;
35using OpenSim.Framework.Monitoring;
34using OpenSim.Region.ClientStack.LindenUDP; 36using OpenSim.Region.ClientStack.LindenUDP;
35using OpenSim.Region.Framework; 37using OpenSim.Region.Framework;
36using OpenSim.Region.Framework.Interfaces; 38using OpenSim.Region.Framework.Interfaces;
@@ -44,28 +46,24 @@ using log4net;
44using Nini.Config; 46using Nini.Config;
45using Mono.Addins; 47using Mono.Addins;
46 48
49using DirFindFlags = OpenMetaverse.DirectoryManager.DirFindFlags;
50
47namespace OpenSim.Region.CoreModules.Framework.UserManagement 51namespace OpenSim.Region.CoreModules.Framework.UserManagement
48{ 52{
49 public class UserData
50 {
51 public UUID Id { get; set; }
52 public string FirstName { get; set; }
53 public string LastName { get; set; }
54 public string HomeURL { get; set; }
55 public Dictionary<string, object> ServerURLs { get; set; }
56 }
57
58 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "UserManagementModule")] 53 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "UserManagementModule")]
59 public class UserManagementModule : ISharedRegionModule, IUserManagement 54 public class UserManagementModule : ISharedRegionModule, IUserManagement, IPeople
60 { 55 {
61 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 56 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
62 57
63 protected bool m_Enabled; 58 protected bool m_Enabled;
64 protected List<Scene> m_Scenes = new List<Scene>(); 59 protected List<Scene> m_Scenes = new List<Scene>();
65 60
61 protected IServiceThrottleModule m_ServiceThrottle;
66 // The cache 62 // The cache
67 protected Dictionary<UUID, UserData> m_UserCache = new Dictionary<UUID, UserData>(); 63 protected Dictionary<UUID, UserData> m_UserCache = new Dictionary<UUID, UserData>();
68 64
65 protected bool m_DisplayChangingHomeURI = false;
66
69 #region ISharedRegionModule 67 #region ISharedRegionModule
70 68
71 public void Initialise(IConfigSource config) 69 public void Initialise(IConfigSource config)
@@ -74,9 +72,20 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
74 if (umanmod == Name) 72 if (umanmod == Name)
75 { 73 {
76 m_Enabled = true; 74 m_Enabled = true;
77 RegisterConsoleCmds(); 75 Init();
78 m_log.DebugFormat("[USER MANAGEMENT MODULE]: {0} is enabled", Name); 76 m_log.DebugFormat("[USER MANAGEMENT MODULE]: {0} is enabled", Name);
79 } 77 }
78
79 if(!m_Enabled)
80 {
81 return;
82 }
83
84 IConfig userManagementConfig = config.Configs["UserManagement"];
85 if (userManagementConfig == null)
86 return;
87
88 m_DisplayChangingHomeURI = userManagementConfig.GetBoolean("DisplayChangingHomeURI", false);
80 } 89 }
81 90
82 public bool IsSharedModule 91 public bool IsSharedModule
@@ -98,9 +107,13 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
98 { 107 {
99 if (m_Enabled) 108 if (m_Enabled)
100 { 109 {
101 m_Scenes.Add(scene); 110 lock (m_Scenes)
111 {
112 m_Scenes.Add(scene);
113 }
102 114
103 scene.RegisterModuleInterface<IUserManagement>(this); 115 scene.RegisterModuleInterface<IUserManagement>(this);
116 scene.RegisterModuleInterface<IPeople>(this);
104 scene.EventManager.OnNewClient += new EventManager.OnNewClientDelegate(EventManager_OnNewClient); 117 scene.EventManager.OnNewClient += new EventManager.OnNewClientDelegate(EventManager_OnNewClient);
105 scene.EventManager.OnPrimsLoaded += new EventManager.PrimsLoaded(EventManager_OnPrimsLoaded); 118 scene.EventManager.OnPrimsLoaded += new EventManager.PrimsLoaded(EventManager_OnPrimsLoaded);
106 } 119 }
@@ -111,12 +124,17 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
111 if (m_Enabled) 124 if (m_Enabled)
112 { 125 {
113 scene.UnregisterModuleInterface<IUserManagement>(this); 126 scene.UnregisterModuleInterface<IUserManagement>(this);
114 m_Scenes.Remove(scene); 127 lock (m_Scenes)
128 {
129 m_Scenes.Remove(scene);
130 }
115 } 131 }
116 } 132 }
117 133
118 public void RegionLoaded(Scene s) 134 public void RegionLoaded(Scene s)
119 { 135 {
136 if (m_Enabled && m_ServiceThrottle == null)
137 m_ServiceThrottle = s.RequestModuleInterface<IServiceThrottleModule>();
120 } 138 }
121 139
122 public void PostInitialise() 140 public void PostInitialise()
@@ -125,7 +143,10 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
125 143
126 public void Close() 144 public void Close()
127 { 145 {
128 m_Scenes.Clear(); 146 lock (m_Scenes)
147 {
148 m_Scenes.Clear();
149 }
129 150
130 lock (m_UserCache) 151 lock (m_UserCache)
131 m_UserCache.Clear(); 152 m_UserCache.Clear();
@@ -133,7 +154,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
133 154
134 #endregion ISharedRegionModule 155 #endregion ISharedRegionModule
135 156
136 157
137 #region Event Handlers 158 #region Event Handlers
138 159
139 void EventManager_OnPrimsLoaded(Scene s) 160 void EventManager_OnPrimsLoaded(Scene s)
@@ -143,7 +164,6 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
143 s.ForEachSOG(delegate(SceneObjectGroup sog) { CacheCreators(sog); }); 164 s.ForEachSOG(delegate(SceneObjectGroup sog) { CacheCreators(sog); });
144 } 165 }
145 166
146
147 void EventManager_OnNewClient(IClientAPI client) 167 void EventManager_OnNewClient(IClientAPI client)
148 { 168 {
149 client.OnConnectionClosed += new Action<IClientAPI>(HandleConnectionClosed); 169 client.OnConnectionClosed += new Action<IClientAPI>(HandleConnectionClosed);
@@ -157,21 +177,52 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
157 client.OnAvatarPickerRequest -= new AvatarPickerRequest(HandleAvatarPickerRequest); 177 client.OnAvatarPickerRequest -= new AvatarPickerRequest(HandleAvatarPickerRequest);
158 } 178 }
159 179
160 void HandleUUIDNameRequest(UUID uuid, IClientAPI remote_client) 180 void HandleUUIDNameRequest(UUID uuid, IClientAPI client)
161 { 181 {
182// m_log.DebugFormat(
183// "[USER MANAGEMENT MODULE]: Handling request for name binding of UUID {0} from {1}",
184// uuid, remote_client.Name);
185
162 if (m_Scenes[0].LibraryService != null && (m_Scenes[0].LibraryService.LibraryRootFolder.Owner == uuid)) 186 if (m_Scenes[0].LibraryService != null && (m_Scenes[0].LibraryService.LibraryRootFolder.Owner == uuid))
163 { 187 {
164 remote_client.SendNameReply(uuid, "Mr", "OpenSim"); 188 client.SendNameReply(uuid, "Mr", "OpenSim");
165 } 189 }
166 else 190 else
167 { 191 {
168 string[] names = GetUserNames(uuid); 192 UserData user;
169 if (names.Length == 2) 193 /* bypass that continuation here when entry is already available */
194 lock (m_UserCache)
170 { 195 {
171 //m_log.DebugFormat("[XXX] HandleUUIDNameRequest {0} is {1} {2}", uuid, names[0], names[1]); 196 if (m_UserCache.TryGetValue(uuid, out user))
172 remote_client.SendNameReply(uuid, names[0], names[1]); 197 {
198 if (!user.IsUnknownUser && user.HasGridUserTried)
199 {
200 client.SendNameReply(uuid, user.FirstName, user.LastName);
201 return;
202 }
203 }
173 } 204 }
174 205
206 // Not found in cache, queue continuation
207 m_ServiceThrottle.Enqueue("name", uuid.ToString(), delegate
208 {
209 //m_log.DebugFormat("[YYY]: Name request {0}", uuid);
210
211 // As least upto September 2013, clients permanently cache UUID -> Name bindings. Some clients
212 // appear to clear this when the user asks it to clear the cache, but others may not.
213 //
214 // So to avoid clients
215 // (particularly Hypergrid clients) permanently binding "Unknown User" to a given UUID, we will
216 // instead drop the request entirely.
217 if (GetUser(uuid, out user))
218 {
219 client.SendNameReply(uuid, user.FirstName, user.LastName);
220 }
221// else
222// m_log.DebugFormat(
223// "[USER MANAGEMENT MODULE]: No bound name for {0} found, ignoring request from {1}",
224// uuid, client.Name);
225 });
175 } 226 }
176 } 227 }
177 228
@@ -181,29 +232,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
181 232
182 m_log.DebugFormat("[USER MANAGEMENT MODULE]: HandleAvatarPickerRequest for {0}", query); 233 m_log.DebugFormat("[USER MANAGEMENT MODULE]: HandleAvatarPickerRequest for {0}", query);
183 234
184 // searhc the user accounts service 235 List<UserData> users = GetUserData(query, 500, 1);
185 List<UserAccount> accs = m_Scenes[0].UserAccountService.GetUserAccounts(m_Scenes[0].RegionInfo.ScopeID, query);
186
187 List<UserData> users = new List<UserData>();
188 if (accs != null)
189 {
190 foreach (UserAccount acc in accs)
191 {
192 UserData ud = new UserData();
193 ud.FirstName = acc.FirstName;
194 ud.LastName = acc.LastName;
195 ud.Id = acc.PrincipalID;
196 users.Add(ud);
197 }
198 }
199
200 // search the local cache
201 foreach (UserData data in m_UserCache.Values)
202 if (users.Find(delegate(UserData d) { return d.Id == data.Id; }) == null &&
203 (data.FirstName.StartsWith(query) || data.LastName.StartsWith(query)))
204 users.Add(data);
205
206 AddAdditionalUsers(avatarID, query, users);
207 236
208 AvatarPickerReplyPacket replyPacket = (AvatarPickerReplyPacket)PacketPool.Instance.GetPacket(PacketType.AvatarPickerReply); 237 AvatarPickerReplyPacket replyPacket = (AvatarPickerReplyPacket)PacketPool.Instance.GetPacket(PacketType.AvatarPickerReply);
209 // TODO: don't create new blocks if recycling an old packet 238 // TODO: don't create new blocks if recycling an old packet
@@ -249,60 +278,62 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
249 client.SendAvatarPickerReply(agent_data, data_args); 278 client.SendAvatarPickerReply(agent_data, data_args);
250 } 279 }
251 280
252 protected virtual void AddAdditionalUsers(UUID avatarID, string query, List<UserData> users) 281 protected virtual void AddAdditionalUsers(string query, List<UserData> users)
253 { 282 {
254 } 283 }
255 284
256 #endregion Event Handlers 285 #endregion Event Handlers
257 286
258 private void CacheCreators(SceneObjectGroup sog) 287 #region IPeople
259 {
260 //m_log.DebugFormat("[USER MANAGEMENT MODULE]: processing {0} {1}; {2}", sog.RootPart.Name, sog.RootPart.CreatorData, sog.RootPart.CreatorIdentification);
261 AddUser(sog.RootPart.CreatorID, sog.RootPart.CreatorData);
262
263 foreach (SceneObjectPart sop in sog.Parts)
264 {
265 AddUser(sop.CreatorID, sop.CreatorData);
266 foreach (TaskInventoryItem item in sop.TaskInventory.Values)
267 AddUser(item.CreatorID, item.CreatorData);
268 }
269 }
270 288
271 private string[] GetUserNames(UUID uuid) 289 public List<UserData> GetUserData(string query, int page_size, int page_number)
272 { 290 {
273 string[] returnstring = new string[2]; 291 // search the user accounts service
292 List<UserAccount> accs = m_Scenes[0].UserAccountService.GetUserAccounts(m_Scenes[0].RegionInfo.ScopeID, query);
274 293
275 lock (m_UserCache) 294 List<UserData> users = new List<UserData>();
295 if (accs != null)
276 { 296 {
277 if (m_UserCache.ContainsKey(uuid)) 297 foreach (UserAccount acc in accs)
278 { 298 {
279 returnstring[0] = m_UserCache[uuid].FirstName; 299 UserData ud = new UserData();
280 returnstring[1] = m_UserCache[uuid].LastName; 300 ud.FirstName = acc.FirstName;
281 return returnstring; 301 ud.LastName = acc.LastName;
302 ud.Id = acc.PrincipalID;
303 ud.HasGridUserTried = true;
304 ud.IsUnknownUser = false;
305 users.Add(ud);
282 } 306 }
283 } 307 }
284 308
285 UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(UUID.Zero, uuid); 309 // search the local cache
286 310 foreach (UserData data in m_UserCache.Values)
287 if (account != null)
288 { 311 {
289 returnstring[0] = account.FirstName; 312 if (data.Id != UUID.Zero && !data.IsUnknownUser &&
290 returnstring[1] = account.LastName; 313 users.Find(delegate(UserData d) { return d.Id == data.Id; }) == null &&
314 (data.FirstName.ToLower().StartsWith(query.ToLower()) || data.LastName.ToLower().StartsWith(query.ToLower())))
315 users.Add(data);
316 }
291 317
292 UserData user = new UserData(); 318 AddAdditionalUsers(query, users);
293 user.FirstName = account.FirstName;
294 user.LastName = account.LastName;
295 319
296 lock (m_UserCache) 320 return users;
297 m_UserCache[uuid] = user; 321
298 } 322 }
299 else 323
324 #endregion IPeople
325
326 private void CacheCreators(SceneObjectGroup sog)
327 {
328 //m_log.DebugFormat("[USER MANAGEMENT MODULE]: processing {0} {1}; {2}", sog.RootPart.Name, sog.RootPart.CreatorData, sog.RootPart.CreatorIdentification);
329 AddUser(sog.RootPart.CreatorID, sog.RootPart.CreatorData);
330
331 foreach (SceneObjectPart sop in sog.Parts)
300 { 332 {
301 returnstring[0] = "Unknown"; 333 AddUser(sop.CreatorID, sop.CreatorData);
302 returnstring[1] = "User"; 334 foreach (TaskInventoryItem item in sop.TaskInventory.Values)
335 AddUser(item.CreatorID, item.CreatorData);
303 } 336 }
304
305 return returnstring;
306 } 337 }
307 338
308 #region IUserManagement 339 #region IUserManagement
@@ -338,55 +369,56 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
338 369
339 public string GetUserName(UUID uuid) 370 public string GetUserName(UUID uuid)
340 { 371 {
341 string[] names = GetUserNames(uuid); 372 UserData user;
342 if (names.Length == 2) 373 GetUser(uuid, out user);
343 { 374 return user.FirstName + " " + user.LastName;
344 string firstname = names[0];
345 string lastname = names[1];
346
347 return firstname + " " + lastname;
348
349 }
350 return "(hippos)";
351 } 375 }
352 376
353 public string GetUserHomeURL(UUID userID) 377 public string GetUserHomeURL(UUID userID)
354 { 378 {
355 lock (m_UserCache) 379 UserData user;
380 if(GetUser(userID, out user))
356 { 381 {
357 if (m_UserCache.ContainsKey(userID)) 382 return user.HomeURL;
358 return m_UserCache[userID].HomeURL;
359 } 383 }
360
361 return string.Empty; 384 return string.Empty;
362 } 385 }
363 386
364 public string GetUserServerURL(UUID userID, string serverType) 387 public string GetUserServerURL(UUID userID, string serverType)
365 { 388 {
366 UserData userdata; 389 UserData userdata;
367 lock (m_UserCache) 390 if(!GetUser(userID, out userdata))
368 m_UserCache.TryGetValue(userID, out userdata); 391 {
392 return string.Empty;
393 }
394
395 if (userdata.ServerURLs != null && userdata.ServerURLs.ContainsKey(serverType) && userdata.ServerURLs[serverType] != null)
396 {
397 return userdata.ServerURLs[serverType].ToString();
398 }
369 399
370 if (userdata != null) 400 if (!string.IsNullOrEmpty(userdata.HomeURL))
371 { 401 {
372// m_log.DebugFormat("[USER MANAGEMENT MODULE]: Requested url type {0} for {1}", serverType, userID); 402// m_log.DebugFormat("[USER MANAGEMENT MODULE]: Requested url type {0} for {1}", serverType, userID);
373 403
374 if (userdata.ServerURLs != null && userdata.ServerURLs.ContainsKey(serverType) && userdata.ServerURLs[serverType] != null) 404 UserAgentServiceConnector uConn = new UserAgentServiceConnector(userdata.HomeURL);
405 try
375 { 406 {
376 return userdata.ServerURLs[serverType].ToString(); 407 userdata.ServerURLs = uConn.GetServerURLs(userID);
377 } 408 }
378 409 catch(System.Net.WebException e)
379 if (userdata.HomeURL != null && userdata.HomeURL != string.Empty)
380 { 410 {
381 //m_log.DebugFormat( 411 m_log.DebugFormat("[USER MANAGEMENT MODULE]: GetServerURLs call failed {0}", e.Message);
382 // "[USER MANAGEMENT MODULE]: Did not find url type {0} so requesting urls from '{1}' for {2}", 412 userdata.ServerURLs = new Dictionary<string, object>();
383 // serverType, userdata.HomeURL, userID);
384
385 UserAgentServiceConnector uConn = new UserAgentServiceConnector(userdata.HomeURL);
386 userdata.ServerURLs = uConn.GetServerURLs(userID);
387 if (userdata.ServerURLs != null && userdata.ServerURLs.ContainsKey(serverType) && userdata.ServerURLs[serverType] != null)
388 return userdata.ServerURLs[serverType].ToString();
389 } 413 }
414 catch (Exception e)
415 {
416 m_log.Debug("[USER MANAGEMENT MODULE]: GetServerURLs call failed ", e);
417 userdata.ServerURLs = new Dictionary<string, object>();
418 }
419
420 if (userdata.ServerURLs != null && userdata.ServerURLs.ContainsKey(serverType) && userdata.ServerURLs[serverType] != null)
421 return userdata.ServerURLs[serverType].ToString();
390 } 422 }
391 423
392 return string.Empty; 424 return string.Empty;
@@ -394,13 +426,15 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
394 426
395 public string GetUserUUI(UUID userID) 427 public string GetUserUUI(UUID userID)
396 { 428 {
397 UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, userID); 429 string uui;
398 if (account != null) 430 GetUserUUI(userID, out uui);
399 return userID.ToString(); 431 return uui;
432 }
400 433
434 public bool GetUserUUI(UUID userID, out string uui)
435 {
401 UserData ud; 436 UserData ud;
402 lock (m_UserCache) 437 bool result = GetUser(userID, out ud);
403 m_UserCache.TryGetValue(userID, out ud);
404 438
405 if (ud != null) 439 if (ud != null)
406 { 440 {
@@ -414,121 +448,251 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
414 first = parts[0]; 448 first = parts[0];
415 last = parts[1]; 449 last = parts[1];
416 } 450 }
417 return userID + ";" + homeURL + ";" + first + " " + last; 451 uui = userID + ";" + homeURL + ";" + first + " " + last;
418 } 452 }
419 } 453 }
420 454
421 return userID.ToString(); 455 uui = userID.ToString();
456 return result;
422 } 457 }
423 458
424 public void AddUser(UUID uuid, string first, string last) 459 #region Cache Management
460 public bool GetUser(UUID uuid, out UserData userdata)
425 { 461 {
426 lock (m_UserCache) 462 lock (m_UserCache)
427 { 463 {
428 if (m_UserCache.ContainsKey(uuid)) 464 if (m_UserCache.TryGetValue(uuid, out userdata))
429 return; 465 {
466 if (userdata.HasGridUserTried)
467 {
468 return true;
469 }
470 }
471 else
472 {
473 userdata = new UserData();
474 userdata.HasGridUserTried = false;
475 userdata.Id = uuid;
476 userdata.FirstName = "Unknown";
477 userdata.LastName = "UserUMMAU42";
478 userdata.HomeURL = string.Empty;
479 userdata.IsUnknownUser = true;
480 userdata.HasGridUserTried = false;
481 }
482 }
483
484 /* BEGIN: do not wrap this code in any lock here
485 * There are HTTP calls in here.
486 */
487 if (!userdata.HasGridUserTried)
488 {
489 /* rewrite here */
490 UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, uuid);
491 if (account != null)
492 {
493 userdata.FirstName = account.FirstName;
494 userdata.LastName = account.LastName;
495 userdata.HomeURL = string.Empty;
496 userdata.IsUnknownUser = false;
497 userdata.HasGridUserTried = true;
498 }
430 } 499 }
431 500
432 UserData user = new UserData(); 501 if (!userdata.HasGridUserTried)
433 user.Id = uuid; 502 {
434 user.FirstName = first; 503 GridUserInfo uInfo = null;
435 user.LastName = last; 504 if (null != m_Scenes[0].GridUserService)
505 {
506 uInfo = m_Scenes[0].GridUserService.GetGridUserInfo(uuid.ToString());
507 }
508 if (uInfo != null)
509 {
510 string url, first, last, tmp;
511 UUID u;
512 if(uInfo.UserID.Length <= 36)
513 {
514 /* not a UUI */
515 }
516 else if (Util.ParseUniversalUserIdentifier(uInfo.UserID, out u, out url, out first, out last, out tmp))
517 {
518 if (url != string.Empty)
519 {
520 userdata.FirstName = first.Replace(" ", ".") + "." + last.Replace(" ", ".");
521 userdata.HomeURL = url;
522 try
523 {
524 userdata.LastName = "@" + new Uri(url).Authority;
525 userdata.IsUnknownUser = false;
526 }
527 catch
528 {
529 userdata.LastName = "@unknown";
530 }
531 userdata.HasGridUserTried = true;
532 }
533 }
534 else
535 m_log.DebugFormat("[USER MANAGEMENT MODULE]: Unable to parse UUI {0}", uInfo.UserID);
536 }
537 }
538 /* END: do not wrap this code in any lock here */
436 539
437 AddUserInternal(user); 540 lock (m_UserCache)
541 {
542 m_UserCache[uuid] = userdata;
543 }
544 return !userdata.IsUnknownUser;
438 } 545 }
439 546
440 public void AddUser(UUID uuid, string first, string last, string homeURL) 547 public void AddUser(UUID uuid, string first, string last)
441 { 548 {
442 //m_log.DebugFormat("[USER MANAGEMENT MODULE]: Adding user with id {0}, first {1}, last {2}, url {3}", uuid, first, last, homeURL); 549 lock(m_UserCache)
443 if (homeURL == string.Empty) 550 {
444 return; 551 if(!m_UserCache.ContainsKey(uuid))
445 552 {
446 AddUser(uuid, homeURL + ";" + first + " " + last); 553 UserData user = new UserData();
554 user.Id = uuid;
555 user.FirstName = first;
556 user.LastName = last;
557 user.IsUnknownUser = false;
558 user.HasGridUserTried = false;
559 m_UserCache.Add(uuid, user);
560 }
561 }
447 } 562 }
448 563
449 public void AddUser (UUID id, string creatorData) 564 public void AddUser(UUID uuid, string first, string last, string homeURL)
450 { 565 {
451 //m_log.DebugFormat("[USER MANAGEMENT MODULE]: Adding user with id {0}, creatorData {1}", id, creatorData); 566 //m_log.DebugFormat("[USER MANAGEMENT MODULE]: Adding user with id {0}, first {1}, last {2}, url {3}", uuid, first, last, homeURL);
452 567
453 UserData oldUser; 568 UserData oldUser;
454 //lock the whole block - prevent concurrent update
455 lock (m_UserCache) 569 lock (m_UserCache)
456 { 570 {
457 m_UserCache.TryGetValue (id, out oldUser); 571 if (m_UserCache.TryGetValue(uuid, out oldUser))
458 if (oldUser != null)
459 { 572 {
460 if (creatorData == null || creatorData == String.Empty) 573 if (!oldUser.IsUnknownUser)
461 { 574 {
462 //ignore updates without creator data 575 if (homeURL != oldUser.HomeURL && m_DisplayChangingHomeURI)
576 {
577 m_log.DebugFormat("[USER MANAGEMENT MODULE]: Different HomeURI for {0} {1} ({2}): {3} and {4}",
578 first, last, uuid.ToString(), homeURL, oldUser.HomeURL);
579 }
580 /* no update needed */
463 return; 581 return;
464 } 582 }
465 //try update unknown users 583 }
466 //and creator's home URL's 584 else if(!m_UserCache.ContainsKey(uuid))
467 if ((oldUser.FirstName == "Unknown" && !creatorData.Contains ("Unknown")) || (oldUser.HomeURL != null && !creatorData.StartsWith (oldUser.HomeURL))) 585 {
586 oldUser = new UserData();
587 oldUser.HasGridUserTried = false;
588 oldUser.IsUnknownUser = false;
589 if (homeURL != string.Empty)
468 { 590 {
469 m_UserCache.Remove (id); 591 oldUser.FirstName = first.Replace(" ", ".") + "." + last.Replace(" ", ".");
470// m_log.DebugFormat("[USER MANAGEMENT MODULE]: Re-adding user with id {0}, creatorData [{1}] and old HomeURL {2}", id, creatorData,oldUser.HomeURL); 592 try
593 {
594 oldUser.LastName = "@" + new Uri(homeURL).Authority;
595 oldUser.IsUnknownUser = false;
596 }
597 catch
598 {
599 oldUser.LastName = "@unknown";
600 }
471 } 601 }
472 else 602 else
473 { 603 {
474 //we have already a valid user within the cache 604 oldUser.FirstName = first;
475 return; 605 oldUser.LastName = last;
476 } 606 }
607 oldUser.HomeURL = homeURL;
608 oldUser.Id = uuid;
609 m_UserCache.Add(uuid, oldUser);
477 } 610 }
611 }
612 }
478 613
479 UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount (m_Scenes [0].RegionInfo.ScopeID, id); 614 public void AddUser(UUID id, string creatorData)
615 {
616 // m_log.InfoFormat("[USER MANAGEMENT MODULE]: Adding user with id {0}, creatorData {1}", id, creatorData);
480 617
481 if (account != null) 618 if(string.IsNullOrEmpty(creatorData))
619 {
620 AddUser(id, string.Empty, string.Empty, string.Empty);
621 }
622 else
623 {
624 string homeURL;
625 string firstname = string.Empty;
626 string lastname = string.Empty;
627
628 //creatorData = <endpoint>;<name>
629
630 string[] parts = creatorData.Split(';');
631 if(parts.Length > 1)
482 { 632 {
483 AddUser (id, account.FirstName, account.LastName); 633 string[] nameparts = parts[1].Split(' ');
634 firstname = nameparts[0];
635 for(int xi = 1; xi < nameparts.Length; ++xi)
636 {
637 if(xi != 1)
638 {
639 lastname += " ";
640 }
641 lastname += nameparts[xi];
642 }
484 } 643 }
485 else 644 else
486 { 645 {
487 UserData user = new UserData (); 646 firstname = "Unknown";
488 user.Id = id; 647 lastname = "UserUMMAU5";
489 648 }
490 if (creatorData != null && creatorData != string.Empty) 649 if (parts.Length >= 1)
650 {
651 homeURL = parts[0];
652 if(Uri.IsWellFormedUriString(homeURL, UriKind.Absolute))
653 {
654 AddUser(id, firstname, lastname, homeURL);
655 }
656 else
491 { 657 {
492 //creatorData = <endpoint>;<name> 658 m_log.DebugFormat("[SCENE]: Unable to parse Uri {0} for CreatorID {1}", parts[0], creatorData);
493 659
494 string[] parts = creatorData.Split (';'); 660 lock (m_UserCache)
495 if (parts.Length >= 1)
496 { 661 {
497 user.HomeURL = parts [0]; 662 if(!m_UserCache.ContainsKey(id))
498 try
499 {
500 Uri uri = new Uri (parts [0]);
501 user.LastName = "@" + uri.Authority;
502 }
503 catch (UriFormatException)
504 { 663 {
505 m_log.DebugFormat ("[SCENE]: Unable to parse Uri {0}", parts [0]); 664 UserData newUser = new UserData();
506 user.LastName = "@unknown"; 665 newUser.Id = id;
666 newUser.FirstName = firstname + "." + lastname.Replace(' ', '.');
667 newUser.LastName = "@unknown";
668 newUser.HomeURL = string.Empty;
669 newUser.HasGridUserTried = false;
670 newUser.IsUnknownUser = true; /* we mark those users as Unknown user so a re-retrieve may be activated */
671 m_UserCache.Add(id, newUser);
507 } 672 }
508 } 673 }
509 if (parts.Length >= 2)
510 user.FirstName = parts [1].Replace (' ', '.');
511 } 674 }
512 else 675 }
676 else
677 {
678 lock(m_UserCache)
513 { 679 {
514 user.FirstName = "Unknown"; 680 if(!m_UserCache.ContainsKey(id))
515 user.LastName = "User"; 681 {
682 UserData newUser = new UserData();
683 newUser.Id = id;
684 newUser.FirstName = "Unknown";
685 newUser.LastName = "UserUMMAU4";
686 newUser.HomeURL = string.Empty;
687 newUser.IsUnknownUser = true;
688 newUser.HasGridUserTried = false;
689 m_UserCache.Add(id, newUser);
690 }
516 } 691 }
517
518 AddUserInternal (user);
519 } 692 }
520 } 693 }
521 } 694 }
522 695 #endregion
523 void AddUserInternal(UserData user)
524 {
525 lock (m_UserCache)
526 m_UserCache[user.Id] = user;
527
528 //m_log.DebugFormat(
529 // "[USER MANAGEMENT MODULE]: Added user {0} {1} {2} {3}",
530 // user.Id, user.FirstName, user.LastName, user.HomeURL);
531 }
532 696
533 public bool IsLocalGridUser(UUID uuid) 697 public bool IsLocalGridUser(UUID uuid)
534 { 698 {
@@ -541,36 +705,95 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
541 705
542 #endregion IUserManagement 706 #endregion IUserManagement
543 707
708 protected void Init()
709 {
710 AddUser(UUID.Zero, "Unknown", "User");
711 RegisterConsoleCmds();
712 }
713
544 protected void RegisterConsoleCmds() 714 protected void RegisterConsoleCmds()
545 { 715 {
546 MainConsole.Instance.Commands.AddCommand("Users", true, 716 MainConsole.Instance.Commands.AddCommand("Users", true,
717 "show name",
718 "show name <uuid>",
719 "Show the bindings between a single user UUID and a user name",
720 String.Empty,
721 HandleShowUser);
722
723 MainConsole.Instance.Commands.AddCommand("Users", true,
547 "show names", 724 "show names",
548 "show names", 725 "show names",
549 "Show the bindings between user UUIDs and user names", 726 "Show the bindings between user UUIDs and user names",
550 String.Empty, 727 String.Empty,
551 HandleShowUsers); 728 HandleShowUsers);
729
730 MainConsole.Instance.Commands.AddCommand("Users", true,
731 "reset user cache",
732 "reset user cache",
733 "reset user cache to allow changed settings to be applied",
734 String.Empty,
735 HandleResetUserCache);
552 } 736 }
553 737
554 private void HandleShowUsers(string module, string[] cmd) 738 private void HandleResetUserCache(string module, string[] cmd)
555 { 739 {
556 lock (m_UserCache) 740 lock(m_UserCache)
557 { 741 {
558 if (m_UserCache.Count == 0) 742 m_UserCache.Clear();
559 { 743 }
560 MainConsole.Instance.Output("No users found"); 744 }
561 return; 745
562 } 746 private void HandleShowUser(string module, string[] cmd)
563 747 {
564 MainConsole.Instance.Output("UUID User Name"); 748 if (cmd.Length < 3)
565 MainConsole.Instance.Output("-----------------------------------------------------------------------------"); 749 {
566 foreach (KeyValuePair<UUID, UserData> kvp in m_UserCache) 750 MainConsole.Instance.OutputFormat("Usage: show name <uuid>");
567 {
568 MainConsole.Instance.Output(String.Format("{0} {1} {2} ({3})",
569 kvp.Key, kvp.Value.FirstName, kvp.Value.LastName, kvp.Value.HomeURL));
570 }
571
572 return; 751 return;
573 } 752 }
753
754 UUID userId;
755 if (!ConsoleUtil.TryParseConsoleUuid(MainConsole.Instance, cmd[2], out userId))
756 return;
757
758 UserData ud;
759
760 if(!GetUser(userId, out ud))
761 {
762 MainConsole.Instance.OutputFormat("No name known for user with id {0}", userId);
763 return;
764 }
765
766 ConsoleDisplayTable cdt = new ConsoleDisplayTable();
767 cdt.AddColumn("UUID", 36);
768 cdt.AddColumn("Name", 30);
769 cdt.AddColumn("HomeURL", 40);
770 cdt.AddRow(userId, string.Format("{0} {1}", ud.FirstName, ud.LastName), ud.HomeURL);
771
772 MainConsole.Instance.Output(cdt.ToString());
574 } 773 }
774
775 private void HandleShowUsers(string module, string[] cmd)
776 {
777 ConsoleDisplayTable cdt = new ConsoleDisplayTable();
778 cdt.AddColumn("UUID", 36);
779 cdt.AddColumn("Name", 30);
780 cdt.AddColumn("HomeURL", 40);
781 cdt.AddColumn("Checked", 10);
782
783 Dictionary<UUID, UserData> copyDict;
784 lock(m_UserCache)
785 {
786 copyDict = new Dictionary<UUID, UserData>(m_UserCache);
787 }
788
789 foreach(KeyValuePair<UUID, UserData> kvp in copyDict)
790 {
791 cdt.AddRow(kvp.Key, string.Format("{0} {1}", kvp.Value.FirstName, kvp.Value.LastName), kvp.Value.HomeURL, kvp.Value.HasGridUserTried ? "yes" : "no");
792 }
793
794 MainConsole.Instance.Output(cdt.ToString());
795 }
796
575 } 797 }
576} \ No newline at end of file 798
799}