diff options
Diffstat (limited to 'OpenSim/Region/CoreModules/Framework')
14 files changed, 1702 insertions, 383 deletions
diff --git a/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs b/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs index fff86d5..de8925d 100644 --- a/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs +++ b/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs | |||
@@ -28,6 +28,7 @@ | |||
28 | using System; | 28 | using System; |
29 | using System.Collections; | 29 | using System.Collections; |
30 | using System.Collections.Generic; | 30 | using System.Collections.Generic; |
31 | using System.Linq; | ||
31 | using System.Reflection; | 32 | using System.Reflection; |
32 | using System.Text; | 33 | using System.Text; |
33 | using log4net; | 34 | using log4net; |
@@ -37,6 +38,7 @@ using OpenMetaverse; | |||
37 | using OpenSim.Framework; | 38 | using OpenSim.Framework; |
38 | using OpenSim.Framework.Console; | 39 | using OpenSim.Framework.Console; |
39 | using OpenSim.Framework.Servers; | 40 | using OpenSim.Framework.Servers; |
41 | using OpenSim.Framework.Servers.HttpServer; | ||
40 | using OpenSim.Region.Framework.Interfaces; | 42 | using OpenSim.Region.Framework.Interfaces; |
41 | using OpenSim.Region.Framework.Scenes; | 43 | using OpenSim.Region.Framework.Scenes; |
42 | using Caps=OpenSim.Framework.Capabilities.Caps; | 44 | using Caps=OpenSim.Framework.Capabilities.Caps; |
@@ -57,8 +59,9 @@ namespace OpenSim.Region.CoreModules.Framework | |||
57 | /// </summary> | 59 | /// </summary> |
58 | protected Dictionary<uint, Caps> m_capsObjects = new Dictionary<uint, Caps>(); | 60 | protected Dictionary<uint, Caps> m_capsObjects = new Dictionary<uint, 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) |
@@ -106,35 +124,38 @@ namespace OpenSim.Region.CoreModules.Framework | |||
106 | if (m_scene.RegionInfo.EstateSettings.IsBanned(agentId, flags)) | 124 | if (m_scene.RegionInfo.EstateSettings.IsBanned(agentId, flags)) |
107 | return; | 125 | return; |
108 | 126 | ||
127 | Caps caps; | ||
109 | String capsObjectPath = GetCapsPath(agentId); | 128 | String capsObjectPath = GetCapsPath(agentId); |
110 | 129 | ||
111 | if (m_capsObjects.ContainsKey(circuitCode)) | 130 | lock (m_capsObjects) |
112 | { | 131 | { |
113 | Caps oldCaps = m_capsObjects[circuitCode]; | 132 | if (m_capsObjects.ContainsKey(circuitCode)) |
114 | 133 | { | |
115 | m_log.DebugFormat( | 134 | Caps oldCaps = m_capsObjects[circuitCode]; |
116 | "[CAPS]: Recreating caps for agent {0}. Old caps path {1}, new caps path {2}. ", | 135 | |
117 | agentId, oldCaps.CapsObjectPath, capsObjectPath); | 136 | //m_log.WarnFormat( |
118 | // This should not happen. The caller code is confused. We need to fix that. | 137 | // "[CAPS]: Recreating caps for agent {0} in region {1}. Old caps path {2}, new caps path {3}. ", |
119 | // CAPs can never be reregistered, or the client will be confused. | 138 | // agentId, m_scene.RegionInfo.RegionName, oldCaps.CapsObjectPath, capsObjectPath); |
120 | // Hence this return here. | 139 | } |
121 | //return; | ||
122 | } | ||
123 | |||
124 | Caps caps = new Caps(MainServer.Instance, m_scene.RegionInfo.ExternalHostName, | ||
125 | (MainServer.Instance == null) ? 0: MainServer.Instance.Port, | ||
126 | capsObjectPath, agentId, m_scene.RegionInfo.RegionName); | ||
127 | 140 | ||
128 | m_capsObjects[circuitCode] = caps; | 141 | caps = new Caps(MainServer.Instance, m_scene.RegionInfo.ExternalHostName, |
142 | (MainServer.Instance == null) ? 0: MainServer.Instance.Port, | ||
143 | capsObjectPath, agentId, m_scene.RegionInfo.RegionName); | ||
129 | 144 | ||
145 | m_capsObjects[circuitCode] = caps; | ||
146 | } | ||
130 | m_scene.EventManager.TriggerOnRegisterCaps(agentId, caps); | 147 | m_scene.EventManager.TriggerOnRegisterCaps(agentId, caps); |
131 | } | 148 | } |
132 | 149 | ||
133 | public void RemoveCaps(UUID agentId, uint circuitCode) | 150 | public void RemoveCaps(UUID agentId, uint circuitCode) |
134 | { | 151 | { |
135 | if (childrenSeeds.ContainsKey(agentId)) | 152 | m_log.DebugFormat("[CAPS]: Remove caps for agent {0} in region {1}", agentId, m_scene.RegionInfo.RegionName); |
153 | lock (m_childrenSeeds) | ||
136 | { | 154 | { |
137 | childrenSeeds.Remove(agentId); | 155 | if (m_childrenSeeds.ContainsKey(agentId)) |
156 | { | ||
157 | m_childrenSeeds.Remove(agentId); | ||
158 | } | ||
138 | } | 159 | } |
139 | 160 | ||
140 | lock (m_capsObjects) | 161 | lock (m_capsObjects) |
@@ -180,16 +201,22 @@ namespace OpenSim.Region.CoreModules.Framework | |||
180 | 201 | ||
181 | public void SetAgentCapsSeeds(AgentCircuitData agent) | 202 | public void SetAgentCapsSeeds(AgentCircuitData agent) |
182 | { | 203 | { |
183 | capsPaths[agent.AgentID] = agent.CapsPath; | 204 | lock (m_capsPaths) |
184 | childrenSeeds[agent.AgentID] | 205 | m_capsPaths[agent.AgentID] = agent.CapsPath; |
185 | = ((agent.ChildrenCapSeeds == null) ? new Dictionary<ulong, string>() : agent.ChildrenCapSeeds); | 206 | |
207 | lock (m_childrenSeeds) | ||
208 | m_childrenSeeds[agent.AgentID] | ||
209 | = ((agent.ChildrenCapSeeds == null) ? new Dictionary<ulong, string>() : agent.ChildrenCapSeeds); | ||
186 | } | 210 | } |
187 | 211 | ||
188 | public string GetCapsPath(UUID agentId) | 212 | public string GetCapsPath(UUID agentId) |
189 | { | 213 | { |
190 | if (capsPaths.ContainsKey(agentId)) | 214 | lock (m_capsPaths) |
191 | { | 215 | { |
192 | return capsPaths[agentId]; | 216 | if (m_capsPaths.ContainsKey(agentId)) |
217 | { | ||
218 | return m_capsPaths[agentId]; | ||
219 | } | ||
193 | } | 220 | } |
194 | 221 | ||
195 | return null; | 222 | return null; |
@@ -198,17 +225,24 @@ namespace OpenSim.Region.CoreModules.Framework | |||
198 | public Dictionary<ulong, string> GetChildrenSeeds(UUID agentID) | 225 | public Dictionary<ulong, string> GetChildrenSeeds(UUID agentID) |
199 | { | 226 | { |
200 | Dictionary<ulong, string> seeds = null; | 227 | Dictionary<ulong, string> seeds = null; |
201 | if (childrenSeeds.TryGetValue(agentID, out seeds)) | 228 | |
202 | return seeds; | 229 | lock (m_childrenSeeds) |
230 | if (m_childrenSeeds.TryGetValue(agentID, out seeds)) | ||
231 | return seeds; | ||
232 | |||
203 | return new Dictionary<ulong, string>(); | 233 | return new Dictionary<ulong, string>(); |
204 | } | 234 | } |
205 | 235 | ||
206 | public void DropChildSeed(UUID agentID, ulong handle) | 236 | public void DropChildSeed(UUID agentID, ulong handle) |
207 | { | 237 | { |
208 | Dictionary<ulong, string> seeds; | 238 | Dictionary<ulong, string> seeds; |
209 | if (childrenSeeds.TryGetValue(agentID, out seeds)) | 239 | |
240 | lock (m_childrenSeeds) | ||
210 | { | 241 | { |
211 | seeds.Remove(handle); | 242 | if (m_childrenSeeds.TryGetValue(agentID, out seeds)) |
243 | { | ||
244 | seeds.Remove(handle); | ||
245 | } | ||
212 | } | 246 | } |
213 | } | 247 | } |
214 | 248 | ||
@@ -216,53 +250,339 @@ namespace OpenSim.Region.CoreModules.Framework | |||
216 | { | 250 | { |
217 | Dictionary<ulong, string> seeds; | 251 | Dictionary<ulong, string> seeds; |
218 | string returnval; | 252 | string returnval; |
219 | if (childrenSeeds.TryGetValue(agentID, out seeds)) | 253 | |
254 | lock (m_childrenSeeds) | ||
220 | { | 255 | { |
221 | if (seeds.TryGetValue(handle, out returnval)) | 256 | if (m_childrenSeeds.TryGetValue(agentID, out seeds)) |
222 | return returnval; | 257 | { |
258 | if (seeds.TryGetValue(handle, out returnval)) | ||
259 | return returnval; | ||
260 | } | ||
223 | } | 261 | } |
262 | |||
224 | return null; | 263 | return null; |
225 | } | 264 | } |
226 | 265 | ||
227 | public void SetChildrenSeed(UUID agentID, Dictionary<ulong, string> seeds) | 266 | public void SetChildrenSeed(UUID agentID, Dictionary<ulong, string> seeds) |
228 | { | 267 | { |
229 | //m_log.DebugFormat(" !!! Setting child seeds in {0} to {1}", m_scene.RegionInfo.RegionName, seeds.Count); | 268 | //m_log.DebugFormat(" !!! Setting child seeds in {0} to {1}", m_scene.RegionInfo.RegionName, seeds.Count); |
230 | childrenSeeds[agentID] = seeds; | 269 | |
270 | lock (m_childrenSeeds) | ||
271 | m_childrenSeeds[agentID] = seeds; | ||
231 | } | 272 | } |
232 | 273 | ||
233 | public void DumpChildrenSeeds(UUID agentID) | 274 | public void DumpChildrenSeeds(UUID agentID) |
234 | { | 275 | { |
235 | m_log.Info("================ ChildrenSeed "+m_scene.RegionInfo.RegionName+" ================"); | 276 | m_log.Info("================ ChildrenSeed "+m_scene.RegionInfo.RegionName+" ================"); |
236 | foreach (KeyValuePair<ulong, string> kvp in childrenSeeds[agentID]) | 277 | |
278 | lock (m_childrenSeeds) | ||
279 | { | ||
280 | foreach (KeyValuePair<ulong, string> kvp in m_childrenSeeds[agentID]) | ||
281 | { | ||
282 | uint x, y; | ||
283 | Utils.LongToUInts(kvp.Key, out x, out y); | ||
284 | x = x / Constants.RegionSize; | ||
285 | y = y / Constants.RegionSize; | ||
286 | m_log.Info(" >> "+x+", "+y+": "+kvp.Value); | ||
287 | } | ||
288 | } | ||
289 | } | ||
290 | |||
291 | private void HandleShowCapsListCommand(string module, string[] cmdParams) | ||
292 | { | ||
293 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) | ||
294 | return; | ||
295 | |||
296 | StringBuilder capsReport = new StringBuilder(); | ||
297 | capsReport.AppendFormat("Region {0}:\n", m_scene.RegionInfo.RegionName); | ||
298 | |||
299 | lock (m_capsObjects) | ||
237 | { | 300 | { |
238 | uint x, y; | 301 | foreach (KeyValuePair<uint, Caps> kvp in m_capsObjects) |
239 | Utils.LongToUInts(kvp.Key, out x, out y); | 302 | { |
240 | x = x / Constants.RegionSize; | 303 | capsReport.AppendFormat("** Circuit {0}:\n", kvp.Key); |
241 | y = y / Constants.RegionSize; | 304 | Caps caps = kvp.Value; |
242 | m_log.Info(" >> "+x+", "+y+": "+kvp.Value); | 305 | |
306 | for (IDictionaryEnumerator kvp2 = caps.CapsHandlers.GetCapsDetails(false, null).GetEnumerator(); kvp2.MoveNext(); ) | ||
307 | { | ||
308 | Uri uri = new Uri(kvp2.Value.ToString()); | ||
309 | capsReport.AppendFormat(m_showCapsCommandFormat, kvp2.Key, uri.PathAndQuery); | ||
310 | } | ||
311 | |||
312 | foreach (KeyValuePair<string, PollServiceEventArgs> kvp2 in caps.GetPollHandlers()) | ||
313 | capsReport.AppendFormat(m_showCapsCommandFormat, kvp2.Key, kvp2.Value.Url); | ||
314 | |||
315 | foreach (KeyValuePair<string, string> kvp3 in caps.ExternalCapsHandlers) | ||
316 | capsReport.AppendFormat(m_showCapsCommandFormat, kvp3.Key, kvp3.Value); | ||
317 | } | ||
243 | } | 318 | } |
319 | |||
320 | MainConsole.Instance.Output(capsReport.ToString()); | ||
244 | } | 321 | } |
245 | 322 | ||
246 | private void HandleShowCapsCommand(string module, string[] cmdparams) | 323 | private void HandleShowCapsStatsByCapCommand(string module, string[] cmdParams) |
247 | { | 324 | { |
248 | StringBuilder caps = new StringBuilder(); | 325 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) |
249 | caps.AppendFormat("Region {0}:\n", m_scene.RegionInfo.RegionName); | 326 | return; |
327 | |||
328 | if (cmdParams.Length != 5 && cmdParams.Length != 6) | ||
329 | { | ||
330 | MainConsole.Instance.Output("Usage: show caps stats by cap [<cap-name>]"); | ||
331 | return; | ||
332 | } | ||
333 | |||
334 | StringBuilder sb = new StringBuilder(); | ||
335 | sb.AppendFormat("Region {0}:\n", m_scene.Name); | ||
336 | |||
337 | if (cmdParams.Length == 5) | ||
338 | { | ||
339 | BuildSummaryStatsByCapReport(sb); | ||
340 | } | ||
341 | else if (cmdParams.Length == 6) | ||
342 | { | ||
343 | BuildDetailedStatsByCapReport(sb, cmdParams[5]); | ||
344 | } | ||
345 | |||
346 | MainConsole.Instance.Output(sb.ToString()); | ||
347 | } | ||
348 | |||
349 | private void BuildDetailedStatsByCapReport(StringBuilder sb, string capName) | ||
350 | { | ||
351 | /* | ||
352 | sb.AppendFormat("Capability name {0}\n", capName); | ||
353 | |||
354 | ConsoleDisplayTable cdt = new ConsoleDisplayTable(); | ||
355 | cdt.AddColumn("User Name", 34); | ||
356 | cdt.AddColumn("Req Received", 12); | ||
357 | cdt.AddColumn("Req Handled", 12); | ||
358 | cdt.Indent = 2; | ||
359 | |||
360 | Dictionary<string, int> receivedStats = new Dictionary<string, int>(); | ||
361 | Dictionary<string, int> handledStats = new Dictionary<string, int>(); | ||
362 | |||
363 | m_scene.ForEachScenePresence( | ||
364 | sp => | ||
365 | { | ||
366 | Caps caps = m_scene.CapsModule.GetCapsForUser(sp.UUID); | ||
250 | 367 | ||
251 | foreach (KeyValuePair<uint, Caps> kvp in m_capsObjects) | 368 | if (caps == null) |
369 | return; | ||
370 | |||
371 | Dictionary<string, IRequestHandler> capsHandlers = caps.CapsHandlers.GetCapsHandlers(); | ||
372 | |||
373 | IRequestHandler reqHandler; | ||
374 | if (capsHandlers.TryGetValue(capName, out reqHandler)) | ||
375 | { | ||
376 | receivedStats[sp.Name] = reqHandler.RequestsReceived; | ||
377 | handledStats[sp.Name] = reqHandler.RequestsHandled; | ||
378 | } | ||
379 | else | ||
380 | { | ||
381 | PollServiceEventArgs pollHandler = null; | ||
382 | if (caps.TryGetPollHandler(capName, out pollHandler)) | ||
383 | { | ||
384 | receivedStats[sp.Name] = pollHandler.RequestsReceived; | ||
385 | handledStats[sp.Name] = pollHandler.RequestsHandled; | ||
386 | } | ||
387 | } | ||
388 | } | ||
389 | ); | ||
390 | |||
391 | foreach (KeyValuePair<string, int> kvp in receivedStats.OrderByDescending(kp => kp.Value)) | ||
252 | { | 392 | { |
253 | caps.AppendFormat("** Circuit {0}:\n", kvp.Key); | 393 | cdt.AddRow(kvp.Key, kvp.Value, handledStats[kvp.Key]); |
394 | } | ||
395 | |||
396 | sb.Append(cdt.ToString()); | ||
397 | */ | ||
398 | } | ||
399 | |||
400 | private void BuildSummaryStatsByCapReport(StringBuilder sb) | ||
401 | { | ||
402 | /* | ||
403 | ConsoleDisplayTable cdt = new ConsoleDisplayTable(); | ||
404 | cdt.AddColumn("Name", 34); | ||
405 | cdt.AddColumn("Req Received", 12); | ||
406 | cdt.AddColumn("Req Handled", 12); | ||
407 | cdt.Indent = 2; | ||
408 | |||
409 | Dictionary<string, int> receivedStats = new Dictionary<string, int>(); | ||
410 | Dictionary<string, int> handledStats = new Dictionary<string, int>(); | ||
254 | 411 | ||
255 | for (IDictionaryEnumerator kvp2 = kvp.Value.CapsHandlers.GetCapsDetails(false, null).GetEnumerator(); kvp2.MoveNext(); ) | 412 | m_scene.ForEachScenePresence( |
413 | sp => | ||
256 | { | 414 | { |
257 | Uri uri = new Uri(kvp2.Value.ToString()); | 415 | Caps caps = m_scene.CapsModule.GetCapsForUser(sp.UUID); |
258 | caps.AppendFormat(m_showCapsCommandFormat, kvp2.Key, uri.PathAndQuery); | 416 | |
417 | if (caps == null) | ||
418 | return; | ||
419 | |||
420 | foreach (IRequestHandler reqHandler in caps.CapsHandlers.GetCapsHandlers().Values) | ||
421 | { | ||
422 | string reqName = reqHandler.Name ?? ""; | ||
423 | |||
424 | if (!receivedStats.ContainsKey(reqName)) | ||
425 | { | ||
426 | receivedStats[reqName] = reqHandler.RequestsReceived; | ||
427 | handledStats[reqName] = reqHandler.RequestsHandled; | ||
428 | } | ||
429 | else | ||
430 | { | ||
431 | receivedStats[reqName] += reqHandler.RequestsReceived; | ||
432 | handledStats[reqName] += reqHandler.RequestsHandled; | ||
433 | } | ||
434 | } | ||
435 | |||
436 | foreach (KeyValuePair<string, PollServiceEventArgs> kvp in caps.GetPollHandlers()) | ||
437 | { | ||
438 | string name = kvp.Key; | ||
439 | PollServiceEventArgs pollHandler = kvp.Value; | ||
440 | |||
441 | if (!receivedStats.ContainsKey(name)) | ||
442 | { | ||
443 | receivedStats[name] = pollHandler.RequestsReceived; | ||
444 | handledStats[name] = pollHandler.RequestsHandled; | ||
445 | } | ||
446 | else | ||
447 | { | ||
448 | receivedStats[name] += pollHandler.RequestsReceived; | ||
449 | handledStats[name] += pollHandler.RequestsHandled; | ||
450 | } | ||
451 | } | ||
259 | } | 452 | } |
453 | ); | ||
454 | |||
455 | foreach (KeyValuePair<string, int> kvp in receivedStats.OrderByDescending(kp => kp.Value)) | ||
456 | cdt.AddRow(kvp.Key, kvp.Value, handledStats[kvp.Key]); | ||
457 | |||
458 | sb.Append(cdt.ToString()); | ||
459 | */ | ||
460 | } | ||
461 | |||
462 | private void HandleShowCapsStatsByUserCommand(string module, string[] cmdParams) | ||
463 | { | ||
464 | /* | ||
465 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) | ||
466 | return; | ||
467 | |||
468 | if (cmdParams.Length != 5 && cmdParams.Length != 7) | ||
469 | { | ||
470 | MainConsole.Instance.Output("Usage: show caps stats by user [<first-name> <last-name>]"); | ||
471 | return; | ||
472 | } | ||
473 | |||
474 | StringBuilder sb = new StringBuilder(); | ||
475 | sb.AppendFormat("Region {0}:\n", m_scene.Name); | ||
476 | |||
477 | if (cmdParams.Length == 5) | ||
478 | { | ||
479 | BuildSummaryStatsByUserReport(sb); | ||
480 | } | ||
481 | else if (cmdParams.Length == 7) | ||
482 | { | ||
483 | string firstName = cmdParams[5]; | ||
484 | string lastName = cmdParams[6]; | ||
485 | |||
486 | ScenePresence sp = m_scene.GetScenePresence(firstName, lastName); | ||
487 | |||
488 | if (sp == null) | ||
489 | return; | ||
260 | 490 | ||
261 | foreach (KeyValuePair<string, string> kvp3 in kvp.Value.ExternalCapsHandlers) | 491 | BuildDetailedStatsByUserReport(sb, sp); |
262 | caps.AppendFormat(m_showCapsCommandFormat, kvp3.Key, kvp3.Value); | ||
263 | } | 492 | } |
264 | 493 | ||
265 | MainConsole.Instance.Output(caps.ToString()); | 494 | MainConsole.Instance.Output(sb.ToString()); |
495 | */ | ||
496 | } | ||
497 | |||
498 | private void BuildDetailedStatsByUserReport(StringBuilder sb, ScenePresence sp) | ||
499 | { | ||
500 | /* | ||
501 | sb.AppendFormat("Avatar name {0}, type {1}\n", sp.Name, sp.IsChildAgent ? "child" : "root"); | ||
502 | |||
503 | ConsoleDisplayTable cdt = new ConsoleDisplayTable(); | ||
504 | cdt.AddColumn("Cap Name", 34); | ||
505 | cdt.AddColumn("Req Received", 12); | ||
506 | cdt.AddColumn("Req Handled", 12); | ||
507 | cdt.Indent = 2; | ||
508 | |||
509 | Caps caps = m_scene.CapsModule.GetCapsForUser(sp.UUID); | ||
510 | |||
511 | if (caps == null) | ||
512 | return; | ||
513 | |||
514 | List<CapTableRow> capRows = new List<CapTableRow>(); | ||
515 | |||
516 | foreach (IRequestHandler reqHandler in caps.CapsHandlers.GetCapsHandlers().Values) | ||
517 | capRows.Add(new CapTableRow(reqHandler.Name, reqHandler.RequestsReceived, reqHandler.RequestsHandled)); | ||
518 | |||
519 | foreach (KeyValuePair<string, PollServiceEventArgs> kvp in caps.GetPollHandlers()) | ||
520 | capRows.Add(new CapTableRow(kvp.Key, kvp.Value.RequestsReceived, kvp.Value.RequestsHandled)); | ||
521 | |||
522 | foreach (CapTableRow ctr in capRows.OrderByDescending(ctr => ctr.RequestsReceived)) | ||
523 | cdt.AddRow(ctr.Name, ctr.RequestsReceived, ctr.RequestsHandled); | ||
524 | |||
525 | sb.Append(cdt.ToString()); | ||
526 | */ | ||
527 | } | ||
528 | |||
529 | private void BuildSummaryStatsByUserReport(StringBuilder sb) | ||
530 | { | ||
531 | /* | ||
532 | ConsoleDisplayTable cdt = new ConsoleDisplayTable(); | ||
533 | cdt.AddColumn("Name", 32); | ||
534 | cdt.AddColumn("Type", 5); | ||
535 | cdt.AddColumn("Req Received", 12); | ||
536 | cdt.AddColumn("Req Handled", 12); | ||
537 | cdt.Indent = 2; | ||
538 | |||
539 | m_scene.ForEachScenePresence( | ||
540 | sp => | ||
541 | { | ||
542 | Caps caps = m_scene.CapsModule.GetCapsForUser(sp.UUID); | ||
543 | |||
544 | if (caps == null) | ||
545 | return; | ||
546 | |||
547 | Dictionary<string, IRequestHandler> capsHandlers = caps.CapsHandlers.GetCapsHandlers(); | ||
548 | |||
549 | int totalRequestsReceived = 0; | ||
550 | int totalRequestsHandled = 0; | ||
551 | |||
552 | foreach (IRequestHandler reqHandler in capsHandlers.Values) | ||
553 | { | ||
554 | totalRequestsReceived += reqHandler.RequestsReceived; | ||
555 | totalRequestsHandled += reqHandler.RequestsHandled; | ||
556 | } | ||
557 | |||
558 | Dictionary<string, PollServiceEventArgs> capsPollHandlers = caps.GetPollHandlers(); | ||
559 | |||
560 | foreach (PollServiceEventArgs handler in capsPollHandlers.Values) | ||
561 | { | ||
562 | totalRequestsReceived += handler.RequestsReceived; | ||
563 | totalRequestsHandled += handler.RequestsHandled; | ||
564 | } | ||
565 | |||
566 | cdt.AddRow(sp.Name, sp.IsChildAgent ? "child" : "root", totalRequestsReceived, totalRequestsHandled); | ||
567 | } | ||
568 | ); | ||
569 | |||
570 | sb.Append(cdt.ToString()); | ||
571 | */ | ||
572 | } | ||
573 | |||
574 | private class CapTableRow | ||
575 | { | ||
576 | public string Name { get; set; } | ||
577 | public int RequestsReceived { get; set; } | ||
578 | public int RequestsHandled { get; set; } | ||
579 | |||
580 | public CapTableRow(string name, int requestsReceived, int requestsHandled) | ||
581 | { | ||
582 | Name = name; | ||
583 | RequestsReceived = requestsReceived; | ||
584 | RequestsHandled = requestsHandled; | ||
585 | } | ||
266 | } | 586 | } |
267 | } | 587 | } |
268 | } | 588 | } |
diff --git a/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs b/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs index 1f1568f..0c632b1 100644 --- a/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs +++ b/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs | |||
@@ -44,11 +44,12 @@ namespace OpenSim.Region.CoreModules.Framework.DynamicAttributes.DAExampleModule | |||
44 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DAExampleModule")] | 44 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DAExampleModule")] |
45 | public class DAExampleModule : INonSharedRegionModule | 45 | public class DAExampleModule : INonSharedRegionModule |
46 | { | 46 | { |
47 | // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 47 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
48 | 48 | ||
49 | private static readonly bool ENABLED = false; // enable for testing | 49 | private readonly bool ENABLED = false; // enable for testing |
50 | 50 | ||
51 | public const string DANamespace = "DAExample Module"; | 51 | public const string Namespace = "Example"; |
52 | public const string StoreName = "DA"; | ||
52 | 53 | ||
53 | protected Scene m_scene; | 54 | protected Scene m_scene; |
54 | protected IDialogModule m_dialogMod; | 55 | protected IDialogModule m_dialogMod; |
@@ -65,6 +66,8 @@ namespace OpenSim.Region.CoreModules.Framework.DynamicAttributes.DAExampleModule | |||
65 | m_scene = scene; | 66 | m_scene = scene; |
66 | m_scene.EventManager.OnSceneGroupMove += OnSceneGroupMove; | 67 | m_scene.EventManager.OnSceneGroupMove += OnSceneGroupMove; |
67 | m_dialogMod = m_scene.RequestModuleInterface<IDialogModule>(); | 68 | m_dialogMod = m_scene.RequestModuleInterface<IDialogModule>(); |
69 | |||
70 | m_log.DebugFormat("[DA EXAMPLE MODULE]: Added region {0}", m_scene.Name); | ||
68 | } | 71 | } |
69 | } | 72 | } |
70 | 73 | ||
@@ -91,7 +94,7 @@ namespace OpenSim.Region.CoreModules.Framework.DynamicAttributes.DAExampleModule | |||
91 | if (sop == null) | 94 | if (sop == null) |
92 | return true; | 95 | return true; |
93 | 96 | ||
94 | if (!sop.DynAttrs.TryGetValue(DANamespace, out attrs)) | 97 | if (!sop.DynAttrs.TryGetStore(Namespace, StoreName, out attrs)) |
95 | attrs = new OSDMap(); | 98 | attrs = new OSDMap(); |
96 | 99 | ||
97 | OSDInteger newValue; | 100 | OSDInteger newValue; |
@@ -106,12 +109,14 @@ namespace OpenSim.Region.CoreModules.Framework.DynamicAttributes.DAExampleModule | |||
106 | 109 | ||
107 | attrs["moves"] = newValue; | 110 | attrs["moves"] = newValue; |
108 | 111 | ||
109 | sop.DynAttrs[DANamespace] = attrs; | 112 | sop.DynAttrs.SetStore(Namespace, StoreName, attrs); |
110 | } | 113 | } |
111 | 114 | ||
112 | sop.ParentGroup.HasGroupChanged = true; | 115 | sop.ParentGroup.HasGroupChanged = true; |
113 | 116 | ||
114 | m_dialogMod.SendGeneralAlert(string.Format("{0} {1} moved {2} times", sop.Name, sop.UUID, newValue)); | 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); | ||
115 | 120 | ||
116 | return true; | 121 | return true; |
117 | } | 122 | } |
diff --git a/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DOExampleModule.cs b/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DOExampleModule.cs index 650aa35..166a994 100644 --- a/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DOExampleModule.cs +++ b/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DOExampleModule.cs | |||
@@ -64,8 +64,8 @@ namespace OpenSim.Region.Framework.DynamicAttributes.DOExampleModule | |||
64 | 64 | ||
65 | private Scene m_scene; | 65 | private Scene m_scene; |
66 | private IDialogModule m_dialogMod; | 66 | private IDialogModule m_dialogMod; |
67 | 67 | ||
68 | public string Name { get { return "DOExample Module"; } } | 68 | public string Name { get { return "DO"; } } |
69 | public Type ReplaceableInterface { get { return null; } } | 69 | public Type ReplaceableInterface { get { return null; } } |
70 | 70 | ||
71 | public void Initialise(IConfigSource source) {} | 71 | public void Initialise(IConfigSource source) {} |
@@ -106,7 +106,7 @@ namespace OpenSim.Region.Framework.DynamicAttributes.DOExampleModule | |||
106 | 106 | ||
107 | // Console.WriteLine("Here for {0}", so.Name); | 107 | // Console.WriteLine("Here for {0}", so.Name); |
108 | 108 | ||
109 | if (rootPart.DynAttrs.TryGetValue(DAExampleModule.DANamespace, out attrs)) | 109 | if (rootPart.DynAttrs.TryGetStore(DAExampleModule.Namespace, DAExampleModule.StoreName, out attrs)) |
110 | { | 110 | { |
111 | movesSoFar = attrs["moves"].AsInteger(); | 111 | movesSoFar = attrs["moves"].AsInteger(); |
112 | 112 | ||
@@ -114,7 +114,7 @@ namespace OpenSim.Region.Framework.DynamicAttributes.DOExampleModule | |||
114 | "[DO EXAMPLE MODULE]: Found saved moves {0} for {1} in {2}", movesSoFar, so.Name, m_scene.Name); | 114 | "[DO EXAMPLE MODULE]: Found saved moves {0} for {1} in {2}", movesSoFar, so.Name, m_scene.Name); |
115 | } | 115 | } |
116 | 116 | ||
117 | rootPart.DynObjs.Add(Name, new MyObject(movesSoFar)); | 117 | rootPart.DynObjs.Add(DAExampleModule.Namespace, Name, new MyObject(movesSoFar)); |
118 | } | 118 | } |
119 | 119 | ||
120 | private bool OnSceneGroupMove(UUID groupId, Vector3 delta) | 120 | private bool OnSceneGroupMove(UUID groupId, Vector3 delta) |
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index ed867b8..5fea0cf 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs | |||
@@ -51,11 +51,19 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
51 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "EntityTransferModule")] | 51 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "EntityTransferModule")] |
52 | public class EntityTransferModule : INonSharedRegionModule, IEntityTransferModule | 52 | public class EntityTransferModule : INonSharedRegionModule, IEntityTransferModule |
53 | { | 53 | { |
54 | 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]"; | ||
55 | 56 | ||
56 | public const int DefaultMaxTransferDistance = 4095; | 57 | public const int DefaultMaxTransferDistance = 4095; |
57 | public const bool WaitForAgentArrivedAtDestinationDefault = true; | 58 | public const bool WaitForAgentArrivedAtDestinationDefault = true; |
58 | 59 | ||
60 | public string OutgoingTransferVersionName { get; set; } | ||
61 | |||
62 | /// <summary> | ||
63 | /// Determine the maximum entity transfer version we will use for teleports. | ||
64 | /// </summary> | ||
65 | public float MaxOutgoingTransferVersion { get; set; } | ||
66 | |||
59 | /// <summary> | 67 | /// <summary> |
60 | /// The maximum distance, in standard region units (256m) that an agent is allowed to transfer. | 68 | /// The maximum distance, in standard region units (256m) that an agent is allowed to transfer. |
61 | /// </summary> | 69 | /// </summary> |
@@ -151,9 +159,39 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
151 | /// <param name="source"></param> | 159 | /// <param name="source"></param> |
152 | protected virtual void InitialiseCommon(IConfigSource source) | 160 | protected virtual void InitialiseCommon(IConfigSource source) |
153 | { | 161 | { |
162 | string transferVersionName = "SIMULATION"; | ||
163 | float maxTransferVersion = 0.2f; | ||
164 | |||
154 | IConfig transferConfig = source.Configs["EntityTransfer"]; | 165 | IConfig transferConfig = source.Configs["EntityTransfer"]; |
155 | if (transferConfig != null) | 166 | if (transferConfig != null) |
156 | { | 167 | { |
168 | string rawVersion | ||
169 | = transferConfig.GetString( | ||
170 | "MaxOutgoingTransferVersion", | ||
171 | string.Format("{0}/{1}", transferVersionName, maxTransferVersion)); | ||
172 | |||
173 | string[] rawVersionComponents = rawVersion.Split(new char[] { '/' }); | ||
174 | |||
175 | bool versionValid = false; | ||
176 | |||
177 | if (rawVersionComponents.Length >= 2) | ||
178 | versionValid = float.TryParse(rawVersionComponents[1], out maxTransferVersion); | ||
179 | |||
180 | if (!versionValid) | ||
181 | { | ||
182 | m_log.ErrorFormat( | ||
183 | "[ENTITY TRANSFER MODULE]: MaxOutgoingTransferVersion {0} is invalid, using {1}", | ||
184 | rawVersion, string.Format("{0}/{1}", transferVersionName, maxTransferVersion)); | ||
185 | } | ||
186 | else | ||
187 | { | ||
188 | transferVersionName = rawVersionComponents[0]; | ||
189 | |||
190 | m_log.InfoFormat( | ||
191 | "[ENTITY TRANSFER MODULE]: MaxOutgoingTransferVersion set to {0}", | ||
192 | string.Format("{0}/{1}", transferVersionName, maxTransferVersion)); | ||
193 | } | ||
194 | |||
157 | DisableInterRegionTeleportCancellation | 195 | DisableInterRegionTeleportCancellation |
158 | = transferConfig.GetBoolean("DisableInterRegionTeleportCancellation", false); | 196 | = transferConfig.GetBoolean("DisableInterRegionTeleportCancellation", false); |
159 | 197 | ||
@@ -167,6 +205,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
167 | MaxTransferDistance = DefaultMaxTransferDistance; | 205 | MaxTransferDistance = DefaultMaxTransferDistance; |
168 | } | 206 | } |
169 | 207 | ||
208 | OutgoingTransferVersionName = transferVersionName; | ||
209 | MaxOutgoingTransferVersion = maxTransferVersion; | ||
210 | |||
170 | m_entityTransferStateMachine = new EntityTransferStateMachine(this); | 211 | m_entityTransferStateMachine = new EntityTransferStateMachine(this); |
171 | 212 | ||
172 | m_Enabled = true; | 213 | m_Enabled = true; |
@@ -280,10 +321,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
280 | 321 | ||
281 | private void OnConnectionClosed(IClientAPI client) | 322 | private void OnConnectionClosed(IClientAPI client) |
282 | { | 323 | { |
283 | if (client.IsLoggingOut) | 324 | if (client.IsLoggingOut && m_entityTransferStateMachine.UpdateInTransit(client.AgentId, AgentTransferState.Aborting)) |
284 | { | 325 | { |
285 | m_entityTransferStateMachine.UpdateInTransit(client.AgentId, AgentTransferState.Aborting); | ||
286 | |||
287 | m_log.DebugFormat( | 326 | m_log.DebugFormat( |
288 | "[ENTITY TRANSFER MODULE]: Aborted teleport request from {0} in {1} due to simultaneous logout", | 327 | "[ENTITY TRANSFER MODULE]: Aborted teleport request from {0} in {1} due to simultaneous logout", |
289 | client.Name, Scene.Name); | 328 | client.Name, Scene.Name); |
@@ -318,7 +357,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
318 | m_log.DebugFormat( | 357 | m_log.DebugFormat( |
319 | "[ENTITY TRANSFER MODULE]: Ignoring teleport request of {0} {1} to {2}@{3} - agent is already in transit.", | 358 | "[ENTITY TRANSFER MODULE]: Ignoring teleport request of {0} {1} to {2}@{3} - agent is already in transit.", |
320 | sp.Name, sp.UUID, position, regionHandle); | 359 | sp.Name, sp.UUID, position, regionHandle); |
321 | 360 | ||
361 | sp.ControllingClient.SendTeleportFailed("Previous teleport process incomplete. Please retry shortly."); | ||
362 | |||
322 | return; | 363 | return; |
323 | } | 364 | } |
324 | 365 | ||
@@ -522,6 +563,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
522 | /// </returns> | 563 | /// </returns> |
523 | private bool IsWithinMaxTeleportDistance(RegionInfo sourceRegion, GridRegion destRegion) | 564 | private bool IsWithinMaxTeleportDistance(RegionInfo sourceRegion, GridRegion destRegion) |
524 | { | 565 | { |
566 | if(MaxTransferDistance == 0) | ||
567 | return true; | ||
568 | |||
525 | // m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Source co-ords are x={0} y={1}", curRegionX, curRegionY); | 569 | // m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Source co-ords are x={0} y={1}", curRegionX, curRegionY); |
526 | // | 570 | // |
527 | // m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Final dest is x={0} y={1} {2}@{3}", | 571 | // m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Final dest is x={0} y={1} {2}@{3}", |
@@ -623,7 +667,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
623 | if (!sp.ValidateAttachments()) | 667 | if (!sp.ValidateAttachments()) |
624 | m_log.DebugFormat( | 668 | m_log.DebugFormat( |
625 | "[ENTITY TRANSFER MODULE]: Failed validation of all attachments for teleport of {0} from {1} to {2}. Continuing.", | 669 | "[ENTITY TRANSFER MODULE]: Failed validation of all attachments for teleport of {0} from {1} to {2}. Continuing.", |
626 | sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName); | 670 | sp.Name, sp.Scene.Name, finalDestination.RegionName); |
627 | 671 | ||
628 | string reason; | 672 | string reason; |
629 | string version; | 673 | string version; |
@@ -634,7 +678,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
634 | 678 | ||
635 | m_log.DebugFormat( | 679 | m_log.DebugFormat( |
636 | "[ENTITY TRANSFER MODULE]: {0} was stopped from teleporting from {1} to {2} because {3}", | 680 | "[ENTITY TRANSFER MODULE]: {0} was stopped from teleporting from {1} to {2} because {3}", |
637 | sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName, reason); | 681 | sp.Name, sp.Scene.Name, finalDestination.RegionName, reason); |
638 | 682 | ||
639 | return; | 683 | return; |
640 | } | 684 | } |
@@ -644,7 +688,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
644 | // as server attempts. | 688 | // as server attempts. |
645 | m_interRegionTeleportAttempts.Value++; | 689 | m_interRegionTeleportAttempts.Value++; |
646 | 690 | ||
647 | m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Destination is running version {0}", version); | 691 | m_log.DebugFormat( |
692 | "[ENTITY TRANSFER MODULE]: {0} max transfer version is {1}/{2}, {3} max version is {4}", | ||
693 | sp.Scene.Name, OutgoingTransferVersionName, MaxOutgoingTransferVersion, finalDestination.RegionName, version); | ||
648 | 694 | ||
649 | // Fixing a bug where teleporting while sitting results in the avatar ending up removed from | 695 | // Fixing a bug where teleporting while sitting results in the avatar ending up removed from |
650 | // both regions | 696 | // both regions |
@@ -691,6 +737,29 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
691 | agentCircuit.CapsPath = CapsUtil.GetRandomCapsObjectPath(); | 737 | agentCircuit.CapsPath = CapsUtil.GetRandomCapsObjectPath(); |
692 | } | 738 | } |
693 | 739 | ||
740 | // We're going to fallback to V1 if the destination gives us anything smaller than 0.2 or we're forcing | ||
741 | // use of the earlier protocol | ||
742 | float versionNumber = 0.1f; | ||
743 | string[] versionComponents = version.Split(new char[] { '/' }); | ||
744 | if (versionComponents.Length >= 2) | ||
745 | float.TryParse(versionComponents[1], out versionNumber); | ||
746 | |||
747 | if (versionNumber == 0.2f && MaxOutgoingTransferVersion >= versionNumber) | ||
748 | TransferAgent_V2(sp, agentCircuit, reg, finalDestination, endPoint, teleportFlags, oldRegionX, newRegionX, oldRegionY, newRegionY, version, out reason); | ||
749 | else | ||
750 | TransferAgent_V1(sp, agentCircuit, reg, finalDestination, endPoint, teleportFlags, oldRegionX, newRegionX, oldRegionY, newRegionY, version, out reason); | ||
751 | } | ||
752 | |||
753 | private void TransferAgent_V1(ScenePresence sp, AgentCircuitData agentCircuit, GridRegion reg, GridRegion finalDestination, | ||
754 | IPEndPoint endPoint, uint teleportFlags, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY, string version, out string reason) | ||
755 | { | ||
756 | ulong destinationHandle = finalDestination.RegionHandle; | ||
757 | AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode); | ||
758 | |||
759 | m_log.DebugFormat( | ||
760 | "[ENTITY TRANSFER MODULE]: Using TP V1 for {0} going from {1} to {2}", | ||
761 | sp.Name, Scene.Name, finalDestination.RegionName); | ||
762 | |||
694 | // Let's create an agent there if one doesn't exist yet. | 763 | // Let's create an agent there if one doesn't exist yet. |
695 | // NOTE: logout will always be false for a non-HG teleport. | 764 | // NOTE: logout will always be false for a non-HG teleport. |
696 | bool logout = false; | 765 | bool logout = false; |
@@ -712,7 +781,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
712 | m_interRegionTeleportCancels.Value++; | 781 | m_interRegionTeleportCancels.Value++; |
713 | 782 | ||
714 | m_log.DebugFormat( | 783 | m_log.DebugFormat( |
715 | "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after CreateAgent on client request", | 784 | "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after CreateAgent on client request", |
716 | sp.Name, finalDestination.RegionName, sp.Scene.Name); | 785 | sp.Name, finalDestination.RegionName, sp.Scene.Name); |
717 | 786 | ||
718 | return; | 787 | return; |
@@ -734,11 +803,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
734 | // OK, it got this agent. Let's close some child agents | 803 | // OK, it got this agent. Let's close some child agents |
735 | sp.CloseChildAgents(newRegionX, newRegionY); | 804 | sp.CloseChildAgents(newRegionX, newRegionY); |
736 | 805 | ||
737 | IClientIPEndpoint ipepClient; | 806 | IClientIPEndpoint ipepClient; |
807 | string capsPath = String.Empty; | ||
738 | if (NeedsNewAgent(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY)) | 808 | if (NeedsNewAgent(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY)) |
739 | { | 809 | { |
740 | m_log.DebugFormat( | 810 | m_log.DebugFormat( |
741 | "[ENTITY TRANSFER MODULE]: Determined that region {0} at {1},{2} needs new child agent for incoming agent {3} from {4}", | 811 | "[ENTITY TRANSFER MODULE]: Determined that region {0} at {1},{2} needs new child agent for incoming agent {3} from {4}", |
742 | finalDestination.RegionName, newRegionX, newRegionY, sp.Name, Scene.Name); | 812 | finalDestination.RegionName, newRegionX, newRegionY, sp.Name, Scene.Name); |
743 | 813 | ||
744 | //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Creating agent..."); | 814 | //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Creating agent..."); |
@@ -756,7 +826,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
756 | // The EnableSimulator message makes the client establish a connection with the destination | 826 | // The EnableSimulator message makes the client establish a connection with the destination |
757 | // simulator by sending the initial UseCircuitCode UDP packet to the destination containing the | 827 | // simulator by sending the initial UseCircuitCode UDP packet to the destination containing the |
758 | // correct circuit code. | 828 | // correct circuit code. |
759 | m_eqModule.EnableSimulator(destinationHandle, endPoint, sp.UUID); | 829 | m_eqModule.EnableSimulator(destinationHandle, endPoint, sp.UUID, |
830 | finalDestination.RegionSizeX, finalDestination.RegionSizeY); | ||
831 | m_log.DebugFormat("{0} Sent EnableSimulator. regName={1}, size=<{2},{3}>", LogHeader, | ||
832 | finalDestination.RegionName, finalDestination.RegionSizeX, finalDestination.RegionSizeY); | ||
760 | 833 | ||
761 | // XXX: Is this wait necessary? We will always end up waiting on UpdateAgent for the destination | 834 | // XXX: Is this wait necessary? We will always end up waiting on UpdateAgent for the destination |
762 | // simulator to confirm that it has established communication with the viewer. | 835 | // simulator to confirm that it has established communication with the viewer. |
@@ -766,7 +839,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
766 | // unnecessary - teleport will succeed and SEED caps will be requested without it (though possibly | 839 | // unnecessary - teleport will succeed and SEED caps will be requested without it (though possibly |
767 | // only on TeleportFinish). This is untested for region teleport between different simulators | 840 | // only on TeleportFinish). This is untested for region teleport between different simulators |
768 | // though this probably also works. | 841 | // though this probably also works. |
769 | m_eqModule.EstablishAgentCommunication(sp.UUID, endPoint, capsPath); | 842 | m_eqModule.EstablishAgentCommunication(sp.UUID, endPoint, capsPath, finalDestination.RegionHandle, |
843 | finalDestination.RegionSizeX, finalDestination.RegionSizeY); | ||
770 | } | 844 | } |
771 | else | 845 | else |
772 | { | 846 | { |
@@ -785,10 +859,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
785 | // Let's send a full update of the agent. This is a synchronous call. | 859 | // Let's send a full update of the agent. This is a synchronous call. |
786 | AgentData agent = new AgentData(); | 860 | AgentData agent = new AgentData(); |
787 | sp.CopyTo(agent); | 861 | sp.CopyTo(agent); |
788 | agent.Position = position; | 862 | agent.Position = agentCircuit.startpos; |
789 | SetCallbackURL(agent, sp.Scene.RegionInfo); | 863 | SetCallbackURL(agent, sp.Scene.RegionInfo); |
790 | 864 | ||
791 | //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Updating agent..."); | ||
792 | 865 | ||
793 | // We will check for an abort before UpdateAgent since UpdateAgent will require an active viewer to | 866 | // We will check for an abort before UpdateAgent since UpdateAgent will require an active viewer to |
794 | // establish th econnection to the destination which makes it return true. | 867 | // establish th econnection to the destination which makes it return true. |
@@ -821,10 +894,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
821 | } | 894 | } |
822 | 895 | ||
823 | m_log.WarnFormat( | 896 | m_log.WarnFormat( |
824 | "[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1} from {2}. Keeping avatar in source region.", | 897 | "[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1}. Keeping avatar in {2}", |
825 | sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); | 898 | sp.Name, finalDestination.RegionName, sp.Scene.Name); |
826 | 899 | ||
827 | Fail(sp, finalDestination, logout, "Connection between viewer and destination region could not be established."); | 900 | Fail(sp, finalDestination, logout, currentAgentCircuit.SessionID.ToString(), "Connection between viewer and destination region could not be established."); |
828 | return; | 901 | return; |
829 | } | 902 | } |
830 | 903 | ||
@@ -833,10 +906,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
833 | m_interRegionTeleportCancels.Value++; | 906 | m_interRegionTeleportCancels.Value++; |
834 | 907 | ||
835 | m_log.DebugFormat( | 908 | m_log.DebugFormat( |
836 | "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after UpdateAgent on client request", | 909 | "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after UpdateAgent on client request", |
837 | sp.Name, finalDestination.RegionName, sp.Scene.Name); | 910 | sp.Name, finalDestination.RegionName, sp.Scene.Name); |
838 | 911 | ||
839 | CleanupFailedInterRegionTeleport(sp, finalDestination); | 912 | CleanupFailedInterRegionTeleport(sp, currentAgentCircuit.SessionID.ToString(), finalDestination); |
840 | 913 | ||
841 | return; | 914 | return; |
842 | } | 915 | } |
@@ -850,9 +923,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
850 | // closes our existing agent which is still signalled as root. | 923 | // closes our existing agent which is still signalled as root. |
851 | sp.IsChildAgent = true; | 924 | sp.IsChildAgent = true; |
852 | 925 | ||
926 | // OK, send TPFinish to the client, so that it starts the process of contacting the destination region | ||
853 | if (m_eqModule != null) | 927 | if (m_eqModule != null) |
854 | { | 928 | { |
855 | m_eqModule.TeleportFinishEvent(destinationHandle, 13, endPoint, 0, teleportFlags, capsPath, sp.UUID); | 929 | m_eqModule.TeleportFinishEvent(destinationHandle, 13, endPoint, 0, teleportFlags, capsPath, sp.UUID, |
930 | finalDestination.RegionSizeX, finalDestination.RegionSizeY); | ||
856 | } | 931 | } |
857 | else | 932 | else |
858 | { | 933 | { |
@@ -879,8 +954,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
879 | m_log.WarnFormat( | 954 | m_log.WarnFormat( |
880 | "[ENTITY TRANSFER MODULE]: Teleport of {0} to {1} from {2} failed due to no callback from destination region. Returning avatar to source region.", | 955 | "[ENTITY TRANSFER MODULE]: Teleport of {0} to {1} from {2} failed due to no callback from destination region. Returning avatar to source region.", |
881 | sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); | 956 | sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); |
882 | 957 | ||
883 | Fail(sp, finalDestination, logout, "Destination region did not signal teleport completion."); | 958 | Fail(sp, finalDestination, logout, currentAgentCircuit.SessionID.ToString(), "Destination region did not signal teleport completion."); |
884 | 959 | ||
885 | return; | 960 | return; |
886 | } | 961 | } |
@@ -908,15 +983,190 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
908 | 983 | ||
909 | if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) | 984 | if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) |
910 | { | 985 | { |
986 | if (!sp.Scene.IncomingPreCloseClient(sp)) | ||
987 | return; | ||
988 | |||
911 | // We need to delay here because Imprudence viewers, unlike v1 or v3, have a short (<200ms, <500ms) delay before | 989 | // We need to delay here because Imprudence viewers, unlike v1 or v3, have a short (<200ms, <500ms) delay before |
912 | // they regard the new region as the current region after receiving the AgentMovementComplete | 990 | // they regard the new region as the current region after receiving the AgentMovementComplete |
913 | // response. If close is sent before then, it will cause the viewer to quit instead. | 991 | // response. If close is sent before then, it will cause the viewer to quit instead. |
914 | // | 992 | // |
915 | // This sleep can be increased if necessary. However, whilst it's active, | 993 | // This sleep can be increased if necessary. However, whilst it's active, |
916 | // an agent cannot teleport back to this region if it has teleported away. | 994 | // an agent cannot teleport back to this region if it has teleported away. |
917 | Thread.Sleep(3000); | 995 | Thread.Sleep(2000); |
918 | 996 | ||
919 | sp.Scene.IncomingCloseAgent(sp.UUID, false); | 997 | sp.Scene.CloseAgent(sp.UUID, false); |
998 | } | ||
999 | else | ||
1000 | { | ||
1001 | // now we have a child agent in this region. | ||
1002 | sp.Reset(); | ||
1003 | } | ||
1004 | } | ||
1005 | |||
1006 | private void TransferAgent_V2(ScenePresence sp, AgentCircuitData agentCircuit, GridRegion reg, GridRegion finalDestination, | ||
1007 | IPEndPoint endPoint, uint teleportFlags, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY, string version, out string reason) | ||
1008 | { | ||
1009 | ulong destinationHandle = finalDestination.RegionHandle; | ||
1010 | AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode); | ||
1011 | |||
1012 | // Let's create an agent there if one doesn't exist yet. | ||
1013 | // NOTE: logout will always be false for a non-HG teleport. | ||
1014 | bool logout = false; | ||
1015 | if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason, out logout)) | ||
1016 | { | ||
1017 | m_interRegionTeleportFailures.Value++; | ||
1018 | |||
1019 | sp.ControllingClient.SendTeleportFailed(String.Format("Teleport refused: {0}", reason)); | ||
1020 | |||
1021 | m_log.DebugFormat( | ||
1022 | "[ENTITY TRANSFER MODULE]: Teleport of {0} from {1} to {2} was refused because {3}", | ||
1023 | sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName, reason); | ||
1024 | |||
1025 | return; | ||
1026 | } | ||
1027 | |||
1028 | if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Cancelling) | ||
1029 | { | ||
1030 | m_interRegionTeleportCancels.Value++; | ||
1031 | |||
1032 | m_log.DebugFormat( | ||
1033 | "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after CreateAgent on client request", | ||
1034 | sp.Name, finalDestination.RegionName, sp.Scene.Name); | ||
1035 | |||
1036 | return; | ||
1037 | } | ||
1038 | else if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting) | ||
1039 | { | ||
1040 | m_interRegionTeleportAborts.Value++; | ||
1041 | |||
1042 | m_log.DebugFormat( | ||
1043 | "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after CreateAgent due to previous client close.", | ||
1044 | sp.Name, finalDestination.RegionName, sp.Scene.Name); | ||
1045 | |||
1046 | return; | ||
1047 | } | ||
1048 | |||
1049 | // Past this point we have to attempt clean up if the teleport fails, so update transfer state. | ||
1050 | m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring); | ||
1051 | |||
1052 | IClientIPEndpoint ipepClient; | ||
1053 | string capsPath = String.Empty; | ||
1054 | if (NeedsNewAgent(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY)) | ||
1055 | { | ||
1056 | m_log.DebugFormat( | ||
1057 | "[ENTITY TRANSFER MODULE]: Determined that region {0} at {1},{2} needs new child agent for agent {3} from {4}", | ||
1058 | finalDestination.RegionName, newRegionX, newRegionY, sp.Name, Scene.Name); | ||
1059 | |||
1060 | //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Creating agent..."); | ||
1061 | #region IP Translation for NAT | ||
1062 | // Uses ipepClient above | ||
1063 | if (sp.ClientView.TryGet(out ipepClient)) | ||
1064 | { | ||
1065 | endPoint.Address = NetworkUtil.GetIPFor(ipepClient.EndPoint, endPoint.Address); | ||
1066 | } | ||
1067 | #endregion | ||
1068 | capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath); | ||
1069 | } | ||
1070 | else | ||
1071 | { | ||
1072 | agentCircuit.CapsPath = sp.Scene.CapsModule.GetChildSeed(sp.UUID, reg.RegionHandle); | ||
1073 | capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath); | ||
1074 | } | ||
1075 | |||
1076 | // We need to set this here to avoid an unlikely race condition when teleporting to a neighbour simulator, | ||
1077 | // where that neighbour simulator could otherwise request a child agent create on the source which then | ||
1078 | // closes our existing agent which is still signalled as root. | ||
1079 | //sp.IsChildAgent = true; | ||
1080 | |||
1081 | // New protocol: send TP Finish directly, without prior ES or EAC. That's what happens in the Linden grid | ||
1082 | if (m_eqModule != null) | ||
1083 | m_eqModule.TeleportFinishEvent(destinationHandle, 13, endPoint, 0, teleportFlags, capsPath, sp.UUID, | ||
1084 | finalDestination.RegionSizeX, finalDestination.RegionSizeY); | ||
1085 | else | ||
1086 | sp.ControllingClient.SendRegionTeleport(destinationHandle, 13, endPoint, 4, | ||
1087 | teleportFlags, capsPath); | ||
1088 | |||
1089 | m_log.DebugFormat( | ||
1090 | "[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} from {1} to {2}", | ||
1091 | capsPath, sp.Scene.RegionInfo.RegionName, sp.Name); | ||
1092 | |||
1093 | // Let's send a full update of the agent. | ||
1094 | AgentData agent = new AgentData(); | ||
1095 | sp.CopyTo(agent); | ||
1096 | agent.Position = agentCircuit.startpos; | ||
1097 | agent.SenderWantsToWaitForRoot = true; | ||
1098 | //SetCallbackURL(agent, sp.Scene.RegionInfo); | ||
1099 | |||
1100 | // Reset the do not close flag. This must be done before the destination opens child connections (here | ||
1101 | // triggered by UpdateAgent) to avoid race conditions. However, we also want to reset it as late as possible | ||
1102 | // to avoid a situation where an unexpectedly early call to Scene.NewUserConnection() wrongly results | ||
1103 | // in no close. | ||
1104 | sp.DoNotCloseAfterTeleport = false; | ||
1105 | |||
1106 | // Send the Update. If this returns true, we know the client has contacted the destination | ||
1107 | // via CompleteMovementIntoRegion, so we can let go. | ||
1108 | // If it returns false, something went wrong, and we need to abort. | ||
1109 | if (!UpdateAgent(reg, finalDestination, agent, sp)) | ||
1110 | { | ||
1111 | if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting) | ||
1112 | { | ||
1113 | m_interRegionTeleportAborts.Value++; | ||
1114 | |||
1115 | m_log.DebugFormat( | ||
1116 | "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after UpdateAgent due to previous client close.", | ||
1117 | sp.Name, finalDestination.RegionName, sp.Scene.Name); | ||
1118 | |||
1119 | return; | ||
1120 | } | ||
1121 | |||
1122 | m_log.WarnFormat( | ||
1123 | "[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1}. Keeping avatar in {2}", | ||
1124 | sp.Name, finalDestination.RegionName, sp.Scene.Name); | ||
1125 | |||
1126 | Fail(sp, finalDestination, logout, currentAgentCircuit.SessionID.ToString(), "Connection between viewer and destination region could not be established."); | ||
1127 | return; | ||
1128 | } | ||
1129 | |||
1130 | m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); | ||
1131 | |||
1132 | // Need to signal neighbours whether child agents may need closing irrespective of whether this | ||
1133 | // one needed closing. We also need to close child agents as quickly as possible to avoid complicated | ||
1134 | // race conditions with rapid agent releporting (e.g. from A1 to a non-neighbour B, back | ||
1135 | // to a neighbour A2 then off to a non-neighbour C). Closing child agents any later requires complex | ||
1136 | // distributed checks to avoid problems in rapid reteleporting scenarios and where child agents are | ||
1137 | // abandoned without proper close by viewer but then re-used by an incoming connection. | ||
1138 | sp.CloseChildAgents(newRegionX, newRegionY); | ||
1139 | |||
1140 | // May need to logout or other cleanup | ||
1141 | AgentHasMovedAway(sp, logout); | ||
1142 | |||
1143 | // Well, this is it. The agent is over there. | ||
1144 | KillEntity(sp.Scene, sp.LocalId); | ||
1145 | |||
1146 | // Now let's make it officially a child agent | ||
1147 | sp.MakeChildAgent(); | ||
1148 | |||
1149 | // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone | ||
1150 | if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) | ||
1151 | { | ||
1152 | if (!sp.Scene.IncomingPreCloseClient(sp)) | ||
1153 | return; | ||
1154 | |||
1155 | // RED ALERT!!!! | ||
1156 | // PLEASE DO NOT DECREASE THIS WAIT TIME UNDER ANY CIRCUMSTANCES. | ||
1157 | // THE VIEWERS SEEM TO NEED SOME TIME AFTER RECEIVING MoveAgentIntoRegion | ||
1158 | // BEFORE THEY SETTLE IN THE NEW REGION. | ||
1159 | // DECREASING THE WAIT TIME HERE WILL EITHER RESULT IN A VIEWER CRASH OR | ||
1160 | // IN THE AVIE BEING PLACED IN INFINITY FOR A COUPLE OF SECONDS. | ||
1161 | Thread.Sleep(15000); | ||
1162 | |||
1163 | // OK, it got this agent. Let's close everything | ||
1164 | // If we shouldn't close the agent due to some other region renewing the connection | ||
1165 | // then this will be handled in IncomingCloseAgent under lock conditions | ||
1166 | m_log.DebugFormat( | ||
1167 | "[ENTITY TRANSFER MODULE]: Closing agent {0} in {1} after teleport", sp.Name, Scene.Name); | ||
1168 | |||
1169 | sp.Scene.CloseAgent(sp.UUID, false); | ||
920 | } | 1170 | } |
921 | else | 1171 | else |
922 | { | 1172 | { |
@@ -934,17 +1184,20 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
934 | /// <remarks> | 1184 | /// <remarks> |
935 | /// <param name='sp'> </param> | 1185 | /// <param name='sp'> </param> |
936 | /// <param name='finalDestination'></param> | 1186 | /// <param name='finalDestination'></param> |
937 | protected virtual void CleanupFailedInterRegionTeleport(ScenePresence sp, GridRegion finalDestination) | 1187 | protected virtual void CleanupFailedInterRegionTeleport(ScenePresence sp, string auth_token, GridRegion finalDestination) |
938 | { | 1188 | { |
939 | m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); | 1189 | m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); |
940 | 1190 | ||
941 | sp.IsChildAgent = false; | 1191 | if (sp.IsChildAgent) // We had set it to child before attempted TP (V1) |
942 | ReInstantiateScripts(sp); | 1192 | { |
943 | 1193 | sp.IsChildAgent = false; | |
944 | EnableChildAgents(sp); | 1194 | ReInstantiateScripts(sp); |
945 | 1195 | ||
1196 | EnableChildAgents(sp); | ||
1197 | } | ||
946 | // Finally, kill the agent we just created at the destination. | 1198 | // Finally, kill the agent we just created at the destination. |
947 | Scene.SimulationService.CloseAgent(finalDestination, sp.UUID); | 1199 | // XXX: Possibly this should be done asynchronously. |
1200 | Scene.SimulationService.CloseAgent(finalDestination, sp.UUID, auth_token); | ||
948 | } | 1201 | } |
949 | 1202 | ||
950 | /// <summary> | 1203 | /// <summary> |
@@ -954,9 +1207,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
954 | /// <param name='finalDestination'></param> | 1207 | /// <param name='finalDestination'></param> |
955 | /// <param name='logout'></param> | 1208 | /// <param name='logout'></param> |
956 | /// <param name='reason'>Human readable reason for teleport failure. Will be sent to client.</param> | 1209 | /// <param name='reason'>Human readable reason for teleport failure. Will be sent to client.</param> |
957 | protected virtual void Fail(ScenePresence sp, GridRegion finalDestination, bool logout, string reason) | 1210 | protected virtual void Fail(ScenePresence sp, GridRegion finalDestination, bool logout, string auth_code, string reason) |
958 | { | 1211 | { |
959 | CleanupFailedInterRegionTeleport(sp, finalDestination); | 1212 | CleanupFailedInterRegionTeleport(sp, auth_code, finalDestination); |
960 | 1213 | ||
961 | m_interRegionTeleportFailures.Value++; | 1214 | m_interRegionTeleportFailures.Value++; |
962 | 1215 | ||
@@ -1132,7 +1385,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1132 | public GridRegion GetDestination(Scene scene, UUID agentID, Vector3 pos, out uint xDest, out uint yDest, out string version, out Vector3 newpos) | 1385 | public GridRegion GetDestination(Scene scene, UUID agentID, Vector3 pos, out uint xDest, out uint yDest, out string version, out Vector3 newpos) |
1133 | { | 1386 | { |
1134 | version = String.Empty; | 1387 | version = String.Empty; |
1135 | newpos = new Vector3(pos.X, pos.Y, pos.Z); | 1388 | newpos = pos; |
1136 | 1389 | ||
1137 | // m_log.DebugFormat( | 1390 | // m_log.DebugFormat( |
1138 | // "[ENTITY TRANSFER MODULE]: Crossing agent {0} at pos {1} in {2}", agent.Name, pos, scene.Name); | 1391 | // "[ENTITY TRANSFER MODULE]: Crossing agent {0} at pos {1} in {2}", agent.Name, pos, scene.Name); |
@@ -1471,11 +1724,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1471 | if (m_eqModule != null) | 1724 | if (m_eqModule != null) |
1472 | { | 1725 | { |
1473 | m_eqModule.CrossRegion( | 1726 | m_eqModule.CrossRegion( |
1474 | neighbourRegion.RegionHandle, pos + agent.Velocity, vel2 /* agent.Velocity */, neighbourRegion.ExternalEndPoint, | 1727 | neighbourRegion.RegionHandle, pos + agent.Velocity, vel2 /* agent.Velocity */, |
1475 | capsPath, agent.UUID, agent.ControllingClient.SessionId); | 1728 | neighbourRegion.ExternalEndPoint, |
1729 | capsPath, agent.UUID, agent.ControllingClient.SessionId, | ||
1730 | neighbourRegion.RegionSizeX, neighbourRegion.RegionSizeY); | ||
1476 | } | 1731 | } |
1477 | else | 1732 | else |
1478 | { | 1733 | { |
1734 | m_log.ErrorFormat("{0} Using old CrossRegion packet. Varregion will not work!!", LogHeader); | ||
1479 | agent.ControllingClient.CrossRegion(neighbourRegion.RegionHandle, pos + agent.Velocity, agent.Velocity, neighbourRegion.ExternalEndPoint, | 1735 | agent.ControllingClient.CrossRegion(neighbourRegion.RegionHandle, pos + agent.Velocity, agent.Velocity, neighbourRegion.ExternalEndPoint, |
1480 | capsPath); | 1736 | capsPath); |
1481 | } | 1737 | } |
@@ -1654,10 +1910,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1654 | List<ulong> newRegions = NewNeighbours(neighbourHandles, previousRegionNeighbourHandles); | 1910 | List<ulong> newRegions = NewNeighbours(neighbourHandles, previousRegionNeighbourHandles); |
1655 | List<ulong> oldRegions = OldNeighbours(neighbourHandles, previousRegionNeighbourHandles); | 1911 | List<ulong> oldRegions = OldNeighbours(neighbourHandles, previousRegionNeighbourHandles); |
1656 | 1912 | ||
1657 | //Dump("Current Neighbors", neighbourHandles); | 1913 | // Dump("Current Neighbors", neighbourHandles); |
1658 | //Dump("Previous Neighbours", previousRegionNeighbourHandles); | 1914 | // Dump("Previous Neighbours", previousRegionNeighbourHandles); |
1659 | //Dump("New Neighbours", newRegions); | 1915 | // Dump("New Neighbours", newRegions); |
1660 | //Dump("Old Neighbours", oldRegions); | 1916 | // Dump("Old Neighbours", oldRegions); |
1661 | 1917 | ||
1662 | /// Update the scene presence's known regions here on this region | 1918 | /// Update the scene presence's known regions here on this region |
1663 | sp.DropOldNeighbours(oldRegions); | 1919 | sp.DropOldNeighbours(oldRegions); |
@@ -1665,8 +1921,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1665 | /// Collect as many seeds as possible | 1921 | /// Collect as many seeds as possible |
1666 | Dictionary<ulong, string> seeds; | 1922 | Dictionary<ulong, string> seeds; |
1667 | if (sp.Scene.CapsModule != null) | 1923 | if (sp.Scene.CapsModule != null) |
1668 | seeds | 1924 | seeds = new Dictionary<ulong, string>(sp.Scene.CapsModule.GetChildrenSeeds(sp.UUID)); |
1669 | = new Dictionary<ulong, string>(sp.Scene.CapsModule.GetChildrenSeeds(sp.UUID)); | ||
1670 | else | 1925 | else |
1671 | seeds = new Dictionary<ulong, string>(); | 1926 | seeds = new Dictionary<ulong, string>(); |
1672 | 1927 | ||
@@ -1736,6 +1991,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1736 | newAgent = true; | 1991 | newAgent = true; |
1737 | else | 1992 | else |
1738 | newAgent = false; | 1993 | newAgent = false; |
1994 | // continue; | ||
1739 | 1995 | ||
1740 | if (neighbour.RegionHandle != sp.Scene.RegionInfo.RegionHandle) | 1996 | if (neighbour.RegionHandle != sp.Scene.RegionInfo.RegionHandle) |
1741 | { | 1997 | { |
@@ -1841,12 +2097,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1841 | } | 2097 | } |
1842 | #endregion | 2098 | #endregion |
1843 | 2099 | ||
1844 | m_log.DebugFormat("[ENTITY TRANSFER MODULE]: {0} is sending {1} EnableSimulator for neighbour region {2} @ {3} " + | 2100 | m_log.DebugFormat("{0} {1} is sending {2} EnableSimulator for neighbour region {3}(loc=<{4},{5}>,siz=<{6},{7}>) " + |
1845 | "and EstablishAgentCommunication with seed cap {4}", | 2101 | "and EstablishAgentCommunication with seed cap {8}", LogHeader, |
1846 | scene.RegionInfo.RegionName, sp.Name, reg.RegionName, reg.RegionHandle, capsPath); | 2102 | scene.RegionInfo.RegionName, sp.Name, |
2103 | reg.RegionName, reg.RegionLocX, reg.RegionLocY, reg.RegionSizeX, reg.RegionSizeY , capsPath); | ||
1847 | 2104 | ||
1848 | m_eqModule.EnableSimulator(reg.RegionHandle, endPoint, sp.UUID); | 2105 | m_eqModule.EnableSimulator(reg.RegionHandle, endPoint, sp.UUID, reg.RegionSizeX, reg.RegionSizeY); |
1849 | m_eqModule.EstablishAgentCommunication(sp.UUID, endPoint, capsPath); | 2106 | m_eqModule.EstablishAgentCommunication(sp.UUID, endPoint, capsPath, reg.RegionHandle, reg.RegionSizeX, reg.RegionSizeY); |
1850 | } | 2107 | } |
1851 | else | 2108 | else |
1852 | { | 2109 | { |
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs index d372c0e..7abdc21 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs | |||
@@ -53,8 +53,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
53 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 53 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
54 | 54 | ||
55 | private int m_levelHGTeleport = 0; | 55 | private int m_levelHGTeleport = 0; |
56 | private string m_ThisHomeURI; | ||
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; |
@@ -143,6 +145,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
143 | m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: {0} enabled.", Name); | 145 | m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: {0} enabled.", Name); |
144 | } | 146 | } |
145 | } | 147 | } |
148 | |||
149 | moduleConfig = source.Configs["Hypergrid"]; | ||
150 | if (moduleConfig != null) | ||
151 | { | ||
152 | m_ThisHomeURI = moduleConfig.GetString("HomeURI", string.Empty); | ||
153 | if (m_ThisHomeURI != string.Empty && !m_ThisHomeURI.EndsWith("/")) | ||
154 | m_ThisHomeURI += '/'; | ||
155 | } | ||
146 | } | 156 | } |
147 | 157 | ||
148 | public override void AddRegion(Scene scene) | 158 | public override void AddRegion(Scene scene) |
@@ -161,22 +171,22 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
161 | if (!so.IsAttachment) | 171 | if (!so.IsAttachment) |
162 | return; | 172 | return; |
163 | 173 | ||
164 | if (so.Scene.UserManagementModule.IsLocalGridUser(so.AttachedAvatar)) | 174 | if (so.AttachedAvatar == UUID.Zero || Scene.UserManagementModule.IsLocalGridUser(so.AttachedAvatar)) |
165 | return; | 175 | return; |
166 | 176 | ||
167 | // foreign user | 177 | // foreign user |
168 | AgentCircuitData aCircuit = so.Scene.AuthenticateHandler.GetAgentCircuitData(so.AttachedAvatar); | 178 | AgentCircuitData aCircuit = Scene.AuthenticateHandler.GetAgentCircuitData(so.AttachedAvatar); |
169 | if (aCircuit != null && (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0) | 179 | if (aCircuit != null && (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0) |
170 | { | 180 | { |
171 | if (aCircuit.ServiceURLs != null && aCircuit.ServiceURLs.ContainsKey("AssetServerURI")) | 181 | if (aCircuit.ServiceURLs != null && aCircuit.ServiceURLs.ContainsKey("AssetServerURI")) |
172 | { | 182 | { |
173 | string url = aCircuit.ServiceURLs["AssetServerURI"].ToString(); | 183 | string url = aCircuit.ServiceURLs["AssetServerURI"].ToString(); |
174 | m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Incoming attachement {0} for HG user {1} with asset server {2}", so.Name, so.AttachedAvatar, url); | 184 | m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Incoming attachment {0} for HG user {1} with asset server {2}", so.Name, so.AttachedAvatar, url); |
175 | Dictionary<UUID, AssetType> ids = new Dictionary<UUID, AssetType>(); | 185 | Dictionary<UUID, sbyte> ids = new Dictionary<UUID, sbyte>(); |
176 | HGUuidGatherer uuidGatherer = new HGUuidGatherer(so.Scene.AssetService, url); | 186 | HGUuidGatherer uuidGatherer = new HGUuidGatherer(Scene.AssetService, url); |
177 | uuidGatherer.GatherAssetUuids(so, ids); | 187 | uuidGatherer.GatherAssetUuids(so, ids); |
178 | 188 | ||
179 | foreach (KeyValuePair<UUID, AssetType> kvp in ids) | 189 | foreach (KeyValuePair<UUID, sbyte> kvp in ids) |
180 | uuidGatherer.FetchAsset(kvp.Key); | 190 | uuidGatherer.FetchAsset(kvp.Key); |
181 | } | 191 | } |
182 | } | 192 | } |
@@ -194,7 +204,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
194 | base.RegionLoaded(scene); | 204 | base.RegionLoaded(scene); |
195 | 205 | ||
196 | if (m_Enabled) | 206 | if (m_Enabled) |
207 | { | ||
197 | m_GatekeeperConnector = new GatekeeperServiceConnector(scene.AssetService); | 208 | m_GatekeeperConnector = new GatekeeperServiceConnector(scene.AssetService); |
209 | m_UAS = scene.RequestModuleInterface<IUserAgentService>(); | ||
210 | if (m_UAS == null) | ||
211 | m_UAS = new UserAgentServiceConnector(m_ThisHomeURI); | ||
212 | |||
213 | } | ||
198 | } | 214 | } |
199 | 215 | ||
200 | public override void RemoveRegion(Scene scene) | 216 | public override void RemoveRegion(Scene scene) |
@@ -272,8 +288,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
272 | if (agentCircuit.ServiceURLs.ContainsKey("HomeURI")) | 288 | if (agentCircuit.ServiceURLs.ContainsKey("HomeURI")) |
273 | { | 289 | { |
274 | string userAgentDriver = agentCircuit.ServiceURLs["HomeURI"].ToString(); | 290 | string userAgentDriver = agentCircuit.ServiceURLs["HomeURI"].ToString(); |
275 | IUserAgentService connector = new UserAgentServiceConnector(userAgentDriver); | 291 | IUserAgentService connector; |
276 | bool success = connector.LoginAgentToGrid(agentCircuit, reg, finalDestination, out reason); | 292 | |
293 | if (userAgentDriver.Equals(m_ThisHomeURI) && m_UAS != null) | ||
294 | connector = m_UAS; | ||
295 | else | ||
296 | connector = new UserAgentServiceConnector(userAgentDriver); | ||
297 | |||
298 | bool success = connector.LoginAgentToGrid(agentCircuit, reg, finalDestination, false, out reason); | ||
277 | logout = success; // flag for later logout from this grid; this is an HG TP | 299 | logout = success; // flag for later logout from this grid; this is an HG TP |
278 | 300 | ||
279 | if (success) | 301 | if (success) |
@@ -552,12 +574,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
552 | if (uMan != null && uMan.IsLocalGridUser(obj.AgentId)) | 574 | if (uMan != null && uMan.IsLocalGridUser(obj.AgentId)) |
553 | { | 575 | { |
554 | // local grid user | 576 | // local grid user |
577 | m_UAS.LogoutAgent(obj.AgentId, obj.SessionId); | ||
555 | return; | 578 | return; |
556 | } | 579 | } |
557 | 580 | ||
558 | AgentCircuitData aCircuit = ((Scene)(obj.Scene)).AuthenticateHandler.GetAgentCircuitData(obj.CircuitCode); | 581 | AgentCircuitData aCircuit = ((Scene)(obj.Scene)).AuthenticateHandler.GetAgentCircuitData(obj.CircuitCode); |
559 | 582 | if (aCircuit != null && aCircuit.ServiceURLs != null && aCircuit.ServiceURLs.ContainsKey("HomeURI")) | |
560 | if (aCircuit.ServiceURLs.ContainsKey("HomeURI")) | ||
561 | { | 583 | { |
562 | string url = aCircuit.ServiceURLs["HomeURI"].ToString(); | 584 | string url = aCircuit.ServiceURLs["HomeURI"].ToString(); |
563 | IUserAgentService security = new UserAgentServiceConnector(url); | 585 | 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..d4fb1ba 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs | |||
@@ -73,6 +73,9 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
73 | 73 | ||
74 | private AssetMetadata FetchMetadata(string url, UUID assetID) | 74 | private AssetMetadata FetchMetadata(string url, UUID assetID) |
75 | { | 75 | { |
76 | if (string.IsNullOrEmpty(url)) | ||
77 | return null; | ||
78 | |||
76 | if (!url.EndsWith("/") && !url.EndsWith("=")) | 79 | if (!url.EndsWith("/") && !url.EndsWith("=")) |
77 | url = url + "/"; | 80 | url = url + "/"; |
78 | 81 | ||
@@ -92,6 +95,9 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
92 | AssetBase asset = m_scene.AssetService.Get(assetID.ToString()); | 95 | AssetBase asset = m_scene.AssetService.Get(assetID.ToString()); |
93 | if (asset == null) | 96 | if (asset == null) |
94 | { | 97 | { |
98 | if (string.IsNullOrEmpty(url)) | ||
99 | return null; | ||
100 | |||
95 | if (!url.EndsWith("/") && !url.EndsWith("=")) | 101 | if (!url.EndsWith("/") && !url.EndsWith("=")) |
96 | url = url + "/"; | 102 | url = url + "/"; |
97 | 103 | ||
@@ -109,6 +115,9 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
109 | 115 | ||
110 | public bool PostAsset(string url, AssetBase asset) | 116 | public bool PostAsset(string url, AssetBase asset) |
111 | { | 117 | { |
118 | if (string.IsNullOrEmpty(url)) | ||
119 | return false; | ||
120 | |||
112 | if (asset != null) | 121 | if (asset != null) |
113 | { | 122 | { |
114 | if (!url.EndsWith("/") && !url.EndsWith("=")) | 123 | if (!url.EndsWith("/") && !url.EndsWith("=")) |
@@ -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); |
@@ -251,9 +260,9 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
251 | 260 | ||
252 | // The act of gathering UUIDs downloads some assets from the remote server | 261 | // The act of gathering UUIDs downloads some assets from the remote server |
253 | // but not all... | 262 | // but not all... |
254 | Dictionary<UUID, AssetType> ids = new Dictionary<UUID, AssetType>(); | 263 | Dictionary<UUID, sbyte> ids = new Dictionary<UUID, sbyte>(); |
255 | HGUuidGatherer uuidGatherer = new HGUuidGatherer(m_scene.AssetService, userAssetURL); | 264 | HGUuidGatherer uuidGatherer = new HGUuidGatherer(m_scene.AssetService, userAssetURL); |
256 | uuidGatherer.GatherAssetUuids(assetID, (AssetType)meta.Type, ids); | 265 | uuidGatherer.GatherAssetUuids(assetID, meta.Type, ids); |
257 | m_log.DebugFormat("[HG ASSET MAPPER]: Preparing to get {0} assets", ids.Count); | 266 | m_log.DebugFormat("[HG ASSET MAPPER]: Preparing to get {0} assets", ids.Count); |
258 | bool success = true; | 267 | bool success = true; |
259 | foreach (UUID uuid in ids.Keys) | 268 | foreach (UUID uuid in ids.Keys) |
@@ -277,9 +286,9 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
277 | AssetBase asset = m_scene.AssetService.Get(assetID.ToString()); | 286 | AssetBase asset = m_scene.AssetService.Get(assetID.ToString()); |
278 | if (asset != null) | 287 | if (asset != null) |
279 | { | 288 | { |
280 | Dictionary<UUID, AssetType> ids = new Dictionary<UUID, AssetType>(); | 289 | Dictionary<UUID, sbyte> ids = new Dictionary<UUID, sbyte>(); |
281 | HGUuidGatherer uuidGatherer = new HGUuidGatherer(m_scene.AssetService, string.Empty); | 290 | HGUuidGatherer uuidGatherer = new HGUuidGatherer(m_scene.AssetService, string.Empty); |
282 | uuidGatherer.GatherAssetUuids(asset.FullID, (AssetType)asset.Type, ids); | 291 | uuidGatherer.GatherAssetUuids(asset.FullID, asset.Type, ids); |
283 | bool success = false; | 292 | bool success = false; |
284 | foreach (UUID uuid in ids.Keys) | 293 | foreach (UUID uuid in ids.Keys) |
285 | { | 294 | { |
diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs index b2b628d..ce7ed26 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs | |||
@@ -62,6 +62,8 @@ 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 | |||
65 | // private bool m_Initialized = false; | 67 | // private bool m_Initialized = false; |
66 | 68 | ||
67 | #region INonSharedRegionModule | 69 | #region INonSharedRegionModule |
@@ -100,6 +102,10 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
100 | } | 102 | } |
101 | else | 103 | else |
102 | m_log.Warn("[HG INVENTORY ACCESS MODULE]: HGInventoryAccessModule configs not found. ProfileServerURI not set!"); | 104 | m_log.Warn("[HG INVENTORY ACCESS MODULE]: HGInventoryAccessModule configs not found. ProfileServerURI not set!"); |
105 | |||
106 | m_bypassPermissions = !Util.GetConfigVarFromSections<bool>(source, "serverside_object_permissions", | ||
107 | new string[] { "Startup", "Permissions" }, true); | ||
108 | |||
103 | } | 109 | } |
104 | } | 110 | } |
105 | } | 111 | } |
@@ -114,6 +120,11 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
114 | scene.EventManager.OnNewInventoryItemUploadComplete += UploadInventoryItem; | 120 | scene.EventManager.OnNewInventoryItemUploadComplete += UploadInventoryItem; |
115 | scene.EventManager.OnTeleportStart += TeleportStart; | 121 | scene.EventManager.OnTeleportStart += TeleportStart; |
116 | scene.EventManager.OnTeleportFail += TeleportFail; | 122 | scene.EventManager.OnTeleportFail += TeleportFail; |
123 | |||
124 | // We're fgoing to enforce some stricter permissions if Outbound is false | ||
125 | scene.Permissions.OnTakeObject += CanTakeObject; | ||
126 | scene.Permissions.OnTakeCopyObject += CanTakeObject; | ||
127 | scene.Permissions.OnTransferUserInventory += OnTransferUserInventory; | ||
117 | } | 128 | } |
118 | 129 | ||
119 | #endregion | 130 | #endregion |
@@ -135,7 +146,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
135 | if (sp is ScenePresence) | 146 | if (sp is ScenePresence) |
136 | { | 147 | { |
137 | AgentCircuitData aCircuit = ((ScenePresence)sp).Scene.AuthenticateHandler.GetAgentCircuitData(client.AgentId); | 148 | AgentCircuitData aCircuit = ((ScenePresence)sp).Scene.AuthenticateHandler.GetAgentCircuitData(client.AgentId); |
138 | if ((aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0) | 149 | if (aCircuit != null && (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0) |
139 | { | 150 | { |
140 | if (m_RestrictInventoryAccessAbroad) | 151 | if (m_RestrictInventoryAccessAbroad) |
141 | { | 152 | { |
@@ -185,8 +196,11 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
185 | } | 196 | } |
186 | } | 197 | } |
187 | 198 | ||
188 | public void UploadInventoryItem(UUID avatarID, UUID assetID, string name, int userlevel) | 199 | public void UploadInventoryItem(UUID avatarID, AssetType type, UUID assetID, string name, int userlevel) |
189 | { | 200 | { |
201 | if (type == AssetType.Link) | ||
202 | return; | ||
203 | |||
190 | string userAssetServer = string.Empty; | 204 | string userAssetServer = string.Empty; |
191 | if (IsForeignUser(avatarID, out userAssetServer) && userAssetServer != string.Empty && m_OutboundPermission) | 205 | if (IsForeignUser(avatarID, out userAssetServer) && userAssetServer != string.Empty && m_OutboundPermission) |
192 | { | 206 | { |
@@ -221,7 +235,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
221 | { | 235 | { |
222 | UUID newAssetID = base.CapsUpdateInventoryItemAsset(remoteClient, itemID, data); | 236 | UUID newAssetID = base.CapsUpdateInventoryItemAsset(remoteClient, itemID, data); |
223 | 237 | ||
224 | UploadInventoryItem(remoteClient.AgentId, newAssetID, "", 0); | 238 | UploadInventoryItem(remoteClient.AgentId, AssetType.Unknown, newAssetID, "", 0); |
225 | 239 | ||
226 | return newAssetID; | 240 | return newAssetID; |
227 | } | 241 | } |
@@ -232,7 +246,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
232 | protected override void ExportAsset(UUID agentID, UUID assetID) | 246 | protected override void ExportAsset(UUID agentID, UUID assetID) |
233 | { | 247 | { |
234 | if (!assetID.Equals(UUID.Zero)) | 248 | if (!assetID.Equals(UUID.Zero)) |
235 | UploadInventoryItem(agentID, assetID, "", 0); | 249 | UploadInventoryItem(agentID, AssetType.Unknown, assetID, "", 0); |
236 | else | 250 | else |
237 | m_log.Debug("[HGScene]: Scene.Inventory did not create asset"); | 251 | m_log.Debug("[HGScene]: Scene.Inventory did not create asset"); |
238 | } | 252 | } |
@@ -244,7 +258,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
244 | UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection, | 258 | UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection, |
245 | bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment) | 259 | bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment) |
246 | { | 260 | { |
247 | m_log.DebugFormat("[HGScene] RezObject itemID={0} fromTaskID={1}", itemID, fromTaskID); | 261 | m_log.DebugFormat("[HGScene]: RezObject itemID={0} fromTaskID={1}", itemID, fromTaskID); |
248 | 262 | ||
249 | //if (fromTaskID.Equals(UUID.Zero)) | 263 | //if (fromTaskID.Equals(UUID.Zero)) |
250 | //{ | 264 | //{ |
@@ -297,7 +311,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
297 | if (m_Scene.TryGetScenePresence(userID, out sp)) | 311 | if (m_Scene.TryGetScenePresence(userID, out sp)) |
298 | { | 312 | { |
299 | AgentCircuitData aCircuit = m_Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode); | 313 | AgentCircuitData aCircuit = m_Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode); |
300 | if (aCircuit.ServiceURLs.ContainsKey("AssetServerURI")) | 314 | if (aCircuit != null && aCircuit.ServiceURLs != null && aCircuit.ServiceURLs.ContainsKey("AssetServerURI")) |
301 | { | 315 | { |
302 | assetServerURL = aCircuit.ServiceURLs["AssetServerURI"].ToString(); | 316 | assetServerURL = aCircuit.ServiceURLs["AssetServerURI"].ToString(); |
303 | assetServerURL = assetServerURL.Trim(new char[] { '/' }); | 317 | assetServerURL = assetServerURL.Trim(new char[] { '/' }); |
@@ -348,7 +362,15 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
348 | InventoryFolderBase root = m_Scene.InventoryService.GetRootFolder(client.AgentId); | 362 | InventoryFolderBase root = m_Scene.InventoryService.GetRootFolder(client.AgentId); |
349 | InventoryCollection content = m_Scene.InventoryService.GetFolderContent(client.AgentId, root.ID); | 363 | InventoryCollection content = m_Scene.InventoryService.GetFolderContent(client.AgentId, root.ID); |
350 | 364 | ||
351 | inv.SendBulkUpdateInventory(content.Folders.ToArray(), content.Items.ToArray()); | 365 | List<InventoryFolderBase> keep = new List<InventoryFolderBase>(); |
366 | |||
367 | foreach (InventoryFolderBase f in content.Folders) | ||
368 | { | ||
369 | if (f.Name != "My Suitcase" && f.Name != "Current Outfit") | ||
370 | keep.Add(f); | ||
371 | } | ||
372 | |||
373 | inv.SendBulkUpdateInventory(keep.ToArray(), content.Items.ToArray()); | ||
352 | } | 374 | } |
353 | } | 375 | } |
354 | } | 376 | } |
@@ -381,7 +403,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
381 | 403 | ||
382 | foreach (InventoryFolderBase f in content.Folders) | 404 | foreach (InventoryFolderBase f in content.Folders) |
383 | { | 405 | { |
384 | if (f.Name != "My Suitcase") | 406 | if (f.Name != "My Suitcase" && f.Name != "Current Outfit") |
385 | { | 407 | { |
386 | f.Name = f.Name + " (Unavailable)"; | 408 | f.Name = f.Name + " (Unavailable)"; |
387 | keep.Add(f); | 409 | keep.Add(f); |
@@ -406,5 +428,36 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
406 | } | 428 | } |
407 | 429 | ||
408 | #endregion | 430 | #endregion |
431 | |||
432 | #region Permissions | ||
433 | |||
434 | private bool CanTakeObject(UUID objectID, UUID stealer, Scene scene) | ||
435 | { | ||
436 | if (m_bypassPermissions) return true; | ||
437 | |||
438 | if (!m_OutboundPermission && !UserManagementModule.IsLocalGridUser(stealer)) | ||
439 | { | ||
440 | SceneObjectGroup sog = null; | ||
441 | if (m_Scene.TryGetSceneObjectGroup(objectID, out sog) && sog.OwnerID == stealer) | ||
442 | return true; | ||
443 | |||
444 | return false; | ||
445 | } | ||
446 | |||
447 | return true; | ||
448 | } | ||
449 | |||
450 | private bool OnTransferUserInventory(UUID itemID, UUID userID, UUID recipientID) | ||
451 | { | ||
452 | if (m_bypassPermissions) return true; | ||
453 | |||
454 | if (!m_OutboundPermission && !UserManagementModule.IsLocalGridUser(recipientID)) | ||
455 | return false; | ||
456 | |||
457 | return true; | ||
458 | } | ||
459 | |||
460 | |||
461 | #endregion | ||
409 | } | 462 | } |
410 | } \ No newline at end of file | 463 | } \ 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 d09ea3e..fadcd5e 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs | |||
@@ -358,7 +358,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
358 | bool asAttachment) | 358 | bool asAttachment) |
359 | { | 359 | { |
360 | CoalescedSceneObjects coa = new CoalescedSceneObjects(UUID.Zero); | 360 | CoalescedSceneObjects coa = new CoalescedSceneObjects(UUID.Zero); |
361 | Dictionary<UUID, Vector3> originalPositions = new Dictionary<UUID, Vector3>(); | 361 | // Dictionary<UUID, Vector3> originalPositions = new Dictionary<UUID, Vector3>(); |
362 | 362 | ||
363 | foreach (SceneObjectGroup objectGroup in objlist) | 363 | foreach (SceneObjectGroup objectGroup in objlist) |
364 | { | 364 | { |
@@ -379,7 +379,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
379 | objectGroup.AbsolutePosition.Z); | 379 | objectGroup.AbsolutePosition.Z); |
380 | 380 | ||
381 | Quaternion inventoryStoredRotation = objectGroup.GroupRotation; | 381 | Quaternion inventoryStoredRotation = objectGroup.GroupRotation; |
382 | originalPositions[objectGroup.UUID] = objectGroup.AbsolutePosition; | 382 | //originalPositions[objectGroup.UUID] = objectGroup.AbsolutePosition; |
383 | 383 | ||
384 | // Restore attachment data after trip through the sim | 384 | // Restore attachment data after trip through the sim |
385 | if (objectGroup.RootPart.AttachPoint > 0) | 385 | if (objectGroup.RootPart.AttachPoint > 0) |
@@ -390,9 +390,13 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
390 | 390 | ||
391 | // Trees could be attached and it's been done, but it makes | 391 | // Trees could be attached and it's been done, but it makes |
392 | // no sense. State must be preserved because it's the tree type | 392 | // no sense. State must be preserved because it's the tree type |
393 | if (objectGroup.RootPart.Shape.PCode != (byte)PCode.Tree && | 393 | if (objectGroup.RootPart.Shape.PCode != (byte) PCode.Tree && |
394 | objectGroup.RootPart.Shape.PCode != (byte)PCode.NewTree) | 394 | objectGroup.RootPart.Shape.PCode != (byte) PCode.NewTree) |
395 | { | ||
395 | objectGroup.RootPart.Shape.State = objectGroup.RootPart.AttachPoint; | 396 | objectGroup.RootPart.Shape.State = objectGroup.RootPart.AttachPoint; |
397 | if (objectGroup.RootPart.AttachPoint > 0) | ||
398 | objectGroup.RootPart.Shape.LastAttachPoint = objectGroup.RootPart.AttachPoint; | ||
399 | } | ||
396 | 400 | ||
397 | objectGroup.AbsolutePosition = inventoryStoredPosition; | 401 | objectGroup.AbsolutePosition = inventoryStoredPosition; |
398 | objectGroup.RootPart.RotationOffset = inventoryStoredRotation; | 402 | objectGroup.RootPart.RotationOffset = inventoryStoredRotation; |
@@ -423,9 +427,9 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
423 | else | 427 | else |
424 | itemXml = SceneObjectSerializer.ToOriginalXmlFormat(objlist[0], !asAttachment); | 428 | itemXml = SceneObjectSerializer.ToOriginalXmlFormat(objlist[0], !asAttachment); |
425 | 429 | ||
426 | // Restore the position of each group now that it has been stored to inventory. | 430 | // // Restore the position of each group now that it has been stored to inventory. |
427 | foreach (SceneObjectGroup objectGroup in objlist) | 431 | // foreach (SceneObjectGroup objectGroup in objlist) |
428 | objectGroup.AbsolutePosition = originalPositions[objectGroup.UUID]; | 432 | // objectGroup.AbsolutePosition = originalPositions[objectGroup.UUID]; |
429 | 433 | ||
430 | InventoryItemBase item = CreateItemForObject(action, remoteClient, objlist[0], folderID); | 434 | InventoryItemBase item = CreateItemForObject(action, remoteClient, objlist[0], folderID); |
431 | 435 | ||
@@ -435,17 +439,28 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
435 | 439 | ||
436 | if (item == null) | 440 | if (item == null) |
437 | return null; | 441 | return null; |
442 | |||
443 | item.CreatorId = objlist[0].RootPart.CreatorID.ToString(); | ||
444 | item.CreatorData = objlist[0].RootPart.CreatorData; | ||
438 | 445 | ||
439 | // Can't know creator is the same, so null it in inventory | ||
440 | if (objlist.Count > 1) | 446 | if (objlist.Count > 1) |
441 | { | 447 | { |
442 | item.CreatorId = UUID.Zero.ToString(); | ||
443 | item.Flags = (uint)InventoryItemFlags.ObjectHasMultipleItems; | 448 | item.Flags = (uint)InventoryItemFlags.ObjectHasMultipleItems; |
449 | |||
450 | // If the objects have different creators then don't specify a creator at all | ||
451 | foreach (SceneObjectGroup objectGroup in objlist) | ||
452 | { | ||
453 | if ((objectGroup.RootPart.CreatorID.ToString() != item.CreatorId) | ||
454 | || (objectGroup.RootPart.CreatorData.ToString() != item.CreatorData)) | ||
455 | { | ||
456 | item.CreatorId = UUID.Zero.ToString(); | ||
457 | item.CreatorData = string.Empty; | ||
458 | break; | ||
459 | } | ||
460 | } | ||
444 | } | 461 | } |
445 | else | 462 | else |
446 | { | 463 | { |
447 | item.CreatorId = objlist[0].RootPart.CreatorID.ToString(); | ||
448 | item.CreatorData = objlist[0].RootPart.CreatorData; | ||
449 | item.SaleType = objlist[0].RootPart.ObjectSaleType; | 464 | item.SaleType = objlist[0].RootPart.ObjectSaleType; |
450 | item.SalePrice = objlist[0].RootPart.SalePrice; | 465 | item.SalePrice = objlist[0].RootPart.SalePrice; |
451 | } | 466 | } |
@@ -466,13 +481,13 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
466 | } | 481 | } |
467 | else | 482 | else |
468 | { | 483 | { |
469 | AddPermissions(item, objlist[0], objlist, remoteClient); | ||
470 | |||
471 | item.CreationDate = Util.UnixTimeSinceEpoch(); | 484 | item.CreationDate = Util.UnixTimeSinceEpoch(); |
472 | item.Description = asset.Description; | 485 | item.Description = asset.Description; |
473 | item.Name = asset.Name; | 486 | item.Name = asset.Name; |
474 | item.AssetType = asset.Type; | 487 | item.AssetType = asset.Type; |
475 | 488 | ||
489 | AddPermissions(item, objlist[0], objlist, remoteClient); | ||
490 | |||
476 | m_Scene.AddInventoryItem(item); | 491 | m_Scene.AddInventoryItem(item); |
477 | 492 | ||
478 | if (remoteClient != null && item.Owner == remoteClient.AgentId) | 493 | if (remoteClient != null && item.Owner == remoteClient.AgentId) |
@@ -527,16 +542,12 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
527 | } | 542 | } |
528 | effectivePerms |= (uint)PermissionMask.Move; | 543 | effectivePerms |= (uint)PermissionMask.Move; |
529 | 544 | ||
545 | //PermissionsUtil.LogPermissions(item.Name, "Before AddPermissions", item.BasePermissions, item.CurrentPermissions, item.NextPermissions); | ||
546 | |||
530 | if (remoteClient != null && (remoteClient.AgentId != so.RootPart.OwnerID) && m_Scene.Permissions.PropagatePermissions()) | 547 | if (remoteClient != null && (remoteClient.AgentId != so.RootPart.OwnerID) && m_Scene.Permissions.PropagatePermissions()) |
531 | { | 548 | { |
532 | uint perms = effectivePerms; | 549 | uint perms = effectivePerms; |
533 | uint nextPerms = (perms & 7) << 13; | 550 | PermissionsUtil.ApplyFoldedPermissions(effectivePerms, ref perms); |
534 | if ((nextPerms & (uint)PermissionMask.Copy) == 0) | ||
535 | perms &= ~(uint)PermissionMask.Copy; | ||
536 | if ((nextPerms & (uint)PermissionMask.Transfer) == 0) | ||
537 | perms &= ~(uint)PermissionMask.Transfer; | ||
538 | if ((nextPerms & (uint)PermissionMask.Modify) == 0) | ||
539 | perms &= ~(uint)PermissionMask.Modify; | ||
540 | 551 | ||
541 | item.BasePermissions = perms & so.RootPart.NextOwnerMask; | 552 | item.BasePermissions = perms & so.RootPart.NextOwnerMask; |
542 | item.CurrentPermissions = item.BasePermissions; | 553 | item.CurrentPermissions = item.BasePermissions; |
@@ -544,10 +555,8 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
544 | item.EveryOnePermissions = so.RootPart.EveryoneMask & so.RootPart.NextOwnerMask; | 555 | item.EveryOnePermissions = so.RootPart.EveryoneMask & so.RootPart.NextOwnerMask; |
545 | item.GroupPermissions = so.RootPart.GroupMask & so.RootPart.NextOwnerMask; | 556 | item.GroupPermissions = so.RootPart.GroupMask & so.RootPart.NextOwnerMask; |
546 | 557 | ||
547 | // Magic number badness. Maybe this deserves an enum. | 558 | // apply next owner perms on rez |
548 | // bit 4 (16) is the "Slam" bit, it means treat as passed | 559 | item.CurrentPermissions |= SceneObjectGroup.SLAM; |
549 | // and apply next owner perms on rez | ||
550 | item.CurrentPermissions |= 16; // Slam! | ||
551 | } | 560 | } |
552 | else | 561 | else |
553 | { | 562 | { |
@@ -564,8 +573,10 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
564 | (uint)PermissionMask.Move | | 573 | (uint)PermissionMask.Move | |
565 | (uint)PermissionMask.Export | | 574 | (uint)PermissionMask.Export | |
566 | 7); // Preserve folded permissions | 575 | 7); // Preserve folded permissions |
567 | } | 576 | } |
568 | 577 | ||
578 | //PermissionsUtil.LogPermissions(item.Name, "After AddPermissions", item.BasePermissions, item.CurrentPermissions, item.NextPermissions); | ||
579 | |||
569 | return item; | 580 | return item; |
570 | } | 581 | } |
571 | 582 | ||
@@ -707,6 +718,12 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
707 | InventoryFolderBase f = new InventoryFolderBase(so.FromFolderID, userID); | 718 | InventoryFolderBase f = new InventoryFolderBase(so.FromFolderID, userID); |
708 | if (f != null) | 719 | if (f != null) |
709 | folder = m_Scene.InventoryService.GetFolder(f); | 720 | folder = m_Scene.InventoryService.GetFolder(f); |
721 | |||
722 | if(folder.Type == 14 || folder.Type == 16) | ||
723 | { | ||
724 | // folder.Type = 6; | ||
725 | folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.Object); | ||
726 | } | ||
710 | } | 727 | } |
711 | } | 728 | } |
712 | 729 | ||
@@ -779,83 +796,29 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
779 | 796 | ||
780 | SceneObjectGroup group = null; | 797 | SceneObjectGroup group = null; |
781 | 798 | ||
782 | string xmlData = Utils.BytesToString(rezAsset.Data); | 799 | List<SceneObjectGroup> objlist; |
783 | List<SceneObjectGroup> objlist = new List<SceneObjectGroup>(); | 800 | List<Vector3> veclist; |
784 | List<Vector3> veclist = new List<Vector3>(); | 801 | Vector3 bbox; |
802 | float offsetHeight; | ||
785 | byte bRayEndIsIntersection = (byte)(RayEndIsIntersection ? 1 : 0); | 803 | byte bRayEndIsIntersection = (byte)(RayEndIsIntersection ? 1 : 0); |
786 | Vector3 pos; | 804 | Vector3 pos; |
787 | 805 | ||
788 | XmlDocument doc = new XmlDocument(); | 806 | bool single = m_Scene.GetObjectsToRez(rezAsset.Data, attachment, out objlist, out veclist, out bbox, out offsetHeight); |
789 | doc.LoadXml(xmlData); | ||
790 | XmlElement e = (XmlElement)doc.SelectSingleNode("/CoalescedObject"); | ||
791 | Vector3 rez_pos; | ||
792 | if (e == null || attachment) // Single | ||
793 | { | ||
794 | SceneObjectGroup g = SceneObjectSerializer.FromOriginalXmlFormat(xmlData); | ||
795 | if (!attachment) | ||
796 | { | ||
797 | g.RootPart.AttachPoint = g.RootPart.Shape.State; | ||
798 | g.RootPart.AttachOffset = g.AbsolutePosition; | ||
799 | g.RootPart.AttachRotation = g.GroupRotation; | ||
800 | if (g.RootPart.Shape.PCode != (byte)PCode.NewTree && | ||
801 | g.RootPart.Shape.PCode != (byte)PCode.Tree) | ||
802 | g.RootPart.Shape.State = 0; | ||
803 | } | ||
804 | 807 | ||
805 | objlist.Add(g); | 808 | if (single) |
806 | veclist.Add(new Vector3(0, 0, 0)); | 809 | { |
807 | |||
808 | float offsetHeight = 0; | ||
809 | pos = m_Scene.GetNewRezLocation( | 810 | pos = m_Scene.GetNewRezLocation( |
810 | RayStart, RayEnd, RayTargetID, Quaternion.Identity, | 811 | RayStart, RayEnd, RayTargetID, Quaternion.Identity, |
811 | BypassRayCast, bRayEndIsIntersection, true, g.GetAxisAlignedBoundingBox(out offsetHeight), false); | 812 | BypassRayCast, bRayEndIsIntersection, true, bbox, false); |
812 | pos.Z += offsetHeight; | 813 | pos.Z += offsetHeight; |
813 | rez_pos = pos; | ||
814 | } | 814 | } |
815 | else | 815 | else |
816 | { | 816 | { |
817 | XmlElement coll = (XmlElement)e; | ||
818 | float bx = Convert.ToSingle(coll.GetAttribute("x")); | ||
819 | float by = Convert.ToSingle(coll.GetAttribute("y")); | ||
820 | float bz = Convert.ToSingle(coll.GetAttribute("z")); | ||
821 | Vector3 bbox = new Vector3(bx, by, bz); | ||
822 | |||
823 | pos = m_Scene.GetNewRezLocation(RayStart, RayEnd, | 817 | pos = m_Scene.GetNewRezLocation(RayStart, RayEnd, |
824 | RayTargetID, Quaternion.Identity, | 818 | RayTargetID, Quaternion.Identity, |
825 | BypassRayCast, bRayEndIsIntersection, true, | 819 | BypassRayCast, bRayEndIsIntersection, true, |
826 | bbox, false); | 820 | bbox, false); |
827 | |||
828 | rez_pos = pos; | ||
829 | |||
830 | pos -= bbox / 2; | 821 | pos -= bbox / 2; |
831 | |||
832 | XmlNodeList groups = e.SelectNodes("SceneObjectGroup"); | ||
833 | foreach (XmlNode n in groups) | ||
834 | { | ||
835 | SceneObjectGroup g = SceneObjectSerializer.FromOriginalXmlFormat(n.OuterXml); | ||
836 | g.RootPart.AttachPoint = g.RootPart.Shape.State; | ||
837 | g.RootPart.AttachOffset = g.AbsolutePosition; | ||
838 | g.RootPart.AttachRotation = g.GroupRotation; | ||
839 | if (g.RootPart.Shape.PCode != (byte)PCode.NewTree && | ||
840 | g.RootPart.Shape.PCode != (byte)PCode.Tree) | ||
841 | g.RootPart.Shape.State = 0; | ||
842 | |||
843 | objlist.Add(g); | ||
844 | XmlElement el = (XmlElement)n; | ||
845 | |||
846 | string rawX = el.GetAttribute("offsetx"); | ||
847 | string rawY = el.GetAttribute("offsety"); | ||
848 | string rawZ = el.GetAttribute("offsetz"); | ||
849 | // | ||
850 | // m_log.DebugFormat( | ||
851 | // "[INVENTORY ACCESS MODULE]: Converting coalesced object {0} offset <{1}, {2}, {3}>", | ||
852 | // g.Name, rawX, rawY, rawZ); | ||
853 | |||
854 | float x = Convert.ToSingle(rawX); | ||
855 | float y = Convert.ToSingle(rawY); | ||
856 | float z = Convert.ToSingle(rawZ); | ||
857 | veclist.Add(new Vector3(x, y, z)); | ||
858 | } | ||
859 | } | 822 | } |
860 | 823 | ||
861 | int primcount = 0; | 824 | int primcount = 0; |
@@ -863,7 +826,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
863 | primcount += g.PrimCount; | 826 | primcount += g.PrimCount; |
864 | 827 | ||
865 | if (!m_Scene.Permissions.CanRezObject( | 828 | if (!m_Scene.Permissions.CanRezObject( |
866 | primcount, remoteClient.AgentId, rez_pos) | 829 | primcount, remoteClient.AgentId, pos) |
867 | && !attachment) | 830 | && !attachment) |
868 | { | 831 | { |
869 | // The client operates in no fail mode. It will | 832 | // The client operates in no fail mode. It will |
@@ -880,7 +843,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
880 | return null; | 843 | return null; |
881 | } | 844 | } |
882 | 845 | ||
883 | if (item != null && !DoPreRezWhenFromItem(remoteClient, item, objlist, rez_pos, attachment)) | 846 | if (item != null && !DoPreRezWhenFromItem(remoteClient, item, objlist, pos, veclist, attachment)) |
884 | return null; | 847 | return null; |
885 | 848 | ||
886 | for (int i = 0; i < objlist.Count; i++) | 849 | for (int i = 0; i < objlist.Count; i++) |
@@ -900,11 +863,23 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
900 | m_log.Debug("[INVENTORY ACCESS MODULE]: Object has UUID.Zero! Position 3"); | 863 | m_log.Debug("[INVENTORY ACCESS MODULE]: Object has UUID.Zero! Position 3"); |
901 | } | 864 | } |
902 | 865 | ||
903 | foreach (SceneObjectPart part in group.Parts) | 866 | // if this was previously an attachment and is now being rezzed, |
867 | // save the old attachment info. | ||
868 | if (group.IsAttachment == false && group.RootPart.Shape.State != 0) | ||
904 | { | 869 | { |
905 | // Make the rezzer the owner, as this is not necessarily set correctly in the serialized asset. | 870 | group.RootPart.AttachedPos = group.AbsolutePosition; |
906 | part.LastOwnerID = part.OwnerID; | 871 | group.RootPart.Shape.LastAttachPoint = (byte)group.AttachmentPoint; |
907 | part.OwnerID = remoteClient.AgentId; | 872 | } |
873 | |||
874 | if (item == null) | ||
875 | { | ||
876 | // Change ownership. Normally this is done in DoPreRezWhenFromItem(), but in this case we must do it here. | ||
877 | foreach (SceneObjectPart part in group.Parts) | ||
878 | { | ||
879 | // Make the rezzer the owner, as this is not necessarily set correctly in the serialized asset. | ||
880 | part.LastOwnerID = part.OwnerID; | ||
881 | part.OwnerID = remoteClient.AgentId; | ||
882 | } | ||
908 | } | 883 | } |
909 | 884 | ||
910 | if (!attachment) | 885 | if (!attachment) |
@@ -979,10 +954,15 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
979 | /// <param name="item"></param> | 954 | /// <param name="item"></param> |
980 | /// <param name="objlist"></param> | 955 | /// <param name="objlist"></param> |
981 | /// <param name="pos"></param> | 956 | /// <param name="pos"></param> |
957 | /// <param name="veclist"> | ||
958 | /// List of vector position adjustments for a coalesced objects. For ordinary objects | ||
959 | /// this list will contain just Vector3.Zero. The order of adjustments must match the order of objlist | ||
960 | /// </param> | ||
982 | /// <param name="isAttachment"></param> | 961 | /// <param name="isAttachment"></param> |
983 | /// <returns>true if we can processed with rezzing, false if we need to abort</returns> | 962 | /// <returns>true if we can processed with rezzing, false if we need to abort</returns> |
984 | private bool DoPreRezWhenFromItem( | 963 | private bool DoPreRezWhenFromItem( |
985 | IClientAPI remoteClient, InventoryItemBase item, List<SceneObjectGroup> objlist, Vector3 pos, bool isAttachment) | 964 | IClientAPI remoteClient, InventoryItemBase item, List<SceneObjectGroup> objlist, |
965 | Vector3 pos, List<Vector3> veclist, bool isAttachment) | ||
986 | { | 966 | { |
987 | UUID fromUserInventoryItemId = UUID.Zero; | 967 | UUID fromUserInventoryItemId = UUID.Zero; |
988 | 968 | ||
@@ -1005,28 +985,29 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
1005 | } | 985 | } |
1006 | } | 986 | } |
1007 | 987 | ||
1008 | int primcount = 0; | 988 | for (int i = 0; i < objlist.Count; i++) |
1009 | foreach (SceneObjectGroup g in objlist) | ||
1010 | primcount += g.PrimCount; | ||
1011 | |||
1012 | if (!m_Scene.Permissions.CanRezObject( | ||
1013 | primcount, remoteClient.AgentId, pos) | ||
1014 | && !isAttachment) | ||
1015 | { | 989 | { |
1016 | // The client operates in no fail mode. It will | 990 | SceneObjectGroup g = objlist[i]; |
1017 | // have already removed the item from the folder | ||
1018 | // if it's no copy. | ||
1019 | // Put it back if it's not an attachment | ||
1020 | // | ||
1021 | if (((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0) && (!isAttachment)) | ||
1022 | remoteClient.SendBulkUpdateInventory(item); | ||
1023 | 991 | ||
1024 | ILandObject land = m_Scene.LandChannel.GetLandObject(pos.X, pos.Y); | 992 | if (!m_Scene.Permissions.CanRezObject( |
1025 | remoteClient.SendAlertMessage(string.Format( | 993 | g.PrimCount, remoteClient.AgentId, pos + veclist[i]) |
1026 | "Can't rez object '{0}' at <{1:F3}, {2:F3}, {3:F3}> on parcel '{4}' in region {5}.", | 994 | && !isAttachment) |
1027 | item.Name, pos.X, pos.Y, pos.Z, land != null ? land.LandData.Name : "Unknown", m_Scene.RegionInfo.RegionName)); | 995 | { |
996 | // The client operates in no fail mode. It will | ||
997 | // have already removed the item from the folder | ||
998 | // if it's no copy. | ||
999 | // Put it back if it's not an attachment | ||
1000 | // | ||
1001 | if (((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0) && (!isAttachment)) | ||
1002 | remoteClient.SendBulkUpdateInventory(item); | ||
1028 | 1003 | ||
1029 | return false; | 1004 | ILandObject land = m_Scene.LandChannel.GetLandObject(pos.X, pos.Y); |
1005 | remoteClient.SendAlertMessage(string.Format( | ||
1006 | "Can't rez object '{0}' at <{1:F3}, {2:F3}, {3:F3}> on parcel '{4}' in region {5}.", | ||
1007 | item.Name, pos.X, pos.Y, pos.Z, land != null ? land.LandData.Name : "Unknown", m_Scene.Name)); | ||
1008 | |||
1009 | return false; | ||
1010 | } | ||
1030 | } | 1011 | } |
1031 | 1012 | ||
1032 | for (int i = 0; i < objlist.Count; i++) | 1013 | for (int i = 0; i < objlist.Count; i++) |
@@ -1107,7 +1088,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
1107 | part.GroupMask = item.GroupPermissions; | 1088 | part.GroupMask = item.GroupPermissions; |
1108 | } | 1089 | } |
1109 | } | 1090 | } |
1110 | 1091 | ||
1111 | rootPart.TrimPermissions(); | 1092 | rootPart.TrimPermissions(); |
1112 | 1093 | ||
1113 | if (isAttachment) | 1094 | if (isAttachment) |
diff --git a/OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs b/OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs index d07cff4..69d7e16 100644 --- a/OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs +++ b/OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs | |||
@@ -176,7 +176,7 @@ namespace OpenSim.Region.CoreModules.Framework.Library | |||
176 | m_log.InfoFormat("[LIBRARY MODULE]: Loading library archive {0} ({1})...", iarFileName, simpleName); | 176 | m_log.InfoFormat("[LIBRARY MODULE]: Loading library archive {0} ({1})...", iarFileName, simpleName); |
177 | simpleName = GetInventoryPathFromName(simpleName); | 177 | simpleName = GetInventoryPathFromName(simpleName); |
178 | 178 | ||
179 | InventoryArchiveReadRequest archread = new InventoryArchiveReadRequest(m_MockScene, uinfo, simpleName, iarFileName, false); | 179 | InventoryArchiveReadRequest archread = new InventoryArchiveReadRequest(m_MockScene.InventoryService, m_MockScene.AssetService, m_MockScene.UserAccountService, uinfo, simpleName, iarFileName, false); |
180 | try | 180 | try |
181 | { | 181 | { |
182 | HashSet<InventoryNodeBase> nodes = archread.Execute(); | 182 | HashSet<InventoryNodeBase> nodes = archread.Execute(); |
@@ -185,7 +185,7 @@ namespace OpenSim.Region.CoreModules.Framework.Library | |||
185 | // didn't find the subfolder with the given name; place it on the top | 185 | // didn't find the subfolder with the given name; place it on the top |
186 | m_log.InfoFormat("[LIBRARY MODULE]: Didn't find {0} in library. Placing archive on the top level", simpleName); | 186 | m_log.InfoFormat("[LIBRARY MODULE]: Didn't find {0} in library. Placing archive on the top level", simpleName); |
187 | archread.Close(); | 187 | archread.Close(); |
188 | archread = new InventoryArchiveReadRequest(m_MockScene, uinfo, "/", iarFileName, false); | 188 | archread = new InventoryArchiveReadRequest(m_MockScene.InventoryService, m_MockScene.AssetService, m_MockScene.UserAccountService, uinfo, "/", iarFileName, false); |
189 | archread.Execute(); | 189 | archread.Execute(); |
190 | } | 190 | } |
191 | 191 | ||
diff --git a/OpenSim/Region/CoreModules/Framework/Search/BasicSearchModule.cs b/OpenSim/Region/CoreModules/Framework/Search/BasicSearchModule.cs new file mode 100644 index 0000000..8838612 --- /dev/null +++ b/OpenSim/Region/CoreModules/Framework/Search/BasicSearchModule.cs | |||
@@ -0,0 +1,197 @@ | |||
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 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.IO; | ||
30 | using System.Reflection; | ||
31 | using System.Threading; | ||
32 | |||
33 | using OpenSim.Framework; | ||
34 | using OpenSim.Framework.Console; | ||
35 | using OpenSim.Framework.Monitoring; | ||
36 | using OpenSim.Region.ClientStack.LindenUDP; | ||
37 | using OpenSim.Region.Framework; | ||
38 | using OpenSim.Region.Framework.Interfaces; | ||
39 | using OpenSim.Region.Framework.Scenes; | ||
40 | using OpenSim.Services.Interfaces; | ||
41 | using OpenSim.Services.Connectors.Hypergrid; | ||
42 | |||
43 | using OpenMetaverse; | ||
44 | using OpenMetaverse.Packets; | ||
45 | using log4net; | ||
46 | using Nini.Config; | ||
47 | using Mono.Addins; | ||
48 | |||
49 | using DirFindFlags = OpenMetaverse.DirectoryManager.DirFindFlags; | ||
50 | |||
51 | namespace 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 | if (((DirFindFlags)queryFlags & DirFindFlags.People) == DirFindFlags.People) | ||
154 | { | ||
155 | if (string.IsNullOrEmpty(queryText)) | ||
156 | remoteClient.SendDirPeopleReply(queryID, new DirPeopleReplyData[0]); | ||
157 | |||
158 | List<UserAccount> accounts = m_Scenes[0].UserAccountService.GetUserAccounts(m_Scenes[0].RegionInfo.ScopeID, queryText); | ||
159 | DirPeopleReplyData[] hits = new DirPeopleReplyData[accounts.Count]; | ||
160 | int i = 0; | ||
161 | foreach (UserAccount acc in accounts) | ||
162 | { | ||
163 | DirPeopleReplyData d = new DirPeopleReplyData(); | ||
164 | d.agentID = acc.PrincipalID; | ||
165 | d.firstName = acc.FirstName; | ||
166 | d.lastName = acc.LastName; | ||
167 | d.online = false; | ||
168 | |||
169 | hits[i++] = d; | ||
170 | } | ||
171 | |||
172 | // TODO: This currently ignores pretty much all the query flags including Mature and sort order | ||
173 | remoteClient.SendDirPeopleReply(queryID, hits); | ||
174 | } | ||
175 | else if (((DirFindFlags)queryFlags & DirFindFlags.Groups) == DirFindFlags.Groups) | ||
176 | { | ||
177 | if (m_GroupsService == null) | ||
178 | { | ||
179 | m_log.Warn("[BASIC SEARCH MODULE]: Groups service is not available. Unable to search groups."); | ||
180 | remoteClient.SendAlertMessage("Groups search is not enabled"); | ||
181 | return; | ||
182 | } | ||
183 | |||
184 | if (string.IsNullOrEmpty(queryText)) | ||
185 | remoteClient.SendDirGroupsReply(queryID, new DirGroupsReplyData[0]); | ||
186 | |||
187 | // TODO: This currently ignores pretty much all the query flags including Mature and sort order | ||
188 | remoteClient.SendDirGroupsReply(queryID, m_GroupsService.FindGroups(remoteClient, queryText).ToArray()); | ||
189 | } | ||
190 | |||
191 | } | ||
192 | |||
193 | #endregion Event Handlers | ||
194 | |||
195 | } | ||
196 | |||
197 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs b/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs new file mode 100644 index 0000000..a70261e --- /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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Reflection; | ||
31 | using System.Threading; | ||
32 | using log4net; | ||
33 | using Mono.Addins; | ||
34 | using Nini.Config; | ||
35 | using OpenMetaverse; | ||
36 | using OpenSim.Framework; | ||
37 | using OpenSim.Region.Framework.Interfaces; | ||
38 | using OpenSim.Framework.Monitoring; | ||
39 | using OpenSim.Region.Framework.Scenes; | ||
40 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; | ||
41 | |||
42 | namespace 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 | //Watchdog.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/UserManagement/HGUserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs index 8ce20e9..245c808 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs | |||
@@ -54,11 +54,11 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement | |||
54 | 54 | ||
55 | public new void Initialise(IConfigSource config) | 55 | public new void Initialise(IConfigSource config) |
56 | { | 56 | { |
57 | string umanmod = config.Configs["Modules"].GetString("UserManagementModule", Name); | 57 | string umanmod = config.Configs["Modules"].GetString("UserManagementModule", null); |
58 | if (umanmod == Name) | 58 | if (umanmod == Name) |
59 | { | 59 | { |
60 | m_Enabled = true; | 60 | m_Enabled = true; |
61 | RegisterConsoleCmds(); | 61 | Init(); |
62 | m_log.DebugFormat("[USER MANAGEMENT MODULE]: {0} is enabled", Name); | 62 | m_log.DebugFormat("[USER MANAGEMENT MODULE]: {0} is enabled", Name); |
63 | } | 63 | } |
64 | } | 64 | } |
@@ -70,7 +70,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement | |||
70 | 70 | ||
71 | #endregion ISharedRegionModule | 71 | #endregion ISharedRegionModule |
72 | 72 | ||
73 | protected override void AddAdditionalUsers(UUID avatarID, string query, List<UserData> users) | 73 | protected override void AddAdditionalUsers(string query, List<UserData> users) |
74 | { | 74 | { |
75 | if (query.Contains("@")) // First.Last@foo.com, maybe? | 75 | if (query.Contains("@")) // First.Last@foo.com, maybe? |
76 | { | 76 | { |
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..9d36aa5 --- /dev/null +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/Tests/HGUserManagementModuleTests.cs | |||
@@ -0,0 +1,76 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using Nini.Config; | ||
30 | using NUnit.Framework; | ||
31 | using OpenMetaverse; | ||
32 | using OpenSim.Framework; | ||
33 | using OpenSim.Region.CoreModules.Framework.UserManagement; | ||
34 | using OpenSim.Tests.Common; | ||
35 | using OpenSim.Tests.Common.Mock; | ||
36 | |||
37 | namespace OpenSim.Region.CoreModules.Framework.UserManagement.Tests | ||
38 | { | ||
39 | [TestFixture] | ||
40 | public class HGUserManagementModuleTests : OpenSimTestCase | ||
41 | { | ||
42 | /// <summary> | ||
43 | /// Test that a new HG agent (i.e. one without a user account) has their name cached in the UMM upon creation. | ||
44 | /// </summary> | ||
45 | [Test] | ||
46 | public void TestCachedUserNameForNewAgent() | ||
47 | { | ||
48 | TestHelpers.InMethod(); | ||
49 | // TestHelpers.EnableLogging(); | ||
50 | |||
51 | HGUserManagementModule hgumm = new HGUserManagementModule(); | ||
52 | UUID userId = TestHelpers.ParseStem("11"); | ||
53 | string firstName = "Fred"; | ||
54 | string lastName = "Astaire"; | ||
55 | string homeUri = "example.com"; | ||
56 | |||
57 | IConfigSource config = new IniConfigSource(); | ||
58 | config.AddConfig("Modules"); | ||
59 | config.Configs["Modules"].Set("UserManagementModule", hgumm.Name); | ||
60 | |||
61 | SceneHelpers sceneHelpers = new SceneHelpers(); | ||
62 | TestScene scene = sceneHelpers.SetupScene(); | ||
63 | SceneHelpers.SetupSceneModules(scene, config, hgumm); | ||
64 | |||
65 | AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId); | ||
66 | acd.firstname = firstName; | ||
67 | acd.lastname = lastName; | ||
68 | acd.ServiceURLs["HomeURI"] = "http://" + homeUri; | ||
69 | |||
70 | SceneHelpers.AddScenePresence(scene, acd); | ||
71 | |||
72 | string name = hgumm.GetUserName(userId); | ||
73 | Assert.That(name, Is.EqualTo(string.Format("{0}.{1} @{2}", firstName, lastName, homeUri))); | ||
74 | } | ||
75 | } | ||
76 | } \ 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..3fb5195 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs | |||
@@ -28,9 +28,11 @@ using System; | |||
28 | using System.Collections.Generic; | 28 | using System.Collections.Generic; |
29 | using System.IO; | 29 | using System.IO; |
30 | using System.Reflection; | 30 | using System.Reflection; |
31 | using System.Threading; | ||
31 | 32 | ||
32 | using OpenSim.Framework; | 33 | using OpenSim.Framework; |
33 | using OpenSim.Framework.Console; | 34 | using OpenSim.Framework.Console; |
35 | using OpenSim.Framework.Monitoring; | ||
34 | using OpenSim.Region.ClientStack.LindenUDP; | 36 | using OpenSim.Region.ClientStack.LindenUDP; |
35 | using OpenSim.Region.Framework; | 37 | using OpenSim.Region.Framework; |
36 | using OpenSim.Region.Framework.Interfaces; | 38 | using OpenSim.Region.Framework.Interfaces; |
@@ -44,25 +46,19 @@ using log4net; | |||
44 | using Nini.Config; | 46 | using Nini.Config; |
45 | using Mono.Addins; | 47 | using Mono.Addins; |
46 | 48 | ||
49 | using DirFindFlags = OpenMetaverse.DirectoryManager.DirFindFlags; | ||
50 | |||
47 | namespace OpenSim.Region.CoreModules.Framework.UserManagement | 51 | namespace 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 | ||
@@ -74,7 +70,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement | |||
74 | if (umanmod == Name) | 70 | if (umanmod == Name) |
75 | { | 71 | { |
76 | m_Enabled = true; | 72 | m_Enabled = true; |
77 | RegisterConsoleCmds(); | 73 | Init(); |
78 | m_log.DebugFormat("[USER MANAGEMENT MODULE]: {0} is enabled", Name); | 74 | m_log.DebugFormat("[USER MANAGEMENT MODULE]: {0} is enabled", Name); |
79 | } | 75 | } |
80 | } | 76 | } |
@@ -101,6 +97,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement | |||
101 | m_Scenes.Add(scene); | 97 | m_Scenes.Add(scene); |
102 | 98 | ||
103 | scene.RegisterModuleInterface<IUserManagement>(this); | 99 | scene.RegisterModuleInterface<IUserManagement>(this); |
100 | scene.RegisterModuleInterface<IPeople>(this); | ||
104 | scene.EventManager.OnNewClient += new EventManager.OnNewClientDelegate(EventManager_OnNewClient); | 101 | scene.EventManager.OnNewClient += new EventManager.OnNewClientDelegate(EventManager_OnNewClient); |
105 | scene.EventManager.OnPrimsLoaded += new EventManager.PrimsLoaded(EventManager_OnPrimsLoaded); | 102 | scene.EventManager.OnPrimsLoaded += new EventManager.PrimsLoaded(EventManager_OnPrimsLoaded); |
106 | } | 103 | } |
@@ -117,6 +114,8 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement | |||
117 | 114 | ||
118 | public void RegionLoaded(Scene s) | 115 | public void RegionLoaded(Scene s) |
119 | { | 116 | { |
117 | if (m_Enabled && m_ServiceThrottle == null) | ||
118 | m_ServiceThrottle = s.RequestModuleInterface<IServiceThrottleModule>(); | ||
120 | } | 119 | } |
121 | 120 | ||
122 | public void PostInitialise() | 121 | public void PostInitialise() |
@@ -143,7 +142,6 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement | |||
143 | s.ForEachSOG(delegate(SceneObjectGroup sog) { CacheCreators(sog); }); | 142 | s.ForEachSOG(delegate(SceneObjectGroup sog) { CacheCreators(sog); }); |
144 | } | 143 | } |
145 | 144 | ||
146 | |||
147 | void EventManager_OnNewClient(IClientAPI client) | 145 | void EventManager_OnNewClient(IClientAPI client) |
148 | { | 146 | { |
149 | client.OnConnectionClosed += new Action<IClientAPI>(HandleConnectionClosed); | 147 | client.OnConnectionClosed += new Action<IClientAPI>(HandleConnectionClosed); |
@@ -157,21 +155,43 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement | |||
157 | client.OnAvatarPickerRequest -= new AvatarPickerRequest(HandleAvatarPickerRequest); | 155 | client.OnAvatarPickerRequest -= new AvatarPickerRequest(HandleAvatarPickerRequest); |
158 | } | 156 | } |
159 | 157 | ||
160 | void HandleUUIDNameRequest(UUID uuid, IClientAPI remote_client) | 158 | void HandleUUIDNameRequest(UUID uuid, IClientAPI client) |
161 | { | 159 | { |
160 | // m_log.DebugFormat( | ||
161 | // "[USER MANAGEMENT MODULE]: Handling request for name binding of UUID {0} from {1}", | ||
162 | // uuid, remote_client.Name); | ||
163 | |||
162 | if (m_Scenes[0].LibraryService != null && (m_Scenes[0].LibraryService.LibraryRootFolder.Owner == uuid)) | 164 | if (m_Scenes[0].LibraryService != null && (m_Scenes[0].LibraryService.LibraryRootFolder.Owner == uuid)) |
163 | { | 165 | { |
164 | remote_client.SendNameReply(uuid, "Mr", "OpenSim"); | 166 | client.SendNameReply(uuid, "Mr", "OpenSim"); |
165 | } | 167 | } |
166 | else | 168 | else |
167 | { | 169 | { |
168 | string[] names = GetUserNames(uuid); | 170 | string[] names = new string[2]; |
169 | if (names.Length == 2) | 171 | if (TryGetUserNamesFromCache(uuid, names)) |
170 | { | 172 | { |
171 | //m_log.DebugFormat("[XXX] HandleUUIDNameRequest {0} is {1} {2}", uuid, names[0], names[1]); | 173 | client.SendNameReply(uuid, names[0], names[1]); |
172 | remote_client.SendNameReply(uuid, names[0], names[1]); | 174 | return; |
173 | } | 175 | } |
174 | 176 | ||
177 | // Not found in cache, queue continuation | ||
178 | m_ServiceThrottle.Enqueue("name", uuid.ToString(), delegate | ||
179 | { | ||
180 | //m_log.DebugFormat("[YYY]: Name request {0}", uuid); | ||
181 | |||
182 | // As least upto September 2013, clients permanently cache UUID -> Name bindings. Some clients | ||
183 | // appear to clear this when the user asks it to clear the cache, but others may not. | ||
184 | // | ||
185 | // So to avoid clients | ||
186 | // (particularly Hypergrid clients) permanently binding "Unknown User" to a given UUID, we will | ||
187 | // instead drop the request entirely. | ||
188 | if (TryGetUserNames(uuid, names)) | ||
189 | client.SendNameReply(uuid, names[0], names[1]); | ||
190 | // else | ||
191 | // m_log.DebugFormat( | ||
192 | // "[USER MANAGEMENT MODULE]: No bound name for {0} found, ignoring request from {1}", | ||
193 | // uuid, client.Name); | ||
194 | }); | ||
175 | } | 195 | } |
176 | } | 196 | } |
177 | 197 | ||
@@ -181,29 +201,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement | |||
181 | 201 | ||
182 | m_log.DebugFormat("[USER MANAGEMENT MODULE]: HandleAvatarPickerRequest for {0}", query); | 202 | m_log.DebugFormat("[USER MANAGEMENT MODULE]: HandleAvatarPickerRequest for {0}", query); |
183 | 203 | ||
184 | // searhc the user accounts service | 204 | 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 | 205 | ||
208 | AvatarPickerReplyPacket replyPacket = (AvatarPickerReplyPacket)PacketPool.Instance.GetPacket(PacketType.AvatarPickerReply); | 206 | AvatarPickerReplyPacket replyPacket = (AvatarPickerReplyPacket)PacketPool.Instance.GetPacket(PacketType.AvatarPickerReply); |
209 | // TODO: don't create new blocks if recycling an old packet | 207 | // TODO: don't create new blocks if recycling an old packet |
@@ -249,12 +247,51 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement | |||
249 | client.SendAvatarPickerReply(agent_data, data_args); | 247 | client.SendAvatarPickerReply(agent_data, data_args); |
250 | } | 248 | } |
251 | 249 | ||
252 | protected virtual void AddAdditionalUsers(UUID avatarID, string query, List<UserData> users) | 250 | protected virtual void AddAdditionalUsers(string query, List<UserData> users) |
253 | { | 251 | { |
254 | } | 252 | } |
255 | 253 | ||
256 | #endregion Event Handlers | 254 | #endregion Event Handlers |
257 | 255 | ||
256 | #region IPeople | ||
257 | |||
258 | public List<UserData> GetUserData(string query, int page_size, int page_number) | ||
259 | { | ||
260 | // search the user accounts service | ||
261 | List<UserAccount> accs = m_Scenes[0].UserAccountService.GetUserAccounts(m_Scenes[0].RegionInfo.ScopeID, query); | ||
262 | |||
263 | List<UserData> users = new List<UserData>(); | ||
264 | if (accs != null) | ||
265 | { | ||
266 | foreach (UserAccount acc in accs) | ||
267 | { | ||
268 | UserData ud = new UserData(); | ||
269 | ud.FirstName = acc.FirstName; | ||
270 | ud.LastName = acc.LastName; | ||
271 | ud.Id = acc.PrincipalID; | ||
272 | users.Add(ud); | ||
273 | } | ||
274 | } | ||
275 | |||
276 | // search the local cache | ||
277 | lock (m_UserCache) | ||
278 | { | ||
279 | foreach (UserData data in m_UserCache.Values) | ||
280 | { | ||
281 | if (users.Find(delegate(UserData d) { return d.Id == data.Id; }) == null && | ||
282 | (data.FirstName.ToLower().StartsWith(query.ToLower()) || data.LastName.ToLower().StartsWith(query.ToLower()))) | ||
283 | users.Add(data); | ||
284 | } | ||
285 | } | ||
286 | |||
287 | AddAdditionalUsers(query, users); | ||
288 | |||
289 | return users; | ||
290 | |||
291 | } | ||
292 | |||
293 | #endregion IPeople | ||
294 | |||
258 | private void CacheCreators(SceneObjectGroup sog) | 295 | private void CacheCreators(SceneObjectGroup sog) |
259 | { | 296 | { |
260 | //m_log.DebugFormat("[USER MANAGEMENT MODULE]: processing {0} {1}; {2}", sog.RootPart.Name, sog.RootPart.CreatorData, sog.RootPart.CreatorIdentification); | 297 | //m_log.DebugFormat("[USER MANAGEMENT MODULE]: processing {0} {1}; {2}", sog.RootPart.Name, sog.RootPart.CreatorData, sog.RootPart.CreatorIdentification); |
@@ -268,26 +305,56 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement | |||
268 | } | 305 | } |
269 | } | 306 | } |
270 | 307 | ||
271 | private string[] GetUserNames(UUID uuid) | 308 | /// <summary> |
309 | /// | ||
310 | /// </summary> | ||
311 | /// <param name="uuid"></param> | ||
312 | /// <param name="names">Caller please provide a properly instantiated array for names, string[2]</param> | ||
313 | /// <returns></returns> | ||
314 | private bool TryGetUserNames(UUID uuid, string[] names) | ||
272 | { | 315 | { |
273 | string[] returnstring = new string[2]; | 316 | if (names == null) |
317 | names = new string[2]; | ||
318 | |||
319 | if (TryGetUserNamesFromCache(uuid, names)) | ||
320 | return true; | ||
321 | |||
322 | if (TryGetUserNamesFromServices(uuid, names)) | ||
323 | return true; | ||
324 | |||
325 | return false; | ||
326 | } | ||
274 | 327 | ||
328 | private bool TryGetUserNamesFromCache(UUID uuid, string[] names) | ||
329 | { | ||
275 | lock (m_UserCache) | 330 | lock (m_UserCache) |
276 | { | 331 | { |
277 | if (m_UserCache.ContainsKey(uuid)) | 332 | if (m_UserCache.ContainsKey(uuid)) |
278 | { | 333 | { |
279 | returnstring[0] = m_UserCache[uuid].FirstName; | 334 | names[0] = m_UserCache[uuid].FirstName; |
280 | returnstring[1] = m_UserCache[uuid].LastName; | 335 | names[1] = m_UserCache[uuid].LastName; |
281 | return returnstring; | 336 | |
337 | return true; | ||
282 | } | 338 | } |
283 | } | 339 | } |
284 | 340 | ||
341 | return false; | ||
342 | } | ||
343 | |||
344 | /// <summary> | ||
345 | /// Try to get the names bound to the given uuid, from the services. | ||
346 | /// </summary> | ||
347 | /// <returns>True if the name was found, false if not.</returns> | ||
348 | /// <param name='uuid'></param> | ||
349 | /// <param name='names'>The array of names if found. If not found, then names[0] = "Unknown" and names[1] = "User"</param> | ||
350 | private bool TryGetUserNamesFromServices(UUID uuid, string[] names) | ||
351 | { | ||
285 | UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(UUID.Zero, uuid); | 352 | UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(UUID.Zero, uuid); |
286 | 353 | ||
287 | if (account != null) | 354 | if (account != null) |
288 | { | 355 | { |
289 | returnstring[0] = account.FirstName; | 356 | names[0] = account.FirstName; |
290 | returnstring[1] = account.LastName; | 357 | names[1] = account.LastName; |
291 | 358 | ||
292 | UserData user = new UserData(); | 359 | UserData user = new UserData(); |
293 | user.FirstName = account.FirstName; | 360 | user.FirstName = account.FirstName; |
@@ -295,14 +362,42 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement | |||
295 | 362 | ||
296 | lock (m_UserCache) | 363 | lock (m_UserCache) |
297 | m_UserCache[uuid] = user; | 364 | m_UserCache[uuid] = user; |
365 | |||
366 | return true; | ||
298 | } | 367 | } |
299 | else | 368 | else |
300 | { | 369 | { |
301 | returnstring[0] = "Unknown"; | 370 | // Let's try the GridUser service |
302 | returnstring[1] = "User"; | 371 | GridUserInfo uInfo = m_Scenes[0].GridUserService.GetGridUserInfo(uuid.ToString()); |
303 | } | 372 | if (uInfo != null) |
373 | { | ||
374 | string url, first, last, tmp; | ||
375 | UUID u; | ||
376 | if (Util.ParseUniversalUserIdentifier(uInfo.UserID, out u, out url, out first, out last, out tmp)) | ||
377 | { | ||
378 | AddUser(uuid, first, last, url); | ||
379 | |||
380 | if (m_UserCache.ContainsKey(uuid)) | ||
381 | { | ||
382 | names[0] = m_UserCache[uuid].FirstName; | ||
383 | names[1] = m_UserCache[uuid].LastName; | ||
384 | |||
385 | return true; | ||
386 | } | ||
387 | } | ||
388 | else | ||
389 | m_log.DebugFormat("[USER MANAGEMENT MODULE]: Unable to parse UUI {0}", uInfo.UserID); | ||
390 | } | ||
391 | else | ||
392 | { | ||
393 | m_log.DebugFormat("[USER MANAGEMENT MODULE]: No grid user found for {0}", uuid); | ||
394 | } | ||
304 | 395 | ||
305 | return returnstring; | 396 | names[0] = "Unknown"; |
397 | names[1] = "UserUMMTGUN9"; | ||
398 | |||
399 | return false; | ||
400 | } | ||
306 | } | 401 | } |
307 | 402 | ||
308 | #region IUserManagement | 403 | #region IUserManagement |
@@ -338,16 +433,11 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement | |||
338 | 433 | ||
339 | public string GetUserName(UUID uuid) | 434 | public string GetUserName(UUID uuid) |
340 | { | 435 | { |
341 | string[] names = GetUserNames(uuid); | 436 | string[] names = new string[2]; |
342 | if (names.Length == 2) | 437 | TryGetUserNames(uuid, names); |
343 | { | ||
344 | string firstname = names[0]; | ||
345 | string lastname = names[1]; | ||
346 | 438 | ||
347 | return firstname + " " + lastname; | 439 | return names[0] + " " + names[1]; |
348 | 440 | ||
349 | } | ||
350 | return "(hippos)"; | ||
351 | } | 441 | } |
352 | 442 | ||
353 | public string GetUserHomeURL(UUID userID) | 443 | public string GetUserHomeURL(UUID userID) |
@@ -376,7 +466,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement | |||
376 | return userdata.ServerURLs[serverType].ToString(); | 466 | return userdata.ServerURLs[serverType].ToString(); |
377 | } | 467 | } |
378 | 468 | ||
379 | if (userdata.HomeURL != null && userdata.HomeURL != string.Empty) | 469 | if (!string.IsNullOrEmpty(userdata.HomeURL)) |
380 | { | 470 | { |
381 | //m_log.DebugFormat( | 471 | //m_log.DebugFormat( |
382 | // "[USER MANAGEMENT MODULE]: Did not find url type {0} so requesting urls from '{1}' for {2}", | 472 | // "[USER MANAGEMENT MODULE]: Did not find url type {0} so requesting urls from '{1}' for {2}", |
@@ -394,14 +484,20 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement | |||
394 | 484 | ||
395 | public string GetUserUUI(UUID userID) | 485 | public string GetUserUUI(UUID userID) |
396 | { | 486 | { |
397 | UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, userID); | ||
398 | if (account != null) | ||
399 | return userID.ToString(); | ||
400 | |||
401 | UserData ud; | 487 | UserData ud; |
402 | lock (m_UserCache) | 488 | lock (m_UserCache) |
403 | m_UserCache.TryGetValue(userID, out ud); | 489 | m_UserCache.TryGetValue(userID, out ud); |
404 | 490 | ||
491 | if (ud == null) // It's not in the cache | ||
492 | { | ||
493 | string[] names = new string[2]; | ||
494 | // This will pull the data from either UserAccounts or GridUser | ||
495 | // and stick it into the cache | ||
496 | TryGetUserNamesFromServices(userID, names); | ||
497 | lock (m_UserCache) | ||
498 | m_UserCache.TryGetValue(userID, out ud); | ||
499 | } | ||
500 | |||
405 | if (ud != null) | 501 | if (ud != null) |
406 | { | 502 | { |
407 | string homeURL = ud.HomeURL; | 503 | string homeURL = ud.HomeURL; |
@@ -446,77 +542,81 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement | |||
446 | AddUser(uuid, homeURL + ";" + first + " " + last); | 542 | AddUser(uuid, homeURL + ";" + first + " " + last); |
447 | } | 543 | } |
448 | 544 | ||
449 | public void AddUser (UUID id, string creatorData) | 545 | public void AddUser(UUID id, string creatorData) |
450 | { | 546 | { |
451 | //m_log.DebugFormat("[USER MANAGEMENT MODULE]: Adding user with id {0}, creatorData {1}", id, creatorData); | 547 | //m_log.DebugFormat("[USER MANAGEMENT MODULE]: Adding user with id {0}, creatorData {1}", id, creatorData); |
452 | 548 | ||
453 | UserData oldUser; | 549 | UserData oldUser; |
454 | //lock the whole block - prevent concurrent update | ||
455 | lock (m_UserCache) | 550 | lock (m_UserCache) |
551 | m_UserCache.TryGetValue(id, out oldUser); | ||
552 | |||
553 | if (oldUser != null) | ||
456 | { | 554 | { |
457 | m_UserCache.TryGetValue (id, out oldUser); | 555 | if (string.IsNullOrEmpty(creatorData)) |
458 | if (oldUser != null) | ||
459 | { | 556 | { |
460 | if (creatorData == null || creatorData == String.Empty) | 557 | //ignore updates without creator data |
461 | { | 558 | return; |
462 | //ignore updates without creator data | ||
463 | return; | ||
464 | } | ||
465 | //try update unknown users | ||
466 | //and creator's home URL's | ||
467 | if ((oldUser.FirstName == "Unknown" && !creatorData.Contains ("Unknown")) || (oldUser.HomeURL != null && !creatorData.StartsWith (oldUser.HomeURL))) | ||
468 | { | ||
469 | m_UserCache.Remove (id); | ||
470 | // m_log.DebugFormat("[USER MANAGEMENT MODULE]: Re-adding user with id {0}, creatorData [{1}] and old HomeURL {2}", id, creatorData,oldUser.HomeURL); | ||
471 | } | ||
472 | else | ||
473 | { | ||
474 | //we have already a valid user within the cache | ||
475 | return; | ||
476 | } | ||
477 | } | 559 | } |
478 | 560 | ||
479 | UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount (m_Scenes [0].RegionInfo.ScopeID, id); | 561 | //try update unknown users, but don't update anyone else |
480 | 562 | if (oldUser.FirstName == "Unknown" && !creatorData.Contains("Unknown")) | |
481 | if (account != null) | ||
482 | { | 563 | { |
483 | AddUser (id, account.FirstName, account.LastName); | 564 | lock (m_UserCache) |
565 | m_UserCache.Remove(id); | ||
566 | m_log.DebugFormat("[USER MANAGEMENT MODULE]: Re-adding user with id {0}, creatorData [{1}] and old HomeURL {2}", id, creatorData, oldUser.HomeURL); | ||
484 | } | 567 | } |
485 | else | 568 | else |
486 | { | 569 | { |
487 | UserData user = new UserData (); | 570 | //we have already a valid user within the cache |
488 | user.Id = id; | 571 | return; |
572 | } | ||
573 | } | ||
489 | 574 | ||
490 | if (creatorData != null && creatorData != string.Empty) | 575 | UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, id); |
491 | { | ||
492 | //creatorData = <endpoint>;<name> | ||
493 | 576 | ||
494 | string[] parts = creatorData.Split (';'); | 577 | if (account != null) |
495 | if (parts.Length >= 1) | 578 | { |
579 | AddUser(id, account.FirstName, account.LastName); | ||
580 | } | ||
581 | else | ||
582 | { | ||
583 | UserData user = new UserData(); | ||
584 | user.Id = id; | ||
585 | |||
586 | if (!string.IsNullOrEmpty(creatorData)) | ||
587 | { | ||
588 | //creatorData = <endpoint>;<name> | ||
589 | |||
590 | string[] parts = creatorData.Split(';'); | ||
591 | if (parts.Length >= 1) | ||
592 | { | ||
593 | user.HomeURL = parts[0]; | ||
594 | try | ||
496 | { | 595 | { |
497 | user.HomeURL = parts [0]; | 596 | Uri uri = new Uri(parts[0]); |
498 | try | 597 | user.LastName = "@" + uri.Authority; |
499 | { | 598 | } |
500 | Uri uri = new Uri (parts [0]); | 599 | catch (UriFormatException) |
501 | user.LastName = "@" + uri.Authority; | 600 | { |
502 | } | 601 | m_log.DebugFormat("[SCENE]: Unable to parse Uri {0}", parts[0]); |
503 | catch (UriFormatException) | 602 | user.LastName = "@unknown"; |
504 | { | ||
505 | m_log.DebugFormat ("[SCENE]: Unable to parse Uri {0}", parts [0]); | ||
506 | user.LastName = "@unknown"; | ||
507 | } | ||
508 | } | 603 | } |
509 | if (parts.Length >= 2) | ||
510 | user.FirstName = parts [1].Replace (' ', '.'); | ||
511 | } | ||
512 | else | ||
513 | { | ||
514 | user.FirstName = "Unknown"; | ||
515 | user.LastName = "User"; | ||
516 | } | 604 | } |
517 | 605 | ||
518 | AddUserInternal (user); | 606 | if (parts.Length >= 2) |
607 | user.FirstName = parts[1].Replace(' ', '.'); | ||
608 | } | ||
609 | else | ||
610 | { | ||
611 | // Temporarily add unknown user entries of this type into the cache so that we can distinguish | ||
612 | // this source from other recent (hopefully resolved) bugs that fail to retrieve a user name binding | ||
613 | // TODO: Can be removed when GUN* unknown users have definitely dropped significantly or | ||
614 | // disappeared. | ||
615 | user.FirstName = "Unknown"; | ||
616 | user.LastName = "UserUMMAU4"; | ||
519 | } | 617 | } |
618 | |||
619 | AddUserInternal(user); | ||
520 | } | 620 | } |
521 | } | 621 | } |
522 | 622 | ||
@@ -541,9 +641,22 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement | |||
541 | 641 | ||
542 | #endregion IUserManagement | 642 | #endregion IUserManagement |
543 | 643 | ||
644 | protected void Init() | ||
645 | { | ||
646 | AddUser(UUID.Zero, "Unknown", "User"); | ||
647 | RegisterConsoleCmds(); | ||
648 | } | ||
649 | |||
544 | protected void RegisterConsoleCmds() | 650 | protected void RegisterConsoleCmds() |
545 | { | 651 | { |
546 | MainConsole.Instance.Commands.AddCommand("Users", true, | 652 | MainConsole.Instance.Commands.AddCommand("Users", true, |
653 | "show name", | ||
654 | "show name <uuid>", | ||
655 | "Show the bindings between a single user UUID and a user name", | ||
656 | String.Empty, | ||
657 | HandleShowUser); | ||
658 | |||
659 | MainConsole.Instance.Commands.AddCommand("Users", true, | ||
547 | "show names", | 660 | "show names", |
548 | "show names", | 661 | "show names", |
549 | "Show the bindings between user UUIDs and user names", | 662 | "Show the bindings between user UUIDs and user names", |
@@ -551,26 +664,56 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement | |||
551 | HandleShowUsers); | 664 | HandleShowUsers); |
552 | } | 665 | } |
553 | 666 | ||
554 | private void HandleShowUsers(string module, string[] cmd) | 667 | private void HandleShowUser(string module, string[] cmd) |
555 | { | 668 | { |
669 | if (cmd.Length < 3) | ||
670 | { | ||
671 | MainConsole.Instance.OutputFormat("Usage: show name <uuid>"); | ||
672 | return; | ||
673 | } | ||
674 | |||
675 | UUID userId; | ||
676 | if (!ConsoleUtil.TryParseConsoleUuid(MainConsole.Instance, cmd[2], out userId)) | ||
677 | return; | ||
678 | |||
679 | string[] names; | ||
680 | |||
681 | UserData ud; | ||
682 | |||
556 | lock (m_UserCache) | 683 | lock (m_UserCache) |
557 | { | 684 | { |
558 | if (m_UserCache.Count == 0) | 685 | if (!m_UserCache.TryGetValue(userId, out ud)) |
559 | { | 686 | { |
560 | MainConsole.Instance.Output("No users found"); | 687 | MainConsole.Instance.OutputFormat("No name known for user with id {0}", userId); |
561 | return; | 688 | return; |
562 | } | 689 | } |
563 | 690 | } | |
564 | MainConsole.Instance.Output("UUID User Name"); | 691 | |
565 | MainConsole.Instance.Output("-----------------------------------------------------------------------------"); | 692 | ConsoleDisplayTable cdt = new ConsoleDisplayTable(); |
693 | cdt.AddColumn("UUID", 36); | ||
694 | cdt.AddColumn("Name", 30); | ||
695 | cdt.AddColumn("HomeURL", 40); | ||
696 | cdt.AddRow(userId, string.Format("{0} {1}", ud.FirstName, ud.LastName), ud.HomeURL); | ||
697 | |||
698 | MainConsole.Instance.Output(cdt.ToString()); | ||
699 | } | ||
700 | |||
701 | private void HandleShowUsers(string module, string[] cmd) | ||
702 | { | ||
703 | ConsoleDisplayTable cdt = new ConsoleDisplayTable(); | ||
704 | cdt.AddColumn("UUID", 36); | ||
705 | cdt.AddColumn("Name", 30); | ||
706 | cdt.AddColumn("HomeURL", 40); | ||
707 | |||
708 | lock (m_UserCache) | ||
709 | { | ||
566 | foreach (KeyValuePair<UUID, UserData> kvp in m_UserCache) | 710 | foreach (KeyValuePair<UUID, UserData> kvp in m_UserCache) |
567 | { | 711 | cdt.AddRow(kvp.Key, string.Format("{0} {1}", kvp.Value.FirstName, kvp.Value.LastName), kvp.Value.HomeURL); |
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; | ||
573 | } | 712 | } |
713 | |||
714 | MainConsole.Instance.Output(cdt.ToString()); | ||
574 | } | 715 | } |
716 | |||
575 | } | 717 | } |
718 | |||
576 | } \ No newline at end of file | 719 | } \ No newline at end of file |