aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/OptionalModules
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/OptionalModules')
-rw-r--r--OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs37
-rw-r--r--OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCServer.cs2
-rw-r--r--OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs219
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Appearance/AppearanceInfoModule.cs196
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Attachments/AttachmentsCommandModule.cs17
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Attachments/TempAttachmentsModule.cs5
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Chat/ChannelState.cs160
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Chat/IRCBridgeModule.cs41
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Chat/IRCConnector.cs303
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Chat/RegionState.cs98
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeModule.cs6
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/SitStand/SitStandCommandsModule.cs220
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs41
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs75
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsMessagingModule.cs289
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs272
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/SimianGroupsServicesConnectorModule.cs6
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/Tests/GroupsModuleTests.cs214
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/XmlRpcGroupsServicesConnectorModule.cs71
-rw-r--r--OpenSim/Region/OptionalModules/DataSnapshot/DataRequestHandler.cs99
-rw-r--r--OpenSim/Region/OptionalModules/DataSnapshot/DataSnapshotManager.cs487
-rw-r--r--OpenSim/Region/OptionalModules/DataSnapshot/EstateSnapshot.cs149
-rw-r--r--OpenSim/Region/OptionalModules/DataSnapshot/Interfaces/IDataSnapshot.cs36
-rw-r--r--OpenSim/Region/OptionalModules/DataSnapshot/Interfaces/IDataSnapshotProvider.cs46
-rw-r--r--OpenSim/Region/OptionalModules/DataSnapshot/LLSDDiscovery.cs44
-rw-r--r--OpenSim/Region/OptionalModules/DataSnapshot/LandSnapshot.cs433
-rw-r--r--OpenSim/Region/OptionalModules/DataSnapshot/ObjectSnapshot.cs264
-rw-r--r--OpenSim/Region/OptionalModules/DataSnapshot/SnapshotStore.cs337
-rw-r--r--OpenSim/Region/OptionalModules/Example/BareBonesNonShared/BareBonesNonSharedModule.cs6
-rw-r--r--OpenSim/Region/OptionalModules/Example/BareBonesShared/BareBonesSharedModule.cs6
-rw-r--r--OpenSim/Region/OptionalModules/Example/WebSocketEchoTest/WebSocketEchoModule.cs175
-rw-r--r--OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs608
-rwxr-xr-xOpenSim/Region/OptionalModules/PhysicsParameters/PhysicsParameters.cs21
-rw-r--r--OpenSim/Region/OptionalModules/PrimLimitsModule/PrimLimitsModule.cs99
-rw-r--r--OpenSim/Region/OptionalModules/Properties/AssemblyInfo.cs8
-rw-r--r--OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCombinerClientEventForwarder.cs94
-rw-r--r--OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCombinerIndividualEventForwarder.cs139
-rw-r--r--OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCombinerLargeLandChannel.cs201
-rw-r--r--OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCombinerModule.cs880
-rw-r--r--OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCombinerPermissionModule.cs270
-rw-r--r--OpenSim/Region/OptionalModules/RegionCombinerModule/RegionConnections.cs94
-rw-r--r--OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCourseLocation.cs43
-rw-r--r--OpenSim/Region/OptionalModules/RegionCombinerModule/RegionData.cs40
-rw-r--r--OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStore.cs391
-rw-r--r--OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreCommands.cs195
-rw-r--r--OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs200
-rw-r--r--OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs482
-rw-r--r--OpenSim/Region/OptionalModules/Scripting/JsonStore/Tests/JsonStoreScriptModuleTests.cs900
-rw-r--r--OpenSim/Region/OptionalModules/Scripting/Minimodule/MRMModule.cs2
-rw-r--r--OpenSim/Region/OptionalModules/Scripting/Minimodule/SOPObject.cs2
-rw-r--r--OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs19
-rw-r--r--OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcGridRouterModule.cs1
-rw-r--r--OpenSim/Region/OptionalModules/UserStatistics/ActiveConnectionsAJAX.cs308
-rw-r--r--OpenSim/Region/OptionalModules/UserStatistics/Clients_report.cs329
-rw-r--r--OpenSim/Region/OptionalModules/UserStatistics/Default_Report.cs277
-rw-r--r--OpenSim/Region/OptionalModules/UserStatistics/HTMLUtil.cs263
-rw-r--r--OpenSim/Region/OptionalModules/UserStatistics/IStatsReport.cs39
-rw-r--r--OpenSim/Region/OptionalModules/UserStatistics/LogLinesAJAX.cs159
-rw-r--r--OpenSim/Region/OptionalModules/UserStatistics/Prototype_distributor.cs80
-rw-r--r--OpenSim/Region/OptionalModules/UserStatistics/Sessions_Report.cs288
-rw-r--r--OpenSim/Region/OptionalModules/UserStatistics/SimStatsAJAX.cs276
-rw-r--r--OpenSim/Region/OptionalModules/UserStatistics/Updater_distributor.cs70
-rw-r--r--OpenSim/Region/OptionalModules/UserStatistics/WebStatsModule.cs1203
-rw-r--r--OpenSim/Region/OptionalModules/ViewerSupport/CameraOnlyModeModule.cs176
-rw-r--r--OpenSim/Region/OptionalModules/ViewerSupport/DynamicFloaterModule.cs238
-rw-r--r--OpenSim/Region/OptionalModules/ViewerSupport/DynamicMenuModule.cs304
-rw-r--r--OpenSim/Region/OptionalModules/ViewerSupport/GodNamesModule.cs144
-rw-r--r--OpenSim/Region/OptionalModules/ViewerSupport/SimulatorFeaturesHelper.cs171
-rw-r--r--OpenSim/Region/OptionalModules/ViewerSupport/SpecialUIModule.cs165
-rw-r--r--OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModule.cs123
-rw-r--r--OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModuleState.cs14
-rw-r--r--OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs34
-rw-r--r--OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs69
-rw-r--r--OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs98
-rw-r--r--OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs154
-rw-r--r--OpenSim/Region/OptionalModules/World/SceneCommands/SceneCommandsModule.cs142
-rw-r--r--OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs4
-rw-r--r--OpenSim/Region/OptionalModules/World/WorldView/WorldViewRequestHandler.cs2
78 files changed, 13158 insertions, 1015 deletions
diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs
index 781539a..6fe86b2 100644
--- a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs
+++ b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs
@@ -71,7 +71,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
71 m_client = client; 71 m_client = client;
72 m_scene = scene; 72 m_scene = scene;
73 73
74 Watchdog.StartThread(InternalLoop, "IRCClientView", ThreadPriority.Normal, false, true); 74 WorkManager.StartThread(InternalLoop, "IRCClientView", ThreadPriority.Normal, false, true);
75 } 75 }
76 76
77 private void SendServerCommand(string command) 77 private void SendServerCommand(string command)
@@ -516,7 +516,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
516 516
517 public Vector3 StartPos 517 public Vector3 StartPos
518 { 518 {
519 get { return new Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 50); } 519 get { return new Vector3(m_scene.RegionInfo.RegionSizeX * 0.5f, m_scene.RegionInfo.RegionSizeY * 0.5f, 50f); }
520 set { } 520 set { }
521 } 521 }
522 522
@@ -660,6 +660,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
660 public event BakeTerrain OnBakeTerrain; 660 public event BakeTerrain OnBakeTerrain;
661 public event EstateChangeInfo OnEstateChangeInfo; 661 public event EstateChangeInfo OnEstateChangeInfo;
662 public event EstateManageTelehub OnEstateManageTelehub; 662 public event EstateManageTelehub OnEstateManageTelehub;
663 public event CachedTextureRequest OnCachedTextureRequest;
663 public event SetAppearance OnSetAppearance; 664 public event SetAppearance OnSetAppearance;
664 public event AvatarNowWearing OnAvatarNowWearing; 665 public event AvatarNowWearing OnAvatarNowWearing;
665 public event RezSingleAttachmentFromInv OnRezSingleAttachmentFromInv; 666 public event RezSingleAttachmentFromInv OnRezSingleAttachmentFromInv;
@@ -686,6 +687,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
686 public event Action<IClientAPI, bool> OnCompleteMovementToRegion; 687 public event Action<IClientAPI, bool> OnCompleteMovementToRegion;
687 public event UpdateAgent OnPreAgentUpdate; 688 public event UpdateAgent OnPreAgentUpdate;
688 public event UpdateAgent OnAgentUpdate; 689 public event UpdateAgent OnAgentUpdate;
690 public event UpdateAgent OnAgentCameraUpdate;
689 public event AgentRequestSit OnAgentRequestSit; 691 public event AgentRequestSit OnAgentRequestSit;
690 public event AgentSit OnAgentSit; 692 public event AgentSit OnAgentSit;
691 public event AvatarPickerRequest OnAvatarPickerRequest; 693 public event AvatarPickerRequest OnAvatarPickerRequest;
@@ -901,12 +903,12 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
901 903
902 public void Start() 904 public void Start()
903 { 905 {
904 m_scene.AddNewClient(this, PresenceType.User); 906 m_scene.AddNewAgent(this, PresenceType.User);
905 907
906 // Mimicking LLClientView which gets always set appearance from client. 908 // Mimicking LLClientView which gets always set appearance from client.
907 AvatarAppearance appearance; 909 AvatarAppearance appearance;
908 m_scene.GetAvatarAppearance(this, out appearance); 910 m_scene.GetAvatarAppearance(this, out appearance);
909 OnSetAppearance(this, appearance.Texture, (byte[])appearance.VisualParams.Clone()); 911 OnSetAppearance(this, appearance.Texture, (byte[])appearance.VisualParams.Clone(),appearance.AvatarSize, new WearableCacheItem[0]);
910 } 912 }
911 913
912 public void SendRegionHandshake(RegionInfo regionInfo, RegionHandshakeArgs args) 914 public void SendRegionHandshake(RegionInfo regionInfo, RegionHandshakeArgs args)
@@ -938,13 +940,18 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
938 { 940 {
939 941
940 } 942 }
943
944 public void SendCachedTextureResponse(ISceneEntity avatar, int serial, List<CachedTextureResponseArg> cachedTextures)
945 {
941 946
947 }
948
942 public void SendStartPingCheck(byte seq) 949 public void SendStartPingCheck(byte seq)
943 { 950 {
944 951
945 } 952 }
946 953
947 public void SendKillObject(ulong regionHandle, List<uint> localID) 954 public void SendKillObject(List<uint> localID)
948 { 955 {
949 956
950 } 957 }
@@ -971,12 +978,12 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
971 // TODO 978 // TODO
972 } 979 }
973 980
974 public void SendGenericMessage(string method, List<string> message) 981 public void SendGenericMessage(string method, UUID invoice, List<string> message)
975 { 982 {
976 983
977 } 984 }
978 985
979 public void SendGenericMessage(string method, List<byte[]> message) 986 public void SendGenericMessage(string method, UUID invoice, List<byte[]> message)
980 { 987 {
981 988
982 } 989 }
@@ -1050,7 +1057,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
1050 { 1057 {
1051 } 1058 }
1052 1059
1053 public void SendMoneyBalance(UUID transaction, bool success, byte[] description, int balance) 1060 public void SendMoneyBalance(UUID transaction, bool success, byte[] description, int balance, int transactionType, UUID sourceID, bool sourceIsGroup, UUID destID, bool destIsGroup, int amount, string item)
1054 { 1061 {
1055 1062
1056 } 1063 }
@@ -1190,11 +1197,6 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
1190 1197
1191 } 1198 }
1192 1199
1193 public bool AddMoney(int debit)
1194 {
1195 return true;
1196 }
1197
1198 public void SendSunPos(Vector3 sunPos, Vector3 sunVel, ulong CurrentTime, uint SecondsPerSunCycle, uint SecondsPerYear, float OrbitalPosition) 1200 public void SendSunPos(Vector3 sunPos, Vector3 sunVel, ulong CurrentTime, uint SecondsPerSunCycle, uint SecondsPerYear, float OrbitalPosition)
1199 { 1201 {
1200 1202
@@ -1424,9 +1426,11 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
1424 return new byte[0]; 1426 return new byte[0];
1425 } 1427 }
1426 1428
1429#pragma warning disable 0067
1427 public event ViewerEffectEventHandler OnViewerEffect; 1430 public event ViewerEffectEventHandler OnViewerEffect;
1428 public event Action<IClientAPI> OnLogout; 1431 public event Action<IClientAPI> OnLogout;
1429 public event Action<IClientAPI> OnConnectionClosed; 1432 public event Action<IClientAPI> OnConnectionClosed;
1433#pragma warning restore 0067
1430 1434
1431 public void SendBlueBoxMessage(UUID FromAvatarID, string FromAvatarName, string Message) 1435 public void SendBlueBoxMessage(UUID FromAvatarID, string FromAvatarName, string Message)
1432 { 1436 {
@@ -1671,12 +1675,17 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
1671 { 1675 {
1672 } 1676 }
1673 1677
1674 public void StopFlying(ISceneEntity presence) 1678 public void SendAgentTerseUpdate(ISceneEntity presence)
1675 { 1679 {
1676 } 1680 }
1677 1681
1678 public void SendPlacesReply(UUID queryID, UUID transactionID, PlacesReplyData[] data) 1682 public void SendPlacesReply(UUID queryID, UUID transactionID, PlacesReplyData[] data)
1679 { 1683 {
1680 } 1684 }
1685
1686 public void SendPartPhysicsProprieties(ISceneEntity entity)
1687 {
1688 }
1689
1681 } 1690 }
1682} 1691}
diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCServer.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCServer.cs
index 9d27386..a1682d2 100644
--- a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCServer.cs
+++ b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCServer.cs
@@ -58,7 +58,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
58 58
59 m_listener.Start(50); 59 m_listener.Start(50);
60 60
61 Watchdog.StartThread(ListenLoop, "IRCServer", ThreadPriority.Normal, false, true); 61 WorkManager.StartThread(ListenLoop, "IRCServer", ThreadPriority.Normal, false, true);
62 m_baseScene = baseScene; 62 m_baseScene = baseScene;
63 } 63 }
64 64
diff --git a/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs b/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs
index 992f38e..08d0fbf 100644
--- a/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs
+++ b/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs
@@ -27,6 +27,7 @@
27 27
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Linq;
30using System.Reflection; 31using System.Reflection;
31using System.Text; 32using System.Text;
32using log4net; 33using log4net;
@@ -51,7 +52,7 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden
51 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "LindenUDPInfoModule")] 52 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "LindenUDPInfoModule")]
52 public class LindenUDPInfoModule : ISharedRegionModule 53 public class LindenUDPInfoModule : ISharedRegionModule
53 { 54 {
54// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 55 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
55 56
56 protected Dictionary<UUID, Scene> m_scenes = new Dictionary<UUID, Scene>(); 57 protected Dictionary<UUID, Scene> m_scenes = new Dictionary<UUID, Scene>();
57 58
@@ -130,6 +131,15 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden
130 "Go on/off emergency monitoring mode", 131 "Go on/off emergency monitoring mode",
131 "Go on/off emergency monitoring mode", 132 "Go on/off emergency monitoring mode",
132 HandleEmergencyMonitoring); 133 HandleEmergencyMonitoring);
134
135 scene.AddCommand(
136 "Comms", this, "show client stats",
137 "show client stats [first_name last_name]",
138 "Show client request stats",
139 "Without the 'first_name last_name' option, all clients are shown."
140 + " With the 'first_name last_name' option only a specific client is shown.",
141 (mod, cmd) => MainConsole.Instance.Output(HandleClientStatsReport(cmd)));
142
133 } 143 }
134 144
135 public void RemoveRegion(Scene scene) 145 public void RemoveRegion(Scene scene)
@@ -294,7 +304,7 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden
294 private string GetImageQueuesReport(string[] showParams) 304 private string GetImageQueuesReport(string[] showParams)
295 { 305 {
296 if (showParams.Length < 5 || showParams.Length > 6) 306 if (showParams.Length < 5 || showParams.Length > 6)
297 return "Usage: image queues show <first-name> <last-name> [full]"; 307 return "Usage: show image queues <first-name> <last-name> [full]";
298 308
299 string firstName = showParams[3]; 309 string firstName = showParams[3];
300 string lastName = showParams[4]; 310 string lastName = showParams[4];
@@ -385,7 +395,7 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden
385 report.Append(GetColumnEntry("Type", maxTypeLength, columnPadding)); 395 report.Append(GetColumnEntry("Type", maxTypeLength, columnPadding));
386 396
387 report.AppendFormat( 397 report.AppendFormat(
388 "{0,7} {1,7} {2,7} {3,7} {4,9} {5,7} {6,7} {7,7} {8,7} {9,7} {10,8} {11,7} {12,7}\n", 398 "{0,7} {1,7} {2,7} {3,7} {4,9} {5,7} {6,7} {7,7} {8,7} {9,7} {10,8} {11,7}\n",
389 "Since", 399 "Since",
390 "Pkts", 400 "Pkts",
391 "Pkts", 401 "Pkts",
@@ -397,12 +407,11 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden
397 "Q Pkts", 407 "Q Pkts",
398 "Q Pkts", 408 "Q Pkts",
399 "Q Pkts", 409 "Q Pkts",
400 "Q Pkts",
401 "Q Pkts"); 410 "Q Pkts");
402 411
403 report.AppendFormat("{0,-" + totalInfoFieldsLength + "}", ""); 412 report.AppendFormat("{0,-" + totalInfoFieldsLength + "}", "");
404 report.AppendFormat( 413 report.AppendFormat(
405 "{0,7} {1,7} {2,7} {3,7} {4,9} {5,7} {6,7} {7,7} {8,7} {9,7} {10,8} {11,7} {12,7}\n", 414 "{0,7} {1,7} {2,7} {3,7} {4,9} {5,7} {6,7} {7,7} {8,7} {9,7} {10,8} {11,7}\n",
406 "Last In", 415 "Last In",
407 "In", 416 "In",
408 "Out", 417 "Out",
@@ -414,8 +423,7 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden
414 "Cloud", 423 "Cloud",
415 "Task", 424 "Task",
416 "Texture", 425 "Texture",
417 "Asset", 426 "Asset");
418 "State");
419 427
420 lock (m_scenes) 428 lock (m_scenes)
421 { 429 {
@@ -424,24 +432,24 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden
424 scene.ForEachClient( 432 scene.ForEachClient(
425 delegate(IClientAPI client) 433 delegate(IClientAPI client)
426 { 434 {
427 bool isChild = client.SceneAgent.IsChildAgent;
428 if (isChild && !showChildren)
429 return;
430
431 string name = client.Name;
432 if (pname != "" && name != pname)
433 return;
434
435 string regionName = scene.RegionInfo.RegionName;
436
437 report.Append(GetColumnEntry(name, maxNameLength, columnPadding));
438 report.Append(GetColumnEntry(regionName, maxRegionNameLength, columnPadding));
439 report.Append(GetColumnEntry(isChild ? "Cd" : "Rt", maxTypeLength, columnPadding));
440
441 if (client is IStatsCollector) 435 if (client is IStatsCollector)
442 { 436 {
443 IStatsCollector stats = (IStatsCollector)client; 437
438 bool isChild = client.SceneAgent.IsChildAgent;
439 if (isChild && !showChildren)
440 return;
444 441
442 string name = client.Name;
443 if (pname != "" && name != pname)
444 return;
445
446 string regionName = scene.RegionInfo.RegionName;
447
448 report.Append(GetColumnEntry(name, maxNameLength, columnPadding));
449 report.Append(GetColumnEntry(regionName, maxRegionNameLength, columnPadding));
450 report.Append(GetColumnEntry(isChild ? "Cd" : "Rt", maxTypeLength, columnPadding));
451
452 IStatsCollector stats = (IStatsCollector)client;
445 report.AppendLine(stats.Report()); 453 report.AppendLine(stats.Report());
446 } 454 }
447 }); 455 });
@@ -479,8 +487,10 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden
479 report.Append(GetColumnEntry("Type", maxTypeLength, columnPadding)); 487 report.Append(GetColumnEntry("Type", maxTypeLength, columnPadding));
480 488
481 report.AppendFormat( 489 report.AppendFormat(
482 "{0,7} {1,8} {2,7} {3,7} {4,7} {5,7} {6,9} {7,7}\n", 490 "{0,8} {1,8} {2,7} {3,8} {4,7} {5,7} {6,7} {7,7} {8,9} {9,7}\n",
483 "Total", 491 "Max",
492 "Target",
493 "Actual",
484 "Resend", 494 "Resend",
485 "Land", 495 "Land",
486 "Wind", 496 "Wind",
@@ -491,7 +501,9 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden
491 501
492 report.AppendFormat("{0,-" + totalInfoFieldsLength + "}", ""); 502 report.AppendFormat("{0,-" + totalInfoFieldsLength + "}", "");
493 report.AppendFormat( 503 report.AppendFormat(
494 "{0,7} {1,8} {2,7} {3,7} {4,7} {5,7} {6,9} {7,7}", 504 "{0,8} {1,8} {2,7} {3,8} {4,7} {5,7} {6,7} {7,7} {8,9} {9,7}\n",
505 "kb/s",
506 "kb/s",
495 "kb/s", 507 "kb/s",
496 "kb/s", 508 "kb/s",
497 "kb/s", 509 "kb/s",
@@ -503,8 +515,6 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden
503 515
504 report.AppendLine(); 516 report.AppendLine();
505 517
506 bool firstClient = true;
507
508 lock (m_scenes) 518 lock (m_scenes)
509 { 519 {
510 foreach (Scene scene in m_scenes.Values) 520 foreach (Scene scene in m_scenes.Values)
@@ -516,12 +526,6 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden
516 { 526 {
517 LLClientView llClient = client as LLClientView; 527 LLClientView llClient = client as LLClientView;
518 528
519 if (firstClient)
520 {
521 report.AppendLine(GetServerThrottlesReport(llClient.UDPServer));
522 firstClient = false;
523 }
524
525 bool isChild = client.SceneAgent.IsChildAgent; 529 bool isChild = client.SceneAgent.IsChildAgent;
526 if (isChild && !showChildren) 530 if (isChild && !showChildren)
527 return; 531 return;
@@ -540,7 +544,11 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden
540 report.Append(GetColumnEntry(isChild ? "Cd" : "Rt", maxTypeLength, columnPadding)); 544 report.Append(GetColumnEntry(isChild ? "Cd" : "Rt", maxTypeLength, columnPadding));
541 545
542 report.AppendFormat( 546 report.AppendFormat(
543 "{0,7} {1,8} {2,7} {3,7} {4,7} {5,7} {6,9} {7,7}", 547 "{0,8} {1,8} {2,7} {3,8} {4,7} {5,7} {6,7} {7,7} {8,9} {9,7}\n",
548 ci.maxThrottle > 0 ? ((ci.maxThrottle * 8) / 1000).ToString() : "-",
549 llUdpClient.FlowThrottle.AdaptiveEnabled
550 ? ((ci.targetThrottle * 8) / 1000).ToString()
551 : (llUdpClient.FlowThrottle.TotalDripRequest * 8 / 1000).ToString(),
544 (ci.totalThrottle * 8) / 1000, 552 (ci.totalThrottle * 8) / 1000,
545 (ci.resendThrottle * 8) / 1000, 553 (ci.resendThrottle * 8) / 1000,
546 (ci.landThrottle * 8) / 1000, 554 (ci.landThrottle * 8) / 1000,
@@ -548,9 +556,7 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden
548 (ci.cloudThrottle * 8) / 1000, 556 (ci.cloudThrottle * 8) / 1000,
549 (ci.taskThrottle * 8) / 1000, 557 (ci.taskThrottle * 8) / 1000,
550 (ci.textureThrottle * 8) / 1000, 558 (ci.textureThrottle * 8) / 1000,
551 (ci.assetThrottle * 8) / 1000); 559 (ci.assetThrottle * 8) / 1000);
552
553 report.AppendLine();
554 } 560 }
555 }); 561 });
556 } 562 }
@@ -558,35 +564,116 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden
558 564
559 return report.ToString(); 565 return report.ToString();
560 } 566 }
561 567
562 protected string GetServerThrottlesReport(LLUDPServer udpServer) 568 /// <summary>
569 /// Show client stats data
570 /// </summary>
571 /// <param name="showParams"></param>
572 /// <returns></returns>
573 protected string HandleClientStatsReport(string[] showParams)
563 { 574 {
564 StringBuilder report = new StringBuilder(); 575 // NOTE: This writes to m_log on purpose. We want to store this information
565 576 // in case we need to analyze it later.
566 int columnPadding = 2; 577 //
567 int maxNameLength = 18; 578 if (showParams.Length <= 4)
568 int maxRegionNameLength = 14; 579 {
569 int maxTypeLength = 4; 580 m_log.InfoFormat("[INFO]: {0,-12} {1,-20} {2,-6} {3,-11} {4,-11} {5,-16}", "Region", "Name", "Root", "Time", "Reqs/min", "AgentUpdates");
570 581 foreach (Scene scene in m_scenes.Values)
571 string name = "SERVER AGENT RATES"; 582 {
572 583 scene.ForEachClient(
573 report.Append(GetColumnEntry(name, maxNameLength, columnPadding)); 584 delegate(IClientAPI client)
574 report.Append(GetColumnEntry("-", maxRegionNameLength, columnPadding)); 585 {
575 report.Append(GetColumnEntry("-", maxTypeLength, columnPadding)); 586 if (client is LLClientView)
576 587 {
577 ThrottleRates throttleRates = udpServer.ThrottleRates; 588 LLClientView llClient = client as LLClientView;
578 report.AppendFormat( 589 ClientInfo cinfo = llClient.UDPClient.GetClientInfo();
579 "{0,7} {1,8} {2,7} {3,7} {4,7} {5,7} {6,9} {7,7}", 590 int avg_reqs = cinfo.AsyncRequests.Values.Sum() + cinfo.GenericRequests.Values.Sum() + cinfo.SyncRequests.Values.Sum();
580 (throttleRates.Total * 8) / 1000, 591 avg_reqs = avg_reqs / ((DateTime.Now - cinfo.StartedTime).Minutes + 1);
581 (throttleRates.Resend * 8) / 1000, 592
582 (throttleRates.Land * 8) / 1000, 593 string childAgentStatus;
583 (throttleRates.Wind * 8) / 1000, 594
584 (throttleRates.Cloud * 8) / 1000, 595 if (llClient.SceneAgent != null)
585 (throttleRates.Task * 8) / 1000, 596 childAgentStatus = llClient.SceneAgent.IsChildAgent ? "N" : "Y";
586 (throttleRates.Texture * 8) / 1000, 597 else
587 (throttleRates.Asset * 8) / 1000); 598 childAgentStatus = "Off!";
599
600 m_log.InfoFormat("[INFO]: {0,-12} {1,-20} {2,-6} {3,-11} {4,-11} {5,-16}",
601 scene.RegionInfo.RegionName, llClient.Name,
602 childAgentStatus,
603 (DateTime.Now - cinfo.StartedTime).Minutes,
604 avg_reqs,
605 string.Format(
606 "{0} ({1:0.00}%)",
607 llClient.TotalAgentUpdates,
608 cinfo.SyncRequests.ContainsKey("AgentUpdate")
609 ? (float)cinfo.SyncRequests["AgentUpdate"] / llClient.TotalAgentUpdates * 100
610 : 0));
611 }
612 });
613 }
614 return string.Empty;
615 }
588 616
589 return report.ToString(); 617 string fname = "", lname = "";
590 } 618
619 if (showParams.Length > 3)
620 fname = showParams[3];
621 if (showParams.Length > 4)
622 lname = showParams[4];
623
624 foreach (Scene scene in m_scenes.Values)
625 {
626 scene.ForEachClient(
627 delegate(IClientAPI client)
628 {
629 if (client is LLClientView)
630 {
631 LLClientView llClient = client as LLClientView;
632
633 if (llClient.Name == fname + " " + lname)
634 {
635
636 ClientInfo cinfo = llClient.GetClientInfo();
637 AgentCircuitData aCircuit = scene.AuthenticateHandler.GetAgentCircuitData(llClient.CircuitCode);
638 if (aCircuit == null) // create a dummy one
639 aCircuit = new AgentCircuitData();
640
641 if (!llClient.SceneAgent.IsChildAgent)
642 m_log.InfoFormat("[INFO]: {0} # {1} # {2}", llClient.Name, Util.GetViewerName(aCircuit), aCircuit.Id0);
643
644 int avg_reqs = cinfo.AsyncRequests.Values.Sum() + cinfo.GenericRequests.Values.Sum() + cinfo.SyncRequests.Values.Sum();
645 avg_reqs = avg_reqs / ((DateTime.Now - cinfo.StartedTime).Minutes + 1);
646
647 m_log.InfoFormat("[INFO]:");
648 m_log.InfoFormat("[INFO]: {0} # {1} # Time: {2}min # Avg Reqs/min: {3}", scene.RegionInfo.RegionName,
649 (llClient.SceneAgent.IsChildAgent ? "Child" : "Root"), (DateTime.Now - cinfo.StartedTime).Minutes, avg_reqs);
650
651 Dictionary<string, int> sortedDict = (from entry in cinfo.AsyncRequests orderby entry.Value descending select entry)
652 .ToDictionary(pair => pair.Key, pair => pair.Value);
653 PrintRequests("TOP ASYNC", sortedDict, cinfo.AsyncRequests.Values.Sum());
654
655 sortedDict = (from entry in cinfo.SyncRequests orderby entry.Value descending select entry)
656 .ToDictionary(pair => pair.Key, pair => pair.Value);
657 PrintRequests("TOP SYNC", sortedDict, cinfo.SyncRequests.Values.Sum());
658
659 sortedDict = (from entry in cinfo.GenericRequests orderby entry.Value descending select entry)
660 .ToDictionary(pair => pair.Key, pair => pair.Value);
661 PrintRequests("TOP GENERIC", sortedDict, cinfo.GenericRequests.Values.Sum());
662 }
663 }
664 });
665 }
666 return string.Empty;
667 }
668
669 private void PrintRequests(string type, Dictionary<string, int> sortedDict, int sum)
670 {
671 m_log.InfoFormat("[INFO]:");
672 m_log.InfoFormat("[INFO]: {0,25}", type);
673 foreach (KeyValuePair<string, int> kvp in sortedDict.Take(12))
674 m_log.InfoFormat("[INFO]: {0,25} {1,-6}", kvp.Key, kvp.Value);
675 m_log.InfoFormat("[INFO]: {0,25}", "...");
676 m_log.InfoFormat("[INFO]: {0,25} {1,-6}", "Total", sum);
677 }
591 } 678 }
592} \ No newline at end of file 679}
diff --git a/OpenSim/Region/OptionalModules/Avatar/Appearance/AppearanceInfoModule.cs b/OpenSim/Region/OptionalModules/Avatar/Appearance/AppearanceInfoModule.cs
index d718a2f..2f9bb1e 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Appearance/AppearanceInfoModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Appearance/AppearanceInfoModule.cs
@@ -51,7 +51,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance
51 { 51 {
52// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 52// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
53 53
54 private Dictionary<UUID, Scene> m_scenes = new Dictionary<UUID, Scene>(); 54 private List<Scene> m_scenes = new List<Scene>();
55
55// private IAvatarFactoryModule m_avatarFactory; 56// private IAvatarFactoryModule m_avatarFactory;
56 57
57 public string Name { get { return "Appearance Information Module"; } } 58 public string Name { get { return "Appearance Information Module"; } }
@@ -83,7 +84,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance
83// m_log.DebugFormat("[APPEARANCE INFO MODULE]: REGION {0} REMOVED", scene.RegionInfo.RegionName); 84// m_log.DebugFormat("[APPEARANCE INFO MODULE]: REGION {0} REMOVED", scene.RegionInfo.RegionName);
84 85
85 lock (m_scenes) 86 lock (m_scenes)
86 m_scenes.Remove(scene.RegionInfo.RegionID); 87 m_scenes.Remove(scene);
87 } 88 }
88 89
89 public void RegionLoaded(Scene scene) 90 public void RegionLoaded(Scene scene)
@@ -91,7 +92,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance
91// m_log.DebugFormat("[APPEARANCE INFO MODULE]: REGION {0} LOADED", scene.RegionInfo.RegionName); 92// m_log.DebugFormat("[APPEARANCE INFO MODULE]: REGION {0} LOADED", scene.RegionInfo.RegionName);
92 93
93 lock (m_scenes) 94 lock (m_scenes)
94 m_scenes[scene.RegionInfo.RegionID] = scene; 95 m_scenes.Add(scene);
95 96
96 scene.AddCommand( 97 scene.AddCommand(
97 "Users", this, "show appearance", 98 "Users", this, "show appearance",
@@ -102,7 +103,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance
102 scene.AddCommand( 103 scene.AddCommand(
103 "Users", this, "appearance show", 104 "Users", this, "appearance show",
104 "appearance show [<first-name> <last-name>]", 105 "appearance show [<first-name> <last-name>]",
105 "Show appearance information for each avatar in the simulator.", 106 "Show appearance information for avatars.",
106 "This command checks whether the simulator has all the baked textures required to display an avatar to other viewers. " 107 "This command checks whether the simulator has all the baked textures required to display an avatar to other viewers. "
107 + "\nIf not, then appearance is 'corrupt' and other avatars will continue to see it as a cloud." 108 + "\nIf not, then appearance is 'corrupt' and other avatars will continue to see it as a cloud."
108 + "\nOptionally, you can view just a particular avatar's appearance information." 109 + "\nOptionally, you can view just a particular avatar's appearance information."
@@ -132,6 +133,21 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance
132 "Find out which avatar uses the given asset as a baked texture, if any.", 133 "Find out which avatar uses the given asset as a baked texture, if any.",
133 "You can specify just the beginning of the uuid, e.g. 2008a8d. A longer UUID must be in dashed format.", 134 "You can specify just the beginning of the uuid, e.g. 2008a8d. A longer UUID must be in dashed format.",
134 HandleFindAppearanceCommand); 135 HandleFindAppearanceCommand);
136
137 scene.AddCommand(
138 "Users", this, "wearables show",
139 "wearables show [<first-name> <last-name>]",
140 "Show information about wearables for avatars.",
141 "If no avatar name is given then a general summary for all avatars in the scene is shown.\n"
142 + "If an avatar name is given then specific information about current wearables is shown.",
143 HandleShowWearablesCommand);
144
145 scene.AddCommand(
146 "Users", this, "wearables check",
147 "wearables check <first-name> <last-name>",
148 "Check that the wearables of a given avatar in the scene are valid.",
149 "This currently checks that the wearable assets themselves and any assets referenced by them exist.",
150 HandleCheckWearablesCommand);
135 } 151 }
136 152
137 private void HandleSendAppearanceCommand(string module, string[] cmd) 153 private void HandleSendAppearanceCommand(string module, string[] cmd)
@@ -155,7 +171,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance
155 171
156 lock (m_scenes) 172 lock (m_scenes)
157 { 173 {
158 foreach (Scene scene in m_scenes.Values) 174 foreach (Scene scene in m_scenes)
159 { 175 {
160 if (targetNameSupplied) 176 if (targetNameSupplied)
161 { 177 {
@@ -186,7 +202,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance
186 } 202 }
187 } 203 }
188 204
189 protected void HandleShowAppearanceCommand(string module, string[] cmd) 205 private void HandleShowAppearanceCommand(string module, string[] cmd)
190 { 206 {
191 if (cmd.Length != 2 && cmd.Length < 4) 207 if (cmd.Length != 2 && cmd.Length < 4)
192 { 208 {
@@ -207,7 +223,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance
207 223
208 lock (m_scenes) 224 lock (m_scenes)
209 { 225 {
210 foreach (Scene scene in m_scenes.Values) 226 foreach (Scene scene in m_scenes)
211 { 227 {
212 if (targetNameSupplied) 228 if (targetNameSupplied)
213 { 229 {
@@ -222,7 +238,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance
222 { 238 {
223 bool bakedTextureValid = scene.AvatarFactory.ValidateBakedTextureCache(sp); 239 bool bakedTextureValid = scene.AvatarFactory.ValidateBakedTextureCache(sp);
224 MainConsole.Instance.OutputFormat( 240 MainConsole.Instance.OutputFormat(
225 "{0} baked appearance texture is {1}", sp.Name, bakedTextureValid ? "OK" : "corrupt"); 241 "{0} baked appearance texture is {1}", sp.Name, bakedTextureValid ? "OK" : "incomplete");
226 } 242 }
227 ); 243 );
228 } 244 }
@@ -243,7 +259,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance
243 259
244 lock (m_scenes) 260 lock (m_scenes)
245 { 261 {
246 foreach (Scene scene in m_scenes.Values) 262 foreach (Scene scene in m_scenes)
247 { 263 {
248 ScenePresence sp = scene.GetScenePresence(firstname, lastname); 264 ScenePresence sp = scene.GetScenePresence(firstname, lastname);
249 if (sp != null && !sp.IsChildAgent) 265 if (sp != null && !sp.IsChildAgent)
@@ -263,7 +279,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance
263 } 279 }
264 } 280 }
265 281
266 protected void HandleFindAppearanceCommand(string module, string[] cmd) 282 private void HandleFindAppearanceCommand(string module, string[] cmd)
267 { 283 {
268 if (cmd.Length != 3) 284 if (cmd.Length != 3)
269 { 285 {
@@ -277,7 +293,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance
277 293
278 lock (m_scenes) 294 lock (m_scenes)
279 { 295 {
280 foreach (Scene scene in m_scenes.Values) 296 foreach (Scene scene in m_scenes)
281 { 297 {
282 scene.ForEachRootScenePresence( 298 scene.ForEachRootScenePresence(
283 sp => 299 sp =>
@@ -304,5 +320,163 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance
304 string.Join(", ", matchedAvatars.ToList().ConvertAll<string>(sp => sp.Name).ToArray())); 320 string.Join(", ", matchedAvatars.ToList().ConvertAll<string>(sp => sp.Name).ToArray()));
305 } 321 }
306 } 322 }
323
324 protected void HandleShowWearablesCommand(string module, string[] cmd)
325 {
326 if (cmd.Length != 2 && cmd.Length < 4)
327 {
328 MainConsole.Instance.OutputFormat("Usage: wearables show [<first-name> <last-name>]");
329 return;
330 }
331
332 bool targetNameSupplied = false;
333 string optionalTargetFirstName = null;
334 string optionalTargetLastName = null;
335
336 if (cmd.Length >= 4)
337 {
338 targetNameSupplied = true;
339 optionalTargetFirstName = cmd[2];
340 optionalTargetLastName = cmd[3];
341 }
342
343 StringBuilder sb = new StringBuilder();
344
345 if (targetNameSupplied)
346 {
347 lock (m_scenes)
348 {
349 foreach (Scene scene in m_scenes)
350 {
351 ScenePresence sp = scene.GetScenePresence(optionalTargetFirstName, optionalTargetLastName);
352 if (sp != null && !sp.IsChildAgent)
353 AppendWearablesDetailReport(sp, sb);
354 }
355 }
356 }
357 else
358 {
359 ConsoleDisplayTable cdt = new ConsoleDisplayTable();
360 cdt.AddColumn("Name", ConsoleDisplayUtil.UserNameSize);
361 cdt.AddColumn("Wearables", 2);
362
363 lock (m_scenes)
364 {
365 foreach (Scene scene in m_scenes)
366 {
367 scene.ForEachRootScenePresence(
368 sp =>
369 {
370 int count = 0;
371
372 for (int i = (int)WearableType.Shape; i < (int)WearableType.Physics; i++)
373 count += sp.Appearance.Wearables[i].Count;
374
375 cdt.AddRow(sp.Name, count);
376 }
377 );
378 }
379 }
380
381 sb.Append(cdt.ToString());
382 }
383
384 MainConsole.Instance.Output(sb.ToString());
385 }
386
387 private void HandleCheckWearablesCommand(string module, string[] cmd)
388 {
389 if (cmd.Length != 4)
390 {
391 MainConsole.Instance.OutputFormat("Usage: wearables check <first-name> <last-name>");
392 return;
393 }
394
395 string firstname = cmd[2];
396 string lastname = cmd[3];
397
398 StringBuilder sb = new StringBuilder();
399 UuidGatherer uuidGatherer = new UuidGatherer(m_scenes[0].AssetService);
400
401 lock (m_scenes)
402 {
403 foreach (Scene scene in m_scenes)
404 {
405 ScenePresence sp = scene.GetScenePresence(firstname, lastname);
406 if (sp != null && !sp.IsChildAgent)
407 {
408 sb.AppendFormat("Wearables checks for {0}\n\n", sp.Name);
409
410 for (int i = (int)WearableType.Shape; i < (int)WearableType.Physics; i++)
411 {
412 AvatarWearable aw = sp.Appearance.Wearables[i];
413
414 if (aw.Count > 0)
415 {
416 sb.Append(Enum.GetName(typeof(WearableType), i));
417 sb.Append("\n");
418
419 for (int j = 0; j < aw.Count; j++)
420 {
421 WearableItem wi = aw[j];
422
423 ConsoleDisplayList cdl = new ConsoleDisplayList();
424 cdl.Indent = 2;
425 cdl.AddRow("Item UUID", wi.ItemID);
426 cdl.AddRow("Assets", "");
427 sb.Append(cdl.ToString());
428
429 uuidGatherer.AddForInspection(wi.AssetID);
430 uuidGatherer.GatherAll();
431 string[] assetStrings
432 = Array.ConvertAll<UUID, string>(uuidGatherer.GatheredUuids.Keys.ToArray(), u => u.ToString());
433
434 bool[] existChecks = scene.AssetService.AssetsExist(assetStrings);
435
436 ConsoleDisplayTable cdt = new ConsoleDisplayTable();
437 cdt.Indent = 4;
438 cdt.AddColumn("Type", 10);
439 cdt.AddColumn("UUID", ConsoleDisplayUtil.UuidSize);
440 cdt.AddColumn("Found", 5);
441
442 for (int k = 0; k < existChecks.Length; k++)
443 cdt.AddRow(
444 (AssetType)uuidGatherer.GatheredUuids[new UUID(assetStrings[k])],
445 assetStrings[k], existChecks[k] ? "yes" : "no");
446
447 sb.Append(cdt.ToString());
448 sb.Append("\n");
449 }
450 }
451 }
452 }
453 }
454 }
455
456 MainConsole.Instance.Output(sb.ToString());
457 }
458
459 private void AppendWearablesDetailReport(ScenePresence sp, StringBuilder sb)
460 {
461 sb.AppendFormat("\nWearables for {0}\n", sp.Name);
462
463 ConsoleDisplayTable cdt = new ConsoleDisplayTable();
464 cdt.AddColumn("Type", 10);
465 cdt.AddColumn("Item UUID", ConsoleDisplayUtil.UuidSize);
466 cdt.AddColumn("Asset UUID", ConsoleDisplayUtil.UuidSize);
467
468 for (int i = (int)WearableType.Shape; i < (int)WearableType.Physics; i++)
469 {
470 AvatarWearable aw = sp.Appearance.Wearables[i];
471
472 for (int j = 0; j < aw.Count; j++)
473 {
474 WearableItem wi = aw[j];
475 cdt.AddRow(Enum.GetName(typeof(WearableType), i), wi.ItemID, wi.AssetID);
476 }
477 }
478
479 sb.Append(cdt.ToString());
480 }
307 } 481 }
308} \ No newline at end of file 482} \ No newline at end of file
diff --git a/OpenSim/Region/OptionalModules/Avatar/Attachments/AttachmentsCommandModule.cs b/OpenSim/Region/OptionalModules/Avatar/Attachments/AttachmentsCommandModule.cs
index d97e3b3..0333747 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Attachments/AttachmentsCommandModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Attachments/AttachmentsCommandModule.cs
@@ -176,16 +176,13 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments
176// " {0,-36} {1,-10} {2,-36} {3,-14} {4,-15}\n", 176// " {0,-36} {1,-10} {2,-36} {3,-14} {4,-15}\n",
177// attachmentObject.Name, attachmentObject.LocalId, attachmentObject.FromItemID, 177// attachmentObject.Name, attachmentObject.LocalId, attachmentObject.FromItemID,
178// (AttachmentPoint)attachmentObject.AttachmentPoint, attachmentObject.RootPart.AttachedPos); 178// (AttachmentPoint)attachmentObject.AttachmentPoint, attachmentObject.RootPart.AttachedPos);
179 ct.Rows.Add( 179
180 new ConsoleDisplayTableRow( 180 ct.AddRow(
181 new List<string>() 181 attachmentObject.Name,
182 { 182 attachmentObject.LocalId,
183 attachmentObject.Name, 183 attachmentObject.FromItemID,
184 attachmentObject.LocalId.ToString(), 184 ((AttachmentPoint)attachmentObject.AttachmentPoint),
185 attachmentObject.FromItemID.ToString(), 185 attachmentObject.RootPart.AttachedPos);
186 ((AttachmentPoint)attachmentObject.AttachmentPoint).ToString(),
187 attachmentObject.RootPart.AttachedPos.ToString()
188 }));
189// } 186// }
190 } 187 }
191 188
diff --git a/OpenSim/Region/OptionalModules/Avatar/Attachments/TempAttachmentsModule.cs b/OpenSim/Region/OptionalModules/Avatar/Attachments/TempAttachmentsModule.cs
index d7fb272..535bf67 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Attachments/TempAttachmentsModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Attachments/TempAttachmentsModule.cs
@@ -40,6 +40,7 @@ using OpenSim.Framework.Monitoring;
40using OpenSim.Region.ClientStack.LindenUDP; 40using OpenSim.Region.ClientStack.LindenUDP;
41using OpenSim.Region.Framework.Interfaces; 41using OpenSim.Region.Framework.Interfaces;
42using OpenSim.Region.Framework.Scenes; 42using OpenSim.Region.Framework.Scenes;
43using PermissionMask = OpenSim.Framework.PermissionMask;
43 44
44namespace OpenSim.Region.OptionalModules.Avatar.Attachments 45namespace OpenSim.Region.OptionalModules.Avatar.Attachments
45{ 46{
@@ -76,7 +77,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments
76 77
77 if (m_console != null) 78 if (m_console != null)
78 { 79 {
79 m_console.AddCommand("TempATtachModule", false, "set auto_grant_attach_perms", "set auto_grant_attach_perms true|false", "Allow objects owned by the region owner os estate managers to obtain attach permissions without asking the user", SetAutoGrantAttachPerms); 80 m_console.AddCommand("TempAttachModule", false, "set auto_grant_attach_perms", "set auto_grant_attach_perms true|false", "Allow objects owned by the region owner or estate managers to obtain attach permissions without asking the user", SetAutoGrantAttachPerms);
80 } 81 }
81 } 82 }
82 else 83 else
@@ -183,7 +184,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments
183 hostPart.ParentGroup.RootPart.ScheduleFullUpdate(); 184 hostPart.ParentGroup.RootPart.ScheduleFullUpdate();
184 } 185 }
185 186
186 return attachmentsModule.AttachObject(target, hostPart.ParentGroup, (uint)attachmentPoint, false, true) ? 1 : 0; 187 return attachmentsModule.AttachObject(target, hostPart.ParentGroup, (uint)attachmentPoint, false, false, true) ? 1 : 0;
187 } 188 }
188 } 189 }
189} 190}
diff --git a/OpenSim/Region/OptionalModules/Avatar/Chat/ChannelState.cs b/OpenSim/Region/OptionalModules/Avatar/Chat/ChannelState.cs
index 66265d8..b5d9fda 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Chat/ChannelState.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Chat/ChannelState.cs
@@ -55,42 +55,42 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
55 // These are the IRC Connector configurable parameters with hard-wired 55 // These are the IRC Connector configurable parameters with hard-wired
56 // default values (retained for compatability). 56 // default values (retained for compatability).
57 57
58 internal string Server = null; 58 internal string Server = null;
59 internal string Password = null; 59 internal string Password = null;
60 internal string IrcChannel = null; 60 internal string IrcChannel = null;
61 internal string BaseNickname = "OSimBot"; 61 internal string BaseNickname = "OSimBot";
62 internal uint Port = 6667; 62 internal uint Port = 6667;
63 internal string User = null; 63 internal string User = null;
64 64
65 internal bool ClientReporting = true; 65 internal bool ClientReporting = true;
66 internal bool RelayChat = true; 66 internal bool RelayChat = true;
67 internal bool RelayPrivateChannels = false; 67 internal bool RelayPrivateChannels = false;
68 internal int RelayChannel = 1; 68 internal int RelayChannel = 1;
69 internal List<int> ValidInWorldChannels = new List<int>(); 69 internal List<int> ValidInWorldChannels = new List<int>();
70 70
71 // Connector agnostic parameters. These values are NOT shared with the 71 // Connector agnostic parameters. These values are NOT shared with the
72 // connector and do not differentiate at an IRC level 72 // connector and do not differentiate at an IRC level
73 73
74 internal string PrivateMessageFormat = "PRIVMSG {0} :<{2}> {1} {3}"; 74 internal string PrivateMessageFormat = "PRIVMSG {0} :<{2}> {1} {3}";
75 internal string NoticeMessageFormat = "PRIVMSG {0} :<{2}> {3}"; 75 internal string NoticeMessageFormat = "PRIVMSG {0} :<{2}> {3}";
76 internal int RelayChannelOut = -1; 76 internal int RelayChannelOut = -1;
77 internal bool RandomizeNickname = true; 77 internal bool RandomizeNickname = true;
78 internal bool CommandsEnabled = false; 78 internal bool CommandsEnabled = false;
79 internal int CommandChannel = -1; 79 internal int CommandChannel = -1;
80 internal int ConnectDelay = 10; 80 internal int ConnectDelay = 10;
81 internal int PingDelay = 15; 81 internal int PingDelay = 15;
82 internal string DefaultZone = "Sim"; 82 internal string DefaultZone = "Sim";
83 83
84 internal string _accessPassword = String.Empty; 84 internal string _accessPassword = String.Empty;
85 internal Regex AccessPasswordRegex = null; 85 internal Regex AccessPasswordRegex = null;
86 internal List<string> ExcludeList = new List<string>(); 86 internal List<string> ExcludeList = new List<string>();
87 internal string AccessPassword 87 internal string AccessPassword
88 { 88 {
89 get { return _accessPassword; } 89 get { return _accessPassword; }
90 set 90 set
91 { 91 {
92 _accessPassword = value; 92 _accessPassword = value;
93 AccessPasswordRegex = new Regex(String.Format(@"^{0},\s*(?<avatar>[^,]+),\s*(?<message>.+)$", _accessPassword), 93 AccessPasswordRegex = new Regex(String.Format(@"^{0},\s*(?<avatar>[^,]+),\s*(?<message>.+)$", _accessPassword),
94 RegexOptions.Compiled); 94 RegexOptions.Compiled);
95 } 95 }
96 } 96 }
@@ -99,9 +99,9 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
99 99
100 // IRC connector reference 100 // IRC connector reference
101 101
102 internal IRCConnector irc = null; 102 internal IRCConnector irc = null;
103 103
104 internal int idn = _idk_++; 104 internal int idn = _idk_++;
105 105
106 // List of regions dependent upon this connection 106 // List of regions dependent upon this connection
107 107
@@ -119,29 +119,29 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
119 119
120 internal ChannelState(ChannelState model) 120 internal ChannelState(ChannelState model)
121 { 121 {
122 Server = model.Server; 122 Server = model.Server;
123 Password = model.Password; 123 Password = model.Password;
124 IrcChannel = model.IrcChannel; 124 IrcChannel = model.IrcChannel;
125 Port = model.Port; 125 Port = model.Port;
126 BaseNickname = model.BaseNickname; 126 BaseNickname = model.BaseNickname;
127 RandomizeNickname = model.RandomizeNickname; 127 RandomizeNickname = model.RandomizeNickname;
128 User = model.User; 128 User = model.User;
129 CommandsEnabled = model.CommandsEnabled; 129 CommandsEnabled = model.CommandsEnabled;
130 CommandChannel = model.CommandChannel; 130 CommandChannel = model.CommandChannel;
131 RelayChat = model.RelayChat; 131 RelayChat = model.RelayChat;
132 RelayPrivateChannels = model.RelayPrivateChannels; 132 RelayPrivateChannels = model.RelayPrivateChannels;
133 RelayChannelOut = model.RelayChannelOut; 133 RelayChannelOut = model.RelayChannelOut;
134 RelayChannel = model.RelayChannel; 134 RelayChannel = model.RelayChannel;
135 ValidInWorldChannels = model.ValidInWorldChannels; 135 ValidInWorldChannels = model.ValidInWorldChannels;
136 PrivateMessageFormat = model.PrivateMessageFormat; 136 PrivateMessageFormat = model.PrivateMessageFormat;
137 NoticeMessageFormat = model.NoticeMessageFormat; 137 NoticeMessageFormat = model.NoticeMessageFormat;
138 ClientReporting = model.ClientReporting; 138 ClientReporting = model.ClientReporting;
139 AccessPassword = model.AccessPassword; 139 AccessPassword = model.AccessPassword;
140 DefaultZone = model.DefaultZone; 140 DefaultZone = model.DefaultZone;
141 ConnectDelay = model.ConnectDelay; 141 ConnectDelay = model.ConnectDelay;
142 PingDelay = model.PingDelay; 142 PingDelay = model.PingDelay;
143 } 143 }
144 144
145 // Read the configuration file, performing variable substitution and any 145 // Read the configuration file, performing variable substitution and any
146 // necessary aliasing. See accompanying documentation for how this works. 146 // necessary aliasing. See accompanying documentation for how this works.
147 // If you don't need variables, then this works exactly as before. 147 // If you don't need variables, then this works exactly as before.
@@ -160,54 +160,54 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
160 160
161 m_log.DebugFormat("[IRC-Channel-{0}] Initial request by Region {1} to connect to IRC", cs.idn, rs.Region); 161 m_log.DebugFormat("[IRC-Channel-{0}] Initial request by Region {1} to connect to IRC", cs.idn, rs.Region);
162 162
163 cs.Server = Substitute(rs, config.GetString("server", null)); 163 cs.Server = Substitute(rs, config.GetString("server", null));
164 m_log.DebugFormat("[IRC-Channel-{0}] Server : <{1}>", cs.idn, cs.Server); 164 m_log.DebugFormat("[IRC-Channel-{0}] Server : <{1}>", cs.idn, cs.Server);
165 cs.Password = Substitute(rs, config.GetString("password", null)); 165 cs.Password = Substitute(rs, config.GetString("password", null));
166 // probably not a good idea to put a password in the log file 166 // probably not a good idea to put a password in the log file
167 cs.User = Substitute(rs, config.GetString("user", null)); 167 cs.User = Substitute(rs, config.GetString("user", null));
168 cs.IrcChannel = Substitute(rs, config.GetString("channel", null)); 168 cs.IrcChannel = Substitute(rs, config.GetString("channel", null));
169 m_log.DebugFormat("[IRC-Channel-{0}] IrcChannel : <{1}>", cs.idn, cs.IrcChannel); 169 m_log.DebugFormat("[IRC-Channel-{0}] IrcChannel : <{1}>", cs.idn, cs.IrcChannel);
170 cs.Port = Convert.ToUInt32(Substitute(rs, config.GetString("port", Convert.ToString(cs.Port)))); 170 cs.Port = Convert.ToUInt32(Substitute(rs, config.GetString("port", Convert.ToString(cs.Port))));
171 m_log.DebugFormat("[IRC-Channel-{0}] Port : <{1}>", cs.idn, cs.Port); 171 m_log.DebugFormat("[IRC-Channel-{0}] Port : <{1}>", cs.idn, cs.Port);
172 cs.BaseNickname = Substitute(rs, config.GetString("nick", cs.BaseNickname)); 172 cs.BaseNickname = Substitute(rs, config.GetString("nick", cs.BaseNickname));
173 m_log.DebugFormat("[IRC-Channel-{0}] BaseNickname : <{1}>", cs.idn, cs.BaseNickname); 173 m_log.DebugFormat("[IRC-Channel-{0}] BaseNickname : <{1}>", cs.idn, cs.BaseNickname);
174 cs.RandomizeNickname = Convert.ToBoolean(Substitute(rs, config.GetString("randomize_nick", Convert.ToString(cs.RandomizeNickname)))); 174 cs.RandomizeNickname = Convert.ToBoolean(Substitute(rs, config.GetString("randomize_nick", Convert.ToString(cs.RandomizeNickname))));
175 m_log.DebugFormat("[IRC-Channel-{0}] RandomizeNickname : <{1}>", cs.idn, cs.RandomizeNickname); 175 m_log.DebugFormat("[IRC-Channel-{0}] RandomizeNickname : <{1}>", cs.idn, cs.RandomizeNickname);
176 cs.RandomizeNickname = Convert.ToBoolean(Substitute(rs, config.GetString("nicknum", Convert.ToString(cs.RandomizeNickname)))); 176 cs.RandomizeNickname = Convert.ToBoolean(Substitute(rs, config.GetString("nicknum", Convert.ToString(cs.RandomizeNickname))));
177 m_log.DebugFormat("[IRC-Channel-{0}] RandomizeNickname : <{1}>", cs.idn, cs.RandomizeNickname); 177 m_log.DebugFormat("[IRC-Channel-{0}] RandomizeNickname : <{1}>", cs.idn, cs.RandomizeNickname);
178 cs.User = Substitute(rs, config.GetString("username", cs.User)); 178 cs.User = Substitute(rs, config.GetString("username", cs.User));
179 m_log.DebugFormat("[IRC-Channel-{0}] User : <{1}>", cs.idn, cs.User); 179 m_log.DebugFormat("[IRC-Channel-{0}] User : <{1}>", cs.idn, cs.User);
180 cs.CommandsEnabled = Convert.ToBoolean(Substitute(rs, config.GetString("commands_enabled", Convert.ToString(cs.CommandsEnabled)))); 180 cs.CommandsEnabled = Convert.ToBoolean(Substitute(rs, config.GetString("commands_enabled", Convert.ToString(cs.CommandsEnabled))));
181 m_log.DebugFormat("[IRC-Channel-{0}] CommandsEnabled : <{1}>", cs.idn, cs.CommandsEnabled); 181 m_log.DebugFormat("[IRC-Channel-{0}] CommandsEnabled : <{1}>", cs.idn, cs.CommandsEnabled);
182 cs.CommandChannel = Convert.ToInt32(Substitute(rs, config.GetString("commandchannel", Convert.ToString(cs.CommandChannel)))); 182 cs.CommandChannel = Convert.ToInt32(Substitute(rs, config.GetString("commandchannel", Convert.ToString(cs.CommandChannel))));
183 m_log.DebugFormat("[IRC-Channel-{0}] CommandChannel : <{1}>", cs.idn, cs.CommandChannel); 183 m_log.DebugFormat("[IRC-Channel-{0}] CommandChannel : <{1}>", cs.idn, cs.CommandChannel);
184 cs.CommandChannel = Convert.ToInt32(Substitute(rs, config.GetString("command_channel", Convert.ToString(cs.CommandChannel)))); 184 cs.CommandChannel = Convert.ToInt32(Substitute(rs, config.GetString("command_channel", Convert.ToString(cs.CommandChannel))));
185 m_log.DebugFormat("[IRC-Channel-{0}] CommandChannel : <{1}>", cs.idn, cs.CommandChannel); 185 m_log.DebugFormat("[IRC-Channel-{0}] CommandChannel : <{1}>", cs.idn, cs.CommandChannel);
186 cs.RelayChat = Convert.ToBoolean(Substitute(rs, config.GetString("relay_chat", Convert.ToString(cs.RelayChat)))); 186 cs.RelayChat = Convert.ToBoolean(Substitute(rs, config.GetString("relay_chat", Convert.ToString(cs.RelayChat))));
187 m_log.DebugFormat("[IRC-Channel-{0}] RelayChat : <{1}>", cs.idn, cs.RelayChat); 187 m_log.DebugFormat("[IRC-Channel-{0}] RelayChat : <{1}>", cs.idn, cs.RelayChat);
188 cs.RelayPrivateChannels = Convert.ToBoolean(Substitute(rs, config.GetString("relay_private_channels", Convert.ToString(cs.RelayPrivateChannels)))); 188 cs.RelayPrivateChannels = Convert.ToBoolean(Substitute(rs, config.GetString("relay_private_channels", Convert.ToString(cs.RelayPrivateChannels))));
189 m_log.DebugFormat("[IRC-Channel-{0}] RelayPrivateChannels : <{1}>", cs.idn, cs.RelayPrivateChannels); 189 m_log.DebugFormat("[IRC-Channel-{0}] RelayPrivateChannels : <{1}>", cs.idn, cs.RelayPrivateChannels);
190 cs.RelayPrivateChannels = Convert.ToBoolean(Substitute(rs, config.GetString("useworldcomm", Convert.ToString(cs.RelayPrivateChannels)))); 190 cs.RelayPrivateChannels = Convert.ToBoolean(Substitute(rs, config.GetString("useworldcomm", Convert.ToString(cs.RelayPrivateChannels))));
191 m_log.DebugFormat("[IRC-Channel-{0}] RelayPrivateChannels : <{1}>", cs.idn, cs.RelayPrivateChannels); 191 m_log.DebugFormat("[IRC-Channel-{0}] RelayPrivateChannels : <{1}>", cs.idn, cs.RelayPrivateChannels);
192 cs.RelayChannelOut = Convert.ToInt32(Substitute(rs, config.GetString("relay_private_channel_out", Convert.ToString(cs.RelayChannelOut)))); 192 cs.RelayChannelOut = Convert.ToInt32(Substitute(rs, config.GetString("relay_private_channel_out", Convert.ToString(cs.RelayChannelOut))));
193 m_log.DebugFormat("[IRC-Channel-{0}] RelayChannelOut : <{1}>", cs.idn, cs.RelayChannelOut); 193 m_log.DebugFormat("[IRC-Channel-{0}] RelayChannelOut : <{1}>", cs.idn, cs.RelayChannelOut);
194 cs.RelayChannel = Convert.ToInt32(Substitute(rs, config.GetString("relay_private_channel_in", Convert.ToString(cs.RelayChannel)))); 194 cs.RelayChannel = Convert.ToInt32(Substitute(rs, config.GetString("relay_private_channel_in", Convert.ToString(cs.RelayChannel))));
195 m_log.DebugFormat("[IRC-Channel-{0}] RelayChannel : <{1}>", cs.idn, cs.RelayChannel); 195 m_log.DebugFormat("[IRC-Channel-{0}] RelayChannel : <{1}>", cs.idn, cs.RelayChannel);
196 cs.RelayChannel = Convert.ToInt32(Substitute(rs, config.GetString("inchannel", Convert.ToString(cs.RelayChannel)))); 196 cs.RelayChannel = Convert.ToInt32(Substitute(rs, config.GetString("inchannel", Convert.ToString(cs.RelayChannel))));
197 m_log.DebugFormat("[IRC-Channel-{0}] RelayChannel : <{1}>", cs.idn, cs.RelayChannel); 197 m_log.DebugFormat("[IRC-Channel-{0}] RelayChannel : <{1}>", cs.idn, cs.RelayChannel);
198 cs.PrivateMessageFormat = Substitute(rs, config.GetString("msgformat", cs.PrivateMessageFormat)); 198 cs.PrivateMessageFormat = Substitute(rs, config.GetString("msgformat", cs.PrivateMessageFormat));
199 m_log.DebugFormat("[IRC-Channel-{0}] PrivateMessageFormat : <{1}>", cs.idn, cs.PrivateMessageFormat); 199 m_log.DebugFormat("[IRC-Channel-{0}] PrivateMessageFormat : <{1}>", cs.idn, cs.PrivateMessageFormat);
200 cs.NoticeMessageFormat = Substitute(rs, config.GetString("noticeformat", cs.NoticeMessageFormat)); 200 cs.NoticeMessageFormat = Substitute(rs, config.GetString("noticeformat", cs.NoticeMessageFormat));
201 m_log.DebugFormat("[IRC-Channel-{0}] NoticeMessageFormat : <{1}>", cs.idn, cs.NoticeMessageFormat); 201 m_log.DebugFormat("[IRC-Channel-{0}] NoticeMessageFormat : <{1}>", cs.idn, cs.NoticeMessageFormat);
202 cs.ClientReporting = Convert.ToInt32(Substitute(rs, config.GetString("verbosity", cs.ClientReporting?"1":"0"))) > 0; 202 cs.ClientReporting = Convert.ToInt32(Substitute(rs, config.GetString("verbosity", cs.ClientReporting ? "1" : "0"))) > 0;
203 m_log.DebugFormat("[IRC-Channel-{0}] ClientReporting : <{1}>", cs.idn, cs.ClientReporting); 203 m_log.DebugFormat("[IRC-Channel-{0}] ClientReporting : <{1}>", cs.idn, cs.ClientReporting);
204 cs.ClientReporting = Convert.ToBoolean(Substitute(rs, config.GetString("report_clients", Convert.ToString(cs.ClientReporting)))); 204 cs.ClientReporting = Convert.ToBoolean(Substitute(rs, config.GetString("report_clients", Convert.ToString(cs.ClientReporting))));
205 m_log.DebugFormat("[IRC-Channel-{0}] ClientReporting : <{1}>", cs.idn, cs.ClientReporting); 205 m_log.DebugFormat("[IRC-Channel-{0}] ClientReporting : <{1}>", cs.idn, cs.ClientReporting);
206 cs.DefaultZone = Substitute(rs, config.GetString("fallback_region", cs.DefaultZone)); 206 cs.DefaultZone = Substitute(rs, config.GetString("fallback_region", cs.DefaultZone));
207 m_log.DebugFormat("[IRC-Channel-{0}] DefaultZone : <{1}>", cs.idn, cs.DefaultZone); 207 m_log.DebugFormat("[IRC-Channel-{0}] DefaultZone : <{1}>", cs.idn, cs.DefaultZone);
208 cs.ConnectDelay = Convert.ToInt32(Substitute(rs, config.GetString("connect_delay", Convert.ToString(cs.ConnectDelay)))); 208 cs.ConnectDelay = Convert.ToInt32(Substitute(rs, config.GetString("connect_delay", Convert.ToString(cs.ConnectDelay))));
209 m_log.DebugFormat("[IRC-Channel-{0}] ConnectDelay : <{1}>", cs.idn, cs.ConnectDelay); 209 m_log.DebugFormat("[IRC-Channel-{0}] ConnectDelay : <{1}>", cs.idn, cs.ConnectDelay);
210 cs.PingDelay = Convert.ToInt32(Substitute(rs, config.GetString("ping_delay", Convert.ToString(cs.PingDelay)))); 210 cs.PingDelay = Convert.ToInt32(Substitute(rs, config.GetString("ping_delay", Convert.ToString(cs.PingDelay))));
211 m_log.DebugFormat("[IRC-Channel-{0}] PingDelay : <{1}>", cs.idn, cs.PingDelay); 211 m_log.DebugFormat("[IRC-Channel-{0}] PingDelay : <{1}>", cs.idn, cs.PingDelay);
212 cs.AccessPassword = Substitute(rs, config.GetString("access_password", cs.AccessPassword)); 212 cs.AccessPassword = Substitute(rs, config.GetString("access_password", cs.AccessPassword));
213 m_log.DebugFormat("[IRC-Channel-{0}] AccessPassword : <{1}>", cs.idn, cs.AccessPassword); 213 m_log.DebugFormat("[IRC-Channel-{0}] AccessPassword : <{1}>", cs.idn, cs.AccessPassword);
@@ -217,7 +217,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
217 { 217 {
218 cs.ExcludeList.Add(name.Trim().ToLower()); 218 cs.ExcludeList.Add(name.Trim().ToLower());
219 } 219 }
220 220
221 // Fail if fundamental information is still missing 221 // Fail if fundamental information is still missing
222 222
223 if (cs.Server == null) 223 if (cs.Server == null)
@@ -306,8 +306,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
306 306
307 IRCBridgeModule.m_channels.Add(cs); 307 IRCBridgeModule.m_channels.Add(cs);
308 308
309 m_log.InfoFormat("[IRC-Channel-{0}] New channel initialized for {1}, nick: {2}, commands {3}, private channels {4}", 309 m_log.InfoFormat("[IRC-Channel-{0}] New channel initialized for {1}, nick: {2}, commands {3}, private channels {4}",
310 cs.idn, rs.Region, cs.DefaultZone, 310 cs.idn, rs.Region, cs.DefaultZone,
311 cs.CommandsEnabled ? "enabled" : "not enabled", 311 cs.CommandsEnabled ? "enabled" : "not enabled",
312 cs.RelayPrivateChannels ? "relayed" : "not relayed"); 312 cs.RelayPrivateChannels ? "relayed" : "not relayed");
313 } 313 }
@@ -417,7 +417,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
417 private bool IsAConnectionMatchFor(ChannelState cs) 417 private bool IsAConnectionMatchFor(ChannelState cs)
418 { 418 {
419 return ( 419 return (
420 Server == cs.Server && 420 Server == cs.Server &&
421 IrcChannel == cs.IrcChannel && 421 IrcChannel == cs.IrcChannel &&
422 Port == cs.Port && 422 Port == cs.Port &&
423 BaseNickname == cs.BaseNickname && 423 BaseNickname == cs.BaseNickname &&
@@ -461,7 +461,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
461 461
462 string result = instr; 462 string result = instr;
463 463
464 if (result == null || result.Length == 0) 464 if (string.IsNullOrEmpty(result))
465 return result; 465 return result;
466 466
467 // Repeatedly scan the string until all possible 467 // Repeatedly scan the string until all possible
@@ -473,27 +473,27 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
473 { 473 {
474 474
475 string vvar = arg.Match(result).ToString(); 475 string vvar = arg.Match(result).ToString();
476 string var = vvar.Substring(1,vvar.Length-2).Trim(); 476 string var = vvar.Substring(1, vvar.Length - 2).Trim();
477 477
478 switch (var.ToLower()) 478 switch (var.ToLower())
479 { 479 {
480 case "%region" : 480 case "%region":
481 result = result.Replace(vvar, rs.Region); 481 result = result.Replace(vvar, rs.Region);
482 break; 482 break;
483 case "%host" : 483 case "%host":
484 result = result.Replace(vvar, rs.Host); 484 result = result.Replace(vvar, rs.Host);
485 break; 485 break;
486 case "%locx" : 486 case "%locx":
487 result = result.Replace(vvar, rs.LocX); 487 result = result.Replace(vvar, rs.LocX);
488 break; 488 break;
489 case "%locy" : 489 case "%locy":
490 result = result.Replace(vvar, rs.LocY); 490 result = result.Replace(vvar, rs.LocY);
491 break; 491 break;
492 case "%k" : 492 case "%k":
493 result = result.Replace(vvar, rs.IDK); 493 result = result.Replace(vvar, rs.IDK);
494 break; 494 break;
495 default : 495 default:
496 result = result.Replace(vvar, rs.config.GetString(var,var)); 496 result = result.Replace(vvar, rs.config.GetString(var, var));
497 break; 497 break;
498 } 498 }
499 // m_log.DebugFormat("[IRC-Channel] Parse[2]: {0}", result); 499 // m_log.DebugFormat("[IRC-Channel] Parse[2]: {0}", result);
diff --git a/OpenSim/Region/OptionalModules/Avatar/Chat/IRCBridgeModule.cs b/OpenSim/Region/OptionalModules/Avatar/Chat/IRCBridgeModule.cs
index 2e1d03d..351dbfe 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Chat/IRCBridgeModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Chat/IRCBridgeModule.cs
@@ -46,18 +46,18 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
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 internal static bool m_pluginEnabled = false; 49 internal static bool Enabled = false;
50 internal static IConfig m_config = null; 50 internal static IConfig m_config = null;
51 51
52 internal static List<ChannelState> m_channels = new List<ChannelState>(); 52 internal static List<ChannelState> m_channels = new List<ChannelState>();
53 internal static List<RegionState> m_regions = new List<RegionState>(); 53 internal static List<RegionState> m_regions = new List<RegionState>();
54 54
55 internal static string m_password = String.Empty; 55 internal static string m_password = String.Empty;
56 internal RegionState m_region = null; 56 internal RegionState m_region = null;
57 57
58 #region INonSharedRegionModule Members 58 #region INonSharedRegionModule Members
59 59
60 public Type ReplaceableInterface 60 public Type ReplaceableInterface
61 { 61 {
62 get { return null; } 62 get { return null; }
63 } 63 }
@@ -72,13 +72,13 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
72 m_config = config.Configs["IRC"]; 72 m_config = config.Configs["IRC"];
73 if (m_config == null) 73 if (m_config == null)
74 { 74 {
75// m_log.InfoFormat("[IRC-Bridge] module not configured"); 75 // m_log.InfoFormat("[IRC-Bridge] module not configured");
76 return; 76 return;
77 } 77 }
78 78
79 if (!m_config.GetBoolean("enabled", false)) 79 if (!m_config.GetBoolean("enabled", false))
80 { 80 {
81// m_log.InfoFormat("[IRC-Bridge] module disabled in configuration"); 81 // m_log.InfoFormat("[IRC-Bridge] module disabled in configuration");
82 return; 82 return;
83 } 83 }
84 84
@@ -87,19 +87,22 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
87 m_password = config.Configs["RemoteAdmin"].GetString("access_password", m_password); 87 m_password = config.Configs["RemoteAdmin"].GetString("access_password", m_password);
88 } 88 }
89 89
90 m_pluginEnabled = true; 90 Enabled = true;
91 m_log.InfoFormat("[IRC-Bridge]: Module enabled"); 91
92 m_log.InfoFormat("[IRC-Bridge]: Module is enabled");
92 } 93 }
93 94
94 public void AddRegion(Scene scene) 95 public void AddRegion(Scene scene)
95 { 96 {
96 if (m_pluginEnabled) 97 if (Enabled)
97 { 98 {
98 try 99 try
99 { 100 {
100 m_log.InfoFormat("[IRC-Bridge] Connecting region {0}", scene.RegionInfo.RegionName); 101 m_log.InfoFormat("[IRC-Bridge] Connecting region {0}", scene.RegionInfo.RegionName);
102
101 if (!String.IsNullOrEmpty(m_password)) 103 if (!String.IsNullOrEmpty(m_password))
102 MainServer.Instance.AddXmlRPCHandler("irc_admin", XmlRpcAdminMethod, false); 104 MainServer.Instance.AddXmlRPCHandler("irc_admin", XmlRpcAdminMethod, false);
105
103 m_region = new RegionState(scene, m_config); 106 m_region = new RegionState(scene, m_config);
104 lock (m_regions) m_regions.Add(m_region); 107 lock (m_regions) m_regions.Add(m_region);
105 m_region.Open(); 108 m_region.Open();
@@ -123,7 +126,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
123 126
124 public void RemoveRegion(Scene scene) 127 public void RemoveRegion(Scene scene)
125 { 128 {
126 if (!m_pluginEnabled) 129 if (!Enabled)
127 return; 130 return;
128 131
129 if (m_region == null) 132 if (m_region == null)
@@ -150,12 +153,12 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
150 m_log.Debug("[IRC-Bridge]: XML RPC Admin Entry"); 153 m_log.Debug("[IRC-Bridge]: XML RPC Admin Entry");
151 154
152 XmlRpcResponse response = new XmlRpcResponse(); 155 XmlRpcResponse response = new XmlRpcResponse();
153 Hashtable responseData = new Hashtable(); 156 Hashtable responseData = new Hashtable();
154 157
155 try 158 try
156 { 159 {
157 Hashtable requestData = (Hashtable)request.Params[0]; 160 Hashtable requestData = (Hashtable)request.Params[0];
158 bool found = false; 161 bool found = false;
159 string region = String.Empty; 162 string region = String.Empty;
160 163
161 if (m_password != String.Empty) 164 if (m_password != String.Empty)
@@ -169,18 +172,18 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
169 if (!requestData.ContainsKey("region")) 172 if (!requestData.ContainsKey("region"))
170 throw new Exception("No region name specified"); 173 throw new Exception("No region name specified");
171 region = (string)requestData["region"]; 174 region = (string)requestData["region"];
172 175
173 foreach (RegionState rs in m_regions) 176 foreach (RegionState rs in m_regions)
174 { 177 {
175 if (rs.Region == region) 178 if (rs.Region == region)
176 { 179 {
177 responseData["server"] = rs.cs.Server; 180 responseData["server"] = rs.cs.Server;
178 responseData["port"] = (int)rs.cs.Port; 181 responseData["port"] = (int)rs.cs.Port;
179 responseData["user"] = rs.cs.User; 182 responseData["user"] = rs.cs.User;
180 responseData["channel"] = rs.cs.IrcChannel; 183 responseData["channel"] = rs.cs.IrcChannel;
181 responseData["enabled"] = rs.cs.irc.Enabled; 184 responseData["enabled"] = rs.cs.irc.Enabled;
182 responseData["connected"] = rs.cs.irc.Connected; 185 responseData["connected"] = rs.cs.irc.Connected;
183 responseData["nickname"] = rs.cs.irc.Nick; 186 responseData["nickname"] = rs.cs.irc.Nick;
184 found = true; 187 found = true;
185 break; 188 break;
186 } 189 }
@@ -195,7 +198,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
195 m_log.ErrorFormat("[IRC-Bridge] XML RPC Admin request failed : {0}", e.Message); 198 m_log.ErrorFormat("[IRC-Bridge] XML RPC Admin request failed : {0}", e.Message);
196 199
197 responseData["success"] = "false"; 200 responseData["success"] = "false";
198 responseData["error"] = e.Message; 201 responseData["error"] = e.Message;
199 } 202 }
200 finally 203 finally
201 { 204 {
diff --git a/OpenSim/Region/OptionalModules/Avatar/Chat/IRCConnector.cs b/OpenSim/Region/OptionalModules/Avatar/Chat/IRCConnector.cs
index a014798..6985371 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Chat/IRCConnector.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Chat/IRCConnector.cs
@@ -52,17 +52,19 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
52 52
53 // Local constants 53 // Local constants
54 54
55 // This computation is not the real region center if the region is larger than 256.
56 // This computation isn't fixed because there is not a handle back to the region.
55 private static readonly Vector3 CenterOfRegion = new Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 20); 57 private static readonly Vector3 CenterOfRegion = new Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 20);
56 private static readonly char[] CS_SPACE = { ' ' }; 58 private static readonly char[] CS_SPACE = { ' ' };
57 59
58 private const int WD_INTERVAL = 1000; // base watchdog interval 60 private const int WD_INTERVAL = 1000; // base watchdog interval
59 private static int PING_PERIOD = 15; // WD intervals per PING 61 private static int PING_PERIOD = 15; // WD intervals per PING
60 private static int ICCD_PERIOD = 10; // WD intervals between Connects 62 private static int ICCD_PERIOD = 10; // WD intervals between Connects
61 private static int L_TIMEOUT = 25; // Login time out interval 63 private static int L_TIMEOUT = 25; // Login time out interval
62 64
63 private static int _idk_ = 0; // core connector identifier 65 private static int _idk_ = 0; // core connector identifier
64 private static int _pdk_ = 0; // ping interval counter 66 private static int _pdk_ = 0; // ping interval counter
65 private static int _icc_ = ICCD_PERIOD; // IRC connect counter 67 private static int _icc_ = ICCD_PERIOD; // IRC connect counter
66 68
67 // List of configured connectors 69 // List of configured connectors
68 70
@@ -107,13 +109,9 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
107 109
108 internal int m_resetk = 0; 110 internal int m_resetk = 0;
109 111
110 // Working threads
111
112 private Thread m_listener = null;
113
114 private Object msyncConnect = new Object(); 112 private Object msyncConnect = new Object();
115 113
116 internal bool m_randomizeNick = true; // add random suffix 114 internal bool m_randomizeNick = true; // add random suffix
117 internal string m_baseNick = null; // base name for randomizing 115 internal string m_baseNick = null; // base name for randomizing
118 internal string m_nick = null; // effective nickname 116 internal string m_nick = null; // effective nickname
119 117
@@ -122,7 +120,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
122 get { return m_nick; } 120 get { return m_nick; }
123 set { m_nick = value; } 121 set { m_nick = value; }
124 } 122 }
125 123
126 private bool m_enabled = false; // connector enablement 124 private bool m_enabled = false; // connector enablement
127 public bool Enabled 125 public bool Enabled
128 { 126 {
@@ -130,8 +128,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
130 } 128 }
131 129
132 private bool m_connected = false; // connection status 130 private bool m_connected = false; // connection status
133 private bool m_pending = false; // login disposition 131 private bool m_pending = false; // login disposition
134 private int m_timeout = L_TIMEOUT; // login timeout counter 132 private int m_timeout = L_TIMEOUT; // login timeout counter
135 public bool Connected 133 public bool Connected
136 { 134 {
137 get { return m_connected; } 135 get { return m_connected; }
@@ -143,9 +141,9 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
143 get { return m_ircChannel; } 141 get { return m_ircChannel; }
144 set { m_ircChannel = value; } 142 set { m_ircChannel = value; }
145 } 143 }
146 144
147 private uint m_port = 6667; // session port 145 private uint m_port = 6667; // session port
148 public uint Port 146 public uint Port
149 { 147 {
150 get { return m_port; } 148 get { return m_port; }
151 set { m_port = value; } 149 set { m_port = value; }
@@ -172,10 +170,10 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
172 170
173 // Network interface 171 // Network interface
174 172
175 private TcpClient m_tcp; 173 private TcpClient m_tcp;
176 private NetworkStream m_stream = null; 174 private NetworkStream m_stream = null;
177 private StreamReader m_reader; 175 private StreamReader m_reader;
178 private StreamWriter m_writer; 176 private StreamWriter m_writer;
179 177
180 // Channel characteristic info (if available) 178 // Channel characteristic info (if available)
181 179
@@ -193,26 +191,26 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
193 191
194 // Prepare network interface 192 // Prepare network interface
195 193
196 m_tcp = null; 194 m_tcp = null;
197 m_writer = null; 195 m_writer = null;
198 m_reader = null; 196 m_reader = null;
199 197
200 // Setup IRC session parameters 198 // Setup IRC session parameters
201 199
202 m_server = cs.Server; 200 m_server = cs.Server;
203 m_password = cs.Password; 201 m_password = cs.Password;
204 m_baseNick = cs.BaseNickname; 202 m_baseNick = cs.BaseNickname;
205 m_randomizeNick = cs.RandomizeNickname; 203 m_randomizeNick = cs.RandomizeNickname;
206 m_ircChannel = cs.IrcChannel; 204 m_ircChannel = cs.IrcChannel;
207 m_port = cs.Port; 205 m_port = cs.Port;
208 m_user = cs.User; 206 m_user = cs.User;
209 207
210 if (m_watchdog == null) 208 if (m_watchdog == null)
211 { 209 {
212 // Non-differentiating 210 // Non-differentiating
213 211
214 ICCD_PERIOD = cs.ConnectDelay; 212 ICCD_PERIOD = cs.ConnectDelay;
215 PING_PERIOD = cs.PingDelay; 213 PING_PERIOD = cs.PingDelay;
216 214
217 // Smaller values are not reasonable 215 // Smaller values are not reasonable
218 216
@@ -235,7 +233,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
235 233
236 if (m_randomizeNick) 234 if (m_randomizeNick)
237 m_nick = m_baseNick + Util.RandomClass.Next(1, 99); 235 m_nick = m_baseNick + Util.RandomClass.Next(1, 99);
238 else 236 else
239 m_nick = m_baseNick; 237 m_nick = m_baseNick;
240 238
241 m_log.InfoFormat("[IRC-Connector-{0}]: Initialization complete", idn); 239 m_log.InfoFormat("[IRC-Connector-{0}]: Initialization complete", idn);
@@ -295,18 +293,22 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
295 m_nick, m_ircChannel, m_server)); 293 m_nick, m_ircChannel, m_server));
296 m_writer.Flush(); 294 m_writer.Flush();
297 } 295 }
298 catch (Exception) {} 296 catch (Exception) { }
299 297
300 298
301 m_connected = false; 299 m_connected = false;
302 300
303 try { m_writer.Close(); } catch (Exception) {} 301 try { m_writer.Close(); }
304 try { m_reader.Close(); } catch (Exception) {} 302 catch (Exception) { }
305 try { m_stream.Close(); } catch (Exception) {} 303 try { m_reader.Close(); }
306 try { m_tcp.Close(); } catch (Exception) {} 304 catch (Exception) { }
305 try { m_stream.Close(); }
306 catch (Exception) { }
307 try { m_tcp.Close(); }
308 catch (Exception) { }
307 309
308 } 310 }
309 311
310 lock (m_connectors) 312 lock (m_connectors)
311 m_connectors.Remove(this); 313 m_connectors.Remove(this);
312 314
@@ -347,20 +349,17 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
347 if (m_connected) return; 349 if (m_connected) return;
348 350
349 m_connected = true; 351 m_connected = true;
350 m_pending = true; 352 m_pending = true;
351 m_timeout = L_TIMEOUT; 353 m_timeout = L_TIMEOUT;
352 354
353 m_tcp = new TcpClient(m_server, (int)m_port); 355 m_tcp = new TcpClient(m_server, (int)m_port);
354 m_stream = m_tcp.GetStream(); 356 m_stream = m_tcp.GetStream();
355 m_reader = new StreamReader(m_stream); 357 m_reader = new StreamReader(m_stream);
356 m_writer = new StreamWriter(m_stream); 358 m_writer = new StreamWriter(m_stream);
357 359
358 m_log.InfoFormat("[IRC-Connector-{0}]: Connected to {1}:{2}", idn, m_server, m_port); 360 m_log.InfoFormat("[IRC-Connector-{0}]: Connected to {1}:{2}", idn, m_server, m_port);
359 361
360 m_listener = new Thread(new ThreadStart(ListenerRun)); 362 WorkManager.StartThread(ListenerRun, "IRCConnectionListenerThread", ThreadPriority.Normal, true, false);
361 m_listener.Name = "IRCConnectorListenerThread";
362 m_listener.IsBackground = true;
363 m_listener.Start();
364 363
365 // This is the message order recommended by RFC 2812 364 // This is the message order recommended by RFC 2812
366 if (m_password != null) 365 if (m_password != null)
@@ -418,12 +417,15 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
418 // the socket and it will disappear of its own accord, once this 417 // the socket and it will disappear of its own accord, once this
419 // processing is completed. 418 // processing is completed.
420 419
421 try { m_writer.Close(); } catch (Exception) {} 420 try { m_writer.Close(); }
422 try { m_reader.Close(); } catch (Exception) {} 421 catch (Exception) { }
423 try { m_tcp.Close(); } catch (Exception) {} 422 try { m_reader.Close(); }
423 catch (Exception) { }
424 try { m_tcp.Close(); }
425 catch (Exception) { }
424 426
425 m_connected = false; 427 m_connected = false;
426 m_pending = false; 428 m_pending = false;
427 m_resetk++; 429 m_resetk++;
428 430
429 } 431 }
@@ -495,27 +497,26 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
495 { 497 {
496 498
497 string inputLine; 499 string inputLine;
498 int resetk = m_resetk; 500 int resetk = m_resetk;
499 501
500 try 502 try
501 { 503 {
502 while (m_enabled && m_connected) 504 while (m_enabled && m_connected)
503 { 505 {
504
505 if ((inputLine = m_reader.ReadLine()) == null) 506 if ((inputLine = m_reader.ReadLine()) == null)
506 throw new Exception("Listener input socket closed"); 507 throw new Exception("Listener input socket closed");
507 508
509 Watchdog.UpdateThread();
510
508 // m_log.Info("[IRCConnector]: " + inputLine); 511 // m_log.Info("[IRCConnector]: " + inputLine);
509 512
510 if (inputLine.Contains("PRIVMSG")) 513 if (inputLine.Contains("PRIVMSG"))
511 { 514 {
512
513 Dictionary<string, string> data = ExtractMsg(inputLine); 515 Dictionary<string, string> data = ExtractMsg(inputLine);
514 516
515 // Any chat ??? 517 // Any chat ???
516 if (data != null) 518 if (data != null)
517 { 519 {
518
519 OSChatMessage c = new OSChatMessage(); 520 OSChatMessage c = new OSChatMessage();
520 c.Message = data["msg"]; 521 c.Message = data["msg"];
521 c.Type = ChatTypeEnum.Region; 522 c.Type = ChatTypeEnum.Region;
@@ -531,9 +532,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
531 c.Message = String.Format("/me {0}", c.Message.Substring(8, c.Message.Length - 9)); 532 c.Message = String.Format("/me {0}", c.Message.Substring(8, c.Message.Length - 9));
532 533
533 ChannelState.OSChat(this, c, false); 534 ChannelState.OSChat(this, c, false);
534
535 } 535 }
536
537 } 536 }
538 else 537 else
539 { 538 {
@@ -553,9 +552,11 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
553 552
554 if (m_enabled && (m_resetk == resetk)) 553 if (m_enabled && (m_resetk == resetk))
555 Reconnect(); 554 Reconnect();
555
556 Watchdog.RemoveThread();
556 } 557 }
557 558
558 private Regex RE = new Regex(@":(?<nick>[\w-]*)!(?<user>\S*) PRIVMSG (?<channel>\S+) :(?<msg>.*)", 559 private Regex RE = new Regex(@":(?<nick>[\w-]*)!(?<user>\S*) PRIVMSG (?<channel>\S+) :(?<msg>.*)",
559 RegexOptions.Multiline); 560 RegexOptions.Multiline);
560 561
561 private Dictionary<string, string> ExtractMsg(string input) 562 private Dictionary<string, string> ExtractMsg(string input)
@@ -617,8 +618,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
617 string[] commArgs; 618 string[] commArgs;
618 string c_server = m_server; 619 string c_server = m_server;
619 620
620 string pfx = String.Empty; 621 string pfx = String.Empty;
621 string cmd = String.Empty; 622 string cmd = String.Empty;
622 string parms = String.Empty; 623 string parms = String.Empty;
623 624
624 // ":" indicates that a prefix is present 625 // ":" indicates that a prefix is present
@@ -627,15 +628,15 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
627 // ":" indicates that the remainder of the 628 // ":" indicates that the remainder of the
628 // line is a single parameter value. 629 // line is a single parameter value.
629 630
630 commArgs = command.Split(CS_SPACE,2); 631 commArgs = command.Split(CS_SPACE, 2);
631 632
632 if (commArgs[0].StartsWith(":")) 633 if (commArgs[0].StartsWith(":"))
633 { 634 {
634 pfx = commArgs[0].Substring(1); 635 pfx = commArgs[0].Substring(1);
635 commArgs = commArgs[1].Split(CS_SPACE,2); 636 commArgs = commArgs[1].Split(CS_SPACE, 2);
636 } 637 }
637 638
638 cmd = commArgs[0]; 639 cmd = commArgs[0];
639 parms = commArgs[1]; 640 parms = commArgs[1];
640 641
641 // m_log.DebugFormat("[IRC-Connector-{0}] prefix = <{1}> cmd = <{2}>", idn, pfx, cmd); 642 // m_log.DebugFormat("[IRC-Connector-{0}] prefix = <{1}> cmd = <{2}>", idn, pfx, cmd);
@@ -646,44 +647,44 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
646 // Messages 001-004 are always sent 647 // Messages 001-004 are always sent
647 // following signon. 648 // following signon.
648 649
649 case "001" : // Welcome ... 650 case "001": // Welcome ...
650 case "002" : // Server information 651 case "002": // Server information
651 case "003" : // Welcome ... 652 case "003": // Welcome ...
652 break; 653 break;
653 case "004" : // Server information 654 case "004": // Server information
654 m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms); 655 m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms);
655 commArgs = parms.Split(CS_SPACE); 656 commArgs = parms.Split(CS_SPACE);
656 c_server = commArgs[1]; 657 c_server = commArgs[1];
657 m_server = c_server; 658 m_server = c_server;
658 version = commArgs[2]; 659 version = commArgs[2];
659 usermod = commArgs[3]; 660 usermod = commArgs[3];
660 chanmod = commArgs[4]; 661 chanmod = commArgs[4];
661 break; 662 break;
662 case "005" : // Server information 663 case "005": // Server information
663 break; 664 break;
664 case "042" : 665 case "042":
665 case "250" : 666 case "250":
666 case "251" : 667 case "251":
667 case "252" : 668 case "252":
668 case "254" : 669 case "254":
669 case "255" : 670 case "255":
670 case "265" : 671 case "265":
671 case "266" : 672 case "266":
672 case "332" : // Subject 673 case "332": // Subject
673 case "333" : // Subject owner (?) 674 case "333": // Subject owner (?)
674 case "353" : // Name list 675 case "353": // Name list
675 case "366" : // End-of-Name list marker 676 case "366": // End-of-Name list marker
676 case "372" : // MOTD body 677 case "372": // MOTD body
677 case "375" : // MOTD start 678 case "375": // MOTD start
678 // m_log.InfoFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]); 679 // m_log.InfoFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]);
679 break; 680 break;
680 case "376" : // MOTD end 681 case "376": // MOTD end
681 // m_log.InfoFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]); 682 // m_log.InfoFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]);
682 motd = true; 683 motd = true;
683 break; 684 break;
684 case "451" : // Not registered 685 case "451": // Not registered
685 break; 686 break;
686 case "433" : // Nickname in use 687 case "433": // Nickname in use
687 // Gen a new name 688 // Gen a new name
688 m_nick = m_baseNick + Util.RandomClass.Next(1, 99); 689 m_nick = m_baseNick + Util.RandomClass.Next(1, 99);
689 m_log.ErrorFormat("[IRC-Connector-{0}]: [{1}] IRC SERVER reports NicknameInUse, trying {2}", idn, cmd, m_nick); 690 m_log.ErrorFormat("[IRC-Connector-{0}]: [{1}] IRC SERVER reports NicknameInUse, trying {2}", idn, cmd, m_nick);
@@ -695,29 +696,29 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
695 m_writer.WriteLine(String.Format("JOIN {0}", m_ircChannel)); 696 m_writer.WriteLine(String.Format("JOIN {0}", m_ircChannel));
696 m_writer.Flush(); 697 m_writer.Flush();
697 break; 698 break;
698 case "479" : // Bad channel name, etc. This will never work, so disable the connection 699 case "479": // Bad channel name, etc. This will never work, so disable the connection
699 m_log.ErrorFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]); 700 m_log.ErrorFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE, 2)[1]);
700 m_log.ErrorFormat("[IRC-Connector-{0}] [{1}] Connector disabled", idn, cmd); 701 m_log.ErrorFormat("[IRC-Connector-{0}] [{1}] Connector disabled", idn, cmd);
701 m_enabled = false; 702 m_enabled = false;
702 m_connected = false; 703 m_connected = false;
703 m_pending = false; 704 m_pending = false;
704 break; 705 break;
705 case "NOTICE" : 706 case "NOTICE":
706 // m_log.WarnFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]); 707 // m_log.WarnFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]);
707 break; 708 break;
708 case "ERROR" : 709 case "ERROR":
709 m_log.ErrorFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]); 710 m_log.ErrorFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE, 2)[1]);
710 if (parms.Contains("reconnect too fast")) 711 if (parms.Contains("reconnect too fast"))
711 ICCD_PERIOD++; 712 ICCD_PERIOD++;
712 m_pending = false; 713 m_pending = false;
713 Reconnect(); 714 Reconnect();
714 break; 715 break;
715 case "PING" : 716 case "PING":
716 m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms); 717 m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms);
717 m_writer.WriteLine(String.Format("PONG {0}", parms)); 718 m_writer.WriteLine(String.Format("PONG {0}", parms));
718 m_writer.Flush(); 719 m_writer.Flush();
719 break; 720 break;
720 case "PONG" : 721 case "PONG":
721 break; 722 break;
722 case "JOIN": 723 case "JOIN":
723 if (m_pending) 724 if (m_pending)
@@ -748,19 +749,19 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
748 m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms); 749 m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms);
749 eventIrcQuit(pfx, cmd, parms); 750 eventIrcQuit(pfx, cmd, parms);
750 break; 751 break;
751 default : 752 default:
752 m_log.DebugFormat("[IRC-Connector-{0}] Command '{1}' ignored, parms = {2}", idn, cmd, parms); 753 m_log.DebugFormat("[IRC-Connector-{0}] Command '{1}' ignored, parms = {2}", idn, cmd, parms);
753 break; 754 break;
754 } 755 }
755 756
756 // m_log.DebugFormat("[IRC-Connector-{0}] prefix = <{1}> cmd = <{2}> complete", idn, pfx, cmd); 757 // m_log.DebugFormat("[IRC-Connector-{0}] prefix = <{1}> cmd = <{2}> complete", idn, pfx, cmd);
757 758
758 } 759 }
759 760
760 public void eventIrcJoin(string prefix, string command, string parms) 761 public void eventIrcJoin(string prefix, string command, string parms)
761 { 762 {
762 string[] args = parms.Split(CS_SPACE,2); 763 string[] args = parms.Split(CS_SPACE, 2);
763 string IrcUser = prefix.Split('!')[0]; 764 string IrcUser = prefix.Split('!')[0];
764 string IrcChannel = args[0]; 765 string IrcChannel = args[0];
765 766
766 if (IrcChannel.StartsWith(":")) 767 if (IrcChannel.StartsWith(":"))
@@ -772,8 +773,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
772 773
773 public void eventIrcPart(string prefix, string command, string parms) 774 public void eventIrcPart(string prefix, string command, string parms)
774 { 775 {
775 string[] args = parms.Split(CS_SPACE,2); 776 string[] args = parms.Split(CS_SPACE, 2);
776 string IrcUser = prefix.Split('!')[0]; 777 string IrcUser = prefix.Split('!')[0];
777 string IrcChannel = args[0]; 778 string IrcChannel = args[0];
778 779
779 m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCPart {1}:{2}", idn, m_server, m_ircChannel); 780 m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCPart {1}:{2}", idn, m_server, m_ircChannel);
@@ -782,7 +783,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
782 783
783 public void eventIrcMode(string prefix, string command, string parms) 784 public void eventIrcMode(string prefix, string command, string parms)
784 { 785 {
785 string[] args = parms.Split(CS_SPACE,2); 786 string[] args = parms.Split(CS_SPACE, 2);
786 string UserMode = args[1]; 787 string UserMode = args[1];
787 788
788 m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCMode {1}:{2}", idn, m_server, m_ircChannel); 789 m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCMode {1}:{2}", idn, m_server, m_ircChannel);
@@ -794,7 +795,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
794 795
795 public void eventIrcNickChange(string prefix, string command, string parms) 796 public void eventIrcNickChange(string prefix, string command, string parms)
796 { 797 {
797 string[] args = parms.Split(CS_SPACE,2); 798 string[] args = parms.Split(CS_SPACE, 2);
798 string UserOldNick = prefix.Split('!')[0]; 799 string UserOldNick = prefix.Split('!')[0];
799 string UserNewNick = args[0].Remove(0, 1); 800 string UserNewNick = args[0].Remove(0, 1);
800 801
@@ -804,11 +805,11 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
804 805
805 public void eventIrcKick(string prefix, string command, string parms) 806 public void eventIrcKick(string prefix, string command, string parms)
806 { 807 {
807 string[] args = parms.Split(CS_SPACE,3); 808 string[] args = parms.Split(CS_SPACE, 3);
808 string UserKicker = prefix.Split('!')[0]; 809 string UserKicker = prefix.Split('!')[0];
809 string IrcChannel = args[0]; 810 string IrcChannel = args[0];
810 string UserKicked = args[1]; 811 string UserKicked = args[1];
811 string KickMessage = args[2]; 812 string KickMessage = args[2];
812 813
813 m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCKick {1}:{2}", idn, m_server, m_ircChannel); 814 m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCKick {1}:{2}", idn, m_server, m_ircChannel);
814 BroadcastSim(UserKicker, "/me kicks kicks {0} off {1} saying \"{2}\"", UserKicked, IrcChannel, KickMessage); 815 BroadcastSim(UserKicker, "/me kicks kicks {0} off {1} saying \"{2}\"", UserKicked, IrcChannel, KickMessage);
@@ -822,7 +823,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
822 823
823 public void eventIrcQuit(string prefix, string command, string parms) 824 public void eventIrcQuit(string prefix, string command, string parms)
824 { 825 {
825 string IrcUser = prefix.Split('!')[0]; 826 string IrcUser = prefix.Split('!')[0];
826 string QuitMessage = parms; 827 string QuitMessage = parms;
827 828
828 m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCQuit {1}:{2}", idn, m_server, m_ircChannel); 829 m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCQuit {1}:{2}", idn, m_server, m_ircChannel);
@@ -842,65 +843,65 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
842 843
843 // m_log.InfoFormat("[IRC-Watchdog] Status scan, pdk = {0}, icc = {1}", _pdk_, _icc_); 844 // m_log.InfoFormat("[IRC-Watchdog] Status scan, pdk = {0}, icc = {1}", _pdk_, _icc_);
844 845
845 _pdk_ = (_pdk_+1)%PING_PERIOD; // cycle the ping trigger 846 _pdk_ = (_pdk_ + 1) % PING_PERIOD; // cycle the ping trigger
846 _icc_++; // increment the inter-consecutive-connect-delay counter 847 _icc_++; // increment the inter-consecutive-connect-delay counter
847 848
848 lock (m_connectors) 849 lock (m_connectors)
849 foreach (IRCConnector connector in m_connectors) 850 foreach (IRCConnector connector in m_connectors)
850 { 851 {
851 852
852 // m_log.InfoFormat("[IRC-Watchdog] Scanning {0}", connector); 853 // m_log.InfoFormat("[IRC-Watchdog] Scanning {0}", connector);
853 854
854 if (connector.Enabled) 855 if (connector.Enabled)
855 {
856 if (!connector.Connected)
857 { 856 {
858 try 857 if (!connector.Connected)
859 { 858 {
860 // m_log.DebugFormat("[IRC-Watchdog] Connecting {1}:{2}", connector.idn, connector.m_server, connector.m_ircChannel); 859 try
861 connector.Connect(); 860 {
861 // m_log.DebugFormat("[IRC-Watchdog] Connecting {1}:{2}", connector.idn, connector.m_server, connector.m_ircChannel);
862 connector.Connect();
863 }
864 catch (Exception e)
865 {
866 m_log.ErrorFormat("[IRC-Watchdog] Exception on connector {0}: {1} ", connector.idn, e.Message);
867 }
862 } 868 }
863 catch (Exception e) 869 else
864 { 870 {
865 m_log.ErrorFormat("[IRC-Watchdog] Exception on connector {0}: {1} ", connector.idn, e.Message);
866 }
867 }
868 else
869 {
870 871
871 if (connector.m_pending) 872 if (connector.m_pending)
872 {
873 if (connector.m_timeout == 0)
874 { 873 {
875 m_log.ErrorFormat("[IRC-Watchdog] Login timed-out for connector {0}, reconnecting", connector.idn); 874 if (connector.m_timeout == 0)
876 connector.Reconnect(); 875 {
876 m_log.ErrorFormat("[IRC-Watchdog] Login timed-out for connector {0}, reconnecting", connector.idn);
877 connector.Reconnect();
878 }
879 else
880 connector.m_timeout--;
877 } 881 }
878 else
879 connector.m_timeout--;
880 }
881 882
882 // Being marked connected is not enough to ping. Socket establishment can sometimes take a long 883 // Being marked connected is not enough to ping. Socket establishment can sometimes take a long
883 // time, in which case the watch dog might try to ping the server before the socket has been 884 // time, in which case the watch dog might try to ping the server before the socket has been
884 // set up, with nasty side-effects. 885 // set up, with nasty side-effects.
885 886
886 else if (_pdk_ == 0) 887 else if (_pdk_ == 0)
887 {
888 try
889 {
890 connector.m_writer.WriteLine(String.Format("PING :{0}", connector.m_server));
891 connector.m_writer.Flush();
892 }
893 catch (Exception e)
894 { 888 {
895 m_log.ErrorFormat("[IRC-PingRun] Exception on connector {0}: {1} ", connector.idn, e.Message); 889 try
896 m_log.Debug(e); 890 {
897 connector.Reconnect(); 891 connector.m_writer.WriteLine(String.Format("PING :{0}", connector.m_server));
892 connector.m_writer.Flush();
893 }
894 catch (Exception e)
895 {
896 m_log.ErrorFormat("[IRC-PingRun] Exception on connector {0}: {1} ", connector.idn, e.Message);
897 m_log.Debug(e);
898 connector.Reconnect();
899 }
898 } 900 }
899 }
900 901
902 }
901 } 903 }
902 } 904 }
903 }
904 905
905 // m_log.InfoFormat("[IRC-Watchdog] Status scan completed"); 906 // m_log.InfoFormat("[IRC-Watchdog] Status scan completed");
906 907
diff --git a/OpenSim/Region/OptionalModules/Avatar/Chat/RegionState.cs b/OpenSim/Region/OptionalModules/Avatar/Chat/RegionState.cs
index 53b103e..5505001 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Chat/RegionState.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Chat/RegionState.cs
@@ -41,49 +41,73 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
41 41
42 internal class RegionState 42 internal class RegionState
43 { 43 {
44
45 private static readonly ILog m_log = 44 private static readonly ILog m_log =
46 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 45 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
47 46
47 // This computation is not the real region center if the region is larger than 256.
48 // This computation isn't fixed because there is not a handle back to the region.
48 private static readonly OpenMetaverse.Vector3 CenterOfRegion = new OpenMetaverse.Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 20); 49 private static readonly OpenMetaverse.Vector3 CenterOfRegion = new OpenMetaverse.Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 20);
49 private const int DEBUG_CHANNEL = 2147483647; 50 private const int DEBUG_CHANNEL = 2147483647;
50 51
51 private static int _idk_ = 0; 52 private static int _idk_ = 0;
52 53
53 // Runtime variables; these values are assigned when the 54 // Runtime variables; these values are assigned when the
54 // IrcState is created and remain constant thereafter. 55 // IrcState is created and remain constant thereafter.
55 56
56 internal string Region = String.Empty; 57 internal string Region = String.Empty;
57 internal string Host = String.Empty; 58 internal string Host = String.Empty;
58 internal string LocX = String.Empty; 59 internal string LocX = String.Empty;
59 internal string LocY = String.Empty; 60 internal string LocY = String.Empty;
60 internal string IDK = String.Empty; 61 internal string IDK = String.Empty;
61 62
62 // System values - used only be the IRC classes themselves 63 // System values - used only be the IRC classes themselves
63 64
64 internal ChannelState cs = null; // associated IRC configuration 65 internal ChannelState cs = null; // associated IRC configuration
65 internal Scene scene = null; // associated scene 66 internal Scene scene = null; // associated scene
66 internal IConfig config = null; // configuration file reference 67 internal IConfig config = null; // configuration file reference
67 internal bool enabled = true; 68 internal bool enabled = true;
68 69
70 //AgentAlert
71 internal bool showAlert = false;
72 internal string alertMessage = String.Empty;
73 internal IDialogModule dialogModule = null;
74
69 // This list is used to keep track of who is here, and by 75 // This list is used to keep track of who is here, and by
70 // implication, who is not. 76 // implication, who is not.
71 77
72 internal List<IClientAPI> clients = new List<IClientAPI>(); 78 internal List<IClientAPI> clients = new List<IClientAPI>();
73 79
74 // Setup runtime variable values 80 // Setup runtime variable values
75 81
76 public RegionState(Scene p_scene, IConfig p_config) 82 public RegionState(Scene p_scene, IConfig p_config)
77 { 83 {
78 84 scene = p_scene;
79 scene = p_scene;
80 config = p_config; 85 config = p_config;
81 86
82 Region = scene.RegionInfo.RegionName; 87 Region = scene.RegionInfo.RegionName;
83 Host = scene.RegionInfo.ExternalHostName; 88 Host = scene.RegionInfo.ExternalHostName;
84 LocX = Convert.ToString(scene.RegionInfo.RegionLocX); 89 LocX = Convert.ToString(scene.RegionInfo.RegionLocX);
85 LocY = Convert.ToString(scene.RegionInfo.RegionLocY); 90 LocY = Convert.ToString(scene.RegionInfo.RegionLocY);
86 IDK = Convert.ToString(_idk_++); 91 IDK = Convert.ToString(_idk_++);
92
93 showAlert = config.GetBoolean("alert_show", false);
94 string alertServerInfo = String.Empty;
95
96 if (showAlert)
97 {
98 bool showAlertServerInfo = config.GetBoolean("alert_show_serverinfo", true);
99
100 if (showAlertServerInfo)
101 alertServerInfo = String.Format("\nServer: {0}\nPort: {1}\nChannel: {2}\n\n",
102 config.GetString("server", ""), config.GetString("port", ""), config.GetString("channel", ""));
103
104 string alertPreMessage = config.GetString("alert_msg_pre", "This region is linked to Irc.");
105 string alertPostMessage = config.GetString("alert_msg_post", "Everything you say in public chat can be listened.");
106
107 alertMessage = String.Format("{0}\n{1}{2}", alertPreMessage, alertServerInfo, alertPostMessage);
108
109 dialogModule = scene.RequestModuleInterface<IDialogModule>();
110 }
87 111
88 // OpenChannel conditionally establishes a connection to the 112 // OpenChannel conditionally establishes a connection to the
89 // IRC server. The request will either succeed, or it will 113 // IRC server. The request will either succeed, or it will
@@ -93,9 +117,9 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
93 117
94 // Connect channel to world events 118 // Connect channel to world events
95 119
96 scene.EventManager.OnChatFromWorld += OnSimChat; 120 scene.EventManager.OnChatFromWorld += OnSimChat;
97 scene.EventManager.OnChatFromClient += OnSimChat; 121 scene.EventManager.OnChatFromClient += OnSimChat;
98 scene.EventManager.OnMakeRootAgent += OnMakeRootAgent; 122 scene.EventManager.OnMakeRootAgent += OnMakeRootAgent;
99 scene.EventManager.OnMakeChildAgent += OnMakeChildAgent; 123 scene.EventManager.OnMakeChildAgent += OnMakeChildAgent;
100 124
101 m_log.InfoFormat("[IRC-Region {0}] Initialization complete", Region); 125 m_log.InfoFormat("[IRC-Region {0}] Initialization complete", Region);
@@ -106,8 +130,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
106 130
107 ~RegionState() 131 ~RegionState()
108 { 132 {
109 if (cs != null) 133 if (cs != null)
110 cs.RemoveRegion(this); 134 cs.RemoveRegion(this);
111 } 135 }
112 136
113 // Called by PostInitialize after all regions have been created 137 // Called by PostInitialize after all regions have been created
@@ -138,7 +162,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
138 { 162 {
139 if (clients.Contains(client)) 163 if (clients.Contains(client))
140 { 164 {
141 if (enabled && (cs.irc.Enabled) && (cs.irc.Connected) && (cs.ClientReporting)) 165 if (enabled && (cs.irc.Enabled) && (cs.irc.Connected) && (cs.ClientReporting))
142 { 166 {
143 m_log.InfoFormat("[IRC-Region {0}]: {1} has left", Region, client.Name); 167 m_log.InfoFormat("[IRC-Region {0}]: {1} has left", Region, client.Name);
144 //Check if this person is excluded from IRC 168 //Check if this person is excluded from IRC
@@ -147,7 +171,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
147 cs.irc.PrivMsg(cs.NoticeMessageFormat, cs.irc.Nick, Region, String.Format("{0} has left", client.Name)); 171 cs.irc.PrivMsg(cs.NoticeMessageFormat, cs.irc.Nick, Region, String.Format("{0} has left", client.Name));
148 } 172 }
149 } 173 }
150 client.OnLogout -= OnClientLoggedOut; 174 client.OnLogout -= OnClientLoggedOut;
151 client.OnConnectionClosed -= OnClientLoggedOut; 175 client.OnConnectionClosed -= OnClientLoggedOut;
152 clients.Remove(client); 176 clients.Remove(client);
153 } 177 }
@@ -171,13 +195,13 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
171 { 195 {
172 if (clients.Contains(client)) 196 if (clients.Contains(client))
173 { 197 {
174 if (enabled && (cs.irc.Enabled) && (cs.irc.Connected) && (cs.ClientReporting)) 198 if (enabled && (cs.irc.Enabled) && (cs.irc.Connected) && (cs.ClientReporting))
175 { 199 {
176 string clientName = String.Format("{0} {1}", presence.Firstname, presence.Lastname); 200 string clientName = String.Format("{0} {1}", presence.Firstname, presence.Lastname);
177 m_log.DebugFormat("[IRC-Region {0}] {1} has left", Region, clientName); 201 m_log.DebugFormat("[IRC-Region {0}] {1} has left", Region, clientName);
178 cs.irc.PrivMsg(cs.NoticeMessageFormat, cs.irc.Nick, Region, String.Format("{0} has left", clientName)); 202 cs.irc.PrivMsg(cs.NoticeMessageFormat, cs.irc.Nick, Region, String.Format("{0} has left", clientName));
179 } 203 }
180 client.OnLogout -= OnClientLoggedOut; 204 client.OnLogout -= OnClientLoggedOut;
181 client.OnConnectionClosed -= OnClientLoggedOut; 205 client.OnConnectionClosed -= OnClientLoggedOut;
182 clients.Remove(client); 206 clients.Remove(client);
183 } 207 }
@@ -195,14 +219,13 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
195 219
196 private void OnMakeRootAgent(ScenePresence presence) 220 private void OnMakeRootAgent(ScenePresence presence)
197 { 221 {
198
199 IClientAPI client = presence.ControllingClient; 222 IClientAPI client = presence.ControllingClient;
200 223
201 try 224 try
202 { 225 {
203 if (!clients.Contains(client)) 226 if (!clients.Contains(client))
204 { 227 {
205 client.OnLogout += OnClientLoggedOut; 228 client.OnLogout += OnClientLoggedOut;
206 client.OnConnectionClosed += OnClientLoggedOut; 229 client.OnConnectionClosed += OnClientLoggedOut;
207 clients.Add(client); 230 clients.Add(client);
208 if (enabled && (cs.irc.Enabled) && (cs.irc.Connected) && (cs.ClientReporting)) 231 if (enabled && (cs.irc.Enabled) && (cs.irc.Connected) && (cs.ClientReporting))
@@ -216,17 +239,18 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
216 } 239 }
217 } 240 }
218 } 241 }
242
243 if (dialogModule != null && showAlert)
244 dialogModule.SendAlertToUser(client, alertMessage, true);
219 } 245 }
220 catch (Exception ex) 246 catch (Exception ex)
221 { 247 {
222 m_log.ErrorFormat("[IRC-Region {0}]: MakeRootAgent exception: {1}", Region, ex.Message); 248 m_log.ErrorFormat("[IRC-Region {0}]: MakeRootAgent exception: {1}", Region, ex.Message);
223 m_log.Debug(ex); 249 m_log.Debug(ex);
224 } 250 }
225
226 } 251 }
227 252
228 // This handler detects chat events int he virtual world. 253 // This handler detects chat events int he virtual world.
229
230 public void OnSimChat(Object sender, OSChatMessage msg) 254 public void OnSimChat(Object sender, OSChatMessage msg)
231 { 255 {
232 256
@@ -317,14 +341,14 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
317 // that evident. 341 // that evident.
318 342
319 default: 343 default:
320 m_log.DebugFormat("[IRC-Region {0}] Forwarding unrecognized command to IRC : {1}", 344 m_log.DebugFormat("[IRC-Region {0}] Forwarding unrecognized command to IRC : {1}",
321 Region, msg.Message); 345 Region, msg.Message);
322 cs.irc.Send(msg.Message); 346 cs.irc.Send(msg.Message);
323 break; 347 break;
324 } 348 }
325 } 349 }
326 catch (Exception ex) 350 catch (Exception ex)
327 { 351 {
328 m_log.WarnFormat("[IRC-Region {0}] error processing in-world command channel input: {1}", 352 m_log.WarnFormat("[IRC-Region {0}] error processing in-world command channel input: {1}",
329 Region, ex.Message); 353 Region, ex.Message);
330 m_log.Debug(ex); 354 m_log.Debug(ex);
@@ -366,7 +390,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
366 390
367 m_log.DebugFormat("[IRC-Region {0}] heard on channel {1} : {2}", Region, msg.Channel, msg.Message); 391 m_log.DebugFormat("[IRC-Region {0}] heard on channel {1} : {2}", Region, msg.Channel, msg.Message);
368 392
369 if (null != avatar && cs.RelayChat && (msg.Channel == 0 || msg.Channel == DEBUG_CHANNEL)) 393 if (null != avatar && cs.RelayChat && (msg.Channel == 0 || msg.Channel == DEBUG_CHANNEL))
370 { 394 {
371 string txt = msg.Message; 395 string txt = msg.Message;
372 if (txt.StartsWith("/me ")) 396 if (txt.StartsWith("/me "))
@@ -376,13 +400,13 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
376 return; 400 return;
377 } 401 }
378 402
379 if (null == avatar && cs.RelayPrivateChannels && null != cs.AccessPassword && 403 if (null == avatar && cs.RelayPrivateChannels && null != cs.AccessPassword &&
380 msg.Channel == cs.RelayChannelOut) 404 msg.Channel == cs.RelayChannelOut)
381 { 405 {
382 Match m = cs.AccessPasswordRegex.Match(msg.Message); 406 Match m = cs.AccessPasswordRegex.Match(msg.Message);
383 if (null != m) 407 if (null != m)
384 { 408 {
385 m_log.DebugFormat("[IRC] relaying message from {0}: {1}", m.Groups["avatar"].ToString(), 409 m_log.DebugFormat("[IRC] relaying message from {0}: {1}", m.Groups["avatar"].ToString(),
386 m.Groups["message"].ToString()); 410 m.Groups["message"].ToString());
387 cs.irc.PrivMsg(cs.PrivateMessageFormat, m.Groups["avatar"].ToString(), 411 cs.irc.PrivMsg(cs.PrivateMessageFormat, m.Groups["avatar"].ToString(),
388 scene.RegionInfo.RegionName, m.Groups["message"].ToString()); 412 scene.RegionInfo.RegionName, m.Groups["message"].ToString());
diff --git a/OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeModule.cs b/OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeModule.cs
index 018357a..c48e585 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeModule.cs
@@ -375,11 +375,13 @@ namespace OpenSim.Region.OptionalModules.Avatar.Concierge
375 scene.GetRootAgentCount(), scene.RegionInfo.RegionName, 375 scene.GetRootAgentCount(), scene.RegionInfo.RegionName,
376 scene.RegionInfo.RegionID, 376 scene.RegionInfo.RegionID,
377 DateTime.UtcNow.ToString("s"))); 377 DateTime.UtcNow.ToString("s")));
378
378 scene.ForEachRootScenePresence(delegate(ScenePresence sp) 379 scene.ForEachRootScenePresence(delegate(ScenePresence sp)
379 { 380 {
380 list.Append(String.Format(" <avatar name=\"{0}\" uuid=\"{1}\" />\n", sp.Name, sp.UUID)); 381 list.Append(String.Format(" <avatar name=\"{0}\" uuid=\"{1}\" />\n", sp.Name, sp.UUID));
381 list.Append("</avatars>");
382 }); 382 });
383
384 list.Append("</avatars>");
383 string payload = list.ToString(); 385 string payload = list.ToString();
384 386
385 // post via REST to broker 387 // post via REST to broker
diff --git a/OpenSim/Region/OptionalModules/Avatar/SitStand/SitStandCommandsModule.cs b/OpenSim/Region/OptionalModules/Avatar/SitStand/SitStandCommandsModule.cs
new file mode 100644
index 0000000..5a6b284
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/Avatar/SitStand/SitStandCommandsModule.cs
@@ -0,0 +1,220 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Reflection;
32using System.Text;
33using System.Text.RegularExpressions;
34using log4net;
35using Mono.Addins;
36using NDesk.Options;
37using Nini.Config;
38using OpenMetaverse;
39using OpenSim.Framework;
40using OpenSim.Framework.Console;
41using OpenSim.Region.Framework.Interfaces;
42using OpenSim.Region.Framework.Scenes;
43
44namespace OpenSim.Region.OptionalModules.Avatar.SitStand
45{
46 /// <summary>
47 /// A module that just holds commands for changing avatar sitting and standing states.
48 /// </summary>
49 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "AnimationsCommandModule")]
50 public class SitStandCommandModule : INonSharedRegionModule
51 {
52// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
53
54 private Scene m_scene;
55
56 public string Name { get { return "SitStand Command Module"; } }
57
58 public Type ReplaceableInterface { get { return null; } }
59
60 public void Initialise(IConfigSource source)
61 {
62// m_log.DebugFormat("[ANIMATIONS COMMAND MODULE]: INITIALIZED MODULE");
63 }
64
65 public void PostInitialise()
66 {
67// m_log.DebugFormat("[ANIMATIONS COMMAND MODULE]: POST INITIALIZED MODULE");
68 }
69
70 public void Close()
71 {
72// m_log.DebugFormat("[ANIMATIONS COMMAND MODULE]: CLOSED MODULE");
73 }
74
75 public void AddRegion(Scene scene)
76 {
77// m_log.DebugFormat("[ANIMATIONS COMMAND MODULE]: REGION {0} ADDED", scene.RegionInfo.RegionName);
78 }
79
80 public void RemoveRegion(Scene scene)
81 {
82// m_log.DebugFormat("[ATTACHMENTS COMMAND MODULE]: REGION {0} REMOVED", scene.RegionInfo.RegionName);
83 }
84
85 public void RegionLoaded(Scene scene)
86 {
87// m_log.DebugFormat("[ANIMATIONS COMMAND MODULE]: REGION {0} LOADED", scene.RegionInfo.RegionName);
88
89 m_scene = scene;
90
91 scene.AddCommand(
92 "Users", this, "sit user name",
93 "sit user name [--regex] <first-name> <last-name>",
94 "Sit the named user on an unoccupied object with a sit target.",
95 "If there are no such objects then nothing happens.\n"
96 + "If --regex is specified then the names are treated as regular expressions.",
97 HandleSitUserNameCommand);
98
99 scene.AddCommand(
100 "Users", this, "stand user name",
101 "stand user name [--regex] <first-name> <last-name>",
102 "Stand the named user.",
103 "If --regex is specified then the names are treated as regular expressions.",
104 HandleStandUserNameCommand);
105 }
106
107 private void HandleSitUserNameCommand(string module, string[] cmd)
108 {
109 if (MainConsole.Instance.ConsoleScene != m_scene && MainConsole.Instance.ConsoleScene != null)
110 return;
111
112 if (cmd.Length < 5)
113 {
114 MainConsole.Instance.Output("Usage: sit user name [--regex] <first-name> <last-name>");
115 return;
116 }
117
118 List<ScenePresence> scenePresences = GetScenePresences(cmd);
119
120 foreach (ScenePresence sp in scenePresences)
121 {
122 if (sp.SitGround || sp.IsSatOnObject)
123 continue;
124
125 SceneObjectPart sitPart = null;
126 List<SceneObjectGroup> sceneObjects = m_scene.GetSceneObjectGroups();
127
128 foreach (SceneObjectGroup sceneObject in sceneObjects)
129 {
130 if (sceneObject.IsAttachment)
131 continue;
132
133 foreach (SceneObjectPart part in sceneObject.Parts)
134 {
135 if (part.IsSitTargetSet && part.SitTargetAvatar == UUID.Zero)
136 {
137 sitPart = part;
138 break;
139 }
140 }
141 }
142
143 if (sitPart != null)
144 {
145 MainConsole.Instance.OutputFormat(
146 "Sitting {0} on {1} {2} in {3}",
147 sp.Name, sitPart.ParentGroup.Name, sitPart.ParentGroup.UUID, m_scene.Name);
148
149 sp.HandleAgentRequestSit(sp.ControllingClient, sp.UUID, sitPart.UUID, Vector3.Zero);
150 sp.HandleAgentSit(sp.ControllingClient, sp.UUID);
151 }
152 else
153 {
154 MainConsole.Instance.OutputFormat(
155 "Could not find any unoccupied set seat on which to sit {0} in {1}. Aborting",
156 sp.Name, m_scene.Name);
157
158 break;
159 }
160 }
161 }
162
163 private void HandleStandUserNameCommand(string module, string[] cmd)
164 {
165 if (MainConsole.Instance.ConsoleScene != m_scene && MainConsole.Instance.ConsoleScene != null)
166 return;
167
168 if (cmd.Length < 5)
169 {
170 MainConsole.Instance.Output("Usage: stand user name [--regex] <first-name> <last-name>");
171 return;
172 }
173
174 List<ScenePresence> scenePresences = GetScenePresences(cmd);
175
176 foreach (ScenePresence sp in scenePresences)
177 {
178 if (sp.SitGround || sp.IsSatOnObject)
179 {
180 MainConsole.Instance.OutputFormat("Standing {0} in {1}", sp.Name, m_scene.Name);
181 sp.StandUp();
182 }
183 }
184 }
185
186 private List<ScenePresence> GetScenePresences(string[] cmdParams)
187 {
188 bool useRegex = false;
189 OptionSet options = new OptionSet().Add("regex", v=> useRegex = v != null );
190
191 List<string> mainParams = options.Parse(cmdParams);
192
193 string firstName = mainParams[3];
194 string lastName = mainParams[4];
195
196 List<ScenePresence> scenePresencesMatched = new List<ScenePresence>();
197
198 if (useRegex)
199 {
200 Regex nameRegex = new Regex(string.Format("{0} {1}", firstName, lastName));
201 List<ScenePresence> scenePresences = m_scene.GetScenePresences();
202
203 foreach (ScenePresence sp in scenePresences)
204 {
205 if (!sp.IsChildAgent && nameRegex.IsMatch(sp.Name))
206 scenePresencesMatched.Add(sp);
207 }
208 }
209 else
210 {
211 ScenePresence sp = m_scene.GetScenePresence(firstName, lastName);
212
213 if (sp != null && !sp.IsChildAgent)
214 scenePresencesMatched.Add(sp);
215 }
216
217 return scenePresencesMatched;
218 }
219 }
220} \ No newline at end of file
diff --git a/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs b/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs
index 37ab35a..45af212 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs
@@ -65,7 +65,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice
65 // Capability string prefixes 65 // Capability string prefixes
66 private static readonly string m_parcelVoiceInfoRequestPath = "0207/"; 66 private static readonly string m_parcelVoiceInfoRequestPath = "0207/";
67 private static readonly string m_provisionVoiceAccountRequestPath = "0208/"; 67 private static readonly string m_provisionVoiceAccountRequestPath = "0208/";
68 private static readonly string m_chatSessionRequestPath = "0209/"; 68 //private static readonly string m_chatSessionRequestPath = "0209/";
69 69
70 // Control info 70 // Control info
71 private static bool m_Enabled = false; 71 private static bool m_Enabled = false;
@@ -326,15 +326,15 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice
326 "ParcelVoiceInfoRequest", 326 "ParcelVoiceInfoRequest",
327 agentID.ToString())); 327 agentID.ToString()));
328 328
329 caps.RegisterHandler( 329 //caps.RegisterHandler(
330 "ChatSessionRequest", 330 // "ChatSessionRequest",
331 new RestStreamHandler( 331 // new RestStreamHandler(
332 "POST", 332 // "POST",
333 capsBase + m_chatSessionRequestPath, 333 // capsBase + m_chatSessionRequestPath,
334 (request, path, param, httpRequest, httpResponse) 334 // (request, path, param, httpRequest, httpResponse)
335 => ChatSessionRequest(scene, request, path, param, agentID, caps), 335 // => ChatSessionRequest(scene, request, path, param, agentID, caps),
336 "ChatSessionRequest", 336 // "ChatSessionRequest",
337 agentID.ToString())); 337 // agentID.ToString()));
338 } 338 }
339 339
340 /// <summary> 340 /// <summary>
@@ -551,13 +551,20 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice
551 reqStream.Close(); 551 reqStream.Close();
552 } 552 }
553 553
554 HttpWebResponse fwdrsp = (HttpWebResponse)forwardreq.GetResponse(); 554 using (HttpWebResponse fwdrsp = (HttpWebResponse)forwardreq.GetResponse())
555 Encoding encoding = Util.UTF8; 555 {
556 StreamReader fwdresponsestream = new StreamReader(fwdrsp.GetResponseStream(), encoding); 556 Encoding encoding = Util.UTF8;
557 fwdresponsestr = fwdresponsestream.ReadToEnd(); 557
558 fwdresponsecontenttype = fwdrsp.ContentType; 558 using (Stream s = fwdrsp.GetResponseStream())
559 fwdresponsecode = (int)fwdrsp.StatusCode; 559 {
560 fwdresponsestream.Close(); 560 using (StreamReader fwdresponsestream = new StreamReader(s))
561 {
562 fwdresponsestr = fwdresponsestream.ReadToEnd();
563 fwdresponsecontenttype = fwdrsp.ContentType;
564 fwdresponsecode = (int)fwdrsp.StatusCode;
565 }
566 }
567 }
561 568
562 response["content_type"] = fwdresponsecontenttype; 569 response["content_type"] = fwdresponsecontenttype;
563 response["str_response_string"] = fwdresponsestr; 570 response["str_response_string"] = fwdresponsestr;
diff --git a/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs b/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs
index 881807a..dd44564 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs
@@ -92,7 +92,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice
92 // Capability strings 92 // Capability strings
93 private static readonly string m_parcelVoiceInfoRequestPath = "0107/"; 93 private static readonly string m_parcelVoiceInfoRequestPath = "0107/";
94 private static readonly string m_provisionVoiceAccountRequestPath = "0108/"; 94 private static readonly string m_provisionVoiceAccountRequestPath = "0108/";
95 private static readonly string m_chatSessionRequestPath = "0109/"; 95 //private static readonly string m_chatSessionRequestPath = "0109/";
96 96
97 // Control info, e.g. vivox server, admin user, admin password 97 // Control info, e.g. vivox server, admin user, admin password
98 private static bool m_pluginEnabled = false; 98 private static bool m_pluginEnabled = false;
@@ -117,6 +117,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice
117 117
118 private IConfig m_config; 118 private IConfig m_config;
119 119
120 private object m_Lock;
121
120 public void Initialise(IConfigSource config) 122 public void Initialise(IConfigSource config)
121 { 123 {
122 124
@@ -128,6 +130,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice
128 if (!m_config.GetBoolean("enabled", false)) 130 if (!m_config.GetBoolean("enabled", false))
129 return; 131 return;
130 132
133 m_Lock = new object();
134
131 try 135 try
132 { 136 {
133 // retrieve configuration variables 137 // retrieve configuration variables
@@ -429,15 +433,15 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice
429 "ParcelVoiceInfoRequest", 433 "ParcelVoiceInfoRequest",
430 agentID.ToString())); 434 agentID.ToString()));
431 435
432 caps.RegisterHandler( 436 //caps.RegisterHandler(
433 "ChatSessionRequest", 437 // "ChatSessionRequest",
434 new RestStreamHandler( 438 // new RestStreamHandler(
435 "POST", 439 // "POST",
436 capsBase + m_chatSessionRequestPath, 440 // capsBase + m_chatSessionRequestPath,
437 (request, path, param, httpRequest, httpResponse) 441 // (request, path, param, httpRequest, httpResponse)
438 => ChatSessionRequest(scene, request, path, param, agentID, caps), 442 // => ChatSessionRequest(scene, request, path, param, agentID, caps),
439 "ChatSessionRequest", 443 // "ChatSessionRequest",
440 agentID.ToString())); 444 // agentID.ToString()));
441 } 445 }
442 446
443 /// <summary> 447 /// <summary>
@@ -818,11 +822,11 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice
818 { 822 {
819 string requrl = String.Format(m_vivoxChannelPath, m_vivoxServer, "create", channelId, m_authToken); 823 string requrl = String.Format(m_vivoxChannelPath, m_vivoxServer, "create", channelId, m_authToken);
820 824
821 if (parent != null && parent != String.Empty) 825 if (!string.IsNullOrEmpty(parent))
822 { 826 {
823 requrl = String.Format("{0}&chan_parent={1}", requrl, parent); 827 requrl = String.Format("{0}&chan_parent={1}", requrl, parent);
824 } 828 }
825 if (description != null && description != String.Empty) 829 if (!string.IsNullOrEmpty(description))
826 { 830 {
827 requrl = String.Format("{0}&chan_desc={1}", requrl, description); 831 requrl = String.Format("{0}&chan_desc={1}", requrl, description);
828 } 832 }
@@ -832,7 +836,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice
832 requrl = String.Format("{0}&chan_roll_off={1}", requrl, m_vivoxChannelRollOff); 836 requrl = String.Format("{0}&chan_roll_off={1}", requrl, m_vivoxChannelRollOff);
833 requrl = String.Format("{0}&chan_dist_model={1}", requrl, m_vivoxChannelDistanceModel); 837 requrl = String.Format("{0}&chan_dist_model={1}", requrl, m_vivoxChannelDistanceModel);
834 requrl = String.Format("{0}&chan_max_range={1}", requrl, m_vivoxChannelMaximumRange); 838 requrl = String.Format("{0}&chan_max_range={1}", requrl, m_vivoxChannelMaximumRange);
835 requrl = String.Format("{0}&chan_ckamping_distance={1}", requrl, m_vivoxChannelClampingDistance); 839 requrl = String.Format("{0}&chan_clamping_distance={1}", requrl, m_vivoxChannelClampingDistance);
836 840
837 XmlElement resp = VivoxCall(requrl, true); 841 XmlElement resp = VivoxCall(requrl, true);
838 if (XmlFind(resp, "response.level0.body.chan_uri", out channelUri)) 842 if (XmlFind(resp, "response.level0.body.chan_uri", out channelUri))
@@ -858,7 +862,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice
858 // requrl = String.Format("{0}&chan_parent={1}", requrl, parent); 862 // requrl = String.Format("{0}&chan_parent={1}", requrl, parent);
859 // } 863 // }
860 864
861 if (description != null && description != String.Empty) 865 if (!string.IsNullOrEmpty(description))
862 { 866 {
863 requrl = String.Format("{0}&chan_desc={1}", requrl, description); 867 requrl = String.Format("{0}&chan_desc={1}", requrl, description);
864 } 868 }
@@ -1043,7 +1047,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice
1043 private XmlElement VivoxDeleteChannel(string parent, string channelid) 1047 private XmlElement VivoxDeleteChannel(string parent, string channelid)
1044 { 1048 {
1045 string requrl = String.Format(m_vivoxChannelDel, m_vivoxServer, "delete", channelid, m_authToken); 1049 string requrl = String.Format(m_vivoxChannelDel, m_vivoxServer, "delete", channelid, m_authToken);
1046 if (parent != null && parent != String.Empty) 1050 if (!string.IsNullOrEmpty(parent))
1047 { 1051 {
1048 requrl = String.Format("{0}&chan_parent={1}", requrl, parent); 1052 requrl = String.Format("{0}&chan_parent={1}", requrl, parent);
1049 } 1053 }
@@ -1111,27 +1115,32 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice
1111 1115
1112 doc = new XmlDocument(); 1116 doc = new XmlDocument();
1113 1117
1114 try 1118 // Let's serialize all calls to Vivox. Most of these are driven by
1119 // the clients (CAPs), when the user arrives at the region. We don't
1120 // want to issue many simultaneous http requests to Vivox, because mono
1121 // doesn't like that
1122 lock (m_Lock)
1115 { 1123 {
1116 // Otherwise prepare the request 1124 try
1117 m_log.DebugFormat("[VivoxVoice] Sending request <{0}>", requrl); 1125 {
1118 1126 // Otherwise prepare the request
1119 HttpWebRequest req = (HttpWebRequest)WebRequest.Create(requrl); 1127 m_log.DebugFormat("[VivoxVoice] Sending request <{0}>", requrl);
1120 HttpWebResponse rsp = null;
1121 1128
1122 // We are sending just parameters, no content 1129 HttpWebRequest req = (HttpWebRequest)WebRequest.Create(requrl);
1123 req.ContentLength = 0;
1124 1130
1125 // Send request and retrieve the response 1131 // We are sending just parameters, no content
1126 rsp = (HttpWebResponse)req.GetResponse(); 1132 req.ContentLength = 0;
1127 1133
1128 XmlTextReader rdr = new XmlTextReader(rsp.GetResponseStream()); 1134 // Send request and retrieve the response
1129 doc.Load(rdr); 1135 using (HttpWebResponse rsp = (HttpWebResponse)req.GetResponse())
1130 rdr.Close(); 1136 using (Stream s = rsp.GetResponseStream())
1131 } 1137 using (XmlTextReader rdr = new XmlTextReader(s))
1132 catch (Exception e) 1138 doc.Load(rdr);
1133 { 1139 }
1134 m_log.ErrorFormat("[VivoxVoice] Error in admin call : {0}", e.Message); 1140 catch (Exception e)
1141 {
1142 m_log.ErrorFormat("[VivoxVoice] Error in admin call : {0}", e.Message);
1143 }
1135 } 1144 }
1136 1145
1137 // If we're debugging server responses, dump the whole 1146 // If we're debugging server responses, dump the whole
@@ -1316,4 +1325,4 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice
1316 return false; 1325 return false;
1317 } 1326 }
1318 } 1327 }
1319} \ No newline at end of file 1328}
diff --git a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsMessagingModule.cs b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsMessagingModule.cs
index 2802e2f..e1b6abb 100644
--- a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsMessagingModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsMessagingModule.cs
@@ -55,8 +55,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
55 private IGroupsServicesConnector m_groupData = null; 55 private IGroupsServicesConnector m_groupData = null;
56 56
57 // Config Options 57 // Config Options
58 private bool m_groupMessagingEnabled = false; 58 private bool m_groupMessagingEnabled;
59 private bool m_debugEnabled = true; 59 private bool m_debugEnabled;
60 60
61 /// <summary> 61 /// <summary>
62 /// If enabled, module only tries to send group IMs to online users by querying cached presence information. 62 /// If enabled, module only tries to send group IMs to online users by querying cached presence information.
@@ -113,7 +113,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
113 if (m_messageOnlineAgentsOnly) 113 if (m_messageOnlineAgentsOnly)
114 m_usersOnlineCache = new ExpiringCache<UUID, PresenceInfo[]>(); 114 m_usersOnlineCache = new ExpiringCache<UUID, PresenceInfo[]>();
115 115
116 m_debugEnabled = groupsConfig.GetBoolean("DebugEnabled", true); 116 m_debugEnabled = groupsConfig.GetBoolean("MessagingDebugEnabled", m_debugEnabled);
117 } 117 }
118 118
119 m_log.InfoFormat( 119 m_log.InfoFormat(
@@ -127,6 +127,14 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
127 return; 127 return;
128 128
129 scene.RegisterModuleInterface<IGroupsMessagingModule>(this); 129 scene.RegisterModuleInterface<IGroupsMessagingModule>(this);
130
131 scene.AddCommand(
132 "Debug",
133 this,
134 "debug groups messaging verbose",
135 "debug groups messaging verbose <true|false>",
136 "This setting turns on very verbose groups messaging debugging",
137 HandleDebugGroupsMessagingVerbose);
130 } 138 }
131 139
132 public void RegionLoaded(Scene scene) 140 public void RegionLoaded(Scene scene)
@@ -218,6 +226,26 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
218 226
219 #endregion 227 #endregion
220 228
229 private void HandleDebugGroupsMessagingVerbose(object modules, string[] args)
230 {
231 if (args.Length < 5)
232 {
233 MainConsole.Instance.Output("Usage: debug groups messaging verbose <true|false>");
234 return;
235 }
236
237 bool verbose = false;
238 if (!bool.TryParse(args[4], out verbose))
239 {
240 MainConsole.Instance.Output("Usage: debug groups messaging verbose <true|false>");
241 return;
242 }
243
244 m_debugEnabled = verbose;
245
246 MainConsole.Instance.OutputFormat("{0} verbose logging set to {1}", Name, m_debugEnabled);
247 }
248
221 /// <summary> 249 /// <summary>
222 /// Not really needed, but does confirm that the group exists. 250 /// Not really needed, but does confirm that the group exists.
223 /// </summary> 251 /// </summary>
@@ -237,11 +265,20 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
237 return false; 265 return false;
238 } 266 }
239 } 267 }
240 268
241 public void SendMessageToGroup(GridInstantMessage im, UUID groupID) 269 public void SendMessageToGroup(GridInstantMessage im, UUID groupID)
242 { 270 {
243 List<GroupMembersData> groupMembers = m_groupData.GetGroupMembers(new UUID(im.fromAgentID), groupID); 271 SendMessageToGroup(im, groupID, new UUID(im.fromAgentID), null);
272 }
273
274 public void SendMessageToGroup(
275 GridInstantMessage im, UUID groupID, UUID sendingAgentForGroupCalls, Func<GroupMembersData, bool> sendCondition)
276 {
277 int requestStartTick = Environment.TickCount;
278
279 List<GroupMembersData> groupMembers = m_groupData.GetGroupMembers(sendingAgentForGroupCalls, groupID);
244 int groupMembersCount = groupMembers.Count; 280 int groupMembersCount = groupMembers.Count;
281 HashSet<string> attemptDeliveryUuidSet = null;
245 282
246 if (m_messageOnlineAgentsOnly) 283 if (m_messageOnlineAgentsOnly)
247 { 284 {
@@ -257,10 +294,12 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
257 m_usersOnlineCache.Add(groupID, onlineAgents, m_usersOnlineCacheExpirySeconds); 294 m_usersOnlineCache.Add(groupID, onlineAgents, m_usersOnlineCacheExpirySeconds);
258 } 295 }
259 296
260 HashSet<string> onlineAgentsUuidSet = new HashSet<string>(); 297 attemptDeliveryUuidSet
261 Array.ForEach<PresenceInfo>(onlineAgents, pi => onlineAgentsUuidSet.Add(pi.UserID)); 298 = new HashSet<string>(Array.ConvertAll<PresenceInfo, string>(onlineAgents, pi => pi.UserID));
299
300 //Array.ForEach<PresenceInfo>(onlineAgents, pi => attemptDeliveryUuidSet.Add(pi.UserID));
262 301
263 groupMembers = groupMembers.Where(gmd => onlineAgentsUuidSet.Contains(gmd.AgentID.ToString())).ToList(); 302 //groupMembers = groupMembers.Where(gmd => onlineAgentsUuidSet.Contains(gmd.AgentID.ToString())).ToList();
264 303
265 // if (m_debugEnabled) 304 // if (m_debugEnabled)
266// m_log.DebugFormat( 305// m_log.DebugFormat(
@@ -269,26 +308,42 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
269 } 308 }
270 else 309 else
271 { 310 {
311 attemptDeliveryUuidSet
312 = new HashSet<string>(groupMembers.ConvertAll<string>(gmd => gmd.AgentID.ToString()));
313
272 if (m_debugEnabled) 314 if (m_debugEnabled)
273 m_log.DebugFormat( 315 m_log.DebugFormat(
274 "[GROUPS-MESSAGING]: SendMessageToGroup called for group {0} with {1} visible members", 316 "[GROUPS-MESSAGING]: SendMessageToGroup called for group {0} with {1} visible members",
275 groupID, groupMembers.Count); 317 groupID, groupMembers.Count);
276 } 318 }
277
278 int requestStartTick = Environment.TickCount;
279 319
280 foreach (GroupMembersData member in groupMembers) 320 foreach (GroupMembersData member in groupMembers)
281 { 321 {
282 if (m_groupData.hasAgentDroppedGroupChatSession(member.AgentID, groupID)) 322 if (sendCondition != null)
323 {
324 if (!sendCondition(member))
325 {
326 if (m_debugEnabled)
327 m_log.DebugFormat(
328 "[GROUPS-MESSAGING]: Not sending to {0} as they do not fulfill send condition",
329 member.AgentID);
330
331 continue;
332 }
333 }
334 else if (m_groupData.hasAgentDroppedGroupChatSession(member.AgentID, groupID))
283 { 335 {
284 // Don't deliver messages to people who have dropped this session 336 // Don't deliver messages to people who have dropped this session
285 if (m_debugEnabled) m_log.DebugFormat("[GROUPS-MESSAGING]: {0} has dropped session, not delivering to them", member.AgentID); 337 if (m_debugEnabled)
338 m_log.DebugFormat(
339 "[GROUPS-MESSAGING]: {0} has dropped session, not delivering to them", member.AgentID);
340
286 continue; 341 continue;
287 } 342 }
288 343
289 // Copy Message 344 // Copy Message
290 GridInstantMessage msg = new GridInstantMessage(); 345 GridInstantMessage msg = new GridInstantMessage();
291 msg.imSessionID = groupID.Guid; 346 msg.imSessionID = im.imSessionID;
292 msg.fromAgentName = im.fromAgentName; 347 msg.fromAgentName = im.fromAgentName;
293 msg.message = im.message; 348 msg.message = im.message;
294 msg.dialog = im.dialog; 349 msg.dialog = im.dialog;
@@ -304,26 +359,51 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
304 359
305 msg.toAgentID = member.AgentID.Guid; 360 msg.toAgentID = member.AgentID.Guid;
306 361
307 IClientAPI client = GetActiveClient(member.AgentID); 362 if (attemptDeliveryUuidSet.Contains(member.AgentID.ToString()))
308 if (client == null)
309 { 363 {
310 // If they're not local, forward across the grid 364 IClientAPI client = GetActiveClient(member.AgentID);
311 if (m_debugEnabled) m_log.DebugFormat("[GROUPS-MESSAGING]: Delivering to {0} via Grid", member.AgentID); 365 if (client == null)
312 m_msgTransferModule.SendInstantMessage(msg, delegate(bool success) { }); 366 {
367 int startTick = Environment.TickCount;
368
369 // If they're not local, forward across the grid
370 m_msgTransferModule.SendInstantMessage(msg, delegate(bool success) { });
371
372 if (m_debugEnabled)
373 m_log.DebugFormat(
374 "[GROUPS-MESSAGING]: Delivering to {0} via grid took {1} ms",
375 member.AgentID, Environment.TickCount - startTick);
376 }
377 else
378 {
379 int startTick = Environment.TickCount;
380
381 ProcessMessageFromGroupSession(msg, client);
382
383 // Deliver locally, directly
384 if (m_debugEnabled)
385 m_log.DebugFormat(
386 "[GROUPS-MESSAGING]: Delivering to {0} locally took {1} ms",
387 member.AgentID, Environment.TickCount - startTick);
388 }
313 } 389 }
314 else 390 else
315 { 391 {
316 // Deliver locally, directly 392 int startTick = Environment.TickCount;
317 if (m_debugEnabled) m_log.DebugFormat("[GROUPS-MESSAGING]: Passing to ProcessMessageFromGroupSession to deliver to {0} locally", client.Name); 393
318 ProcessMessageFromGroupSession(msg); 394 m_msgTransferModule.HandleUndeliverableMessage(msg, delegate(bool success) { });
395
396 if (m_debugEnabled)
397 m_log.DebugFormat(
398 "[GROUPS-MESSAGING]: Handling undeliverable message for {0} took {1} ms",
399 member.AgentID, Environment.TickCount - startTick);
319 } 400 }
320 } 401 }
321 402
322 // Temporary for assessing how long it still takes to send messages to large online groups. 403 if (m_debugEnabled)
323 if (m_messageOnlineAgentsOnly)
324 m_log.DebugFormat( 404 m_log.DebugFormat(
325 "[GROUPS-MESSAGING]: SendMessageToGroup for group {0} with {1} visible members, {2} online took {3}ms", 405 "[GROUPS-MESSAGING]: Total SendMessageToGroup for group {0} with {1} members, {2} candidates for delivery took {3} ms",
326 groupID, groupMembersCount, groupMembers.Count(), Environment.TickCount - requestStartTick); 406 groupID, groupMembersCount, attemptDeliveryUuidSet.Count(), Environment.TickCount - requestStartTick);
327 } 407 }
328 408
329 #region SimGridEventHandlers 409 #region SimGridEventHandlers
@@ -348,7 +428,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
348 // Any other message type will not be delivered to a client by the 428 // Any other message type will not be delivered to a client by the
349 // Instant Message Module 429 // Instant Message Module
350 430
351
352 if (m_debugEnabled) 431 if (m_debugEnabled)
353 { 432 {
354 m_log.DebugFormat("[GROUPS-MESSAGING]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); 433 m_log.DebugFormat("[GROUPS-MESSAGING]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
@@ -362,13 +441,35 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
362 || (msg.dialog == (byte)InstantMessageDialog.SessionAdd) 441 || (msg.dialog == (byte)InstantMessageDialog.SessionAdd)
363 || (msg.dialog == (byte)InstantMessageDialog.SessionDrop))) 442 || (msg.dialog == (byte)InstantMessageDialog.SessionDrop)))
364 { 443 {
365 ProcessMessageFromGroupSession(msg); 444 IClientAPI client = null;
445
446 if (msg.dialog == (byte)InstantMessageDialog.SessionSend)
447 {
448 client = GetActiveClient(new UUID(msg.toAgentID));
449
450 if (client != null)
451 {
452 if (m_debugEnabled)
453 m_log.DebugFormat("[GROUPS-MESSAGING]: Delivering to {0} locally", client.Name);
454 }
455 else
456 {
457 m_log.WarnFormat("[GROUPS-MESSAGING]: Received a message over the grid for a client that isn't here: {0}", msg.toAgentID);
458
459 return;
460 }
461 }
462
463 ProcessMessageFromGroupSession(msg, client);
366 } 464 }
367 } 465 }
368 466
369 private void ProcessMessageFromGroupSession(GridInstantMessage msg) 467 private void ProcessMessageFromGroupSession(GridInstantMessage msg, IClientAPI client)
370 { 468 {
371 if (m_debugEnabled) m_log.DebugFormat("[GROUPS-MESSAGING]: Session message from {0} going to agent {1}", msg.fromAgentName, msg.toAgentID); 469 if (m_debugEnabled)
470 m_log.DebugFormat(
471 "[GROUPS-MESSAGING]: Session message from {0} going to agent {1}, sessionID {2}, type {3}",
472 msg.fromAgentName, msg.toAgentID, msg.imSessionID, (InstantMessageDialog)msg.dialog);
372 473
373 UUID AgentID = new UUID(msg.fromAgentID); 474 UUID AgentID = new UUID(msg.fromAgentID);
374 UUID GroupID = new UUID(msg.imSessionID); 475 UUID GroupID = new UUID(msg.imSessionID);
@@ -392,74 +493,62 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
392 // Add them to the session for now, and Invite them 493 // Add them to the session for now, and Invite them
393 m_groupData.AgentInvitedToGroupChatSession(AgentID, GroupID); 494 m_groupData.AgentInvitedToGroupChatSession(AgentID, GroupID);
394 495
395 UUID toAgentID = new UUID(msg.toAgentID); 496 GroupRecord groupInfo = m_groupData.GetGroupRecord(UUID.Zero, GroupID, null);
396 IClientAPI activeClient = GetActiveClient(toAgentID); 497 if (groupInfo != null)
397 if (activeClient != null)
398 { 498 {
399 GroupRecord groupInfo = m_groupData.GetGroupRecord(UUID.Zero, GroupID, null); 499 if (m_debugEnabled) m_log.DebugFormat("[GROUPS-MESSAGING]: Sending chatterbox invite instant message");
400 if (groupInfo != null) 500
401 { 501 // Force? open the group session dialog???
402 if (m_debugEnabled) m_log.DebugFormat("[GROUPS-MESSAGING]: Sending chatterbox invite instant message"); 502 // and simultanously deliver the message, so we don't need to do a seperate client.SendInstantMessage(msg);
403 503 IEventQueue eq = client.Scene.RequestModuleInterface<IEventQueue>();
404 // Force? open the group session dialog??? 504 eq.ChatterboxInvitation(
405 // and simultanously deliver the message, so we don't need to do a seperate client.SendInstantMessage(msg); 505 GroupID
406 IEventQueue eq = activeClient.Scene.RequestModuleInterface<IEventQueue>(); 506 , groupInfo.GroupName
407 eq.ChatterboxInvitation( 507 , new UUID(msg.fromAgentID)
408 GroupID 508 , msg.message
409 , groupInfo.GroupName 509 , new UUID(msg.toAgentID)
410 , new UUID(msg.fromAgentID) 510 , msg.fromAgentName
411 , msg.message 511 , msg.dialog
412 , new UUID(msg.toAgentID) 512 , msg.timestamp
413 , msg.fromAgentName 513 , msg.offline == 1
414 , msg.dialog 514 , (int)msg.ParentEstateID
415 , msg.timestamp 515 , msg.Position
416 , msg.offline == 1 516 , 1
417 , (int)msg.ParentEstateID 517 , new UUID(msg.imSessionID)
418 , msg.Position 518 , msg.fromGroup
419 , 1 519 , Utils.StringToBytes(groupInfo.GroupName)
420 , new UUID(msg.imSessionID) 520 );
421 , msg.fromGroup 521
422 , Utils.StringToBytes(groupInfo.GroupName) 522 eq.ChatterBoxSessionAgentListUpdates(
423 ); 523 new UUID(GroupID)
424 524 , new UUID(msg.fromAgentID)
425 eq.ChatterBoxSessionAgentListUpdates( 525 , new UUID(msg.toAgentID)
426 new UUID(GroupID) 526 , false //canVoiceChat
427 , new UUID(msg.fromAgentID) 527 , false //isModerator
428 , new UUID(msg.toAgentID) 528 , false //text mute
429 , false //canVoiceChat 529 );
430 , false //isModerator
431 , false //text mute
432 );
433 }
434 } 530 }
531
532 break;
435 } 533 }
436 else if (!m_groupData.hasAgentDroppedGroupChatSession(AgentID, GroupID)) 534 else if (!m_groupData.hasAgentDroppedGroupChatSession(AgentID, GroupID))
437 { 535 {
438 // User hasn't dropped, so they're in the session, 536 // User hasn't dropped, so they're in the session,
439 // maybe we should deliver it. 537 // maybe we should deliver it.
440 IClientAPI client = GetActiveClient(new UUID(msg.toAgentID)); 538 client.SendInstantMessage(msg);
441 if (client != null)
442 {
443 // Deliver locally, directly
444 if (m_debugEnabled) m_log.DebugFormat("[GROUPS-MESSAGING]: Delivering to {0} locally", client.Name);
445 client.SendInstantMessage(msg);
446 }
447 else
448 {
449 m_log.WarnFormat("[GROUPS-MESSAGING]: Received a message over the grid for a client that isn't here: {0}", msg.toAgentID);
450 }
451 } 539 }
540
452 break; 541 break;
453 542
454 default: 543 default:
455 m_log.WarnFormat("[GROUPS-MESSAGING]: I don't know how to proccess a {0} message.", ((InstantMessageDialog)msg.dialog).ToString()); 544 client.SendInstantMessage(msg);
456 break; 545
546 break;;
457 } 547 }
458 } 548 }
459 549
460 #endregion 550 #endregion
461 551
462
463 #region ClientEvents 552 #region ClientEvents
464 private void OnInstantMessage(IClientAPI remoteClient, GridInstantMessage im) 553 private void OnInstantMessage(IClientAPI remoteClient, GridInstantMessage im)
465 { 554 {
@@ -548,15 +637,15 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
548 // Don't log any normal IMs (privacy!) 637 // Don't log any normal IMs (privacy!)
549 if (m_debugEnabled && im.dialog != (byte)InstantMessageDialog.MessageFromAgent) 638 if (m_debugEnabled && im.dialog != (byte)InstantMessageDialog.MessageFromAgent)
550 { 639 {
551 m_log.WarnFormat("[GROUPS-MESSAGING]: IM: fromGroup({0})", im.fromGroup ? "True" : "False"); 640 m_log.DebugFormat("[GROUPS-MESSAGING]: IM: fromGroup({0})", im.fromGroup ? "True" : "False");
552 m_log.WarnFormat("[GROUPS-MESSAGING]: IM: Dialog({0})", ((InstantMessageDialog)im.dialog).ToString()); 641 m_log.DebugFormat("[GROUPS-MESSAGING]: IM: Dialog({0})", (InstantMessageDialog)im.dialog);
553 m_log.WarnFormat("[GROUPS-MESSAGING]: IM: fromAgentID({0})", im.fromAgentID.ToString()); 642 m_log.DebugFormat("[GROUPS-MESSAGING]: IM: fromAgentID({0})", im.fromAgentID);
554 m_log.WarnFormat("[GROUPS-MESSAGING]: IM: fromAgentName({0})", im.fromAgentName.ToString()); 643 m_log.DebugFormat("[GROUPS-MESSAGING]: IM: fromAgentName({0})", im.fromAgentName);
555 m_log.WarnFormat("[GROUPS-MESSAGING]: IM: imSessionID({0})", im.imSessionID.ToString()); 644 m_log.DebugFormat("[GROUPS-MESSAGING]: IM: imSessionID({0})", im.imSessionID);
556 m_log.WarnFormat("[GROUPS-MESSAGING]: IM: message({0})", im.message.ToString()); 645 m_log.DebugFormat("[GROUPS-MESSAGING]: IM: message({0})", im.message);
557 m_log.WarnFormat("[GROUPS-MESSAGING]: IM: offline({0})", im.offline.ToString()); 646 m_log.DebugFormat("[GROUPS-MESSAGING]: IM: offline({0})", im.offline);
558 m_log.WarnFormat("[GROUPS-MESSAGING]: IM: toAgentID({0})", im.toAgentID.ToString()); 647 m_log.DebugFormat("[GROUPS-MESSAGING]: IM: toAgentID({0})", im.toAgentID);
559 m_log.WarnFormat("[GROUPS-MESSAGING]: IM: binaryBucket({0})", OpenMetaverse.Utils.BytesToHexString(im.binaryBucket, "BinaryBucket")); 648 m_log.DebugFormat("[GROUPS-MESSAGING]: IM: binaryBucket({0})", OpenMetaverse.Utils.BytesToHexString(im.binaryBucket, "BinaryBucket"));
560 } 649 }
561 } 650 }
562 651
@@ -567,7 +656,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
567 /// </summary> 656 /// </summary>
568 private IClientAPI GetActiveClient(UUID agentID) 657 private IClientAPI GetActiveClient(UUID agentID)
569 { 658 {
570 if (m_debugEnabled) m_log.WarnFormat("[GROUPS-MESSAGING]: Looking for local client {0}", agentID); 659 if (m_debugEnabled)
660 m_log.DebugFormat("[GROUPS-MESSAGING]: Looking for local client {0}", agentID);
571 661
572 IClientAPI child = null; 662 IClientAPI child = null;
573 663
@@ -579,12 +669,16 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
579 { 669 {
580 if (!sp.IsChildAgent) 670 if (!sp.IsChildAgent)
581 { 671 {
582 if (m_debugEnabled) m_log.WarnFormat("[GROUPS-MESSAGING]: Found root agent for client : {0}", sp.ControllingClient.Name); 672 if (m_debugEnabled)
673 m_log.DebugFormat("[GROUPS-MESSAGING]: Found root agent for client : {0}", sp.ControllingClient.Name);
674
583 return sp.ControllingClient; 675 return sp.ControllingClient;
584 } 676 }
585 else 677 else
586 { 678 {
587 if (m_debugEnabled) m_log.WarnFormat("[GROUPS-MESSAGING]: Found child agent for client : {0}", sp.ControllingClient.Name); 679 if (m_debugEnabled)
680 m_log.DebugFormat("[GROUPS-MESSAGING]: Found child agent for client : {0}", sp.ControllingClient.Name);
681
588 child = sp.ControllingClient; 682 child = sp.ControllingClient;
589 } 683 }
590 } 684 }
@@ -593,12 +687,15 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
593 // If we didn't find a root, then just return whichever child we found, or null if none 687 // If we didn't find a root, then just return whichever child we found, or null if none
594 if (child == null) 688 if (child == null)
595 { 689 {
596 if (m_debugEnabled) m_log.WarnFormat("[GROUPS-MESSAGING]: Could not find local client for agent : {0}", agentID); 690 if (m_debugEnabled)
691 m_log.DebugFormat("[GROUPS-MESSAGING]: Could not find local client for agent : {0}", agentID);
597 } 692 }
598 else 693 else
599 { 694 {
600 if (m_debugEnabled) m_log.WarnFormat("[GROUPS-MESSAGING]: Returning child agent for client : {0}", child.Name); 695 if (m_debugEnabled)
696 m_log.DebugFormat("[GROUPS-MESSAGING]: Returning child agent for client : {0}", child.Name);
601 } 697 }
698
602 return child; 699 return child;
603 } 700 }
604 701
diff --git a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs
index 29f9591..1565da9 100644
--- a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs
@@ -35,10 +35,10 @@ using Nini.Config;
35using OpenMetaverse; 35using OpenMetaverse;
36using OpenMetaverse.StructuredData; 36using OpenMetaverse.StructuredData;
37using OpenSim.Framework; 37using OpenSim.Framework;
38using OpenSim.Framework.Communications;
39using OpenSim.Region.Framework.Interfaces; 38using OpenSim.Region.Framework.Interfaces;
40using OpenSim.Region.Framework.Scenes; 39using OpenSim.Region.Framework.Scenes;
41using OpenSim.Services.Interfaces; 40using OpenSim.Services.Interfaces;
41using System.Text;
42using DirFindFlags = OpenMetaverse.DirectoryManager.DirFindFlags; 42using DirFindFlags = OpenMetaverse.DirectoryManager.DirFindFlags;
43 43
44namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups 44namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
@@ -76,9 +76,11 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
76 76
77 private List<Scene> m_sceneList = new List<Scene>(); 77 private List<Scene> m_sceneList = new List<Scene>();
78 78
79 private IMessageTransferModule m_msgTransferModule = null; 79 private IMessageTransferModule m_msgTransferModule;
80
81 private IGroupsMessagingModule m_groupsMessagingModule;
80 82
81 private IGroupsServicesConnector m_groupData = null; 83 private IGroupsServicesConnector m_groupData;
82 84
83 // Configuration settings 85 // Configuration settings
84 private bool m_groupsEnabled = false; 86 private bool m_groupsEnabled = false;
@@ -184,10 +186,19 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
184 if (m_msgTransferModule == null) 186 if (m_msgTransferModule == null)
185 { 187 {
186 m_groupsEnabled = false; 188 m_groupsEnabled = false;
187 m_log.Warn("[GROUPS]: Could not get MessageTransferModule"); 189 m_log.Warn("[GROUPS]: Could not get IMessageTransferModule");
188 } 190 }
189 } 191 }
190 192
193 if (m_groupsMessagingModule == null)
194 {
195 m_groupsMessagingModule = scene.RequestModuleInterface<IGroupsMessagingModule>();
196
197 // No message transfer module, no notices, group invites, rejects, ejects, etc
198 if (m_groupsMessagingModule == null)
199 m_log.Warn("[GROUPS]: Could not get IGroupsMessagingModule");
200 }
201
191 lock (m_sceneList) 202 lock (m_sceneList)
192 { 203 {
193 m_sceneList.Add(scene); 204 m_sceneList.Add(scene);
@@ -250,7 +261,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
250 261
251 client.OnUUIDGroupNameRequest += HandleUUIDGroupNameRequest; 262 client.OnUUIDGroupNameRequest += HandleUUIDGroupNameRequest;
252 client.OnAgentDataUpdateRequest += OnAgentDataUpdateRequest; 263 client.OnAgentDataUpdateRequest += OnAgentDataUpdateRequest;
253 client.OnDirFindQuery += OnDirFindQuery;
254 client.OnRequestAvatarProperties += OnRequestAvatarProperties; 264 client.OnRequestAvatarProperties += OnRequestAvatarProperties;
255 265
256 // Used for Notices and Group Invites/Accept/Reject 266 // Used for Notices and Group Invites/Accept/Reject
@@ -303,21 +313,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
303 } 313 }
304 */ 314 */
305 315
306 void OnDirFindQuery(IClientAPI remoteClient, UUID queryID, string queryText, uint queryFlags, int queryStart)
307 {
308 if (((DirFindFlags)queryFlags & DirFindFlags.Groups) == DirFindFlags.Groups)
309 {
310 if (m_debugEnabled)
311 m_log.DebugFormat(
312 "[GROUPS]: {0} called with queryText({1}) queryFlags({2}) queryStart({3})",
313 System.Reflection.MethodBase.GetCurrentMethod().Name, queryText, (DirFindFlags)queryFlags, queryStart);
314
315 // TODO: This currently ignores pretty much all the query flags including Mature and sort order
316 remoteClient.SendDirGroupsReply(queryID, m_groupData.FindGroups(GetRequestingAgentID(remoteClient), queryText).ToArray());
317 }
318
319 }
320
321 private void OnAgentDataUpdateRequest(IClientAPI remoteClient, UUID dataForAgentID, UUID sessionID) 316 private void OnAgentDataUpdateRequest(IClientAPI remoteClient, UUID dataForAgentID, UUID sessionID)
322 { 317 {
323 if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); 318 if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
@@ -361,7 +356,10 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
361 356
362 private void OnInstantMessage(IClientAPI remoteClient, GridInstantMessage im) 357 private void OnInstantMessage(IClientAPI remoteClient, GridInstantMessage im)
363 { 358 {
364 if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); 359 if (m_debugEnabled)
360 m_log.DebugFormat(
361 "[GROUPS]: {0} called for {1}, message type {2}",
362 System.Reflection.MethodBase.GetCurrentMethod().Name, remoteClient.Name, (InstantMessageDialog)im.dialog);
365 363
366 // Group invitations 364 // Group invitations
367 if ((im.dialog == (byte)InstantMessageDialog.GroupInvitationAccept) || (im.dialog == (byte)InstantMessageDialog.GroupInvitationDecline)) 365 if ((im.dialog == (byte)InstantMessageDialog.GroupInvitationAccept) || (im.dialog == (byte)InstantMessageDialog.GroupInvitationDecline))
@@ -437,81 +435,160 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
437 string Subject = im.message.Substring(0, im.message.IndexOf('|')); 435 string Subject = im.message.Substring(0, im.message.IndexOf('|'));
438 string Message = im.message.Substring(Subject.Length + 1); 436 string Message = im.message.Substring(Subject.Length + 1);
439 437
438 InventoryItemBase item = null;
439 bool hasAttachment = false;
440 UUID itemID = UUID.Zero; //Assignment to quiet compiler
441 UUID ownerID = UUID.Zero; //Assignment to quiet compiler
440 byte[] bucket; 442 byte[] bucket;
441 443
442 if ((im.binaryBucket.Length == 1) && (im.binaryBucket[0] == 0)) 444 if (im.binaryBucket.Length >= 1 && im.binaryBucket[0] > 0)
443 {
444 bucket = new byte[19];
445 bucket[0] = 0; //dunno
446 bucket[1] = 0; //dunno
447 GroupID.ToBytes(bucket, 2);
448 bucket[18] = 0; //dunno
449 }
450 else
451 { 445 {
452 string binBucket = OpenMetaverse.Utils.BytesToString(im.binaryBucket); 446 string binBucket = OpenMetaverse.Utils.BytesToString(im.binaryBucket);
453 binBucket = binBucket.Remove(0, 14).Trim(); 447 binBucket = binBucket.Remove(0, 14).Trim();
454 if (m_debugEnabled) 448
449 OSDMap binBucketOSD = (OSDMap)OSDParser.DeserializeLLSDXml(binBucket);
450 if (binBucketOSD is OSD)
455 { 451 {
456 m_log.WarnFormat("I don't understand a group notice binary bucket of: {0}", binBucket); 452 OSDMap binBucketMap = (OSDMap)binBucketOSD;
453
454 itemID = binBucketMap["item_id"].AsUUID();
455 ownerID = binBucketMap["owner_id"].AsUUID();
456
457 //Attempt to get the details of the attached item.
458 //If sender doesn't own the attachment, the item
459 //variable will be set to null and attachment will
460 //not be included with the group notice.
461 Scene scene = (Scene)remoteClient.Scene;
462 item = new InventoryItemBase(itemID, ownerID);
463 item = scene.InventoryService.GetItem(item);
457 464
458 OSDMap binBucketOSD = (OSDMap)OSDParser.DeserializeLLSDXml(binBucket); 465 if (item != null)
459
460 foreach (string key in binBucketOSD.Keys)
461 { 466 {
462 if (binBucketOSD.ContainsKey(key)) 467 //Got item details so include the attachment.
463 { 468 hasAttachment = true;
464 m_log.WarnFormat("{0}: {1}", key, binBucketOSD[key].ToString());
465 }
466 } 469 }
467 } 470 }
468 471 else
469 // treat as if no attachment 472 {
473 m_log.DebugFormat("[Groups]: Received OSD with unexpected type: {0}", binBucketOSD.GetType());
474 }
475 }
476
477 if (hasAttachment)
478 {
479 //Bucket contains information about attachment.
480 //
481 //Byte offset and description of bucket data:
482 //0: 1 byte indicating if attachment is present
483 //1: 1 byte indicating the type of attachment
484 //2: 16 bytes - Group UUID
485 //18: 16 bytes - UUID of the attachment owner
486 //34: 16 bytes - UUID of the attachment
487 //50: variable - Name of the attachment
488 //??: NUL byte to terminate the attachment name
489 byte[] name = Encoding.UTF8.GetBytes(item.Name);
490 bucket = new byte[51 + name.Length];//3 bytes, 3 UUIDs, and name
491 bucket[0] = 1; //Has attachment flag
492 bucket[1] = (byte)item.InvType; //Type of Attachment
493 GroupID.ToBytes(bucket, 2);
494 ownerID.ToBytes(bucket, 18);
495 itemID.ToBytes(bucket, 34);
496 name.CopyTo(bucket, 50);
497 }
498 else
499 {
470 bucket = new byte[19]; 500 bucket = new byte[19];
471 bucket[0] = 0; //dunno 501 bucket[0] = 0; //Has attachment flag
472 bucket[1] = 0; //dunno 502 bucket[1] = 0; //Type of attachment
473 GroupID.ToBytes(bucket, 2); 503 GroupID.ToBytes(bucket, 2);
474 bucket[18] = 0; //dunno 504 bucket[18] = 0; //NUL terminate name of attachment
475 } 505 }
476 506
477
478 m_groupData.AddGroupNotice(GetRequestingAgentID(remoteClient), GroupID, NoticeID, im.fromAgentName, Subject, Message, bucket); 507 m_groupData.AddGroupNotice(GetRequestingAgentID(remoteClient), GroupID, NoticeID, im.fromAgentName, Subject, Message, bucket);
479 if (OnNewGroupNotice != null) 508 if (OnNewGroupNotice != null)
480 { 509 {
481 OnNewGroupNotice(GroupID, NoticeID); 510 OnNewGroupNotice(GroupID, NoticeID);
482 } 511 }
483 512
484 // Send notice out to everyone that wants notices 513 if (m_debugEnabled)
485 foreach (GroupMembersData member in m_groupData.GetGroupMembers(GetRequestingAgentID(remoteClient), GroupID))
486 { 514 {
487 if (m_debugEnabled) 515 foreach (GroupMembersData member in m_groupData.GetGroupMembers(GetRequestingAgentID(remoteClient), GroupID))
488 { 516 {
489 UserAccount targetUser = m_sceneList[0].UserAccountService.GetUserAccount(remoteClient.Scene.RegionInfo.ScopeID, member.AgentID); 517 if (m_debugEnabled)
490 if (targetUser != null)
491 { 518 {
492 m_log.DebugFormat("[GROUPS]: Prepping group notice {0} for agent: {1} who Accepts Notices ({2})", NoticeID, targetUser.FirstName + " " + targetUser.LastName, member.AcceptNotices); 519 UserAccount targetUser
493 } 520 = m_sceneList[0].UserAccountService.GetUserAccount(
494 else 521 remoteClient.Scene.RegionInfo.ScopeID, member.AgentID);
495 { 522
496 m_log.DebugFormat("[GROUPS]: Prepping group notice {0} for agent: {1} who Accepts Notices ({2})", NoticeID, member.AgentID, member.AcceptNotices); 523 if (targetUser != null)
524 {
525 m_log.DebugFormat(
526 "[GROUPS]: Prepping group notice {0} for agent: {1} who Accepts Notices ({2})",
527 NoticeID, targetUser.FirstName + " " + targetUser.LastName, member.AcceptNotices);
528 }
529 else
530 {
531 m_log.DebugFormat(
532 "[GROUPS]: Prepping group notice {0} for agent: {1} who Accepts Notices ({2})",
533 NoticeID, member.AgentID, member.AcceptNotices);
534 }
497 } 535 }
498 } 536 }
537 }
499 538
500 if (member.AcceptNotices) 539 GridInstantMessage msg
501 { 540 = CreateGroupNoticeIM(UUID.Zero, NoticeID, (byte)OpenMetaverse.InstantMessageDialog.GroupNotice);
502 // Build notice IIM
503 GridInstantMessage msg = CreateGroupNoticeIM(UUID.Zero, NoticeID, (byte)OpenMetaverse.InstantMessageDialog.GroupNotice);
504 541
505 msg.toAgentID = member.AgentID.Guid; 542 if (m_groupsMessagingModule != null)
506 OutgoingInstantMessage(msg, member.AgentID); 543 m_groupsMessagingModule.SendMessageToGroup(
507 } 544 msg, GroupID, remoteClient.AgentId, gmd => gmd.AcceptNotices);
545 }
546 }
547
548 if (im.dialog == (byte)InstantMessageDialog.GroupNoticeInventoryAccepted)
549 {
550 //Is bucket large enough to hold UUID of the attachment?
551 if (im.binaryBucket.Length < 16)
552 return;
553
554 UUID noticeID = new UUID(im.imSessionID);
555
556 if (m_debugEnabled)
557 m_log.DebugFormat("[GROUPS]: Requesting notice {0} for {1}", noticeID, remoteClient.AgentId);
558
559 GroupNoticeInfo notice = m_groupData.GetGroupNotice(GetRequestingAgentID(remoteClient), noticeID);
560 if (notice != null)
561 {
562 UUID giver = new UUID(notice.BinaryBucket, 18);
563 UUID attachmentUUID = new UUID(notice.BinaryBucket, 34);
564
565 if (m_debugEnabled)
566 m_log.DebugFormat("[Groups]: Giving inventory from {0} to {1}", giver, remoteClient.AgentId);
567
568 string message;
569 InventoryItemBase itemCopy = ((Scene)(remoteClient.Scene)).GiveInventoryItem(remoteClient.AgentId,
570 giver, attachmentUUID, out message);
571
572 if (itemCopy == null)
573 {
574 remoteClient.SendAgentAlertMessage(message, false);
575 return;
508 } 576 }
577
578 remoteClient.SendInventoryItemCreateUpdate(itemCopy, 0);
579 }
580 else
581 {
582 if (m_debugEnabled)
583 m_log.DebugFormat(
584 "[GROUPS]: Could not find notice {0} for {1} on GroupNoticeInventoryAccepted.",
585 noticeID, remoteClient.AgentId);
509 } 586 }
510 } 587 }
511 588
512 // Interop, received special 210 code for ejecting a group member 589 // Interop, received special 210 code for ejecting a group member
513 // this only works within the comms servers domain, and won't work hypergrid 590 // this only works within the comms servers domain, and won't work hypergrid
514 // TODO:FIXME: Use a presense server of some kind to find out where the 591 // TODO:FIXME: Use a presence server of some kind to find out where the
515 // client actually is, and try contacting that region directly to notify them, 592 // client actually is, and try contacting that region directly to notify them,
516 // or provide the notification via xmlrpc update queue 593 // or provide the notification via xmlrpc update queue
517 if ((im.dialog == 210)) 594 if ((im.dialog == 210))
@@ -764,7 +841,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
764 remoteClient.SendCreateGroupReply(UUID.Zero, false, "You have got insufficient funds to create a group."); 841 remoteClient.SendCreateGroupReply(UUID.Zero, false, "You have got insufficient funds to create a group.");
765 return UUID.Zero; 842 return UUID.Zero;
766 } 843 }
767 money.ApplyCharge(GetRequestingAgentID(remoteClient), money.GroupCreationCharge, "Group Creation"); 844 money.ApplyCharge(GetRequestingAgentID(remoteClient), money.GroupCreationCharge, MoneyTransactionType.GroupCreate);
768 } 845 }
769 UUID groupID = m_groupData.CreateGroup(GetRequestingAgentID(remoteClient), name, charter, showInList, insigniaID, membershipFee, openEnrollment, allowPublish, maturePublish, GetRequestingAgentID(remoteClient)); 846 UUID groupID = m_groupData.CreateGroup(GetRequestingAgentID(remoteClient), name, charter, showInList, insigniaID, membershipFee, openEnrollment, allowPublish, maturePublish, GetRequestingAgentID(remoteClient));
770 847
@@ -889,26 +966,10 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
889 966
890 if (data != null) 967 if (data != null)
891 { 968 {
892 GroupRecord groupInfo = m_groupData.GetGroupRecord(GetRequestingAgentID(remoteClient), data.GroupID, null); 969 GridInstantMessage msg = CreateGroupNoticeIM(remoteClient.AgentId, groupNoticeID, (byte)InstantMessageDialog.GroupNoticeRequested);
893
894 GridInstantMessage msg = new GridInstantMessage();
895 msg.imSessionID = UUID.Zero.Guid;
896 msg.fromAgentID = data.GroupID.Guid;
897 msg.toAgentID = GetRequestingAgentID(remoteClient).Guid;
898 msg.timestamp = (uint)Util.UnixTimeSinceEpoch();
899 msg.fromAgentName = "Group Notice : " + groupInfo == null ? "Unknown" : groupInfo.GroupName;
900 msg.message = data.noticeData.Subject + "|" + data.Message;
901 msg.dialog = (byte)OpenMetaverse.InstantMessageDialog.GroupNoticeRequested;
902 msg.fromGroup = true;
903 msg.offline = (byte)0;
904 msg.ParentEstateID = 0;
905 msg.Position = Vector3.Zero;
906 msg.RegionID = UUID.Zero.Guid;
907 msg.binaryBucket = data.BinaryBucket;
908 970
909 OutgoingInstantMessage(msg, GetRequestingAgentID(remoteClient)); 971 OutgoingInstantMessage(msg, GetRequestingAgentID(remoteClient));
910 } 972 }
911
912 } 973 }
913 974
914 public GridInstantMessage CreateGroupNoticeIM(UUID agentID, UUID groupNoticeID, byte dialog) 975 public GridInstantMessage CreateGroupNoticeIM(UUID agentID, UUID groupNoticeID, byte dialog)
@@ -916,10 +977,11 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
916 if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); 977 if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
917 978
918 GridInstantMessage msg = new GridInstantMessage(); 979 GridInstantMessage msg = new GridInstantMessage();
919 msg.imSessionID = UUID.Zero.Guid; 980 byte[] bucket;
981
982 msg.imSessionID = groupNoticeID.Guid;
920 msg.toAgentID = agentID.Guid; 983 msg.toAgentID = agentID.Guid;
921 msg.dialog = dialog; 984 msg.dialog = dialog;
922 // msg.dialog = (byte)OpenMetaverse.InstantMessageDialog.GroupNotice;
923 msg.fromGroup = true; 985 msg.fromGroup = true;
924 msg.offline = (byte)0; 986 msg.offline = (byte)0;
925 msg.ParentEstateID = 0; 987 msg.ParentEstateID = 0;
@@ -933,13 +995,38 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
933 msg.timestamp = info.noticeData.Timestamp; 995 msg.timestamp = info.noticeData.Timestamp;
934 msg.fromAgentName = info.noticeData.FromName; 996 msg.fromAgentName = info.noticeData.FromName;
935 msg.message = info.noticeData.Subject + "|" + info.Message; 997 msg.message = info.noticeData.Subject + "|" + info.Message;
936 msg.binaryBucket = info.BinaryBucket; 998
999 if (info.BinaryBucket[0] > 0)
1000 {
1001 //32 is due to not needing space for two of the UUIDs.
1002 //(Don't need UUID of attachment or its owner in IM)
1003 //50 offset gets us to start of attachment name.
1004 //We are skipping the attachment flag, type, and
1005 //the three UUID fields at the start of the bucket.
1006 bucket = new byte[info.BinaryBucket.Length-32];
1007 bucket[0] = 1; //Has attachment
1008 bucket[1] = info.BinaryBucket[1];
1009 Array.Copy(info.BinaryBucket, 50,
1010 bucket, 18, info.BinaryBucket.Length-50);
1011 }
1012 else
1013 {
1014 bucket = new byte[19];
1015 bucket[0] = 0; //No attachment
1016 bucket[1] = 0; //Attachment type
1017 bucket[18] = 0; //NUL terminate name
1018 }
1019
1020 info.GroupID.ToBytes(bucket, 2);
1021 msg.binaryBucket = bucket;
937 } 1022 }
938 else 1023 else
939 { 1024 {
940 if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: Group Notice {0} not found, composing empty message.", groupNoticeID); 1025 if (m_debugEnabled)
1026 m_log.DebugFormat("[GROUPS]: Group Notice {0} not found, composing empty message.", groupNoticeID);
1027
941 msg.fromAgentID = UUID.Zero.Guid; 1028 msg.fromAgentID = UUID.Zero.Guid;
942 msg.timestamp = (uint)Util.UnixTimeSinceEpoch(); ; 1029 msg.timestamp = (uint)Util.UnixTimeSinceEpoch();
943 msg.fromAgentName = string.Empty; 1030 msg.fromAgentName = string.Empty;
944 msg.message = string.Empty; 1031 msg.message = string.Empty;
945 msg.binaryBucket = new byte[0]; 1032 msg.binaryBucket = new byte[0];
@@ -1063,7 +1150,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
1063 // Message to ejector 1150 // Message to ejector
1064 // Interop, received special 210 code for ejecting a group member 1151 // Interop, received special 210 code for ejecting a group member
1065 // this only works within the comms servers domain, and won't work hypergrid 1152 // this only works within the comms servers domain, and won't work hypergrid
1066 // TODO:FIXME: Use a presense server of some kind to find out where the 1153 // TODO:FIXME: Use a presence server of some kind to find out where the
1067 // client actually is, and try contacting that region directly to notify them, 1154 // client actually is, and try contacting that region directly to notify them,
1068 // or provide the notification via xmlrpc update queue 1155 // or provide the notification via xmlrpc update queue
1069 1156
@@ -1178,6 +1265,12 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
1178 } 1265 }
1179 } 1266 }
1180 1267
1268 public List<DirGroupsReplyData> FindGroups(IClientAPI remoteClient, string query)
1269 {
1270 return m_groupData.FindGroups(GetRequestingAgentID(remoteClient), query);
1271 }
1272
1273
1181 #endregion 1274 #endregion
1182 1275
1183 #region Client/Update Tools 1276 #region Client/Update Tools
@@ -1222,7 +1315,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
1222 AgentDataMap.Add("AgentID", OSD.FromUUID(dataForAgentID)); 1315 AgentDataMap.Add("AgentID", OSD.FromUUID(dataForAgentID));
1223 AgentData.Add(AgentDataMap); 1316 AgentData.Add(AgentDataMap);
1224 1317
1225
1226 OSDArray GroupData = new OSDArray(data.Length); 1318 OSDArray GroupData = new OSDArray(data.Length);
1227 OSDArray NewGroupData = new OSDArray(data.Length); 1319 OSDArray NewGroupData = new OSDArray(data.Length);
1228 1320
@@ -1288,7 +1380,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
1288 presence.Grouptitle = Title; 1380 presence.Grouptitle = Title;
1289 1381
1290 if (! presence.IsChildAgent) 1382 if (! presence.IsChildAgent)
1291 presence.SendAvatarDataToAllAgents(); 1383 presence.SendAvatarDataToAllClients();
1292 } 1384 }
1293 } 1385 }
1294 } 1386 }
diff --git a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/SimianGroupsServicesConnectorModule.cs b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/SimianGroupsServicesConnectorModule.cs
index 7bae8f7..1cb4747 100644
--- a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/SimianGroupsServicesConnectorModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/SimianGroupsServicesConnectorModule.cs
@@ -42,7 +42,6 @@ using OpenMetaverse;
42using OpenMetaverse.StructuredData; 42using OpenMetaverse.StructuredData;
43 43
44using OpenSim.Framework; 44using OpenSim.Framework;
45using OpenSim.Framework.Communications;
46using OpenSim.Region.Framework.Interfaces; 45using OpenSim.Region.Framework.Interfaces;
47using OpenSim.Services.Interfaces; 46using OpenSim.Services.Interfaces;
48 47
@@ -212,8 +211,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
212 m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR]: Initializing {0}", this.Name); 211 m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR]: Initializing {0}", this.Name);
213 212
214 m_groupsServerURI = groupsConfig.GetString("GroupsServerURI", string.Empty); 213 m_groupsServerURI = groupsConfig.GetString("GroupsServerURI", string.Empty);
215 if ((m_groupsServerURI == null) || 214 if (string.IsNullOrEmpty(m_groupsServerURI))
216 (m_groupsServerURI == string.Empty))
217 { 215 {
218 m_log.ErrorFormat("Please specify a valid Simian Server for GroupsServerURI in OpenSim.ini, [Groups]"); 216 m_log.ErrorFormat("Please specify a valid Simian Server for GroupsServerURI in OpenSim.ini, [Groups]");
219 m_connectorEnabled = false; 217 m_connectorEnabled = false;
@@ -438,7 +436,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
438 return null; 436 return null;
439 } 437 }
440 } 438 }
441 else if ((groupName != null) && (groupName != string.Empty)) 439 else if (!string.IsNullOrEmpty(groupName))
442 { 440 {
443 if (!SimianGetFirstGenericEntry("Group", groupName, out groupID, out GroupInfoMap)) 441 if (!SimianGetFirstGenericEntry("Group", groupName, out groupID, out GroupInfoMap))
444 { 442 {
diff --git a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/Tests/GroupsModuleTests.cs b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/Tests/GroupsModuleTests.cs
index c1bdacb..9a42bac 100644
--- a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/Tests/GroupsModuleTests.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/Tests/GroupsModuleTests.cs
@@ -26,15 +26,25 @@
26 */ 26 */
27 27
28using System; 28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Net;
29using System.Reflection; 32using System.Reflection;
30using Nini.Config; 33using Nini.Config;
31using NUnit.Framework; 34using NUnit.Framework;
32using OpenMetaverse; 35using OpenMetaverse;
36using OpenMetaverse.Messages.Linden;
37using OpenMetaverse.Packets;
38using OpenMetaverse.StructuredData;
33using OpenSim.Framework; 39using OpenSim.Framework;
34using OpenSim.Framework.Communications; 40using OpenSim.Framework.Servers;
41using OpenSim.Framework.Servers.HttpServer;
42using OpenSim.Region.ClientStack.Linden;
43using OpenSim.Region.CoreModules.Avatar.InstantMessage;
44using OpenSim.Region.CoreModules.Framework;
35using OpenSim.Region.Framework.Scenes; 45using OpenSim.Region.Framework.Scenes;
46using OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups;
36using OpenSim.Tests.Common; 47using OpenSim.Tests.Common;
37using OpenSim.Tests.Common.Mock;
38 48
39namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups.Tests 49namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups.Tests
40{ 50{
@@ -44,11 +54,28 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups.Tests
44 [TestFixture] 54 [TestFixture]
45 public class GroupsModuleTests : OpenSimTestCase 55 public class GroupsModuleTests : OpenSimTestCase
46 { 56 {
57 [SetUp]
58 public override void SetUp()
59 {
60 base.SetUp();
61
62 uint port = 9999;
63 uint sslPort = 9998;
64
65 // This is an unfortunate bit of clean up we have to do because MainServer manages things through static
66 // variables and the VM is not restarted between tests.
67 MainServer.RemoveHttpServer(port);
68
69 BaseHttpServer server = new BaseHttpServer(port, false, sslPort, "");
70 MainServer.AddHttpServer(server);
71 MainServer.Instance = server;
72 }
73
47 [Test] 74 [Test]
48 public void TestBasic() 75 public void TestSendAgentGroupDataUpdate()
49 { 76 {
50 TestHelpers.InMethod(); 77 TestHelpers.InMethod();
51// log4net.Config.XmlConfigurator.Configure(); 78// TestHelpers.EnableLogging();
52 79
53 TestScene scene = new SceneHelpers().SetupScene(); 80 TestScene scene = new SceneHelpers().SetupScene();
54 IConfigSource configSource = new IniConfigSource(); 81 IConfigSource configSource = new IniConfigSource();
@@ -56,8 +83,185 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups.Tests
56 config.Set("Enabled", true); 83 config.Set("Enabled", true);
57 config.Set("Module", "GroupsModule"); 84 config.Set("Module", "GroupsModule");
58 config.Set("DebugEnabled", true); 85 config.Set("DebugEnabled", true);
86
87 GroupsModule gm = new GroupsModule();
88 EventQueueGetModule eqgm = new EventQueueGetModule();
89
90 // We need a capabilities module active so that adding the scene presence creates an event queue in the
91 // EventQueueGetModule
59 SceneHelpers.SetupSceneModules( 92 SceneHelpers.SetupSceneModules(
60 scene, configSource, new object[] { new MockGroupsServicesConnector() }); 93 scene, configSource, gm, new MockGroupsServicesConnector(), new CapabilitiesModule(), eqgm);
94
95 ScenePresence sp = SceneHelpers.AddScenePresence(scene, TestHelpers.ParseStem("1"));
96
97 gm.SendAgentGroupDataUpdate(sp.ControllingClient);
98
99 Hashtable eventsResponse = eqgm.GetEvents(UUID.Zero, sp.UUID);
100
101 Assert.That((int)eventsResponse["int_response_code"], Is.EqualTo((int)HttpStatusCode.OK));
102
103// Console.WriteLine("Response [{0}]", (string)eventsResponse["str_response_string"]);
104
105 OSDMap rawOsd = (OSDMap)OSDParser.DeserializeLLSDXml((string)eventsResponse["str_response_string"]);
106 OSDArray eventsOsd = (OSDArray)rawOsd["events"];
107
108 bool foundUpdate = false;
109 foreach (OSD osd in eventsOsd)
110 {
111 OSDMap eventOsd = (OSDMap)osd;
112
113 if (eventOsd["message"] == "AgentGroupDataUpdate")
114 foundUpdate = true;
115 }
116
117 Assert.That(foundUpdate, Is.True, "Did not find AgentGroupDataUpdate in response");
118
119 // TODO: More checking of more actual event data.
120 }
121
122 [Test]
123 public void TestSendGroupNotice()
124 {
125 TestHelpers.InMethod();
126// TestHelpers.EnableLogging();
127
128 TestScene scene = new SceneHelpers().SetupScene();
129
130 MessageTransferModule mtm = new MessageTransferModule();
131 GroupsModule gm = new GroupsModule();
132 GroupsMessagingModule gmm = new GroupsMessagingModule();
133 MockGroupsServicesConnector mgsc = new MockGroupsServicesConnector();
134
135 IConfigSource configSource = new IniConfigSource();
136
137 {
138 IConfig config = configSource.AddConfig("Messaging");
139 config.Set("MessageTransferModule", mtm.Name);
140 }
141
142 {
143 IConfig config = configSource.AddConfig("Groups");
144 config.Set("Enabled", true);
145 config.Set("Module", gm.Name);
146 config.Set("DebugEnabled", true);
147 config.Set("MessagingModule", gmm.Name);
148 config.Set("MessagingEnabled", true);
149 }
150
151 SceneHelpers.SetupSceneModules(scene, configSource, mgsc, mtm, gm, gmm);
152
153 UUID userId = TestHelpers.ParseTail(0x1);
154 string subjectText = "newman";
155 string messageText = "Hello";
156 string combinedSubjectMessage = string.Format("{0}|{1}", subjectText, messageText);
157
158 ScenePresence sp = SceneHelpers.AddScenePresence(scene, TestHelpers.ParseTail(0x1));
159 TestClient tc = (TestClient)sp.ControllingClient;
160
161 UUID groupID = gm.CreateGroup(tc, "group1", null, true, UUID.Zero, 0, true, true, true);
162 gm.JoinGroupRequest(tc, groupID);
163
164 // Create a second user who doesn't want to receive notices
165 ScenePresence sp2 = SceneHelpers.AddScenePresence(scene, TestHelpers.ParseTail(0x2));
166 TestClient tc2 = (TestClient)sp2.ControllingClient;
167 gm.JoinGroupRequest(tc2, groupID);
168 gm.SetGroupAcceptNotices(tc2, groupID, false, true);
169
170 List<GridInstantMessage> spReceivedMessages = new List<GridInstantMessage>();
171 tc.OnReceivedInstantMessage += im => spReceivedMessages.Add(im);
172
173 List<GridInstantMessage> sp2ReceivedMessages = new List<GridInstantMessage>();
174 tc2.OnReceivedInstantMessage += im => sp2ReceivedMessages.Add(im);
175
176 GridInstantMessage noticeIm = new GridInstantMessage();
177 noticeIm.fromAgentID = userId.Guid;
178 noticeIm.toAgentID = groupID.Guid;
179 noticeIm.message = combinedSubjectMessage;
180 noticeIm.dialog = (byte)InstantMessageDialog.GroupNotice;
181
182 tc.HandleImprovedInstantMessage(noticeIm);
183
184 Assert.That(spReceivedMessages.Count, Is.EqualTo(1));
185 Assert.That(spReceivedMessages[0].message, Is.EqualTo(combinedSubjectMessage));
186
187 List<GroupNoticeData> notices = mgsc.GetGroupNotices(UUID.Zero, groupID);
188 Assert.AreEqual(1, notices.Count);
189
190 // OpenSimulator (possibly also SL) transport the notice ID as the session ID!
191 Assert.AreEqual(notices[0].NoticeID.Guid, spReceivedMessages[0].imSessionID);
192
193 Assert.That(sp2ReceivedMessages.Count, Is.EqualTo(0));
194 }
195
196 /// <summary>
197 /// Run test with the MessageOnlineUsersOnly flag set.
198 /// </summary>
199 [Test]
200 public void TestSendGroupNoticeOnlineOnly()
201 {
202 TestHelpers.InMethod();
203 // TestHelpers.EnableLogging();
204
205 TestScene scene = new SceneHelpers().SetupScene();
206
207 MessageTransferModule mtm = new MessageTransferModule();
208 GroupsModule gm = new GroupsModule();
209 GroupsMessagingModule gmm = new GroupsMessagingModule();
210
211 IConfigSource configSource = new IniConfigSource();
212
213 {
214 IConfig config = configSource.AddConfig("Messaging");
215 config.Set("MessageTransferModule", mtm.Name);
216 }
217
218 {
219 IConfig config = configSource.AddConfig("Groups");
220 config.Set("Enabled", true);
221 config.Set("Module", gm.Name);
222 config.Set("DebugEnabled", true);
223 config.Set("MessagingModule", gmm.Name);
224 config.Set("MessagingEnabled", true);
225 config.Set("MessageOnlineUsersOnly", true);
226 }
227
228 SceneHelpers.SetupSceneModules(scene, configSource, new MockGroupsServicesConnector(), mtm, gm, gmm);
229
230 UUID userId = TestHelpers.ParseTail(0x1);
231 string subjectText = "newman";
232 string messageText = "Hello";
233 string combinedSubjectMessage = string.Format("{0}|{1}", subjectText, messageText);
234
235 ScenePresence sp = SceneHelpers.AddScenePresence(scene, TestHelpers.ParseTail(0x1));
236 TestClient tc = (TestClient)sp.ControllingClient;
237
238 UUID groupID = gm.CreateGroup(tc, "group1", null, true, UUID.Zero, 0, true, true, true);
239 gm.JoinGroupRequest(tc, groupID);
240
241 // Create a second user who doesn't want to receive notices
242 ScenePresence sp2 = SceneHelpers.AddScenePresence(scene, TestHelpers.ParseTail(0x2));
243 TestClient tc2 = (TestClient)sp2.ControllingClient;
244 gm.JoinGroupRequest(tc2, groupID);
245 gm.SetGroupAcceptNotices(tc2, groupID, false, true);
246
247 List<GridInstantMessage> spReceivedMessages = new List<GridInstantMessage>();
248 tc.OnReceivedInstantMessage += im => spReceivedMessages.Add(im);
249
250 List<GridInstantMessage> sp2ReceivedMessages = new List<GridInstantMessage>();
251 tc2.OnReceivedInstantMessage += im => sp2ReceivedMessages.Add(im);
252
253 GridInstantMessage noticeIm = new GridInstantMessage();
254 noticeIm.fromAgentID = userId.Guid;
255 noticeIm.toAgentID = groupID.Guid;
256 noticeIm.message = combinedSubjectMessage;
257 noticeIm.dialog = (byte)InstantMessageDialog.GroupNotice;
258
259 tc.HandleImprovedInstantMessage(noticeIm);
260
261 Assert.That(spReceivedMessages.Count, Is.EqualTo(1));
262 Assert.That(spReceivedMessages[0].message, Is.EqualTo(combinedSubjectMessage));
263
264 Assert.That(sp2ReceivedMessages.Count, Is.EqualTo(0));
61 } 265 }
62 } 266 }
63} \ No newline at end of file 267} \ No newline at end of file
diff --git a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/XmlRpcGroupsServicesConnectorModule.cs b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/XmlRpcGroupsServicesConnectorModule.cs
index 1101851..20555e4 100644
--- a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/XmlRpcGroupsServicesConnectorModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/XmlRpcGroupsServicesConnectorModule.cs
@@ -41,7 +41,6 @@ using OpenMetaverse;
41using OpenMetaverse.StructuredData; 41using OpenMetaverse.StructuredData;
42 42
43using OpenSim.Framework; 43using OpenSim.Framework;
44using OpenSim.Framework.Communications;
45using OpenSim.Region.Framework.Interfaces; 44using OpenSim.Region.Framework.Interfaces;
46using OpenSim.Services.Interfaces; 45using OpenSim.Services.Interfaces;
47 46
@@ -168,8 +167,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
168 m_log.DebugFormat("[XMLRPC-GROUPS-CONNECTOR]: Initializing {0}", this.Name); 167 m_log.DebugFormat("[XMLRPC-GROUPS-CONNECTOR]: Initializing {0}", this.Name);
169 168
170 m_groupsServerURI = groupsConfig.GetString("GroupsServerURI", string.Empty); 169 m_groupsServerURI = groupsConfig.GetString("GroupsServerURI", string.Empty);
171 if ((m_groupsServerURI == null) || 170 if (string.IsNullOrEmpty(m_groupsServerURI))
172 (m_groupsServerURI == string.Empty))
173 { 171 {
174 m_log.ErrorFormat("Please specify a valid URL for GroupsServerURI in OpenSim.ini, [Groups]"); 172 m_log.ErrorFormat("Please specify a valid URL for GroupsServerURI in OpenSim.ini, [Groups]");
175 m_connectorEnabled = false; 173 m_connectorEnabled = false;
@@ -354,7 +352,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
354 { 352 {
355 param["GroupID"] = GroupID.ToString(); 353 param["GroupID"] = GroupID.ToString();
356 } 354 }
357 if ((GroupName != null) && (GroupName != string.Empty)) 355 if (!string.IsNullOrEmpty(GroupName))
358 { 356 {
359 param["Name"] = GroupName.ToString(); 357 param["Name"] = GroupName.ToString();
360 } 358 }
@@ -1013,7 +1011,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
1013 Hashtable respData = (Hashtable)resp.Value; 1011 Hashtable respData = (Hashtable)resp.Value;
1014 if (respData.Contains("error") && !respData.Contains("succeed")) 1012 if (respData.Contains("error") && !respData.Contains("succeed"))
1015 { 1013 {
1016 LogRespDataToConsoleError(respData); 1014 LogRespDataToConsoleError(requestingAgentID, function, param, respData);
1017 } 1015 }
1018 1016
1019 return respData; 1017 return respData;
@@ -1041,20 +1039,11 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
1041 return error; 1039 return error;
1042 } 1040 }
1043 1041
1044 private void LogRespDataToConsoleError(Hashtable respData) 1042 private void LogRespDataToConsoleError(UUID requestingAgentID, string function, Hashtable param, Hashtable respData)
1045 { 1043 {
1046 m_log.Error("[XMLRPC-GROUPS-CONNECTOR]: Error:"); 1044 m_log.ErrorFormat(
1047 1045 "[XMLRPC-GROUPS-CONNECTOR]: Error when calling {0} for {1} with params {2}. Response params are {3}",
1048 foreach (string key in respData.Keys) 1046 function, requestingAgentID, Util.PrettyFormatToSingleLine(param), Util.PrettyFormatToSingleLine(respData));
1049 {
1050 m_log.ErrorFormat("[XMLRPC-GROUPS-CONNECTOR]: Key: {0}", key);
1051
1052 string[] lines = respData[key].ToString().Split(new char[] { '\n' });
1053 foreach (string line in lines)
1054 {
1055 m_log.ErrorFormat("[XMLRPC-GROUPS-CONNECTOR]: {0}", line);
1056 }
1057 }
1058 } 1047 }
1059 1048
1060 /// <summary> 1049 /// <summary>
@@ -1146,28 +1135,38 @@ namespace Nwc.XmlRpc
1146 request.AllowWriteStreamBuffering = true; 1135 request.AllowWriteStreamBuffering = true;
1147 request.KeepAlive = !_disableKeepAlive; 1136 request.KeepAlive = !_disableKeepAlive;
1148 1137
1149 Stream stream = request.GetRequestStream(); 1138 using (Stream stream = request.GetRequestStream())
1150 XmlTextWriter xml = new XmlTextWriter(stream, Encoding.ASCII);
1151 _serializer.Serialize(xml, this);
1152 xml.Flush();
1153 xml.Close();
1154
1155 HttpWebResponse response = (HttpWebResponse)request.GetResponse();
1156 StreamReader input = new StreamReader(response.GetResponseStream());
1157
1158 string inputXml = input.ReadToEnd();
1159 XmlRpcResponse resp;
1160 try
1161 { 1139 {
1162 resp = (XmlRpcResponse)_deserializer.Deserialize(inputXml); 1140 using (XmlTextWriter xml = new XmlTextWriter(stream, Encoding.ASCII))
1141 {
1142 _serializer.Serialize(xml, this);
1143 xml.Flush();
1144 }
1163 } 1145 }
1164 catch (Exception e) 1146
1147 XmlRpcResponse resp;
1148
1149 using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
1165 { 1150 {
1166 RequestResponse = inputXml; 1151 using (Stream s = response.GetResponseStream())
1167 throw e; 1152 {
1153 using (StreamReader input = new StreamReader(s))
1154 {
1155 string inputXml = input.ReadToEnd();
1156
1157 try
1158 {
1159 resp = (XmlRpcResponse)_deserializer.Deserialize(inputXml);
1160 }
1161 catch (Exception e)
1162 {
1163 RequestResponse = inputXml;
1164 throw e;
1165 }
1166 }
1167 }
1168 } 1168 }
1169 input.Close(); 1169
1170 response.Close();
1171 return resp; 1170 return resp;
1172 } 1171 }
1173 } 1172 }
diff --git a/OpenSim/Region/OptionalModules/DataSnapshot/DataRequestHandler.cs b/OpenSim/Region/OptionalModules/DataSnapshot/DataRequestHandler.cs
new file mode 100644
index 0000000..50276ae
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/DataSnapshot/DataRequestHandler.cs
@@ -0,0 +1,99 @@
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
29using System.Collections;
30using System.Reflection;
31using System.Xml;
32using log4net;
33using OpenMetaverse;
34using OpenSim.Framework;
35using OpenSim.Framework.Capabilities;
36using OpenSim.Framework.Servers;
37using OpenSim.Framework.Servers.HttpServer;
38using OpenSim.Region.Framework.Scenes;
39using Caps = OpenSim.Framework.Capabilities.Caps;
40
41namespace OpenSim.Region.DataSnapshot
42{
43 public class DataRequestHandler
44 {
45// private Scene m_scene = null;
46 private DataSnapshotManager m_externalData = null;
47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48
49 public DataRequestHandler(Scene scene, DataSnapshotManager externalData)
50 {
51// m_scene = scene;
52 m_externalData = externalData;
53
54 //Register HTTP handler
55 if (MainServer.Instance.AddHTTPHandler("collector", OnGetSnapshot))
56 {
57 m_log.Info("[DATASNAPSHOT]: Set up snapshot service");
58 }
59 // Register validation callback handler
60 MainServer.Instance.AddHTTPHandler("validate", OnValidate);
61
62 }
63
64 public Hashtable OnGetSnapshot(Hashtable keysvals)
65 {
66 m_log.Debug("[DATASNAPSHOT] Received collection request");
67 Hashtable reply = new Hashtable();
68 int statuscode = 200;
69
70 string snapObj = (string)keysvals["region"];
71
72 XmlDocument response = m_externalData.GetSnapshot(snapObj);
73
74 reply["str_response_string"] = response.OuterXml;
75 reply["int_response_code"] = statuscode;
76 reply["content_type"] = "text/xml";
77
78 return reply;
79 }
80
81 public Hashtable OnValidate(Hashtable keysvals)
82 {
83 m_log.Debug("[DATASNAPSHOT] Received validation request");
84 Hashtable reply = new Hashtable();
85 int statuscode = 200;
86
87 string secret = (string)keysvals["secret"];
88 if (secret == m_externalData.Secret.ToString())
89 statuscode = 403;
90
91 reply["str_response_string"] = string.Empty;
92 reply["int_response_code"] = statuscode;
93 reply["content_type"] = "text/plain";
94
95 return reply;
96 }
97
98 }
99}
diff --git a/OpenSim/Region/OptionalModules/DataSnapshot/DataSnapshotManager.cs b/OpenSim/Region/OptionalModules/DataSnapshot/DataSnapshotManager.cs
new file mode 100644
index 0000000..0c3446d
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/DataSnapshot/DataSnapshotManager.cs
@@ -0,0 +1,487 @@
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
29using System;
30using System.Collections.Generic;
31using System.IO;
32using System.Linq;
33using System.Net;
34using System.Reflection;
35using System.Text;
36using System.Xml;
37using log4net;
38using Nini.Config;
39using OpenMetaverse;
40using Mono.Addins;
41using OpenSim.Framework;
42using OpenSim.Region.DataSnapshot.Interfaces;
43using OpenSim.Region.Framework.Interfaces;
44using OpenSim.Region.Framework.Scenes;
45
46namespace OpenSim.Region.DataSnapshot
47{
48 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DataSnapshotManager")]
49 public class DataSnapshotManager : ISharedRegionModule, IDataSnapshot
50 {
51 #region Class members
52 //Information from config
53 private bool m_enabled = false;
54 private bool m_configLoaded = false;
55 private List<string> m_disabledModules = new List<string>();
56 private Dictionary<string, string> m_gridinfo = new Dictionary<string, string>();
57 private string m_snapsDir = "DataSnapshot";
58 private string m_exposure_level = "minimum";
59
60 //Lists of stuff we need
61 private List<Scene> m_scenes = new List<Scene>();
62 private List<IDataSnapshotProvider> m_dataproviders = new List<IDataSnapshotProvider>();
63
64 //Various internal objects
65 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
66 internal object m_syncInit = new object();
67
68 //DataServices and networking
69 private string m_dataServices = "noservices";
70 public string m_listener_port = ConfigSettings.DefaultRegionHttpPort.ToString();
71 public string m_hostname = "127.0.0.1";
72 private UUID m_Secret = UUID.Random();
73 private bool m_servicesNotified = false;
74
75 //Update timers
76 private int m_period = 20; // in seconds
77 private int m_maxStales = 500;
78 private int m_stales = 0;
79 private int m_lastUpdate = 0;
80
81 //Program objects
82 private SnapshotStore m_snapStore = null;
83
84 #endregion
85
86 #region Properties
87
88 public string ExposureLevel
89 {
90 get { return m_exposure_level; }
91 }
92
93 public UUID Secret
94 {
95 get { return m_Secret; }
96 }
97
98 #endregion
99
100 #region Region Module interface
101
102 public void Initialise(IConfigSource config)
103 {
104 if (!m_configLoaded)
105 {
106 m_configLoaded = true;
107 //m_log.Debug("[DATASNAPSHOT]: Loading configuration");
108 //Read from the config for options
109 lock (m_syncInit)
110 {
111 try
112 {
113 m_enabled = config.Configs["DataSnapshot"].GetBoolean("index_sims", m_enabled);
114 string gatekeeper = Util.GetConfigVarFromSections<string>(config, "GatekeeperURI",
115 new string[] { "Startup", "Hypergrid", "GridService" }, String.Empty);
116 // Legacy. Remove soon!
117 if (string.IsNullOrEmpty(gatekeeper))
118 {
119 IConfig conf = config.Configs["GridService"];
120 if (conf != null)
121 gatekeeper = conf.GetString("Gatekeeper", gatekeeper);
122 }
123 if (!string.IsNullOrEmpty(gatekeeper))
124 m_gridinfo.Add("gatekeeperURL", gatekeeper);
125
126 m_gridinfo.Add(
127 "name", config.Configs["DataSnapshot"].GetString("gridname", "the lost continent of hippo"));
128 m_exposure_level = config.Configs["DataSnapshot"].GetString("data_exposure", m_exposure_level);
129 m_period = config.Configs["DataSnapshot"].GetInt("default_snapshot_period", m_period);
130 m_maxStales = config.Configs["DataSnapshot"].GetInt("max_changes_before_update", m_maxStales);
131 m_snapsDir = config.Configs["DataSnapshot"].GetString("snapshot_cache_directory", m_snapsDir);
132 m_listener_port = config.Configs["Network"].GetString("http_listener_port", m_listener_port);
133
134 m_dataServices = config.Configs["DataSnapshot"].GetString("data_services", m_dataServices);
135 // New way of spec'ing data services, one per line
136 AddDataServicesVars(config.Configs["DataSnapshot"]);
137
138 String[] annoying_string_array = config.Configs["DataSnapshot"].GetString("disable_modules", "").Split(".".ToCharArray());
139 foreach (String bloody_wanker in annoying_string_array)
140 {
141 m_disabledModules.Add(bloody_wanker);
142 }
143 m_lastUpdate = Environment.TickCount;
144 }
145 catch (Exception)
146 {
147 m_log.Warn("[DATASNAPSHOT]: Could not load configuration. DataSnapshot will be disabled.");
148 m_enabled = false;
149 return;
150 }
151
152 }
153
154 }
155
156 }
157
158 public void AddRegion(Scene scene)
159 {
160 if (!m_enabled)
161 return;
162
163 m_log.DebugFormat("[DATASNAPSHOT]: Module added to Scene {0}.", scene.RegionInfo.RegionName);
164
165 if (!m_servicesNotified)
166 {
167 m_hostname = scene.RegionInfo.ExternalHostName;
168 m_snapStore = new SnapshotStore(m_snapsDir, m_gridinfo, m_listener_port, m_hostname);
169
170 //Hand it the first scene, assuming that all scenes have the same BaseHTTPServer
171 new DataRequestHandler(scene, this);
172
173 if (m_dataServices != "" && m_dataServices != "noservices")
174 NotifyDataServices(m_dataServices, "online");
175
176 m_servicesNotified = true;
177 }
178
179 m_scenes.Add(scene);
180 m_snapStore.AddScene(scene);
181
182 Assembly currentasm = Assembly.GetExecutingAssembly();
183
184 foreach (Type pluginType in currentasm.GetTypes())
185 {
186 if (pluginType.IsPublic)
187 {
188 if (!pluginType.IsAbstract)
189 {
190 if (pluginType.GetInterface("IDataSnapshotProvider") != null)
191 {
192 IDataSnapshotProvider module = (IDataSnapshotProvider)Activator.CreateInstance(pluginType);
193 module.Initialize(scene, this);
194 module.OnStale += MarkDataStale;
195
196 m_dataproviders.Add(module);
197 m_snapStore.AddProvider(module);
198
199 m_log.Debug("[DATASNAPSHOT]: Added new data provider type: " + pluginType.Name);
200 }
201 }
202 }
203 }
204
205 }
206
207 public void RemoveRegion(Scene scene)
208 {
209 if (!m_enabled)
210 return;
211
212 m_log.Info("[DATASNAPSHOT]: Region " + scene.RegionInfo.RegionName + " is being removed, removing from indexing");
213 Scene restartedScene = SceneForUUID(scene.RegionInfo.RegionID);
214
215 m_scenes.Remove(restartedScene);
216 m_snapStore.RemoveScene(restartedScene);
217
218 //Getting around the fact that we can't remove objects from a collection we are enumerating over
219 List<IDataSnapshotProvider> providersToRemove = new List<IDataSnapshotProvider>();
220
221 foreach (IDataSnapshotProvider provider in m_dataproviders)
222 {
223 if (provider.GetParentScene == restartedScene)
224 {
225 providersToRemove.Add(provider);
226 }
227 }
228
229 foreach (IDataSnapshotProvider provider in providersToRemove)
230 {
231 m_dataproviders.Remove(provider);
232 m_snapStore.RemoveProvider(provider);
233 }
234
235 m_snapStore.RemoveScene(restartedScene);
236 }
237
238 public void PostInitialise()
239 {
240 }
241
242 public void RegionLoaded(Scene scene)
243 {
244 if (!m_enabled)
245 return;
246
247 m_log.DebugFormat("[DATASNAPSHOT]: Marking scene {0} as stale.", scene.RegionInfo.RegionName);
248 m_snapStore.ForceSceneStale(scene);
249 }
250
251 public void Close()
252 {
253 if (!m_enabled)
254 return;
255
256 if (m_enabled && m_dataServices != "" && m_dataServices != "noservices")
257 NotifyDataServices(m_dataServices, "offline");
258 }
259
260
261 public string Name
262 {
263 get { return "External Data Generator"; }
264 }
265
266 public Type ReplaceableInterface
267 {
268 get { return null; }
269 }
270
271 #endregion
272
273 #region Associated helper functions
274
275 public Scene SceneForName(string name)
276 {
277 foreach (Scene scene in m_scenes)
278 if (scene.RegionInfo.RegionName == name)
279 return scene;
280
281 return null;
282 }
283
284 public Scene SceneForUUID(UUID id)
285 {
286 foreach (Scene scene in m_scenes)
287 if (scene.RegionInfo.RegionID == id)
288 return scene;
289
290 return null;
291 }
292
293 private void AddDataServicesVars(IConfig config)
294 {
295 // Make sure the services given this way aren't in m_dataServices already
296 List<string> servs = new List<string>(m_dataServices.Split(new char[] { ';' }));
297
298 StringBuilder sb = new StringBuilder();
299 string[] keys = config.GetKeys();
300
301 if (keys.Length > 0)
302 {
303 IEnumerable<string> serviceKeys = keys.Where(value => value.StartsWith("DATA_SRV_"));
304 foreach (string serviceKey in serviceKeys)
305 {
306 string keyValue = config.GetString(serviceKey, string.Empty).Trim();
307 if (!servs.Contains(keyValue))
308 sb.Append(keyValue).Append(";");
309 }
310 }
311
312 m_dataServices = (m_dataServices == "noservices") ? sb.ToString() : sb.Append(m_dataServices).ToString();
313 }
314
315 #endregion
316
317 #region [Public] Snapshot storage functions
318
319 /**
320 * Reply to the http request
321 */
322 public XmlDocument GetSnapshot(string regionName)
323 {
324 CheckStale();
325
326 XmlDocument requestedSnap = new XmlDocument();
327 requestedSnap.AppendChild(requestedSnap.CreateXmlDeclaration("1.0", null, null));
328 requestedSnap.AppendChild(requestedSnap.CreateWhitespace("\r\n"));
329
330 XmlNode regiondata = requestedSnap.CreateNode(XmlNodeType.Element, "regiondata", "");
331 try
332 {
333 if (string.IsNullOrEmpty(regionName))
334 {
335 XmlNode timerblock = requestedSnap.CreateNode(XmlNodeType.Element, "expire", "");
336 timerblock.InnerText = m_period.ToString();
337 regiondata.AppendChild(timerblock);
338
339 regiondata.AppendChild(requestedSnap.CreateWhitespace("\r\n"));
340 foreach (Scene scene in m_scenes)
341 {
342 regiondata.AppendChild(m_snapStore.GetScene(scene, requestedSnap));
343 }
344 }
345 else
346 {
347 Scene scene = SceneForName(regionName);
348 regiondata.AppendChild(m_snapStore.GetScene(scene, requestedSnap));
349 }
350 requestedSnap.AppendChild(regiondata);
351 regiondata.AppendChild(requestedSnap.CreateWhitespace("\r\n"));
352 }
353 catch (XmlException e)
354 {
355 m_log.Warn("[DATASNAPSHOT]: XmlException while trying to load snapshot: " + e.ToString());
356 requestedSnap = GetErrorMessage(regionName, e);
357 }
358 catch (Exception e)
359 {
360 m_log.Warn("[DATASNAPSHOT]: Caught unknown exception while trying to load snapshot: " + e.StackTrace);
361 requestedSnap = GetErrorMessage(regionName, e);
362 }
363
364
365 return requestedSnap;
366 }
367
368 private XmlDocument GetErrorMessage(string regionName, Exception e)
369 {
370 XmlDocument errorMessage = new XmlDocument();
371 XmlNode error = errorMessage.CreateNode(XmlNodeType.Element, "error", "");
372 XmlNode region = errorMessage.CreateNode(XmlNodeType.Element, "region", "");
373 region.InnerText = regionName;
374
375 XmlNode exception = errorMessage.CreateNode(XmlNodeType.Element, "exception", "");
376 exception.InnerText = e.ToString();
377
378 error.AppendChild(region);
379 error.AppendChild(exception);
380 errorMessage.AppendChild(error);
381
382 return errorMessage;
383 }
384
385 #endregion
386
387 #region External data services
388 private void NotifyDataServices(string servicesStr, string serviceName)
389 {
390 Stream reply = null;
391 string delimStr = ";";
392 char [] delimiter = delimStr.ToCharArray();
393
394 string[] services = servicesStr.Split(delimiter, StringSplitOptions.RemoveEmptyEntries);
395
396 for (int i = 0; i < services.Length; i++)
397 {
398 string url = services[i].Trim();
399 using (RestClient cli = new RestClient(url))
400 {
401 cli.AddQueryParameter("service", serviceName);
402 cli.AddQueryParameter("host", m_hostname);
403 cli.AddQueryParameter("port", m_listener_port);
404 cli.AddQueryParameter("secret", m_Secret.ToString());
405 cli.RequestMethod = "GET";
406 try
407 {
408 reply = cli.Request(null);
409 }
410 catch (WebException)
411 {
412 m_log.Warn("[DATASNAPSHOT]: Unable to notify " + url);
413 }
414 catch (Exception e)
415 {
416 m_log.Warn("[DATASNAPSHOT]: Ignoring unknown exception " + e.ToString());
417 }
418
419 byte[] response = new byte[1024];
420 // int n = 0;
421 try
422 {
423 // n = reply.Read(response, 0, 1024);
424 reply.Read(response, 0, 1024);
425 }
426 catch (Exception e)
427 {
428 m_log.WarnFormat("[DATASNAPSHOT]: Unable to decode reply from data service. Ignoring. {0}", e.StackTrace);
429 }
430 // This is not quite working, so...
431 // string responseStr = Util.UTF8.GetString(response);
432 m_log.Info("[DATASNAPSHOT]: data service " + url + " notified. Secret: " + m_Secret);
433 }
434 }
435
436 }
437 #endregion
438
439 #region Latency-based update functions
440
441 public void MarkDataStale(IDataSnapshotProvider provider)
442 {
443 //Behavior here: Wait m_period seconds, then update if there has not been a request in m_period seconds
444 //or m_maxStales has been exceeded
445 m_stales++;
446 }
447
448 private void CheckStale()
449 {
450 // Wrap check
451 if (Environment.TickCount < m_lastUpdate)
452 {
453 m_lastUpdate = Environment.TickCount;
454 }
455
456 if (m_stales >= m_maxStales)
457 {
458 if (Environment.TickCount - m_lastUpdate >= 20000)
459 {
460 m_stales = 0;
461 m_lastUpdate = Environment.TickCount;
462 MakeEverythingStale();
463 }
464 }
465 else
466 {
467 if (m_lastUpdate + 1000 * m_period < Environment.TickCount)
468 {
469 m_stales = 0;
470 m_lastUpdate = Environment.TickCount;
471 MakeEverythingStale();
472 }
473 }
474 }
475
476 public void MakeEverythingStale()
477 {
478 m_log.Debug("[DATASNAPSHOT]: Marking all scenes as stale.");
479 foreach (Scene scene in m_scenes)
480 {
481 m_snapStore.ForceSceneStale(scene);
482 }
483 }
484 #endregion
485
486 }
487}
diff --git a/OpenSim/Region/OptionalModules/DataSnapshot/EstateSnapshot.cs b/OpenSim/Region/OptionalModules/DataSnapshot/EstateSnapshot.cs
new file mode 100644
index 0000000..8da9e8c
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/DataSnapshot/EstateSnapshot.cs
@@ -0,0 +1,149 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Xml;
30using OpenMetaverse;
31using OpenSim.Framework;
32
33using OpenSim.Region.DataSnapshot.Interfaces;
34using OpenSim.Region.Framework.Scenes;
35using OpenSim.Services.Interfaces;
36
37namespace OpenSim.Region.DataSnapshot.Providers
38{
39 public class EstateSnapshot : IDataSnapshotProvider
40 {
41 /* This module doesn't check for changes, since it's *assumed* there are none.
42 * Nevertheless, it's possible to have changes, since all the fields are public.
43 * There's no event to subscribe to. :/
44 *
45 * I don't think anything changes the fields beyond RegionModule PostInit, however.
46 */
47 private Scene m_scene = null;
48 // private DataSnapshotManager m_parent = null;
49 private bool m_stale = true;
50
51 #region IDataSnapshotProvider Members
52
53 public XmlNode RequestSnapshotData(XmlDocument factory)
54 {
55 //Estate data section - contains who owns a set of sims and the name of the set.
56 //Now in DataSnapshotProvider module form!
57 XmlNode estatedata = factory.CreateNode(XmlNodeType.Element, "estate", "");
58
59 UUID ownerid = m_scene.RegionInfo.EstateSettings.EstateOwner;
60
61 UserAccount userInfo = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, ownerid);
62 //TODO: Change to query userserver about the master avatar UUID ?
63 String firstname;
64 String lastname;
65
66 if (userInfo != null)
67 {
68 firstname = userInfo.FirstName;
69 lastname = userInfo.LastName;
70
71 //TODO: Fix the marshalling system to have less copypasta gruntwork
72 XmlNode user = factory.CreateNode(XmlNodeType.Element, "user", "");
73// XmlAttribute type = (XmlAttribute)factory.CreateNode(XmlNodeType.Attribute, "type", "");
74// type.Value = "owner";
75// user.Attributes.Append(type);
76
77 //TODO: Create more TODOs
78 XmlNode username = factory.CreateNode(XmlNodeType.Element, "name", "");
79 username.InnerText = firstname + " " + lastname;
80 user.AppendChild(username);
81
82 XmlNode useruuid = factory.CreateNode(XmlNodeType.Element, "uuid", "");
83 useruuid.InnerText = ownerid.ToString();
84 user.AppendChild(useruuid);
85
86 estatedata.AppendChild(user);
87 }
88
89 XmlNode estatename = factory.CreateNode(XmlNodeType.Element, "name", "");
90 estatename.InnerText = m_scene.RegionInfo.EstateSettings.EstateName.ToString();
91 estatedata.AppendChild(estatename);
92
93 XmlNode estateid = factory.CreateNode(XmlNodeType.Element, "id", "");
94 estateid.InnerText = m_scene.RegionInfo.EstateSettings.EstateID.ToString();
95 estatedata.AppendChild(estateid);
96
97 XmlNode parentid = factory.CreateNode(XmlNodeType.Element, "parentid", "");
98 parentid.InnerText = m_scene.RegionInfo.EstateSettings.ParentEstateID.ToString();
99 estatedata.AppendChild(parentid);
100
101 XmlNode flags = factory.CreateNode(XmlNodeType.Element, "flags", "");
102
103 XmlAttribute teleport = (XmlAttribute)factory.CreateNode(XmlNodeType.Attribute, "teleport", "");
104 teleport.Value = m_scene.RegionInfo.EstateSettings.AllowDirectTeleport.ToString();
105 flags.Attributes.Append(teleport);
106
107 XmlAttribute publicaccess = (XmlAttribute)factory.CreateNode(XmlNodeType.Attribute, "public", "");
108 publicaccess.Value = m_scene.RegionInfo.EstateSettings.PublicAccess.ToString();
109 flags.Attributes.Append(publicaccess);
110
111 estatedata.AppendChild(flags);
112
113 this.Stale = false;
114 return estatedata;
115 }
116
117 public void Initialize(Scene scene, DataSnapshotManager parent)
118 {
119 m_scene = scene;
120 // m_parent = parent;
121 }
122
123 public Scene GetParentScene
124 {
125 get { return m_scene; }
126 }
127
128 public String Name {
129 get { return "EstateSnapshot"; }
130 }
131
132 public bool Stale
133 {
134 get {
135 return m_stale;
136 }
137 set {
138 m_stale = value;
139
140 if (m_stale)
141 OnStale(this);
142 }
143 }
144
145 public event ProviderStale OnStale;
146
147 #endregion
148 }
149}
diff --git a/OpenSim/Region/OptionalModules/DataSnapshot/Interfaces/IDataSnapshot.cs b/OpenSim/Region/OptionalModules/DataSnapshot/Interfaces/IDataSnapshot.cs
new file mode 100644
index 0000000..3b3db65
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/DataSnapshot/Interfaces/IDataSnapshot.cs
@@ -0,0 +1,36 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System.Xml;
29
30namespace OpenSim.Region.DataSnapshot.Interfaces
31{
32 public interface IDataSnapshot
33 {
34 XmlDocument GetSnapshot(string regionName);
35 }
36}
diff --git a/OpenSim/Region/OptionalModules/DataSnapshot/Interfaces/IDataSnapshotProvider.cs b/OpenSim/Region/OptionalModules/DataSnapshot/Interfaces/IDataSnapshotProvider.cs
new file mode 100644
index 0000000..daea373
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/DataSnapshot/Interfaces/IDataSnapshotProvider.cs
@@ -0,0 +1,46 @@
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
29using System;
30using System.Xml;
31using OpenSim.Region.Framework.Scenes;
32
33namespace OpenSim.Region.DataSnapshot.Interfaces
34{
35 public delegate void ProviderStale(IDataSnapshotProvider provider);
36
37 public interface IDataSnapshotProvider
38 {
39 XmlNode RequestSnapshotData(XmlDocument document);
40 void Initialize(Scene scene, DataSnapshotManager parent);
41 Scene GetParentScene { get; }
42 String Name { get; }
43 bool Stale { get; set; }
44 event ProviderStale OnStale;
45 }
46}
diff --git a/OpenSim/Region/OptionalModules/DataSnapshot/LLSDDiscovery.cs b/OpenSim/Region/OptionalModules/DataSnapshot/LLSDDiscovery.cs
new file mode 100644
index 0000000..54a87f9
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/DataSnapshot/LLSDDiscovery.cs
@@ -0,0 +1,44 @@
1/*
2* Copyright (c) Contributors, http://opensimulator.org/
3* See CONTRIBUTORS.TXT for a full list of copyright holders.
4*
5* Redistribution and use in source and binary forms, with or without
6* modification, are permitted provided that the following conditions are met:
7* * Redistributions of source code must retain the above copyright
8* notice, this list of conditions and the following disclaimer.
9* * Redistributions in binary form must reproduce the above copyright
10* notice, this list of conditions and the following disclaimer in the
11* documentation and/or other materials provided with the distribution.
12* * Neither the name of the OpenSimulator Project nor the
13* names of its contributors may be used to endorse or promote products
14* derived from this software without specific prior written permission.
15*
16* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*/
27
28using OpenSim.Framework.Capabilities;
29
30namespace OpenSim.Region.DataSnapshot
31{
32 [OSDMap]
33 public class LLSDDiscoveryResponse
34 {
35 public OSDArray snapshot_resources;
36 }
37
38 [OSDMap]
39 public class LLSDDiscoveryDataURL
40 {
41 public string snapshot_format;
42 public string snapshot_url;
43 }
44}
diff --git a/OpenSim/Region/OptionalModules/DataSnapshot/LandSnapshot.cs b/OpenSim/Region/OptionalModules/DataSnapshot/LandSnapshot.cs
new file mode 100644
index 0000000..b8c90cd
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/DataSnapshot/LandSnapshot.cs
@@ -0,0 +1,433 @@
1/*
2* Copyright (c) Contributors, http://opensimulator.org/
3* See CONTRIBUTORS.TXT for a full list of copyright holders.
4*
5* Redistribution and use in source and binary forms, with or without
6* modification, are permitted provided that the following conditions are met:
7* * Redistributions of source code must retain the above copyright
8* notice, this list of conditions and the following disclaimer.
9* * Redistributions in binary form must reproduce the above copyright
10* notice, this list of conditions and the following disclaimer in the
11* documentation and/or other materials provided with the distribution.
12* * Neither the name of the OpenSimulator Project nor the
13* names of its contributors may be used to endorse or promote products
14* derived from this software without specific prior written permission.
15*
16* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*/
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using System.Xml;
32using log4net;
33using OpenMetaverse;
34using OpenSim.Framework;
35
36using OpenSim.Region.CoreModules.World.Land;
37using OpenSim.Region.DataSnapshot.Interfaces;
38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes;
40using OpenSim.Services.Interfaces;
41
42namespace OpenSim.Region.DataSnapshot.Providers
43{
44 public class LandSnapshot : IDataSnapshotProvider
45 {
46 private Scene m_scene = null;
47 private DataSnapshotManager m_parent = null;
48 //private Dictionary<int, Land> m_landIndexed = new Dictionary<int, Land>();
49 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
50 private bool m_stale = true;
51
52 #region Dead code
53
54 /*
55 * David, I don't think we need this at all. When we do the snapshot, we can
56 * simply look into the parcels that are marked for ShowDirectory -- see
57 * conditional in RequestSnapshotData
58 *
59 //Revise this, look for more direct way of checking for change in land
60 #region Client hooks
61
62 public void OnNewClient(IClientAPI client)
63 {
64 //Land hooks
65 client.OnParcelDivideRequest += ParcelSplitHook;
66 client.OnParcelJoinRequest += ParcelSplitHook;
67 client.OnParcelPropertiesUpdateRequest += ParcelPropsHook;
68 }
69
70 public void ParcelSplitHook(int west, int south, int east, int north, IClientAPI remote_client)
71 {
72 PrepareData();
73 }
74
75 public void ParcelPropsHook(ParcelPropertiesUpdatePacket packet, IClientAPI remote_client)
76 {
77 PrepareData();
78 }
79
80 #endregion
81
82 public void PrepareData()
83 {
84 m_log.Info("[EXTERNALDATA]: Generating land data.");
85
86 m_landIndexed.Clear();
87
88 //Index sim land
89 foreach (KeyValuePair<int, Land> curLand in m_scene.LandManager.landList)
90 {
91 //if ((curLand.Value.LandData.landFlags & (uint)ParcelFlags.ShowDirectory) == (uint)ParcelFlags.ShowDirectory)
92 //{
93 m_landIndexed.Add(curLand.Key, curLand.Value.Copy());
94 //}
95 }
96 }
97
98 public Dictionary<int,Land> IndexedLand {
99 get { return m_landIndexed; }
100 }
101 */
102
103 #endregion
104
105 #region IDataSnapshotProvider members
106
107 public void Initialize(Scene scene, DataSnapshotManager parent)
108 {
109 m_scene = scene;
110 m_parent = parent;
111
112 //Brought back from the dead for staleness checks.
113 m_scene.EventManager.OnNewClient += OnNewClient;
114 }
115
116 public Scene GetParentScene
117 {
118 get { return m_scene; }
119 }
120
121 public XmlNode RequestSnapshotData(XmlDocument nodeFactory)
122 {
123 ILandChannel landChannel = m_scene.LandChannel;
124 List<ILandObject> parcels = landChannel.AllParcels();
125
126 IDwellModule dwellModule = m_scene.RequestModuleInterface<IDwellModule>();
127
128 XmlNode parent = nodeFactory.CreateNode(XmlNodeType.Element, "parceldata", "");
129 if (parcels != null)
130 {
131
132 //foreach (KeyValuePair<int, Land> curParcel in m_landIndexed)
133 foreach (ILandObject parcel_interface in parcels)
134 {
135 // Play it safe
136 if (!(parcel_interface is LandObject))
137 continue;
138
139 LandObject land = (LandObject)parcel_interface;
140
141 LandData parcel = land.LandData;
142 if (m_parent.ExposureLevel.Equals("all") ||
143 (m_parent.ExposureLevel.Equals("minimum") &&
144 (parcel.Flags & (uint)ParcelFlags.ShowDirectory) == (uint)ParcelFlags.ShowDirectory))
145 {
146
147 //TODO: make better method of marshalling data from LandData to XmlNode
148 XmlNode xmlparcel = nodeFactory.CreateNode(XmlNodeType.Element, "parcel", "");
149
150 // Attributes of the parcel node
151 XmlAttribute scripts_attr = nodeFactory.CreateAttribute("scripts");
152 scripts_attr.Value = GetScriptsPermissions(parcel);
153 XmlAttribute build_attr = nodeFactory.CreateAttribute("build");
154 build_attr.Value = GetBuildPermissions(parcel);
155 XmlAttribute public_attr = nodeFactory.CreateAttribute("public");
156 public_attr.Value = GetPublicPermissions(parcel);
157 // Check the category of the Parcel
158 XmlAttribute category_attr = nodeFactory.CreateAttribute("category");
159 category_attr.Value = ((int)parcel.Category).ToString();
160 // Check if the parcel is for sale
161 XmlAttribute forsale_attr = nodeFactory.CreateAttribute("forsale");
162 forsale_attr.Value = CheckForSale(parcel);
163 XmlAttribute sales_attr = nodeFactory.CreateAttribute("salesprice");
164 sales_attr.Value = parcel.SalePrice.ToString();
165
166 XmlAttribute directory_attr = nodeFactory.CreateAttribute("showinsearch");
167 directory_attr.Value = GetShowInSearch(parcel);
168 //XmlAttribute entities_attr = nodeFactory.CreateAttribute("entities");
169 //entities_attr.Value = land.primsOverMe.Count.ToString();
170 xmlparcel.Attributes.Append(directory_attr);
171 xmlparcel.Attributes.Append(scripts_attr);
172 xmlparcel.Attributes.Append(build_attr);
173 xmlparcel.Attributes.Append(public_attr);
174 xmlparcel.Attributes.Append(category_attr);
175 xmlparcel.Attributes.Append(forsale_attr);
176 xmlparcel.Attributes.Append(sales_attr);
177 //xmlparcel.Attributes.Append(entities_attr);
178
179
180 //name, description, area, and UUID
181 XmlNode name = nodeFactory.CreateNode(XmlNodeType.Element, "name", "");
182 name.InnerText = parcel.Name;
183 xmlparcel.AppendChild(name);
184
185 XmlNode desc = nodeFactory.CreateNode(XmlNodeType.Element, "description", "");
186 desc.InnerText = parcel.Description;
187 xmlparcel.AppendChild(desc);
188
189 XmlNode uuid = nodeFactory.CreateNode(XmlNodeType.Element, "uuid", "");
190 uuid.InnerText = parcel.GlobalID.ToString();
191 xmlparcel.AppendChild(uuid);
192
193 XmlNode area = nodeFactory.CreateNode(XmlNodeType.Element, "area", "");
194 area.InnerText = parcel.Area.ToString();
195 xmlparcel.AppendChild(area);
196
197 //default location
198 XmlNode tpLocation = nodeFactory.CreateNode(XmlNodeType.Element, "location", "");
199 Vector3 loc = parcel.UserLocation;
200 if (loc.Equals(Vector3.Zero)) // This test is moot at this point: the location is wrong by default
201 loc = new Vector3((parcel.AABBMax.X + parcel.AABBMin.X) / 2, (parcel.AABBMax.Y + parcel.AABBMin.Y) / 2, (parcel.AABBMax.Z + parcel.AABBMin.Z) / 2);
202 tpLocation.InnerText = loc.X.ToString() + "/" + loc.Y.ToString() + "/" + loc.Z.ToString();
203 xmlparcel.AppendChild(tpLocation);
204
205 XmlNode infouuid = nodeFactory.CreateNode(XmlNodeType.Element, "infouuid", "");
206 uint x = (uint)loc.X, y = (uint)loc.Y;
207 findPointInParcel(land, ref x, ref y); // find a suitable spot
208 infouuid.InnerText = Util.BuildFakeParcelID(
209 m_scene.RegionInfo.RegionHandle, x, y).ToString();
210 xmlparcel.AppendChild(infouuid);
211
212 XmlNode dwell = nodeFactory.CreateNode(XmlNodeType.Element, "dwell", "");
213 if (dwellModule != null)
214 dwell.InnerText = dwellModule.GetDwell(parcel.GlobalID).ToString();
215 else
216 dwell.InnerText = "0";
217 xmlparcel.AppendChild(dwell);
218
219 //TODO: figure how to figure out teleport system landData.landingType
220
221 //land texture snapshot uuid
222 if (parcel.SnapshotID != UUID.Zero)
223 {
224 XmlNode textureuuid = nodeFactory.CreateNode(XmlNodeType.Element, "image", "");
225 textureuuid.InnerText = parcel.SnapshotID.ToString();
226 xmlparcel.AppendChild(textureuuid);
227 }
228
229 string groupName = String.Empty;
230
231 //attached user and group
232 if (parcel.GroupID != UUID.Zero)
233 {
234 XmlNode groupblock = nodeFactory.CreateNode(XmlNodeType.Element, "group", "");
235 XmlNode groupuuid = nodeFactory.CreateNode(XmlNodeType.Element, "groupuuid", "");
236 groupuuid.InnerText = parcel.GroupID.ToString();
237 groupblock.AppendChild(groupuuid);
238
239 IGroupsModule gm = m_scene.RequestModuleInterface<IGroupsModule>();
240 if (gm != null)
241 {
242 GroupRecord g = gm.GetGroupRecord(parcel.GroupID);
243 if (g != null)
244 groupName = g.GroupName;
245 }
246
247 XmlNode groupname = nodeFactory.CreateNode(XmlNodeType.Element, "groupname", "");
248 groupname.InnerText = groupName;
249 groupblock.AppendChild(groupname);
250
251 xmlparcel.AppendChild(groupblock);
252 }
253
254 XmlNode userblock = nodeFactory.CreateNode(XmlNodeType.Element, "owner", "");
255
256 UUID userOwnerUUID = parcel.OwnerID;
257
258 XmlNode useruuid = nodeFactory.CreateNode(XmlNodeType.Element, "uuid", "");
259 useruuid.InnerText = userOwnerUUID.ToString();
260 userblock.AppendChild(useruuid);
261
262 if (!parcel.IsGroupOwned)
263 {
264 try
265 {
266 XmlNode username = nodeFactory.CreateNode(XmlNodeType.Element, "name", "");
267 UserAccount account = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, userOwnerUUID);
268 username.InnerText = account.FirstName + " " + account.LastName;
269 userblock.AppendChild(username);
270 }
271 catch (Exception)
272 {
273 //m_log.Info("[DATASNAPSHOT]: Cannot find owner name; ignoring this parcel");
274 }
275
276 }
277 else
278 {
279 XmlNode username = nodeFactory.CreateNode(XmlNodeType.Element, "name", "");
280 username.InnerText = groupName;
281 userblock.AppendChild(username);
282 }
283
284 xmlparcel.AppendChild(userblock);
285
286 parent.AppendChild(xmlparcel);
287 }
288 }
289 //snap.AppendChild(parent);
290 }
291
292 this.Stale = false;
293 return parent;
294 }
295
296 public String Name
297 {
298 get { return "LandSnapshot"; }
299 }
300
301 public bool Stale
302 {
303 get
304 {
305 return m_stale;
306 }
307 set
308 {
309 m_stale = value;
310
311 if (m_stale)
312 OnStale(this);
313 }
314 }
315
316 public event ProviderStale OnStale;
317
318 #endregion
319
320 #region Helper functions
321
322 private string GetScriptsPermissions(LandData parcel)
323 {
324 if ((parcel.Flags & (uint)ParcelFlags.AllowOtherScripts) == (uint)ParcelFlags.AllowOtherScripts)
325 return "true";
326 else
327 return "false";
328
329 }
330
331 private string GetPublicPermissions(LandData parcel)
332 {
333 if ((parcel.Flags & (uint)ParcelFlags.UseAccessList) == (uint)ParcelFlags.UseAccessList)
334 return "false";
335 else
336 return "true";
337
338 }
339
340 private string GetBuildPermissions(LandData parcel)
341 {
342 if ((parcel.Flags & (uint)ParcelFlags.CreateObjects) == (uint)ParcelFlags.CreateObjects)
343 return "true";
344 else
345 return "false";
346
347 }
348
349 private string CheckForSale(LandData parcel)
350 {
351 if ((parcel.Flags & (uint)ParcelFlags.ForSale) == (uint)ParcelFlags.ForSale)
352 return "true";
353 else
354 return "false";
355 }
356
357 private string GetShowInSearch(LandData parcel)
358 {
359 if ((parcel.Flags & (uint)ParcelFlags.ShowDirectory) == (uint)ParcelFlags.ShowDirectory)
360 return "true";
361 else
362 return "false";
363
364 }
365
366 #endregion
367
368 #region Change detection hooks
369
370 public void OnNewClient(IClientAPI client)
371 {
372 //Land hooks
373 client.OnParcelDivideRequest += delegate(int west, int south, int east, int north,
374 IClientAPI remote_client) { this.Stale = true; };
375 client.OnParcelJoinRequest += delegate(int west, int south, int east, int north,
376 IClientAPI remote_client) { this.Stale = true; };
377 client.OnParcelPropertiesUpdateRequest += delegate(LandUpdateArgs args, int local_id,
378 IClientAPI remote_client) { this.Stale = true; };
379 client.OnParcelBuy += delegate(UUID agentId, UUID groupId, bool final, bool groupOwned,
380 bool removeContribution, int parcelLocalID, int parcelArea, int parcelPrice, bool authenticated)
381 { this.Stale = true; };
382 }
383
384 public void ParcelSplitHook(int west, int south, int east, int north, IClientAPI remote_client)
385 {
386 this.Stale = true;
387 }
388
389 public void ParcelPropsHook(LandUpdateArgs args, int local_id, IClientAPI remote_client)
390 {
391 this.Stale = true;
392 }
393
394 #endregion
395
396 // this is needed for non-convex parcels (example: rectangular parcel, and in the exact center
397 // another, smaller rectangular parcel). Both will have the same initial coordinates.
398 private void findPointInParcel(ILandObject land, ref uint refX, ref uint refY)
399 {
400 m_log.DebugFormat("[DATASNAPSHOT] trying {0}, {1}", refX, refY);
401 // the point we started with already is in the parcel
402 if (land.ContainsPoint((int)refX, (int)refY)) return;
403
404 // ... otherwise, we have to search for a point within the parcel
405 uint startX = (uint)land.LandData.AABBMin.X;
406 uint startY = (uint)land.LandData.AABBMin.Y;
407 uint endX = (uint)land.LandData.AABBMax.X;
408 uint endY = (uint)land.LandData.AABBMax.Y;
409
410 // default: center of the parcel
411 refX = (startX + endX) / 2;
412 refY = (startY + endY) / 2;
413 // If the center point is within the parcel, take that one
414 if (land.ContainsPoint((int)refX, (int)refY)) return;
415
416 // otherwise, go the long way.
417 for (uint y = startY; y <= endY; ++y)
418 {
419 for (uint x = startX; x <= endX; ++x)
420 {
421 if (land.ContainsPoint((int)x, (int)y))
422 {
423 // found a point
424 refX = x;
425 refY = y;
426 return;
427 }
428 }
429 }
430 }
431 }
432}
433
diff --git a/OpenSim/Region/OptionalModules/DataSnapshot/ObjectSnapshot.cs b/OpenSim/Region/OptionalModules/DataSnapshot/ObjectSnapshot.cs
new file mode 100644
index 0000000..0bb4044
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/DataSnapshot/ObjectSnapshot.cs
@@ -0,0 +1,264 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using System.Xml;
32using log4net;
33using OpenMetaverse;
34using OpenSim.Framework;
35using OpenSim.Region.DataSnapshot.Interfaces;
36using OpenSim.Region.Framework.Interfaces;
37using OpenSim.Region.Framework.Scenes;
38
39namespace OpenSim.Region.DataSnapshot.Providers
40{
41 public class ObjectSnapshot : IDataSnapshotProvider
42 {
43 private Scene m_scene = null;
44 // private DataSnapshotManager m_parent = null;
45 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
46 private bool m_stale = true;
47
48 private static UUID m_DefaultImage = new UUID("89556747-24cb-43ed-920b-47caed15465f");
49 private static UUID m_BlankImage = new UUID("5748decc-f629-461c-9a36-a35a221fe21f");
50
51
52 public void Initialize(Scene scene, DataSnapshotManager parent)
53 {
54 m_scene = scene;
55 // m_parent = parent;
56
57 //To check for staleness, we must catch all incoming client packets.
58 m_scene.EventManager.OnNewClient += OnNewClient;
59 m_scene.EventManager.OnParcelPrimCountAdd += delegate(SceneObjectGroup obj) { this.Stale = true; };
60 }
61
62 public void OnNewClient(IClientAPI client)
63 {
64 //Detect object data changes by hooking into the IClientAPI.
65 //Very dirty, and breaks whenever someone changes the client API.
66
67 client.OnAddPrim += delegate (UUID ownerID, UUID groupID, Vector3 RayEnd, Quaternion rot,
68 PrimitiveBaseShape shape, byte bypassRaycast, Vector3 RayStart, UUID RayTargetID,
69 byte RayEndIsIntersection) { this.Stale = true; };
70 client.OnLinkObjects += delegate (IClientAPI remoteClient, uint parent, List<uint> children)
71 { this.Stale = true; };
72 client.OnDelinkObjects += delegate(List<uint> primIds, IClientAPI clientApi) { this.Stale = true; };
73 client.OnGrabUpdate += delegate(UUID objectID, Vector3 offset, Vector3 grapPos,
74 IClientAPI remoteClient, List<SurfaceTouchEventArgs> surfaceArgs) { this.Stale = true; };
75 client.OnObjectAttach += delegate(IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt,
76 bool silent) { this.Stale = true; };
77 client.OnObjectDuplicate += delegate(uint localID, Vector3 offset, uint dupeFlags, UUID AgentID,
78 UUID GroupID) { this.Stale = true; };
79 client.OnObjectDuplicateOnRay += delegate(uint localID, uint dupeFlags, UUID AgentID, UUID GroupID,
80 UUID RayTargetObj, Vector3 RayEnd, Vector3 RayStart, bool BypassRaycast,
81 bool RayEndIsIntersection, bool CopyCenters, bool CopyRotates) { this.Stale = true; };
82 client.OnObjectIncludeInSearch += delegate(IClientAPI remoteClient, bool IncludeInSearch, uint localID)
83 { this.Stale = true; };
84 client.OnObjectPermissions += delegate(IClientAPI controller, UUID agentID, UUID sessionID,
85 byte field, uint localId, uint mask, byte set) { this.Stale = true; };
86 client.OnRezObject += delegate(IClientAPI remoteClient, UUID itemID, Vector3 RayEnd,
87 Vector3 RayStart, UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection,
88 bool RezSelected,
89 bool RemoveItem, UUID fromTaskID) { this.Stale = true; };
90 }
91
92 public Scene GetParentScene
93 {
94 get { return m_scene; }
95 }
96
97 public XmlNode RequestSnapshotData(XmlDocument nodeFactory)
98 {
99 m_log.Debug("[DATASNAPSHOT]: Generating object data for scene " + m_scene.RegionInfo.RegionName);
100
101 XmlNode parent = nodeFactory.CreateNode(XmlNodeType.Element, "objectdata", "");
102 XmlNode node;
103
104 EntityBase[] entities = m_scene.Entities.GetEntities();
105 foreach (EntityBase entity in entities)
106 {
107 // only objects, not avatars
108 if (entity is SceneObjectGroup)
109 {
110 SceneObjectGroup obj = (SceneObjectGroup)entity;
111
112// m_log.Debug("[DATASNAPSHOT]: Found object " + obj.Name + " in scene");
113
114 // libomv will complain about PrimFlags.JointWheel
115 // being obsolete, so we...
116 #pragma warning disable 0612
117 if ((obj.RootPart.Flags & PrimFlags.JointWheel) == PrimFlags.JointWheel)
118 {
119 SceneObjectPart m_rootPart = obj.RootPart;
120
121 ILandObject land = m_scene.LandChannel.GetLandObject(m_rootPart.AbsolutePosition.X, m_rootPart.AbsolutePosition.Y);
122
123 XmlNode xmlobject = nodeFactory.CreateNode(XmlNodeType.Element, "object", "");
124 node = nodeFactory.CreateNode(XmlNodeType.Element, "uuid", "");
125 node.InnerText = obj.UUID.ToString();
126 xmlobject.AppendChild(node);
127
128 node = nodeFactory.CreateNode(XmlNodeType.Element, "title", "");
129 node.InnerText = m_rootPart.Name;
130 xmlobject.AppendChild(node);
131
132 node = nodeFactory.CreateNode(XmlNodeType.Element, "description", "");
133 node.InnerText = m_rootPart.Description;
134 xmlobject.AppendChild(node);
135
136 node = nodeFactory.CreateNode(XmlNodeType.Element, "flags", "");
137 node.InnerText = String.Format("{0:x}", (uint)m_rootPart.Flags);
138 xmlobject.AppendChild(node);
139
140 node = nodeFactory.CreateNode(XmlNodeType.Element, "regionuuid", "");
141 node.InnerText = m_scene.RegionInfo.RegionSettings.RegionUUID.ToString();
142 xmlobject.AppendChild(node);
143
144 if (land != null && land.LandData != null)
145 {
146 node = nodeFactory.CreateNode(XmlNodeType.Element, "parceluuid", "");
147 node.InnerText = land.LandData.GlobalID.ToString();
148 xmlobject.AppendChild(node);
149 }
150 else
151 {
152 // Something is wrong with this object. Let's not list it.
153 m_log.WarnFormat("[DATASNAPSHOT]: Bad data for object {0} ({1}) in region {2}", obj.Name, obj.UUID, m_scene.RegionInfo.RegionName);
154 continue;
155 }
156
157 node = nodeFactory.CreateNode(XmlNodeType.Element, "location", "");
158 Vector3 loc = obj.AbsolutePosition;
159 node.InnerText = loc.X.ToString() + "/" + loc.Y.ToString() + "/" + loc.Z.ToString();
160 xmlobject.AppendChild(node);
161
162 string bestImage = GuessImage(obj);
163 if (bestImage != string.Empty)
164 {
165 node = nodeFactory.CreateNode(XmlNodeType.Element, "image", "");
166 node.InnerText = bestImage;
167 xmlobject.AppendChild(node);
168 }
169
170 parent.AppendChild(xmlobject);
171 }
172 #pragma warning disable 0612
173 }
174 }
175 this.Stale = false;
176 return parent;
177 }
178
179 public String Name
180 {
181 get { return "ObjectSnapshot"; }
182 }
183
184 public bool Stale
185 {
186 get
187 {
188 return m_stale;
189 }
190 set
191 {
192 m_stale = value;
193
194 if (m_stale)
195 OnStale(this);
196 }
197 }
198
199 public event ProviderStale OnStale;
200
201 /// <summary>
202 /// Guesses the best image, based on a simple heuristic. It guesses only for boxes.
203 /// We're optimizing for boxes, because those are the most common objects
204 /// marked "Show in search" -- boxes with content inside.For other shapes,
205 /// it's really hard to tell which texture should be grabbed.
206 /// </summary>
207 /// <param name="sog"></param>
208 /// <returns></returns>
209 private string GuessImage(SceneObjectGroup sog)
210 {
211 string bestguess = string.Empty;
212 Dictionary<UUID, int> counts = new Dictionary<UUID, int>();
213
214 PrimitiveBaseShape shape = sog.RootPart.Shape;
215 if (shape != null && shape.ProfileShape == ProfileShape.Square)
216 {
217 Primitive.TextureEntry textures = shape.Textures;
218 if (textures != null)
219 {
220 if (textures.DefaultTexture != null &&
221 textures.DefaultTexture.TextureID != UUID.Zero &&
222 textures.DefaultTexture.TextureID != m_DefaultImage &&
223 textures.DefaultTexture.TextureID != m_BlankImage &&
224 textures.DefaultTexture.RGBA.A < 50f)
225 {
226 counts[textures.DefaultTexture.TextureID] = 8;
227 }
228
229 if (textures.FaceTextures != null)
230 {
231 foreach (Primitive.TextureEntryFace tentry in textures.FaceTextures)
232 {
233 if (tentry != null)
234 {
235 if (tentry.TextureID != UUID.Zero && tentry.TextureID != m_DefaultImage && tentry.TextureID != m_BlankImage && tentry.RGBA.A < 50)
236 {
237 int c = 0;
238 counts.TryGetValue(tentry.TextureID, out c);
239 counts[tentry.TextureID] = c + 1;
240 // decrease the default texture count
241 if (counts.ContainsKey(textures.DefaultTexture.TextureID))
242 counts[textures.DefaultTexture.TextureID] = counts[textures.DefaultTexture.TextureID] - 1;
243 }
244 }
245 }
246 }
247
248 // Let's pick the most unique texture
249 int min = 9999;
250 foreach (KeyValuePair<UUID, int> kv in counts)
251 {
252 if (kv.Value < min && kv.Value >= 1)
253 {
254 bestguess = kv.Key.ToString();
255 min = kv.Value;
256 }
257 }
258 }
259 }
260
261 return bestguess;
262 }
263 }
264}
diff --git a/OpenSim/Region/OptionalModules/DataSnapshot/SnapshotStore.cs b/OpenSim/Region/OptionalModules/DataSnapshot/SnapshotStore.cs
new file mode 100644
index 0000000..480aaaf
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/DataSnapshot/SnapshotStore.cs
@@ -0,0 +1,337 @@
1/*
2* Copyright (c) Contributors, http://opensimulator.org/
3* See CONTRIBUTORS.TXT for a full list of copyright holders.
4*
5* Redistribution and use in source and binary forms, with or without
6* modification, are permitted provided that the following conditions are met:
7* * Redistributions of source code must retain the above copyright
8* notice, this list of conditions and the following disclaimer.
9* * Redistributions in binary form must reproduce the above copyright
10* notice, this list of conditions and the following disclaimer in the
11* documentation and/or other materials provided with the distribution.
12* * Neither the name of the OpenSimulator Project nor the
13* names of its contributors may be used to endorse or promote products
14* derived from this software without specific prior written permission.
15*
16* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*/
27
28using System;
29using System.Collections.Generic;
30using System.IO;
31using System.Reflection;
32using System.Text;
33using System.Text.RegularExpressions;
34using System.Xml;
35using log4net;
36using OpenSim.Region.DataSnapshot.Interfaces;
37using OpenSim.Region.Framework.Scenes;
38
39namespace OpenSim.Region.DataSnapshot
40{
41 public class SnapshotStore
42 {
43 #region Class Members
44 private String m_directory = "unyuu"; //not an attempt at adding RM references to core SVN, honest
45 private Dictionary<Scene, bool> m_scenes = null;
46 private List<IDataSnapshotProvider> m_providers = null;
47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48 private Dictionary<String, String> m_gridinfo = null;
49 private bool m_cacheEnabled = true;
50 private string m_listener_port = "9000"; //TODO: Set default port over 9000
51 private string m_hostname = "127.0.0.1";
52 #endregion
53
54 public SnapshotStore(string directory, Dictionary<String, String> gridinfo, string port, string hostname) {
55 m_directory = directory;
56 m_scenes = new Dictionary<Scene, bool>();
57 m_providers = new List<IDataSnapshotProvider>();
58 m_gridinfo = gridinfo;
59 m_listener_port = port;
60 m_hostname = hostname;
61
62 if (Directory.Exists(m_directory))
63 {
64 m_log.Info("[DATASNAPSHOT]: Response and fragment cache directory already exists.");
65 }
66 else
67 {
68 // Try to create the directory.
69 m_log.Info("[DATASNAPSHOT]: Creating directory " + m_directory);
70 try
71 {
72 Directory.CreateDirectory(m_directory);
73 }
74 catch (Exception e)
75 {
76 m_log.Error("[DATASNAPSHOT]: Failed to create directory " + m_directory, e);
77
78 //This isn't a horrible problem, just disable cacheing.
79 m_cacheEnabled = false;
80 m_log.Error("[DATASNAPSHOT]: Could not create directory, response cache has been disabled.");
81 }
82 }
83 }
84
85 public void ForceSceneStale(Scene scene) {
86 m_scenes[scene] = true;
87 }
88
89 #region Fragment storage
90 public XmlNode GetFragment(IDataSnapshotProvider provider, XmlDocument factory)
91 {
92 XmlNode data = null;
93
94 if (provider.Stale || !m_cacheEnabled)
95 {
96 data = provider.RequestSnapshotData(factory);
97
98 if (m_cacheEnabled)
99 {
100 String path = DataFileNameFragment(provider.GetParentScene, provider.Name);
101
102 try
103 {
104 using (XmlTextWriter snapXWriter = new XmlTextWriter(path, Encoding.Default))
105 {
106 snapXWriter.Formatting = Formatting.Indented;
107 snapXWriter.WriteStartDocument();
108 data.WriteTo(snapXWriter);
109 snapXWriter.WriteEndDocument();
110 }
111 }
112 catch (Exception e)
113 {
114 m_log.WarnFormat("[DATASNAPSHOT]: Exception on writing to file {0}: {1}", path, e.Message);
115 }
116
117 }
118
119 //mark provider as not stale, parent scene as stale
120 provider.Stale = false;
121 m_scenes[provider.GetParentScene] = true;
122
123 m_log.Debug("[DATASNAPSHOT]: Generated fragment response for provider type " + provider.Name);
124 }
125 else
126 {
127 String path = DataFileNameFragment(provider.GetParentScene, provider.Name);
128
129 XmlDocument fragDocument = new XmlDocument();
130 fragDocument.PreserveWhitespace = true;
131 fragDocument.Load(path);
132 foreach (XmlNode node in fragDocument)
133 {
134 data = factory.ImportNode(node, true);
135 }
136
137 m_log.Debug("[DATASNAPSHOT]: Retrieved fragment response for provider type " + provider.Name);
138 }
139
140 return data;
141 }
142 #endregion
143
144 #region Response storage
145 public XmlNode GetScene(Scene scene, XmlDocument factory)
146 {
147 m_log.Debug("[DATASNAPSHOT]: Data requested for scene " + scene.RegionInfo.RegionName);
148
149 if (!m_scenes.ContainsKey(scene)) {
150 m_scenes.Add(scene, true); //stale by default
151 }
152
153 XmlNode regionElement = null;
154
155 if (!m_scenes[scene])
156 {
157 m_log.Debug("[DATASNAPSHOT]: Attempting to retrieve snapshot from cache.");
158 //get snapshot from cache
159 String path = DataFileNameScene(scene);
160
161 XmlDocument fragDocument = new XmlDocument();
162 fragDocument.PreserveWhitespace = true;
163
164 fragDocument.Load(path);
165
166 foreach (XmlNode node in fragDocument)
167 {
168 regionElement = factory.ImportNode(node, true);
169 }
170
171 m_log.Debug("[DATASNAPSHOT]: Obtained snapshot from cache for " + scene.RegionInfo.RegionName);
172 }
173 else
174 {
175 m_log.Debug("[DATASNAPSHOT]: Attempting to generate snapshot.");
176 //make snapshot
177 regionElement = MakeRegionNode(scene, factory);
178
179 regionElement.AppendChild(GetGridSnapshotData(factory));
180 XmlNode regionData = factory.CreateNode(XmlNodeType.Element, "data", "");
181
182 foreach (IDataSnapshotProvider dataprovider in m_providers)
183 {
184 if (dataprovider.GetParentScene == scene)
185 {
186 regionData.AppendChild(GetFragment(dataprovider, factory));
187 }
188 }
189
190 regionElement.AppendChild(regionData);
191
192 factory.AppendChild(regionElement);
193
194 //save snapshot
195 String path = DataFileNameScene(scene);
196
197 try
198 {
199 using (XmlTextWriter snapXWriter = new XmlTextWriter(path, Encoding.Default))
200 {
201 snapXWriter.Formatting = Formatting.Indented;
202 snapXWriter.WriteStartDocument();
203 regionElement.WriteTo(snapXWriter);
204 snapXWriter.WriteEndDocument();
205 }
206 }
207 catch (Exception e)
208 {
209 m_log.WarnFormat("[DATASNAPSHOT]: Exception on writing to file {0}: {1}", path, e.Message);
210 }
211
212 m_scenes[scene] = false;
213
214 m_log.Debug("[DATASNAPSHOT]: Generated new snapshot for " + scene.RegionInfo.RegionName);
215 }
216
217 return regionElement;
218 }
219
220 #endregion
221
222 #region Helpers
223 private string DataFileNameFragment(Scene scene, String fragmentName)
224 {
225 return Path.Combine(m_directory, Path.ChangeExtension(Sanitize(scene.RegionInfo.RegionName + "_" + fragmentName), "xml"));
226 }
227
228 private string DataFileNameScene(Scene scene)
229 {
230 return Path.Combine(m_directory, Path.ChangeExtension(Sanitize(scene.RegionInfo.RegionName), "xml"));
231 //return (m_snapsDir + Path.DirectorySeparatorChar + scene.RegionInfo.RegionName + ".xml");
232 }
233
234 private static string Sanitize(string name)
235 {
236 string invalidChars = Regex.Escape(new string(Path.GetInvalidFileNameChars()));
237 string invalidReStr = string.Format(@"[{0}]", invalidChars);
238 string newname = Regex.Replace(name, invalidReStr, "_");
239 return newname.Replace('.', '_');
240 }
241
242 private XmlNode MakeRegionNode(Scene scene, XmlDocument basedoc)
243 {
244 XmlNode docElement = basedoc.CreateNode(XmlNodeType.Element, "region", "");
245
246 XmlAttribute attr = basedoc.CreateAttribute("category");
247 attr.Value = GetRegionCategory(scene);
248 docElement.Attributes.Append(attr);
249
250 attr = basedoc.CreateAttribute("entities");
251 attr.Value = scene.Entities.Count.ToString();
252 docElement.Attributes.Append(attr);
253
254 //attr = basedoc.CreateAttribute("parcels");
255 //attr.Value = scene.LandManager.landList.Count.ToString();
256 //docElement.Attributes.Append(attr);
257
258
259 XmlNode infoblock = basedoc.CreateNode(XmlNodeType.Element, "info", "");
260
261 XmlNode infopiece = basedoc.CreateNode(XmlNodeType.Element, "uuid", "");
262 infopiece.InnerText = scene.RegionInfo.RegionID.ToString();
263 infoblock.AppendChild(infopiece);
264
265 infopiece = basedoc.CreateNode(XmlNodeType.Element, "url", "");
266 infopiece.InnerText = "http://" + m_hostname + ":" + m_listener_port;
267 infoblock.AppendChild(infopiece);
268
269 infopiece = basedoc.CreateNode(XmlNodeType.Element, "name", "");
270 infopiece.InnerText = scene.RegionInfo.RegionName;
271 infoblock.AppendChild(infopiece);
272
273 infopiece = basedoc.CreateNode(XmlNodeType.Element, "handle", "");
274 infopiece.InnerText = scene.RegionInfo.RegionHandle.ToString();
275 infoblock.AppendChild(infopiece);
276
277 docElement.AppendChild(infoblock);
278
279 m_log.Debug("[DATASNAPSHOT]: Generated region node");
280 return docElement;
281 }
282
283 private String GetRegionCategory(Scene scene)
284 {
285 if (scene.RegionInfo.RegionSettings.Maturity == 0)
286 return "PG";
287
288 if (scene.RegionInfo.RegionSettings.Maturity == 1)
289 return "Mature";
290
291 if (scene.RegionInfo.RegionSettings.Maturity == 2)
292 return "Adult";
293
294 return "Unknown";
295 }
296
297 private XmlNode GetGridSnapshotData(XmlDocument factory)
298 {
299 XmlNode griddata = factory.CreateNode(XmlNodeType.Element, "grid", "");
300
301 foreach (KeyValuePair<String, String> GridData in m_gridinfo)
302 {
303 //TODO: make it lowercase tag names for diva
304 XmlNode childnode = factory.CreateNode(XmlNodeType.Element, GridData.Key, "");
305 childnode.InnerText = GridData.Value;
306 griddata.AppendChild(childnode);
307 }
308
309 m_log.Debug("[DATASNAPSHOT]: Got grid snapshot data");
310
311 return griddata;
312 }
313 #endregion
314
315 #region Manage internal collections
316 public void AddScene(Scene newScene)
317 {
318 m_scenes.Add(newScene, true);
319 }
320
321 public void RemoveScene(Scene deadScene)
322 {
323 m_scenes.Remove(deadScene);
324 }
325
326 public void AddProvider(IDataSnapshotProvider newProvider)
327 {
328 m_providers.Add(newProvider);
329 }
330
331 public void RemoveProvider(IDataSnapshotProvider deadProvider)
332 {
333 m_providers.Remove(deadProvider);
334 }
335 #endregion
336 }
337}
diff --git a/OpenSim/Region/OptionalModules/Example/BareBonesNonShared/BareBonesNonSharedModule.cs b/OpenSim/Region/OptionalModules/Example/BareBonesNonShared/BareBonesNonSharedModule.cs
index 7d37135..bbf7168 100644
--- a/OpenSim/Region/OptionalModules/Example/BareBonesNonShared/BareBonesNonSharedModule.cs
+++ b/OpenSim/Region/OptionalModules/Example/BareBonesNonShared/BareBonesNonSharedModule.cs
@@ -33,6 +33,12 @@ using Nini.Config;
33using OpenSim.Region.Framework.Interfaces; 33using OpenSim.Region.Framework.Interfaces;
34using OpenSim.Region.Framework.Scenes; 34using OpenSim.Region.Framework.Scenes;
35 35
36// You will need to uncomment these lines if you are adding a region module to some other assembly which does not already
37// specify its assembly. Otherwise, the region modules in the assembly will not be picked up when OpenSimulator scans
38// the available DLLs
39//[assembly: Addin("MyModule", "1.0")]
40//[assembly: AddinDependency("OpenSim", "0.8.1")]
41
36namespace OpenSim.Region.OptionalModules.Example.BareBonesNonShared 42namespace OpenSim.Region.OptionalModules.Example.BareBonesNonShared
37{ 43{
38 /// <summary> 44 /// <summary>
diff --git a/OpenSim/Region/OptionalModules/Example/BareBonesShared/BareBonesSharedModule.cs b/OpenSim/Region/OptionalModules/Example/BareBonesShared/BareBonesSharedModule.cs
index 781fe95..46fea3e 100644
--- a/OpenSim/Region/OptionalModules/Example/BareBonesShared/BareBonesSharedModule.cs
+++ b/OpenSim/Region/OptionalModules/Example/BareBonesShared/BareBonesSharedModule.cs
@@ -33,6 +33,12 @@ using Nini.Config;
33using OpenSim.Region.Framework.Interfaces; 33using OpenSim.Region.Framework.Interfaces;
34using OpenSim.Region.Framework.Scenes; 34using OpenSim.Region.Framework.Scenes;
35 35
36// You will need to uncomment these lines if you are adding a region module to some other assembly which does not already
37// specify its assembly. Otherwise, the region modules in the assembly will not be picked up when OpenSimulator scans
38// the available DLLs
39//[assembly: Addin("MyModule", "1.0")]
40//[assembly: AddinDependency("OpenSim", "0.8.1")]
41
36namespace OpenSim.Region.OptionalModules.Example.BareBonesShared 42namespace OpenSim.Region.OptionalModules.Example.BareBonesShared
37{ 43{
38 /// <summary> 44 /// <summary>
diff --git a/OpenSim/Region/OptionalModules/Example/WebSocketEchoTest/WebSocketEchoModule.cs b/OpenSim/Region/OptionalModules/Example/WebSocketEchoTest/WebSocketEchoModule.cs
new file mode 100644
index 0000000..5bf0ed4
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/Example/WebSocketEchoTest/WebSocketEchoModule.cs
@@ -0,0 +1,175 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using OpenSim.Framework.Servers;
32using Mono.Addins;
33using log4net;
34using Nini.Config;
35using OpenSim.Region.Framework.Interfaces;
36using OpenSim.Region.Framework.Scenes;
37
38using OpenSim.Framework.Servers.HttpServer;
39
40
41namespace OpenSim.Region.OptionalModules.WebSocketEchoModule
42{
43
44 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "WebSocketEchoModule")]
45 public class WebSocketEchoModule : ISharedRegionModule
46 {
47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48
49 private bool enabled;
50 public string Name { get { return "WebSocketEchoModule"; } }
51
52 public Type ReplaceableInterface { get { return null; } }
53
54
55 private HashSet<WebSocketHttpServerHandler> _activeHandlers = new HashSet<WebSocketHttpServerHandler>();
56
57 public void Initialise(IConfigSource pConfig)
58 {
59 enabled = (pConfig.Configs["WebSocketEcho"] != null);
60// if (enabled)
61// m_log.DebugFormat("[WebSocketEchoModule]: INITIALIZED MODULE");
62 }
63
64 /// <summary>
65 /// This method sets up the callback to WebSocketHandlerCallback below when a HTTPRequest comes in for /echo
66 /// </summary>
67 public void PostInitialise()
68 {
69 if (enabled)
70 MainServer.Instance.AddWebSocketHandler("/echo", WebSocketHandlerCallback);
71 }
72
73 // This gets called by BaseHttpServer and gives us an opportunity to set things on the WebSocket handler before we turn it on
74 public void WebSocketHandlerCallback(string path, WebSocketHttpServerHandler handler)
75 {
76 SubscribeToEvents(handler);
77 handler.SetChunksize(8192);
78 handler.NoDelay_TCP_Nagle = true;
79 handler.HandshakeAndUpgrade();
80 }
81
82 //These are our normal events
83 public void SubscribeToEvents(WebSocketHttpServerHandler handler)
84 {
85 handler.OnClose += HandlerOnOnClose;
86 handler.OnText += HandlerOnOnText;
87 handler.OnUpgradeCompleted += HandlerOnOnUpgradeCompleted;
88 handler.OnData += HandlerOnOnData;
89 handler.OnPong += HandlerOnOnPong;
90 }
91
92 public void UnSubscribeToEvents(WebSocketHttpServerHandler handler)
93 {
94 handler.OnClose -= HandlerOnOnClose;
95 handler.OnText -= HandlerOnOnText;
96 handler.OnUpgradeCompleted -= HandlerOnOnUpgradeCompleted;
97 handler.OnData -= HandlerOnOnData;
98 handler.OnPong -= HandlerOnOnPong;
99 }
100
101 private void HandlerOnOnPong(object sender, PongEventArgs pongdata)
102 {
103 m_log.Info("[WebSocketEchoModule]: Got a pong.. ping time: " + pongdata.PingResponseMS);
104 }
105
106 private void HandlerOnOnData(object sender, WebsocketDataEventArgs data)
107 {
108 WebSocketHttpServerHandler obj = sender as WebSocketHttpServerHandler;
109 obj.SendData(data.Data);
110 m_log.Info("[WebSocketEchoModule]: We received a bunch of ugly non-printable bytes");
111 obj.SendPingCheck();
112 }
113
114
115 private void HandlerOnOnUpgradeCompleted(object sender, UpgradeCompletedEventArgs completeddata)
116 {
117 WebSocketHttpServerHandler obj = sender as WebSocketHttpServerHandler;
118 _activeHandlers.Add(obj);
119 }
120
121 private void HandlerOnOnText(object sender, WebsocketTextEventArgs text)
122 {
123 WebSocketHttpServerHandler obj = sender as WebSocketHttpServerHandler;
124 obj.SendMessage(text.Data);
125 m_log.Info("[WebSocketEchoModule]: We received this: " + text.Data);
126 }
127
128 // Remove the references to our handler
129 private void HandlerOnOnClose(object sender, CloseEventArgs closedata)
130 {
131 WebSocketHttpServerHandler obj = sender as WebSocketHttpServerHandler;
132 UnSubscribeToEvents(obj);
133
134 lock (_activeHandlers)
135 _activeHandlers.Remove(obj);
136 obj.Dispose();
137 }
138
139 // Shutting down.. so shut down all sockets.
140 // Note.. this should be done outside of an ienumerable if you're also hook to the close event.
141 public void Close()
142 {
143 if (!enabled)
144 return;
145
146 // We convert this to a for loop so we're not in in an IEnumerable when the close
147 //call triggers an event which then removes item from _activeHandlers that we're enumerating
148 WebSocketHttpServerHandler[] items = new WebSocketHttpServerHandler[_activeHandlers.Count];
149 _activeHandlers.CopyTo(items);
150
151 for (int i = 0; i < items.Length; i++)
152 {
153 items[i].Close(string.Empty);
154 items[i].Dispose();
155 }
156 _activeHandlers.Clear();
157 MainServer.Instance.RemoveWebSocketHandler("/echo");
158 }
159
160 public void AddRegion(Scene scene)
161 {
162// m_log.DebugFormat("[WebSocketEchoModule]: REGION {0} ADDED", scene.RegionInfo.RegionName);
163 }
164
165 public void RemoveRegion(Scene scene)
166 {
167// m_log.DebugFormat("[WebSocketEchoModule]: REGION {0} REMOVED", scene.RegionInfo.RegionName);
168 }
169
170 public void RegionLoaded(Scene scene)
171 {
172// m_log.DebugFormat("[WebSocketEchoModule]: REGION {0} LOADED", scene.RegionInfo.RegionName);
173 }
174 }
175} \ No newline at end of file
diff --git a/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs b/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs
new file mode 100644
index 0000000..e95889d
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs
@@ -0,0 +1,608 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.IO;
31using System.Reflection;
32using System.Security.Cryptography; // for computing md5 hash
33using log4net;
34using Mono.Addins;
35using Nini.Config;
36
37using OpenMetaverse;
38using OpenMetaverse.StructuredData;
39
40using OpenSim.Framework;
41using OpenSim.Framework.Servers;
42using OpenSim.Framework.Servers.HttpServer;
43using OpenSim.Region.Framework.Interfaces;
44using OpenSim.Region.Framework.Scenes;
45using OpenSimAssetType = OpenSim.Framework.SLUtil.OpenSimAssetType;
46
47using Ionic.Zlib;
48
49// You will need to uncomment these lines if you are adding a region module to some other assembly which does not already
50// specify its assembly. Otherwise, the region modules in the assembly will not be picked up when OpenSimulator scans
51// the available DLLs
52//[assembly: Addin("MaterialsModule", "1.0")]
53//[assembly: AddinDependency("OpenSim", "0.8.1")]
54
55namespace OpenSim.Region.OptionalModules.Materials
56{
57 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "MaterialsModule")]
58 public class MaterialsModule : INonSharedRegionModule
59 {
60 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
61
62 public string Name { get { return "MaterialsModule"; } }
63
64 public Type ReplaceableInterface { get { return null; } }
65
66 private Scene m_scene = null;
67 private bool m_enabled = false;
68 private int m_maxMaterialsPerTransaction = 50;
69
70 public Dictionary<UUID, OSDMap> m_regionMaterials = new Dictionary<UUID, OSDMap>();
71
72 public void Initialise(IConfigSource source)
73 {
74 m_enabled = true; // default is enabled
75
76 IConfig config = source.Configs["Materials"];
77 if (config != null)
78 {
79 m_enabled = config.GetBoolean("enable_materials", m_enabled);
80 m_maxMaterialsPerTransaction = config.GetInt("MaxMaterialsPerTransaction", m_maxMaterialsPerTransaction);
81 }
82
83 if (m_enabled)
84 m_log.DebugFormat("[Materials]: Initialized");
85 }
86
87 public void Close()
88 {
89 if (!m_enabled)
90 return;
91 }
92
93 public void AddRegion(Scene scene)
94 {
95 if (!m_enabled)
96 return;
97
98 m_scene = scene;
99 m_scene.EventManager.OnRegisterCaps += OnRegisterCaps;
100 m_scene.EventManager.OnObjectAddedToScene += EventManager_OnObjectAddedToScene;
101 }
102
103 private void EventManager_OnObjectAddedToScene(SceneObjectGroup obj)
104 {
105 foreach (var part in obj.Parts)
106 if (part != null)
107 GetStoredMaterialsInPart(part);
108 }
109
110 private void OnRegisterCaps(OpenMetaverse.UUID agentID, OpenSim.Framework.Capabilities.Caps caps)
111 {
112 string capsBase = "/CAPS/" + caps.CapsObjectPath;
113
114 IRequestHandler renderMaterialsPostHandler
115 = new RestStreamHandler("POST", capsBase + "/",
116 (request, path, param, httpRequest, httpResponse)
117 => RenderMaterialsPostCap(request, agentID),
118 "RenderMaterials", null);
119 caps.RegisterHandler("RenderMaterials", renderMaterialsPostHandler);
120
121 // OpenSimulator CAPs infrastructure seems to be somewhat hostile towards any CAP that requires both GET
122 // and POST handlers, (at least at the time this was originally written), so we first set up a POST
123 // handler normally and then add a GET handler via MainServer
124
125 IRequestHandler renderMaterialsGetHandler
126 = new RestStreamHandler("GET", capsBase + "/",
127 (request, path, param, httpRequest, httpResponse)
128 => RenderMaterialsGetCap(request),
129 "RenderMaterials", null);
130 MainServer.Instance.AddStreamHandler(renderMaterialsGetHandler);
131
132 // materials viewer seems to use either POST or PUT, so assign POST handler for PUT as well
133 IRequestHandler renderMaterialsPutHandler
134 = new RestStreamHandler("PUT", capsBase + "/",
135 (request, path, param, httpRequest, httpResponse)
136 => RenderMaterialsPostCap(request, agentID),
137 "RenderMaterials", null);
138 MainServer.Instance.AddStreamHandler(renderMaterialsPutHandler);
139 }
140
141 public void RemoveRegion(Scene scene)
142 {
143 if (!m_enabled)
144 return;
145
146 m_scene.EventManager.OnRegisterCaps -= OnRegisterCaps;
147 m_scene.EventManager.OnObjectAddedToScene -= EventManager_OnObjectAddedToScene;
148 }
149
150 public void RegionLoaded(Scene scene)
151 {
152 if (!m_enabled) return;
153
154 ISimulatorFeaturesModule featuresModule = scene.RequestModuleInterface<ISimulatorFeaturesModule>();
155 if (featuresModule != null)
156 featuresModule.OnSimulatorFeaturesRequest += OnSimulatorFeaturesRequest;
157 }
158
159 private void OnSimulatorFeaturesRequest(UUID agentID, ref OSDMap features)
160 {
161 features["MaxMaterialsPerTransaction"] = m_maxMaterialsPerTransaction;
162 }
163
164 /// <summary>
165 /// Finds any legacy materials stored in DynAttrs that may exist for this part and add them to 'm_regionMaterials'.
166 /// </summary>
167 /// <param name="part"></param>
168 private void GetLegacyStoredMaterialsInPart(SceneObjectPart part)
169 {
170 if (part.DynAttrs == null)
171 return;
172
173 OSD OSMaterials = null;
174 OSDArray matsArr = null;
175
176 lock (part.DynAttrs)
177 {
178 if (part.DynAttrs.ContainsStore("OpenSim", "Materials"))
179 {
180 OSDMap materialsStore = part.DynAttrs.GetStore("OpenSim", "Materials");
181
182 if (materialsStore == null)
183 return;
184
185 materialsStore.TryGetValue("Materials", out OSMaterials);
186 }
187
188 if (OSMaterials != null && OSMaterials is OSDArray)
189 matsArr = OSMaterials as OSDArray;
190 else
191 return;
192 }
193
194 if (matsArr == null)
195 return;
196
197 foreach (OSD elemOsd in matsArr)
198 {
199 if (elemOsd != null && elemOsd is OSDMap)
200 {
201 OSDMap matMap = elemOsd as OSDMap;
202 if (matMap.ContainsKey("ID") && matMap.ContainsKey("Material"))
203 {
204 try
205 {
206 lock (m_regionMaterials)
207 m_regionMaterials[matMap["ID"].AsUUID()] = (OSDMap)matMap["Material"];
208 }
209 catch (Exception e)
210 {
211 m_log.Warn("[Materials]: exception decoding persisted legacy material: " + e.ToString());
212 }
213 }
214 }
215 }
216 }
217
218 /// <summary>
219 /// Find the materials used in the SOP, and add them to 'm_regionMaterials'.
220 /// </summary>
221 private void GetStoredMaterialsInPart(SceneObjectPart part)
222 {
223 if (part.Shape == null)
224 return;
225
226 var te = new Primitive.TextureEntry(part.Shape.TextureEntry, 0, part.Shape.TextureEntry.Length);
227 if (te == null)
228 return;
229
230 GetLegacyStoredMaterialsInPart(part);
231
232 if (te.DefaultTexture != null)
233 GetStoredMaterialInFace(part, te.DefaultTexture);
234 else
235 m_log.WarnFormat(
236 "[Materials]: Default texture for part {0} (part of object {1}) in {2} unexpectedly null. Ignoring.",
237 part.Name, part.ParentGroup.Name, m_scene.Name);
238
239 foreach (Primitive.TextureEntryFace face in te.FaceTextures)
240 {
241 if (face != null)
242 GetStoredMaterialInFace(part, face);
243 }
244 }
245
246 /// <summary>
247 /// Find the materials used in one Face, and add them to 'm_regionMaterials'.
248 /// </summary>
249 private void GetStoredMaterialInFace(SceneObjectPart part, Primitive.TextureEntryFace face)
250 {
251 UUID id = face.MaterialID;
252 if (id == UUID.Zero)
253 return;
254
255 lock (m_regionMaterials)
256 {
257 if (m_regionMaterials.ContainsKey(id))
258 return;
259
260 byte[] data = m_scene.AssetService.GetData(id.ToString());
261 if (data == null)
262 {
263 m_log.WarnFormat("[Materials]: Prim \"{0}\" ({1}) contains unknown material ID {2}", part.Name, part.UUID, id);
264 return;
265 }
266
267 OSDMap mat;
268 try
269 {
270 mat = (OSDMap)OSDParser.DeserializeLLSDXml(data);
271 }
272 catch (Exception e)
273 {
274 m_log.WarnFormat("[Materials]: cannot decode material asset {0}: {1}", id, e.Message);
275 return;
276 }
277
278 m_regionMaterials[id] = mat;
279 }
280 }
281
282 public string RenderMaterialsPostCap(string request, UUID agentID)
283 {
284 OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request);
285 OSDMap resp = new OSDMap();
286
287 OSDMap materialsFromViewer = null;
288
289 OSDArray respArr = new OSDArray();
290
291 if (req.ContainsKey("Zipped"))
292 {
293 OSD osd = null;
294
295 byte[] inBytes = req["Zipped"].AsBinary();
296
297 try
298 {
299 osd = ZDecompressBytesToOsd(inBytes);
300
301 if (osd != null)
302 {
303 if (osd is OSDArray) // assume array of MaterialIDs designating requested material entries
304 {
305 foreach (OSD elem in (OSDArray)osd)
306 {
307 try
308 {
309 UUID id = new UUID(elem.AsBinary(), 0);
310
311 lock (m_regionMaterials)
312 {
313 if (m_regionMaterials.ContainsKey(id))
314 {
315 OSDMap matMap = new OSDMap();
316 matMap["ID"] = OSD.FromBinary(id.GetBytes());
317 matMap["Material"] = m_regionMaterials[id];
318 respArr.Add(matMap);
319 }
320 else
321 {
322 m_log.Warn("[Materials]: request for unknown material ID: " + id.ToString());
323
324 // Theoretically we could try to load the material from the assets service,
325 // but that shouldn't be necessary because the viewer should only request
326 // materials that exist in a prim on the region, and all of these materials
327 // are already stored in m_regionMaterials.
328 }
329 }
330 }
331 catch (Exception e)
332 {
333 m_log.Error("Error getting materials in response to viewer request", e);
334 continue;
335 }
336 }
337 }
338 else if (osd is OSDMap) // request to assign a material
339 {
340 materialsFromViewer = osd as OSDMap;
341
342 if (materialsFromViewer.ContainsKey("FullMaterialsPerFace"))
343 {
344 OSD matsOsd = materialsFromViewer["FullMaterialsPerFace"];
345 if (matsOsd is OSDArray)
346 {
347 OSDArray matsArr = matsOsd as OSDArray;
348
349 try
350 {
351 foreach (OSDMap matsMap in matsArr)
352 {
353 uint primLocalID = 0;
354 try {
355 primLocalID = matsMap["ID"].AsUInteger();
356 }
357 catch (Exception e) {
358 m_log.Warn("[Materials]: cannot decode \"ID\" from matsMap: " + e.Message);
359 continue;
360 }
361
362 OSDMap mat = null;
363 try
364 {
365 mat = matsMap["Material"] as OSDMap;
366 }
367 catch (Exception e)
368 {
369 m_log.Warn("[Materials]: cannot decode \"Material\" from matsMap: " + e.Message);
370 continue;
371 }
372
373 SceneObjectPart sop = m_scene.GetSceneObjectPart(primLocalID);
374 if (sop == null)
375 {
376 m_log.WarnFormat("[Materials]: SOP not found for localId: {0}", primLocalID.ToString());
377 continue;
378 }
379
380 if (!m_scene.Permissions.CanEditObject(sop.UUID, agentID))
381 {
382 m_log.WarnFormat("User {0} can't edit object {1} {2}", agentID, sop.Name, sop.UUID);
383 continue;
384 }
385
386 Primitive.TextureEntry te = new Primitive.TextureEntry(sop.Shape.TextureEntry, 0, sop.Shape.TextureEntry.Length);
387 if (te == null)
388 {
389 m_log.WarnFormat("[Materials]: Error in TextureEntry for SOP {0} {1}", sop.Name, sop.UUID);
390 continue;
391 }
392
393
394 UUID id;
395 if (mat == null)
396 {
397 // This happens then the user removes a material from a prim
398 id = UUID.Zero;
399 }
400 else
401 {
402 id = StoreMaterialAsAsset(agentID, mat, sop);
403 }
404
405
406 int face = -1;
407
408 if (matsMap.ContainsKey("Face"))
409 {
410 face = matsMap["Face"].AsInteger();
411 Primitive.TextureEntryFace faceEntry = te.CreateFace((uint)face);
412 faceEntry.MaterialID = id;
413 }
414 else
415 {
416 if (te.DefaultTexture == null)
417 m_log.WarnFormat("[Materials]: TextureEntry.DefaultTexture is null in {0} {1}", sop.Name, sop.UUID);
418 else
419 te.DefaultTexture.MaterialID = id;
420 }
421
422 //m_log.DebugFormat("[Materials]: in \"{0}\" {1}, setting material ID for face {2} to {3}", sop.Name, sop.UUID, face, id);
423
424 // We can't use sop.UpdateTextureEntry(te) because it filters, so do it manually
425 sop.Shape.TextureEntry = te.GetBytes();
426
427 if (sop.ParentGroup != null)
428 {
429 sop.TriggerScriptChangedEvent(Changed.TEXTURE);
430 sop.UpdateFlag = UpdateRequired.FULL;
431 sop.ParentGroup.HasGroupChanged = true;
432 sop.ScheduleFullUpdate();
433 }
434 }
435 }
436 catch (Exception e)
437 {
438 m_log.Warn("[Materials]: exception processing received material ", e);
439 }
440 }
441 }
442 }
443 }
444
445 }
446 catch (Exception e)
447 {
448 m_log.Warn("[Materials]: exception decoding zipped CAP payload ", e);
449 //return "";
450 }
451 }
452
453
454 resp["Zipped"] = ZCompressOSD(respArr, false);
455 string response = OSDParser.SerializeLLSDXmlString(resp);
456
457 //m_log.Debug("[Materials]: cap request: " + request);
458 //m_log.Debug("[Materials]: cap request (zipped portion): " + ZippedOsdBytesToString(req["Zipped"].AsBinary()));
459 //m_log.Debug("[Materials]: cap response: " + response);
460 return response;
461 }
462
463 private UUID StoreMaterialAsAsset(UUID agentID, OSDMap mat, SceneObjectPart sop)
464 {
465 UUID id;
466 // Material UUID = hash of the material's data.
467 // This makes materials deduplicate across the entire grid (but isn't otherwise required).
468 byte[] data = System.Text.Encoding.ASCII.GetBytes(OSDParser.SerializeLLSDXmlString(mat));
469 using (var md5 = MD5.Create())
470 id = new UUID(md5.ComputeHash(data), 0);
471
472 lock (m_regionMaterials)
473 {
474 if (!m_regionMaterials.ContainsKey(id))
475 {
476 m_regionMaterials[id] = mat;
477
478 // This asset might exist already, but it's ok to try to store it again
479 string name = "Material " + ChooseMaterialName(mat, sop);
480 name = name.Substring(0, Math.Min(64, name.Length)).Trim();
481 AssetBase asset = new AssetBase(id, name, (sbyte)OpenSimAssetType.Material, agentID.ToString());
482 asset.Data = data;
483 m_scene.AssetService.Store(asset);
484 }
485 }
486 return id;
487 }
488
489 /// <summary>
490 /// Use heuristics to choose a good name for the material.
491 /// </summary>
492 private string ChooseMaterialName(OSDMap mat, SceneObjectPart sop)
493 {
494 UUID normMap = mat["NormMap"].AsUUID();
495 if (normMap != UUID.Zero)
496 {
497 AssetBase asset = m_scene.AssetService.GetCached(normMap.ToString());
498 if ((asset != null) && (asset.Name.Length > 0) && !asset.Name.Equals("From IAR"))
499 return asset.Name;
500 }
501
502 UUID specMap = mat["SpecMap"].AsUUID();
503 if (specMap != UUID.Zero)
504 {
505 AssetBase asset = m_scene.AssetService.GetCached(specMap.ToString());
506 if ((asset != null) && (asset.Name.Length > 0) && !asset.Name.Equals("From IAR"))
507 return asset.Name;
508 }
509
510 if (sop.Name != "Primitive")
511 return sop.Name;
512
513 if ((sop.ParentGroup != null) && (sop.ParentGroup.Name != "Primitive"))
514 return sop.ParentGroup.Name;
515
516 return "";
517 }
518
519
520 public string RenderMaterialsGetCap(string request)
521 {
522 OSDMap resp = new OSDMap();
523 int matsCount = 0;
524 OSDArray allOsd = new OSDArray();
525
526 lock (m_regionMaterials)
527 {
528 foreach (KeyValuePair<UUID, OSDMap> kvp in m_regionMaterials)
529 {
530 OSDMap matMap = new OSDMap();
531
532 matMap["ID"] = OSD.FromBinary(kvp.Key.GetBytes());
533 matMap["Material"] = kvp.Value;
534 allOsd.Add(matMap);
535 matsCount++;
536 }
537 }
538
539 resp["Zipped"] = ZCompressOSD(allOsd, false);
540
541 return OSDParser.SerializeLLSDXmlString(resp);
542 }
543
544 private static string ZippedOsdBytesToString(byte[] bytes)
545 {
546 try
547 {
548 return OSDParser.SerializeJsonString(ZDecompressBytesToOsd(bytes));
549 }
550 catch (Exception e)
551 {
552 return "ZippedOsdBytesToString caught an exception: " + e.ToString();
553 }
554 }
555
556 /// <summary>
557 /// computes a UUID by hashing a OSD object
558 /// </summary>
559 /// <param name="osd"></param>
560 /// <returns></returns>
561 private static UUID HashOsd(OSD osd)
562 {
563 byte[] data = OSDParser.SerializeLLSDBinary(osd, false);
564 using (var md5 = MD5.Create())
565 return new UUID(md5.ComputeHash(data), 0);
566 }
567
568 public static OSD ZCompressOSD(OSD inOsd, bool useHeader)
569 {
570 OSD osd = null;
571
572 byte[] data = OSDParser.SerializeLLSDBinary(inOsd, useHeader);
573
574 using (MemoryStream msSinkCompressed = new MemoryStream())
575 {
576 using (Ionic.Zlib.ZlibStream zOut = new Ionic.Zlib.ZlibStream(msSinkCompressed,
577 Ionic.Zlib.CompressionMode.Compress, CompressionLevel.BestCompression, true))
578 {
579 zOut.Write(data, 0, data.Length);
580 }
581
582 msSinkCompressed.Seek(0L, SeekOrigin.Begin);
583 osd = OSD.FromBinary(msSinkCompressed.ToArray());
584 }
585
586 return osd;
587 }
588
589
590 public static OSD ZDecompressBytesToOsd(byte[] input)
591 {
592 OSD osd = null;
593
594 using (MemoryStream msSinkUnCompressed = new MemoryStream())
595 {
596 using (Ionic.Zlib.ZlibStream zOut = new Ionic.Zlib.ZlibStream(msSinkUnCompressed, CompressionMode.Decompress, true))
597 {
598 zOut.Write(input, 0, input.Length);
599 }
600
601 msSinkUnCompressed.Seek(0L, SeekOrigin.Begin);
602 osd = OSDParser.DeserializeLLSDBinary(msSinkUnCompressed.ToArray());
603 }
604
605 return osd;
606 }
607 }
608}
diff --git a/OpenSim/Region/OptionalModules/PhysicsParameters/PhysicsParameters.cs b/OpenSim/Region/OptionalModules/PhysicsParameters/PhysicsParameters.cs
index 40f7fbc..1d9179c 100755
--- a/OpenSim/Region/OptionalModules/PhysicsParameters/PhysicsParameters.cs
+++ b/OpenSim/Region/OptionalModules/PhysicsParameters/PhysicsParameters.cs
@@ -36,7 +36,7 @@ using OpenSim.Framework.Console;
36using OpenSim.Region.CoreModules.Framework.InterfaceCommander; 36using OpenSim.Region.CoreModules.Framework.InterfaceCommander;
37using OpenSim.Region.Framework.Interfaces; 37using OpenSim.Region.Framework.Interfaces;
38using OpenSim.Region.Framework.Scenes; 38using OpenSim.Region.Framework.Scenes;
39using OpenSim.Region.Physics.Manager; 39using OpenSim.Region.PhysicsModules.SharedBase;
40 40
41namespace OpenSim.Region.OptionalModules.PhysicsParameters 41namespace OpenSim.Region.OptionalModules.PhysicsParameters
42{ 42{
@@ -146,7 +146,7 @@ namespace OpenSim.Region.OptionalModules.PhysicsParameters
146 { 146 {
147 foreach (PhysParameterEntry ppe in physScene.GetParameterList()) 147 foreach (PhysParameterEntry ppe in physScene.GetParameterList())
148 { 148 {
149 float val = 0.0f; 149 string val = string.Empty;
150 if (physScene.GetPhysicsParameter(ppe.name, out val)) 150 if (physScene.GetPhysicsParameter(ppe.name, out val))
151 { 151 {
152 WriteOut(" {0}/{1} = {2}", scene.RegionInfo.RegionName, ppe.name, val); 152 WriteOut(" {0}/{1} = {2}", scene.RegionInfo.RegionName, ppe.name, val);
@@ -159,7 +159,7 @@ namespace OpenSim.Region.OptionalModules.PhysicsParameters
159 } 159 }
160 else 160 else
161 { 161 {
162 float val = 0.0f; 162 string val = string.Empty;
163 if (physScene.GetPhysicsParameter(parm, out val)) 163 if (physScene.GetPhysicsParameter(parm, out val))
164 { 164 {
165 WriteOut(" {0}/{1} = {2}", scene.RegionInfo.RegionName, parm, val); 165 WriteOut(" {0}/{1} = {2}", scene.RegionInfo.RegionName, parm, val);
@@ -185,21 +185,12 @@ namespace OpenSim.Region.OptionalModules.PhysicsParameters
185 return; 185 return;
186 } 186 }
187 string parm = "xxx"; 187 string parm = "xxx";
188 float val = 0f; 188 string valparm = String.Empty;
189 uint localID = (uint)PhysParameterEntry.APPLY_TO_NONE; // set default value 189 uint localID = (uint)PhysParameterEntry.APPLY_TO_NONE; // set default value
190 try 190 try
191 { 191 {
192 parm = cmdparms[2]; 192 parm = cmdparms[2];
193 string valparm = cmdparms[3].ToLower(); 193 valparm = cmdparms[3].ToLower();
194 if (valparm == "true")
195 val = PhysParameterEntry.NUMERIC_TRUE;
196 else
197 {
198 if (valparm == "false")
199 val = PhysParameterEntry.NUMERIC_FALSE;
200 else
201 val = float.Parse(valparm, Culture.NumberFormatInfo);
202 }
203 if (cmdparms.Length > 4) 194 if (cmdparms.Length > 4)
204 { 195 {
205 if (cmdparms[4].ToLower() == "all") 196 if (cmdparms[4].ToLower() == "all")
@@ -224,7 +215,7 @@ namespace OpenSim.Region.OptionalModules.PhysicsParameters
224 IPhysicsParameters physScene = scene.PhysicsScene as IPhysicsParameters; 215 IPhysicsParameters physScene = scene.PhysicsScene as IPhysicsParameters;
225 if (physScene != null) 216 if (physScene != null)
226 { 217 {
227 if (!physScene.SetPhysicsParameter(parm, val, localID)) 218 if (!physScene.SetPhysicsParameter(parm, valparm, localID))
228 { 219 {
229 WriteError("Failed set of parameter '{0}' for region '{1}'", parm, scene.RegionInfo.RegionName); 220 WriteError("Failed set of parameter '{0}' for region '{1}'", parm, scene.RegionInfo.RegionName);
230 } 221 }
diff --git a/OpenSim/Region/OptionalModules/PrimLimitsModule/PrimLimitsModule.cs b/OpenSim/Region/OptionalModules/PrimLimitsModule/PrimLimitsModule.cs
index c1957e2..395bbf1 100644
--- a/OpenSim/Region/OptionalModules/PrimLimitsModule/PrimLimitsModule.cs
+++ b/OpenSim/Region/OptionalModules/PrimLimitsModule/PrimLimitsModule.cs
@@ -26,8 +26,9 @@
26 */ 26 */
27 27
28using System; 28using System;
29using System.Reflection;
30using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Linq;
31using System.Reflection;
31using log4net; 32using log4net;
32using Mono.Addins; 33using Mono.Addins;
33using Nini.Config; 34using Nini.Config;
@@ -57,11 +58,10 @@ namespace OpenSim.Region.OptionalModules
57 58
58 public void Initialise(IConfigSource config) 59 public void Initialise(IConfigSource config)
59 { 60 {
60 IConfig myConfig = config.Configs["Startup"]; 61 string permissionModules = Util.GetConfigVarFromSections<string>(config, "permissionmodules",
62 new string[] { "Startup", "Permissions" }, "DefaultPermissionsModule");
61 63
62 string permissionModules = myConfig.GetString("permissionmodules", "DefaultPermissionsModule"); 64 List<string> modules = new List<string>(permissionModules.Split(',').Select(m => m.Trim()));
63
64 List<string> modules=new List<string>(permissionModules.Split(','));
65 65
66 if(!modules.Contains("PrimLimitsModule")) 66 if(!modules.Contains("PrimLimitsModule"))
67 return; 67 return;
@@ -102,20 +102,34 @@ namespace OpenSim.Region.OptionalModules
102 public void RegionLoaded(Scene scene) 102 public void RegionLoaded(Scene scene)
103 { 103 {
104 m_dialogModule = scene.RequestModuleInterface<IDialogModule>(); 104 m_dialogModule = scene.RequestModuleInterface<IDialogModule>();
105 } 105 }
106 106
107 private bool CanRezObject(int objectCount, UUID owner, Vector3 objectPosition, Scene scene) 107 private bool CanRezObject(int objectCount, UUID ownerID, Vector3 objectPosition, Scene scene)
108 { 108 {
109 ILandObject lo = scene.LandChannel.GetLandObject(objectPosition.X, objectPosition.Y); 109 ILandObject lo = scene.LandChannel.GetLandObject(objectPosition.X, objectPosition.Y);
110 int usedPrims = lo.PrimCounts.Total;
111 int simulatorCapacity = lo.GetSimulatorMaxPrimCount();
112 110
113 if (objectCount + usedPrims > simulatorCapacity) 111 string response = DoCommonChecks(objectCount, ownerID, lo, scene);
112
113 if (response != null)
114 { 114 {
115 m_dialogModule.SendAlertToUser(owner, "Unable to rez object because the parcel is too full"); 115 m_dialogModule.SendAlertToUser(ownerID, response);
116 return false; 116 return false;
117 } 117 }
118 return true;
119 }
118 120
121 //OnDuplicateObject
122 private bool CanDuplicateObject(int objectCount, UUID objectID, UUID ownerID, Scene scene, Vector3 objectPosition)
123 {
124 ILandObject lo = scene.LandChannel.GetLandObject(objectPosition.X, objectPosition.Y);
125
126 string response = DoCommonChecks(objectCount, ownerID, lo, scene);
127
128 if (response != null)
129 {
130 m_dialogModule.SendAlertToUser(ownerID, response);
131 return false;
132 }
119 return true; 133 return true;
120 } 134 }
121 135
@@ -127,10 +141,12 @@ namespace OpenSim.Region.OptionalModules
127 ILandObject oldParcel = scene.LandChannel.GetLandObject(oldPoint.X, oldPoint.Y); 141 ILandObject oldParcel = scene.LandChannel.GetLandObject(oldPoint.X, oldPoint.Y);
128 ILandObject newParcel = scene.LandChannel.GetLandObject(newPoint.X, newPoint.Y); 142 ILandObject newParcel = scene.LandChannel.GetLandObject(newPoint.X, newPoint.Y);
129 143
130 int usedPrims = newParcel.PrimCounts.Total; 144 // newParcel will be null only if it outside of our current region. If this is the case, then the
131 int simulatorCapacity = newParcel.GetSimulatorMaxPrimCount(); 145 // receiving permissions will perform the check.
132 146 if (newParcel == null)
133 // The prim hasn't crossed a region boundry so we don't need to worry 147 return true;
148
149 // The prim hasn't crossed a region boundary so we don't need to worry
134 // about prim counts here 150 // about prim counts here
135 if(oldParcel.Equals(newParcel)) 151 if(oldParcel.Equals(newParcel))
136 { 152 {
@@ -145,30 +161,53 @@ namespace OpenSim.Region.OptionalModules
145 } 161 }
146 162
147 // TODO: Add Special Case here for temporary prims 163 // TODO: Add Special Case here for temporary prims
148 164
149 if(objectCount + usedPrims > simulatorCapacity) 165 string response = DoCommonChecks(objectCount, obj.OwnerID, newParcel, scene);
166
167 if (response != null)
150 { 168 {
151 m_dialogModule.SendAlertToUser(obj.OwnerID, "Unable to move object because the destination parcel is too full"); 169 m_dialogModule.SendAlertToUser(obj.OwnerID, response);
152 return false; 170 return false;
153 } 171 }
154
155 return true; 172 return true;
156 } 173 }
157 174
158 //OnDuplicateObject 175 private string DoCommonChecks(int objectCount, UUID ownerID, ILandObject lo, Scene scene)
159 private bool CanDuplicateObject(int objectCount, UUID objectID, UUID owner, Scene scene, Vector3 objectPosition)
160 { 176 {
161 ILandObject lo = scene.LandChannel.GetLandObject(objectPosition.X, objectPosition.Y); 177 string response = null;
162 int usedPrims = lo.PrimCounts.Total;
163 int simulatorCapacity = lo.GetSimulatorMaxPrimCount();
164 178
165 if(objectCount + usedPrims > simulatorCapacity) 179 int simulatorCapacity = lo.GetSimulatorMaxPrimCount();
180 if ((objectCount + lo.PrimCounts.Total) > simulatorCapacity)
166 { 181 {
167 m_dialogModule.SendAlertToUser(owner, "Unable to duplicate object because the parcel is too full"); 182 response = "Unable to rez object because the parcel is too full";
168 return false;
169 } 183 }
170 184 else
171 return true; 185 {
186 int maxPrimsPerUser = scene.RegionInfo.MaxPrimsPerUser;
187 if (maxPrimsPerUser >= 0)
188 {
189 // per-user prim limit is set
190 if (ownerID != lo.LandData.OwnerID || lo.LandData.IsGroupOwned)
191 {
192 // caller is not the sole Parcel owner
193 EstateSettings estateSettings = scene.RegionInfo.EstateSettings;
194 if (ownerID != estateSettings.EstateOwner)
195 {
196 // caller is NOT the Estate owner
197 List<UUID> mgrs = new List<UUID>(estateSettings.EstateManagers);
198 if (!mgrs.Contains(ownerID))
199 {
200 // caller is not an Estate Manager
201 if ((lo.PrimCounts.Users[ownerID] + objectCount) > maxPrimsPerUser)
202 {
203 response = "Unable to rez object because you have reached your limit";
204 }
205 }
206 }
207 }
208 }
209 }
210 return response;
172 } 211 }
173 } 212 }
174} \ No newline at end of file 213}
diff --git a/OpenSim/Region/OptionalModules/Properties/AssemblyInfo.cs b/OpenSim/Region/OptionalModules/Properties/AssemblyInfo.cs
index 217b2d5..dc6ca6f 100644
--- a/OpenSim/Region/OptionalModules/Properties/AssemblyInfo.cs
+++ b/OpenSim/Region/OptionalModules/Properties/AssemblyInfo.cs
@@ -30,8 +30,8 @@ using Mono.Addins;
30// Build Number 30// Build Number
31// Revision 31// Revision
32// 32//
33[assembly: AssemblyVersion("0.7.5.*")] 33[assembly: AssemblyVersion("0.8.3.*")]
34[assembly: AssemblyFileVersion("1.0.0.0")]
35 34
36[assembly: Addin("OpenSim.Region.OptionalModules", "0.1")] 35
37[assembly: AddinDependency("OpenSim", "0.5")] 36[assembly: Addin("OpenSim.Region.OptionalModules", OpenSim.VersionInfo.VersionNumber)]
37[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)]
diff --git a/OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCombinerClientEventForwarder.cs b/OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCombinerClientEventForwarder.cs
new file mode 100644
index 0000000..721d396
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCombinerClientEventForwarder.cs
@@ -0,0 +1,94 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using OpenMetaverse;
31using OpenSim.Region.Framework.Scenes;
32
33namespace OpenSim.Region.RegionCombinerModule
34{
35public class RegionCombinerClientEventForwarder
36 {
37 private Scene m_rootScene;
38 private Dictionary<UUID, Scene> m_virtScene = new Dictionary<UUID, Scene>();
39 private Dictionary<UUID,RegionCombinerIndividualEventForwarder> m_forwarders = new Dictionary<UUID,
40 RegionCombinerIndividualEventForwarder>();
41
42 public RegionCombinerClientEventForwarder(RegionConnections rootScene)
43 {
44 m_rootScene = rootScene.RegionScene;
45 }
46
47 public void AddSceneToEventForwarding(Scene virtualScene)
48 {
49 lock (m_virtScene)
50 {
51 if (m_virtScene.ContainsKey(virtualScene.RegionInfo.originRegionID))
52 {
53 m_virtScene[virtualScene.RegionInfo.originRegionID] = virtualScene;
54 }
55 else
56 {
57 m_virtScene.Add(virtualScene.RegionInfo.originRegionID, virtualScene);
58 }
59 }
60
61 lock (m_forwarders)
62 {
63 // TODO: Fix this to unregister if this happens
64 if (m_forwarders.ContainsKey(virtualScene.RegionInfo.originRegionID))
65 m_forwarders.Remove(virtualScene.RegionInfo.originRegionID);
66
67 RegionCombinerIndividualEventForwarder forwarder =
68 new RegionCombinerIndividualEventForwarder(m_rootScene, virtualScene);
69 m_forwarders.Add(virtualScene.RegionInfo.originRegionID, forwarder);
70
71 virtualScene.EventManager.OnNewClient += forwarder.ClientConnect;
72 virtualScene.EventManager.OnClientClosed += forwarder.ClientClosed;
73 }
74 }
75
76 public void RemoveSceneFromEventForwarding (Scene virtualScene)
77 {
78 lock (m_forwarders)
79 {
80 RegionCombinerIndividualEventForwarder forwarder = m_forwarders[virtualScene.RegionInfo.originRegionID];
81 virtualScene.EventManager.OnNewClient -= forwarder.ClientConnect;
82 virtualScene.EventManager.OnClientClosed -= forwarder.ClientClosed;
83 m_forwarders.Remove(virtualScene.RegionInfo.originRegionID);
84 }
85 lock (m_virtScene)
86 {
87 if (m_virtScene.ContainsKey(virtualScene.RegionInfo.originRegionID))
88 {
89 m_virtScene.Remove(virtualScene.RegionInfo.originRegionID);
90 }
91 }
92 }
93 }
94} \ No newline at end of file
diff --git a/OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCombinerIndividualEventForwarder.cs b/OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCombinerIndividualEventForwarder.cs
new file mode 100644
index 0000000..83732e2
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCombinerIndividualEventForwarder.cs
@@ -0,0 +1,139 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using OpenMetaverse;
30using OpenSim.Framework;
31using OpenSim.Region.CoreModules.Avatar.Attachments;
32using OpenSim.Region.CoreModules.Avatar.Gods;
33using OpenSim.Region.Framework.Interfaces;
34using OpenSim.Region.Framework.Scenes;
35
36namespace OpenSim.Region.RegionCombinerModule
37{
38 public class RegionCombinerIndividualEventForwarder
39 {
40 private Scene m_rootScene;
41 private Scene m_virtScene;
42
43 public RegionCombinerIndividualEventForwarder(Scene rootScene, Scene virtScene)
44 {
45 m_rootScene = rootScene;
46 m_virtScene = virtScene;
47 }
48
49 public void ClientConnect(IClientAPI client)
50 {
51 m_virtScene.UnSubscribeToClientPrimEvents(client);
52 m_virtScene.UnSubscribeToClientPrimRezEvents(client);
53 m_virtScene.UnSubscribeToClientInventoryEvents(client);
54 if(m_virtScene.AttachmentsModule != null)
55 ((AttachmentsModule)m_virtScene.AttachmentsModule).UnsubscribeFromClientEvents(client);
56 //m_virtScene.UnSubscribeToClientTeleportEvents(client);
57 m_virtScene.UnSubscribeToClientScriptEvents(client);
58
59 IGodsModule virtGodsModule = m_virtScene.RequestModuleInterface<IGodsModule>();
60 if (virtGodsModule != null)
61 ((GodsModule)virtGodsModule).UnsubscribeFromClientEvents(client);
62
63 m_virtScene.UnSubscribeToClientNetworkEvents(client);
64
65 m_rootScene.SubscribeToClientPrimEvents(client);
66 client.OnAddPrim += LocalAddNewPrim;
67 client.OnRezObject += LocalRezObject;
68
69 m_rootScene.SubscribeToClientInventoryEvents(client);
70 if (m_rootScene.AttachmentsModule != null)
71 ((AttachmentsModule)m_rootScene.AttachmentsModule).SubscribeToClientEvents(client);
72 //m_rootScene.SubscribeToClientTeleportEvents(client);
73 m_rootScene.SubscribeToClientScriptEvents(client);
74
75 IGodsModule rootGodsModule = m_virtScene.RequestModuleInterface<IGodsModule>();
76 if (rootGodsModule != null)
77 ((GodsModule)rootGodsModule).UnsubscribeFromClientEvents(client);
78
79 m_rootScene.SubscribeToClientNetworkEvents(client);
80 }
81
82 public void ClientClosed(UUID clientid, Scene scene)
83 {
84 }
85
86 /// <summary>
87 /// Fixes position based on the region the Rez event came in on
88 /// </summary>
89 /// <param name="remoteclient"></param>
90 /// <param name="itemid"></param>
91 /// <param name="rayend"></param>
92 /// <param name="raystart"></param>
93 /// <param name="raytargetid"></param>
94 /// <param name="bypassraycast"></param>
95 /// <param name="rayendisintersection"></param>
96 /// <param name="rezselected"></param>
97 /// <param name="removeitem"></param>
98 /// <param name="fromtaskid"></param>
99 private void LocalRezObject(IClientAPI remoteclient, UUID itemid, Vector3 rayend, Vector3 raystart,
100 UUID raytargetid, byte bypassraycast, bool rayendisintersection, bool rezselected, bool removeitem,
101 UUID fromtaskid)
102 {
103 int differenceX = (int)m_virtScene.RegionInfo.RegionLocX - (int)m_rootScene.RegionInfo.RegionLocX;
104 int differenceY = (int)m_virtScene.RegionInfo.RegionLocY - (int)m_rootScene.RegionInfo.RegionLocY;
105 rayend.X += differenceX * (int)Constants.RegionSize;
106 rayend.Y += differenceY * (int)Constants.RegionSize;
107 raystart.X += differenceX * (int)Constants.RegionSize;
108 raystart.Y += differenceY * (int)Constants.RegionSize;
109
110 m_rootScene.RezObject(remoteclient, itemid, rayend, raystart, raytargetid, bypassraycast,
111 rayendisintersection, rezselected, removeitem, fromtaskid);
112 }
113 /// <summary>
114 /// Fixes position based on the region the AddPrimShape event came in on
115 /// </summary>
116 /// <param name="ownerid"></param>
117 /// <param name="groupid"></param>
118 /// <param name="rayend"></param>
119 /// <param name="rot"></param>
120 /// <param name="shape"></param>
121 /// <param name="bypassraycast"></param>
122 /// <param name="raystart"></param>
123 /// <param name="raytargetid"></param>
124 /// <param name="rayendisintersection"></param>
125 private void LocalAddNewPrim(UUID ownerid, UUID groupid, Vector3 rayend, Quaternion rot,
126 PrimitiveBaseShape shape, byte bypassraycast, Vector3 raystart, UUID raytargetid,
127 byte rayendisintersection)
128 {
129 int differenceX = (int)m_virtScene.RegionInfo.RegionLocX - (int)m_rootScene.RegionInfo.RegionLocX;
130 int differenceY = (int)m_virtScene.RegionInfo.RegionLocY - (int)m_rootScene.RegionInfo.RegionLocY;
131 rayend.X += differenceX * (int)Constants.RegionSize;
132 rayend.Y += differenceY * (int)Constants.RegionSize;
133 raystart.X += differenceX * (int)Constants.RegionSize;
134 raystart.Y += differenceY * (int)Constants.RegionSize;
135 m_rootScene.AddNewPrim(ownerid, groupid, rayend, rot, shape, bypassraycast, raystart, raytargetid,
136 rayendisintersection);
137 }
138 }
139} \ No newline at end of file
diff --git a/OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCombinerLargeLandChannel.cs b/OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCombinerLargeLandChannel.cs
new file mode 100644
index 0000000..4bf2a82
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCombinerLargeLandChannel.cs
@@ -0,0 +1,201 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using log4net;
32using OpenMetaverse;
33using OpenSim.Framework;
34using OpenSim.Region.Framework.Interfaces;
35using OpenSim.Region.CoreModules.World.Land;
36
37namespace OpenSim.Region.RegionCombinerModule
38{
39 public class RegionCombinerLargeLandChannel : ILandChannel
40 {
41// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
42
43 private RegionData RegData;
44 private ILandChannel RootRegionLandChannel;
45 private readonly List<RegionData> RegionConnections;
46
47 #region ILandChannel Members
48
49 public RegionCombinerLargeLandChannel(RegionData regData, ILandChannel rootRegionLandChannel,
50 List<RegionData> regionConnections)
51 {
52 RegData = regData;
53 RootRegionLandChannel = rootRegionLandChannel;
54 RegionConnections = regionConnections;
55 }
56
57 public List<ILandObject> ParcelsNearPoint(Vector3 position)
58 {
59 //m_log.DebugFormat("[LANDPARCELNEARPOINT]: {0}>", position);
60 return RootRegionLandChannel.ParcelsNearPoint(position - RegData.Offset);
61 }
62
63 public List<ILandObject> AllParcels()
64 {
65 return RootRegionLandChannel.AllParcels();
66 }
67
68 public void Clear(bool setupDefaultParcel)
69 {
70 RootRegionLandChannel.Clear(setupDefaultParcel);
71 }
72
73 public ILandObject GetLandObject(Vector3 position)
74 {
75 return GetLandObject(position.X, position.Y);
76 }
77
78 public ILandObject GetLandObject(int x, int y)
79 {
80 return GetLandObject((float)x, (float)y);
81
82// m_log.DebugFormat("[BIGLANDTESTINT]: <{0},{1}>", x, y);
83//
84// if (x > 0 && x <= (int)Constants.RegionSize && y > 0 && y <= (int)Constants.RegionSize)
85// {
86// return RootRegionLandChannel.GetLandObject(x, y);
87// }
88// else
89// {
90// int offsetX = (x / (int)Constants.RegionSize);
91// int offsetY = (y / (int)Constants.RegionSize);
92// offsetX *= (int)Constants.RegionSize;
93// offsetY *= (int)Constants.RegionSize;
94//
95// foreach (RegionData regionData in RegionConnections)
96// {
97// if (regionData.Offset.X == offsetX && regionData.Offset.Y == offsetY)
98// {
99// m_log.DebugFormat(
100// "[REGION COMBINER LARGE LAND CHANNEL]: Found region {0} at offset {1},{2}",
101// regionData.RegionScene.Name, offsetX, offsetY);
102//
103// return regionData.RegionScene.LandChannel.GetLandObject(x - offsetX, y - offsetY);
104// }
105// }
106// //ILandObject obj = new LandObject(UUID.Zero, false, RegData.RegionScene);
107// //obj.LandData.Name = "NO LAND";
108// //return obj;
109// }
110//
111// m_log.DebugFormat("[REGION COMBINER LARGE LAND CHANNEL]: No region found at {0},{1}, returning null", x, y);
112//
113// return null;
114 }
115
116 public ILandObject GetLandObject(int localID)
117 {
118 // XXX: Possibly should be looking in every land channel, not just the root.
119 return RootRegionLandChannel.GetLandObject(localID);
120 }
121
122 public ILandObject GetLandObject(float x, float y)
123 {
124// m_log.DebugFormat("[BIGLANDTESTFLOAT]: <{0},{1}>", x, y);
125
126 if (x > 0 && x <= (int)Constants.RegionSize && y > 0 && y <= (int)Constants.RegionSize)
127 {
128 return RootRegionLandChannel.GetLandObject(x, y);
129 }
130 else
131 {
132 int offsetX = (int)(x/(int) Constants.RegionSize);
133 int offsetY = (int)(y/(int) Constants.RegionSize);
134 offsetX *= (int) Constants.RegionSize;
135 offsetY *= (int) Constants.RegionSize;
136
137 foreach (RegionData regionData in RegionConnections)
138 {
139 if (regionData.Offset.X == offsetX && regionData.Offset.Y == offsetY)
140 {
141// m_log.DebugFormat(
142// "[REGION COMBINER LARGE LAND CHANNEL]: Found region {0} at offset {1},{2}",
143// regionData.RegionScene.Name, offsetX, offsetY);
144
145 return regionData.RegionScene.LandChannel.GetLandObject(x - offsetX, y - offsetY);
146 }
147 }
148
149// ILandObject obj = new LandObject(UUID.Zero, false, RegData.RegionScene);
150// obj.LandData.Name = "NO LAND";
151// return obj;
152 }
153
154// m_log.DebugFormat("[REGION COMBINER LARGE LAND CHANNEL]: No region found at {0},{1}, returning null", x, y);
155
156 return null;
157 }
158
159 public bool IsForcefulBansAllowed()
160 {
161 return RootRegionLandChannel.IsForcefulBansAllowed();
162 }
163
164 public void UpdateLandObject(int localID, LandData data)
165 {
166 RootRegionLandChannel.UpdateLandObject(localID, data);
167 }
168
169 public void Join(int start_x, int start_y, int end_x, int end_y, UUID attempting_user_id)
170 {
171 RootRegionLandChannel.Join(start_x, start_y, end_x, end_y, attempting_user_id);
172 }
173
174 public void Subdivide(int start_x, int start_y, int end_x, int end_y, UUID attempting_user_id)
175 {
176 RootRegionLandChannel.Subdivide(start_x, start_y, end_x, end_y, attempting_user_id);
177 }
178
179 public void ReturnObjectsInParcel(int localID, uint returnType, UUID[] agentIDs, UUID[] taskIDs, IClientAPI remoteClient)
180 {
181 RootRegionLandChannel.ReturnObjectsInParcel(localID, returnType, agentIDs, taskIDs, remoteClient);
182 }
183
184 public void setParcelObjectMaxOverride(overrideParcelMaxPrimCountDelegate overrideDel)
185 {
186 RootRegionLandChannel.setParcelObjectMaxOverride(overrideDel);
187 }
188
189 public void setSimulatorObjectMaxOverride(overrideSimulatorMaxPrimCountDelegate overrideDel)
190 {
191 RootRegionLandChannel.setSimulatorObjectMaxOverride(overrideDel);
192 }
193
194 public void SetParcelOtherCleanTime(IClientAPI remoteClient, int localID, int otherCleanTime)
195 {
196 RootRegionLandChannel.SetParcelOtherCleanTime(remoteClient, localID, otherCleanTime);
197 }
198
199 #endregion
200 }
201} \ No newline at end of file
diff --git a/OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCombinerModule.cs b/OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCombinerModule.cs
new file mode 100644
index 0000000..32eead0
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCombinerModule.cs
@@ -0,0 +1,880 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using log4net;
32using Nini.Config;
33using OpenMetaverse;
34using OpenSim.Framework;
35using OpenSim.Framework.Client;
36using OpenSim.Region.Framework.Interfaces;
37using OpenSim.Region.Framework.Scenes;
38using OpenSim.Framework.Console;
39using OpenSim.Region.PhysicsModules.SharedBase;
40using Mono.Addins;
41
42namespace OpenSim.Region.RegionCombinerModule
43{
44 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "RegionCombinerModule")]
45 public class RegionCombinerModule : ISharedRegionModule, IRegionCombinerModule
46 {
47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48// private static string LogHeader = "[REGION COMBINER MODULE]";
49
50 public string Name
51 {
52 get { return "RegionCombinerModule"; }
53 }
54
55 public Type ReplaceableInterface
56 {
57 get { return null; }
58 }
59
60 /// <summary>
61 /// Is this module enabled?
62 /// </summary>
63 private bool m_combineContiguousRegions = false;
64
65 /// <summary>
66 /// This holds the root regions for the megaregions.
67 /// </summary>
68 /// <remarks>
69 /// Usually there is only ever one megaregion (and hence only one entry here).
70 /// </remarks>
71 private Dictionary<UUID, RegionConnections> m_regions = new Dictionary<UUID, RegionConnections>();
72
73 /// <summary>
74 /// The scenes that comprise the megaregion.
75 /// </summary>
76 private Dictionary<UUID, Scene> m_startingScenes = new Dictionary<UUID, Scene>();
77
78 public void Initialise(IConfigSource source)
79 {
80 IConfig myConfig = source.Configs["Startup"];
81 m_combineContiguousRegions = myConfig.GetBoolean("CombineContiguousRegions", false);
82 if (m_combineContiguousRegions)
83 m_log.ErrorFormat("[REGION COMBINER MODULE]: THIS MODULE IS BEING MARKED OBSOLETE AND MAY SOON BE REMOVED. PLEASE USE VARREGIONS INSTEAD.");
84
85 MainConsole.Instance.Commands.AddCommand(
86 "RegionCombinerModule", false, "fix-phantoms", "fix-phantoms",
87 "Fixes phantom objects after an import to a megaregion or a change from a megaregion back to normal regions",
88 FixPhantoms);
89 }
90
91 public void Close()
92 {
93 }
94
95 public void AddRegion(Scene scene)
96 {
97 if (m_combineContiguousRegions)
98 scene.RegisterModuleInterface<IRegionCombinerModule>(this);
99 }
100
101 public void RemoveRegion(Scene scene)
102 {
103 lock (m_startingScenes)
104 m_startingScenes.Remove(scene.RegionInfo.originRegionID);
105 }
106
107 public void RegionLoaded(Scene scene)
108 {
109 lock (m_startingScenes)
110 m_startingScenes.Add(scene.RegionInfo.originRegionID, scene);
111
112 if (m_combineContiguousRegions)
113 {
114 RegionLoadedDoWork(scene);
115
116 scene.EventManager.OnNewPresence += NewPresence;
117 }
118 }
119
120 public bool IsRootForMegaregion(UUID regionId)
121 {
122 lock (m_regions)
123 return m_regions.ContainsKey(regionId);
124 }
125
126 public Vector2 GetSizeOfMegaregion(UUID regionId)
127 {
128 lock (m_regions)
129 {
130 if (m_regions.ContainsKey(regionId))
131 {
132 RegionConnections rootConn = m_regions[regionId];
133
134 return new Vector2((float)rootConn.XEnd, (float)rootConn.YEnd);
135 }
136 }
137
138 throw new Exception(string.Format("Region with id {0} not found", regionId));
139 }
140
141 // Test to see if this postiion (relative to the region) is within the area covered
142 // by this megaregion.
143 public bool PositionIsInMegaregion(UUID currentRegion, int xx, int yy)
144 {
145 bool ret = false;
146 if (xx < 0 || yy < 0)
147 return ret;
148
149 foreach (RegionConnections rootRegion in m_regions.Values)
150 {
151 if (currentRegion == rootRegion.RegionId)
152 {
153 // The caller is in the root region so this is an easy test
154 if (xx < rootRegion.XEnd && yy < rootRegion.YEnd)
155 {
156 ret = true;
157 }
158 break;
159 }
160 else
161 {
162 // Maybe the caller is in one of the sub-regions
163 foreach (RegionData childRegion in rootRegion.ConnectedRegions)
164 {
165 if (currentRegion == childRegion.RegionId)
166 {
167 // This is a child. Diddle the offsets and check if in
168 Vector3 positionInMegaregion = childRegion.Offset;
169 positionInMegaregion.X += xx;
170 positionInMegaregion.Y += yy;
171 if (positionInMegaregion.X < rootRegion.XEnd && positionInMegaregion.Y < rootRegion.YEnd)
172 {
173 ret = true;
174 }
175 break;
176 }
177 }
178 }
179 }
180
181 return ret;
182 }
183
184 private void NewPresence(ScenePresence presence)
185 {
186 if (presence.IsChildAgent)
187 {
188 byte[] throttleData;
189
190 try
191 {
192 throttleData = presence.ControllingClient.GetThrottlesPacked(1);
193 }
194 catch (NotImplementedException)
195 {
196 return;
197 }
198
199 if (throttleData == null)
200 return;
201
202 if (throttleData.Length == 0)
203 return;
204
205 if (throttleData.Length != 28)
206 return;
207
208 byte[] adjData;
209 int pos = 0;
210
211 if (!BitConverter.IsLittleEndian)
212 {
213 byte[] newData = new byte[7 * 4];
214 Buffer.BlockCopy(throttleData, 0, newData, 0, 7 * 4);
215
216 for (int i = 0; i < 7; i++)
217 Array.Reverse(newData, i * 4, 4);
218
219 adjData = newData;
220 }
221 else
222 {
223 adjData = throttleData;
224 }
225
226 // 0.125f converts from bits to bytes
227 int resend = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
228 int land = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
229 int wind = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
230 int cloud = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
231 int task = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
232 int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
233 int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
234 // State is a subcategory of task that we allocate a percentage to
235
236
237 //int total = resend + land + wind + cloud + task + texture + asset;
238
239 byte[] data = new byte[7 * 4];
240 int ii = 0;
241
242 Buffer.BlockCopy(Utils.FloatToBytes(resend), 0, data, ii, 4); ii += 4;
243 Buffer.BlockCopy(Utils.FloatToBytes(land * 50), 0, data, ii, 4); ii += 4;
244 Buffer.BlockCopy(Utils.FloatToBytes(wind), 0, data, ii, 4); ii += 4;
245 Buffer.BlockCopy(Utils.FloatToBytes(cloud), 0, data, ii, 4); ii += 4;
246 Buffer.BlockCopy(Utils.FloatToBytes(task), 0, data, ii, 4); ii += 4;
247 Buffer.BlockCopy(Utils.FloatToBytes(texture), 0, data, ii, 4); ii += 4;
248 Buffer.BlockCopy(Utils.FloatToBytes(asset), 0, data, ii, 4);
249
250 try
251 {
252 presence.ControllingClient.SetChildAgentThrottle(data);
253 }
254 catch (NotImplementedException)
255 {
256 return;
257 }
258 }
259 }
260
261 private void RegionLoadedDoWork(Scene scene)
262 {
263/*
264 // For testing on a single instance
265 if (scene.RegionInfo.RegionLocX == 1004 && scene.RegionInfo.RegionLocY == 1000)
266 return;
267 //
268*/
269
270 RegionConnections newConn = new RegionConnections();
271 newConn.ConnectedRegions = new List<RegionData>();
272 newConn.RegionScene = scene;
273 newConn.RegionLandChannel = scene.LandChannel;
274 newConn.RegionId = scene.RegionInfo.originRegionID;
275 newConn.X = scene.RegionInfo.RegionLocX;
276 newConn.Y = scene.RegionInfo.RegionLocY;
277 newConn.XEnd = scene.RegionInfo.RegionSizeX;
278 newConn.YEnd = scene.RegionInfo.RegionSizeX;
279
280 lock (m_regions)
281 {
282 bool connectedYN = false;
283
284 foreach (RegionConnections rootConn in m_regions.Values)
285 {
286 #region commented
287 /*
288 // If we're one region over +x +y
289 //xxy
290 //xxx
291 //xxx
292 if ((((int)conn.X * (int)Constants.RegionSize) + conn.XEnd
293 == (regionConnections.X * (int)Constants.RegionSize))
294 && (((int)conn.Y * (int)Constants.RegionSize) - conn.YEnd
295 == (regionConnections.Y * (int)Constants.RegionSize)))
296 {
297 Vector3 offset = Vector3.Zero;
298 offset.X = (((regionConnections.X * (int) Constants.RegionSize)) -
299 ((conn.X * (int) Constants.RegionSize)));
300 offset.Y = (((regionConnections.Y * (int) Constants.RegionSize)) -
301 ((conn.Y * (int) Constants.RegionSize)));
302
303 Vector3 extents = Vector3.Zero;
304 extents.Y = regionConnections.YEnd + conn.YEnd;
305 extents.X = conn.XEnd + conn.XEnd;
306
307 m_log.DebugFormat("Scene: {0} to the northwest of Scene{1}. Offset: {2}. Extents:{3}",
308 conn.RegionScene.RegionInfo.RegionName,
309 regionConnections.RegionScene.RegionInfo.RegionName,
310 offset, extents);
311
312 scene.PhysicsScene.Combine(conn.RegionScene.PhysicsScene, offset, extents);
313
314 connectedYN = true;
315 break;
316 }
317 */
318
319 /*
320 //If we're one region over x +y
321 //xxx
322 //xxx
323 //xyx
324 if ((((int)conn.X * (int)Constants.RegionSize)
325 == (regionConnections.X * (int)Constants.RegionSize))
326 && (((int)conn.Y * (int)Constants.RegionSize) - conn.YEnd
327 == (regionConnections.Y * (int)Constants.RegionSize)))
328 {
329 Vector3 offset = Vector3.Zero;
330 offset.X = (((regionConnections.X * (int)Constants.RegionSize)) -
331 ((conn.X * (int)Constants.RegionSize)));
332 offset.Y = (((regionConnections.Y * (int)Constants.RegionSize)) -
333 ((conn.Y * (int)Constants.RegionSize)));
334
335 Vector3 extents = Vector3.Zero;
336 extents.Y = regionConnections.YEnd + conn.YEnd;
337 extents.X = conn.XEnd;
338
339 m_log.DebugFormat("Scene: {0} to the north of Scene{1}. Offset: {2}. Extents:{3}",
340 conn.RegionScene.RegionInfo.RegionName,
341 regionConnections.RegionScene.RegionInfo.RegionName, offset, extents);
342
343 scene.PhysicsScene.Combine(conn.RegionScene.PhysicsScene, offset, extents);
344 connectedYN = true;
345 break;
346 }
347 */
348
349 /*
350 // If we're one region over -x +y
351 //xxx
352 //xxx
353 //yxx
354 if ((((int)conn.X * (int)Constants.RegionSize) - conn.XEnd
355 == (regionConnections.X * (int)Constants.RegionSize))
356 && (((int)conn.Y * (int)Constants.RegionSize) - conn.YEnd
357 == (regionConnections.Y * (int)Constants.RegionSize)))
358 {
359 Vector3 offset = Vector3.Zero;
360 offset.X = (((regionConnections.X * (int)Constants.RegionSize)) -
361 ((conn.X * (int)Constants.RegionSize)));
362 offset.Y = (((regionConnections.Y * (int)Constants.RegionSize)) -
363 ((conn.Y * (int)Constants.RegionSize)));
364
365 Vector3 extents = Vector3.Zero;
366 extents.Y = regionConnections.YEnd + conn.YEnd;
367 extents.X = conn.XEnd + conn.XEnd;
368
369 m_log.DebugFormat("Scene: {0} to the northeast of Scene. Offset: {2}. Extents:{3}",
370 conn.RegionScene.RegionInfo.RegionName,
371 regionConnections.RegionScene.RegionInfo.RegionName, offset, extents);
372
373 scene.PhysicsScene.Combine(conn.RegionScene.PhysicsScene, offset, extents);
374
375
376 connectedYN = true;
377 break;
378 }
379 */
380
381 /*
382 // If we're one region over -x y
383 //xxx
384 //yxx
385 //xxx
386 if ((((int)conn.X * (int)Constants.RegionSize) - conn.XEnd
387 == (regionConnections.X * (int)Constants.RegionSize))
388 && (((int)conn.Y * (int)Constants.RegionSize)
389 == (regionConnections.Y * (int)Constants.RegionSize)))
390 {
391 Vector3 offset = Vector3.Zero;
392 offset.X = (((regionConnections.X * (int)Constants.RegionSize)) -
393 ((conn.X * (int)Constants.RegionSize)));
394 offset.Y = (((regionConnections.Y * (int)Constants.RegionSize)) -
395 ((conn.Y * (int)Constants.RegionSize)));
396
397 Vector3 extents = Vector3.Zero;
398 extents.Y = regionConnections.YEnd;
399 extents.X = conn.XEnd + conn.XEnd;
400
401 m_log.DebugFormat("Scene: {0} to the east of Scene{1} Offset: {2}. Extents:{3}",
402 conn.RegionScene.RegionInfo.RegionName,
403 regionConnections.RegionScene.RegionInfo.RegionName, offset, extents);
404
405 scene.PhysicsScene.Combine(conn.RegionScene.PhysicsScene, offset, extents);
406
407 connectedYN = true;
408 break;
409 }
410 */
411
412 /*
413 // If we're one region over -x -y
414 //yxx
415 //xxx
416 //xxx
417 if ((((int)conn.X * (int)Constants.RegionSize) - conn.XEnd
418 == (regionConnections.X * (int)Constants.RegionSize))
419 && (((int)conn.Y * (int)Constants.RegionSize) + conn.YEnd
420 == (regionConnections.Y * (int)Constants.RegionSize)))
421 {
422 Vector3 offset = Vector3.Zero;
423 offset.X = (((regionConnections.X * (int)Constants.RegionSize)) -
424 ((conn.X * (int)Constants.RegionSize)));
425 offset.Y = (((regionConnections.Y * (int)Constants.RegionSize)) -
426 ((conn.Y * (int)Constants.RegionSize)));
427
428 Vector3 extents = Vector3.Zero;
429 extents.Y = regionConnections.YEnd + conn.YEnd;
430 extents.X = conn.XEnd + conn.XEnd;
431
432 m_log.DebugFormat("Scene: {0} to the northeast of Scene{1} Offset: {2}. Extents:{3}",
433 conn.RegionScene.RegionInfo.RegionName,
434 regionConnections.RegionScene.RegionInfo.RegionName, offset, extents);
435
436 scene.PhysicsScene.Combine(conn.RegionScene.PhysicsScene, offset, extents);
437
438 connectedYN = true;
439 break;
440 }
441 */
442 #endregion
443
444
445 // Check to see if this new region is adjacent to the root region.
446 // Note that we expect the regions to be combined from the root region outward
447 // thus the requirement for the ordering in the configuration files.
448
449 // If we're one region over +x y (i.e. root region is to the west)
450 //xxx
451 //xxy
452 //xxx
453 if (rootConn.PosX + rootConn.XEnd >= newConn.PosX && rootConn.PosY >= newConn.PosY)
454 {
455 connectedYN = DoWorkForOneRegionOverPlusXY(rootConn, newConn, scene);
456 break;
457 }
458
459 // If we're one region over x +y (i.e. root region is to the south)
460 //xyx
461 //xxx
462 //xxx
463 if (rootConn.PosX >= newConn.PosX && rootConn.PosY + rootConn.YEnd >= newConn.PosY)
464 {
465 connectedYN = DoWorkForOneRegionOverPlusXY(rootConn, newConn, scene);
466 break;
467 }
468
469 // If we're one region over +x +y (i.e. root region is to the south-west)
470 //xxy
471 //xxx
472 //xxx
473 if (rootConn.PosX + rootConn.XEnd >= newConn.PosX && rootConn.PosY + rootConn.YEnd >= newConn.PosY)
474 {
475 connectedYN = DoWorkForOneRegionOverPlusXY(rootConn, newConn, scene);
476 break;
477 }
478 }
479
480 // If !connectYN means that this region is a root region
481 if (!connectedYN)
482 {
483 DoWorkForRootRegion(newConn, scene);
484 }
485 }
486 }
487
488 private bool DoWorkForOneRegionOverPlusXY(RegionConnections rootConn, RegionConnections newConn, Scene scene)
489 {
490 // Offset (in meters) from the base of this region to the base of the root region.
491 Vector3 offset = Vector3.Zero;
492 offset.X = newConn.PosX - rootConn.PosX;
493 offset.Y = newConn.PosY - rootConn.PosY;
494
495 // The new total size of the region (in meters)
496 // We just extend the X and Y dimensions so the extent might temporarily include areas without regions.
497 Vector3 extents = Vector3.Zero;
498 extents.X = Math.Max(rootConn.XEnd, offset.X + newConn.RegionScene.RegionInfo.RegionSizeX);
499 extents.Y = Math.Max(rootConn.YEnd, offset.Y + newConn.RegionScene.RegionInfo.RegionSizeY);
500
501 rootConn.UpdateExtents(extents);
502
503 m_log.DebugFormat(
504 "[REGION COMBINER MODULE]: Root region {0} is to the west of region {1}, Offset: {2}, Extents: {3}",
505 rootConn.RegionScene.RegionInfo.RegionName,
506 newConn.RegionScene.RegionInfo.RegionName, offset, extents);
507
508 RegionData ConnectedRegion = new RegionData();
509 ConnectedRegion.Offset = offset;
510 ConnectedRegion.RegionId = scene.RegionInfo.originRegionID;
511 ConnectedRegion.RegionScene = scene;
512 rootConn.ConnectedRegions.Add(ConnectedRegion);
513
514 // Inform root region Physics about the extents of this region
515 rootConn.RegionScene.PhysicsScene.Combine(null, Vector3.Zero, extents);
516
517 // Inform Child region that it needs to forward it's terrain to the root region
518 scene.PhysicsScene.Combine(rootConn.RegionScene.PhysicsScene, offset, Vector3.Zero);
519
520 // Reset Terrain.. since terrain loads before we get here, we need to load
521 // it again so it loads in the root region
522 scene.PhysicsScene.SetTerrain(scene.Heightmap.GetFloatsSerialised());
523
524 // Create a client event forwarder and add this region's events to the root region.
525 if (rootConn.ClientEventForwarder != null)
526 rootConn.ClientEventForwarder.AddSceneToEventForwarding(scene);
527
528 return true;
529 }
530
531 /*
532 * 20140215 radams1: The border stuff was removed and the addition of regions to the mega-regions
533 * was generalized. These functions are not needed for the generalized solution but left for reference.
534 private bool DoWorkForOneRegionOverXPlusY(RegionConnections rootConn, RegionConnections newConn, Scene scene)
535 {
536 Vector3 offset = Vector3.Zero;
537 offset.X = newConn.PosX - rootConn.PosX;
538 offset.Y = newConn.PosY - rootConn.PosY;
539
540 Vector3 extents = Vector3.Zero;
541 extents.Y = newConn.YEnd + rootConn.YEnd;
542 extents.X = rootConn.XEnd;
543 rootConn.UpdateExtents(extents);
544
545 RegionData ConnectedRegion = new RegionData();
546 ConnectedRegion.Offset = offset;
547 ConnectedRegion.RegionId = scene.RegionInfo.originRegionID;
548 ConnectedRegion.RegionScene = scene;
549 rootConn.ConnectedRegions.Add(ConnectedRegion);
550
551 m_log.DebugFormat(
552 "[REGION COMBINER MODULE]: Root region {0} is to the south of region {1}, Offset: {2}, Extents: {3}",
553 rootConn.RegionScene.RegionInfo.RegionName,
554 newConn.RegionScene.RegionInfo.RegionName, offset, extents);
555
556 rootConn.RegionScene.PhysicsScene.Combine(null, Vector3.Zero, extents);
557 scene.PhysicsScene.Combine(rootConn.RegionScene.PhysicsScene, offset, Vector3.Zero);
558
559 // Reset Terrain.. since terrain normally loads first.
560 //conn.RegionScene.PhysicsScene.SetTerrain(conn.RegionScene.Heightmap.GetFloatsSerialised());
561 scene.PhysicsScene.SetTerrain(scene.Heightmap.GetFloatsSerialised());
562 //conn.RegionScene.PhysicsScene.SetTerrain(conn.RegionScene.Heightmap.GetFloatsSerialised());
563
564 if (rootConn.ClientEventForwarder != null)
565 rootConn.ClientEventForwarder.AddSceneToEventForwarding(scene);
566
567 return true;
568 }
569
570 private bool DoWorkForOneRegionOverPlusXPlusY(RegionConnections rootConn, RegionConnections newConn, Scene scene)
571 {
572 Vector3 offset = Vector3.Zero;
573 offset.X = newConn.PosX - rootConn.PosX;
574 offset.Y = newConn.PosY - rootConn.PosY;
575
576 Vector3 extents = Vector3.Zero;
577
578 // We do not want to inflate the extents for regions strictly to the NE of the root region, since this
579 // would double count regions strictly to the north and east that have already been added.
580// extents.Y = regionConnections.YEnd + conn.YEnd;
581// extents.X = regionConnections.XEnd + conn.XEnd;
582// conn.UpdateExtents(extents);
583
584 extents.Y = rootConn.YEnd;
585 extents.X = rootConn.XEnd;
586
587 RegionData ConnectedRegion = new RegionData();
588 ConnectedRegion.Offset = offset;
589 ConnectedRegion.RegionId = scene.RegionInfo.originRegionID;
590 ConnectedRegion.RegionScene = scene;
591
592 rootConn.ConnectedRegions.Add(ConnectedRegion);
593
594 m_log.DebugFormat(
595 "[REGION COMBINER MODULE]: Region {0} is to the southwest of Scene {1}, Offset: {2}, Extents: {3}",
596 rootConn.RegionScene.RegionInfo.RegionName,
597 newConn.RegionScene.RegionInfo.RegionName, offset, extents);
598
599 rootConn.RegionScene.PhysicsScene.Combine(null, Vector3.Zero, extents);
600 scene.PhysicsScene.Combine(rootConn.RegionScene.PhysicsScene, offset, Vector3.Zero);
601
602 // Reset Terrain.. since terrain normally loads first.
603 //conn.RegionScene.PhysicsScene.SetTerrain(conn.RegionScene.Heightmap.GetFloatsSerialised());
604 scene.PhysicsScene.SetTerrain(scene.Heightmap.GetFloatsSerialised());
605 //conn.RegionScene.PhysicsScene.SetTerrain(conn.RegionScene.Heightmap.GetFloatsSerialised());
606
607 if (rootConn.ClientEventForwarder != null)
608 rootConn.ClientEventForwarder.AddSceneToEventForwarding(scene);
609
610 return true;
611
612 //scene.PhysicsScene.Combine(conn.RegionScene.PhysicsScene, offset,extents);
613 }
614 */
615
616 private void DoWorkForRootRegion(RegionConnections rootConn, Scene scene)
617 {
618 m_log.DebugFormat("[REGION COMBINER MODULE]: Adding root region {0}", scene.RegionInfo.RegionName);
619
620 RegionData rdata = new RegionData();
621 rdata.Offset = Vector3.Zero;
622 rdata.RegionId = scene.RegionInfo.originRegionID;
623 rdata.RegionScene = scene;
624 // save it's land channel
625 rootConn.RegionLandChannel = scene.LandChannel;
626
627 // Substitue our landchannel
628 RegionCombinerLargeLandChannel lnd = new RegionCombinerLargeLandChannel(rdata, scene.LandChannel,
629 rootConn.ConnectedRegions);
630
631 scene.LandChannel = lnd;
632
633 // Forward the permissions modules of each of the connected regions to the root region
634 lock (m_regions)
635 {
636 foreach (RegionData r in rootConn.ConnectedRegions)
637 {
638 ForwardPermissionRequests(rootConn, r.RegionScene);
639 }
640
641 // Create the root region's Client Event Forwarder
642 rootConn.ClientEventForwarder = new RegionCombinerClientEventForwarder(rootConn);
643
644 // Sets up the CoarseLocationUpdate forwarder for this root region
645 scene.EventManager.OnNewPresence += SetCoarseLocationDelegate;
646
647 // Adds this root region to a dictionary of regions that are connectable
648 m_regions.Add(scene.RegionInfo.originRegionID, rootConn);
649 }
650 }
651
652 private void SetCoarseLocationDelegate(ScenePresence presence)
653 {
654 presence.SetSendCoarseLocationMethod(SendCoarseLocationUpdates);
655 }
656
657 // This delegate was refactored for non-combined regions.
658 // This combined region version will not use the pre-compiled lists of locations and ids
659 private void SendCoarseLocationUpdates(UUID sceneId, ScenePresence presence, List<Vector3> coarseLocations, List<UUID> avatarUUIDs)
660 {
661 RegionConnections connectiondata = null;
662 lock (m_regions)
663 {
664 if (m_regions.ContainsKey(sceneId))
665 connectiondata = m_regions[sceneId];
666 else
667 return;
668 }
669
670 List<Vector3> CoarseLocations = new List<Vector3>();
671 List<UUID> AvatarUUIDs = new List<UUID>();
672
673 connectiondata.RegionScene.ForEachRootScenePresence(delegate(ScenePresence sp)
674 {
675 if (sp.UUID != presence.UUID)
676 {
677 CoarseLocations.Add(sp.AbsolutePosition);
678 AvatarUUIDs.Add(sp.UUID);
679 }
680 });
681
682 DistributeCoarseLocationUpdates(CoarseLocations, AvatarUUIDs, connectiondata, presence);
683 }
684
685 private void DistributeCoarseLocationUpdates(List<Vector3> locations, List<UUID> uuids,
686 RegionConnections connectiondata, ScenePresence rootPresence)
687 {
688 RegionData[] rdata = connectiondata.ConnectedRegions.ToArray();
689 //List<IClientAPI> clients = new List<IClientAPI>();
690 Dictionary<Vector2, RegionCoarseLocationStruct> updates = new Dictionary<Vector2, RegionCoarseLocationStruct>();
691
692 // Root Region entry
693 RegionCoarseLocationStruct rootupdatedata = new RegionCoarseLocationStruct();
694 rootupdatedata.Locations = new List<Vector3>();
695 rootupdatedata.Uuids = new List<UUID>();
696 rootupdatedata.Offset = Vector2.Zero;
697
698 rootupdatedata.UserAPI = rootPresence.ControllingClient;
699
700 if (rootupdatedata.UserAPI != null)
701 updates.Add(Vector2.Zero, rootupdatedata);
702
703 //Each Region needs an entry or we will end up with dead minimap dots
704 foreach (RegionData regiondata in rdata)
705 {
706 Vector2 offset = new Vector2(regiondata.Offset.X, regiondata.Offset.Y);
707 RegionCoarseLocationStruct updatedata = new RegionCoarseLocationStruct();
708 updatedata.Locations = new List<Vector3>();
709 updatedata.Uuids = new List<UUID>();
710 updatedata.Offset = offset;
711
712 if (offset == Vector2.Zero)
713 updatedata.UserAPI = rootPresence.ControllingClient;
714 else
715 updatedata.UserAPI = LocateUsersChildAgentIClientAPI(offset, rootPresence.UUID, rdata);
716
717 if (updatedata.UserAPI != null)
718 updates.Add(offset, updatedata);
719 }
720
721 // go over the locations and assign them to an IClientAPI
722 for (int i = 0; i < locations.Count; i++)
723 //{locations[i]/(int) Constants.RegionSize;
724 {
725 Vector3 pPosition = new Vector3((int)locations[i].X / (int)Constants.RegionSize,
726 (int)locations[i].Y / (int)Constants.RegionSize, locations[i].Z);
727 Vector2 offset = new Vector2(pPosition.X*(int) Constants.RegionSize,
728 pPosition.Y*(int) Constants.RegionSize);
729
730 if (!updates.ContainsKey(offset))
731 {
732 // This shouldn't happen
733 RegionCoarseLocationStruct updatedata = new RegionCoarseLocationStruct();
734 updatedata.Locations = new List<Vector3>();
735 updatedata.Uuids = new List<UUID>();
736 updatedata.Offset = offset;
737
738 if (offset == Vector2.Zero)
739 updatedata.UserAPI = rootPresence.ControllingClient;
740 else
741 updatedata.UserAPI = LocateUsersChildAgentIClientAPI(offset, rootPresence.UUID, rdata);
742
743 updates.Add(offset,updatedata);
744 }
745
746 updates[offset].Locations.Add(locations[i]);
747 updates[offset].Uuids.Add(uuids[i]);
748 }
749
750 // Send out the CoarseLocationupdates from their respective client connection based on where the avatar is
751 foreach (Vector2 offset in updates.Keys)
752 {
753 if (updates[offset].UserAPI != null)
754 {
755 updates[offset].UserAPI.SendCoarseLocationUpdate(updates[offset].Uuids,updates[offset].Locations);
756 }
757 }
758 }
759
760 /// <summary>
761 /// Locates a the Client of a particular region in an Array of RegionData based on offset
762 /// </summary>
763 /// <param name="offset"></param>
764 /// <param name="uUID"></param>
765 /// <param name="rdata"></param>
766 /// <returns>IClientAPI or null</returns>
767 private IClientAPI LocateUsersChildAgentIClientAPI(Vector2 offset, UUID uUID, RegionData[] rdata)
768 {
769 IClientAPI returnclient = null;
770 foreach (RegionData r in rdata)
771 {
772 if (r.Offset.X == offset.X && r.Offset.Y == offset.Y)
773 {
774 return r.RegionScene.SceneGraph.GetControllingClient(uUID);
775 }
776 }
777
778 return returnclient;
779 }
780
781 public void PostInitialise()
782 {
783 }
784
785// /// <summary>
786// /// TODO:
787// /// </summary>
788// /// <param name="rdata"></param>
789// public void UnCombineRegion(RegionData rdata)
790// {
791// lock (m_regions)
792// {
793// if (m_regions.ContainsKey(rdata.RegionId))
794// {
795// // uncombine root region and virtual regions
796// }
797// else
798// {
799// foreach (RegionConnections r in m_regions.Values)
800// {
801// foreach (RegionData rd in r.ConnectedRegions)
802// {
803// if (rd.RegionId == rdata.RegionId)
804// {
805// // uncombine virtual region
806// }
807// }
808// }
809// }
810// }
811// }
812
813 public void ForwardPermissionRequests(RegionConnections BigRegion, Scene VirtualRegion)
814 {
815 if (BigRegion.PermissionModule == null)
816 BigRegion.PermissionModule = new RegionCombinerPermissionModule(BigRegion.RegionScene);
817
818 VirtualRegion.Permissions.OnBypassPermissions += BigRegion.PermissionModule.BypassPermissions;
819 VirtualRegion.Permissions.OnSetBypassPermissions += BigRegion.PermissionModule.SetBypassPermissions;
820 VirtualRegion.Permissions.OnPropagatePermissions += BigRegion.PermissionModule.PropagatePermissions;
821 VirtualRegion.Permissions.OnGenerateClientFlags += BigRegion.PermissionModule.GenerateClientFlags;
822 VirtualRegion.Permissions.OnAbandonParcel += BigRegion.PermissionModule.CanAbandonParcel;
823 VirtualRegion.Permissions.OnReclaimParcel += BigRegion.PermissionModule.CanReclaimParcel;
824 VirtualRegion.Permissions.OnDeedParcel += BigRegion.PermissionModule.CanDeedParcel;
825 VirtualRegion.Permissions.OnDeedObject += BigRegion.PermissionModule.CanDeedObject;
826 VirtualRegion.Permissions.OnIsGod += BigRegion.PermissionModule.IsGod;
827 VirtualRegion.Permissions.OnDuplicateObject += BigRegion.PermissionModule.CanDuplicateObject;
828 VirtualRegion.Permissions.OnDeleteObject += BigRegion.PermissionModule.CanDeleteObject; //MAYBE FULLY IMPLEMENTED
829 VirtualRegion.Permissions.OnEditObject += BigRegion.PermissionModule.CanEditObject; //MAYBE FULLY IMPLEMENTED
830 VirtualRegion.Permissions.OnEditParcelProperties += BigRegion.PermissionModule.CanEditParcelProperties; //MAYBE FULLY IMPLEMENTED
831 VirtualRegion.Permissions.OnInstantMessage += BigRegion.PermissionModule.CanInstantMessage;
832 VirtualRegion.Permissions.OnInventoryTransfer += BigRegion.PermissionModule.CanInventoryTransfer; //NOT YET IMPLEMENTED
833 VirtualRegion.Permissions.OnIssueEstateCommand += BigRegion.PermissionModule.CanIssueEstateCommand; //FULLY IMPLEMENTED
834 VirtualRegion.Permissions.OnMoveObject += BigRegion.PermissionModule.CanMoveObject; //MAYBE FULLY IMPLEMENTED
835 VirtualRegion.Permissions.OnObjectEntry += BigRegion.PermissionModule.CanObjectEntry;
836 VirtualRegion.Permissions.OnReturnObjects += BigRegion.PermissionModule.CanReturnObjects; //NOT YET IMPLEMENTED
837 VirtualRegion.Permissions.OnRezObject += BigRegion.PermissionModule.CanRezObject; //MAYBE FULLY IMPLEMENTED
838 VirtualRegion.Permissions.OnRunConsoleCommand += BigRegion.PermissionModule.CanRunConsoleCommand;
839 VirtualRegion.Permissions.OnRunScript += BigRegion.PermissionModule.CanRunScript; //NOT YET IMPLEMENTED
840 VirtualRegion.Permissions.OnCompileScript += BigRegion.PermissionModule.CanCompileScript;
841 VirtualRegion.Permissions.OnSellParcel += BigRegion.PermissionModule.CanSellParcel;
842 VirtualRegion.Permissions.OnTakeObject += BigRegion.PermissionModule.CanTakeObject;
843 VirtualRegion.Permissions.OnTakeCopyObject += BigRegion.PermissionModule.CanTakeCopyObject;
844 VirtualRegion.Permissions.OnTerraformLand += BigRegion.PermissionModule.CanTerraformLand;
845 VirtualRegion.Permissions.OnLinkObject += BigRegion.PermissionModule.CanLinkObject; //NOT YET IMPLEMENTED
846 VirtualRegion.Permissions.OnDelinkObject += BigRegion.PermissionModule.CanDelinkObject; //NOT YET IMPLEMENTED
847 VirtualRegion.Permissions.OnBuyLand += BigRegion.PermissionModule.CanBuyLand; //NOT YET IMPLEMENTED
848 VirtualRegion.Permissions.OnViewNotecard += BigRegion.PermissionModule.CanViewNotecard; //NOT YET IMPLEMENTED
849 VirtualRegion.Permissions.OnViewScript += BigRegion.PermissionModule.CanViewScript; //NOT YET IMPLEMENTED
850 VirtualRegion.Permissions.OnEditNotecard += BigRegion.PermissionModule.CanEditNotecard; //NOT YET IMPLEMENTED
851 VirtualRegion.Permissions.OnEditScript += BigRegion.PermissionModule.CanEditScript; //NOT YET IMPLEMENTED
852 VirtualRegion.Permissions.OnCreateObjectInventory += BigRegion.PermissionModule.CanCreateObjectInventory; //NOT IMPLEMENTED HERE
853 VirtualRegion.Permissions.OnEditObjectInventory += BigRegion.PermissionModule.CanEditObjectInventory;//MAYBE FULLY IMPLEMENTED
854 VirtualRegion.Permissions.OnCopyObjectInventory += BigRegion.PermissionModule.CanCopyObjectInventory; //NOT YET IMPLEMENTED
855 VirtualRegion.Permissions.OnDeleteObjectInventory += BigRegion.PermissionModule.CanDeleteObjectInventory; //NOT YET IMPLEMENTED
856 VirtualRegion.Permissions.OnResetScript += BigRegion.PermissionModule.CanResetScript;
857 VirtualRegion.Permissions.OnCreateUserInventory += BigRegion.PermissionModule.CanCreateUserInventory; //NOT YET IMPLEMENTED
858 VirtualRegion.Permissions.OnCopyUserInventory += BigRegion.PermissionModule.CanCopyUserInventory; //NOT YET IMPLEMENTED
859 VirtualRegion.Permissions.OnEditUserInventory += BigRegion.PermissionModule.CanEditUserInventory; //NOT YET IMPLEMENTED
860 VirtualRegion.Permissions.OnDeleteUserInventory += BigRegion.PermissionModule.CanDeleteUserInventory; //NOT YET IMPLEMENTED
861 VirtualRegion.Permissions.OnTeleport += BigRegion.PermissionModule.CanTeleport; //NOT YET IMPLEMENTED
862 }
863
864 #region console commands
865
866 public void FixPhantoms(string module, string[] cmdparams)
867 {
868 List<Scene> scenes = new List<Scene>(m_startingScenes.Values);
869
870 foreach (Scene s in scenes)
871 {
872 MainConsole.Instance.OutputFormat("Fixing phantoms for {0}", s.RegionInfo.RegionName);
873
874 s.ForEachSOG(so => so.AbsolutePosition = so.AbsolutePosition);
875 }
876 }
877
878 #endregion
879 }
880}
diff --git a/OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCombinerPermissionModule.cs b/OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCombinerPermissionModule.cs
new file mode 100644
index 0000000..07dd68b
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCombinerPermissionModule.cs
@@ -0,0 +1,270 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using OpenMetaverse;
31using OpenSim.Framework;
32using OpenSim.Region.Framework.Interfaces;
33using OpenSim.Region.Framework.Scenes;
34
35namespace OpenSim.Region.RegionCombinerModule
36{
37 public class RegionCombinerPermissionModule
38 {
39 private Scene m_rootScene;
40
41 public RegionCombinerPermissionModule(Scene RootScene)
42 {
43 m_rootScene = RootScene;
44 }
45
46 #region Permission Override
47
48 public bool BypassPermissions()
49 {
50 return m_rootScene.Permissions.BypassPermissions();
51 }
52
53 public void SetBypassPermissions(bool value)
54 {
55 m_rootScene.Permissions.SetBypassPermissions(value);
56 }
57
58 public bool PropagatePermissions()
59 {
60 return m_rootScene.Permissions.PropagatePermissions();
61 }
62
63 public uint GenerateClientFlags(UUID userid, UUID objectidid)
64 {
65 return m_rootScene.Permissions.GenerateClientFlags(userid,objectidid);
66 }
67
68 public bool CanAbandonParcel(UUID user, ILandObject parcel, Scene scene)
69 {
70 return m_rootScene.Permissions.CanAbandonParcel(user,parcel);
71 }
72
73 public bool CanReclaimParcel(UUID user, ILandObject parcel, Scene scene)
74 {
75 return m_rootScene.Permissions.CanReclaimParcel(user, parcel);
76 }
77
78 public bool CanDeedParcel(UUID user, ILandObject parcel, Scene scene)
79 {
80 return m_rootScene.Permissions.CanDeedParcel(user, parcel);
81 }
82
83 public bool CanDeedObject(UUID user, UUID @group, Scene scene)
84 {
85 return m_rootScene.Permissions.CanDeedObject(user,@group);
86 }
87
88 public bool IsGod(UUID user, Scene requestfromscene)
89 {
90 return m_rootScene.Permissions.IsGod(user);
91 }
92
93 public bool CanDuplicateObject(int objectcount, UUID objectid, UUID owner, Scene scene, Vector3 objectposition)
94 {
95 return m_rootScene.Permissions.CanDuplicateObject(objectcount, objectid, owner, objectposition);
96 }
97
98 public bool CanDeleteObject(UUID objectid, UUID deleter, Scene scene)
99 {
100 return m_rootScene.Permissions.CanDeleteObject(objectid, deleter);
101 }
102
103 public bool CanEditObject(UUID objectid, UUID editorid, Scene scene)
104 {
105 return m_rootScene.Permissions.CanEditObject(objectid, editorid);
106 }
107
108 public bool CanEditParcelProperties(UUID user, ILandObject parcel, GroupPowers g, Scene scene)
109 {
110 return m_rootScene.Permissions.CanEditParcelProperties(user, parcel, g);
111 }
112
113 public bool CanInstantMessage(UUID user, UUID target, Scene startscene)
114 {
115 return m_rootScene.Permissions.CanInstantMessage(user, target);
116 }
117
118 public bool CanInventoryTransfer(UUID user, UUID target, Scene startscene)
119 {
120 return m_rootScene.Permissions.CanInventoryTransfer(user, target);
121 }
122
123 public bool CanIssueEstateCommand(UUID user, Scene requestfromscene, bool ownercommand)
124 {
125 return m_rootScene.Permissions.CanIssueEstateCommand(user, ownercommand);
126 }
127
128 public bool CanMoveObject(UUID objectid, UUID moverid, Scene scene)
129 {
130 return m_rootScene.Permissions.CanMoveObject(objectid, moverid);
131 }
132
133 public bool CanObjectEntry(UUID objectid, bool enteringregion, Vector3 newpoint, Scene scene)
134 {
135 return m_rootScene.Permissions.CanObjectEntry(objectid, enteringregion, newpoint);
136 }
137
138 public bool CanReturnObjects(ILandObject land, UUID user, List<SceneObjectGroup> objects, Scene scene)
139 {
140 return m_rootScene.Permissions.CanReturnObjects(land, user, objects);
141 }
142
143 public bool CanRezObject(int objectcount, UUID owner, Vector3 objectposition, Scene scene)
144 {
145 return m_rootScene.Permissions.CanRezObject(objectcount, owner, objectposition);
146 }
147
148 public bool CanRunConsoleCommand(UUID user, Scene requestfromscene)
149 {
150 return m_rootScene.Permissions.CanRunConsoleCommand(user);
151 }
152
153 public bool CanRunScript(UUID script, UUID objectid, UUID user, Scene scene)
154 {
155 return m_rootScene.Permissions.CanRunScript(script, objectid, user);
156 }
157
158 public bool CanCompileScript(UUID owneruuid, int scripttype, Scene scene)
159 {
160 return m_rootScene.Permissions.CanCompileScript(owneruuid, scripttype);
161 }
162
163 public bool CanSellParcel(UUID user, ILandObject parcel, Scene scene)
164 {
165 return m_rootScene.Permissions.CanSellParcel(user, parcel);
166 }
167
168 public bool CanTakeObject(UUID objectid, UUID stealer, Scene scene)
169 {
170 return m_rootScene.Permissions.CanTakeObject(objectid, stealer);
171 }
172
173 public bool CanTakeCopyObject(UUID objectid, UUID userid, Scene inscene)
174 {
175 return m_rootScene.Permissions.CanTakeObject(objectid, userid);
176 }
177
178 public bool CanTerraformLand(UUID user, Vector3 position, Scene requestfromscene)
179 {
180 return m_rootScene.Permissions.CanTerraformLand(user, position);
181 }
182
183 public bool CanLinkObject(UUID user, UUID objectid)
184 {
185 return m_rootScene.Permissions.CanLinkObject(user, objectid);
186 }
187
188 public bool CanDelinkObject(UUID user, UUID objectid)
189 {
190 return m_rootScene.Permissions.CanDelinkObject(user, objectid);
191 }
192
193 public bool CanBuyLand(UUID user, ILandObject parcel, Scene scene)
194 {
195 return m_rootScene.Permissions.CanBuyLand(user, parcel);
196 }
197
198 public bool CanViewNotecard(UUID script, UUID objectid, UUID user, Scene scene)
199 {
200 return m_rootScene.Permissions.CanViewNotecard(script, objectid, user);
201 }
202
203 public bool CanViewScript(UUID script, UUID objectid, UUID user, Scene scene)
204 {
205 return m_rootScene.Permissions.CanViewScript(script, objectid, user);
206 }
207
208 public bool CanEditNotecard(UUID notecard, UUID objectid, UUID user, Scene scene)
209 {
210 return m_rootScene.Permissions.CanEditNotecard(notecard, objectid, user);
211 }
212
213 public bool CanEditScript(UUID script, UUID objectid, UUID user, Scene scene)
214 {
215 return m_rootScene.Permissions.CanEditScript(script, objectid, user);
216 }
217
218 public bool CanCreateObjectInventory(int invtype, UUID objectid, UUID userid)
219 {
220 return m_rootScene.Permissions.CanCreateObjectInventory(invtype, objectid, userid);
221 }
222
223 public bool CanEditObjectInventory(UUID objectid, UUID editorid, Scene scene)
224 {
225 return m_rootScene.Permissions.CanEditObjectInventory(objectid, editorid);
226 }
227
228 public bool CanCopyObjectInventory(UUID itemid, UUID objectid, UUID userid)
229 {
230 return m_rootScene.Permissions.CanCopyObjectInventory(itemid, objectid, userid);
231 }
232
233 public bool CanDeleteObjectInventory(UUID itemid, UUID objectid, UUID userid)
234 {
235 return m_rootScene.Permissions.CanDeleteObjectInventory(itemid, objectid, userid);
236 }
237
238 public bool CanResetScript(UUID prim, UUID script, UUID user, Scene scene)
239 {
240 return m_rootScene.Permissions.CanResetScript(prim, script, user);
241 }
242
243 public bool CanCreateUserInventory(int invtype, UUID userid)
244 {
245 return m_rootScene.Permissions.CanCreateUserInventory(invtype, userid);
246 }
247
248 public bool CanCopyUserInventory(UUID itemid, UUID userid)
249 {
250 return m_rootScene.Permissions.CanCopyUserInventory(itemid, userid);
251 }
252
253 public bool CanEditUserInventory(UUID itemid, UUID userid)
254 {
255 return m_rootScene.Permissions.CanEditUserInventory(itemid, userid);
256 }
257
258 public bool CanDeleteUserInventory(UUID itemid, UUID userid)
259 {
260 return m_rootScene.Permissions.CanDeleteUserInventory(itemid, userid);
261 }
262
263 public bool CanTeleport(UUID userid, Scene scene)
264 {
265 return m_rootScene.Permissions.CanTeleport(userid);
266 }
267
268 #endregion
269 }
270}
diff --git a/OpenSim/Region/OptionalModules/RegionCombinerModule/RegionConnections.cs b/OpenSim/Region/OptionalModules/RegionCombinerModule/RegionConnections.cs
new file mode 100644
index 0000000..62a3a91
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/RegionCombinerModule/RegionConnections.cs
@@ -0,0 +1,94 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using OpenMetaverse;
31using OpenSim.Framework;
32using OpenSim.Region.Framework.Interfaces;
33using OpenSim.Region.Framework.Scenes;
34
35namespace OpenSim.Region.RegionCombinerModule
36{
37 public class RegionConnections
38 {
39 /// <summary>
40 /// Root Region ID
41 /// </summary>
42 public UUID RegionId;
43
44 /// <summary>
45 /// Root Region Scene
46 /// </summary>
47 public Scene RegionScene;
48
49 /// <summary>
50 /// LargeLandChannel for combined region
51 /// </summary>
52 public ILandChannel RegionLandChannel;
53
54 /// <summary>
55 /// The x map co-ordinate for this region (where each co-ordinate is a Constants.RegionSize block).
56 /// </summary>
57 public uint X;
58
59 /// <summary>
60 /// The y co-ordinate for this region (where each cor-odinate is a Constants.RegionSize block).
61 /// </summary>
62 public uint Y;
63
64 /// <summary>
65 /// The X meters position of this connection.
66 /// </summary>
67 public uint PosX { get { return Util.RegionToWorldLoc(X); } }
68
69 /// <summary>
70 /// The Y meters co-ordinate of this connection.
71 /// </summary>
72 public uint PosY { get { return Util.RegionToWorldLoc(Y); } }
73
74 /// <summary>
75 /// The size of the megaregion in meters.
76 /// </summary>
77 public uint XEnd;
78
79 /// <summary>
80 /// The size of the megaregion in meters.
81 /// </summary>
82 public uint YEnd;
83
84 public List<RegionData> ConnectedRegions;
85 public RegionCombinerPermissionModule PermissionModule;
86 public RegionCombinerClientEventForwarder ClientEventForwarder;
87
88 public void UpdateExtents(Vector3 extents)
89 {
90 XEnd = (uint)extents.X;
91 YEnd = (uint)extents.Y;
92 }
93 }
94} \ No newline at end of file
diff --git a/OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCourseLocation.cs b/OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCourseLocation.cs
new file mode 100644
index 0000000..224ac99
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCourseLocation.cs
@@ -0,0 +1,43 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using OpenMetaverse;
31using OpenSim.Framework;
32
33namespace OpenSim.Region.RegionCombinerModule
34{
35
36 struct RegionCoarseLocationStruct
37 {
38 public List<Vector3> Locations;
39 public List<UUID> Uuids;
40 public IClientAPI UserAPI;
41 public Vector2 Offset;
42 }
43} \ No newline at end of file
diff --git a/OpenSim/Region/OptionalModules/RegionCombinerModule/RegionData.cs b/OpenSim/Region/OptionalModules/RegionCombinerModule/RegionData.cs
new file mode 100644
index 0000000..42fca9f
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/RegionCombinerModule/RegionData.cs
@@ -0,0 +1,40 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using OpenMetaverse;
29using OpenSim.Region.Framework.Scenes;
30
31namespace OpenSim.Region.RegionCombinerModule
32{
33 public class RegionData
34 {
35 public UUID RegionId;
36 public Scene RegionScene;
37 // Offset of this region from the base of the root region.
38 public Vector3 Offset;
39 }
40} \ No newline at end of file
diff --git a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStore.cs b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStore.cs
index 34894ba..c38bb3e 100644
--- a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStore.cs
+++ b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStore.cs
@@ -49,7 +49,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
49 private static readonly ILog m_log = 49 private static readonly ILog m_log =
50 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 50 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
51 51
52 private OSD m_ValueStore; 52 protected virtual OSD ValueStore { get; set; }
53 53
54 protected class TakeValueCallbackClass 54 protected class TakeValueCallbackClass
55 { 55 {
@@ -68,42 +68,141 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
68 protected List<TakeValueCallbackClass> m_TakeStore; 68 protected List<TakeValueCallbackClass> m_TakeStore;
69 protected List<TakeValueCallbackClass> m_ReadStore; 69 protected List<TakeValueCallbackClass> m_ReadStore;
70 70
71 // add separators for quoted paths and array references
72 protected static Regex m_ParsePassOne = new Regex("({[^}]+}|\\[[0-9]+\\]|\\[\\+\\])");
71 73
74 // add quotes to bare identifiers which are limited to alphabetic characters
75 protected static Regex m_ParsePassThree = new Regex("(?<!{[^}]*)\\.([a-zA-Z]+)(?=\\.)");
76
77 // remove extra separator characters
78 protected static Regex m_ParsePassFour = new Regex("\\.+");
79
80 // expression used to validate the full path, this is canonical representation
81 protected static Regex m_ValidatePath = new Regex("^\\.(({[^}]+}|\\[[0-9]+\\]|\\[\\+\\])\\.)*$");
82
83 // expression used to match path components
84 protected static Regex m_PathComponent = new Regex("\\.({[^}]+}|\\[[0-9]+\\]|\\[\\+\\])");
85
86 // extract the internals of an array reference
87 protected static Regex m_SimpleArrayPattern = new Regex("^\\[([0-9]+)\\]$");
88 protected static Regex m_ArrayPattern = new Regex("^\\[([0-9]+|\\+)\\]$");
89
90 // extract the internals of a has reference
91 protected static Regex m_HashPattern = new Regex("^{([^}]+)}$");
92
93 // -----------------------------------------------------------------
94 /// <summary>
95 /// This is a simple estimator for the size of the stored data, it
96 /// is not precise, but should be close enough to implement reasonable
97 /// limits on the storage space used
98 /// </summary>
99 // -----------------------------------------------------------------
100 public int StringSpace { get; set; }
101
72 // ----------------------------------------------------------------- 102 // -----------------------------------------------------------------
73 /// <summary> 103 /// <summary>
74 /// 104 ///
75 /// </summary> 105 /// </summary>
76 // ----------------------------------------------------------------- 106 // -----------------------------------------------------------------
77 public JsonStore() : this("") {} 107 public static bool CanonicalPathExpression(string ipath, out string opath)
108 {
109 Stack<string> path;
110 if (! ParsePathExpression(ipath,out path))
111 {
112 opath = "";
113 return false;
114 }
115
116 opath = PathExpressionToKey(path);
117 return true;
118 }
78 119
79 public JsonStore(string value) 120 // -----------------------------------------------------------------
121 /// <summary>
122 ///
123 /// </summary>
124 // -----------------------------------------------------------------
125 public JsonStore()
80 { 126 {
127 StringSpace = 0;
81 m_TakeStore = new List<TakeValueCallbackClass>(); 128 m_TakeStore = new List<TakeValueCallbackClass>();
82 m_ReadStore = new List<TakeValueCallbackClass>(); 129 m_ReadStore = new List<TakeValueCallbackClass>();
83 130 }
131
132 public JsonStore(string value) : this()
133 {
134 // This is going to throw an exception if the value is not
135 // a valid JSON chunk. Calling routines should catch the
136 // exception and handle it appropriately
84 if (String.IsNullOrEmpty(value)) 137 if (String.IsNullOrEmpty(value))
85 m_ValueStore = new OSDMap(); 138 ValueStore = new OSDMap();
86 else 139 else
87 m_ValueStore = OSDParser.DeserializeJson(value); 140 ValueStore = OSDParser.DeserializeJson(value);
88 } 141 }
142
143 // -----------------------------------------------------------------
144 /// <summary>
145 ///
146 /// </summary>
147 // -----------------------------------------------------------------
148 public JsonStoreNodeType GetNodeType(string expr)
149 {
150 Stack<string> path;
151 if (! ParsePathExpression(expr,out path))
152 return JsonStoreNodeType.Undefined;
153
154 OSD result = ProcessPathExpression(ValueStore,path);
89 155
156 if (result == null)
157 return JsonStoreNodeType.Undefined;
158
159 if (result is OSDMap)
160 return JsonStoreNodeType.Object;
161
162 if (result is OSDArray)
163 return JsonStoreNodeType.Array;
164
165 if (OSDBaseType(result.Type))
166 return JsonStoreNodeType.Value;
167
168 return JsonStoreNodeType.Undefined;
169 }
170
90 // ----------------------------------------------------------------- 171 // -----------------------------------------------------------------
91 /// <summary> 172 /// <summary>
92 /// 173 ///
93 /// </summary> 174 /// </summary>
94 // ----------------------------------------------------------------- 175 // -----------------------------------------------------------------
95 public bool TestPath(string expr, bool useJson) 176 public JsonStoreValueType GetValueType(string expr)
96 { 177 {
97 Stack<string> path = ParsePathExpression(expr); 178 Stack<string> path;
98 OSD result = ProcessPathExpression(m_ValueStore,path); 179 if (! ParsePathExpression(expr,out path))
180 return JsonStoreValueType.Undefined;
181
182 OSD result = ProcessPathExpression(ValueStore,path);
99 183
100 if (result == null) 184 if (result == null)
101 return false; 185 return JsonStoreValueType.Undefined;
102 186
103 if (useJson || result.Type == OSDType.String) 187 if (result is OSDMap)
104 return true; 188 return JsonStoreValueType.Undefined;
105 189
106 return false; 190 if (result is OSDArray)
191 return JsonStoreValueType.Undefined;
192
193 if (result is OSDBoolean)
194 return JsonStoreValueType.Boolean;
195
196 if (result is OSDInteger)
197 return JsonStoreValueType.Integer;
198
199 if (result is OSDReal)
200 return JsonStoreValueType.Float;
201
202 if (result is OSDString)
203 return JsonStoreValueType.String;
204
205 return JsonStoreValueType.Undefined;
107 } 206 }
108 207
109 // ----------------------------------------------------------------- 208 // -----------------------------------------------------------------
@@ -111,10 +210,37 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
111 /// 210 ///
112 /// </summary> 211 /// </summary>
113 // ----------------------------------------------------------------- 212 // -----------------------------------------------------------------
213 public int ArrayLength(string expr)
214 {
215 Stack<string> path;
216 if (! ParsePathExpression(expr,out path))
217 return -1;
218
219 OSD result = ProcessPathExpression(ValueStore,path);
220 if (result != null && result.Type == OSDType.Array)
221 {
222 OSDArray arr = result as OSDArray;
223 return arr.Count;
224 }
225
226 return -1;
227 }
228
229 // -----------------------------------------------------------------
230 /// <summary>
231 ///
232 /// </summary>
233 // -----------------------------------------------------------------
114 public bool GetValue(string expr, out string value, bool useJson) 234 public bool GetValue(string expr, out string value, bool useJson)
115 { 235 {
116 Stack<string> path = ParsePathExpression(expr); 236 Stack<string> path;
117 OSD result = ProcessPathExpression(m_ValueStore,path); 237 if (! ParsePathExpression(expr,out path))
238 {
239 value = "";
240 return false;
241 }
242
243 OSD result = ProcessPathExpression(ValueStore,path);
118 return ConvertOutputValue(result,out value,useJson); 244 return ConvertOutputValue(result,out value,useJson);
119 } 245 }
120 246
@@ -136,7 +262,37 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
136 // ----------------------------------------------------------------- 262 // -----------------------------------------------------------------
137 public bool SetValue(string expr, string value, bool useJson) 263 public bool SetValue(string expr, string value, bool useJson)
138 { 264 {
139 OSD ovalue = useJson ? OSDParser.DeserializeJson(value) : new OSDString(value); 265 OSD ovalue;
266
267 // One note of caution... if you use an empty string in the
268 // structure it will be assumed to be a default value and will
269 // not be seialized in the json
270
271 if (useJson)
272 {
273 // There doesn't appear to be a good way to determine if the
274 // value is valid Json other than to let the parser crash
275 try
276 {
277 ovalue = OSDParser.DeserializeJson(value);
278 }
279 catch (Exception)
280 {
281 if (value.StartsWith("'") && value.EndsWith("'"))
282 {
283 ovalue = new OSDString(value.Substring(1,value.Length - 2));
284 }
285 else
286 {
287 return false;
288 }
289 }
290 }
291 else
292 {
293 ovalue = new OSDString(value);
294 }
295
140 return SetValueFromExpression(expr,ovalue); 296 return SetValueFromExpression(expr,ovalue);
141 } 297 }
142 298
@@ -147,10 +303,13 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
147 // ----------------------------------------------------------------- 303 // -----------------------------------------------------------------
148 public bool TakeValue(string expr, bool useJson, TakeValueCallback cback) 304 public bool TakeValue(string expr, bool useJson, TakeValueCallback cback)
149 { 305 {
150 Stack<string> path = ParsePathExpression(expr); 306 Stack<string> path;
307 if (! ParsePathExpression(expr,out path))
308 return false;
309
151 string pexpr = PathExpressionToKey(path); 310 string pexpr = PathExpressionToKey(path);
152 311
153 OSD result = ProcessPathExpression(m_ValueStore,path); 312 OSD result = ProcessPathExpression(ValueStore,path);
154 if (result == null) 313 if (result == null)
155 { 314 {
156 m_TakeStore.Add(new TakeValueCallbackClass(pexpr,useJson,cback)); 315 m_TakeStore.Add(new TakeValueCallbackClass(pexpr,useJson,cback));
@@ -178,10 +337,13 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
178 // ----------------------------------------------------------------- 337 // -----------------------------------------------------------------
179 public bool ReadValue(string expr, bool useJson, TakeValueCallback cback) 338 public bool ReadValue(string expr, bool useJson, TakeValueCallback cback)
180 { 339 {
181 Stack<string> path = ParsePathExpression(expr); 340 Stack<string> path;
341 if (! ParsePathExpression(expr,out path))
342 return false;
343
182 string pexpr = PathExpressionToKey(path); 344 string pexpr = PathExpressionToKey(path);
183 345
184 OSD result = ProcessPathExpression(m_ValueStore,path); 346 OSD result = ProcessPathExpression(ValueStore,path);
185 if (result == null) 347 if (result == null)
186 { 348 {
187 m_ReadStore.Add(new TakeValueCallbackClass(pexpr,useJson,cback)); 349 m_ReadStore.Add(new TakeValueCallbackClass(pexpr,useJson,cback));
@@ -208,25 +370,30 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
208 // ----------------------------------------------------------------- 370 // -----------------------------------------------------------------
209 protected bool SetValueFromExpression(string expr, OSD ovalue) 371 protected bool SetValueFromExpression(string expr, OSD ovalue)
210 { 372 {
211 Stack<string> path = ParsePathExpression(expr); 373 Stack<string> path;
374 if (! ParsePathExpression(expr,out path))
375 return false;
376
212 if (path.Count == 0) 377 if (path.Count == 0)
213 { 378 {
214 m_ValueStore = ovalue; 379 ValueStore = ovalue;
380 StringSpace = 0;
215 return true; 381 return true;
216 } 382 }
217 383
384 // pkey will be the final element in the path, we pull it out here to make sure
385 // that the assignment works correctly
218 string pkey = path.Pop(); 386 string pkey = path.Pop();
219 string pexpr = PathExpressionToKey(path); 387 string pexpr = PathExpressionToKey(path);
220 if (pexpr != "") 388 if (pexpr != "")
221 pexpr += "."; 389 pexpr += ".";
222 390
223 OSD result = ProcessPathExpression(m_ValueStore,path); 391 OSD result = ProcessPathExpression(ValueStore,path);
224 if (result == null) 392 if (result == null)
225 return false; 393 return false;
226 394
227 Regex aPattern = new Regex("\\[([0-9]+|\\+)\\]"); 395 // Check pkey, the last element in the path, for and extract array references
228 MatchCollection amatches = aPattern.Matches(pkey,0); 396 MatchCollection amatches = m_ArrayPattern.Matches(pkey,0);
229
230 if (amatches.Count > 0) 397 if (amatches.Count > 0)
231 { 398 {
232 if (result.Type != OSDType.Array) 399 if (result.Type != OSDType.Array)
@@ -242,8 +409,13 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
242 { 409 {
243 string npkey = String.Format("[{0}]",amap.Count); 410 string npkey = String.Format("[{0}]",amap.Count);
244 411
245 amap.Add(ovalue); 412 if (ovalue != null)
246 InvokeNextCallback(pexpr + npkey); 413 {
414 StringSpace += ComputeSizeOf(ovalue);
415
416 amap.Add(ovalue);
417 InvokeNextCallback(pexpr + npkey);
418 }
247 return true; 419 return true;
248 } 420 }
249 421
@@ -251,9 +423,14 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
251 if (0 <= aval && aval < amap.Count) 423 if (0 <= aval && aval < amap.Count)
252 { 424 {
253 if (ovalue == null) 425 if (ovalue == null)
426 {
427 StringSpace -= ComputeSizeOf(amap[aval]);
254 amap.RemoveAt(aval); 428 amap.RemoveAt(aval);
429 }
255 else 430 else
256 { 431 {
432 StringSpace -= ComputeSizeOf(amap[aval]);
433 StringSpace += ComputeSizeOf(ovalue);
257 amap[aval] = ovalue; 434 amap[aval] = ovalue;
258 InvokeNextCallback(pexpr + pkey); 435 InvokeNextCallback(pexpr + pkey);
259 } 436 }
@@ -263,9 +440,8 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
263 return false; 440 return false;
264 } 441 }
265 442
266 Regex hPattern = new Regex("{([^}]+)}"); 443 // Check for and extract hash references
267 MatchCollection hmatches = hPattern.Matches(pkey,0); 444 MatchCollection hmatches = m_HashPattern.Matches(pkey,0);
268
269 if (hmatches.Count > 0) 445 if (hmatches.Count > 0)
270 { 446 {
271 Match match = hmatches[0]; 447 Match match = hmatches[0];
@@ -274,16 +450,27 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
274 450
275 if (result is OSDMap) 451 if (result is OSDMap)
276 { 452 {
453 // this is the assignment case
277 OSDMap hmap = result as OSDMap; 454 OSDMap hmap = result as OSDMap;
278 if (ovalue != null) 455 if (ovalue != null)
279 { 456 {
457 StringSpace -= ComputeSizeOf(hmap[hkey]);
458 StringSpace += ComputeSizeOf(ovalue);
459
280 hmap[hkey] = ovalue; 460 hmap[hkey] = ovalue;
281 InvokeNextCallback(pexpr + pkey); 461 InvokeNextCallback(pexpr + pkey);
462 return true;
282 } 463 }
283 else if (hmap.ContainsKey(hkey)) 464
465 // this is the remove case
466 if (hmap.ContainsKey(hkey))
467 {
468 StringSpace -= ComputeSizeOf(hmap[hkey]);
284 hmap.Remove(hkey); 469 hmap.Remove(hkey);
285 470 return true;
286 return true; 471 }
472
473 return false;
287 } 474 }
288 475
289 return false; 476 return false;
@@ -332,39 +519,33 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
332 /// use a stack because we process the path in inverse order later 519 /// use a stack because we process the path in inverse order later
333 /// </summary> 520 /// </summary>
334 // ----------------------------------------------------------------- 521 // -----------------------------------------------------------------
335 protected static Stack<string> ParsePathExpression(string path) 522 protected static bool ParsePathExpression(string expr, out Stack<string> path)
336 { 523 {
337 Stack<string> m_path = new Stack<string>(); 524 path = new Stack<string>();
338 525
339 // add front and rear separators 526 // add front and rear separators
340 path = "." + path + "."; 527 expr = "." + expr + ".";
341 528
342 // add separators for quoted paths 529 // add separators for quoted exprs and array references
343 Regex pass1 = new Regex("{[^}]+}"); 530 expr = m_ParsePassOne.Replace(expr,".$1.",-1,0);
344 path = pass1.Replace(path,".$0.",-1,0);
345
346 // add separators for array references
347 Regex pass2 = new Regex("(\\[[0-9]+\\]|\\[\\+\\])");
348 path = pass2.Replace(path,".$0.",-1,0);
349 531
350 // add quotes to bare identifier 532 // add quotes to bare identifier
351 Regex pass3 = new Regex("\\.([a-zA-Z]+)"); 533 expr = m_ParsePassThree.Replace(expr,".{$1}",-1,0);
352 path = pass3.Replace(path,".{$1}",-1,0);
353 534
354 // remove extra separators 535 // remove extra separators
355 Regex pass4 = new Regex("\\.+"); 536 expr = m_ParsePassFour.Replace(expr,".",-1,0);
356 path = pass4.Replace(path,".",-1,0);
357 537
358 Regex validate = new Regex("^\\.(({[^}]+}|\\[[0-9]+\\]|\\[\\+\\])\\.)+$"); 538 // validate the results (catches extra quote characters for example)
359 if (validate.IsMatch(path)) 539 if (m_ValidatePath.IsMatch(expr))
360 { 540 {
361 Regex parser = new Regex("\\.({[^}]+}|\\[[0-9]+\\]|\\[\\+\\]+)"); 541 MatchCollection matches = m_PathComponent.Matches(expr,0);
362 MatchCollection matches = parser.Matches(path,0);
363 foreach (Match match in matches) 542 foreach (Match match in matches)
364 m_path.Push(match.Groups[1].Value); 543 path.Push(match.Groups[1].Value);
544
545 return true;
365 } 546 }
366 547
367 return m_path; 548 return false;
368 } 549 }
369 550
370 // ----------------------------------------------------------------- 551 // -----------------------------------------------------------------
@@ -385,9 +566,8 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
385 return null; 566 return null;
386 567
387 // ---------- Check for an array index ---------- 568 // ---------- Check for an array index ----------
388 Regex aPattern = new Regex("\\[([0-9]+)\\]"); 569 MatchCollection amatches = m_SimpleArrayPattern.Matches(pkey,0);
389 MatchCollection amatches = aPattern.Matches(pkey,0); 570
390
391 if (amatches.Count > 0) 571 if (amatches.Count > 0)
392 { 572 {
393 if (rmap.Type != OSDType.Array) 573 if (rmap.Type != OSDType.Array)
@@ -410,9 +590,8 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
410 } 590 }
411 591
412 // ---------- Check for a hash index ---------- 592 // ---------- Check for a hash index ----------
413 Regex hPattern = new Regex("{([^}]+)}"); 593 MatchCollection hmatches = m_HashPattern.Matches(pkey,0);
414 MatchCollection hmatches = hPattern.Matches(pkey,0); 594
415
416 if (hmatches.Count > 0) 595 if (hmatches.Count > 0)
417 { 596 {
418 if (rmap.Type != OSDType.Map) 597 if (rmap.Type != OSDType.Map)
@@ -456,14 +635,14 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
456 // The path pointed to an intermediate hash structure 635 // The path pointed to an intermediate hash structure
457 if (result.Type == OSDType.Map) 636 if (result.Type == OSDType.Map)
458 { 637 {
459 value = OSDParser.SerializeJsonString(result as OSDMap); 638 value = OSDParser.SerializeJsonString(result as OSDMap,true);
460 return true; 639 return true;
461 } 640 }
462 641
463 // The path pointed to an intermediate hash structure 642 // The path pointed to an intermediate hash structure
464 if (result.Type == OSDType.Array) 643 if (result.Type == OSDType.Array)
465 { 644 {
466 value = OSDParser.SerializeJsonString(result as OSDArray); 645 value = OSDParser.SerializeJsonString(result as OSDArray,true);
467 return true; 646 return true;
468 } 647 }
469 648
@@ -471,7 +650,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
471 return true; 650 return true;
472 } 651 }
473 652
474 if (result.Type == OSDType.String) 653 if (OSDBaseType(result.Type))
475 { 654 {
476 value = result.AsString(); 655 value = result.AsString();
477 return true; 656 return true;
@@ -496,5 +675,91 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
496 675
497 return pkey; 676 return pkey;
498 } 677 }
678
679 // -----------------------------------------------------------------
680 /// <summary>
681 ///
682 /// </summary>
683 // -----------------------------------------------------------------
684 protected static bool OSDBaseType(OSDType type)
685 {
686 // Should be the list of base types for which AsString() returns
687 // something useful
688 if (type == OSDType.Boolean)
689 return true;
690 if (type == OSDType.Integer)
691 return true;
692 if (type == OSDType.Real)
693 return true;
694 if (type == OSDType.String)
695 return true;
696 if (type == OSDType.UUID)
697 return true;
698 if (type == OSDType.Date)
699 return true;
700 if (type == OSDType.URI)
701 return true;
702
703 return false;
704 }
705
706 // -----------------------------------------------------------------
707 /// <summary>
708 ///
709 /// </summary>
710 // -----------------------------------------------------------------
711 protected static int ComputeSizeOf(OSD value)
712 {
713 string sval;
714
715 if (ConvertOutputValue(value,out sval,true))
716 return sval.Length;
717
718 return 0;
719 }
720 }
721
722 // -----------------------------------------------------------------
723 /// <summary>
724 /// </summary>
725 // -----------------------------------------------------------------
726 public class JsonObjectStore : JsonStore
727 {
728 private static readonly ILog m_log =
729 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
730
731 private Scene m_scene;
732 private UUID m_objectID;
733
734 protected override OSD ValueStore
735 {
736 get
737 {
738 SceneObjectPart sop = m_scene.GetSceneObjectPart(m_objectID);
739 if (sop == null)
740 {
741 // This is bad
742 return null;
743 }
744
745 return sop.DynAttrs.TopLevelMap;
746 }
747
748 // cannot set the top level
749 set
750 {
751 m_log.InfoFormat("[JsonStore] cannot set top level value in object store");
752 }
753 }
754
755 public JsonObjectStore(Scene scene, UUID oid) : base()
756 {
757 m_scene = scene;
758 m_objectID = oid;
759
760 // the size limit is imposed on whatever is already in the store
761 StringSpace = ComputeSizeOf(ValueStore);
762 }
499 } 763 }
764
500} 765}
diff --git a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreCommands.cs b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreCommands.cs
new file mode 100644
index 0000000..d4b19dd
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreCommands.cs
@@ -0,0 +1,195 @@
1/*
2 * Copyright (c) Contributors
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 OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using Mono.Addins;
28
29using System;
30using System.Reflection;
31using System.Threading;
32using System.Text;
33using System.Net;
34using System.Net.Sockets;
35using log4net;
36using Nini.Config;
37using OpenMetaverse;
38using OpenMetaverse.StructuredData;
39using OpenSim.Framework;
40using OpenSim.Region.Framework.Interfaces;
41using OpenSim.Region.Framework.Scenes;
42using System.Collections.Generic;
43using System.Text.RegularExpressions;
44
45namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
46{
47 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "JsonStoreCommandsModule")]
48
49 public class JsonStoreCommandsModule : INonSharedRegionModule
50 {
51 private static readonly ILog m_log =
52 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
53
54 private IConfig m_config = null;
55 private bool m_enabled = false;
56
57 private Scene m_scene = null;
58 //private IJsonStoreModule m_store;
59 private JsonStoreModule m_store;
60
61#region Region Module interface
62
63 // -----------------------------------------------------------------
64 /// <summary>
65 /// Name of this shared module is it's class name
66 /// </summary>
67 // -----------------------------------------------------------------
68 public string Name
69 {
70 get { return this.GetType().Name; }
71 }
72
73 // -----------------------------------------------------------------
74 /// <summary>
75 /// Initialise this shared module
76 /// </summary>
77 /// <param name="scene">this region is getting initialised</param>
78 /// <param name="source">nini config, we are not using this</param>
79 // -----------------------------------------------------------------
80 public void Initialise(IConfigSource config)
81 {
82 try
83 {
84 if ((m_config = config.Configs["JsonStore"]) == null)
85 {
86 // There is no configuration, the module is disabled
87 // m_log.InfoFormat("[JsonStore] no configuration info");
88 return;
89 }
90
91 m_enabled = m_config.GetBoolean("Enabled", m_enabled);
92 }
93 catch (Exception e)
94 {
95 m_log.Error("[JsonStore]: initialization error: {0}", e);
96 return;
97 }
98
99 if (m_enabled)
100 m_log.DebugFormat("[JsonStore]: module is enabled");
101 }
102
103 // -----------------------------------------------------------------
104 /// <summary>
105 /// everything is loaded, perform post load configuration
106 /// </summary>
107 // -----------------------------------------------------------------
108 public void PostInitialise()
109 {
110 }
111
112 // -----------------------------------------------------------------
113 /// <summary>
114 /// Nothing to do on close
115 /// </summary>
116 // -----------------------------------------------------------------
117 public void Close()
118 {
119 }
120
121 // -----------------------------------------------------------------
122 /// <summary>
123 /// </summary>
124 // -----------------------------------------------------------------
125 public void AddRegion(Scene scene)
126 {
127 if (m_enabled)
128 {
129 m_scene = scene;
130
131 }
132 }
133
134 // -----------------------------------------------------------------
135 /// <summary>
136 /// </summary>
137 // -----------------------------------------------------------------
138 public void RemoveRegion(Scene scene)
139 {
140 // need to remove all references to the scene in the subscription
141 // list to enable full garbage collection of the scene object
142 }
143
144 // -----------------------------------------------------------------
145 /// <summary>
146 /// Called when all modules have been added for a region. This is
147 /// where we hook up events
148 /// </summary>
149 // -----------------------------------------------------------------
150 public void RegionLoaded(Scene scene)
151 {
152 if (m_enabled)
153 {
154 m_scene = scene;
155
156 m_store = (JsonStoreModule) m_scene.RequestModuleInterface<IJsonStoreModule>();
157 if (m_store == null)
158 {
159 m_log.ErrorFormat("[JsonStoreCommands]: JsonModule interface not defined");
160 m_enabled = false;
161 return;
162 }
163
164 scene.AddCommand("JsonStore", this, "jsonstore stats", "jsonstore stats",
165 "Display statistics about the state of the JsonStore module", "",
166 CmdStats);
167 }
168 }
169
170 /// -----------------------------------------------------------------
171 /// <summary>
172 /// </summary>
173 // -----------------------------------------------------------------
174 public Type ReplaceableInterface
175 {
176 get { return null; }
177 }
178
179#endregion
180
181#region Commands
182
183 private void CmdStats(string module, string[] cmd)
184 {
185 if (MainConsole.Instance.ConsoleScene != m_scene && MainConsole.Instance.ConsoleScene != null)
186 return;
187
188 JsonStoreStats stats = m_store.GetStoreStats();
189 MainConsole.Instance.OutputFormat("{0}\t{1}",m_scene.RegionInfo.RegionName,stats.StoreCount);
190 }
191
192#endregion
193
194 }
195}
diff --git a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs
index e68764a..26044f0 100644
--- a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs
+++ b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs
@@ -42,7 +42,6 @@ using OpenSim.Region.Framework.Scenes;
42using System.Collections.Generic; 42using System.Collections.Generic;
43using System.Text.RegularExpressions; 43using System.Text.RegularExpressions;
44 44
45
46namespace OpenSim.Region.OptionalModules.Scripting.JsonStore 45namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
47{ 46{
48 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "JsonStoreModule")] 47 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "JsonStoreModule")]
@@ -54,9 +53,13 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
54 53
55 private IConfig m_config = null; 54 private IConfig m_config = null;
56 private bool m_enabled = false; 55 private bool m_enabled = false;
56 private bool m_enableObjectStore = false;
57 private int m_maxStringSpace = Int32.MaxValue;
58
57 private Scene m_scene = null; 59 private Scene m_scene = null;
58 60
59 private Dictionary<UUID,JsonStore> m_JsonValueStore; 61 private Dictionary<UUID,JsonStore> m_JsonValueStore;
62
60 private UUID m_sharedStore; 63 private UUID m_sharedStore;
61 64
62#region Region Module interface 65#region Region Module interface
@@ -90,15 +93,19 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
90 } 93 }
91 94
92 m_enabled = m_config.GetBoolean("Enabled", m_enabled); 95 m_enabled = m_config.GetBoolean("Enabled", m_enabled);
96 m_enableObjectStore = m_config.GetBoolean("EnableObjectStore", m_enableObjectStore);
97 m_maxStringSpace = m_config.GetInt("MaxStringSpace", m_maxStringSpace);
98 if (m_maxStringSpace == 0)
99 m_maxStringSpace = Int32.MaxValue;
93 } 100 }
94 catch (Exception e) 101 catch (Exception e)
95 { 102 {
96 m_log.ErrorFormat("[JsonStore] initialization error: {0}",e.Message); 103 m_log.Error("[JsonStore]: initialization error: {0}", e);
97 return; 104 return;
98 } 105 }
99 106
100 if (m_enabled) 107 if (m_enabled)
101 m_log.DebugFormat("[JsonStore] module is enabled"); 108 m_log.DebugFormat("[JsonStore]: module is enabled");
102 } 109 }
103 110
104 // ----------------------------------------------------------------- 111 // -----------------------------------------------------------------
@@ -133,6 +140,8 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
133 m_sharedStore = UUID.Zero; 140 m_sharedStore = UUID.Zero;
134 m_JsonValueStore = new Dictionary<UUID,JsonStore>(); 141 m_JsonValueStore = new Dictionary<UUID,JsonStore>();
135 m_JsonValueStore.Add(m_sharedStore,new JsonStore("")); 142 m_JsonValueStore.Add(m_sharedStore,new JsonStore(""));
143
144 scene.EventManager.OnObjectBeingRemovedFromScene += EventManagerOnObjectBeingRemovedFromScene;
136 } 145 }
137 } 146 }
138 147
@@ -142,6 +151,8 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
142 // ----------------------------------------------------------------- 151 // -----------------------------------------------------------------
143 public void RemoveRegion(Scene scene) 152 public void RemoveRegion(Scene scene)
144 { 153 {
154 scene.EventManager.OnObjectBeingRemovedFromScene -= EventManagerOnObjectBeingRemovedFromScene;
155
145 // need to remove all references to the scene in the subscription 156 // need to remove all references to the scene in the subscription
146 // list to enable full garbage collection of the scene object 157 // list to enable full garbage collection of the scene object
147 } 158 }
@@ -154,7 +165,9 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
154 // ----------------------------------------------------------------- 165 // -----------------------------------------------------------------
155 public void RegionLoaded(Scene scene) 166 public void RegionLoaded(Scene scene)
156 { 167 {
157 if (m_enabled) {} 168 if (m_enabled)
169 {
170 }
158 } 171 }
159 172
160 /// ----------------------------------------------------------------- 173 /// -----------------------------------------------------------------
@@ -168,8 +181,68 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
168 181
169#endregion 182#endregion
170 183
184#region SceneEvents
185 // -----------------------------------------------------------------
186 /// <summary>
187 ///
188 /// </summary>
189 // -----------------------------------------------------------------
190 public void EventManagerOnObjectBeingRemovedFromScene(SceneObjectGroup obj)
191 {
192 obj.ForEachPart(delegate(SceneObjectPart sop) { DestroyStore(sop.UUID); } );
193 }
194
195#endregion
196
171#region ScriptInvocationInteface 197#region ScriptInvocationInteface
172 198
199
200 // -----------------------------------------------------------------
201 /// <summary>
202 ///
203 /// </summary>
204 // -----------------------------------------------------------------
205 public JsonStoreStats GetStoreStats()
206 {
207 JsonStoreStats stats;
208
209 lock (m_JsonValueStore)
210 {
211 stats.StoreCount = m_JsonValueStore.Count;
212 }
213
214 return stats;
215 }
216
217 // -----------------------------------------------------------------
218 /// <summary>
219 ///
220 /// </summary>
221 // -----------------------------------------------------------------
222 public bool AttachObjectStore(UUID objectID)
223 {
224 if (! m_enabled) return false;
225 if (! m_enableObjectStore) return false;
226
227 SceneObjectPart sop = m_scene.GetSceneObjectPart(objectID);
228 if (sop == null)
229 {
230 m_log.ErrorFormat("[JsonStore] unable to attach to unknown object; {0}", objectID);
231 return false;
232 }
233
234 lock (m_JsonValueStore)
235 {
236 if (m_JsonValueStore.ContainsKey(objectID))
237 return true;
238
239 JsonStore map = new JsonObjectStore(m_scene,objectID);
240 m_JsonValueStore.Add(objectID,map);
241 }
242
243 return true;
244 }
245
173 // ----------------------------------------------------------------- 246 // -----------------------------------------------------------------
174 /// <summary> 247 /// <summary>
175 /// 248 ///
@@ -189,9 +262,9 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
189 { 262 {
190 map = new JsonStore(value); 263 map = new JsonStore(value);
191 } 264 }
192 catch (Exception e) 265 catch (Exception)
193 { 266 {
194 m_log.InfoFormat("[JsonStore] Unable to initialize store from {0}; {1}",value,e.Message); 267 m_log.ErrorFormat("[JsonStore]: Unable to initialize store from {0}", value);
195 return false; 268 return false;
196 } 269 }
197 270
@@ -211,9 +284,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
211 if (! m_enabled) return false; 284 if (! m_enabled) return false;
212 285
213 lock (m_JsonValueStore) 286 lock (m_JsonValueStore)
214 m_JsonValueStore.Remove(storeID); 287 return m_JsonValueStore.Remove(storeID);
215
216 return true;
217 } 288 }
218 289
219 // ----------------------------------------------------------------- 290 // -----------------------------------------------------------------
@@ -221,31 +292,76 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
221 /// 292 ///
222 /// </summary> 293 /// </summary>
223 // ----------------------------------------------------------------- 294 // -----------------------------------------------------------------
224 public bool TestPath(UUID storeID, string path, bool useJson) 295 public bool TestStore(UUID storeID)
225 { 296 {
226 if (! m_enabled) return false; 297 if (! m_enabled) return false;
227 298
299 lock (m_JsonValueStore)
300 return m_JsonValueStore.ContainsKey(storeID);
301 }
302
303 // -----------------------------------------------------------------
304 /// <summary>
305 ///
306 /// </summary>
307 // -----------------------------------------------------------------
308 public JsonStoreNodeType GetNodeType(UUID storeID, string path)
309 {
310 if (! m_enabled) return JsonStoreNodeType.Undefined;
311
228 JsonStore map = null; 312 JsonStore map = null;
229 lock (m_JsonValueStore) 313 lock (m_JsonValueStore)
230 { 314 {
231 if (! m_JsonValueStore.TryGetValue(storeID,out map)) 315 if (! m_JsonValueStore.TryGetValue(storeID,out map))
232 { 316 {
233 m_log.InfoFormat("[JsonStore] Missing store {0}",storeID); 317 m_log.InfoFormat("[JsonStore] Missing store {0}",storeID);
234 return false; 318 return JsonStoreNodeType.Undefined;
235 } 319 }
236 } 320 }
237 321
238 try 322 try
239 { 323 {
240 lock (map) 324 lock (map)
241 return map.TestPath(path,useJson); 325 return map.GetNodeType(path);
242 } 326 }
243 catch (Exception e) 327 catch (Exception e)
244 { 328 {
245 m_log.InfoFormat("[JsonStore] Path test failed for {0} in {1}; {2}",path,storeID,e.Message); 329 m_log.Error(string.Format("[JsonStore]: Path test failed for {0} in {1}", path, storeID), e);
246 } 330 }
247 331
248 return false; 332 return JsonStoreNodeType.Undefined;
333 }
334
335 // -----------------------------------------------------------------
336 /// <summary>
337 ///
338 /// </summary>
339 // -----------------------------------------------------------------
340 public JsonStoreValueType GetValueType(UUID storeID, string path)
341 {
342 if (! m_enabled) return JsonStoreValueType.Undefined;
343
344 JsonStore map = null;
345 lock (m_JsonValueStore)
346 {
347 if (! m_JsonValueStore.TryGetValue(storeID,out map))
348 {
349 m_log.InfoFormat("[JsonStore] Missing store {0}",storeID);
350 return JsonStoreValueType.Undefined;
351 }
352 }
353
354 try
355 {
356 lock (map)
357 return map.GetValueType(path);
358 }
359 catch (Exception e)
360 {
361 m_log.Error(string.Format("[JsonStore]: Path test failed for {0} in {1}", path, storeID), e);
362 }
363
364 return JsonStoreValueType.Undefined;
249 } 365 }
250 366
251 // ----------------------------------------------------------------- 367 // -----------------------------------------------------------------
@@ -270,12 +386,20 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
270 try 386 try
271 { 387 {
272 lock (map) 388 lock (map)
273 if (map.SetValue(path,value,useJson)) 389 {
274 return true; 390 if (map.StringSpace > m_maxStringSpace)
391 {
392 m_log.WarnFormat("[JsonStore] {0} exceeded string size; {1} bytes used of {2} limit",
393 storeID,map.StringSpace,m_maxStringSpace);
394 return false;
395 }
396
397 return map.SetValue(path,value,useJson);
398 }
275 } 399 }
276 catch (Exception e) 400 catch (Exception e)
277 { 401 {
278 m_log.InfoFormat("[JsonStore] Unable to assign {0} to {1} in {2}; {3}",value,path,storeID,e.Message); 402 m_log.Error(string.Format("[JsonStore]: Unable to assign {0} to {1} in {2}", value, path, storeID), e);
279 } 403 }
280 404
281 return false; 405 return false;
@@ -303,12 +427,11 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
303 try 427 try
304 { 428 {
305 lock (map) 429 lock (map)
306 if (map.RemoveValue(path)) 430 return map.RemoveValue(path);
307 return true;
308 } 431 }
309 catch (Exception e) 432 catch (Exception e)
310 { 433 {
311 m_log.InfoFormat("[JsonStore] Unable to remove {0} in {1}; {2}",path,storeID,e.Message); 434 m_log.Error(string.Format("[JsonStore]: Unable to remove {0} in {1}", path, storeID), e);
312 } 435 }
313 436
314 return false; 437 return false;
@@ -319,6 +442,37 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
319 /// 442 ///
320 /// </summary> 443 /// </summary>
321 // ----------------------------------------------------------------- 444 // -----------------------------------------------------------------
445 public int GetArrayLength(UUID storeID, string path)
446 {
447 if (! m_enabled) return -1;
448
449 JsonStore map = null;
450 lock (m_JsonValueStore)
451 {
452 if (! m_JsonValueStore.TryGetValue(storeID,out map))
453 return -1;
454 }
455
456 try
457 {
458 lock (map)
459 {
460 return map.ArrayLength(path);
461 }
462 }
463 catch (Exception e)
464 {
465 m_log.Error("[JsonStore]: unable to retrieve value", e);
466 }
467
468 return -1;
469 }
470
471 // -----------------------------------------------------------------
472 /// <summary>
473 ///
474 /// </summary>
475 // -----------------------------------------------------------------
322 public bool GetValue(UUID storeID, string path, bool useJson, out string value) 476 public bool GetValue(UUID storeID, string path, bool useJson, out string value)
323 { 477 {
324 value = String.Empty; 478 value = String.Empty;
@@ -341,7 +495,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
341 } 495 }
342 catch (Exception e) 496 catch (Exception e)
343 { 497 {
344 m_log.InfoFormat("[JsonStore] unable to retrieve value; {0}",e.Message); 498 m_log.Error("[JsonStore]: unable to retrieve value", e);
345 } 499 }
346 500
347 return false; 501 return false;
@@ -380,7 +534,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
380 } 534 }
381 catch (Exception e) 535 catch (Exception e)
382 { 536 {
383 m_log.InfoFormat("[JsonStore] unable to retrieve value; {0}",e.ToString()); 537 m_log.Error("[JsonStore] unable to retrieve value", e);
384 } 538 }
385 539
386 cback(String.Empty); 540 cback(String.Empty);
@@ -419,7 +573,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
419 } 573 }
420 catch (Exception e) 574 catch (Exception e)
421 { 575 {
422 m_log.InfoFormat("[JsonStore] unable to retrieve value; {0}",e.ToString()); 576 m_log.Error("[JsonStore]: unable to retrieve value", e);
423 } 577 }
424 578
425 cback(String.Empty); 579 cback(String.Empty);
diff --git a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs
index 0c175ca..edf51a2 100644
--- a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs
+++ b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs
@@ -39,8 +39,10 @@ using OpenMetaverse.StructuredData;
39using OpenSim.Framework; 39using OpenSim.Framework;
40using OpenSim.Region.Framework.Interfaces; 40using OpenSim.Region.Framework.Interfaces;
41using OpenSim.Region.Framework.Scenes; 41using OpenSim.Region.Framework.Scenes;
42using OpenSim.Region.Framework.Scenes.Scripting;
42using System.Collections.Generic; 43using System.Collections.Generic;
43using System.Text.RegularExpressions; 44using System.Text.RegularExpressions;
45using PermissionMask = OpenSim.Framework.PermissionMask;
44 46
45namespace OpenSim.Region.OptionalModules.Scripting.JsonStore 47namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
46{ 48{
@@ -57,7 +59,9 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
57 59
58 private IScriptModuleComms m_comms; 60 private IScriptModuleComms m_comms;
59 private IJsonStoreModule m_store; 61 private IJsonStoreModule m_store;
60 62
63 private Dictionary<UUID,HashSet<UUID>> m_scriptStores = new Dictionary<UUID,HashSet<UUID>>();
64
61#region Region Module interface 65#region Region Module interface
62 66
63 // ----------------------------------------------------------------- 67 // -----------------------------------------------------------------
@@ -92,12 +96,12 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
92 } 96 }
93 catch (Exception e) 97 catch (Exception e)
94 { 98 {
95 m_log.ErrorFormat("[JsonStoreScripts] initialization error: {0}",e.Message); 99 m_log.ErrorFormat("[JsonStoreScripts]: initialization error: {0}", e.Message);
96 return; 100 return;
97 } 101 }
98 102
99 if (m_enabled) 103 if (m_enabled)
100 m_log.DebugFormat("[JsonStoreScripts] module is enabled"); 104 m_log.DebugFormat("[JsonStoreScripts]: module is enabled");
101 } 105 }
102 106
103 // ----------------------------------------------------------------- 107 // -----------------------------------------------------------------
@@ -124,6 +128,8 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
124 // ----------------------------------------------------------------- 128 // -----------------------------------------------------------------
125 public void AddRegion(Scene scene) 129 public void AddRegion(Scene scene)
126 { 130 {
131 scene.EventManager.OnScriptReset += HandleScriptReset;
132 scene.EventManager.OnRemoveScript += HandleScriptReset;
127 } 133 }
128 134
129 // ----------------------------------------------------------------- 135 // -----------------------------------------------------------------
@@ -132,12 +138,34 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
132 // ----------------------------------------------------------------- 138 // -----------------------------------------------------------------
133 public void RemoveRegion(Scene scene) 139 public void RemoveRegion(Scene scene)
134 { 140 {
141 scene.EventManager.OnScriptReset -= HandleScriptReset;
142 scene.EventManager.OnRemoveScript -= HandleScriptReset;
143
135 // need to remove all references to the scene in the subscription 144 // need to remove all references to the scene in the subscription
136 // list to enable full garbage collection of the scene object 145 // list to enable full garbage collection of the scene object
137 } 146 }
138 147
139 // ----------------------------------------------------------------- 148 // -----------------------------------------------------------------
140 /// <summary> 149 /// <summary>
150 /// </summary>
151 // -----------------------------------------------------------------
152 private void HandleScriptReset(uint localID, UUID itemID)
153 {
154 HashSet<UUID> stores;
155
156 lock (m_scriptStores)
157 {
158 if (! m_scriptStores.TryGetValue(itemID, out stores))
159 return;
160 m_scriptStores.Remove(itemID);
161 }
162
163 foreach (UUID id in stores)
164 m_store.DestroyStore(id);
165 }
166
167 // -----------------------------------------------------------------
168 /// <summary>
141 /// Called when all modules have been added for a region. This is 169 /// Called when all modules have been added for a region. This is
142 /// where we hook up events 170 /// where we hook up events
143 /// </summary> 171 /// </summary>
@@ -150,7 +178,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
150 m_comms = m_scene.RequestModuleInterface<IScriptModuleComms>(); 178 m_comms = m_scene.RequestModuleInterface<IScriptModuleComms>();
151 if (m_comms == null) 179 if (m_comms == null)
152 { 180 {
153 m_log.ErrorFormat("[JsonStoreScripts] ScriptModuleComms interface not defined"); 181 m_log.ErrorFormat("[JsonStoreScripts]: ScriptModuleComms interface not defined");
154 m_enabled = false; 182 m_enabled = false;
155 return; 183 return;
156 } 184 }
@@ -158,40 +186,20 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
158 m_store = m_scene.RequestModuleInterface<IJsonStoreModule>(); 186 m_store = m_scene.RequestModuleInterface<IJsonStoreModule>();
159 if (m_store == null) 187 if (m_store == null)
160 { 188 {
161 m_log.ErrorFormat("[JsonStoreScripts] JsonModule interface not defined"); 189 m_log.ErrorFormat("[JsonStoreScripts]: JsonModule interface not defined");
162 m_enabled = false; 190 m_enabled = false;
163 return; 191 return;
164 } 192 }
165 193
166 try 194 try
167 { 195 {
168 m_comms.RegisterScriptInvocation(this,"JsonCreateStore"); 196 m_comms.RegisterScriptInvocations(this);
169 m_comms.RegisterScriptInvocation(this,"JsonDestroyStore"); 197 m_comms.RegisterConstants(this);
170
171 m_comms.RegisterScriptInvocation(this,"JsonReadNotecard");
172 m_comms.RegisterScriptInvocation(this,"JsonWriteNotecard");
173
174 m_comms.RegisterScriptInvocation(this,"JsonTestPath");
175 m_comms.RegisterScriptInvocation(this,"JsonTestPathJson");
176
177 m_comms.RegisterScriptInvocation(this,"JsonGetValue");
178 m_comms.RegisterScriptInvocation(this,"JsonGetValueJson");
179
180 m_comms.RegisterScriptInvocation(this,"JsonTakeValue");
181 m_comms.RegisterScriptInvocation(this,"JsonTakeValueJson");
182
183 m_comms.RegisterScriptInvocation(this,"JsonReadValue");
184 m_comms.RegisterScriptInvocation(this,"JsonReadValueJson");
185
186 m_comms.RegisterScriptInvocation(this,"JsonSetValue");
187 m_comms.RegisterScriptInvocation(this,"JsonSetValueJson");
188
189 m_comms.RegisterScriptInvocation(this,"JsonRemoveValue");
190 } 198 }
191 catch (Exception e) 199 catch (Exception e)
192 { 200 {
193 // See http://opensimulator.org/mantis/view.php?id=5971 for more information 201 // See http://opensimulator.org/mantis/view.php?id=5971 for more information
194 m_log.WarnFormat("[JsonStroreScripts] script method registration failed; {0}",e.Message); 202 m_log.WarnFormat("[JsonStoreScripts]: script method registration failed; {0}", e.Message);
195 m_enabled = false; 203 m_enabled = false;
196 } 204 }
197 } 205 }
@@ -208,28 +216,73 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
208 216
209#endregion 217#endregion
210 218
219#region ScriptConstantsInterface
220
221 [ScriptConstant]
222 public static readonly int JSON_NODETYPE_UNDEF = (int)JsonStoreNodeType.Undefined;
223
224 [ScriptConstant]
225 public static readonly int JSON_NODETYPE_OBJECT = (int)JsonStoreNodeType.Object;
226
227 [ScriptConstant]
228 public static readonly int JSON_NODETYPE_ARRAY = (int)JsonStoreNodeType.Array;
229
230 [ScriptConstant]
231 public static readonly int JSON_NODETYPE_VALUE = (int)JsonStoreNodeType.Value;
232
233 [ScriptConstant]
234 public static readonly int JSON_VALUETYPE_UNDEF = (int)JsonStoreValueType.Undefined;
235
236 [ScriptConstant]
237 public static readonly int JSON_VALUETYPE_BOOLEAN = (int)JsonStoreValueType.Boolean;
238
239 [ScriptConstant]
240 public static readonly int JSON_VALUETYPE_INTEGER = (int)JsonStoreValueType.Integer;
241
242 [ScriptConstant]
243 public static readonly int JSON_VALUETYPE_FLOAT = (int)JsonStoreValueType.Float;
244
245 [ScriptConstant]
246 public static readonly int JSON_VALUETYPE_STRING = (int)JsonStoreValueType.String;
247
248
249#endregion
250
211#region ScriptInvocationInteface 251#region ScriptInvocationInteface
212 // ----------------------------------------------------------------- 252 // -----------------------------------------------------------------
213 /// <summary> 253 /// <summary>
214 /// 254 ///
215 /// </summary> 255 /// </summary>
216 // ----------------------------------------------------------------- 256 // -----------------------------------------------------------------
217 protected void GenerateRuntimeError(string msg) 257 [ScriptInvocation]
258 public UUID JsonAttachObjectStore(UUID hostID, UUID scriptID)
218 { 259 {
219 throw new Exception("JsonStore Runtime Error: " + msg); 260 UUID uuid = UUID.Zero;
261 if (! m_store.AttachObjectStore(hostID))
262 GenerateRuntimeError("Failed to create Json store");
263
264 return hostID;
220 } 265 }
221 266
222 // ----------------------------------------------------------------- 267 // -----------------------------------------------------------------
223 /// <summary> 268 /// <summary>
224 /// 269 ///
225 /// </summary> 270 /// </summary>
226 // ----------------------------------------------------------------- 271 // -----------------------------------------------------------------
227 protected UUID JsonCreateStore(UUID hostID, UUID scriptID, string value) 272 [ScriptInvocation]
273 public UUID JsonCreateStore(UUID hostID, UUID scriptID, string value)
228 { 274 {
229 UUID uuid = UUID.Zero; 275 UUID uuid = UUID.Zero;
230 if (! m_store.CreateStore(value, ref uuid)) 276 if (! m_store.CreateStore(value, ref uuid))
231 GenerateRuntimeError("Failed to create Json store"); 277 GenerateRuntimeError("Failed to create Json store");
232 278
279 lock (m_scriptStores)
280 {
281 if (! m_scriptStores.ContainsKey(scriptID))
282 m_scriptStores[scriptID] = new HashSet<UUID>();
283
284 m_scriptStores[scriptID].Add(uuid);
285 }
233 return uuid; 286 return uuid;
234 } 287 }
235 288
@@ -238,8 +291,15 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
238 /// 291 ///
239 /// </summary> 292 /// </summary>
240 // ----------------------------------------------------------------- 293 // -----------------------------------------------------------------
241 protected int JsonDestroyStore(UUID hostID, UUID scriptID, UUID storeID) 294 [ScriptInvocation]
295 public int JsonDestroyStore(UUID hostID, UUID scriptID, UUID storeID)
242 { 296 {
297 lock(m_scriptStores)
298 {
299 if (m_scriptStores.ContainsKey(scriptID))
300 m_scriptStores[scriptID].Remove(storeID);
301 }
302
243 return m_store.DestroyStore(storeID) ? 1 : 0; 303 return m_store.DestroyStore(storeID) ? 1 : 0;
244 } 304 }
245 305
@@ -248,10 +308,37 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
248 /// 308 ///
249 /// </summary> 309 /// </summary>
250 // ----------------------------------------------------------------- 310 // -----------------------------------------------------------------
251 protected UUID JsonReadNotecard(UUID hostID, UUID scriptID, UUID storeID, string path, UUID assetID) 311 [ScriptInvocation]
312 public int JsonTestStore(UUID hostID, UUID scriptID, UUID storeID)
313 {
314 return m_store.TestStore(storeID) ? 1 : 0;
315 }
316
317 // -----------------------------------------------------------------
318 /// <summary>
319 ///
320 /// </summary>
321 // -----------------------------------------------------------------
322 [ScriptInvocation]
323 public UUID JsonRezAtRoot(UUID hostID, UUID scriptID, string item, Vector3 pos, Vector3 vel, Quaternion rot, string param)
324 {
325 UUID reqID = UUID.Random();
326 Util.FireAndForget(
327 o => DoJsonRezObject(hostID, scriptID, reqID, item, pos, vel, rot, param), null, "JsonStoreScriptModule.DoJsonRezObject");
328 return reqID;
329 }
330
331 // -----------------------------------------------------------------
332 /// <summary>
333 ///
334 /// </summary>
335 // -----------------------------------------------------------------
336 [ScriptInvocation]
337 public UUID JsonReadNotecard(UUID hostID, UUID scriptID, UUID storeID, string path, string notecardIdentifier)
252 { 338 {
253 UUID reqID = UUID.Random(); 339 UUID reqID = UUID.Random();
254 Util.FireAndForget(delegate(object o) { DoJsonReadNotecard(reqID,hostID,scriptID,storeID,path,assetID); }); 340 Util.FireAndForget(
341 o => DoJsonReadNotecard(reqID, hostID, scriptID, storeID, path, notecardIdentifier), null, "JsonStoreScriptModule.JsonReadNotecard");
255 return reqID; 342 return reqID;
256 } 343 }
257 344
@@ -260,10 +347,12 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
260 /// 347 ///
261 /// </summary> 348 /// </summary>
262 // ----------------------------------------------------------------- 349 // -----------------------------------------------------------------
263 protected UUID JsonWriteNotecard(UUID hostID, UUID scriptID, UUID storeID, string path, string name) 350 [ScriptInvocation]
351 public UUID JsonWriteNotecard(UUID hostID, UUID scriptID, UUID storeID, string path, string name)
264 { 352 {
265 UUID reqID = UUID.Random(); 353 UUID reqID = UUID.Random();
266 Util.FireAndForget(delegate(object o) { DoJsonWriteNotecard(reqID,hostID,scriptID,storeID,path,name); }); 354 Util.FireAndForget(
355 o => DoJsonWriteNotecard(reqID,hostID,scriptID,storeID,path,name), null, "JsonStoreScriptModule.DoJsonWriteNotecard");
267 return reqID; 356 return reqID;
268 } 357 }
269 358
@@ -272,14 +361,41 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
272 /// 361 ///
273 /// </summary> 362 /// </summary>
274 // ----------------------------------------------------------------- 363 // -----------------------------------------------------------------
275 protected int JsonTestPath(UUID hostID, UUID scriptID, UUID storeID, string path) 364 [ScriptInvocation]
365 public string JsonList2Path(UUID hostID, UUID scriptID, object[] pathlist)
366 {
367 string ipath = ConvertList2Path(pathlist);
368 string opath;
369
370 if (JsonStore.CanonicalPathExpression(ipath,out opath))
371 return opath;
372
373 // This won't parse if passed to the other routines as opposed to
374 // returning an empty string which is a valid path and would overwrite
375 // the entire store
376 return "**INVALID**";
377 }
378
379 // -----------------------------------------------------------------
380 /// <summary>
381 ///
382 /// </summary>
383 // -----------------------------------------------------------------
384 [ScriptInvocation]
385 public int JsonGetNodeType(UUID hostID, UUID scriptID, UUID storeID, string path)
276 { 386 {
277 return m_store.TestPath(storeID,path,false) ? 1 : 0; 387 return (int)m_store.GetNodeType(storeID,path);
278 } 388 }
279 389
280 protected int JsonTestPathJson(UUID hostID, UUID scriptID, UUID storeID, string path) 390 // -----------------------------------------------------------------
391 /// <summary>
392 ///
393 /// </summary>
394 // -----------------------------------------------------------------
395 [ScriptInvocation]
396 public int JsonGetValueType(UUID hostID, UUID scriptID, UUID storeID, string path)
281 { 397 {
282 return m_store.TestPath(storeID,path,true) ? 1 : 0; 398 return (int)m_store.GetValueType(storeID,path);
283 } 399 }
284 400
285 // ----------------------------------------------------------------- 401 // -----------------------------------------------------------------
@@ -287,12 +403,14 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
287 /// 403 ///
288 /// </summary> 404 /// </summary>
289 // ----------------------------------------------------------------- 405 // -----------------------------------------------------------------
290 protected int JsonSetValue(UUID hostID, UUID scriptID, UUID storeID, string path, string value) 406 [ScriptInvocation]
407 public int JsonSetValue(UUID hostID, UUID scriptID, UUID storeID, string path, string value)
291 { 408 {
292 return m_store.SetValue(storeID,path,value,false) ? 1 : 0; 409 return m_store.SetValue(storeID,path,value,false) ? 1 : 0;
293 } 410 }
294 411
295 protected int JsonSetValueJson(UUID hostID, UUID scriptID, UUID storeID, string path, string value) 412 [ScriptInvocation]
413 public int JsonSetJson(UUID hostID, UUID scriptID, UUID storeID, string path, string value)
296 { 414 {
297 return m_store.SetValue(storeID,path,value,true) ? 1 : 0; 415 return m_store.SetValue(storeID,path,value,true) ? 1 : 0;
298 } 416 }
@@ -302,7 +420,8 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
302 /// 420 ///
303 /// </summary> 421 /// </summary>
304 // ----------------------------------------------------------------- 422 // -----------------------------------------------------------------
305 protected int JsonRemoveValue(UUID hostID, UUID scriptID, UUID storeID, string path) 423 [ScriptInvocation]
424 public int JsonRemoveValue(UUID hostID, UUID scriptID, UUID storeID, string path)
306 { 425 {
307 return m_store.RemoveValue(storeID,path) ? 1 : 0; 426 return m_store.RemoveValue(storeID,path) ? 1 : 0;
308 } 427 }
@@ -312,14 +431,27 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
312 /// 431 ///
313 /// </summary> 432 /// </summary>
314 // ----------------------------------------------------------------- 433 // -----------------------------------------------------------------
315 protected string JsonGetValue(UUID hostID, UUID scriptID, UUID storeID, string path) 434 [ScriptInvocation]
435 public int JsonGetArrayLength(UUID hostID, UUID scriptID, UUID storeID, string path)
436 {
437 return m_store.GetArrayLength(storeID,path);
438 }
439
440 // -----------------------------------------------------------------
441 /// <summary>
442 ///
443 /// </summary>
444 // -----------------------------------------------------------------
445 [ScriptInvocation]
446 public string JsonGetValue(UUID hostID, UUID scriptID, UUID storeID, string path)
316 { 447 {
317 string value = String.Empty; 448 string value = String.Empty;
318 m_store.GetValue(storeID,path,false,out value); 449 m_store.GetValue(storeID,path,false,out value);
319 return value; 450 return value;
320 } 451 }
321 452
322 protected string JsonGetValueJson(UUID hostID, UUID scriptID, UUID storeID, string path) 453 [ScriptInvocation]
454 public string JsonGetJson(UUID hostID, UUID scriptID, UUID storeID, string path)
323 { 455 {
324 string value = String.Empty; 456 string value = String.Empty;
325 m_store.GetValue(storeID,path,true, out value); 457 m_store.GetValue(storeID,path,true, out value);
@@ -331,80 +463,109 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
331 /// 463 ///
332 /// </summary> 464 /// </summary>
333 // ----------------------------------------------------------------- 465 // -----------------------------------------------------------------
334 protected UUID JsonTakeValue(UUID hostID, UUID scriptID, UUID storeID, string path) 466 [ScriptInvocation]
467 public UUID JsonTakeValue(UUID hostID, UUID scriptID, UUID storeID, string path)
335 { 468 {
336 UUID reqID = UUID.Random(); 469 UUID reqID = UUID.Random();
337 Util.FireAndForget(delegate(object o) { DoJsonTakeValue(scriptID,reqID,storeID,path,false); }); 470 Util.FireAndForget(
471 o => DoJsonTakeValue(scriptID,reqID,storeID,path,false), null, "JsonStoreScriptModule.DoJsonTakeValue");
338 return reqID; 472 return reqID;
339 } 473 }
340 474
341 protected UUID JsonTakeValueJson(UUID hostID, UUID scriptID, UUID storeID, string path) 475 [ScriptInvocation]
476 public UUID JsonTakeValueJson(UUID hostID, UUID scriptID, UUID storeID, string path)
342 { 477 {
343 UUID reqID = UUID.Random(); 478 UUID reqID = UUID.Random();
344 Util.FireAndForget(delegate(object o) { DoJsonTakeValue(scriptID,reqID,storeID,path,true); }); 479 Util.FireAndForget(
480 o => DoJsonTakeValue(scriptID,reqID,storeID,path,true), null, "JsonStoreScriptModule.DoJsonTakeValueJson");
345 return reqID; 481 return reqID;
346 } 482 }
347 483
348 private void DoJsonTakeValue(UUID scriptID, UUID reqID, UUID storeID, string path, bool useJson)
349 {
350 try
351 {
352 m_store.TakeValue(storeID,path,useJson,delegate(string value) { DispatchValue(scriptID,reqID,value); });
353 return;
354 }
355 catch (Exception e)
356 {
357 m_log.InfoFormat("[JsonStoreScripts] unable to retrieve value; {0}",e.ToString());
358 }
359
360 DispatchValue(scriptID,reqID,String.Empty);
361 }
362
363
364 // ----------------------------------------------------------------- 484 // -----------------------------------------------------------------
365 /// <summary> 485 /// <summary>
366 /// 486 ///
367 /// </summary> 487 /// </summary>
368 // ----------------------------------------------------------------- 488 // -----------------------------------------------------------------
369 protected UUID JsonReadValue(UUID hostID, UUID scriptID, UUID storeID, string path) 489 [ScriptInvocation]
490 public UUID JsonReadValue(UUID hostID, UUID scriptID, UUID storeID, string path)
370 { 491 {
371 UUID reqID = UUID.Random(); 492 UUID reqID = UUID.Random();
372 Util.FireAndForget(delegate(object o) { DoJsonReadValue(scriptID,reqID,storeID,path,false); }); 493 Util.FireAndForget(
494 o => DoJsonReadValue(scriptID,reqID,storeID,path,false), null, "JsonStoreScriptModule.DoJsonReadValue");
373 return reqID; 495 return reqID;
374 } 496 }
375 497
376 protected UUID JsonReadValueJson(UUID hostID, UUID scriptID, UUID storeID, string path) 498 [ScriptInvocation]
499 public UUID JsonReadValueJson(UUID hostID, UUID scriptID, UUID storeID, string path)
377 { 500 {
378 UUID reqID = UUID.Random(); 501 UUID reqID = UUID.Random();
379 Util.FireAndForget(delegate(object o) { DoJsonReadValue(scriptID,reqID,storeID,path,true); }); 502 Util.FireAndForget(
503 o => DoJsonReadValue(scriptID,reqID,storeID,path,true), null, "JsonStoreScriptModule.DoJsonReadValueJson");
380 return reqID; 504 return reqID;
381 } 505 }
382 506
383 private void DoJsonReadValue(UUID scriptID, UUID reqID, UUID storeID, string path, bool useJson) 507#endregion
508
509 // -----------------------------------------------------------------
510 /// <summary>
511 ///
512 /// </summary>
513 // -----------------------------------------------------------------
514 protected void GenerateRuntimeError(string msg)
515 {
516 m_log.InfoFormat("[JsonStore] runtime error: {0}",msg);
517 throw new Exception("JsonStore Runtime Error: " + msg);
518 }
519
520 // -----------------------------------------------------------------
521 /// <summary>
522 ///
523 /// </summary>
524 // -----------------------------------------------------------------
525 protected void DispatchValue(UUID scriptID, UUID reqID, string value)
526 {
527 m_comms.DispatchReply(scriptID,1,value,reqID.ToString());
528 }
529
530 // -----------------------------------------------------------------
531 /// <summary>
532 ///
533 /// </summary>
534 // -----------------------------------------------------------------
535 private void DoJsonTakeValue(UUID scriptID, UUID reqID, UUID storeID, string path, bool useJson)
384 { 536 {
385 try 537 try
386 { 538 {
387 m_store.ReadValue(storeID,path,useJson,delegate(string value) { DispatchValue(scriptID,reqID,value); }); 539 m_store.TakeValue(storeID,path,useJson,delegate(string value) { DispatchValue(scriptID,reqID,value); });
388 return; 540 return;
389 } 541 }
390 catch (Exception e) 542 catch (Exception e)
391 { 543 {
392 m_log.InfoFormat("[JsonStoreScripts] unable to retrieve value; {0}",e.ToString()); 544 m_log.InfoFormat("[JsonStoreScripts]: unable to retrieve value; {0}",e.ToString());
393 } 545 }
394 546
395 DispatchValue(scriptID,reqID,String.Empty); 547 DispatchValue(scriptID,reqID,String.Empty);
396 } 548 }
397 549
398#endregion
399 550
400 // ----------------------------------------------------------------- 551 // -----------------------------------------------------------------
401 /// <summary> 552 /// <summary>
402 /// 553 ///
403 /// </summary> 554 /// </summary>
404 // ----------------------------------------------------------------- 555 // -----------------------------------------------------------------
405 protected void DispatchValue(UUID scriptID, UUID reqID, string value) 556 private void DoJsonReadValue(UUID scriptID, UUID reqID, UUID storeID, string path, bool useJson)
406 { 557 {
407 m_comms.DispatchReply(scriptID,1,value,reqID.ToString()); 558 try
559 {
560 m_store.ReadValue(storeID,path,useJson,delegate(string value) { DispatchValue(scriptID,reqID,value); });
561 return;
562 }
563 catch (Exception e)
564 {
565 m_log.InfoFormat("[JsonStoreScripts]: unable to retrieve value; {0}",e.ToString());
566 }
567
568 DispatchValue(scriptID,reqID,String.Empty);
408 } 569 }
409 570
410 // ----------------------------------------------------------------- 571 // -----------------------------------------------------------------
@@ -412,31 +573,44 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
412 /// 573 ///
413 /// </summary> 574 /// </summary>
414 // ----------------------------------------------------------------- 575 // -----------------------------------------------------------------
415 private void DoJsonReadNotecard(UUID reqID, UUID hostID, UUID scriptID, UUID storeID, string path, UUID assetID) 576 private void DoJsonReadNotecard(
577 UUID reqID, UUID hostID, UUID scriptID, UUID storeID, string path, string notecardIdentifier)
416 { 578 {
579 UUID assetID;
580
581 if (!UUID.TryParse(notecardIdentifier, out assetID))
582 {
583 SceneObjectPart part = m_scene.GetSceneObjectPart(hostID);
584 assetID = ScriptUtils.GetAssetIdFromItemName(part, notecardIdentifier, (int)AssetType.Notecard);
585 }
586
417 AssetBase a = m_scene.AssetService.Get(assetID.ToString()); 587 AssetBase a = m_scene.AssetService.Get(assetID.ToString());
418 if (a == null) 588 if (a == null)
419 GenerateRuntimeError(String.Format("Unable to find notecard asset {0}",assetID)); 589 GenerateRuntimeError(String.Format("Unable to find notecard asset {0}", assetID));
420 590
421 if (a.Type != (sbyte)AssetType.Notecard) 591 if (a.Type != (sbyte)AssetType.Notecard)
422 GenerateRuntimeError(String.Format("Invalid notecard asset {0}",assetID)); 592 GenerateRuntimeError(String.Format("Invalid notecard asset {0}", assetID));
423 593
424 m_log.DebugFormat("[JsonStoreScripts] read notecard in context {0}",storeID); 594 m_log.DebugFormat("[JsonStoreScripts]: read notecard in context {0}",storeID);
425 595
426 try 596 try
427 { 597 {
428 string jsondata = SLUtil.ParseNotecardToString(Encoding.UTF8.GetString(a.Data)); 598 string jsondata = SLUtil.ParseNotecardToString(a.Data);
429 int result = m_store.SetValue(storeID, path, jsondata,true) ? 1 : 0; 599 int result = m_store.SetValue(storeID, path, jsondata,true) ? 1 : 0;
430 m_comms.DispatchReply(scriptID,result, "", reqID.ToString()); 600 m_comms.DispatchReply(scriptID, result, "", reqID.ToString());
431 return; 601 return;
432 } 602 }
603 catch(SLUtil.NotANotecardFormatException e)
604 {
605 m_log.WarnFormat("[JsonStoreScripts]: Notecard parsing failed; assetId {0} at line number {1}", assetID.ToString(), e.lineNumber);
606 }
433 catch (Exception e) 607 catch (Exception e)
434 { 608 {
435 m_log.WarnFormat("[JsonStoreScripts] Json parsing failed; {0}",e.Message); 609 m_log.WarnFormat("[JsonStoreScripts]: Json parsing failed; {0}", e.Message);
436 } 610 }
437 611
438 GenerateRuntimeError(String.Format("Json parsing failed for {0}",assetID.ToString())); 612 GenerateRuntimeError(String.Format("Json parsing failed for {0}", assetID));
439 m_comms.DispatchReply(scriptID,0,"",reqID.ToString()); 613 m_comms.DispatchReply(scriptID, 0, "", reqID.ToString());
440 } 614 }
441 615
442 // ----------------------------------------------------------------- 616 // -----------------------------------------------------------------
@@ -494,5 +668,141 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
494 668
495 m_comms.DispatchReply(scriptID,1,assetID.ToString(),reqID.ToString()); 669 m_comms.DispatchReply(scriptID,1,assetID.ToString(),reqID.ToString());
496 } 670 }
671
672 // -----------------------------------------------------------------
673 /// <summary>
674 /// Convert a list of values that are path components to a single string path
675 /// </summary>
676 // -----------------------------------------------------------------
677 protected static Regex m_ArrayPattern = new Regex("^([0-9]+|\\+)$");
678 private string ConvertList2Path(object[] pathlist)
679 {
680 string path = "";
681 for (int i = 0; i < pathlist.Length; i++)
682 {
683 string token = "";
684
685 if (pathlist[i] is string)
686 {
687 token = pathlist[i].ToString();
688
689 // Check to see if this is a bare number which would not be a valid
690 // identifier otherwise
691 if (m_ArrayPattern.IsMatch(token))
692 token = '[' + token + ']';
693 }
694 else if (pathlist[i] is int)
695 {
696 token = "[" + pathlist[i].ToString() + "]";
697 }
698 else
699 {
700 token = "." + pathlist[i].ToString() + ".";
701 }
702
703 path += token + ".";
704 }
705
706 return path;
707 }
708
709 // -----------------------------------------------------------------
710 /// <summary>
711 ///
712 /// </summary>
713 // -----------------------------------------------------------------
714 private void DoJsonRezObject(UUID hostID, UUID scriptID, UUID reqID, string name, Vector3 pos, Vector3 vel, Quaternion rot, string param)
715 {
716 if (Double.IsNaN(rot.X) || Double.IsNaN(rot.Y) || Double.IsNaN(rot.Z) || Double.IsNaN(rot.W))
717 {
718 GenerateRuntimeError("Invalid rez rotation");
719 return;
720 }
721
722 SceneObjectGroup host = m_scene.GetSceneObjectGroup(hostID);
723 if (host == null)
724 {
725 GenerateRuntimeError(String.Format("Unable to find rezzing host '{0}'",hostID));
726 return;
727 }
728
729 // hpos = host.RootPart.GetWorldPosition()
730 // float dist = (float)llVecDist(hpos, pos);
731 // if (dist > m_ScriptDistanceFactor * 10.0f)
732 // return;
733
734 TaskInventoryItem item = host.RootPart.Inventory.GetInventoryItem(name);
735 if (item == null)
736 {
737 GenerateRuntimeError(String.Format("Unable to find object to rez '{0}'",name));
738 return;
739 }
740
741 if (item.InvType != (int)InventoryType.Object)
742 {
743 GenerateRuntimeError("Can't create requested object; object is missing from database");
744 return;
745 }
746
747 List<SceneObjectGroup> objlist;
748 List<Vector3> veclist;
749
750 bool success = host.RootPart.Inventory.GetRezReadySceneObjects(item, out objlist, out veclist);
751 if (! success)
752 {
753 GenerateRuntimeError("Failed to create object");
754 return;
755 }
756
757 int totalPrims = 0;
758 foreach (SceneObjectGroup group in objlist)
759 totalPrims += group.PrimCount;
760
761 if (! m_scene.Permissions.CanRezObject(totalPrims, item.OwnerID, pos))
762 {
763 GenerateRuntimeError("Not allowed to create the object");
764 return;
765 }
766
767 if (! m_scene.Permissions.BypassPermissions())
768 {
769 if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0)
770 host.RootPart.Inventory.RemoveInventoryItem(item.ItemID);
771 }
772
773 for (int i = 0; i < objlist.Count; i++)
774 {
775 SceneObjectGroup group = objlist[i];
776 Vector3 curpos = pos + veclist[i];
777
778 if (group.IsAttachment == false && group.RootPart.Shape.State != 0)
779 {
780 group.RootPart.AttachedPos = group.AbsolutePosition;
781 group.RootPart.Shape.LastAttachPoint = (byte)group.AttachmentPoint;
782 }
783
784 group.FromPartID = host.RootPart.UUID;
785 m_scene.AddNewSceneObject(group, true, curpos, rot, vel);
786
787 UUID storeID = group.UUID;
788 if (! m_store.CreateStore(param, ref storeID))
789 {
790 GenerateRuntimeError("Unable to create jsonstore for new object");
791 continue;
792 }
793
794 // We can only call this after adding the scene object, since the scene object references the scene
795 // to find out if scripts should be activated at all.
796 group.RootPart.SetDieAtEdge(true);
797 group.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 3);
798 group.ResumeScripts();
799
800 group.ScheduleGroupForFullUpdate();
801
802 // send the reply back to the host object, use the integer param to indicate the number
803 // of remaining objects
804 m_comms.DispatchReply(scriptID, objlist.Count-i-1, group.RootPart.UUID.ToString(), reqID.ToString());
805 }
806 }
497 } 807 }
498} 808}
diff --git a/OpenSim/Region/OptionalModules/Scripting/JsonStore/Tests/JsonStoreScriptModuleTests.cs b/OpenSim/Region/OptionalModules/Scripting/JsonStore/Tests/JsonStoreScriptModuleTests.cs
new file mode 100644
index 0000000..99a7076
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/Scripting/JsonStore/Tests/JsonStoreScriptModuleTests.cs
@@ -0,0 +1,900 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using System.Text;
32using log4net;
33using Nini.Config;
34using NUnit.Framework;
35using OpenMetaverse;
36using OpenSim.Framework;
37using OpenSim.Region.CoreModules.Scripting.ScriptModuleComms;
38using OpenSim.Region.Framework.Scenes;
39using OpenSim.Region.ScriptEngine.Shared;
40using OpenSim.Region.ScriptEngine.Shared.Api;
41using OpenSim.Services.Interfaces;
42using OpenSim.Tests.Common;
43
44namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
45{
46 /// <summary>
47 /// Tests for inventory functions in LSL
48 /// </summary>
49 [TestFixture]
50 public class JsonStoreScriptModuleTests : OpenSimTestCase
51 {
52 private Scene m_scene;
53 private MockScriptEngine m_engine;
54 private ScriptModuleCommsModule m_smcm;
55 private JsonStoreScriptModule m_jssm;
56
57 [TestFixtureSetUp]
58 public void FixtureInit()
59 {
60 // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread.
61 Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest;
62 }
63
64 [TestFixtureTearDown]
65 public void TearDown()
66 {
67 // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple
68 // threads. Possibly, later tests should be rewritten so none of them require async stuff (which regression
69 // tests really shouldn't).
70 Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod;
71 }
72
73 [SetUp]
74 public override void SetUp()
75 {
76 base.SetUp();
77
78 IConfigSource configSource = new IniConfigSource();
79 IConfig jsonStoreConfig = configSource.AddConfig("JsonStore");
80 jsonStoreConfig.Set("Enabled", "true");
81
82 m_engine = new MockScriptEngine();
83 m_smcm = new ScriptModuleCommsModule();
84 JsonStoreModule jsm = new JsonStoreModule();
85 m_jssm = new JsonStoreScriptModule();
86
87 m_scene = new SceneHelpers().SetupScene();
88 SceneHelpers.SetupSceneModules(m_scene, configSource, m_engine, m_smcm, jsm, m_jssm);
89
90 try
91 {
92 m_smcm.RegisterScriptInvocation(this, "DummyTestMethod");
93 }
94 catch (ArgumentException)
95 {
96 Assert.Ignore("Ignoring test since running on .NET 3.5 or earlier.");
97 }
98
99 // XXX: Unfortunately, ICommsModule currently has no way of deregistering methods.
100 }
101
102 private object InvokeOp(string name, params object[] args)
103 {
104 return InvokeOpOnHost(name, UUID.Zero, args);
105 }
106
107 private object InvokeOpOnHost(string name, UUID hostId, params object[] args)
108 {
109 return m_smcm.InvokeOperation(hostId, UUID.Zero, name, args);
110 }
111
112 [Test]
113 public void TestJsonCreateStore()
114 {
115 TestHelpers.InMethod();
116// TestHelpers.EnableLogging();
117
118 // Test blank store
119 {
120 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
121 Assert.That(storeId, Is.Not.EqualTo(UUID.Zero));
122 }
123
124 // Test single element store
125 {
126 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : 'World' }");
127 Assert.That(storeId, Is.Not.EqualTo(UUID.Zero));
128 }
129
130 // Test with an integer value
131 {
132 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : 42.15 }");
133 Assert.That(storeId, Is.Not.EqualTo(UUID.Zero));
134
135 string value = (string)InvokeOp("JsonGetValue", storeId, "Hello");
136 Assert.That(value, Is.EqualTo("42.15"));
137 }
138
139 // Test with an array as the root node
140 {
141 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "[ 'one', 'two', 'three' ]");
142 Assert.That(storeId, Is.Not.EqualTo(UUID.Zero));
143
144 string value = (string)InvokeOp("JsonGetValue", storeId, "[1]");
145 Assert.That(value, Is.EqualTo("two"));
146 }
147 }
148
149 [Test]
150 public void TestJsonDestroyStore()
151 {
152 TestHelpers.InMethod();
153// TestHelpers.EnableLogging();
154
155 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : 'World' }");
156 int dsrv = (int)InvokeOp("JsonDestroyStore", storeId);
157
158 Assert.That(dsrv, Is.EqualTo(1));
159
160 int tprv = (int)InvokeOp("JsonGetNodeType", storeId, "Hello");
161 Assert.That(tprv, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_UNDEF));
162 }
163
164 [Test]
165 public void TestJsonDestroyStoreNotExists()
166 {
167 TestHelpers.InMethod();
168// TestHelpers.EnableLogging();
169
170 UUID fakeStoreId = TestHelpers.ParseTail(0x500);
171
172 int dsrv = (int)InvokeOp("JsonDestroyStore", fakeStoreId);
173
174 Assert.That(dsrv, Is.EqualTo(0));
175 }
176
177 [Test]
178 public void TestJsonGetValue()
179 {
180 TestHelpers.InMethod();
181// TestHelpers.EnableLogging();
182
183 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : 'Two' } }");
184
185 {
186 string value = (string)InvokeOp("JsonGetValue", storeId, "Hello.World");
187 Assert.That(value, Is.EqualTo("Two"));
188 }
189
190 // Test get of path section instead of leaf
191 {
192 string value = (string)InvokeOp("JsonGetValue", storeId, "Hello");
193 Assert.That(value, Is.EqualTo(""));
194 }
195
196 // Test get of non-existing value
197 {
198 string fakeValueGet = (string)InvokeOp("JsonGetValue", storeId, "foo");
199 Assert.That(fakeValueGet, Is.EqualTo(""));
200 }
201
202 // Test get from non-existing store
203 {
204 UUID fakeStoreId = TestHelpers.ParseTail(0x500);
205 string fakeStoreValueGet = (string)InvokeOp("JsonGetValue", fakeStoreId, "Hello");
206 Assert.That(fakeStoreValueGet, Is.EqualTo(""));
207 }
208 }
209
210 [Test]
211 public void TestJsonGetJson()
212 {
213 TestHelpers.InMethod();
214// TestHelpers.EnableLogging();
215
216 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : 'Two' } }");
217
218 {
219 string value = (string)InvokeOp("JsonGetJson", storeId, "Hello.World");
220 Assert.That(value, Is.EqualTo("'Two'"));
221 }
222
223 // Test get of path section instead of leaf
224 {
225 string value = (string)InvokeOp("JsonGetJson", storeId, "Hello");
226 Assert.That(value, Is.EqualTo("{\"World\":\"Two\"}"));
227 }
228
229 // Test get of non-existing value
230 {
231 string fakeValueGet = (string)InvokeOp("JsonGetJson", storeId, "foo");
232 Assert.That(fakeValueGet, Is.EqualTo(""));
233 }
234
235 // Test get from non-existing store
236 {
237 UUID fakeStoreId = TestHelpers.ParseTail(0x500);
238 string fakeStoreValueGet = (string)InvokeOp("JsonGetJson", fakeStoreId, "Hello");
239 Assert.That(fakeStoreValueGet, Is.EqualTo(""));
240 }
241 }
242
243// [Test]
244// public void TestJsonTakeValue()
245// {
246// TestHelpers.InMethod();
247//// TestHelpers.EnableLogging();
248//
249// UUID storeId
250// = (UUID)m_smcm.InvokeOperation(
251// UUID.Zero, UUID.Zero, "JsonCreateStore", new object[] { "{ 'Hello' : 'World' }" });
252//
253// string value
254// = (string)m_smcm.InvokeOperation(
255// UUID.Zero, UUID.Zero, "JsonTakeValue", new object[] { storeId, "Hello" });
256//
257// Assert.That(value, Is.EqualTo("World"));
258//
259// string value2
260// = (string)m_smcm.InvokeOperation(
261// UUID.Zero, UUID.Zero, "JsonGetValue", new object[] { storeId, "Hello" });
262//
263// Assert.That(value, Is.Null);
264// }
265
266 [Test]
267 public void TestJsonRemoveValue()
268 {
269 TestHelpers.InMethod();
270// TestHelpers.EnableLogging();
271
272 // Test remove of node in object pointing to a string
273 {
274 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : 'World' }");
275
276 int returnValue = (int)InvokeOp( "JsonRemoveValue", storeId, "Hello");
277 Assert.That(returnValue, Is.EqualTo(1));
278
279 int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello");
280 Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_UNDEF));
281
282 string returnValue2 = (string)InvokeOp("JsonGetValue", storeId, "Hello");
283 Assert.That(returnValue2, Is.EqualTo(""));
284 }
285
286 // Test remove of node in object pointing to another object
287 {
288 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : 'Wally' } }");
289
290 int returnValue = (int)InvokeOp( "JsonRemoveValue", storeId, "Hello");
291 Assert.That(returnValue, Is.EqualTo(1));
292
293 int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello");
294 Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_UNDEF));
295
296 string returnValue2 = (string)InvokeOp("JsonGetJson", storeId, "Hello");
297 Assert.That(returnValue2, Is.EqualTo(""));
298 }
299
300 // Test remove of node in an array
301 {
302 UUID storeId
303 = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : [ 'value1', 'value2' ] }");
304
305 int returnValue = (int)InvokeOp( "JsonRemoveValue", storeId, "Hello[0]");
306 Assert.That(returnValue, Is.EqualTo(1));
307
308 int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello[0]");
309 Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_VALUE));
310
311 result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello[1]");
312 Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_UNDEF));
313
314 string stringReturnValue = (string)InvokeOp("JsonGetValue", storeId, "Hello[0]");
315 Assert.That(stringReturnValue, Is.EqualTo("value2"));
316
317 stringReturnValue = (string)InvokeOp("JsonGetJson", storeId, "Hello[1]");
318 Assert.That(stringReturnValue, Is.EqualTo(""));
319 }
320
321 // Test remove of non-existing value
322 {
323 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : 'World' }");
324
325 int fakeValueRemove = (int)InvokeOp("JsonRemoveValue", storeId, "Cheese");
326 Assert.That(fakeValueRemove, Is.EqualTo(0));
327 }
328
329 {
330 // Test get from non-existing store
331 UUID fakeStoreId = TestHelpers.ParseTail(0x500);
332 int fakeStoreValueRemove = (int)InvokeOp("JsonRemoveValue", fakeStoreId, "Hello");
333 Assert.That(fakeStoreValueRemove, Is.EqualTo(0));
334 }
335 }
336
337// [Test]
338// public void TestJsonTestPath()
339// {
340// TestHelpers.InMethod();
341//// TestHelpers.EnableLogging();
342//
343// UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : 'One' } }");
344//
345// {
346// int result = (int)InvokeOp("JsonTestPath", storeId, "Hello.World");
347// Assert.That(result, Is.EqualTo(1));
348// }
349//
350// // Test for path which does not resolve to a value.
351// {
352// int result = (int)InvokeOp("JsonTestPath", storeId, "Hello");
353// Assert.That(result, Is.EqualTo(0));
354// }
355//
356// {
357// int result2 = (int)InvokeOp("JsonTestPath", storeId, "foo");
358// Assert.That(result2, Is.EqualTo(0));
359// }
360//
361// // Test with fake store
362// {
363// UUID fakeStoreId = TestHelpers.ParseTail(0x500);
364// int fakeStoreValueRemove = (int)InvokeOp("JsonTestPath", fakeStoreId, "Hello");
365// Assert.That(fakeStoreValueRemove, Is.EqualTo(0));
366// }
367// }
368
369// [Test]
370// public void TestJsonTestPathJson()
371// {
372// TestHelpers.InMethod();
373//// TestHelpers.EnableLogging();
374//
375// UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : 'One' } }");
376//
377// {
378// int result = (int)InvokeOp("JsonTestPathJson", storeId, "Hello.World");
379// Assert.That(result, Is.EqualTo(1));
380// }
381//
382// // Test for path which does not resolve to a value.
383// {
384// int result = (int)InvokeOp("JsonTestPathJson", storeId, "Hello");
385// Assert.That(result, Is.EqualTo(1));
386// }
387//
388// {
389// int result2 = (int)InvokeOp("JsonTestPathJson", storeId, "foo");
390// Assert.That(result2, Is.EqualTo(0));
391// }
392//
393// // Test with fake store
394// {
395// UUID fakeStoreId = TestHelpers.ParseTail(0x500);
396// int fakeStoreValueRemove = (int)InvokeOp("JsonTestPathJson", fakeStoreId, "Hello");
397// Assert.That(fakeStoreValueRemove, Is.EqualTo(0));
398// }
399// }
400
401 [Test]
402 public void TestJsonGetArrayLength()
403 {
404 TestHelpers.InMethod();
405// TestHelpers.EnableLogging();
406
407 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : [ 'one', 2 ] } }");
408
409 {
410 int result = (int)InvokeOp("JsonGetArrayLength", storeId, "Hello.World");
411 Assert.That(result, Is.EqualTo(2));
412 }
413
414 // Test path which is not an array
415 {
416 int result = (int)InvokeOp("JsonGetArrayLength", storeId, "Hello");
417 Assert.That(result, Is.EqualTo(-1));
418 }
419
420 // Test fake path
421 {
422 int result = (int)InvokeOp("JsonGetArrayLength", storeId, "foo");
423 Assert.That(result, Is.EqualTo(-1));
424 }
425
426 // Test fake store
427 {
428 UUID fakeStoreId = TestHelpers.ParseTail(0x500);
429 int result = (int)InvokeOp("JsonGetArrayLength", fakeStoreId, "Hello.World");
430 Assert.That(result, Is.EqualTo(-1));
431 }
432 }
433
434 [Test]
435 public void TestJsonGetNodeType()
436 {
437 TestHelpers.InMethod();
438// TestHelpers.EnableLogging();
439
440 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : [ 'one', 2 ] } }");
441
442 {
443 int result = (int)InvokeOp("JsonGetNodeType", storeId, ".");
444 Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_OBJECT));
445 }
446
447 {
448 int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello");
449 Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_OBJECT));
450 }
451
452 {
453 int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello.World");
454 Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_ARRAY));
455 }
456
457 {
458 int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello.World[0]");
459 Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_VALUE));
460 }
461
462 {
463 int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello.World[1]");
464 Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_VALUE));
465 }
466
467 // Test for non-existent path
468 {
469 int result = (int)InvokeOp("JsonGetNodeType", storeId, "foo");
470 Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_UNDEF));
471 }
472
473 // Test for non-existent store
474 {
475 UUID fakeStoreId = TestHelpers.ParseTail(0x500);
476 int result = (int)InvokeOp("JsonGetNodeType", fakeStoreId, ".");
477 Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_UNDEF));
478 }
479 }
480
481 [Test]
482 public void TestJsonList2Path()
483 {
484 TestHelpers.InMethod();
485// TestHelpers.EnableLogging();
486
487 // Invoking these methods directly since I just couldn't get comms module invocation to work for some reason
488 // - some confusion with the methods that take a params object[] invocation.
489 {
490 string result = m_jssm.JsonList2Path(UUID.Zero, UUID.Zero, new object[] { "foo" });
491 Assert.That(result, Is.EqualTo("{foo}"));
492 }
493
494 {
495 string result = m_jssm.JsonList2Path(UUID.Zero, UUID.Zero, new object[] { "foo", "bar" });
496 Assert.That(result, Is.EqualTo("{foo}.{bar}"));
497 }
498
499 {
500 string result = m_jssm.JsonList2Path(UUID.Zero, UUID.Zero, new object[] { "foo", 1, "bar" });
501 Assert.That(result, Is.EqualTo("{foo}.[1].{bar}"));
502 }
503 }
504
505 [Test]
506 public void TestJsonSetValue()
507 {
508 TestHelpers.InMethod();
509// TestHelpers.EnableLogging();
510
511 {
512 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
513
514 int result = (int)InvokeOp("JsonSetValue", storeId, "Fun", "Times");
515 Assert.That(result, Is.EqualTo(1));
516
517 string value = (string)InvokeOp("JsonGetValue", storeId, "Fun");
518 Assert.That(value, Is.EqualTo("Times"));
519 }
520
521 // Test setting a key containing periods with delineation
522 {
523 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
524
525 int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun.Circus}", "Times");
526 Assert.That(result, Is.EqualTo(1));
527
528 string value = (string)InvokeOp("JsonGetValue", storeId, "{Fun.Circus}");
529 Assert.That(value, Is.EqualTo("Times"));
530 }
531
532 // *** Test [] ***
533
534 // Test setting a key containing unbalanced ] without delineation. Expecting failure
535 {
536 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
537
538 int result = (int)InvokeOp("JsonSetValue", storeId, "Fun]Circus", "Times");
539 Assert.That(result, Is.EqualTo(0));
540
541 string value = (string)InvokeOp("JsonGetValue", storeId, "Fun]Circus");
542 Assert.That(value, Is.EqualTo(""));
543 }
544
545 // Test setting a key containing unbalanced [ without delineation. Expecting failure
546 {
547 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
548
549 int result = (int)InvokeOp("JsonSetValue", storeId, "Fun[Circus", "Times");
550 Assert.That(result, Is.EqualTo(0));
551
552 string value = (string)InvokeOp("JsonGetValue", storeId, "Fun[Circus");
553 Assert.That(value, Is.EqualTo(""));
554 }
555
556 // Test setting a key containing unbalanced [] without delineation. Expecting failure
557 {
558 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
559
560 int result = (int)InvokeOp("JsonSetValue", storeId, "Fun[]Circus", "Times");
561 Assert.That(result, Is.EqualTo(0));
562
563 string value = (string)InvokeOp("JsonGetValue", storeId, "Fun[]Circus");
564 Assert.That(value, Is.EqualTo(""));
565 }
566
567 // Test setting a key containing unbalanced ] with delineation
568 {
569 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
570
571 int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun]Circus}", "Times");
572 Assert.That(result, Is.EqualTo(1));
573
574 string value = (string)InvokeOp("JsonGetValue", storeId, "{Fun]Circus}");
575 Assert.That(value, Is.EqualTo("Times"));
576 }
577
578 // Test setting a key containing unbalanced [ with delineation
579 {
580 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
581
582 int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun[Circus}", "Times");
583 Assert.That(result, Is.EqualTo(1));
584
585 string value = (string)InvokeOp("JsonGetValue", storeId, "{Fun[Circus}");
586 Assert.That(value, Is.EqualTo("Times"));
587 }
588
589 // Test setting a key containing empty balanced [] with delineation
590 {
591 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
592
593 int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun[]Circus}", "Times");
594 Assert.That(result, Is.EqualTo(1));
595
596 string value = (string)InvokeOp("JsonGetValue", storeId, "{Fun[]Circus}");
597 Assert.That(value, Is.EqualTo("Times"));
598 }
599
600// // Commented out as this currently unexpectedly fails.
601// // Test setting a key containing brackets around an integer with delineation
602// {
603// UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
604//
605// int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun[0]Circus}", "Times");
606// Assert.That(result, Is.EqualTo(1));
607//
608// string value = (string)InvokeOp("JsonGetValue", storeId, "{Fun[0]Circus}");
609// Assert.That(value, Is.EqualTo("Times"));
610// }
611
612 // *** Test {} ***
613
614 // Test setting a key containing unbalanced } without delineation. Expecting failure (?)
615 {
616 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
617
618 int result = (int)InvokeOp("JsonSetValue", storeId, "Fun}Circus", "Times");
619 Assert.That(result, Is.EqualTo(0));
620
621 string value = (string)InvokeOp("JsonGetValue", storeId, "Fun}Circus");
622 Assert.That(value, Is.EqualTo(""));
623 }
624
625 // Test setting a key containing unbalanced { without delineation. Expecting failure (?)
626 {
627 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
628
629 int result = (int)InvokeOp("JsonSetValue", storeId, "Fun{Circus", "Times");
630 Assert.That(result, Is.EqualTo(0));
631
632 string value = (string)InvokeOp("JsonGetValue", storeId, "Fun}Circus");
633 Assert.That(value, Is.EqualTo(""));
634 }
635
636// // Commented out as this currently unexpectedly fails.
637// // Test setting a key containing unbalanced }
638// {
639// UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
640//
641// int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun}Circus}", "Times");
642// Assert.That(result, Is.EqualTo(0));
643// }
644
645 // Test setting a key containing unbalanced { with delineation
646 {
647 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
648
649 int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun{Circus}", "Times");
650 Assert.That(result, Is.EqualTo(1));
651
652 string value = (string)InvokeOp("JsonGetValue", storeId, "{Fun{Circus}");
653 Assert.That(value, Is.EqualTo("Times"));
654 }
655
656 // Test setting a key containing balanced {} with delineation. This should fail.
657 {
658 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
659
660 int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun{Filled}Circus}", "Times");
661 Assert.That(result, Is.EqualTo(0));
662
663 string value = (string)InvokeOp("JsonGetValue", storeId, "{Fun{Filled}Circus}");
664 Assert.That(value, Is.EqualTo(""));
665 }
666
667 // Test setting to location that does not exist. This should fail.
668 {
669 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
670
671 int result = (int)InvokeOp("JsonSetValue", storeId, "Fun.Circus", "Times");
672 Assert.That(result, Is.EqualTo(0));
673
674 string value = (string)InvokeOp("JsonGetValue", storeId, "Fun.Circus");
675 Assert.That(value, Is.EqualTo(""));
676 }
677
678 // Test with fake store
679 {
680 UUID fakeStoreId = TestHelpers.ParseTail(0x500);
681 int fakeStoreValueSet = (int)InvokeOp("JsonSetValue", fakeStoreId, "Hello", "World");
682 Assert.That(fakeStoreValueSet, Is.EqualTo(0));
683 }
684 }
685
686 [Test]
687 public void TestJsonSetJson()
688 {
689 TestHelpers.InMethod();
690// TestHelpers.EnableLogging();
691
692 // Single quoted token case
693 {
694 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ }");
695
696 int result = (int)InvokeOp("JsonSetJson", storeId, "Fun", "'Times'");
697 Assert.That(result, Is.EqualTo(1));
698
699 string value = (string)InvokeOp("JsonGetValue", storeId, "Fun");
700 Assert.That(value, Is.EqualTo("Times"));
701 }
702
703 // Sub-tree case
704 {
705 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ }");
706
707 int result = (int)InvokeOp("JsonSetJson", storeId, "Fun", "{ 'Filled' : 'Times' }");
708 Assert.That(result, Is.EqualTo(1));
709
710 string value = (string)InvokeOp("JsonGetValue", storeId, "Fun.Filled");
711 Assert.That(value, Is.EqualTo("Times"));
712 }
713
714 // If setting single strings in JsonSetValueJson, these must be single quoted tokens, not bare strings.
715 {
716 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ }");
717
718 int result = (int)InvokeOp("JsonSetJson", storeId, "Fun", "Times");
719 Assert.That(result, Is.EqualTo(0));
720
721 string value = (string)InvokeOp("JsonGetValue", storeId, "Fun");
722 Assert.That(value, Is.EqualTo(""));
723 }
724
725 // Test setting to location that does not exist. This should fail.
726 {
727 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ }");
728
729 int result = (int)InvokeOp("JsonSetJson", storeId, "Fun.Circus", "'Times'");
730 Assert.That(result, Is.EqualTo(0));
731
732 string value = (string)InvokeOp("JsonGetValue", storeId, "Fun.Circus");
733 Assert.That(value, Is.EqualTo(""));
734 }
735
736 // Test with fake store
737 {
738 UUID fakeStoreId = TestHelpers.ParseTail(0x500);
739 int fakeStoreValueSet = (int)InvokeOp("JsonSetJson", fakeStoreId, "Hello", "'World'");
740 Assert.That(fakeStoreValueSet, Is.EqualTo(0));
741 }
742 }
743
744 /// <summary>
745 /// Test for writing json to a notecard
746 /// </summary>
747 /// <remarks>
748 /// TODO: Really needs to test correct receipt of the link_message event. Could do this by directly fetching
749 /// it via the MockScriptEngine or perhaps by a dummy script instance.
750 /// </remarks>
751 [Test]
752 public void TestJsonWriteNotecard()
753 {
754 TestHelpers.InMethod();
755// TestHelpers.EnableLogging();
756
757 SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, TestHelpers.ParseTail(0x1));
758 m_scene.AddSceneObject(so);
759
760 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello':'World' }");
761
762 {
763 string notecardName = "nc1";
764
765 // Write notecard
766 UUID writeNotecardRequestId = (UUID)InvokeOpOnHost("JsonWriteNotecard", so.UUID, storeId, "", notecardName);
767 Assert.That(writeNotecardRequestId, Is.Not.EqualTo(UUID.Zero));
768
769 TaskInventoryItem nc1Item = so.RootPart.Inventory.GetInventoryItem(notecardName);
770 Assert.That(nc1Item, Is.Not.Null);
771
772 // TODO: Should independently check the contents.
773 }
774
775 // TODO: Write partial test
776
777 {
778 // Try to write notecard for a bad path
779 // In this case we do get a request id but no notecard is written.
780 string badPathNotecardName = "badPathNotecardName";
781
782 UUID writeNotecardBadPathRequestId
783 = (UUID)InvokeOpOnHost("JsonWriteNotecard", so.UUID, storeId, "flibble", badPathNotecardName);
784 Assert.That(writeNotecardBadPathRequestId, Is.Not.EqualTo(UUID.Zero));
785
786 TaskInventoryItem badPathItem = so.RootPart.Inventory.GetInventoryItem(badPathNotecardName);
787 Assert.That(badPathItem, Is.Null);
788 }
789
790 {
791 // Test with fake store
792 // In this case we do get a request id but no notecard is written.
793 string fakeStoreNotecardName = "fakeStoreNotecardName";
794
795 UUID fakeStoreId = TestHelpers.ParseTail(0x500);
796 UUID fakeStoreWriteNotecardValue
797 = (UUID)InvokeOpOnHost("JsonWriteNotecard", so.UUID, fakeStoreId, "", fakeStoreNotecardName);
798 Assert.That(fakeStoreWriteNotecardValue, Is.Not.EqualTo(UUID.Zero));
799
800 TaskInventoryItem fakeStoreItem = so.RootPart.Inventory.GetInventoryItem(fakeStoreNotecardName);
801 Assert.That(fakeStoreItem, Is.Null);
802 }
803 }
804
805 /// <summary>
806 /// Test for reading json from a notecard
807 /// </summary>
808 /// <remarks>
809 /// TODO: Really needs to test correct receipt of the link_message event. Could do this by directly fetching
810 /// it via the MockScriptEngine or perhaps by a dummy script instance.
811 /// </remarks>
812 [Test]
813 public void TestJsonReadNotecard()
814 {
815 TestHelpers.InMethod();
816// TestHelpers.EnableLogging();
817
818 string notecardName = "nc1";
819
820 SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, TestHelpers.ParseTail(0x1));
821 m_scene.AddSceneObject(so);
822
823 UUID creatingStoreId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello':'World' }");
824
825 // Write notecard
826 InvokeOpOnHost("JsonWriteNotecard", so.UUID, creatingStoreId, "", notecardName);
827
828 {
829 // Read notecard
830 UUID receivingStoreId = (UUID)InvokeOp("JsonCreateStore", "{}");
831 UUID readNotecardRequestId = (UUID)InvokeOpOnHost("JsonReadNotecard", so.UUID, receivingStoreId, "", notecardName);
832 Assert.That(readNotecardRequestId, Is.Not.EqualTo(UUID.Zero));
833
834 string value = (string)InvokeOp("JsonGetValue", receivingStoreId, "Hello");
835 Assert.That(value, Is.EqualTo("World"));
836 }
837
838 {
839 // Read notecard to new single component path
840 UUID receivingStoreId = (UUID)InvokeOp("JsonCreateStore", "{}");
841 UUID readNotecardRequestId = (UUID)InvokeOpOnHost("JsonReadNotecard", so.UUID, receivingStoreId, "make", notecardName);
842 Assert.That(readNotecardRequestId, Is.Not.EqualTo(UUID.Zero));
843
844 string value = (string)InvokeOp("JsonGetValue", receivingStoreId, "Hello");
845 Assert.That(value, Is.EqualTo(""));
846
847 value = (string)InvokeOp("JsonGetValue", receivingStoreId, "make.Hello");
848 Assert.That(value, Is.EqualTo("World"));
849 }
850
851 {
852 // Read notecard to new multi-component path. This should not work.
853 UUID receivingStoreId = (UUID)InvokeOp("JsonCreateStore", "{}");
854 UUID readNotecardRequestId = (UUID)InvokeOpOnHost("JsonReadNotecard", so.UUID, receivingStoreId, "make.it", notecardName);
855 Assert.That(readNotecardRequestId, Is.Not.EqualTo(UUID.Zero));
856
857 string value = (string)InvokeOp("JsonGetValue", receivingStoreId, "Hello");
858 Assert.That(value, Is.EqualTo(""));
859
860 value = (string)InvokeOp("JsonGetValue", receivingStoreId, "make.it.Hello");
861 Assert.That(value, Is.EqualTo(""));
862 }
863
864 {
865 // Read notecard to existing multi-component path. This should work
866 UUID receivingStoreId = (UUID)InvokeOp("JsonCreateStore", "{ 'make' : { 'it' : 'so' } }");
867 UUID readNotecardRequestId = (UUID)InvokeOpOnHost("JsonReadNotecard", so.UUID, receivingStoreId, "make.it", notecardName);
868 Assert.That(readNotecardRequestId, Is.Not.EqualTo(UUID.Zero));
869
870 string value = (string)InvokeOp("JsonGetValue", receivingStoreId, "Hello");
871 Assert.That(value, Is.EqualTo(""));
872
873 value = (string)InvokeOp("JsonGetValue", receivingStoreId, "make.it.Hello");
874 Assert.That(value, Is.EqualTo("World"));
875 }
876
877 {
878 // Read notecard to invalid path. This should not work.
879 UUID receivingStoreId = (UUID)InvokeOp("JsonCreateStore", "{ 'make' : { 'it' : 'so' } }");
880 UUID readNotecardRequestId = (UUID)InvokeOpOnHost("JsonReadNotecard", so.UUID, receivingStoreId, "/", notecardName);
881 Assert.That(readNotecardRequestId, Is.Not.EqualTo(UUID.Zero));
882
883 string value = (string)InvokeOp("JsonGetValue", receivingStoreId, "Hello");
884 Assert.That(value, Is.EqualTo(""));
885 }
886
887 {
888 // Try read notecard to fake store.
889 UUID fakeStoreId = TestHelpers.ParseTail(0x500);
890 UUID readNotecardRequestId = (UUID)InvokeOpOnHost("JsonReadNotecard", so.UUID, fakeStoreId, "", notecardName);
891 Assert.That(readNotecardRequestId, Is.Not.EqualTo(UUID.Zero));
892
893 string value = (string)InvokeOp("JsonGetValue", fakeStoreId, "Hello");
894 Assert.That(value, Is.EqualTo(""));
895 }
896 }
897
898 public object DummyTestMethod(object o1, object o2, object o3, object o4, object o5) { return null; }
899 }
900}
diff --git a/OpenSim/Region/OptionalModules/Scripting/Minimodule/MRMModule.cs b/OpenSim/Region/OptionalModules/Scripting/Minimodule/MRMModule.cs
index 6fb28e2..4bafe2f 100644
--- a/OpenSim/Region/OptionalModules/Scripting/Minimodule/MRMModule.cs
+++ b/OpenSim/Region/OptionalModules/Scripting/Minimodule/MRMModule.cs
@@ -180,6 +180,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.Minimodule
180 /// * Internet 180 /// * Internet
181 /// * Everything 181 /// * Everything
182 /// </remarks> 182 /// </remarks>
183#pragma warning disable 0618
183 public static AppDomain CreateRestrictedDomain(string permissionSetName, string appDomainName) 184 public static AppDomain CreateRestrictedDomain(string permissionSetName, string appDomainName)
184 { 185 {
185 if (permissionSetName == null) 186 if (permissionSetName == null)
@@ -240,6 +241,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.Minimodule
240 241
241 return restrictedDomain; 242 return restrictedDomain;
242 } 243 }
244#pragma warning restore 0618
243 245
244 246
245 void EventManager_OnRezScript(uint localID, UUID itemID, string script, int startParam, bool postOnRez, string engine, int stateSource) 247 void EventManager_OnRezScript(uint localID, UUID itemID, string script, int startParam, bool postOnRez, string engine, int stateSource)
diff --git a/OpenSim/Region/OptionalModules/Scripting/Minimodule/SOPObject.cs b/OpenSim/Region/OptionalModules/Scripting/Minimodule/SOPObject.cs
index 5ed1514..47b9c09 100644
--- a/OpenSim/Region/OptionalModules/Scripting/Minimodule/SOPObject.cs
+++ b/OpenSim/Region/OptionalModules/Scripting/Minimodule/SOPObject.cs
@@ -34,7 +34,7 @@ using OpenSim.Framework;
34using OpenSim.Region.Framework.Interfaces; 34using OpenSim.Region.Framework.Interfaces;
35using OpenSim.Region.Framework.Scenes; 35using OpenSim.Region.Framework.Scenes;
36using OpenSim.Region.OptionalModules.Scripting.Minimodule.Object; 36using OpenSim.Region.OptionalModules.Scripting.Minimodule.Object;
37using OpenSim.Region.Physics.Manager; 37using OpenSim.Region.PhysicsModules.SharedBase;
38using PrimType=OpenSim.Region.OptionalModules.Scripting.Minimodule.Object.PrimType; 38using PrimType=OpenSim.Region.OptionalModules.Scripting.Minimodule.Object.PrimType;
39using SculptType=OpenSim.Region.OptionalModules.Scripting.Minimodule.Object.SculptType; 39using SculptType=OpenSim.Region.OptionalModules.Scripting.Minimodule.Object.SculptType;
40 40
diff --git a/OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs b/OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs
index c550c44..870c0bb 100644
--- a/OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs
+++ b/OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs
@@ -105,7 +105,10 @@ namespace OpenSim.Region.OptionalModules.Scripting.RegionReady
105 m_scene.LoginLock = true; 105 m_scene.LoginLock = true;
106 m_scene.EventManager.OnEmptyScriptCompileQueue += OnEmptyScriptCompileQueue; 106 m_scene.EventManager.OnEmptyScriptCompileQueue += OnEmptyScriptCompileQueue;
107 107
108 m_log.InfoFormat("[RegionReady]: Region {0} - LOGINS DISABLED DURING INITIALIZATION.", m_scene.Name); 108 // This should always show up to the user but should not trigger warn/errors as these messages are
109 // expected and are not simulator problems. Ideally, there would be a status level in log4net but
110 // failing that, we will print out to console instead.
111 MainConsole.Instance.OutputFormat("Region {0} - LOGINS DISABLED DURING INITIALIZATION.", m_scene.Name);
109 112
110 if (m_uri != string.Empty) 113 if (m_uri != string.Empty)
111 { 114 {
@@ -169,7 +172,10 @@ namespace OpenSim.Region.OptionalModules.Scripting.RegionReady
169 c.Channel = m_channelNotify; 172 c.Channel = m_channelNotify;
170 c.Message += numScriptsFailed.ToString() + "," + message; 173 c.Message += numScriptsFailed.ToString() + "," + message;
171 c.Type = ChatTypeEnum.Region; 174 c.Type = ChatTypeEnum.Region;
172 c.Position = new Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 30); 175 if (m_scene != null)
176 c.Position = new Vector3((m_scene.RegionInfo.RegionSizeX * 0.5f), (m_scene.RegionInfo.RegionSizeY * 0.5f), 30);
177 else
178 c.Position = new Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 30);
173 c.Sender = null; 179 c.Sender = null;
174 c.SenderUUID = UUID.Zero; 180 c.SenderUUID = UUID.Zero;
175 c.Scene = m_scene; 181 c.Scene = m_scene;
@@ -215,8 +221,11 @@ namespace OpenSim.Region.OptionalModules.Scripting.RegionReady
215 // m_log.InfoFormat("[RegionReady]: Logins enabled for {0}, Oar {1}", 221 // m_log.InfoFormat("[RegionReady]: Logins enabled for {0}, Oar {1}",
216 // m_scene.RegionInfo.RegionName, m_oarFileLoading.ToString()); 222 // m_scene.RegionInfo.RegionName, m_oarFileLoading.ToString());
217 223
218 m_log.InfoFormat( 224 // Putting this out to console to make it eye-catching for people who are running OpenSimulator
219 "[RegionReady]: INITIALIZATION COMPLETE FOR {0} - LOGINS ENABLED", m_scene.Name); 225 // without info log messages enabled. Making this a warning is arguably misleading since it isn't a
226 // warning, and monitor scripts looking for warn/error/fatal messages will received false positives.
227 // Arguably, log4net needs a status log level (like Apache).
228 MainConsole.Instance.OutputFormat("INITIALIZATION COMPLETE FOR {0} - LOGINS ENABLED", m_scene.Name);
220 } 229 }
221 230
222 m_scene.SceneGridService.InformNeighborsThatRegionisUp( 231 m_scene.SceneGridService.InformNeighborsThatRegionisUp(
@@ -297,7 +306,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.RegionReady
297 finally 306 finally
298 { 307 {
299 if (os != null) 308 if (os != null)
300 os.Close(); 309 os.Dispose();
301 } 310 }
302 } 311 }
303 } 312 }
diff --git a/OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcGridRouterModule.cs b/OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcGridRouterModule.cs
index 709d389..744d1e3 100644
--- a/OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcGridRouterModule.cs
+++ b/OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcGridRouterModule.cs
@@ -35,7 +35,6 @@ using OpenMetaverse;
35using Mono.Addins; 35using Mono.Addins;
36 36
37using OpenSim.Framework; 37using OpenSim.Framework;
38using OpenSim.Framework.Communications;
39using OpenSim.Framework.Servers; 38using OpenSim.Framework.Servers;
40using OpenSim.Framework.Servers.HttpServer; 39using OpenSim.Framework.Servers.HttpServer;
41using OpenSim.Framework.Client; 40using OpenSim.Framework.Client;
diff --git a/OpenSim/Region/OptionalModules/UserStatistics/ActiveConnectionsAJAX.cs b/OpenSim/Region/OptionalModules/UserStatistics/ActiveConnectionsAJAX.cs
new file mode 100644
index 0000000..6a1112c
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/UserStatistics/ActiveConnectionsAJAX.cs
@@ -0,0 +1,308 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Reflection;
32using System.Text;
33using Mono.Data.SqliteClient;
34using OpenMetaverse;
35using OpenMetaverse.StructuredData;
36using OpenSim.Framework;
37using OpenSim.Region.Framework.Scenes;
38using OpenSim.Framework.Monitoring;
39
40namespace OpenSim.Region.UserStatistics
41{
42 public class ActiveConnectionsAJAX : IStatsController
43 {
44 private Vector3 DefaultNeighborPosition = new Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 70);
45
46 #region IStatsController Members
47
48 public string ReportName
49 {
50 get { return ""; }
51 }
52
53 public Hashtable ProcessModel(Hashtable pParams)
54 {
55 List<Scene> m_scene = (List<Scene>)pParams["Scenes"];
56
57 Hashtable nh = new Hashtable();
58 nh.Add("hdata", m_scene);
59
60 return nh;
61 }
62
63 public string RenderView(Hashtable pModelResult)
64 {
65 List<Scene> all_scenes = (List<Scene>) pModelResult["hdata"];
66
67 StringBuilder output = new StringBuilder();
68 HTMLUtil.OL_O(ref output, "");
69 foreach (Scene scene in all_scenes)
70 {
71 HTMLUtil.LI_O(ref output, String.Empty);
72 output.Append(scene.RegionInfo.RegionName);
73 HTMLUtil.OL_O(ref output, String.Empty);
74 scene.ForEachScenePresence(delegate(ScenePresence av)
75 {
76 Dictionary<string, string> queues = new Dictionary<string, string>();
77 if (av.ControllingClient is IStatsCollector)
78 {
79 IStatsCollector isClient = (IStatsCollector)av.ControllingClient;
80 queues = decodeQueueReport(isClient.Report());
81 }
82 HTMLUtil.LI_O(ref output, String.Empty);
83 output.Append(av.Name);
84 output.Append("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;");
85 output.Append((av.IsChildAgent ? "Child" : "Root"));
86 if (av.AbsolutePosition == DefaultNeighborPosition)
87 {
88 output.Append("<br />Position: ?");
89 }
90 else
91 {
92 output.Append(string.Format("<br /><NOBR>Position: <{0},{1},{2}></NOBR>", (int)av.AbsolutePosition.X,
93 (int)av.AbsolutePosition.Y,
94 (int)av.AbsolutePosition.Z));
95 }
96 Dictionary<string, int> throttles = DecodeClientThrottles(av.ControllingClient.GetThrottlesPacked(1));
97
98 HTMLUtil.UL_O(ref output, String.Empty);
99
100 foreach (string throttlename in throttles.Keys)
101 {
102 HTMLUtil.LI_O(ref output, String.Empty);
103 output.Append(throttlename);
104 output.Append(":");
105 output.Append(throttles[throttlename].ToString());
106 if (queues.ContainsKey(throttlename))
107 {
108 output.Append("/");
109 output.Append(queues[throttlename]);
110 }
111 HTMLUtil.LI_C(ref output);
112 }
113 if (queues.ContainsKey("Incoming") && queues.ContainsKey("Outgoing"))
114 {
115 HTMLUtil.LI_O(ref output, "red");
116 output.Append("SEND:");
117 output.Append(queues["Outgoing"]);
118 output.Append("/");
119 output.Append(queues["Incoming"]);
120 HTMLUtil.LI_C(ref output);
121 }
122
123 HTMLUtil.UL_C(ref output);
124 HTMLUtil.LI_C(ref output);
125 });
126 HTMLUtil.OL_C(ref output);
127 }
128 HTMLUtil.OL_C(ref output);
129 return output.ToString();
130 }
131
132 /// <summary>
133 /// Convert active connections information to JSON string. Returns a structure:
134 /// <pre>
135 /// {"regionName": {
136 /// "presenceName": {
137 /// "name": "presenceName",
138 /// "position": "<x,y,z>",
139 /// "isRoot": "false",
140 /// "throttle": {
141 /// },
142 /// "queue": {
143 /// }
144 /// },
145 /// ... // multiple presences in the scene
146 /// },
147 /// ... // multiple regions in the sim
148 /// }
149 ///
150 /// </pre>
151 /// </summary>
152 /// <param name="pModelResult"></param>
153 /// <returns></returns>
154 public string RenderJson(Hashtable pModelResult)
155 {
156 List<Scene> all_scenes = (List<Scene>) pModelResult["hdata"];
157
158 OSDMap regionInfo = new OSDMap();
159 foreach (Scene scene in all_scenes)
160 {
161 OSDMap sceneInfo = new OpenMetaverse.StructuredData.OSDMap();
162 List<ScenePresence> avatarInScene = scene.GetScenePresences();
163 foreach (ScenePresence av in avatarInScene)
164 {
165 OSDMap presenceInfo = new OSDMap();
166 presenceInfo.Add("Name", new OSDString(av.Name));
167
168 Dictionary<string,string> queues = new Dictionary<string, string>();
169 if (av.ControllingClient is IStatsCollector)
170 {
171 IStatsCollector isClient = (IStatsCollector) av.ControllingClient;
172 queues = decodeQueueReport(isClient.Report());
173 }
174 OSDMap queueInfo = new OpenMetaverse.StructuredData.OSDMap();
175 foreach (KeyValuePair<string, string> kvp in queues) {
176 queueInfo.Add(kvp.Key, new OSDString(kvp.Value));
177 }
178 sceneInfo.Add("queues", queueInfo);
179
180 if (av.IsChildAgent)
181 presenceInfo.Add("isRoot", new OSDString("false"));
182 else
183 presenceInfo.Add("isRoot", new OSDString("true"));
184
185 if (av.AbsolutePosition == DefaultNeighborPosition)
186 {
187 presenceInfo.Add("position", new OSDString("<0, 0, 0>"));
188 }
189 else
190 {
191 presenceInfo.Add("position", new OSDString(string.Format("<{0},{1},{2}>",
192 (int)av.AbsolutePosition.X,
193 (int) av.AbsolutePosition.Y,
194 (int) av.AbsolutePosition.Z)) );
195 }
196
197 Dictionary<string, int> throttles = DecodeClientThrottles(av.ControllingClient.GetThrottlesPacked(1));
198 OSDMap throttleInfo = new OpenMetaverse.StructuredData.OSDMap();
199 foreach (string throttlename in throttles.Keys)
200 {
201 throttleInfo.Add(throttlename, new OSDString(throttles[throttlename].ToString()));
202 }
203 presenceInfo.Add("throttle", throttleInfo);
204
205 sceneInfo.Add(av.Name, presenceInfo);
206 }
207 regionInfo.Add(scene.RegionInfo.RegionName, sceneInfo);
208 }
209 return regionInfo.ToString();
210 }
211
212 public Dictionary<string, int> DecodeClientThrottles(byte[] throttle)
213 {
214 Dictionary<string, int> returndict = new Dictionary<string, int>();
215 // From mantis http://opensimulator.org/mantis/view.php?id=1374
216 // it appears that sometimes we are receiving empty throttle byte arrays.
217 // TODO: Investigate this behaviour
218 if (throttle.Length == 0)
219 {
220 return new Dictionary<string, int>();
221 }
222
223 int tResend = -1;
224 int tLand = -1;
225 int tWind = -1;
226 int tCloud = -1;
227 int tTask = -1;
228 int tTexture = -1;
229 int tAsset = -1;
230 int tall = -1;
231 const int singlefloat = 4;
232
233 //Agent Throttle Block contains 7 single floatingpoint values.
234 int j = 0;
235
236 // Some Systems may be big endian...
237 // it might be smart to do this check more often...
238 if (!BitConverter.IsLittleEndian)
239 for (int i = 0; i < 7; i++)
240 Array.Reverse(throttle, j + i * singlefloat, singlefloat);
241
242 // values gotten from OpenMetaverse.org/wiki/Throttle. Thanks MW_
243 // bytes
244 // Convert to integer, since.. the full fp space isn't used.
245 tResend = (int)BitConverter.ToSingle(throttle, j);
246 returndict.Add("Resend", tResend);
247 j += singlefloat;
248 tLand = (int)BitConverter.ToSingle(throttle, j);
249 returndict.Add("Land", tLand);
250 j += singlefloat;
251 tWind = (int)BitConverter.ToSingle(throttle, j);
252 returndict.Add("Wind", tWind);
253 j += singlefloat;
254 tCloud = (int)BitConverter.ToSingle(throttle, j);
255 returndict.Add("Cloud", tCloud);
256 j += singlefloat;
257 tTask = (int)BitConverter.ToSingle(throttle, j);
258 returndict.Add("Task", tTask);
259 j += singlefloat;
260 tTexture = (int)BitConverter.ToSingle(throttle, j);
261 returndict.Add("Texture", tTexture);
262 j += singlefloat;
263 tAsset = (int)BitConverter.ToSingle(throttle, j);
264 returndict.Add("Asset", tAsset);
265
266 tall = tResend + tLand + tWind + tCloud + tTask + tTexture + tAsset;
267 returndict.Add("All", tall);
268
269 return returndict;
270 }
271 public Dictionary<string,string> decodeQueueReport(string rep)
272 {
273 Dictionary<string, string> returndic = new Dictionary<string, string>();
274 if (rep.Length == 79)
275 {
276 int pos = 1;
277 returndic.Add("All", rep.Substring((6 * pos), 8)); pos++;
278 returndic.Add("Incoming", rep.Substring((7 * pos), 8)); pos++;
279 returndic.Add("Outgoing", rep.Substring((7 * pos) , 8)); pos++;
280 returndic.Add("Resend", rep.Substring((7 * pos) , 8)); pos++;
281 returndic.Add("Land", rep.Substring((7 * pos) , 8)); pos++;
282 returndic.Add("Wind", rep.Substring((7 * pos) , 8)); pos++;
283 returndic.Add("Cloud", rep.Substring((7 * pos) , 8)); pos++;
284 returndic.Add("Task", rep.Substring((7 * pos) , 8)); pos++;
285 returndic.Add("Texture", rep.Substring((7 * pos), 8)); pos++;
286 returndic.Add("Asset", rep.Substring((7 * pos), 8));
287 /*
288 * return string.Format("{0,7} {1,7} {2,7} {3,7} {4,7} {5,7} {6,7} {7,7} {8,7} {9,7}",
289 SendQueue.Count(),
290 IncomingPacketQueue.Count,
291 OutgoingPacketQueue.Count,
292 ResendOutgoingPacketQueue.Count,
293 LandOutgoingPacketQueue.Count,
294 WindOutgoingPacketQueue.Count,
295 CloudOutgoingPacketQueue.Count,
296 TaskOutgoingPacketQueue.Count,
297 TextureOutgoingPacketQueue.Count,
298 AssetOutgoingPacketQueue.Count);
299 */
300 }
301
302
303
304 return returndic;
305 }
306 #endregion
307 }
308}
diff --git a/OpenSim/Region/OptionalModules/UserStatistics/Clients_report.cs b/OpenSim/Region/OptionalModules/UserStatistics/Clients_report.cs
new file mode 100644
index 0000000..4a6f7be
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/UserStatistics/Clients_report.cs
@@ -0,0 +1,329 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Text;
32using Mono.Data.SqliteClient;
33using OpenMetaverse;
34using OpenMetaverse.StructuredData;
35using OpenSim.Region.Framework.Scenes;
36
37namespace OpenSim.Region.UserStatistics
38{
39 public class Clients_report : IStatsController
40 {
41 #region IStatsController Members
42
43 public string ReportName
44 {
45 get { return "Client"; }
46 }
47
48 /// <summary>
49 /// Return summar information in the form:
50 /// <pre>
51 /// {"totalUsers": "34",
52 /// "totalSessions": "233",
53 /// ...
54 /// }
55 /// </pre>
56 /// </summary>
57 /// <param name="pModelResult"></param>
58 /// <returns></returns>
59 public string RenderJson(Hashtable pModelResult) {
60 stats_default_page_values values = (stats_default_page_values) pModelResult["hdata"];
61
62 OSDMap summaryInfo = new OpenMetaverse.StructuredData.OSDMap();
63 summaryInfo.Add("totalUsers", new OSDString(values.total_num_users.ToString()));
64 summaryInfo.Add("totalSessions", new OSDString(values.total_num_sessions.ToString()));
65 summaryInfo.Add("averageClientFPS", new OSDString(values.avg_client_fps.ToString()));
66 summaryInfo.Add("averageClientMem", new OSDString(values.avg_client_mem_use.ToString()));
67 summaryInfo.Add("averageSimFPS", new OSDString(values.avg_sim_fps.ToString()));
68 summaryInfo.Add("averagePingTime", new OSDString(values.avg_ping.ToString()));
69 summaryInfo.Add("totalKBOut", new OSDString(values.total_kb_out.ToString()));
70 summaryInfo.Add("totalKBIn", new OSDString(values.total_kb_in.ToString()));
71 return summaryInfo.ToString();
72 }
73
74 public Hashtable ProcessModel(Hashtable pParams)
75 {
76 SqliteConnection dbConn = (SqliteConnection)pParams["DatabaseConnection"];
77
78
79 List<ClientVersionData> clidata = new List<ClientVersionData>();
80 List<ClientVersionData> cliRegData = new List<ClientVersionData>();
81 Hashtable regionTotals = new Hashtable();
82
83 Hashtable modeldata = new Hashtable();
84 modeldata.Add("Scenes", pParams["Scenes"]);
85 modeldata.Add("Reports", pParams["Reports"]);
86 int totalclients = 0;
87 int totalregions = 0;
88
89 lock (dbConn)
90 {
91 string sql = "select count(distinct region_id) as regcnt from stats_session_data";
92
93 SqliteCommand cmd = new SqliteCommand(sql, dbConn);
94 SqliteDataReader sdr = cmd.ExecuteReader();
95 if (sdr.HasRows)
96 {
97 sdr.Read();
98 totalregions = Convert.ToInt32(sdr["regcnt"]);
99 }
100
101 sdr.Close();
102 sdr.Dispose();
103
104 sql =
105 "select client_version, count(*) as cnt, avg(avg_sim_fps) as simfps from stats_session_data group by client_version order by count(*) desc LIMIT 10;";
106
107 cmd = new SqliteCommand(sql, dbConn);
108 sdr = cmd.ExecuteReader();
109 if (sdr.HasRows)
110 {
111 while (sdr.Read())
112 {
113 ClientVersionData udata = new ClientVersionData();
114 udata.version = sdr["client_version"].ToString();
115 udata.count = Convert.ToInt32(sdr["cnt"]);
116 udata.fps = Convert.ToSingle(sdr["simfps"]);
117 clidata.Add(udata);
118 totalclients += udata.count;
119
120 }
121 }
122 sdr.Close();
123 sdr.Dispose();
124
125 if (totalregions > 1)
126 {
127 sql =
128 "select region_id, client_version, count(*) as cnt, avg(avg_sim_fps) as simfps from stats_session_data group by region_id, client_version order by region_id, count(*) desc;";
129 cmd = new SqliteCommand(sql, dbConn);
130
131 sdr = cmd.ExecuteReader();
132
133 if (sdr.HasRows)
134 {
135 while (sdr.Read())
136 {
137 ClientVersionData udata = new ClientVersionData();
138 udata.version = sdr["client_version"].ToString();
139 udata.count = Convert.ToInt32(sdr["cnt"]);
140 udata.fps = Convert.ToSingle(sdr["simfps"]);
141 udata.region_id = UUID.Parse(sdr["region_id"].ToString());
142 cliRegData.Add(udata);
143 }
144 }
145 sdr.Close();
146 sdr.Dispose();
147
148
149 }
150
151 }
152
153 foreach (ClientVersionData cvd in cliRegData)
154 {
155
156 if (regionTotals.ContainsKey(cvd.region_id))
157 {
158 int regiontotal = (int)regionTotals[cvd.region_id];
159 regiontotal += cvd.count;
160 regionTotals[cvd.region_id] = regiontotal;
161 }
162 else
163 {
164 regionTotals.Add(cvd.region_id, cvd.count);
165 }
166
167
168
169 }
170
171 modeldata["ClientData"] = clidata;
172 modeldata["ClientRegionData"] = cliRegData;
173 modeldata["RegionTotals"] = regionTotals;
174 modeldata["Total"] = totalclients;
175
176 return modeldata;
177 }
178
179 public string RenderView(Hashtable pModelResult)
180 {
181 List<ClientVersionData> clidata = (List<ClientVersionData>) pModelResult["ClientData"];
182 int totalclients = (int)pModelResult["Total"];
183 Hashtable regionTotals = (Hashtable) pModelResult["RegionTotals"];
184 List<ClientVersionData> cliRegData = (List<ClientVersionData>) pModelResult["ClientRegionData"];
185 List<Scene> m_scenes = (List<Scene>)pModelResult["Scenes"];
186 Dictionary<string, IStatsController> reports = (Dictionary<string, IStatsController>)pModelResult["Reports"];
187
188 const string STYLESHEET =
189 @"
190<STYLE>
191body
192{
193 font-size:15px; font-family:Helvetica, Verdana; color:Black;
194}
195TABLE.defaultr { }
196TR.defaultr { padding: 5px; }
197TD.header { font-weight:bold; padding:5px; }
198TD.content {}
199TD.contentright { text-align: right; }
200TD.contentcenter { text-align: center; }
201TD.align_top { vertical-align: top; }
202</STYLE>
203";
204
205 StringBuilder output = new StringBuilder();
206 HTMLUtil.HtmlHeaders_O(ref output);
207 output.Append(STYLESHEET);
208 HTMLUtil.HtmlHeaders_C(ref output);
209
210 HTMLUtil.AddReportLinks(ref output, reports, "");
211
212 HTMLUtil.TABLE_O(ref output, "defaultr");
213 HTMLUtil.TR_O(ref output, "");
214 HTMLUtil.TD_O(ref output, "header");
215 output.Append("ClientVersion");
216 HTMLUtil.TD_C(ref output);
217 HTMLUtil.TD_O(ref output, "header");
218 output.Append("Count/%");
219 HTMLUtil.TD_C(ref output);
220 HTMLUtil.TD_O(ref output, "header");
221 output.Append("SimFPS");
222 HTMLUtil.TD_C(ref output);
223 HTMLUtil.TR_C(ref output);
224
225 foreach (ClientVersionData cvd in clidata)
226 {
227 HTMLUtil.TR_O(ref output, "");
228 HTMLUtil.TD_O(ref output, "content");
229 string linkhref = "sessions.report?VersionString=" + cvd.version;
230 HTMLUtil.A(ref output, cvd.version, linkhref, "");
231 HTMLUtil.TD_C(ref output);
232 HTMLUtil.TD_O(ref output, "content");
233 output.Append(cvd.count);
234 output.Append("/");
235 if (totalclients > 0)
236 output.Append((((float)cvd.count / (float)totalclients)*100).ToString());
237 else
238 output.Append(0);
239
240 output.Append("%");
241 HTMLUtil.TD_C(ref output);
242 HTMLUtil.TD_O(ref output, "content");
243 output.Append(cvd.fps);
244 HTMLUtil.TD_C(ref output);
245 HTMLUtil.TR_C(ref output);
246 }
247 HTMLUtil.TABLE_C(ref output);
248
249 if (cliRegData.Count > 0)
250 {
251 HTMLUtil.TABLE_O(ref output, "defaultr");
252 HTMLUtil.TR_O(ref output, "");
253 HTMLUtil.TD_O(ref output, "header");
254 output.Append("Region");
255 HTMLUtil.TD_C(ref output);
256 HTMLUtil.TD_O(ref output, "header");
257 output.Append("ClientVersion");
258 HTMLUtil.TD_C(ref output);
259 HTMLUtil.TD_O(ref output, "header");
260 output.Append("Count/%");
261 HTMLUtil.TD_C(ref output);
262 HTMLUtil.TD_O(ref output, "header");
263 output.Append("SimFPS");
264 HTMLUtil.TD_C(ref output);
265 HTMLUtil.TR_C(ref output);
266
267 foreach (ClientVersionData cvd in cliRegData)
268 {
269 HTMLUtil.TR_O(ref output, "");
270 HTMLUtil.TD_O(ref output, "content");
271 output.Append(regionNamefromUUID(m_scenes, cvd.region_id));
272 HTMLUtil.TD_C(ref output);
273 HTMLUtil.TD_O(ref output, "content");
274 output.Append(cvd.version);
275 HTMLUtil.TD_C(ref output);
276 HTMLUtil.TD_O(ref output, "content");
277 output.Append(cvd.count);
278 output.Append("/");
279 if ((int)regionTotals[cvd.region_id] > 0)
280 output.Append((((float)cvd.count / (float)((int)regionTotals[cvd.region_id])) * 100).ToString());
281 else
282 output.Append(0);
283
284 output.Append("%");
285 HTMLUtil.TD_C(ref output);
286 HTMLUtil.TD_O(ref output, "content");
287 output.Append(cvd.fps);
288 HTMLUtil.TD_C(ref output);
289 HTMLUtil.TR_C(ref output);
290 }
291 HTMLUtil.TABLE_C(ref output);
292
293 }
294
295 output.Append("</BODY>");
296 output.Append("</HTML>");
297 return output.ToString();
298 }
299 public string regionNamefromUUID(List<Scene> scenes, UUID region_id)
300 {
301 string returnstring = string.Empty;
302 foreach (Scene sn in scenes)
303 {
304 if (region_id == sn.RegionInfo.originRegionID)
305 {
306 returnstring = sn.RegionInfo.RegionName;
307 break;
308 }
309 }
310
311 if (returnstring.Length == 0)
312 {
313 returnstring = region_id.ToString();
314 }
315
316 return returnstring;
317 }
318
319 #endregion
320 }
321
322 public struct ClientVersionData
323 {
324 public UUID region_id;
325 public string version;
326 public int count;
327 public float fps;
328 }
329}
diff --git a/OpenSim/Region/OptionalModules/UserStatistics/Default_Report.cs b/OpenSim/Region/OptionalModules/UserStatistics/Default_Report.cs
new file mode 100644
index 0000000..fabe3d4
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/UserStatistics/Default_Report.cs
@@ -0,0 +1,277 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Reflection;
32using System.Text;
33using Mono.Data.SqliteClient;
34using OpenMetaverse;
35using OpenMetaverse.StructuredData;
36using OpenSim.Region.Framework.Scenes;
37using OpenSim.Framework.Monitoring;
38
39
40namespace OpenSim.Region.UserStatistics
41{
42 public class Default_Report : IStatsController
43 {
44
45 public string ReportName
46 {
47 get { return "Home"; }
48 }
49
50 #region IStatsController Members
51
52 public Hashtable ProcessModel(Hashtable pParams)
53 {
54 SqliteConnection conn = (SqliteConnection)pParams["DatabaseConnection"];
55 List<Scene> m_scene = (List<Scene>)pParams["Scenes"];
56
57 stats_default_page_values mData = rep_DefaultReport_data(conn, m_scene);
58 mData.sim_stat_data = (Dictionary<UUID,USimStatsData>)pParams["SimStats"];
59 mData.stats_reports = (Dictionary<string, IStatsController>) pParams["Reports"];
60
61 Hashtable nh = new Hashtable();
62 nh.Add("hdata", mData);
63 nh.Add("Reports", pParams["Reports"]);
64
65 return nh;
66 }
67
68 public string RenderView(Hashtable pModelResult)
69 {
70 stats_default_page_values mData = (stats_default_page_values) pModelResult["hdata"];
71 return rep_Default_report_view(mData);
72 }
73
74 #endregion
75
76 public string rep_Default_report_view(stats_default_page_values values)
77 {
78
79
80 StringBuilder output = new StringBuilder();
81
82
83
84 const string TableClass = "defaultr";
85 const string TRClass = "defaultr";
86 const string TDHeaderClass = "header";
87 const string TDDataClass = "content";
88 //const string TDDataClassRight = "contentright";
89 const string TDDataClassCenter = "contentcenter";
90
91 const string STYLESHEET =
92 @"
93<STYLE>
94body
95{
96 font-size:15px; font-family:Helvetica, Verdana; color:Black;
97}
98TABLE.defaultr { }
99TR.defaultr { padding: 5px; }
100TD.header { font-weight:bold; padding:5px; }
101TD.content {}
102TD.contentright { text-align: right; }
103TD.contentcenter { text-align: center; }
104TD.align_top { vertical-align: top; }
105</STYLE>
106";
107 HTMLUtil.HtmlHeaders_O(ref output);
108
109 HTMLUtil.InsertProtoTypeAJAX(ref output);
110 string[] ajaxUpdaterDivs = new string[3];
111 int[] ajaxUpdaterSeconds = new int[3];
112 string[] ajaxUpdaterReportFragments = new string[3];
113
114 ajaxUpdaterDivs[0] = "activeconnections";
115 ajaxUpdaterSeconds[0] = 10;
116 ajaxUpdaterReportFragments[0] = "activeconnectionsajax.html";
117
118 ajaxUpdaterDivs[1] = "activesimstats";
119 ajaxUpdaterSeconds[1] = 20;
120 ajaxUpdaterReportFragments[1] = "simstatsajax.html";
121
122 ajaxUpdaterDivs[2] = "activelog";
123 ajaxUpdaterSeconds[2] = 5;
124 ajaxUpdaterReportFragments[2] = "activelogajax.html";
125
126 HTMLUtil.InsertPeriodicUpdaters(ref output, ajaxUpdaterDivs, ajaxUpdaterSeconds, ajaxUpdaterReportFragments);
127
128 output.Append(STYLESHEET);
129 HTMLUtil.HtmlHeaders_C(ref output);
130 HTMLUtil.AddReportLinks(ref output, values.stats_reports, "");
131 HTMLUtil.TABLE_O(ref output, TableClass);
132 HTMLUtil.TR_O(ref output, TRClass);
133 HTMLUtil.TD_O(ref output, TDHeaderClass);
134 output.Append("# Users Total");
135 HTMLUtil.TD_C(ref output);
136 HTMLUtil.TD_O(ref output, TDHeaderClass);
137 output.Append("# Sessions Total");
138 HTMLUtil.TD_C(ref output);
139 HTMLUtil.TD_O(ref output, TDHeaderClass);
140 output.Append("Avg Client FPS");
141 HTMLUtil.TD_C(ref output);
142 HTMLUtil.TD_O(ref output, TDHeaderClass);
143 output.Append("Avg Client Mem Use");
144 HTMLUtil.TD_C(ref output);
145 HTMLUtil.TD_O(ref output, TDHeaderClass);
146 output.Append("Avg Sim FPS");
147 HTMLUtil.TD_C(ref output);
148 HTMLUtil.TD_O(ref output, TDHeaderClass);
149 output.Append("Avg Ping");
150 HTMLUtil.TD_C(ref output);
151 HTMLUtil.TD_O(ref output, TDHeaderClass);
152 output.Append("KB Out Total");
153 HTMLUtil.TD_C(ref output);
154 HTMLUtil.TD_O(ref output, TDHeaderClass);
155 output.Append("KB In Total");
156 HTMLUtil.TD_C(ref output);
157 HTMLUtil.TR_C(ref output);
158 HTMLUtil.TR_O(ref output, TRClass);
159 HTMLUtil.TD_O(ref output, TDDataClass);
160 output.Append(values.total_num_users);
161 HTMLUtil.TD_C(ref output);
162 HTMLUtil.TD_O(ref output, TDDataClass);
163 output.Append(values.total_num_sessions);
164 HTMLUtil.TD_C(ref output);
165 HTMLUtil.TD_O(ref output, TDDataClassCenter);
166 output.Append(values.avg_client_fps);
167 HTMLUtil.TD_C(ref output);
168 HTMLUtil.TD_O(ref output, TDDataClassCenter);
169 output.Append(values.avg_client_mem_use);
170 HTMLUtil.TD_C(ref output);
171 HTMLUtil.TD_O(ref output, TDDataClassCenter);
172 output.Append(values.avg_sim_fps);
173 HTMLUtil.TD_C(ref output);
174 HTMLUtil.TD_O(ref output, TDDataClassCenter);
175 output.Append(values.avg_ping);
176 HTMLUtil.TD_C(ref output);
177 HTMLUtil.TD_O(ref output, TDDataClassCenter);
178 output.Append(values.total_kb_out);
179 HTMLUtil.TD_C(ref output);
180 HTMLUtil.TD_O(ref output, TDDataClassCenter);
181 output.Append(values.total_kb_in);
182 HTMLUtil.TD_C(ref output);
183 HTMLUtil.TR_C(ref output);
184 HTMLUtil.TABLE_C(ref output);
185
186 HTMLUtil.HR(ref output, "");
187 HTMLUtil.TABLE_O(ref output, "");
188 HTMLUtil.TR_O(ref output, "");
189 HTMLUtil.TD_O(ref output, "align_top");
190 output.Append("<DIV id=\"activeconnections\">Active Connections loading...</DIV>");
191 HTMLUtil.TD_C(ref output);
192 HTMLUtil.TD_O(ref output, "align_top");
193 output.Append("<DIV id=\"activesimstats\">SimStats loading...</DIV>");
194 output.Append("<DIV id=\"activelog\">ActiveLog loading...</DIV>");
195 HTMLUtil.TD_C(ref output);
196 HTMLUtil.TR_C(ref output);
197 HTMLUtil.TABLE_C(ref output);
198 output.Append("</BODY></HTML>");
199 // TODO: FIXME: template
200 return output.ToString();
201 }
202
203
204
205 public stats_default_page_values rep_DefaultReport_data(SqliteConnection db, List<Scene> m_scene)
206 {
207 stats_default_page_values returnstruct = new stats_default_page_values();
208 returnstruct.all_scenes = m_scene.ToArray();
209 lock (db)
210 {
211 string SQL = @"SELECT COUNT(DISTINCT agent_id) as agents, COUNT(*) as sessions, AVG(avg_fps) as client_fps,
212 AVG(avg_sim_fps) as savg_sim_fps, AVG(avg_ping) as sav_ping, SUM(n_out_kb) as num_in_kb,
213 SUM(n_out_pk) as num_in_packets, SUM(n_in_kb) as num_out_kb, SUM(n_in_pk) as num_out_packets, AVG(mem_use) as sav_mem_use
214 FROM stats_session_data;";
215 SqliteCommand cmd = new SqliteCommand(SQL, db);
216 SqliteDataReader sdr = cmd.ExecuteReader();
217 if (sdr.HasRows)
218 {
219 sdr.Read();
220 returnstruct.total_num_users = Convert.ToInt32(sdr["agents"]);
221 returnstruct.total_num_sessions = Convert.ToInt32(sdr["sessions"]);
222 returnstruct.avg_client_fps = Convert.ToSingle(sdr["client_fps"]);
223 returnstruct.avg_sim_fps = Convert.ToSingle(sdr["savg_sim_fps"]);
224 returnstruct.avg_ping = Convert.ToSingle(sdr["sav_ping"]);
225 returnstruct.total_kb_out = Convert.ToSingle(sdr["num_out_kb"]);
226 returnstruct.total_kb_in = Convert.ToSingle(sdr["num_in_kb"]);
227 returnstruct.avg_client_mem_use = Convert.ToSingle(sdr["sav_mem_use"]);
228
229 }
230 }
231 return returnstruct;
232 }
233
234 /// <summary>
235 /// Return summar information in the form:
236 /// <pre>
237 /// {"totalUsers": "34",
238 /// "totalSessions": "233",
239 /// ...
240 /// }
241 /// </pre>
242 /// </summary>
243 /// <param name="pModelResult"></param>
244 /// <returns></returns>
245 public string RenderJson(Hashtable pModelResult) {
246 stats_default_page_values values = (stats_default_page_values) pModelResult["hdata"];
247
248 OSDMap summaryInfo = new OSDMap();
249 summaryInfo.Add("totalUsers", new OSDString(values.total_num_users.ToString()));
250 summaryInfo.Add("totalSessions", new OSDString(values.total_num_sessions.ToString()));
251 summaryInfo.Add("averageClientFPS", new OSDString(values.avg_client_fps.ToString()));
252 summaryInfo.Add("averageClientMem", new OSDString(values.avg_client_mem_use.ToString()));
253 summaryInfo.Add("averageSimFPS", new OSDString(values.avg_sim_fps.ToString()));
254 summaryInfo.Add("averagePingTime", new OSDString(values.avg_ping.ToString()));
255 summaryInfo.Add("totalKBOut", new OSDString(values.total_kb_out.ToString()));
256 summaryInfo.Add("totalKBIn", new OSDString(values.total_kb_in.ToString()));
257 return summaryInfo.ToString();
258 }
259 }
260
261 public struct stats_default_page_values
262 {
263 public int total_num_users;
264 public int total_num_sessions;
265 public float avg_client_fps;
266 public float avg_client_mem_use;
267 public float avg_sim_fps;
268 public float avg_ping;
269 public float total_kb_out;
270 public float total_kb_in;
271 public float avg_client_resends;
272 public Scene[] all_scenes;
273 public Dictionary<UUID, USimStatsData> sim_stat_data;
274 public Dictionary<string, IStatsController> stats_reports;
275 }
276
277}
diff --git a/OpenSim/Region/OptionalModules/UserStatistics/HTMLUtil.cs b/OpenSim/Region/OptionalModules/UserStatistics/HTMLUtil.cs
new file mode 100644
index 0000000..c07619f
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/UserStatistics/HTMLUtil.cs
@@ -0,0 +1,263 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Text;
31
32namespace OpenSim.Region.UserStatistics
33{
34 public static class HTMLUtil
35 {
36
37 public static void TR_O(ref StringBuilder o, string pclass)
38 {
39 o.Append("<tr");
40 if (pclass.Length > 0)
41 {
42 GenericClass(ref o, pclass);
43 }
44 o.Append(">\n\t");
45 }
46
47 public static void TR_C(ref StringBuilder o)
48 {
49 o.Append("</tr>\n");
50 }
51
52 public static void TD_O(ref StringBuilder o, string pclass)
53 {
54 TD_O(ref o, pclass, 0, 0);
55 }
56
57 public static void TD_O(ref StringBuilder o, string pclass, int rowspan, int colspan)
58 {
59 o.Append("<td");
60 if (pclass.Length > 0)
61 {
62 GenericClass(ref o, pclass);
63 }
64 if (rowspan > 1)
65 {
66 o.Append(" rowspan=\"");
67 o.Append(rowspan);
68 o.Append("\"");
69 }
70 if (colspan > 1)
71 {
72 o.Append(" colspan=\"");
73 o.Append(colspan);
74 o.Append("\"");
75 }
76 o.Append(">");
77 }
78
79 public static void TD_C(ref StringBuilder o)
80 {
81 o.Append("</td>");
82 }
83
84 public static void TABLE_O(ref StringBuilder o, string pclass)
85 {
86 o.Append("<table");
87 if (pclass.Length > 0)
88 {
89 GenericClass(ref o, pclass);
90 }
91 o.Append(">\n\t");
92 }
93
94 public static void TABLE_C(ref StringBuilder o)
95 {
96 o.Append("</table>\n");
97 }
98
99 public static void BLOCKQUOTE_O(ref StringBuilder o, string pclass)
100 {
101 o.Append("<blockquote");
102 if (pclass.Length > 0)
103 {
104 GenericClass(ref o, pclass);
105 }
106 o.Append(" />\n");
107 }
108
109 public static void BLOCKQUOTE_C(ref StringBuilder o)
110 {
111 o.Append("</blockquote>\n");
112 }
113
114 public static void BR(ref StringBuilder o)
115 {
116 o.Append("<br />\n");
117 }
118
119 public static void HR(ref StringBuilder o, string pclass)
120 {
121 o.Append("<hr");
122 if (pclass.Length > 0)
123 {
124 GenericClass(ref o, pclass);
125 }
126 o.Append(" />\n");
127 }
128
129 public static void UL_O(ref StringBuilder o, string pclass)
130 {
131 o.Append("<ul");
132 if (pclass.Length > 0)
133 {
134 GenericClass(ref o, pclass);
135 }
136 o.Append(" />\n");
137 }
138
139 public static void UL_C(ref StringBuilder o)
140 {
141 o.Append("</ul>\n");
142 }
143
144 public static void OL_O(ref StringBuilder o, string pclass)
145 {
146 o.Append("<ol");
147 if (pclass.Length > 0)
148 {
149 GenericClass(ref o, pclass);
150 }
151 o.Append(" />\n");
152 }
153
154 public static void OL_C(ref StringBuilder o)
155 {
156 o.Append("</ol>\n");
157 }
158
159 public static void LI_O(ref StringBuilder o, string pclass)
160 {
161 o.Append("<li");
162 if (pclass.Length > 0)
163 {
164 GenericClass(ref o, pclass);
165 }
166 o.Append(" />\n");
167 }
168
169 public static void LI_C(ref StringBuilder o)
170 {
171 o.Append("</li>\n");
172 }
173
174 public static void GenericClass(ref StringBuilder o, string pclass)
175 {
176 o.Append(" class=\"");
177 o.Append(pclass);
178 o.Append("\"");
179 }
180
181 public static void InsertProtoTypeAJAX(ref StringBuilder o)
182 {
183 o.Append("<script type=\"text/javascript\" src=\"prototype.js\"></script>\n");
184 o.Append("<script type=\"text/javascript\" src=\"updater.js\"></script>\n");
185 }
186
187 public static void InsertPeriodicUpdaters(ref StringBuilder o, string[] divID, int[] seconds, string[] reportfrag)
188 {
189 o.Append("<script type=\"text/javascript\">\n");
190 o.Append(
191 @"
192 // <![CDATA[
193 document.observe('dom:loaded', function() {
194 /*
195 first arg : div to update
196 second arg : interval to poll in seconds
197 third arg : file to get data
198 */
199");
200 for (int i = 0; i < divID.Length; i++)
201 {
202
203 o.Append("new updater('");
204 o.Append(divID[i]);
205 o.Append("', ");
206 o.Append(seconds[i]);
207 o.Append(", '");
208 o.Append(reportfrag[i]);
209 o.Append("');\n");
210 }
211
212 o.Append(@"
213 });
214 // ]]>
215 </script>");
216 }
217
218 public static void HtmlHeaders_O(ref StringBuilder o)
219 {
220 o.Append("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n");
221 o.Append("<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"nl\">");
222 o.Append("<head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />");
223 }
224
225 public static void HtmlHeaders_C(ref StringBuilder o)
226 {
227 o.Append("</HEAD>");
228 o.Append("<BODY>");
229 }
230
231 public static void AddReportLinks(ref StringBuilder o, Dictionary<string, IStatsController> reports, string pClass)
232 {
233 int repcount = 0;
234 foreach (string str in reports.Keys)
235 {
236 if (reports[str].ReportName.Length > 0)
237 {
238 if (repcount > 0)
239 {
240 o.Append("|&nbsp;&nbsp;");
241 }
242 A(ref o, reports[str].ReportName, str, pClass);
243 o.Append("&nbsp;&nbsp;");
244 repcount++;
245 }
246 }
247 }
248
249 public static void A(ref StringBuilder o, string linktext, string linkhref, string pClass)
250 {
251 o.Append("<A");
252 if (pClass.Length > 0)
253 {
254 GenericClass(ref o, pClass);
255 }
256 o.Append(" href=\"");
257 o.Append(linkhref);
258 o.Append("\">");
259 o.Append(linktext);
260 o.Append("</A>");
261 }
262 }
263}
diff --git a/OpenSim/Region/OptionalModules/UserStatistics/IStatsReport.cs b/OpenSim/Region/OptionalModules/UserStatistics/IStatsReport.cs
new file mode 100644
index 0000000..80c4487
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/UserStatistics/IStatsReport.cs
@@ -0,0 +1,39 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System.Collections;
29
30namespace OpenSim.Region.UserStatistics
31{
32 public interface IStatsController
33 {
34 string ReportName { get; }
35 Hashtable ProcessModel(Hashtable pParams);
36 string RenderView(Hashtable pModelResult);
37 string RenderJson(Hashtable pModelResult);
38 }
39}
diff --git a/OpenSim/Region/OptionalModules/UserStatistics/LogLinesAJAX.cs b/OpenSim/Region/OptionalModules/UserStatistics/LogLinesAJAX.cs
new file mode 100644
index 0000000..4d45b80
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/UserStatistics/LogLinesAJAX.cs
@@ -0,0 +1,159 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Reflection;
32using System.Text;
33using System.Text.RegularExpressions;
34using Mono.Data.SqliteClient;
35using OpenMetaverse;
36using OpenMetaverse.StructuredData;
37using OpenSim.Region.Framework.Scenes;
38using OpenSim.Framework.Monitoring;
39
40namespace OpenSim.Region.UserStatistics
41{
42 public class LogLinesAJAX : IStatsController
43 {
44 private Regex normalizeEndLines = new Regex(@"\r\n", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.Multiline);
45
46 private Regex webFormat = new Regex(@"[^\s]*\s([^,]*),[^\s]*\s([A-Z]*)[^\s-][^\[]*\[([^\]]*)\]([^\n]*)",
47 RegexOptions.Singleline | RegexOptions.Compiled);
48 private Regex TitleColor = new Regex(@"[^\s]*\s(?:[^,]*),[^\s]*\s(?:[A-Z]*)[^\s-][^\[]*\[([^\]]*)\](?:[^\n]*)",
49 RegexOptions.Singleline | RegexOptions.Compiled);
50
51
52 #region IStatsController Members
53
54 public string ReportName
55 {
56 get { return ""; }
57 }
58
59 public Hashtable ProcessModel(Hashtable pParams)
60 {
61 Hashtable nh = new Hashtable();
62 nh.Add("loglines", pParams["LogLines"]);
63 return nh;
64 }
65
66 public string RenderView(Hashtable pModelResult)
67 {
68 StringBuilder output = new StringBuilder();
69
70 HTMLUtil.HR(ref output, "");
71 output.Append("<H3>ActiveLog</H3>\n");
72
73 string tmp = normalizeEndLines.Replace(pModelResult["loglines"].ToString(), "\n");
74
75 string[] result = Regex.Split(tmp, "\n");
76
77 string formatopen = "";
78 string formatclose = "";
79
80 for (int i = 0; i < result.Length; i++)
81 {
82 if (result[i].Length >= 30)
83 {
84 string logtype = result[i].Substring(24, 6);
85 switch (logtype)
86 {
87 case "WARN ":
88 formatopen = "<font color=\"#7D7C00\">";
89 formatclose = "</font>";
90 break;
91
92 case "ERROR ":
93 formatopen = "<font color=\"#FF0000\">";
94 formatclose = "</font>";
95 break;
96
97 default:
98 formatopen = "";
99 formatclose = "";
100 break;
101
102 }
103 }
104 StringBuilder replaceStr = new StringBuilder();
105 //string titlecolorresults =
106
107 string formatresult = Regex.Replace(TitleColor.Replace(result[i], "$1"), "[^ABCDEFabcdef0-9]", "");
108 if (formatresult.Length > 6)
109 {
110 formatresult = formatresult.Substring(0, 6);
111
112 }
113 for (int j = formatresult.Length; j <= 5; j++)
114 formatresult += "0";
115 replaceStr.Append("$1 - [<font color=\"#");
116 replaceStr.Append(formatresult);
117 replaceStr.Append("\">$3</font>] $4<br />");
118 string repstr = replaceStr.ToString();
119
120 output.Append(formatopen);
121 output.Append(webFormat.Replace(result[i], repstr));
122 output.Append(formatclose);
123 }
124
125
126 return output.ToString();
127 }
128
129 /// <summary>
130 /// Return the last log lines. Output in the format:
131 /// <pre>
132 /// {"logLines": [
133 /// "line1",
134 /// "line2",
135 /// ...
136 /// ]
137 /// }
138 /// </pre>
139 /// </summary>
140 /// <param name="pModelResult"></param>
141 /// <returns></returns>
142 public string RenderJson(Hashtable pModelResult)
143 {
144 OSDMap logInfo = new OpenMetaverse.StructuredData.OSDMap();
145
146 OSDArray logLines = new OpenMetaverse.StructuredData.OSDArray();
147 string tmp = normalizeEndLines.Replace(pModelResult["loglines"].ToString(), "\n");
148 string[] result = Regex.Split(tmp, "\n");
149 for (int i = 0; i < result.Length; i++)
150 {
151 logLines.Add(new OSDString(result[i]));
152 }
153 logInfo.Add("logLines", logLines);
154 return logInfo.ToString();
155 }
156
157 #endregion
158 }
159}
diff --git a/OpenSim/Region/OptionalModules/UserStatistics/Prototype_distributor.cs b/OpenSim/Region/OptionalModules/UserStatistics/Prototype_distributor.cs
new file mode 100644
index 0000000..6f8b2aa
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/UserStatistics/Prototype_distributor.cs
@@ -0,0 +1,80 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.IO;
30using System.Collections;
31using System.Collections.Generic;
32using System.Text;
33using OpenSim.Framework;
34
35namespace OpenSim.Region.UserStatistics
36{
37 public class Prototype_distributor : IStatsController
38 {
39 private string jsFileName = "prototype.js";
40 private string prototypejs = string.Empty;
41
42 public Prototype_distributor()
43 {
44 jsFileName = "prototype.js";
45 }
46
47 public Prototype_distributor(string jsName)
48 {
49 jsFileName = jsName;
50 }
51
52 public string ReportName
53 {
54 get { return ""; }
55 }
56 public Hashtable ProcessModel(Hashtable pParams)
57 {
58 Hashtable pResult = new Hashtable();
59 pResult["js"] = jsFileName;
60 return pResult;
61 }
62
63 public string RenderView(Hashtable pModelResult)
64 {
65 string fileName = (string)pModelResult["js"];
66 using (StreamReader fs = new StreamReader(new FileStream(Util.dataDir() + "/data/" + fileName, FileMode.Open)))
67 {
68 prototypejs = fs.ReadToEnd();
69 fs.Close();
70 }
71 return prototypejs;
72 }
73
74 public string RenderJson(Hashtable pModelResult)
75 {
76 return "{}";
77 }
78
79 }
80}
diff --git a/OpenSim/Region/OptionalModules/UserStatistics/Sessions_Report.cs b/OpenSim/Region/OptionalModules/UserStatistics/Sessions_Report.cs
new file mode 100644
index 0000000..0e94912
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/UserStatistics/Sessions_Report.cs
@@ -0,0 +1,288 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Text;
32using Mono.Data.SqliteClient;
33using OpenMetaverse;
34using OpenSim.Framework;
35
36namespace OpenSim.Region.UserStatistics
37{
38 public class Sessions_Report : IStatsController
39 {
40 #region IStatsController Members
41
42 public string ReportName
43 {
44 get { return "Sessions"; }
45 }
46
47 public Hashtable ProcessModel(Hashtable pParams)
48 {
49 Hashtable modeldata = new Hashtable();
50 modeldata.Add("Scenes", pParams["Scenes"]);
51 modeldata.Add("Reports", pParams["Reports"]);
52 SqliteConnection dbConn = (SqliteConnection)pParams["DatabaseConnection"];
53 List<SessionList> lstSessions = new List<SessionList>();
54 Hashtable requestvars = (Hashtable) pParams["RequestVars"];
55
56
57 string puserUUID = string.Empty;
58 string clientVersionString = string.Empty;
59 int queryparams = 0;
60
61 if (requestvars != null)
62 {
63 if (requestvars.ContainsKey("UserID"))
64 {
65 UUID testUUID = UUID.Zero;
66 if (UUID.TryParse(requestvars["UserID"].ToString(), out testUUID))
67 {
68 puserUUID = requestvars["UserID"].ToString();
69
70 }
71 }
72
73 if (requestvars.ContainsKey("VersionString"))
74 {
75 clientVersionString = requestvars["VersionString"].ToString();
76 }
77 }
78
79 lock (dbConn)
80 {
81 string sql =
82 "SELECT distinct a.name_f, a.name_l, a.Agent_ID, b.Session_ID, b.client_version, b.last_updated, b.start_time FROM stats_session_data a LEFT OUTER JOIN stats_session_data b ON a.Agent_ID = b.Agent_ID";
83
84 if (puserUUID.Length > 0)
85 {
86 if (queryparams == 0)
87 sql += " WHERE";
88 else
89 sql += " AND";
90
91 sql += " b.agent_id=:agent_id";
92 queryparams++;
93 }
94
95 if (clientVersionString.Length > 0)
96 {
97 if (queryparams == 0)
98 sql += " WHERE";
99 else
100 sql += " AND";
101
102 sql += " b.client_version=:client_version";
103 queryparams++;
104 }
105
106 sql += " ORDER BY a.name_f, a.name_l, b.last_updated;";
107
108 SqliteCommand cmd = new SqliteCommand(sql, dbConn);
109
110 if (puserUUID.Length > 0)
111 cmd.Parameters.Add(new SqliteParameter(":agent_id", puserUUID));
112 if (clientVersionString.Length > 0)
113 cmd.Parameters.Add(new SqliteParameter(":client_version", clientVersionString));
114
115 SqliteDataReader sdr = cmd.ExecuteReader();
116
117 if (sdr.HasRows)
118 {
119 UUID userUUID = UUID.Zero;
120
121 SessionList activeSessionList = new SessionList();
122 activeSessionList.user_id=UUID.Random();
123 while (sdr.Read())
124 {
125 UUID readUUID = UUID.Parse(sdr["agent_id"].ToString());
126 if (readUUID != userUUID)
127 {
128 activeSessionList = new SessionList();
129 activeSessionList.user_id = readUUID;
130 activeSessionList.firstname = sdr["name_f"].ToString();
131 activeSessionList.lastname = sdr["name_l"].ToString();
132 activeSessionList.sessions = new List<ShortSessionData>();
133 lstSessions.Add(activeSessionList);
134 }
135
136 ShortSessionData ssd = new ShortSessionData();
137
138 ssd.last_update = Utils.UnixTimeToDateTime((uint)Convert.ToInt32(sdr["last_updated"]));
139 ssd.start_time = Utils.UnixTimeToDateTime((uint)Convert.ToInt32(sdr["start_time"]));
140 ssd.session_id = UUID.Parse(sdr["session_id"].ToString());
141 ssd.client_version = sdr["client_version"].ToString();
142 activeSessionList.sessions.Add(ssd);
143
144 userUUID = activeSessionList.user_id;
145 }
146 }
147 sdr.Close();
148 sdr.Dispose();
149
150 }
151 modeldata["SessionData"] = lstSessions;
152 return modeldata;
153 }
154
155 public string RenderView(Hashtable pModelResult)
156 {
157 List<SessionList> lstSession = (List<SessionList>) pModelResult["SessionData"];
158 Dictionary<string, IStatsController> reports = (Dictionary<string, IStatsController>)pModelResult["Reports"];
159
160 const string STYLESHEET =
161 @"
162<STYLE>
163body
164{
165 font-size:15px; font-family:Helvetica, Verdana; color:Black;
166}
167TABLE.defaultr { }
168TR.defaultr { padding: 5px; }
169TD.header { font-weight:bold; padding:5px; }
170TD.content {}
171TD.contentright { text-align: right; }
172TD.contentcenter { text-align: center; }
173TD.align_top { vertical-align: top; }
174</STYLE>
175";
176
177 StringBuilder output = new StringBuilder();
178 HTMLUtil.HtmlHeaders_O(ref output);
179 output.Append(STYLESHEET);
180 HTMLUtil.HtmlHeaders_C(ref output);
181
182 HTMLUtil.AddReportLinks(ref output, reports, "");
183
184 HTMLUtil.TABLE_O(ref output, "defaultr");
185 HTMLUtil.TR_O(ref output, "defaultr");
186 HTMLUtil.TD_O(ref output, "header");
187 output.Append("FirstName");
188 HTMLUtil.TD_C(ref output);
189 HTMLUtil.TD_O(ref output, "header");
190 output.Append("LastName");
191 HTMLUtil.TD_C(ref output);
192 HTMLUtil.TD_O(ref output, "header");
193 output.Append("SessionEnd");
194 HTMLUtil.TD_C(ref output);
195 HTMLUtil.TD_O(ref output, "header");
196 output.Append("SessionLength");
197 HTMLUtil.TD_C(ref output);
198 HTMLUtil.TD_O(ref output, "header");
199 output.Append("Client");
200 HTMLUtil.TD_C(ref output);
201 HTMLUtil.TR_C(ref output);
202 if (lstSession.Count == 0)
203 {
204 HTMLUtil.TR_O(ref output, "");
205 HTMLUtil.TD_O(ref output, "align_top", 1, 5);
206 output.Append("No results for that query");
207 HTMLUtil.TD_C(ref output);
208 HTMLUtil.TR_C(ref output);
209 }
210 foreach (SessionList ssnlst in lstSession)
211 {
212 int cnt = 0;
213 foreach (ShortSessionData sesdata in ssnlst.sessions)
214 {
215 HTMLUtil.TR_O(ref output, "");
216 if (cnt++ == 0)
217 {
218 HTMLUtil.TD_O(ref output, "align_top", ssnlst.sessions.Count, 1);
219 output.Append(ssnlst.firstname);
220 HTMLUtil.TD_C(ref output);
221 HTMLUtil.TD_O(ref output, "align_top", ssnlst.sessions.Count, 1);
222 output.Append(ssnlst.lastname);
223 HTMLUtil.TD_C(ref output);
224 }
225 HTMLUtil.TD_O(ref output, "content");
226 output.Append(sesdata.last_update.ToShortDateString());
227 output.Append(" - ");
228 output.Append(sesdata.last_update.ToShortTimeString());
229 HTMLUtil.TD_C(ref output);
230 HTMLUtil.TD_O(ref output, "content");
231 TimeSpan dtlength = sesdata.last_update.Subtract(sesdata.start_time);
232 if (dtlength.Days > 0)
233 {
234 output.Append(dtlength.Days);
235 output.Append(" Days ");
236 }
237 if (dtlength.Hours > 0)
238 {
239 output.Append(dtlength.Hours);
240 output.Append(" Hours ");
241 }
242 if (dtlength.Minutes > 0)
243 {
244 output.Append(dtlength.Minutes);
245 output.Append(" Minutes");
246 }
247 HTMLUtil.TD_C(ref output);
248 HTMLUtil.TD_O(ref output, "content");
249 output.Append(sesdata.client_version);
250 HTMLUtil.TD_C(ref output);
251 HTMLUtil.TR_C(ref output);
252
253 }
254 HTMLUtil.TR_O(ref output, "");
255 HTMLUtil.TD_O(ref output, "align_top", 1, 5);
256 HTMLUtil.HR(ref output, "");
257 HTMLUtil.TD_C(ref output);
258 HTMLUtil.TR_C(ref output);
259 }
260 HTMLUtil.TABLE_C(ref output);
261 output.Append("</BODY>\n</HTML>");
262 return output.ToString();
263 }
264
265 public class SessionList
266 {
267 public string firstname;
268 public string lastname;
269 public UUID user_id;
270 public List<ShortSessionData> sessions;
271 }
272
273 public struct ShortSessionData
274 {
275 public UUID session_id;
276 public string client_version;
277 public DateTime last_update;
278 public DateTime start_time;
279 }
280
281 public string RenderJson(Hashtable pModelResult)
282 {
283 return "{}";
284 }
285 #endregion
286 }
287
288}
diff --git a/OpenSim/Region/OptionalModules/UserStatistics/SimStatsAJAX.cs b/OpenSim/Region/OptionalModules/UserStatistics/SimStatsAJAX.cs
new file mode 100644
index 0000000..06d9e91
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/UserStatistics/SimStatsAJAX.cs
@@ -0,0 +1,276 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Reflection;
32using System.Text;
33using Mono.Data.SqliteClient;
34using OpenMetaverse;
35using OpenMetaverse.StructuredData;
36using OpenSim.Region.Framework.Scenes;
37using OpenSim.Framework.Monitoring;
38
39namespace OpenSim.Region.UserStatistics
40{
41 public class SimStatsAJAX : IStatsController
42 {
43 #region IStatsController Members
44
45 public string ReportName
46 {
47 get { return ""; }
48 }
49
50 public Hashtable ProcessModel(Hashtable pParams)
51 {
52 List<Scene> m_scene = (List<Scene>)pParams["Scenes"];
53
54 Hashtable nh = new Hashtable();
55 nh.Add("hdata", m_scene);
56 nh.Add("simstats", pParams["SimStats"]);
57 return nh;
58 }
59
60 public string RenderView(Hashtable pModelResult)
61 {
62 StringBuilder output = new StringBuilder();
63 List<Scene> all_scenes = (List<Scene>) pModelResult["hdata"];
64 Dictionary<UUID, USimStatsData> sdatadic = (Dictionary<UUID,USimStatsData>)pModelResult["simstats"];
65
66 const string TableClass = "defaultr";
67 const string TRClass = "defaultr";
68 const string TDHeaderClass = "header";
69 const string TDDataClass = "content";
70 //const string TDDataClassRight = "contentright";
71 const string TDDataClassCenter = "contentcenter";
72
73 foreach (USimStatsData sdata in sdatadic.Values)
74 {
75
76
77 foreach (Scene sn in all_scenes)
78 {
79 if (sn.RegionInfo.RegionID == sdata.RegionId)
80 {
81 output.Append("<H2>");
82 output.Append(sn.RegionInfo.RegionName);
83 output.Append("</H2>");
84 }
85 }
86 HTMLUtil.TABLE_O(ref output, TableClass);
87 HTMLUtil.TR_O(ref output, TRClass);
88 HTMLUtil.TD_O(ref output, TDHeaderClass);
89 output.Append("Dilatn");
90 HTMLUtil.TD_C(ref output);
91 HTMLUtil.TD_O(ref output, TDHeaderClass);
92 output.Append("SimFPS");
93 HTMLUtil.TD_C(ref output);
94 HTMLUtil.TD_O(ref output, TDHeaderClass);
95 output.Append("PhysFPS");
96 HTMLUtil.TD_C(ref output);
97 HTMLUtil.TD_O(ref output, TDHeaderClass);
98 output.Append("AgntUp");
99 HTMLUtil.TD_C(ref output);
100 HTMLUtil.TD_O(ref output, TDHeaderClass);
101 output.Append("RootAg");
102 HTMLUtil.TD_C(ref output);
103 HTMLUtil.TD_O(ref output, TDHeaderClass);
104 output.Append("ChldAg");
105 HTMLUtil.TD_C(ref output);
106 HTMLUtil.TD_O(ref output, TDHeaderClass);
107 output.Append("Prims");
108 HTMLUtil.TD_C(ref output);
109 HTMLUtil.TD_O(ref output, TDHeaderClass);
110 output.Append("ATvPrm");
111 HTMLUtil.TD_C(ref output);
112 HTMLUtil.TD_O(ref output, TDHeaderClass);
113 output.Append("AtvScr");
114 HTMLUtil.TD_C(ref output);
115 HTMLUtil.TD_O(ref output, TDHeaderClass);
116 output.Append("ScrLPS");
117 HTMLUtil.TD_C(ref output);
118 HTMLUtil.TR_C(ref output);
119 HTMLUtil.TR_O(ref output, TRClass);
120 HTMLUtil.TD_O(ref output, TDDataClass);
121 output.Append(sdata.TimeDilation);
122 HTMLUtil.TD_C(ref output);
123 HTMLUtil.TD_O(ref output, TDDataClass);
124 output.Append(sdata.SimFps);
125 HTMLUtil.TD_C(ref output);
126 HTMLUtil.TD_O(ref output, TDDataClassCenter);
127 output.Append(sdata.PhysicsFps);
128 HTMLUtil.TD_C(ref output);
129 HTMLUtil.TD_O(ref output, TDDataClassCenter);
130 output.Append(sdata.AgentUpdates);
131 HTMLUtil.TD_C(ref output);
132 HTMLUtil.TD_O(ref output, TDDataClassCenter);
133 output.Append(sdata.RootAgents);
134 HTMLUtil.TD_C(ref output);
135 HTMLUtil.TD_O(ref output, TDDataClassCenter);
136 output.Append(sdata.ChildAgents);
137 HTMLUtil.TD_C(ref output);
138 HTMLUtil.TD_O(ref output, TDDataClassCenter);
139 output.Append(sdata.TotalPrims);
140 HTMLUtil.TD_C(ref output);
141 HTMLUtil.TD_O(ref output, TDDataClassCenter);
142 output.Append(sdata.ActivePrims);
143 HTMLUtil.TD_C(ref output);
144 HTMLUtil.TD_O(ref output, TDDataClassCenter);
145 output.Append(sdata.ActiveScripts);
146 HTMLUtil.TD_C(ref output);
147 HTMLUtil.TD_O(ref output, TDDataClassCenter);
148 output.Append(sdata.ScriptLinesPerSecond);
149 HTMLUtil.TD_C(ref output);
150 HTMLUtil.TR_C(ref output);
151 HTMLUtil.TR_O(ref output, TRClass);
152 HTMLUtil.TD_O(ref output, TDHeaderClass);
153 output.Append("FrmMS");
154 HTMLUtil.TD_C(ref output);
155 HTMLUtil.TD_O(ref output, TDHeaderClass);
156 output.Append("AgtMS");
157 HTMLUtil.TD_C(ref output);
158 HTMLUtil.TD_O(ref output, TDHeaderClass);
159 output.Append("PhysMS");
160 HTMLUtil.TD_C(ref output);
161 HTMLUtil.TD_O(ref output, TDHeaderClass);
162 output.Append("OthrMS");
163 HTMLUtil.TD_C(ref output);
164 HTMLUtil.TD_O(ref output, TDHeaderClass);
165 output.Append("OutPPS");
166 HTMLUtil.TD_C(ref output);
167 HTMLUtil.TD_O(ref output, TDHeaderClass);
168 output.Append("InPPS");
169 HTMLUtil.TD_C(ref output);
170 HTMLUtil.TD_O(ref output, TDHeaderClass);
171 output.Append("NoAckKB");
172 HTMLUtil.TD_C(ref output);
173 HTMLUtil.TD_O(ref output, TDHeaderClass);
174 output.Append("PndDWN");
175 HTMLUtil.TD_C(ref output);
176 HTMLUtil.TD_O(ref output, TDHeaderClass);
177 output.Append("PndUP");
178 HTMLUtil.TD_C(ref output);
179 HTMLUtil.TR_C(ref output);
180 HTMLUtil.TR_O(ref output, TRClass);
181 HTMLUtil.TD_O(ref output, TDDataClass);
182 output.Append(sdata.TotalFrameTime);
183 HTMLUtil.TD_C(ref output);
184 HTMLUtil.TD_O(ref output, TDDataClass);
185 output.Append(sdata.AgentFrameTime);
186 HTMLUtil.TD_C(ref output);
187 HTMLUtil.TD_O(ref output, TDDataClassCenter);
188 output.Append(sdata.PhysicsFrameTime);
189 HTMLUtil.TD_C(ref output);
190 HTMLUtil.TD_O(ref output, TDDataClassCenter);
191 output.Append(sdata.OtherFrameTime);
192 HTMLUtil.TD_C(ref output);
193 HTMLUtil.TD_O(ref output, TDDataClassCenter);
194 output.Append(sdata.OutPacketsPerSecond);
195 HTMLUtil.TD_C(ref output);
196 HTMLUtil.TD_O(ref output, TDDataClassCenter);
197 output.Append(sdata.InPacketsPerSecond);
198 HTMLUtil.TD_C(ref output);
199 HTMLUtil.TD_O(ref output, TDDataClassCenter);
200 output.Append(sdata.UnackedBytes);
201 HTMLUtil.TD_C(ref output);
202 HTMLUtil.TD_O(ref output, TDDataClassCenter);
203 output.Append(sdata.PendingDownloads);
204 HTMLUtil.TD_C(ref output);
205 HTMLUtil.TD_O(ref output, TDDataClassCenter);
206 output.Append(sdata.PendingUploads);
207 HTMLUtil.TD_C(ref output);
208 HTMLUtil.TR_C(ref output);
209 HTMLUtil.TABLE_C(ref output);
210
211 }
212
213 return output.ToString();
214 }
215
216 /// <summary>
217 /// Return stat information for all regions in the sim. Returns data of the form:
218 /// <pre>
219 /// {"REGIONNAME": {
220 /// "region": "REGIONNAME",
221 /// "timeDilation": "101",
222 /// ... // the rest of the stat info
223 /// },
224 /// ... // entries for each region
225 /// }
226 /// </pre>
227 /// </summary>
228 /// <param name="pModelResult"></param>
229 /// <returns></returns>
230 public string RenderJson(Hashtable pModelResult)
231 {
232 List<Scene> all_scenes = (List<Scene>) pModelResult["hdata"];
233 Dictionary<UUID, USimStatsData> sdatadic = (Dictionary<UUID,USimStatsData>)pModelResult["simstats"];
234
235 OSDMap allStatsInfo = new OpenMetaverse.StructuredData.OSDMap();
236 foreach (USimStatsData sdata in sdatadic.Values)
237 {
238 OSDMap statsInfo = new OpenMetaverse.StructuredData.OSDMap();
239 string regionName = "unknown";
240 foreach (Scene sn in all_scenes)
241 {
242 if (sn.RegionInfo.RegionID == sdata.RegionId)
243 {
244 regionName = sn.RegionInfo.RegionName;
245 break;
246 }
247 }
248 statsInfo.Add("region", new OSDString(regionName));
249 statsInfo.Add("timeDilation", new OSDString(sdata.TimeDilation.ToString()));
250 statsInfo.Add("simFPS", new OSDString(sdata.SimFps.ToString()));
251 statsInfo.Add("physicsFPS", new OSDString(sdata.PhysicsFps.ToString()));
252 statsInfo.Add("agentUpdates", new OSDString(sdata.AgentUpdates.ToString()));
253 statsInfo.Add("rootAgents", new OSDString(sdata.RootAgents.ToString()));
254 statsInfo.Add("childAgents", new OSDString(sdata.ChildAgents.ToString()));
255 statsInfo.Add("totalPrims", new OSDString(sdata.TotalPrims.ToString()));
256 statsInfo.Add("activePrims", new OSDString(sdata.ActivePrims.ToString()));
257 statsInfo.Add("activeScripts", new OSDString(sdata.ActiveScripts.ToString()));
258 statsInfo.Add("scriptLinesPerSec", new OSDString(sdata.ScriptLinesPerSecond.ToString()));
259 statsInfo.Add("totalFrameTime", new OSDString(sdata.TotalFrameTime.ToString()));
260 statsInfo.Add("agentFrameTime", new OSDString(sdata.AgentFrameTime.ToString()));
261 statsInfo.Add("physicsFrameTime", new OSDString(sdata.PhysicsFrameTime.ToString()));
262 statsInfo.Add("otherFrameTime", new OSDString(sdata.OtherFrameTime.ToString()));
263 statsInfo.Add("outPacketsPerSec", new OSDString(sdata.OutPacketsPerSecond.ToString()));
264 statsInfo.Add("inPacketsPerSec", new OSDString(sdata.InPacketsPerSecond.ToString()));
265 statsInfo.Add("unackedByptes", new OSDString(sdata.UnackedBytes.ToString()));
266 statsInfo.Add("pendingDownloads", new OSDString(sdata.PendingDownloads.ToString()));
267 statsInfo.Add("pendingUploads", new OSDString(sdata.PendingUploads.ToString()));
268
269 allStatsInfo.Add(regionName, statsInfo);
270 }
271 return allStatsInfo.ToString();
272 }
273
274 #endregion
275 }
276}
diff --git a/OpenSim/Region/OptionalModules/UserStatistics/Updater_distributor.cs b/OpenSim/Region/OptionalModules/UserStatistics/Updater_distributor.cs
new file mode 100644
index 0000000..601e06b
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/UserStatistics/Updater_distributor.cs
@@ -0,0 +1,70 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.IO;
30using System.Collections;
31using System.Collections.Generic;
32using System.Text;
33using OpenSim.Framework;
34
35namespace OpenSim.Region.UserStatistics
36{
37 public class Updater_distributor : IStatsController
38 {
39 private string updaterjs = string.Empty;
40
41 public string ReportName
42 {
43 get { return ""; }
44 }
45
46 public Hashtable ProcessModel(Hashtable pParams)
47 {
48 Hashtable pResult = new Hashtable();
49 if (updaterjs.Length == 0)
50 {
51 StreamReader fs = new StreamReader(new FileStream(Util.dataDir() + "/data/updater.js", FileMode.Open));
52 updaterjs = fs.ReadToEnd();
53 fs.Close();
54 fs.Dispose();
55 }
56 pResult["js"] = updaterjs;
57 return pResult;
58 }
59
60 public string RenderView(Hashtable pModelResult)
61 {
62 return pModelResult["js"].ToString();
63 }
64
65 public string RenderJson(Hashtable pModelResult) {
66 return "{}";
67 }
68
69 }
70} \ No newline at end of file
diff --git a/OpenSim/Region/OptionalModules/UserStatistics/WebStatsModule.cs b/OpenSim/Region/OptionalModules/UserStatistics/WebStatsModule.cs
new file mode 100644
index 0000000..bcb6361
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/UserStatistics/WebStatsModule.cs
@@ -0,0 +1,1203 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.IO;
32using System.Net; // to be used for REST-->Grid shortly
33using System.Reflection;
34using System.Text;
35using System.Threading;
36using log4net;
37using Nini.Config;
38using OpenMetaverse;
39using OpenMetaverse.StructuredData;
40using OpenSim.Framework;
41using OpenSim.Framework.Servers;
42using OpenSim.Framework.Servers.HttpServer;
43using OpenSim.Region.Framework.Interfaces;
44using OpenSim.Region.Framework.Scenes;
45using Mono.Data.SqliteClient;
46using Mono.Addins;
47
48using Caps = OpenSim.Framework.Capabilities.Caps;
49
50using OSD = OpenMetaverse.StructuredData.OSD;
51using OSDMap = OpenMetaverse.StructuredData.OSDMap;
52
53namespace OpenSim.Region.UserStatistics
54{
55 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "WebStatsModule")]
56 public class WebStatsModule : ISharedRegionModule
57 {
58 private static readonly ILog m_log =
59 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
60
61 private static SqliteConnection dbConn;
62
63 /// <summary>
64 /// User statistics sessions keyed by agent ID
65 /// </summary>
66 private Dictionary<UUID, UserSession> m_sessions = new Dictionary<UUID, UserSession>();
67
68 private List<Scene> m_scenes = new List<Scene>();
69 private Dictionary<string, IStatsController> reports = new Dictionary<string, IStatsController>();
70 private Dictionary<UUID, USimStatsData> m_simstatsCounters = new Dictionary<UUID, USimStatsData>();
71 private const int updateStatsMod = 6;
72 private int updateLogMod = 1;
73 private volatile int updateLogCounter = 0;
74 private volatile int concurrencyCounter = 0;
75 private bool enabled = false;
76 private string m_loglines = String.Empty;
77 private volatile int lastHit = 12000;
78
79 #region ISharedRegionModule
80
81 public virtual void Initialise(IConfigSource config)
82 {
83 IConfig cnfg = config.Configs["WebStats"];
84
85 if (cnfg != null)
86 enabled = cnfg.GetBoolean("enabled", false);
87 }
88
89 public virtual void PostInitialise()
90 {
91 if (!enabled)
92 return;
93
94 if (Util.IsWindows())
95 Util.LoadArchSpecificWindowsDll("sqlite3.dll");
96
97 //IConfig startupConfig = config.Configs["Startup"];
98
99 dbConn = new SqliteConnection("URI=file:LocalUserStatistics.db,version=3");
100 dbConn.Open();
101 CreateTables(dbConn);
102
103 Prototype_distributor protodep = new Prototype_distributor();
104 Updater_distributor updatedep = new Updater_distributor();
105 ActiveConnectionsAJAX ajConnections = new ActiveConnectionsAJAX();
106 SimStatsAJAX ajSimStats = new SimStatsAJAX();
107 LogLinesAJAX ajLogLines = new LogLinesAJAX();
108 Default_Report defaultReport = new Default_Report();
109 Clients_report clientReport = new Clients_report();
110 Sessions_Report sessionsReport = new Sessions_Report();
111
112 reports.Add("prototype.js", protodep);
113 reports.Add("updater.js", updatedep);
114 reports.Add("activeconnectionsajax.html", ajConnections);
115 reports.Add("simstatsajax.html", ajSimStats);
116 reports.Add("activelogajax.html", ajLogLines);
117 reports.Add("default.report", defaultReport);
118 reports.Add("clients.report", clientReport);
119 reports.Add("sessions.report", sessionsReport);
120
121 reports.Add("sim.css", new Prototype_distributor("sim.css"));
122 reports.Add("sim.html", new Prototype_distributor("sim.html"));
123 reports.Add("jquery.js", new Prototype_distributor("jquery.js"));
124
125 ////
126 // Add Your own Reports here (Do Not Modify Lines here Devs!)
127 ////
128
129 ////
130 // End Own reports section
131 ////
132
133 MainServer.Instance.AddHTTPHandler("/SStats/", HandleStatsRequest);
134 MainServer.Instance.AddHTTPHandler("/CAPS/VS/", HandleUnknownCAPSRequest);
135 }
136
137 public virtual void AddRegion(Scene scene)
138 {
139 if (!enabled)
140 return;
141
142 lock (m_scenes)
143 {
144 m_scenes.Add(scene);
145 updateLogMod = m_scenes.Count * 2;
146
147 m_simstatsCounters.Add(scene.RegionInfo.RegionID, new USimStatsData(scene.RegionInfo.RegionID));
148
149 scene.EventManager.OnRegisterCaps += OnRegisterCaps;
150 scene.EventManager.OnDeregisterCaps += OnDeRegisterCaps;
151 scene.EventManager.OnClientClosed += OnClientClosed;
152 scene.EventManager.OnMakeRootAgent += OnMakeRootAgent;
153 scene.StatsReporter.OnSendStatsResult += ReceiveClassicSimStatsPacket;
154 }
155 }
156
157 public void RegionLoaded(Scene scene)
158 {
159 }
160
161 public void RemoveRegion(Scene scene)
162 {
163 if (!enabled)
164 return;
165
166 lock (m_scenes)
167 {
168 m_scenes.Remove(scene);
169 updateLogMod = m_scenes.Count * 2;
170 m_simstatsCounters.Remove(scene.RegionInfo.RegionID);
171 }
172 }
173
174 public virtual void Close()
175 {
176 if (!enabled)
177 return;
178
179 dbConn.Close();
180 dbConn.Dispose();
181 m_sessions.Clear();
182 m_scenes.Clear();
183 reports.Clear();
184 m_simstatsCounters.Clear();
185 }
186
187 public virtual string Name
188 {
189 get { return "ViewerStatsModule"; }
190 }
191
192 public Type ReplaceableInterface
193 {
194 get { return null; }
195 }
196
197 #endregion
198
199 private void ReceiveClassicSimStatsPacket(SimStats stats)
200 {
201 if (!enabled)
202 return;
203
204 try
205 {
206 // Ignore the update if there's a report running right now
207 // ignore the update if there hasn't been a hit in 30 seconds.
208 if (concurrencyCounter > 0 || System.Environment.TickCount - lastHit > 30000)
209 return;
210
211 // We will conduct this under lock so that fields such as updateLogCounter do not potentially get
212 // confused if a scene is removed.
213 // XXX: Possibly the scope of this lock could be reduced though it's not critical.
214 lock (m_scenes)
215 {
216 if (updateLogMod != 0 && updateLogCounter++ % updateLogMod == 0)
217 {
218 m_loglines = readLogLines(10);
219
220 if (updateLogCounter > 10000)
221 updateLogCounter = 1;
222 }
223
224 USimStatsData ss = m_simstatsCounters[stats.RegionUUID];
225
226 if ((++ss.StatsCounter % updateStatsMod) == 0)
227 {
228 ss.ConsumeSimStats(stats);
229 }
230 }
231 }
232 catch (KeyNotFoundException)
233 {
234 }
235 }
236
237 private Hashtable HandleUnknownCAPSRequest(Hashtable request)
238 {
239 //string regpath = request["uri"].ToString();
240 int response_code = 200;
241 string contenttype = "text/html";
242 UpdateUserStats(ParseViewerStats(request["body"].ToString(), UUID.Zero), dbConn);
243 Hashtable responsedata = new Hashtable();
244
245 responsedata["int_response_code"] = response_code;
246 responsedata["content_type"] = contenttype;
247 responsedata["keepalive"] = false;
248 responsedata["str_response_string"] = string.Empty;
249 return responsedata;
250 }
251
252 private Hashtable HandleStatsRequest(Hashtable request)
253 {
254 lastHit = System.Environment.TickCount;
255 Hashtable responsedata = new Hashtable();
256 string regpath = request["uri"].ToString();
257 int response_code = 404;
258 string contenttype = "text/html";
259 bool jsonFormatOutput = false;
260
261 string strOut = string.Empty;
262
263 // The request patch should be "/SStats/reportName" where 'reportName'
264 // is one of the names added to the 'reports' hashmap.
265 regpath = regpath.Remove(0, 8);
266 if (regpath.Length == 0) regpath = "default.report";
267 if (reports.ContainsKey(regpath))
268 {
269 IStatsController rep = reports[regpath];
270 Hashtable repParams = new Hashtable();
271
272 if (request.ContainsKey("json"))
273 jsonFormatOutput = true;
274
275 if (request.ContainsKey("requestvars"))
276 repParams["RequestVars"] = request["requestvars"];
277 else
278 repParams["RequestVars"] = new Hashtable();
279
280 if (request.ContainsKey("querystringkeys"))
281 repParams["QueryStringKeys"] = request["querystringkeys"];
282 else
283 repParams["QueryStringKeys"] = new string[0];
284
285
286 repParams["DatabaseConnection"] = dbConn;
287 repParams["Scenes"] = m_scenes;
288 repParams["SimStats"] = m_simstatsCounters;
289 repParams["LogLines"] = m_loglines;
290 repParams["Reports"] = reports;
291
292 concurrencyCounter++;
293
294 if (jsonFormatOutput)
295 {
296 strOut = rep.RenderJson(rep.ProcessModel(repParams));
297 contenttype = "text/json";
298 }
299 else
300 {
301 strOut = rep.RenderView(rep.ProcessModel(repParams));
302 }
303
304 if (regpath.EndsWith("js"))
305 {
306 contenttype = "text/javascript";
307 }
308
309 if (regpath.EndsWith("css"))
310 {
311 contenttype = "text/css";
312 }
313
314 concurrencyCounter--;
315
316 response_code = 200;
317 }
318 else
319 {
320 strOut = MainServer.Instance.GetHTTP404("");
321 }
322
323 responsedata["int_response_code"] = response_code;
324 responsedata["content_type"] = contenttype;
325 responsedata["keepalive"] = false;
326 responsedata["str_response_string"] = strOut;
327
328 return responsedata;
329 }
330
331 private void CreateTables(SqliteConnection db)
332 {
333 using (SqliteCommand createcmd = new SqliteCommand(SQL_STATS_TABLE_CREATE, db))
334 {
335 createcmd.ExecuteNonQuery();
336 }
337 }
338
339 private void OnRegisterCaps(UUID agentID, Caps caps)
340 {
341// m_log.DebugFormat("[WEB STATS MODULE]: OnRegisterCaps: agentID {0} caps {1}", agentID, caps);
342
343 string capsPath = "/CAPS/VS/" + UUID.Random();
344 caps.RegisterHandler(
345 "ViewerStats",
346 new RestStreamHandler(
347 "POST",
348 capsPath,
349 (request, path, param, httpRequest, httpResponse)
350 => ViewerStatsReport(request, path, param, agentID, caps),
351 "ViewerStats",
352 agentID.ToString()));
353 }
354
355 private void OnDeRegisterCaps(UUID agentID, Caps caps)
356 {
357 }
358
359 protected virtual void AddEventHandlers()
360 {
361 lock (m_scenes)
362 {
363 updateLogMod = m_scenes.Count * 2;
364 foreach (Scene scene in m_scenes)
365 {
366 scene.EventManager.OnRegisterCaps += OnRegisterCaps;
367 scene.EventManager.OnDeregisterCaps += OnDeRegisterCaps;
368 scene.EventManager.OnClientClosed += OnClientClosed;
369 scene.EventManager.OnMakeRootAgent += OnMakeRootAgent;
370 }
371 }
372 }
373
374 private void OnMakeRootAgent(ScenePresence agent)
375 {
376// m_log.DebugFormat(
377// "[WEB STATS MODULE]: Looking for session {0} for {1} in {2}",
378// agent.ControllingClient.SessionId, agent.Name, agent.Scene.Name);
379
380 lock (m_sessions)
381 {
382 UserSession uid;
383
384 if (!m_sessions.ContainsKey(agent.UUID))
385 {
386 UserSessionData usd = UserSessionUtil.newUserSessionData();
387 uid = new UserSession();
388 uid.name_f = agent.Firstname;
389 uid.name_l = agent.Lastname;
390 uid.session_data = usd;
391
392 m_sessions.Add(agent.UUID, uid);
393 }
394 else
395 {
396 uid = m_sessions[agent.UUID];
397 }
398
399 uid.region_id = agent.Scene.RegionInfo.RegionID;
400 uid.session_id = agent.ControllingClient.SessionId;
401 }
402 }
403
404 private void OnClientClosed(UUID agentID, Scene scene)
405 {
406 lock (m_sessions)
407 {
408 if (m_sessions.ContainsKey(agentID) && m_sessions[agentID].region_id == scene.RegionInfo.RegionID)
409 {
410 m_sessions.Remove(agentID);
411 }
412 }
413 }
414
415 private string readLogLines(int amount)
416 {
417 Encoding encoding = Encoding.ASCII;
418 int sizeOfChar = encoding.GetByteCount("\n");
419 byte[] buffer = encoding.GetBytes("\n");
420 string logfile = Util.logFile();
421 FileStream fs = new FileStream(logfile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
422 Int64 tokenCount = 0;
423 Int64 endPosition = fs.Length / sizeOfChar;
424
425 for (Int64 position = sizeOfChar; position < endPosition; position += sizeOfChar)
426 {
427 fs.Seek(-position, SeekOrigin.End);
428 fs.Read(buffer, 0, buffer.Length);
429
430 if (encoding.GetString(buffer) == "\n")
431 {
432 tokenCount++;
433 if (tokenCount == amount)
434 {
435 byte[] returnBuffer = new byte[fs.Length - fs.Position];
436 fs.Read(returnBuffer, 0, returnBuffer.Length);
437 fs.Close();
438 fs.Dispose();
439 return encoding.GetString(returnBuffer);
440 }
441 }
442 }
443
444 // handle case where number of tokens in file is less than numberOfTokens
445 fs.Seek(0, SeekOrigin.Begin);
446 buffer = new byte[fs.Length];
447 fs.Read(buffer, 0, buffer.Length);
448 fs.Close();
449 fs.Dispose();
450 return encoding.GetString(buffer);
451 }
452
453 /// <summary>
454 /// Callback for a viewerstats cap
455 /// </summary>
456 /// <param name="request"></param>
457 /// <param name="path"></param>
458 /// <param name="param"></param>
459 /// <param name="agentID"></param>
460 /// <param name="caps"></param>
461 /// <returns></returns>
462 private string ViewerStatsReport(string request, string path, string param,
463 UUID agentID, Caps caps)
464 {
465// m_log.DebugFormat("[WEB STATS MODULE]: Received viewer starts report from {0}", agentID);
466
467 UpdateUserStats(ParseViewerStats(request, agentID), dbConn);
468
469 return String.Empty;
470 }
471
472 private UserSession ParseViewerStats(string request, UUID agentID)
473 {
474 UserSession uid = new UserSession();
475 UserSessionData usd;
476 OSD message = OSDParser.DeserializeLLSDXml(request);
477 OSDMap mmap;
478
479 lock (m_sessions)
480 {
481 if (agentID != UUID.Zero)
482 {
483 if (!m_sessions.ContainsKey(agentID))
484 {
485 m_log.WarnFormat("[WEB STATS MODULE]: no session for stat disclosure for agent {0}", agentID);
486 return new UserSession();
487 }
488
489 uid = m_sessions[agentID];
490
491// m_log.DebugFormat("[WEB STATS MODULE]: Got session {0} for {1}", uid.session_id, agentID);
492 }
493 else
494 {
495 // parse through the beginning to locate the session
496 if (message.Type != OSDType.Map)
497 return new UserSession();
498
499 mmap = (OSDMap)message;
500 {
501 UUID sessionID = mmap["session_id"].AsUUID();
502
503 if (sessionID == UUID.Zero)
504 return new UserSession();
505
506
507 // search through each session looking for the owner
508 foreach (UUID usersessionid in m_sessions.Keys)
509 {
510 // got it!
511 if (m_sessions[usersessionid].session_id == sessionID)
512 {
513 agentID = usersessionid;
514 uid = m_sessions[usersessionid];
515 break;
516 }
517
518 }
519
520 // can't find a session
521 if (agentID == UUID.Zero)
522 {
523 return new UserSession();
524 }
525 }
526 }
527 }
528
529 usd = uid.session_data;
530
531 if (message.Type != OSDType.Map)
532 return new UserSession();
533
534 mmap = (OSDMap)message;
535 {
536 if (mmap["agent"].Type != OSDType.Map)
537 return new UserSession();
538 OSDMap agent_map = (OSDMap)mmap["agent"];
539 usd.agent_id = agentID;
540 usd.name_f = uid.name_f;
541 usd.name_l = uid.name_l;
542 usd.region_id = uid.region_id;
543 usd.a_language = agent_map["language"].AsString();
544 usd.mem_use = (float)agent_map["mem_use"].AsReal();
545 usd.meters_traveled = (float)agent_map["meters_traveled"].AsReal();
546 usd.regions_visited = agent_map["regions_visited"].AsInteger();
547 usd.run_time = (float)agent_map["run_time"].AsReal();
548 usd.start_time = (float)agent_map["start_time"].AsReal();
549 usd.client_version = agent_map["version"].AsString();
550
551 UserSessionUtil.UpdateMultiItems(ref usd, agent_map["agents_in_view"].AsInteger(),
552 (float)agent_map["ping"].AsReal(),
553 (float)agent_map["sim_fps"].AsReal(),
554 (float)agent_map["fps"].AsReal());
555
556 if (mmap["downloads"].Type != OSDType.Map)
557 return new UserSession();
558 OSDMap downloads_map = (OSDMap)mmap["downloads"];
559 usd.d_object_kb = (float)downloads_map["object_kbytes"].AsReal();
560 usd.d_texture_kb = (float)downloads_map["texture_kbytes"].AsReal();
561 usd.d_world_kb = (float)downloads_map["workd_kbytes"].AsReal();
562
563// m_log.DebugFormat("[WEB STATS MODULE]: mmap[\"session_id\"] = [{0}]", mmap["session_id"].AsUUID());
564
565 usd.session_id = mmap["session_id"].AsUUID();
566
567 if (mmap["system"].Type != OSDType.Map)
568 return new UserSession();
569 OSDMap system_map = (OSDMap)mmap["system"];
570
571 usd.s_cpu = system_map["cpu"].AsString();
572 usd.s_gpu = system_map["gpu"].AsString();
573 usd.s_os = system_map["os"].AsString();
574 usd.s_ram = system_map["ram"].AsInteger();
575
576 if (mmap["stats"].Type != OSDType.Map)
577 return new UserSession();
578
579 OSDMap stats_map = (OSDMap)mmap["stats"];
580 {
581
582 if (stats_map["failures"].Type != OSDType.Map)
583 return new UserSession();
584 OSDMap stats_failures = (OSDMap)stats_map["failures"];
585 usd.f_dropped = stats_failures["dropped"].AsInteger();
586 usd.f_failed_resends = stats_failures["failed_resends"].AsInteger();
587 usd.f_invalid = stats_failures["invalid"].AsInteger();
588 usd.f_resent = stats_failures["resent"].AsInteger();
589 usd.f_send_packet = stats_failures["send_packet"].AsInteger();
590
591 if (stats_map["net"].Type != OSDType.Map)
592 return new UserSession();
593 OSDMap stats_net = (OSDMap)stats_map["net"];
594 {
595 if (stats_net["in"].Type != OSDType.Map)
596 return new UserSession();
597
598 OSDMap net_in = (OSDMap)stats_net["in"];
599 usd.n_in_kb = (float)net_in["kbytes"].AsReal();
600 usd.n_in_pk = net_in["packets"].AsInteger();
601
602 if (stats_net["out"].Type != OSDType.Map)
603 return new UserSession();
604 OSDMap net_out = (OSDMap)stats_net["out"];
605
606 usd.n_out_kb = (float)net_out["kbytes"].AsReal();
607 usd.n_out_pk = net_out["packets"].AsInteger();
608 }
609 }
610 }
611
612 uid.session_data = usd;
613 m_sessions[agentID] = uid;
614
615// m_log.DebugFormat(
616// "[WEB STATS MODULE]: Parse data for {0} {1}, session {2}", uid.name_f, uid.name_l, uid.session_id);
617
618 return uid;
619 }
620
621 private void UpdateUserStats(UserSession uid, SqliteConnection db)
622 {
623// m_log.DebugFormat(
624// "[WEB STATS MODULE]: Updating user stats for {0} {1}, session {2}", uid.name_f, uid.name_l, uid.session_id);
625
626 if (uid.session_id == UUID.Zero)
627 return;
628
629 lock (db)
630 {
631 using (SqliteCommand updatecmd = new SqliteCommand(SQL_STATS_TABLE_INSERT, db))
632 {
633 updatecmd.Parameters.Add(new SqliteParameter(":session_id", uid.session_data.session_id.ToString()));
634 updatecmd.Parameters.Add(new SqliteParameter(":agent_id", uid.session_data.agent_id.ToString()));
635 updatecmd.Parameters.Add(new SqliteParameter(":region_id", uid.session_data.region_id.ToString()));
636 updatecmd.Parameters.Add(new SqliteParameter(":last_updated", (int) uid.session_data.last_updated));
637 updatecmd.Parameters.Add(new SqliteParameter(":remote_ip", uid.session_data.remote_ip));
638 updatecmd.Parameters.Add(new SqliteParameter(":name_f", uid.session_data.name_f));
639 updatecmd.Parameters.Add(new SqliteParameter(":name_l", uid.session_data.name_l));
640 updatecmd.Parameters.Add(new SqliteParameter(":avg_agents_in_view", uid.session_data.avg_agents_in_view));
641 updatecmd.Parameters.Add(new SqliteParameter(":min_agents_in_view",
642 (int) uid.session_data.min_agents_in_view));
643 updatecmd.Parameters.Add(new SqliteParameter(":max_agents_in_view",
644 (int) uid.session_data.max_agents_in_view));
645 updatecmd.Parameters.Add(new SqliteParameter(":mode_agents_in_view",
646 (int) uid.session_data.mode_agents_in_view));
647 updatecmd.Parameters.Add(new SqliteParameter(":avg_fps", uid.session_data.avg_fps));
648 updatecmd.Parameters.Add(new SqliteParameter(":min_fps", uid.session_data.min_fps));
649 updatecmd.Parameters.Add(new SqliteParameter(":max_fps", uid.session_data.max_fps));
650 updatecmd.Parameters.Add(new SqliteParameter(":mode_fps", uid.session_data.mode_fps));
651 updatecmd.Parameters.Add(new SqliteParameter(":a_language", uid.session_data.a_language));
652 updatecmd.Parameters.Add(new SqliteParameter(":mem_use", uid.session_data.mem_use));
653 updatecmd.Parameters.Add(new SqliteParameter(":meters_traveled", uid.session_data.meters_traveled));
654 updatecmd.Parameters.Add(new SqliteParameter(":avg_ping", uid.session_data.avg_ping));
655 updatecmd.Parameters.Add(new SqliteParameter(":min_ping", uid.session_data.min_ping));
656 updatecmd.Parameters.Add(new SqliteParameter(":max_ping", uid.session_data.max_ping));
657 updatecmd.Parameters.Add(new SqliteParameter(":mode_ping", uid.session_data.mode_ping));
658 updatecmd.Parameters.Add(new SqliteParameter(":regions_visited", uid.session_data.regions_visited));
659 updatecmd.Parameters.Add(new SqliteParameter(":run_time", uid.session_data.run_time));
660 updatecmd.Parameters.Add(new SqliteParameter(":avg_sim_fps", uid.session_data.avg_sim_fps));
661 updatecmd.Parameters.Add(new SqliteParameter(":min_sim_fps", uid.session_data.min_sim_fps));
662 updatecmd.Parameters.Add(new SqliteParameter(":max_sim_fps", uid.session_data.max_sim_fps));
663 updatecmd.Parameters.Add(new SqliteParameter(":mode_sim_fps", uid.session_data.mode_sim_fps));
664 updatecmd.Parameters.Add(new SqliteParameter(":start_time", uid.session_data.start_time));
665 updatecmd.Parameters.Add(new SqliteParameter(":client_version", uid.session_data.client_version));
666 updatecmd.Parameters.Add(new SqliteParameter(":s_cpu", uid.session_data.s_cpu));
667 updatecmd.Parameters.Add(new SqliteParameter(":s_gpu", uid.session_data.s_gpu));
668 updatecmd.Parameters.Add(new SqliteParameter(":s_os", uid.session_data.s_os));
669 updatecmd.Parameters.Add(new SqliteParameter(":s_ram", uid.session_data.s_ram));
670 updatecmd.Parameters.Add(new SqliteParameter(":d_object_kb", uid.session_data.d_object_kb));
671 updatecmd.Parameters.Add(new SqliteParameter(":d_texture_kb", uid.session_data.d_texture_kb));
672 updatecmd.Parameters.Add(new SqliteParameter(":d_world_kb", uid.session_data.d_world_kb));
673 updatecmd.Parameters.Add(new SqliteParameter(":n_in_kb", uid.session_data.n_in_kb));
674 updatecmd.Parameters.Add(new SqliteParameter(":n_in_pk", uid.session_data.n_in_pk));
675 updatecmd.Parameters.Add(new SqliteParameter(":n_out_kb", uid.session_data.n_out_kb));
676 updatecmd.Parameters.Add(new SqliteParameter(":n_out_pk", uid.session_data.n_out_pk));
677 updatecmd.Parameters.Add(new SqliteParameter(":f_dropped", uid.session_data.f_dropped));
678 updatecmd.Parameters.Add(new SqliteParameter(":f_failed_resends", uid.session_data.f_failed_resends));
679 updatecmd.Parameters.Add(new SqliteParameter(":f_invalid", uid.session_data.f_invalid));
680 updatecmd.Parameters.Add(new SqliteParameter(":f_off_circuit", uid.session_data.f_off_circuit));
681 updatecmd.Parameters.Add(new SqliteParameter(":f_resent", uid.session_data.f_resent));
682 updatecmd.Parameters.Add(new SqliteParameter(":f_send_packet", uid.session_data.f_send_packet));
683
684// StringBuilder parameters = new StringBuilder();
685// SqliteParameterCollection spc = updatecmd.Parameters;
686// foreach (SqliteParameter sp in spc)
687// parameters.AppendFormat("{0}={1},", sp.ParameterName, sp.Value);
688//
689// m_log.DebugFormat("[WEB STATS MODULE]: Parameters {0}", parameters);
690
691// m_log.DebugFormat("[WEB STATS MODULE]: Database stats update for {0}", uid.session_data.agent_id);
692
693 updatecmd.ExecuteNonQuery();
694 }
695 }
696 }
697
698 #region SQL
699 private const string SQL_STATS_TABLE_CREATE = @"CREATE TABLE IF NOT EXISTS stats_session_data (
700 session_id VARCHAR(36) NOT NULL PRIMARY KEY,
701 agent_id VARCHAR(36) NOT NULL DEFAULT '',
702 region_id VARCHAR(36) NOT NULL DEFAULT '',
703 last_updated INT NOT NULL DEFAULT '0',
704 remote_ip VARCHAR(16) NOT NULL DEFAULT '',
705 name_f VARCHAR(50) NOT NULL DEFAULT '',
706 name_l VARCHAR(50) NOT NULL DEFAULT '',
707 avg_agents_in_view FLOAT NOT NULL DEFAULT '0',
708 min_agents_in_view INT NOT NULL DEFAULT '0',
709 max_agents_in_view INT NOT NULL DEFAULT '0',
710 mode_agents_in_view INT NOT NULL DEFAULT '0',
711 avg_fps FLOAT NOT NULL DEFAULT '0',
712 min_fps FLOAT NOT NULL DEFAULT '0',
713 max_fps FLOAT NOT NULL DEFAULT '0',
714 mode_fps FLOAT NOT NULL DEFAULT '0',
715 a_language VARCHAR(25) NOT NULL DEFAULT '',
716 mem_use FLOAT NOT NULL DEFAULT '0',
717 meters_traveled FLOAT NOT NULL DEFAULT '0',
718 avg_ping FLOAT NOT NULL DEFAULT '0',
719 min_ping FLOAT NOT NULL DEFAULT '0',
720 max_ping FLOAT NOT NULL DEFAULT '0',
721 mode_ping FLOAT NOT NULL DEFAULT '0',
722 regions_visited INT NOT NULL DEFAULT '0',
723 run_time FLOAT NOT NULL DEFAULT '0',
724 avg_sim_fps FLOAT NOT NULL DEFAULT '0',
725 min_sim_fps FLOAT NOT NULL DEFAULT '0',
726 max_sim_fps FLOAT NOT NULL DEFAULT '0',
727 mode_sim_fps FLOAT NOT NULL DEFAULT '0',
728 start_time FLOAT NOT NULL DEFAULT '0',
729 client_version VARCHAR(255) NOT NULL DEFAULT '',
730 s_cpu VARCHAR(255) NOT NULL DEFAULT '',
731 s_gpu VARCHAR(255) NOT NULL DEFAULT '',
732 s_os VARCHAR(2255) NOT NULL DEFAULT '',
733 s_ram INT NOT NULL DEFAULT '0',
734 d_object_kb FLOAT NOT NULL DEFAULT '0',
735 d_texture_kb FLOAT NOT NULL DEFAULT '0',
736 d_world_kb FLOAT NOT NULL DEFAULT '0',
737 n_in_kb FLOAT NOT NULL DEFAULT '0',
738 n_in_pk INT NOT NULL DEFAULT '0',
739 n_out_kb FLOAT NOT NULL DEFAULT '0',
740 n_out_pk INT NOT NULL DEFAULT '0',
741 f_dropped INT NOT NULL DEFAULT '0',
742 f_failed_resends INT NOT NULL DEFAULT '0',
743 f_invalid INT NOT NULL DEFAULT '0',
744 f_off_circuit INT NOT NULL DEFAULT '0',
745 f_resent INT NOT NULL DEFAULT '0',
746 f_send_packet INT NOT NULL DEFAULT '0'
747 );";
748
749 private const string SQL_STATS_TABLE_INSERT = @"INSERT OR REPLACE INTO stats_session_data (
750session_id, agent_id, region_id, last_updated, remote_ip, name_f, name_l, avg_agents_in_view, min_agents_in_view, max_agents_in_view,
751mode_agents_in_view, avg_fps, min_fps, max_fps, mode_fps, a_language, mem_use, meters_traveled, avg_ping, min_ping, max_ping, mode_ping,
752regions_visited, run_time, avg_sim_fps, min_sim_fps, max_sim_fps, mode_sim_fps, start_time, client_version, s_cpu, s_gpu, s_os, s_ram,
753d_object_kb, d_texture_kb, d_world_kb, n_in_kb, n_in_pk, n_out_kb, n_out_pk, f_dropped, f_failed_resends, f_invalid, f_off_circuit,
754f_resent, f_send_packet
755)
756VALUES
757(
758:session_id, :agent_id, :region_id, :last_updated, :remote_ip, :name_f, :name_l, :avg_agents_in_view, :min_agents_in_view, :max_agents_in_view,
759:mode_agents_in_view, :avg_fps, :min_fps, :max_fps, :mode_fps, :a_language, :mem_use, :meters_traveled, :avg_ping, :min_ping, :max_ping, :mode_ping,
760:regions_visited, :run_time, :avg_sim_fps, :min_sim_fps, :max_sim_fps, :mode_sim_fps, :start_time, :client_version, :s_cpu, :s_gpu, :s_os, :s_ram,
761:d_object_kb, :d_texture_kb, :d_world_kb, :n_in_kb, :n_in_pk, :n_out_kb, :n_out_pk, :f_dropped, :f_failed_resends, :f_invalid, :f_off_circuit,
762:f_resent, :f_send_packet
763)
764";
765
766 #endregion
767
768 }
769
770 public static class UserSessionUtil
771 {
772 public static UserSessionData newUserSessionData()
773 {
774 UserSessionData obj = ZeroSession(new UserSessionData());
775 return obj;
776 }
777
778 public static void UpdateMultiItems(ref UserSessionData s, int agents_in_view, float ping, float sim_fps, float fps)
779 {
780 // don't insert zero values here or it'll skew the statistics.
781 if (agents_in_view == 0 && fps == 0 && sim_fps == 0 && ping == 0)
782 return;
783 s._agents_in_view.Add(agents_in_view);
784 s._fps.Add(fps);
785 s._sim_fps.Add(sim_fps);
786 s._ping.Add(ping);
787
788 int[] __agents_in_view = s._agents_in_view.ToArray();
789
790 s.avg_agents_in_view = ArrayAvg_i(__agents_in_view);
791 s.min_agents_in_view = ArrayMin_i(__agents_in_view);
792 s.max_agents_in_view = ArrayMax_i(__agents_in_view);
793 s.mode_agents_in_view = ArrayMode_i(__agents_in_view);
794
795 float[] __fps = s._fps.ToArray();
796 s.avg_fps = ArrayAvg_f(__fps);
797 s.min_fps = ArrayMin_f(__fps);
798 s.max_fps = ArrayMax_f(__fps);
799 s.mode_fps = ArrayMode_f(__fps);
800
801 float[] __sim_fps = s._sim_fps.ToArray();
802 s.avg_sim_fps = ArrayAvg_f(__sim_fps);
803 s.min_sim_fps = ArrayMin_f(__sim_fps);
804 s.max_sim_fps = ArrayMax_f(__sim_fps);
805 s.mode_sim_fps = ArrayMode_f(__sim_fps);
806
807 float[] __ping = s._ping.ToArray();
808 s.avg_ping = ArrayAvg_f(__ping);
809 s.min_ping = ArrayMin_f(__ping);
810 s.max_ping = ArrayMax_f(__ping);
811 s.mode_ping = ArrayMode_f(__ping);
812 }
813
814 #region Statistics
815
816 public static int ArrayMin_i(int[] arr)
817 {
818 int cnt = arr.Length;
819 if (cnt == 0)
820 return 0;
821
822 Array.Sort(arr);
823 return arr[0];
824 }
825
826 public static int ArrayMax_i(int[] arr)
827 {
828 int cnt = arr.Length;
829 if (cnt == 0)
830 return 0;
831
832 Array.Sort(arr);
833 return arr[cnt-1];
834 }
835
836 public static float ArrayMin_f(float[] arr)
837 {
838 int cnt = arr.Length;
839 if (cnt == 0)
840 return 0;
841
842 Array.Sort(arr);
843 return arr[0];
844 }
845
846 public static float ArrayMax_f(float[] arr)
847 {
848 int cnt = arr.Length;
849 if (cnt == 0)
850 return 0;
851
852 Array.Sort(arr);
853 return arr[cnt - 1];
854 }
855
856 public static float ArrayAvg_i(int[] arr)
857 {
858 int cnt = arr.Length;
859
860 if (cnt == 0)
861 return 0;
862
863 float result = arr[0];
864
865 for (int i = 1; i < cnt; i++)
866 result += arr[i];
867
868 return result / cnt;
869 }
870
871 public static float ArrayAvg_f(float[] arr)
872 {
873 int cnt = arr.Length;
874
875 if (cnt == 0)
876 return 0;
877
878 float result = arr[0];
879
880 for (int i = 1; i < cnt; i++)
881 result += arr[i];
882
883 return result / cnt;
884 }
885
886 public static float ArrayMode_f(float[] arr)
887 {
888 List<float> mode = new List<float>();
889
890 float[] srtArr = new float[arr.Length];
891 float[,] freq = new float[arr.Length, 2];
892 Array.Copy(arr, srtArr, arr.Length);
893 Array.Sort(srtArr);
894
895 float tmp = srtArr[0];
896 int index = 0;
897 int i = 0;
898 while (i < srtArr.Length)
899 {
900 freq[index, 0] = tmp;
901
902 while (tmp == srtArr[i])
903 {
904 freq[index, 1]++;
905 i++;
906
907 if (i > srtArr.Length - 1)
908 break;
909 }
910
911 if (i < srtArr.Length)
912 {
913 tmp = srtArr[i];
914 index++;
915 }
916
917 }
918
919 Array.Clear(srtArr, 0, srtArr.Length);
920
921 for (i = 0; i < srtArr.Length; i++)
922 srtArr[i] = freq[i, 1];
923
924 Array.Sort(srtArr);
925
926 if ((srtArr[srtArr.Length - 1]) == 0 || (srtArr[srtArr.Length - 1]) == 1)
927 return 0;
928
929 float freqtest = (float)freq.Length / freq.Rank;
930
931 for (i = 0; i < freqtest; i++)
932 {
933 if (freq[i, 1] == srtArr[index])
934 mode.Add(freq[i, 0]);
935
936 }
937
938 return mode.ToArray()[0];
939 }
940
941 public static int ArrayMode_i(int[] arr)
942 {
943 List<int> mode = new List<int>();
944
945 int[] srtArr = new int[arr.Length];
946 int[,] freq = new int[arr.Length, 2];
947 Array.Copy(arr, srtArr, arr.Length);
948 Array.Sort(srtArr);
949
950 int tmp = srtArr[0];
951 int index = 0;
952 int i = 0;
953 while (i < srtArr.Length)
954 {
955 freq[index, 0] = tmp;
956
957 while (tmp == srtArr[i])
958 {
959 freq[index, 1]++;
960 i++;
961
962 if (i > srtArr.Length - 1)
963 break;
964 }
965
966 if (i < srtArr.Length)
967 {
968 tmp = srtArr[i];
969 index++;
970 }
971
972 }
973
974 Array.Clear(srtArr, 0, srtArr.Length);
975
976 for (i = 0; i < srtArr.Length; i++)
977 srtArr[i] = freq[i, 1];
978
979 Array.Sort(srtArr);
980
981 if ((srtArr[srtArr.Length - 1]) == 0 || (srtArr[srtArr.Length - 1]) == 1)
982 return 0;
983
984 float freqtest = (float)freq.Length / freq.Rank;
985
986 for (i = 0; i < freqtest; i++)
987 {
988 if (freq[i, 1] == srtArr[index])
989 mode.Add(freq[i, 0]);
990
991 }
992
993 return mode.ToArray()[0];
994 }
995
996 #endregion
997
998 private static UserSessionData ZeroSession(UserSessionData s)
999 {
1000 s.session_id = UUID.Zero;
1001 s.agent_id = UUID.Zero;
1002 s.region_id = UUID.Zero;
1003 s.last_updated = Util.UnixTimeSinceEpoch();
1004 s.remote_ip = "";
1005 s.name_f = "";
1006 s.name_l = "";
1007 s.avg_agents_in_view = 0;
1008 s.min_agents_in_view = 0;
1009 s.max_agents_in_view = 0;
1010 s.mode_agents_in_view = 0;
1011 s.avg_fps = 0;
1012 s.min_fps = 0;
1013 s.max_fps = 0;
1014 s.mode_fps = 0;
1015 s.a_language = "";
1016 s.mem_use = 0;
1017 s.meters_traveled = 0;
1018 s.avg_ping = 0;
1019 s.min_ping = 0;
1020 s.max_ping = 0;
1021 s.mode_ping = 0;
1022 s.regions_visited = 0;
1023 s.run_time = 0;
1024 s.avg_sim_fps = 0;
1025 s.min_sim_fps = 0;
1026 s.max_sim_fps = 0;
1027 s.mode_sim_fps = 0;
1028 s.start_time = 0;
1029 s.client_version = "";
1030 s.s_cpu = "";
1031 s.s_gpu = "";
1032 s.s_os = "";
1033 s.s_ram = 0;
1034 s.d_object_kb = 0;
1035 s.d_texture_kb = 0;
1036 s.d_world_kb = 0;
1037 s.n_in_kb = 0;
1038 s.n_in_pk = 0;
1039 s.n_out_kb = 0;
1040 s.n_out_pk = 0;
1041 s.f_dropped = 0;
1042 s.f_failed_resends = 0;
1043 s.f_invalid = 0;
1044 s.f_off_circuit = 0;
1045 s.f_resent = 0;
1046 s.f_send_packet = 0;
1047 s._ping = new List<float>();
1048 s._fps = new List<float>();
1049 s._sim_fps = new List<float>();
1050 s._agents_in_view = new List<int>();
1051 return s;
1052 }
1053 }
1054 #region structs
1055
1056 public class UserSession
1057 {
1058 public UUID session_id;
1059 public UUID region_id;
1060 public string name_f;
1061 public string name_l;
1062 public UserSessionData session_data;
1063 }
1064
1065 public struct UserSessionData
1066 {
1067 public UUID session_id;
1068 public UUID agent_id;
1069 public UUID region_id;
1070 public float last_updated;
1071 public string remote_ip;
1072 public string name_f;
1073 public string name_l;
1074 public float avg_agents_in_view;
1075 public float min_agents_in_view;
1076 public float max_agents_in_view;
1077 public float mode_agents_in_view;
1078 public float avg_fps;
1079 public float min_fps;
1080 public float max_fps;
1081 public float mode_fps;
1082 public string a_language;
1083 public float mem_use;
1084 public float meters_traveled;
1085 public float avg_ping;
1086 public float min_ping;
1087 public float max_ping;
1088 public float mode_ping;
1089 public int regions_visited;
1090 public float run_time;
1091 public float avg_sim_fps;
1092 public float min_sim_fps;
1093 public float max_sim_fps;
1094 public float mode_sim_fps;
1095 public float start_time;
1096 public string client_version;
1097 public string s_cpu;
1098 public string s_gpu;
1099 public string s_os;
1100 public int s_ram;
1101 public float d_object_kb;
1102 public float d_texture_kb;
1103 public float d_world_kb;
1104 public float n_in_kb;
1105 public int n_in_pk;
1106 public float n_out_kb;
1107 public int n_out_pk;
1108 public int f_dropped;
1109 public int f_failed_resends;
1110 public int f_invalid;
1111 public int f_off_circuit;
1112 public int f_resent;
1113 public int f_send_packet;
1114 public List<float> _ping;
1115 public List<float> _fps;
1116 public List<float> _sim_fps;
1117 public List<int> _agents_in_view;
1118 }
1119
1120 #endregion
1121
1122 public class USimStatsData
1123 {
1124 private UUID m_regionID = UUID.Zero;
1125 private volatile int m_statcounter = 0;
1126 private volatile float m_timeDilation;
1127 private volatile float m_simFps;
1128 private volatile float m_physicsFps;
1129 private volatile float m_agentUpdates;
1130 private volatile float m_rootAgents;
1131 private volatile float m_childAgents;
1132 private volatile float m_totalPrims;
1133 private volatile float m_activePrims;
1134 private volatile float m_totalFrameTime;
1135 private volatile float m_netFrameTime;
1136 private volatile float m_physicsFrameTime;
1137 private volatile float m_otherFrameTime;
1138 private volatile float m_imageFrameTime;
1139 private volatile float m_inPacketsPerSecond;
1140 private volatile float m_outPacketsPerSecond;
1141 private volatile float m_unackedBytes;
1142 private volatile float m_agentFrameTime;
1143 private volatile float m_pendingDownloads;
1144 private volatile float m_pendingUploads;
1145 private volatile float m_activeScripts;
1146 private volatile float m_scriptLinesPerSecond;
1147
1148 public UUID RegionId { get { return m_regionID; } }
1149 public int StatsCounter { get { return m_statcounter; } set { m_statcounter = value;}}
1150 public float TimeDilation { get { return m_timeDilation; } }
1151 public float SimFps { get { return m_simFps; } }
1152 public float PhysicsFps { get { return m_physicsFps; } }
1153 public float AgentUpdates { get { return m_agentUpdates; } }
1154 public float RootAgents { get { return m_rootAgents; } }
1155 public float ChildAgents { get { return m_childAgents; } }
1156 public float TotalPrims { get { return m_totalPrims; } }
1157 public float ActivePrims { get { return m_activePrims; } }
1158 public float TotalFrameTime { get { return m_totalFrameTime; } }
1159 public float NetFrameTime { get { return m_netFrameTime; } }
1160 public float PhysicsFrameTime { get { return m_physicsFrameTime; } }
1161 public float OtherFrameTime { get { return m_otherFrameTime; } }
1162 public float ImageFrameTime { get { return m_imageFrameTime; } }
1163 public float InPacketsPerSecond { get { return m_inPacketsPerSecond; } }
1164 public float OutPacketsPerSecond { get { return m_outPacketsPerSecond; } }
1165 public float UnackedBytes { get { return m_unackedBytes; } }
1166 public float AgentFrameTime { get { return m_agentFrameTime; } }
1167 public float PendingDownloads { get { return m_pendingDownloads; } }
1168 public float PendingUploads { get { return m_pendingUploads; } }
1169 public float ActiveScripts { get { return m_activeScripts; } }
1170 public float ScriptLinesPerSecond { get { return m_scriptLinesPerSecond; } }
1171
1172 public USimStatsData(UUID pRegionID)
1173 {
1174 m_regionID = pRegionID;
1175 }
1176
1177 public void ConsumeSimStats(SimStats stats)
1178 {
1179 m_regionID = stats.RegionUUID;
1180 m_timeDilation = stats.StatsBlock[0].StatValue;
1181 m_simFps = stats.StatsBlock[1].StatValue;
1182 m_physicsFps = stats.StatsBlock[2].StatValue;
1183 m_agentUpdates = stats.StatsBlock[3].StatValue;
1184 m_rootAgents = stats.StatsBlock[4].StatValue;
1185 m_childAgents = stats.StatsBlock[5].StatValue;
1186 m_totalPrims = stats.StatsBlock[6].StatValue;
1187 m_activePrims = stats.StatsBlock[7].StatValue;
1188 m_totalFrameTime = stats.StatsBlock[8].StatValue;
1189 m_netFrameTime = stats.StatsBlock[9].StatValue;
1190 m_physicsFrameTime = stats.StatsBlock[10].StatValue;
1191 m_otherFrameTime = stats.StatsBlock[11].StatValue;
1192 m_imageFrameTime = stats.StatsBlock[12].StatValue;
1193 m_inPacketsPerSecond = stats.StatsBlock[13].StatValue;
1194 m_outPacketsPerSecond = stats.StatsBlock[14].StatValue;
1195 m_unackedBytes = stats.StatsBlock[15].StatValue;
1196 m_agentFrameTime = stats.StatsBlock[16].StatValue;
1197 m_pendingDownloads = stats.StatsBlock[17].StatValue;
1198 m_pendingUploads = stats.StatsBlock[18].StatValue;
1199 m_activeScripts = stats.StatsBlock[19].StatValue;
1200 m_scriptLinesPerSecond = stats.StatsBlock[20].StatValue;
1201 }
1202 }
1203} \ No newline at end of file
diff --git a/OpenSim/Region/OptionalModules/ViewerSupport/CameraOnlyModeModule.cs b/OpenSim/Region/OptionalModules/ViewerSupport/CameraOnlyModeModule.cs
new file mode 100644
index 0000000..7ae4223
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/ViewerSupport/CameraOnlyModeModule.cs
@@ -0,0 +1,176 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.IO;
30using System.Reflection;
31using System.Text;
32using System.Collections.Generic;
33using System.Threading;
34
35using OpenMetaverse;
36using OpenMetaverse.StructuredData;
37using OpenSim;
38using OpenSim.Region;
39using OpenSim.Region.Framework;
40using OpenSim.Region.Framework.Scenes;
41using OpenSim.Region.Framework.Interfaces;
42using OpenSim.Framework;
43//using OpenSim.Framework.Capabilities;
44using OpenSim.Framework.Servers;
45using OpenSim.Framework.Servers.HttpServer;
46using Nini.Config;
47using log4net;
48using Mono.Addins;
49using OSDMap = OpenMetaverse.StructuredData.OSDMap;
50using TeleportFlags = OpenSim.Framework.Constants.TeleportFlags;
51
52namespace OpenSim.Region.OptionalModules.ViewerSupport
53{
54 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "CameraOnlyMode")]
55 public class CameraOnlyModeModule : INonSharedRegionModule
56 {
57 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
58
59 private Scene m_scene;
60 private SimulatorFeaturesHelper m_Helper;
61 private bool m_Enabled;
62 private int m_UserLevel;
63
64 public string Name
65 {
66 get { return "CameraOnlyModeModule"; }
67 }
68
69 public Type ReplaceableInterface
70 {
71 get { return null; }
72 }
73
74 public void Initialise(IConfigSource config)
75 {
76 IConfig moduleConfig = config.Configs["CameraOnlyModeModule"];
77 if (moduleConfig != null)
78 {
79 m_Enabled = moduleConfig.GetBoolean("enabled", false);
80 if (m_Enabled)
81 {
82 m_UserLevel = moduleConfig.GetInt("UserLevel", 0);
83 m_log.Info("[CAMERA-ONLY MODE]: CameraOnlyModeModule enabled");
84 }
85
86 }
87 }
88
89 public void Close()
90 {
91 }
92
93 public void AddRegion(Scene scene)
94 {
95 if (m_Enabled)
96 {
97 m_scene = scene;
98 //m_scene.EventManager.OnMakeRootAgent += (OnMakeRootAgent);
99 }
100 }
101
102 //private void OnMakeRootAgent(ScenePresence obj)
103 //{
104 // throw new NotImplementedException();
105 //}
106
107 public void RegionLoaded(Scene scene)
108 {
109 if (m_Enabled)
110 {
111 IEntityTransferModule et = m_scene.RequestModuleInterface<IEntityTransferModule>();
112 m_Helper = new SimulatorFeaturesHelper(scene, et);
113
114 ISimulatorFeaturesModule featuresModule = m_scene.RequestModuleInterface<ISimulatorFeaturesModule>();
115 if (featuresModule != null)
116 featuresModule.OnSimulatorFeaturesRequest += OnSimulatorFeaturesRequest;
117 }
118 }
119
120 public void RemoveRegion(Scene scene)
121 {
122 }
123
124 private void OnSimulatorFeaturesRequest(UUID agentID, ref OSDMap features)
125 {
126 m_log.DebugFormat("[CAMERA-ONLY MODE]: OnSimulatorFeaturesRequest in {0}", m_scene.RegionInfo.RegionName);
127 if (m_Helper.ShouldSend(agentID) && m_Helper.UserLevel(agentID) <= m_UserLevel)
128 {
129 OSDMap extrasMap;
130 if (features.ContainsKey("OpenSimExtras"))
131 {
132 extrasMap = (OSDMap)features["OpenSimExtras"];
133 }
134 else
135 {
136 extrasMap = new OSDMap();
137 features["OpenSimExtras"] = extrasMap;
138 }
139 extrasMap["camera-only-mode"] = OSDMap.FromString("true");
140 m_log.DebugFormat("[CAMERA-ONLY MODE]: Sent in {0}", m_scene.RegionInfo.RegionName);
141
142 // Detaching attachments doesn't work for HG visitors,
143 // so I'm giving that up.
144 //Util.FireAndForget(delegate { DetachAttachments(agentID); });
145 }
146 else
147 m_log.DebugFormat("[CAMERA-ONLY MODE]: NOT Sending camera-only-mode in {0}", m_scene.RegionInfo.RegionName);
148 }
149
150 private void DetachAttachments(UUID agentID)
151 {
152 ScenePresence sp = m_scene.GetScenePresence(agentID);
153 if ((sp.TeleportFlags & TeleportFlags.ViaLogin) != 0)
154 // Wait a little, cos there's weird stuff going on at login related to
155 // the Current Outfit Folder
156 Thread.Sleep(8000);
157
158 if (sp != null && m_scene.AttachmentsModule != null)
159 {
160 List<SceneObjectGroup> attachs = sp.GetAttachments();
161 if (attachs != null && attachs.Count > 0)
162 {
163 foreach (SceneObjectGroup sog in attachs)
164 {
165 m_log.DebugFormat("[CAMERA-ONLY MODE]: Forcibly detaching attach {0} from {1} in {2}",
166 sog.Name, sp.Name, m_scene.RegionInfo.RegionName);
167
168 m_scene.AttachmentsModule.DetachSingleAttachmentToInv(sp, sog);
169 }
170 }
171 }
172 }
173
174 }
175
176}
diff --git a/OpenSim/Region/OptionalModules/ViewerSupport/DynamicFloaterModule.cs b/OpenSim/Region/OptionalModules/ViewerSupport/DynamicFloaterModule.cs
new file mode 100644
index 0000000..e76e8f2
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/ViewerSupport/DynamicFloaterModule.cs
@@ -0,0 +1,238 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.IO;
30using System.Reflection;
31using System.Text;
32using System.Collections.Generic;
33using OpenMetaverse;
34using OpenMetaverse.StructuredData;
35using OpenSim;
36using OpenSim.Region;
37using OpenSim.Region.Framework;
38using OpenSim.Region.Framework.Scenes;
39using OpenSim.Region.Framework.Interfaces;
40using OpenSim.Framework;
41using OpenSim.Framework.Servers;
42using OpenSim.Framework.Servers.HttpServer;
43using Nini.Config;
44using log4net;
45using Mono.Addins;
46using Caps = OpenSim.Framework.Capabilities.Caps;
47using OSDMap = OpenMetaverse.StructuredData.OSDMap;
48
49namespace OpenSim.Region.OptionalModules.ViewerSupport
50{
51 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DynamicFloater")]
52 public class DynamicFloaterModule : INonSharedRegionModule, IDynamicFloaterModule
53 {
54 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
55
56 private Scene m_scene;
57
58 private Dictionary<UUID, Dictionary<int, FloaterData>> m_floaters = new Dictionary<UUID, Dictionary<int, FloaterData>>();
59
60 public string Name
61 {
62 get { return "DynamicFloaterModule"; }
63 }
64
65 public Type ReplaceableInterface
66 {
67 get { return null; }
68 }
69
70 public void Initialise(IConfigSource config)
71 {
72 }
73
74 public void Close()
75 {
76 }
77
78 public void AddRegion(Scene scene)
79 {
80 m_scene = scene;
81 scene.EventManager.OnNewClient += OnNewClient;
82 scene.EventManager.OnClientClosed += OnClientClosed;
83 m_scene.RegisterModuleInterface<IDynamicFloaterModule>(this);
84 }
85
86 public void RegionLoaded(Scene scene)
87 {
88 }
89
90 public void RemoveRegion(Scene scene)
91 {
92 }
93
94 private void OnNewClient(IClientAPI client)
95 {
96 client.OnChatFromClient += OnChatFromClient;
97 }
98
99 private void OnClientClosed(UUID agentID, Scene scene)
100 {
101 m_floaters.Remove(agentID);
102 }
103
104 private void SendToClient(ScenePresence sp, string msg)
105 {
106 sp.ControllingClient.SendChatMessage(msg,
107 (byte)ChatTypeEnum.Owner,
108 sp.AbsolutePosition,
109 "Server",
110 UUID.Zero,
111 UUID.Zero,
112 (byte)ChatSourceType.Object,
113 (byte)ChatAudibleLevel.Fully);
114 }
115
116 public void DoUserFloater(UUID agentID, FloaterData dialogData, string configuration)
117 {
118 ScenePresence sp = m_scene.GetScenePresence(agentID);
119 if (sp == null || sp.IsChildAgent)
120 return;
121
122 if (!m_floaters.ContainsKey(agentID))
123 m_floaters[agentID] = new Dictionary<int, FloaterData>();
124
125 if (m_floaters[agentID].ContainsKey(dialogData.Channel))
126 return;
127
128 m_floaters[agentID].Add(dialogData.Channel, dialogData);
129
130 string xml;
131 if (dialogData.XmlText != null && dialogData.XmlText != String.Empty)
132 {
133 xml = dialogData.XmlText;
134 }
135 else
136 {
137 using (FileStream fs = File.Open(dialogData.XmlName + ".xml", FileMode.Open))
138 {
139 using (StreamReader sr = new StreamReader(fs))
140 xml = sr.ReadToEnd().Replace("\n", "");
141 }
142 }
143
144 List<string> xparts = new List<string>();
145
146 while (xml.Length > 0)
147 {
148 string x = xml;
149 if (x.Length > 600)
150 {
151 x = x.Substring(0, 600);
152 xml = xml.Substring(600);
153 }
154 else
155 {
156 xml = String.Empty;
157 }
158
159 xparts.Add(x);
160 }
161
162 for (int i = 0 ; i < xparts.Count ; i++)
163 SendToClient(sp, String.Format("># floater {2} create {0}/{1} " + xparts[i], i + 1, xparts.Count, dialogData.FloaterName));
164
165 SendToClient(sp, String.Format("># floater {0} {{notify:1}} {{channel: {1}}} {{node:cancel {{notify:1}}}} {{node:ok {{notify:1}}}} {2}", dialogData.FloaterName, (uint)dialogData.Channel, configuration));
166 }
167
168 private void OnChatFromClient(object sender, OSChatMessage msg)
169 {
170 if (msg.Sender == null)
171 return;
172
173 //m_log.DebugFormat("chan {0} msg {1}", msg.Channel, msg.Message);
174
175 IClientAPI client = msg.Sender;
176
177 if (!m_floaters.ContainsKey(client.AgentId))
178 return;
179
180 string[] parts = msg.Message.Split(new char[] {':'});
181 if (parts.Length == 0)
182 return;
183
184 ScenePresence sp = m_scene.GetScenePresence(client.AgentId);
185 if (sp == null || sp.IsChildAgent)
186 return;
187
188 Dictionary<int, FloaterData> d = m_floaters[client.AgentId];
189
190 // Work around a viewer bug - VALUE from any
191 // dialog can appear on this channel and needs to
192 // be dispatched to ALL open dialogs for the user
193 if (msg.Channel == 427169570)
194 {
195 if (parts[0] == "VALUE")
196 {
197 foreach (FloaterData dd in d.Values)
198 {
199 if(dd.Handler(client, dd, parts))
200 {
201 m_floaters[client.AgentId].Remove(dd.Channel);
202 SendToClient(sp, String.Format("># floater {0} destroy", dd.FloaterName));
203 break;
204 }
205 }
206 }
207 return;
208 }
209
210 if (!d.ContainsKey(msg.Channel))
211 return;
212
213 FloaterData data = d[msg.Channel];
214
215 if (parts[0] == "NOTIFY")
216 {
217 if (parts[1] == "cancel" || parts[1] == data.FloaterName)
218 {
219 m_floaters[client.AgentId].Remove(data.Channel);
220 SendToClient(sp, String.Format("># floater {0} destroy", data.FloaterName));
221 }
222 }
223
224 if (data.Handler != null && data.Handler(client, data, parts))
225 {
226 m_floaters[client.AgentId].Remove(data.Channel);
227 SendToClient(sp, String.Format("># floater {0} destroy", data.FloaterName));
228 }
229 }
230
231 public void FloaterControl(ScenePresence sp, FloaterData d, string msg)
232 {
233 string sendData = String.Format("># floater {0} {1}", d.FloaterName, msg);
234 SendToClient(sp, sendData);
235
236 }
237 }
238}
diff --git a/OpenSim/Region/OptionalModules/ViewerSupport/DynamicMenuModule.cs b/OpenSim/Region/OptionalModules/ViewerSupport/DynamicMenuModule.cs
new file mode 100644
index 0000000..d37369c
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/ViewerSupport/DynamicMenuModule.cs
@@ -0,0 +1,304 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.IO;
30using System.Reflection;
31using System.Text;
32using System.Collections.Generic;
33using OpenMetaverse;
34using OpenMetaverse.StructuredData;
35using OpenSim;
36using OpenSim.Region;
37using OpenSim.Region.Framework;
38using OpenSim.Region.Framework.Scenes;
39using OpenSim.Region.Framework.Interfaces;
40using OpenSim.Framework;
41//using OpenSim.Framework.Capabilities;
42using OpenSim.Framework.Servers;
43using OpenSim.Framework.Servers.HttpServer;
44using Nini.Config;
45using log4net;
46using Mono.Addins;
47using Caps = OpenSim.Framework.Capabilities.Caps;
48using OSDMap = OpenMetaverse.StructuredData.OSDMap;
49
50namespace OpenSim.Region.OptionalModules.ViewerSupport
51{
52 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DynamicMenu")]
53 public class DynamicMenuModule : INonSharedRegionModule, IDynamicMenuModule
54 {
55 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
56
57 private class MenuItemData
58 {
59 public string Title;
60 public UUID AgentID;
61 public InsertLocation Location;
62 public UserMode Mode;
63 public CustomMenuHandler Handler;
64 }
65
66 private Dictionary<UUID, List<MenuItemData>> m_menuItems =
67 new Dictionary<UUID, List<MenuItemData>>();
68
69 private Scene m_scene;
70
71 public string Name
72 {
73 get { return "DynamicMenuModule"; }
74 }
75
76 public Type ReplaceableInterface
77 {
78 get { return null; }
79 }
80
81 public void Initialise(IConfigSource config)
82 {
83 }
84
85 public void Close()
86 {
87 }
88
89 public void AddRegion(Scene scene)
90 {
91 m_scene = scene;
92 scene.EventManager.OnRegisterCaps += OnRegisterCaps;
93 m_scene.RegisterModuleInterface<IDynamicMenuModule>(this);
94 }
95
96 public void RegionLoaded(Scene scene)
97 {
98 ISimulatorFeaturesModule featuresModule = m_scene.RequestModuleInterface<ISimulatorFeaturesModule>();
99
100 if (featuresModule != null)
101 featuresModule.OnSimulatorFeaturesRequest += OnSimulatorFeaturesRequest;
102 }
103
104 public void RemoveRegion(Scene scene)
105 {
106 }
107
108 private void OnSimulatorFeaturesRequest(UUID agentID, ref OSDMap features)
109 {
110 OSD menus = new OSDMap();
111 if (features.ContainsKey("menus"))
112 menus = features["menus"];
113
114 OSDMap agent = new OSDMap();
115 OSDMap world = new OSDMap();
116 OSDMap tools = new OSDMap();
117 OSDMap advanced = new OSDMap();
118 OSDMap admin = new OSDMap();
119 if (((OSDMap)menus).ContainsKey("agent"))
120 agent = (OSDMap)((OSDMap)menus)["agent"];
121 if (((OSDMap)menus).ContainsKey("world"))
122 world = (OSDMap)((OSDMap)menus)["world"];
123 if (((OSDMap)menus).ContainsKey("tools"))
124 tools = (OSDMap)((OSDMap)menus)["tools"];
125 if (((OSDMap)menus).ContainsKey("advanced"))
126 advanced = (OSDMap)((OSDMap)menus)["advanced"];
127 if (((OSDMap)menus).ContainsKey("admin"))
128 admin = (OSDMap)((OSDMap)menus)["admin"];
129
130 if (m_menuItems.ContainsKey(UUID.Zero))
131 {
132 foreach (MenuItemData d in m_menuItems[UUID.Zero])
133 {
134 if (d.Mode == UserMode.God && (!m_scene.Permissions.IsGod(agentID)))
135 continue;
136
137 OSDMap loc = null;
138 switch (d.Location)
139 {
140 case InsertLocation.Agent:
141 loc = agent;
142 break;
143 case InsertLocation.World:
144 loc = world;
145 break;
146 case InsertLocation.Tools:
147 loc = tools;
148 break;
149 case InsertLocation.Advanced:
150 loc = advanced;
151 break;
152 case InsertLocation.Admin:
153 loc = admin;
154 break;
155 }
156
157 if (loc == null)
158 continue;
159
160 loc[d.Title] = OSD.FromString(d.Title);
161 }
162 }
163
164 if (m_menuItems.ContainsKey(agentID))
165 {
166 foreach (MenuItemData d in m_menuItems[agentID])
167 {
168 if (d.Mode == UserMode.God && (!m_scene.Permissions.IsGod(agentID)))
169 continue;
170
171 OSDMap loc = null;
172 switch (d.Location)
173 {
174 case InsertLocation.Agent:
175 loc = agent;
176 break;
177 case InsertLocation.World:
178 loc = world;
179 break;
180 case InsertLocation.Tools:
181 loc = tools;
182 break;
183 case InsertLocation.Advanced:
184 loc = advanced;
185 break;
186 case InsertLocation.Admin:
187 loc = admin;
188 break;
189 }
190
191 if (loc == null)
192 continue;
193
194 loc[d.Title] = OSD.FromString(d.Title);
195 }
196 }
197
198
199 ((OSDMap)menus)["agent"] = agent;
200 ((OSDMap)menus)["world"] = world;
201 ((OSDMap)menus)["tools"] = tools;
202 ((OSDMap)menus)["advanced"] = advanced;
203 ((OSDMap)menus)["admin"] = admin;
204
205 features["menus"] = menus;
206 }
207
208 private void OnRegisterCaps(UUID agentID, Caps caps)
209 {
210 string capUrl = "/CAPS/" + UUID.Random() + "/";
211
212 capUrl = "/CAPS/" + UUID.Random() + "/";
213 caps.RegisterHandler("CustomMenuAction", new MenuActionHandler(capUrl, "CustomMenuAction", agentID, this, m_scene));
214 }
215
216 internal void HandleMenuSelection(string action, UUID agentID, List<uint> selection)
217 {
218 if (m_menuItems.ContainsKey(agentID))
219 {
220 foreach (MenuItemData d in m_menuItems[agentID])
221 {
222 if (d.Title == action)
223 d.Handler(action, agentID, selection);
224 }
225 }
226
227 if (m_menuItems.ContainsKey(UUID.Zero))
228 {
229 foreach (MenuItemData d in m_menuItems[UUID.Zero])
230 {
231 if (d.Title == action)
232 d.Handler(action, agentID, selection);
233 }
234 }
235 }
236
237 public void AddMenuItem(string title, InsertLocation location, UserMode mode, CustomMenuHandler handler)
238 {
239 AddMenuItem(UUID.Zero, title, location, mode, handler);
240 }
241
242 public void AddMenuItem(UUID agentID, string title, InsertLocation location, UserMode mode, CustomMenuHandler handler)
243 {
244 if (!m_menuItems.ContainsKey(agentID))
245 m_menuItems[agentID] = new List<MenuItemData>();
246
247 m_menuItems[agentID].Add(new MenuItemData() { Title = title, AgentID = agentID, Location = location, Mode = mode, Handler = handler });
248 }
249
250 public void RemoveMenuItem(string action)
251 {
252 foreach (KeyValuePair<UUID,List< MenuItemData>> kvp in m_menuItems)
253 {
254 List<MenuItemData> pendingDeletes = new List<MenuItemData>();
255 foreach (MenuItemData d in kvp.Value)
256 {
257 if (d.Title == action)
258 pendingDeletes.Add(d);
259 }
260
261 foreach (MenuItemData d in pendingDeletes)
262 kvp.Value.Remove(d);
263 }
264 }
265 }
266
267 public class MenuActionHandler : BaseStreamHandler
268 {
269 private static readonly ILog m_log =
270 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
271
272 private UUID m_agentID;
273 private Scene m_scene;
274 private DynamicMenuModule m_module;
275
276 public MenuActionHandler(string path, string name, UUID agentID, DynamicMenuModule module, Scene scene)
277 :base("POST", path, name, agentID.ToString())
278 {
279 m_agentID = agentID;
280 m_scene = scene;
281 m_module = module;
282 }
283
284 protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
285 {
286 StreamReader reader = new StreamReader(request);
287 string requestBody = reader.ReadToEnd();
288
289 OSD osd = OSDParser.DeserializeLLSDXml(requestBody);
290
291 string action = ((OSDMap)osd)["action"].AsString();
292 OSDArray selection = (OSDArray)((OSDMap)osd)["selection"];
293 List<uint> sel = new List<uint>();
294 for (int i = 0 ; i < selection.Count ; i++)
295 sel.Add(selection[i].AsUInteger());
296
297 Util.FireAndForget(
298 x => { m_module.HandleMenuSelection(action, m_agentID, sel); }, null, "DynamicMenuModule.HandleMenuSelection");
299
300 Encoding encoding = Encoding.UTF8;
301 return encoding.GetBytes(OSDParser.SerializeLLSDXmlString(new OSD()));
302 }
303 }
304}
diff --git a/OpenSim/Region/OptionalModules/ViewerSupport/GodNamesModule.cs b/OpenSim/Region/OptionalModules/ViewerSupport/GodNamesModule.cs
new file mode 100644
index 0000000..e0537a4
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/ViewerSupport/GodNamesModule.cs
@@ -0,0 +1,144 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using log4net;
32using Mono.Addins;
33using Nini.Config;
34using OpenMetaverse;
35using OpenMetaverse.StructuredData;
36using OpenSim.Framework;
37using OpenSim.Region.Framework.Interfaces;
38using OpenSim.Region.Framework.Scenes;
39
40namespace OpenSim.Region.OptionalModules.ViewerSupport
41{
42 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GodNamesModule")]
43 public class GodNamesModule : ISharedRegionModule
44 {
45 // Infrastructure
46 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
47
48 // Configuration
49 private static bool m_enabled = false;
50 private static List<String> m_lastNames = new List<String>();
51 private static List<String> m_fullNames = new List<String>();
52
53 public void Initialise(IConfigSource config)
54 {
55 IConfig moduleConfig = config.Configs["GodNames"];
56
57 if (moduleConfig == null) {
58 return;
59 }
60
61 if (!moduleConfig.GetBoolean("Enabled", false)) {
62 m_log.Info("[GODNAMES]: Addon is disabled");
63 return;
64 }
65
66 m_log.Info("[GODNAMES]: Enabled");
67 m_enabled = true;
68 string conf_str = moduleConfig.GetString("FullNames", String.Empty);
69 foreach (string strl in conf_str.Split(',')) {
70 string strlan = strl.Trim(" \t".ToCharArray());
71 m_log.DebugFormat("[GODNAMES]: Adding {0} as a God name", strlan);
72 m_fullNames.Add(strlan);
73 }
74
75 conf_str = moduleConfig.GetString("Surnames", String.Empty);
76 foreach (string strl in conf_str.Split(',')) {
77 string strlan = strl.Trim(" \t".ToCharArray());
78 m_log.DebugFormat("[GODNAMES]: Adding {0} as a God last name", strlan);
79 m_lastNames.Add(strlan);
80 }
81 }
82
83 public void AddRegion(Scene scene) {
84 /*no op*/
85 }
86
87 public void RemoveRegion(Scene scene) {
88 /*no op*/
89 }
90
91 public void PostInitialise() {
92 /*no op*/
93 }
94
95 public void Close() {
96 /*no op*/
97 }
98
99 public Type ReplaceableInterface {
100 get { return null; }
101 }
102
103 public string Name {
104 get { return "Godnames"; }
105 }
106
107 public bool IsSharedModule {
108 get { return true; }
109 }
110
111 public virtual void RegionLoaded(Scene scene)
112 {
113 if (!m_enabled)
114 return;
115
116 ISimulatorFeaturesModule featuresModule = scene.RequestModuleInterface<ISimulatorFeaturesModule>();
117
118 if (featuresModule != null)
119 featuresModule.OnSimulatorFeaturesRequest += OnSimulatorFeaturesRequest;
120
121 }
122
123 private void OnSimulatorFeaturesRequest(UUID agentID, ref OSDMap features)
124 {
125 OSD namesmap = new OSDMap();
126 if (features.ContainsKey("god_names"))
127 namesmap = features["god_names"];
128 else
129 features["god_names"] = namesmap;
130
131 OSDArray fnames = new OSDArray();
132 foreach (string name in m_fullNames) {
133 fnames.Add(name);
134 }
135 ((OSDMap)namesmap)["full_names"] = fnames;
136
137 OSDArray lnames = new OSDArray();
138 foreach (string name in m_lastNames) {
139 lnames.Add(name);
140 }
141 ((OSDMap)namesmap)["last_names"] = lnames;
142 }
143 }
144}
diff --git a/OpenSim/Region/OptionalModules/ViewerSupport/SimulatorFeaturesHelper.cs b/OpenSim/Region/OptionalModules/ViewerSupport/SimulatorFeaturesHelper.cs
new file mode 100644
index 0000000..2661522
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/ViewerSupport/SimulatorFeaturesHelper.cs
@@ -0,0 +1,171 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.IO;
30using System.Reflection;
31using System.Text;
32using System.Collections.Generic;
33using System.Threading;
34
35using OpenMetaverse;
36using OpenMetaverse.StructuredData;
37using OpenSim;
38using OpenSim.Region;
39using OpenSim.Region.Framework;
40using OpenSim.Region.Framework.Scenes;
41using OpenSim.Region.Framework.Interfaces;
42using OpenSim.Framework;
43using OpenSim.Services.Interfaces;
44//using OpenSim.Framework.Capabilities;
45using Nini.Config;
46using log4net;
47using OSDMap = OpenMetaverse.StructuredData.OSDMap;
48using TeleportFlags = OpenSim.Framework.Constants.TeleportFlags;
49
50namespace OpenSim.Region.OptionalModules.ViewerSupport
51{
52 public class SimulatorFeaturesHelper
53 {
54 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
55
56 private IEntityTransferModule m_TransferModule;
57 private Scene m_scene;
58
59 private struct RegionSend {
60 public UUID region;
61 public bool send;
62 };
63 // Using a static cache so that we don't have to perform the time-consuming tests
64 // in ShouldSend on Extra SimFeatures that go on the same response but come from
65 // different modules.
66 // This cached is indexed on the agentID and maps to a list of regions
67 private static ExpiringCache<UUID, List<RegionSend>> m_Cache = new ExpiringCache<UUID, List<RegionSend>>();
68 private const double TIMEOUT = 1.0; // time in cache
69
70 public SimulatorFeaturesHelper(Scene scene, IEntityTransferModule et)
71 {
72 m_scene = scene;
73 m_TransferModule = et;
74 }
75
76 public bool ShouldSend(UUID agentID)
77 {
78 List<RegionSend> rsendlist;
79 RegionSend rsend;
80 if (m_Cache.TryGetValue(agentID, out rsendlist))
81 {
82 rsend = rsendlist.Find(r => r.region == m_scene.RegionInfo.RegionID);
83 if (rsend.region != UUID.Zero) // Found it
84 {
85 return rsend.send;
86 }
87 }
88
89 // Relatively complex logic for deciding whether to send the extra SimFeature or not.
90 // This is because the viewer calls this cap to all sims that it knows about,
91 // including the departing sims and non-neighbors (those that are cached).
92 rsend.region = m_scene.RegionInfo.RegionID;
93 rsend.send = false;
94 IClientAPI client = null;
95 int counter = 200;
96
97 // Let's wait a little to see if we get a client here
98 while (!m_scene.TryGetClient(agentID, out client) && counter-- > 0)
99 Thread.Sleep(50);
100
101 if (client != null)
102 {
103 ScenePresence sp = WaitGetScenePresence(agentID);
104
105 if (sp != null)
106 {
107 // On the receiving region, the call to this cap may arrive before
108 // the agent is root. Make sure we only proceed from here when the agent
109 // has been made root
110 counter = 200;
111 while ((sp.IsInTransit || sp.IsChildAgent) && counter-- > 0)
112 {
113 Thread.Sleep(50);
114 }
115
116 // The viewer calls this cap on the departing sims too. Make sure
117 // that we only proceed after the agent is not in transit anymore.
118 // The agent must be root and not going anywhere
119 if (!sp.IsChildAgent && !m_TransferModule.IsInTransit(agentID))
120 rsend.send = true;
121
122 }
123 }
124 //else
125 // m_log.DebugFormat("[XXX]: client is null");
126
127
128 if (rsendlist == null)
129 {
130 rsendlist = new List<RegionSend>();
131 m_Cache.AddOrUpdate(agentID, rsendlist, TIMEOUT);
132 }
133 rsendlist.Add(rsend);
134
135 return rsend.send;
136 }
137
138 public int UserLevel(UUID agentID)
139 {
140 int level = 0;
141 UserAccount account = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, agentID);
142 if (account != null)
143 level = account.UserLevel;
144
145 return level;
146 }
147
148 protected virtual ScenePresence WaitGetScenePresence(UUID agentID)
149 {
150 int ntimes = 20;
151 ScenePresence sp = null;
152 while ((sp = m_scene.GetScenePresence(agentID)) == null && (ntimes-- > 0))
153 Thread.Sleep(1000);
154
155 if (sp == null)
156 m_log.WarnFormat(
157 "[XXX]: Did not find presence with id {0} in {1} before timeout",
158 agentID, m_scene.RegionInfo.RegionName);
159 else
160 {
161 ntimes = 10;
162 while (sp.IsInTransit && (ntimes-- > 0))
163 Thread.Sleep(1000);
164 }
165
166 return sp;
167 }
168
169 }
170
171}
diff --git a/OpenSim/Region/OptionalModules/ViewerSupport/SpecialUIModule.cs b/OpenSim/Region/OptionalModules/ViewerSupport/SpecialUIModule.cs
new file mode 100644
index 0000000..3fe922d
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/ViewerSupport/SpecialUIModule.cs
@@ -0,0 +1,165 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.IO;
30using System.Reflection;
31using System.Text;
32using System.Collections.Generic;
33using System.Threading;
34using OpenMetaverse;
35using OpenMetaverse.StructuredData;
36using OpenSim;
37using OpenSim.Region;
38using OpenSim.Region.Framework;
39using OpenSim.Region.Framework.Scenes;
40using OpenSim.Region.Framework.Interfaces;
41using OpenSim.Framework;
42//using OpenSim.Framework.Capabilities;
43using OpenSim.Framework.Servers;
44using OpenSim.Framework.Servers.HttpServer;
45using Nini.Config;
46using log4net;
47using Mono.Addins;
48using OSDMap = OpenMetaverse.StructuredData.OSDMap;
49using TeleportFlags = OpenSim.Framework.Constants.TeleportFlags;
50
51namespace OpenSim.Region.OptionalModules.ViewerSupport
52{
53 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "SpecialUI")]
54 public class SpecialUIModule : INonSharedRegionModule
55 {
56 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
57 private const string VIEWER_SUPPORT_DIR = "ViewerSupport";
58
59 private Scene m_scene;
60 private SimulatorFeaturesHelper m_Helper;
61 private bool m_Enabled;
62 private int m_UserLevel;
63
64 public string Name
65 {
66 get { return "SpecialUIModule"; }
67 }
68
69 public Type ReplaceableInterface
70 {
71 get { return null; }
72 }
73
74 public void Initialise(IConfigSource config)
75 {
76 IConfig moduleConfig = config.Configs["SpecialUIModule"];
77 if (moduleConfig != null)
78 {
79 m_Enabled = moduleConfig.GetBoolean("enabled", false);
80 if (m_Enabled)
81 {
82 m_UserLevel = moduleConfig.GetInt("UserLevel", 0);
83 m_log.Info("[SPECIAL UI]: SpecialUIModule enabled");
84 }
85
86 }
87 }
88
89 public void Close()
90 {
91 }
92
93 public void AddRegion(Scene scene)
94 {
95 if (m_Enabled)
96 {
97 m_scene = scene;
98 }
99 }
100
101 public void RegionLoaded(Scene scene)
102 {
103 if (m_Enabled)
104 {
105 IEntityTransferModule et = m_scene.RequestModuleInterface<IEntityTransferModule>();
106 m_Helper = new SimulatorFeaturesHelper(scene, et);
107
108 ISimulatorFeaturesModule featuresModule = m_scene.RequestModuleInterface<ISimulatorFeaturesModule>();
109 if (featuresModule != null)
110 featuresModule.OnSimulatorFeaturesRequest += OnSimulatorFeaturesRequest;
111 }
112 }
113
114 public void RemoveRegion(Scene scene)
115 {
116 }
117
118 private void OnSimulatorFeaturesRequest(UUID agentID, ref OSDMap features)
119 {
120 m_log.DebugFormat("[SPECIAL UI]: OnSimulatorFeaturesRequest in {0}", m_scene.RegionInfo.RegionName);
121 if (m_Helper.ShouldSend(agentID) && m_Helper.UserLevel(agentID) <= m_UserLevel)
122 {
123 OSDMap extrasMap;
124 OSDMap specialUI = new OSDMap();
125 using (StreamReader s = new StreamReader(Path.Combine(VIEWER_SUPPORT_DIR, "panel_toolbar.xml")))
126 {
127 if (features.ContainsKey("OpenSimExtras"))
128 extrasMap = (OSDMap)features["OpenSimExtras"];
129 else
130 {
131 extrasMap = new OSDMap();
132 features["OpenSimExtras"] = extrasMap;
133 }
134
135 specialUI["toolbar"] = OSDMap.FromString(s.ReadToEnd());
136 extrasMap["special-ui"] = specialUI;
137 }
138 m_log.DebugFormat("[SPECIAL UI]: Sending panel_toolbar.xml in {0}", m_scene.RegionInfo.RegionName);
139
140 if (Directory.Exists(Path.Combine(VIEWER_SUPPORT_DIR, "Floaters")))
141 {
142 OSDMap floaters = new OSDMap();
143 uint n = 0;
144 foreach (String name in Directory.GetFiles(Path.Combine(VIEWER_SUPPORT_DIR, "Floaters"), "*.xml"))
145 {
146 using (StreamReader s = new StreamReader(name))
147 {
148 string simple_name = Path.GetFileNameWithoutExtension(name);
149 OSDMap floater = new OSDMap();
150 floaters[simple_name] = OSDMap.FromString(s.ReadToEnd());
151 n++;
152 }
153 }
154 specialUI["floaters"] = floaters;
155 m_log.DebugFormat("[SPECIAL UI]: Sending {0} floaters", n);
156 }
157 }
158 else
159 m_log.DebugFormat("[SPECIAL UI]: NOT Sending panel_toolbar.xml in {0}", m_scene.RegionInfo.RegionName);
160
161 }
162
163 }
164
165}
diff --git a/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModule.cs b/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModule.cs
index 1d35c54..ceb3332 100644
--- a/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModule.cs
+++ b/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModule.cs
@@ -76,6 +76,10 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup
76 /// AutoBackupBusyCheck: True/False. Default: True. 76 /// AutoBackupBusyCheck: True/False. Default: True.
77 /// If True, we will only take an auto-backup if a set of conditions are met. 77 /// If True, we will only take an auto-backup if a set of conditions are met.
78 /// These conditions are heuristics to try and avoid taking a backup when the sim is busy. 78 /// These conditions are heuristics to try and avoid taking a backup when the sim is busy.
79 /// AutoBackupSkipAssets
80 /// If true, assets are not saved to the oar file. Considerably reduces impact on simulator when backing up. Intended for when assets db is backed up separately
81 /// AutoBackupKeepFilesForDays
82 /// Backup files older than this value (in days) are deleted during the current backup process, 0 will disable this and keep all backup files indefinitely
79 /// AutoBackupScript: String. Default: not specified (disabled). 83 /// AutoBackupScript: String. Default: not specified (disabled).
80 /// File path to an executable script or binary to run when an automatic backup is taken. 84 /// File path to an executable script or binary to run when an automatic backup is taken.
81 /// The file should really be (Windows) an .exe or .bat, or (Linux/Mac) a shell script or binary. 85 /// The file should really be (Windows) an .exe or .bat, or (Linux/Mac) a shell script or binary.
@@ -111,6 +115,9 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup
111 115
112 private delegate T DefaultGetter<T>(string settingName, T defaultValue); 116 private delegate T DefaultGetter<T>(string settingName, T defaultValue);
113 private bool m_enabled; 117 private bool m_enabled;
118 private ICommandConsole m_console;
119 private List<Scene> m_Scenes = new List<Scene> ();
120
114 121
115 /// <summary> 122 /// <summary>
116 /// Whether the shared module should be enabled at all. NOT the same as m_Enabled in AutoBackupModuleState! 123 /// Whether the shared module should be enabled at all. NOT the same as m_Enabled in AutoBackupModuleState!
@@ -202,8 +209,20 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup
202 /// Currently a no-op for AutoBackup because we have to wait for region to be fully loaded. 209 /// Currently a no-op for AutoBackup because we have to wait for region to be fully loaded.
203 /// </summary> 210 /// </summary>
204 /// <param name="scene"></param> 211 /// <param name="scene"></param>
205 void IRegionModuleBase.AddRegion(Scene scene) 212 void IRegionModuleBase.AddRegion (Scene scene)
206 { 213 {
214 if (!this.m_enabled) {
215 return;
216 }
217 lock (m_Scenes) {
218 m_Scenes.Add (scene);
219 }
220 m_console = MainConsole.Instance;
221
222 m_console.Commands.AddCommand (
223 "AutoBackup", false, "dobackup",
224 "dobackup",
225 "do backup.", DoBackup);
207 } 226 }
208 227
209 /// <summary> 228 /// <summary>
@@ -216,7 +235,7 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup
216 { 235 {
217 return; 236 return;
218 } 237 }
219 238 m_Scenes.Remove (scene);
220 if (this.m_states.ContainsKey(scene)) 239 if (this.m_states.ContainsKey(scene))
221 { 240 {
222 AutoBackupModuleState abms = this.m_states[scene]; 241 AutoBackupModuleState abms = this.m_states[scene];
@@ -258,6 +277,8 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup
258 AutoBackupModuleState abms = this.ParseConfig(scene, false); 277 AutoBackupModuleState abms = this.ParseConfig(scene, false);
259 m_log.Debug("[AUTO BACKUP]: Config for " + scene.RegionInfo.RegionName); 278 m_log.Debug("[AUTO BACKUP]: Config for " + scene.RegionInfo.RegionName);
260 m_log.Debug((abms == null ? "DEFAULT" : abms.ToString())); 279 m_log.Debug((abms == null ? "DEFAULT" : abms.ToString()));
280
281 m_states.Add(scene, abms);
261 } 282 }
262 283
263 /// <summary> 284 /// <summary>
@@ -269,6 +290,28 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup
269 290
270 #endregion 291 #endregion
271 292
293 private void DoBackup (string module, string[] args)
294 {
295 if (args.Length != 2) {
296 MainConsole.Instance.OutputFormat ("Usage: dobackup <regionname>");
297 return;
298 }
299 bool found = false;
300 string name = args [1];
301 lock (m_Scenes) {
302 foreach (Scene s in m_Scenes) {
303 string test = s.Name.ToString ();
304 if (test == name) {
305 found = true;
306 DoRegionBackup (s);
307 }
308 }
309 if (!found) {
310 MainConsole.Instance.OutputFormat ("No such region {0}. Nothing to backup", name);
311 }
312 }
313 }
314
272 /// <summary> 315 /// <summary>
273 /// Set up internal state for a given scene. Fairly complex code. 316 /// Set up internal state for a given scene. Fairly complex code.
274 /// When this method returns, we've started auto-backup timers, put members in Dictionaries, and created a State object for this scene. 317 /// When this method returns, we've started auto-backup timers, put members in Dictionaries, and created a State object for this scene.
@@ -334,7 +377,7 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup
334 double interval = 377 double interval =
335 this.ResolveDouble("AutoBackupInterval", this.m_defaultState.IntervalMinutes, 378 this.ResolveDouble("AutoBackupInterval", this.m_defaultState.IntervalMinutes,
336 config, regionConfig) * 60000.0; 379 config, regionConfig) * 60000.0;
337 if (state == null && interval != this.m_defaultState.IntervalMinutes*60000.0) 380 if (state == null && interval != this.m_defaultState.IntervalMinutes * 60000.0)
338 { 381 {
339 state = new AutoBackupModuleState(); 382 state = new AutoBackupModuleState();
340 } 383 }
@@ -412,6 +455,32 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup
412 state.BusyCheck = tmpBusyCheck; 455 state.BusyCheck = tmpBusyCheck;
413 } 456 }
414 457
458 // Included Option To Skip Assets
459 bool tmpSkipAssets = ResolveBoolean("AutoBackupSkipAssets",
460 this.m_defaultState.SkipAssets, config, regionConfig);
461 if (state == null && tmpSkipAssets != this.m_defaultState.SkipAssets)
462 {
463 state = new AutoBackupModuleState();
464 }
465
466 if (state != null)
467 {
468 state.SkipAssets = tmpSkipAssets;
469 }
470
471 // How long to keep backup files in days, 0 Disables this feature
472 int tmpKeepFilesForDays = ResolveInt("AutoBackupKeepFilesForDays",
473 this.m_defaultState.KeepFilesForDays, config, regionConfig);
474 if (state == null && tmpKeepFilesForDays != this.m_defaultState.KeepFilesForDays)
475 {
476 state = new AutoBackupModuleState();
477 }
478
479 if (state != null)
480 {
481 state.KeepFilesForDays = tmpKeepFilesForDays;
482 }
483
415 // Set file naming algorithm 484 // Set file naming algorithm
416 string stmpNamingType = ResolveString("AutoBackupNaming", 485 string stmpNamingType = ResolveString("AutoBackupNaming",
417 this.m_defaultState.NamingType.ToString(), config, regionConfig); 486 this.m_defaultState.NamingType.ToString(), config, regionConfig);
@@ -480,7 +549,7 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup
480 catch (Exception e) 549 catch (Exception e)
481 { 550 {
482 m_log.Warn( 551 m_log.Warn(
483 "BAD NEWS. You won't be able to save backups to directory " + 552 "[AUTO BACKUP]: BAD NEWS. You won't be able to save backups to directory " +
484 state.BackupDir + 553 state.BackupDir +
485 " because it doesn't exist or there's a permissions issue with it. Here's the exception.", 554 " because it doesn't exist or there's a permissions issue with it. Here's the exception.",
486 e); 555 e);
@@ -488,6 +557,9 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup
488 } 557 }
489 } 558 }
490 559
560 if(state == null)
561 return m_defaultState;
562
491 return state; 563 return state;
492 } 564 }
493 565
@@ -594,7 +666,7 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup
594 bool heuristicsPassed = false; 666 bool heuristicsPassed = false;
595 if (!this.m_timerMap.ContainsKey((Timer) sender)) 667 if (!this.m_timerMap.ContainsKey((Timer) sender))
596 { 668 {
597 m_log.Debug("Code-up error: timerMap doesn't contain timer " + sender); 669 m_log.Debug("[AUTO BACKUP]: Code-up error: timerMap doesn't contain timer " + sender);
598 } 670 }
599 671
600 List<IScene> tmap = this.m_timerMap[(Timer) sender]; 672 List<IScene> tmap = this.m_timerMap[(Timer) sender];
@@ -630,6 +702,9 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup
630 } 702 }
631 this.DoRegionBackup(scene); 703 this.DoRegionBackup(scene);
632 } 704 }
705
706 // Remove Old Backups
707 this.RemoveOldFiles(state);
633 } 708 }
634 } 709 }
635 } 710 }
@@ -640,7 +715,7 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup
640 /// <param name="scene"></param> 715 /// <param name="scene"></param>
641 private void DoRegionBackup(IScene scene) 716 private void DoRegionBackup(IScene scene)
642 { 717 {
643 if (scene.RegionStatus != RegionStatus.Up) 718 if (!scene.Ready)
644 { 719 {
645 // We won't backup a region that isn't operating normally. 720 // We won't backup a region that isn't operating normally.
646 m_log.Warn("[AUTO BACKUP]: Not backing up region " + scene.RegionInfo.RegionName + 721 m_log.Warn("[AUTO BACKUP]: Not backing up region " + scene.RegionInfo.RegionName +
@@ -662,7 +737,41 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup
662 m_pendingSaves.Add(guid, scene); 737 m_pendingSaves.Add(guid, scene);
663 state.LiveRequests.Add(guid, savePath); 738 state.LiveRequests.Add(guid, savePath);
664 ((Scene) scene).EventManager.OnOarFileSaved += new EventManager.OarFileSaved(EventManager_OnOarFileSaved); 739 ((Scene) scene).EventManager.OnOarFileSaved += new EventManager.OarFileSaved(EventManager_OnOarFileSaved);
665 iram.ArchiveRegion(savePath, guid, null); 740
741 m_log.Info("[AUTO BACKUP]: Backing up region " + scene.RegionInfo.RegionName);
742
743 // Must pass options, even if dictionary is empty!
744 Dictionary<string, object> options = new Dictionary<string, object>();
745
746 if (state.SkipAssets)
747 options["noassets"] = true;
748
749 iram.ArchiveRegion(savePath, guid, options);
750 }
751
752 // For the given state, remove backup files older than the states KeepFilesForDays property
753 private void RemoveOldFiles(AutoBackupModuleState state)
754 {
755 // 0 Means Disabled, Keep Files Indefinitely
756 if (state.KeepFilesForDays > 0)
757 {
758 string[] files = Directory.GetFiles(state.BackupDir, "*.oar");
759 DateTime CuttOffDate = DateTime.Now.AddDays(0 - state.KeepFilesForDays);
760
761 foreach (string file in files)
762 {
763 try
764 {
765 FileInfo fi = new FileInfo(file);
766 if (fi.CreationTime < CuttOffDate)
767 fi.Delete();
768 }
769 catch (Exception Ex)
770 {
771 m_log.Error("[AUTO BACKUP]: Error deleting old backup file '" + file + "': " + Ex.Message);
772 }
773 }
774 }
666 } 775 }
667 776
668 /// <summary> 777 /// <summary>
diff --git a/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModuleState.cs b/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModuleState.cs
index f9e118b..ce7c368 100644
--- a/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModuleState.cs
+++ b/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModuleState.cs
@@ -45,9 +45,11 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup
45 this.Enabled = false; 45 this.Enabled = false;
46 this.BackupDir = "."; 46 this.BackupDir = ".";
47 this.BusyCheck = true; 47 this.BusyCheck = true;
48 this.SkipAssets = false;
48 this.Timer = null; 49 this.Timer = null;
49 this.NamingType = NamingType.Time; 50 this.NamingType = NamingType.Time;
50 this.Script = null; 51 this.Script = null;
52 this.KeepFilesForDays = 0;
51 } 53 }
52 54
53 public Dictionary<Guid, string> LiveRequests 55 public Dictionary<Guid, string> LiveRequests
@@ -91,6 +93,12 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup
91 set; 93 set;
92 } 94 }
93 95
96 public bool SkipAssets
97 {
98 get;
99 set;
100 }
101
94 public string Script 102 public string Script
95 { 103 {
96 get; 104 get;
@@ -109,6 +117,12 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup
109 set; 117 set;
110 } 118 }
111 119
120 public int KeepFilesForDays
121 {
122 get;
123 set;
124 }
125
112 public new string ToString() 126 public new string ToString()
113 { 127 {
114 string retval = ""; 128 string retval = "";
diff --git a/OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs b/OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs
index a999b7f..4cd5676 100644
--- a/OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs
+++ b/OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs
@@ -103,7 +103,9 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule
103 103
104 #region IMoneyModule Members 104 #region IMoneyModule Members
105 105
106#pragma warning disable 0067
106 public event ObjectPaid OnObjectPaid; 107 public event ObjectPaid OnObjectPaid;
108#pragma warning restore 0067
107 109
108 public int UploadCharge 110 public int UploadCharge
109 { 111 {
@@ -191,9 +193,14 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule
191 // Please do not refactor these to be just one method 193 // Please do not refactor these to be just one method
192 // Existing implementations need the distinction 194 // Existing implementations need the distinction
193 // 195 //
194 public void ApplyCharge(UUID agentID, int amount, string text) 196 public void ApplyCharge(UUID agentID, int amount, MoneyTransactionType type, string extraData)
195 { 197 {
196 } 198 }
199
200 public void ApplyCharge(UUID agentID, int amount, MoneyTransactionType type)
201 {
202 }
203
197 public void ApplyUploadCharge(UUID agentID, int amount, string text) 204 public void ApplyUploadCharge(UUID agentID, int amount, string text)
198 { 205 {
199 } 206 }
@@ -322,7 +329,7 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule
322 client.SendAlertMessage(e.Message + " "); 329 client.SendAlertMessage(e.Message + " ");
323 } 330 }
324 331
325 client.SendMoneyBalance(TransactionID, true, new byte[0], returnfunds); 332 client.SendMoneyBalance(TransactionID, true, new byte[0], returnfunds, 0, UUID.Zero, false, UUID.Zero, false, 0, String.Empty);
326 } 333 }
327 else 334 else
328 { 335 {
@@ -385,12 +392,12 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule
385 { 392 {
386 if (sender != null) 393 if (sender != null)
387 { 394 {
388 sender.SendMoneyBalance(UUID.Random(), transactionresult, Utils.StringToBytes(description), GetFundsForAgentID(senderID)); 395 sender.SendMoneyBalance(UUID.Random(), transactionresult, Utils.StringToBytes(description), GetFundsForAgentID(senderID), 0, UUID.Zero, false, UUID.Zero, false, 0, String.Empty);
389 } 396 }
390 397
391 if (receiver != null) 398 if (receiver != null)
392 { 399 {
393 receiver.SendMoneyBalance(UUID.Random(), transactionresult, Utils.StringToBytes(description), GetFundsForAgentID(receiverID)); 400 receiver.SendMoneyBalance(UUID.Random(), transactionresult, Utils.StringToBytes(description), GetFundsForAgentID(receiverID), 0, UUID.Zero, false, UUID.Zero, false, 0, String.Empty);
394 } 401 }
395 } 402 }
396 } 403 }
@@ -555,7 +562,7 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule
555 /// <returns></returns> 562 /// <returns></returns>
556 private int GetFundsForAgentID(UUID AgentID) 563 private int GetFundsForAgentID(UUID AgentID)
557 { 564 {
558 int returnfunds = 75004; // Set it to the OpenSim version, plus the IG build number. Muahahaha; 565 int returnfunds = 0;
559 566
560 return returnfunds; 567 return returnfunds;
561 } 568 }
@@ -688,19 +695,14 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule
688 /// Event called Economy Data Request handler. 695 /// Event called Economy Data Request handler.
689 /// </summary> 696 /// </summary>
690 /// <param name="agentId"></param> 697 /// <param name="agentId"></param>
691 public void EconomyDataRequestHandler(UUID agentId) 698 public void EconomyDataRequestHandler(IClientAPI user)
692 { 699 {
693 IClientAPI user = LocateClientObject(agentId); 700 Scene s = (Scene)user.Scene;
694 701
695 if (user != null) 702 user.SendEconomyData(EnergyEfficiency, s.RegionInfo.ObjectCapacity, ObjectCount, PriceEnergyUnit, PriceGroupCreate,
696 { 703 PriceObjectClaim, PriceObjectRent, PriceObjectScaleFactor, PriceParcelClaim, PriceParcelClaimFactor,
697 Scene s = LocateSceneClientIn(user.AgentId); 704 PriceParcelRent, PricePublicObjectDecay, PricePublicObjectDelete, PriceRentLight, PriceUpload,
698 705 TeleportMinPrice, TeleportPriceExponent);
699 user.SendEconomyData(EnergyEfficiency, s.RegionInfo.ObjectCapacity, ObjectCount, PriceEnergyUnit, PriceGroupCreate,
700 PriceObjectClaim, PriceObjectRent, PriceObjectScaleFactor, PriceParcelClaim, PriceParcelClaimFactor,
701 PriceParcelRent, PricePublicObjectDecay, PricePublicObjectDelete, PriceRentLight, PriceUpload,
702 TeleportMinPrice, TeleportPriceExponent);
703 }
704 } 706 }
705 707
706 private void ValidateLandBuy(Object osender, EventManager.LandBuyArgs e) 708 private void ValidateLandBuy(Object osender, EventManager.LandBuyArgs e)
diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
index 5ea2bcd..fb644b7 100644
--- a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
+++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
@@ -44,10 +44,24 @@ namespace OpenSim.Region.OptionalModules.World.NPC
44 { 44 {
45 public bool SenseAsAgent { get; set; } 45 public bool SenseAsAgent { get; set; }
46 46
47 public delegate void ChatToNPC(
48 string message, byte type, Vector3 fromPos, string fromName,
49 UUID fromAgentID, UUID ownerID, byte source, byte audible);
50
51 /// <summary>
52 /// Fired when the NPC receives a chat message.
53 /// </summary>
54 public event ChatToNPC OnChatToNPC;
55
56 /// <summary>
57 /// Fired when the NPC receives an instant message.
58 /// </summary>
59 public event Action<GridInstantMessage> OnInstantMessageToNPC;
60
47 private readonly string m_firstname; 61 private readonly string m_firstname;
48 private readonly string m_lastname; 62 private readonly string m_lastname;
49 private readonly Vector3 m_startPos; 63 private readonly Vector3 m_startPos;
50 private readonly UUID m_uuid = UUID.Random(); 64 private readonly UUID m_uuid;
51 private readonly Scene m_scene; 65 private readonly Scene m_scene;
52 private readonly UUID m_ownerID; 66 private readonly UUID m_ownerID;
53 67
@@ -57,6 +71,19 @@ namespace OpenSim.Region.OptionalModules.World.NPC
57 m_firstname = firstname; 71 m_firstname = firstname;
58 m_lastname = lastname; 72 m_lastname = lastname;
59 m_startPos = position; 73 m_startPos = position;
74 m_uuid = UUID.Random();
75 m_scene = scene;
76 m_ownerID = ownerID;
77 SenseAsAgent = senseAsAgent;
78 }
79
80 public NPCAvatar(
81 string firstname, string lastname, UUID agentID, Vector3 position, UUID ownerID, bool senseAsAgent, Scene scene)
82 {
83 m_firstname = firstname;
84 m_lastname = lastname;
85 m_startPos = position;
86 m_uuid = agentID;
60 m_scene = scene; 87 m_scene = scene;
61 m_ownerID = ownerID; 88 m_ownerID = ownerID;
62 SenseAsAgent = senseAsAgent; 89 SenseAsAgent = senseAsAgent;
@@ -258,6 +285,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
258 public event Action<IClientAPI, bool> OnCompleteMovementToRegion; 285 public event Action<IClientAPI, bool> OnCompleteMovementToRegion;
259 public event UpdateAgent OnPreAgentUpdate; 286 public event UpdateAgent OnPreAgentUpdate;
260 public event UpdateAgent OnAgentUpdate; 287 public event UpdateAgent OnAgentUpdate;
288 public event UpdateAgent OnAgentCameraUpdate;
261 public event AgentRequestSit OnAgentRequestSit; 289 public event AgentRequestSit OnAgentRequestSit;
262 public event AgentSit OnAgentSit; 290 public event AgentSit OnAgentSit;
263 public event AvatarPickerRequest OnAvatarPickerRequest; 291 public event AvatarPickerRequest OnAvatarPickerRequest;
@@ -391,6 +419,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
391 public event EstateTeleportAllUsersHomeRequest OnEstateTeleportAllUsersHomeRequest; 419 public event EstateTeleportAllUsersHomeRequest OnEstateTeleportAllUsersHomeRequest;
392 public event EstateChangeInfo OnEstateChangeInfo; 420 public event EstateChangeInfo OnEstateChangeInfo;
393 public event EstateManageTelehub OnEstateManageTelehub; 421 public event EstateManageTelehub OnEstateManageTelehub;
422 public event CachedTextureRequest OnCachedTextureRequest;
394 public event ScriptReset OnScriptReset; 423 public event ScriptReset OnScriptReset;
395 public event GetScriptRunning OnGetScriptRunning; 424 public event GetScriptRunning OnGetScriptRunning;
396 public event SetScriptRunning OnSetScriptRunning; 425 public event SetScriptRunning OnSetScriptRunning;
@@ -569,6 +598,11 @@ namespace OpenSim.Region.OptionalModules.World.NPC
569 { 598 {
570 } 599 }
571 600
601 public void SendCachedTextureResponse(ISceneEntity avatar, int serial, List<CachedTextureResponseArg> cachedTextures)
602 {
603
604 }
605
572 public virtual void Kick(string message) 606 public virtual void Kick(string message)
573 { 607 {
574 } 608 }
@@ -586,7 +620,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
586 620
587 } 621 }
588 622
589 public virtual void SendKillObject(ulong regionHandle, List<uint> localID) 623 public virtual void SendKillObject(List<uint> localID)
590 { 624 {
591 } 625 }
592 626
@@ -607,25 +641,26 @@ namespace OpenSim.Region.OptionalModules.World.NPC
607 string message, byte type, Vector3 fromPos, string fromName, 641 string message, byte type, Vector3 fromPos, string fromName,
608 UUID fromAgentID, UUID ownerID, byte source, byte audible) 642 UUID fromAgentID, UUID ownerID, byte source, byte audible)
609 { 643 {
610 } 644 ChatToNPC ctn = OnChatToNPC;
611 645
612 public virtual void SendChatMessage( 646 if (ctn != null)
613 byte[] message, byte type, Vector3 fromPos, string fromName, 647 ctn(message, type, fromPos, fromName, fromAgentID, ownerID, source, audible);
614 UUID fromAgentID, UUID ownerID, byte source, byte audible)
615 {
616 } 648 }
617 649
618 public void SendInstantMessage(GridInstantMessage im) 650 public void SendInstantMessage(GridInstantMessage im)
619 { 651 {
620 652 Action<GridInstantMessage> oimtn = OnInstantMessageToNPC;
653
654 if (oimtn != null)
655 oimtn(im);
621 } 656 }
622 657
623 public void SendGenericMessage(string method, List<string> message) 658 public void SendGenericMessage(string method, UUID invoice, List<string> message)
624 { 659 {
625 660
626 } 661 }
627 662
628 public void SendGenericMessage(string method, List<byte[]> message) 663 public void SendGenericMessage(string method, UUID invoice, List<byte[]> message)
629 { 664 {
630 665
631 } 666 }
@@ -688,7 +723,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
688 { 723 {
689 } 724 }
690 725
691 public virtual void SendMoneyBalance(UUID transaction, bool success, byte[] description, int balance) 726 public virtual void SendMoneyBalance(UUID transaction, bool success, byte[] description, int balance, int transactionType, UUID sourceID, bool sourceIsGroup, UUID destID, bool destIsGroup, int amount, string item)
692 { 727 {
693 } 728 }
694 729
@@ -860,11 +895,6 @@ namespace OpenSim.Region.OptionalModules.World.NPC
860 { 895 {
861 } 896 }
862 897
863 public bool AddMoney(int debit)
864 {
865 return false;
866 }
867
868 public void SendSunPos(Vector3 sunPos, Vector3 sunVel, ulong time, uint dlen, uint ylen, float phase) 898 public void SendSunPos(Vector3 sunPos, Vector3 sunVel, ulong time, uint dlen, uint ylen, float phase)
869 { 899 {
870 } 900 }
@@ -1227,12 +1257,17 @@ namespace OpenSim.Region.OptionalModules.World.NPC
1227 { 1257 {
1228 } 1258 }
1229 1259
1230 public void StopFlying(ISceneEntity presence) 1260 public void SendAgentTerseUpdate(ISceneEntity presence)
1231 { 1261 {
1232 } 1262 }
1233 1263
1234 public void SendPlacesReply(UUID queryID, UUID transactionID, PlacesReplyData[] data) 1264 public void SendPlacesReply(UUID queryID, UUID transactionID, PlacesReplyData[] data)
1235 { 1265 {
1236 } 1266 }
1267
1268 public void SendPartPhysicsProprieties(ISceneEntity entity)
1269 {
1270 }
1271
1237 } 1272 }
1238} 1273}
diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs
index d6cf1ab..9232db9 100644
--- a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs
+++ b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs
@@ -116,7 +116,8 @@ namespace OpenSim.Region.OptionalModules.World.NPC
116 return false; 116 return false;
117 117
118 // Delete existing npc attachments 118 // Delete existing npc attachments
119 scene.AttachmentsModule.DeleteAttachmentsFromScene(npc, false); 119 if(scene.AttachmentsModule != null)
120 scene.AttachmentsModule.DeleteAttachmentsFromScene(npc, false);
120 121
121 // XXX: We can't just use IAvatarFactoryModule.SetAppearance() yet 122 // XXX: We can't just use IAvatarFactoryModule.SetAppearance() yet
122 // since it doesn't transfer attachments 123 // since it doesn't transfer attachments
@@ -125,7 +126,8 @@ namespace OpenSim.Region.OptionalModules.World.NPC
125 npc.Appearance = npcAppearance; 126 npc.Appearance = npcAppearance;
126 127
127 // Rez needed npc attachments 128 // Rez needed npc attachments
128 scene.AttachmentsModule.RezAttachments(npc); 129 if (scene.AttachmentsModule != null)
130 scene.AttachmentsModule.RezAttachments(npc);
129 131
130 IAvatarFactoryModule module = 132 IAvatarFactoryModule module =
131 scene.RequestModuleInterface<IAvatarFactoryModule>(); 133 scene.RequestModuleInterface<IAvatarFactoryModule>();
@@ -138,15 +140,37 @@ namespace OpenSim.Region.OptionalModules.World.NPC
138 Vector3 position, UUID owner, bool senseAsAgent, Scene scene, 140 Vector3 position, UUID owner, bool senseAsAgent, Scene scene,
139 AvatarAppearance appearance) 141 AvatarAppearance appearance)
140 { 142 {
141 NPCAvatar npcAvatar = new NPCAvatar(firstname, lastname, position, 143 return CreateNPC(firstname, lastname, position, UUID.Zero, owner, senseAsAgent, scene, appearance);
142 owner, senseAsAgent, scene); 144 }
145
146 public UUID CreateNPC(string firstname, string lastname,
147 Vector3 position, UUID agentID, UUID owner, bool senseAsAgent, Scene scene,
148 AvatarAppearance appearance)
149 {
150 NPCAvatar npcAvatar = null;
151
152 try
153 {
154 if (agentID == UUID.Zero)
155 npcAvatar = new NPCAvatar(firstname, lastname, position,
156 owner, senseAsAgent, scene);
157 else
158 npcAvatar = new NPCAvatar(firstname, lastname, agentID, position,
159 owner, senseAsAgent, scene);
160 }
161 catch (Exception e)
162 {
163 m_log.Info("[NPC MODULE]: exception creating NPC avatar: " + e.ToString());
164 return UUID.Zero;
165 }
166
143 npcAvatar.CircuitCode = (uint)Util.RandomClass.Next(0, 167 npcAvatar.CircuitCode = (uint)Util.RandomClass.Next(0,
144 int.MaxValue); 168 int.MaxValue);
145 169
146 m_log.DebugFormat( 170 m_log.DebugFormat(
147 "[NPC MODULE]: Creating NPC {0} {1} {2}, owner={3}, senseAsAgent={4} at {5} in {6}", 171 "[NPC MODULE]: Creating NPC {0} {1} {2}, owner={3}, senseAsAgent={4} at {5} in {6}",
148 firstname, lastname, npcAvatar.AgentId, owner, 172 firstname, lastname, npcAvatar.AgentId, owner,
149 senseAsAgent, position, scene.RegionInfo.RegionName); 173 senseAsAgent, position, scene.RegionInfo.RegionName);
150 174
151 AgentCircuitData acd = new AgentCircuitData(); 175 AgentCircuitData acd = new AgentCircuitData();
152 acd.AgentID = npcAvatar.AgentId; 176 acd.AgentID = npcAvatar.AgentId;
@@ -154,8 +178,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
154 acd.lastname = lastname; 178 acd.lastname = lastname;
155 acd.ServiceURLs = new Dictionary<string, object>(); 179 acd.ServiceURLs = new Dictionary<string, object>();
156 180
157 AvatarAppearance npcAppearance = new AvatarAppearance(appearance, 181 AvatarAppearance npcAppearance = new AvatarAppearance(appearance, true);
158 true);
159 acd.Appearance = npcAppearance; 182 acd.Appearance = npcAppearance;
160 183
161 /* 184 /*
@@ -173,7 +196,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
173 { 196 {
174 scene.AuthenticateHandler.AddNewCircuit(npcAvatar.CircuitCode, 197 scene.AuthenticateHandler.AddNewCircuit(npcAvatar.CircuitCode,
175 acd); 198 acd);
176 scene.AddNewClient(npcAvatar, PresenceType.Npc); 199 scene.AddNewAgent(npcAvatar, PresenceType.Npc);
177 200
178 ScenePresence sp; 201 ScenePresence sp;
179 if (scene.TryGetScenePresence(npcAvatar.AgentId, out sp)) 202 if (scene.TryGetScenePresence(npcAvatar.AgentId, out sp))
@@ -186,16 +209,16 @@ namespace OpenSim.Region.OptionalModules.World.NPC
186 209
187 sp.CompleteMovement(npcAvatar, false); 210 sp.CompleteMovement(npcAvatar, false);
188 m_avatars.Add(npcAvatar.AgentId, npcAvatar); 211 m_avatars.Add(npcAvatar.AgentId, npcAvatar);
189 m_log.DebugFormat("[NPC MODULE]: Created NPC {0} {1}", 212 m_log.DebugFormat("[NPC MODULE]: Created NPC {0} {1}", npcAvatar.AgentId, sp.Name);
190 npcAvatar.AgentId, sp.Name);
191 213
192 return npcAvatar.AgentId; 214 return npcAvatar.AgentId;
193 } 215 }
194 else 216 else
195 { 217 {
196 m_log.WarnFormat( 218 m_log.WarnFormat(
197 "[NPC MODULE]: Could not find scene presence for NPC {0} {1}", 219 "[NPC MODULE]: Could not find scene presence for NPC {0} {1}",
198 sp.Name, sp.UUID); 220 sp.Name, sp.UUID);
221
199 return UUID.Zero; 222 return UUID.Zero;
200 } 223 }
201 } 224 }
@@ -211,12 +234,13 @@ namespace OpenSim.Region.OptionalModules.World.NPC
211 ScenePresence sp; 234 ScenePresence sp;
212 if (scene.TryGetScenePresence(agentID, out sp)) 235 if (scene.TryGetScenePresence(agentID, out sp))
213 { 236 {
214 /* 237 if (sp.IsSatOnObject || sp.SitGround)
215 m_log.DebugFormat( 238 return false;
216 "[NPC MODULE]: Moving {0} to {1} in {2}, noFly {3}, landAtTarget {4}", 239
217 sp.Name, pos, scene.RegionInfo.RegionName, 240// m_log.DebugFormat(
218 noFly, landAtTarget); 241// "[NPC MODULE]: Moving {0} to {1} in {2}, noFly {3}, landAtTarget {4}",
219 */ 242// sp.Name, pos, scene.RegionInfo.RegionName,
243// noFly, landAtTarget);
220 244
221 sp.MoveToTarget(pos, noFly, landAtTarget); 245 sp.MoveToTarget(pos, noFly, landAtTarget);
222 sp.SetAlwaysRun = running; 246 sp.SetAlwaysRun = running;
@@ -293,9 +317,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
293 ScenePresence sp; 317 ScenePresence sp;
294 if (scene.TryGetScenePresence(agentID, out sp)) 318 if (scene.TryGetScenePresence(agentID, out sp))
295 { 319 {
296 sp.HandleAgentRequestSit(m_avatars[agentID], agentID, 320 sp.HandleAgentRequestSit(m_avatars[agentID], agentID, partID, Vector3.Zero);
297 partID, Vector3.Zero);
298 //sp.HandleAgentSit(m_avatars[agentID], agentID);
299 321
300 return true; 322 return true;
301 } 323 }
@@ -376,23 +398,30 @@ namespace OpenSim.Region.OptionalModules.World.NPC
376 398
377 public bool DeleteNPC(UUID agentID, Scene scene) 399 public bool DeleteNPC(UUID agentID, Scene scene)
378 { 400 {
401 bool doRemove = false;
402 NPCAvatar av;
379 lock (m_avatars) 403 lock (m_avatars)
380 { 404 {
381 NPCAvatar av;
382 if (m_avatars.TryGetValue(agentID, out av)) 405 if (m_avatars.TryGetValue(agentID, out av))
383 { 406 {
384 /* 407 /*
385 m_log.DebugFormat("[NPC MODULE]: Found {0} {1} to remove", 408 m_log.DebugFormat("[NPC MODULE]: Found {0} {1} to remove",
386 agentID, av.Name); 409 agentID, av.Name);
387 */ 410 */
388 scene.RemoveClient(agentID, false); 411 doRemove = true;
412 }
413 }
414
415 if (doRemove)
416 {
417 scene.CloseAgent(agentID, false);
418 lock (m_avatars)
419 {
389 m_avatars.Remove(agentID); 420 m_avatars.Remove(agentID);
390 /*
391 m_log.DebugFormat("[NPC MODULE]: Removed NPC {0} {1}",
392 agentID, av.Name);
393 */
394 return true;
395 } 421 }
422 m_log.DebugFormat("[NPC MODULE]: Removed NPC {0} {1}",
423 agentID, av.Name);
424 return true;
396 } 425 }
397 /* 426 /*
398 m_log.DebugFormat("[NPC MODULE]: Could not find {0} to remove", 427 m_log.DebugFormat("[NPC MODULE]: Could not find {0} to remove",
@@ -416,13 +445,20 @@ namespace OpenSim.Region.OptionalModules.World.NPC
416 /// <summary> 445 /// <summary>
417 /// Check if the caller has permission to manipulate the given NPC. 446 /// Check if the caller has permission to manipulate the given NPC.
418 /// </summary> 447 /// </summary>
448 /// <remarks>
449 /// A caller has permission if
450 /// * The caller UUID given is UUID.Zero.
451 /// * The avatar is unowned (owner is UUID.Zero).
452 /// * The avatar is owned and the owner and callerID match.
453 /// * The avatar is owned and the callerID matches its agentID.
454 /// </remarks>
419 /// <param name="av"></param> 455 /// <param name="av"></param>
420 /// <param name="callerID"></param> 456 /// <param name="callerID"></param>
421 /// <returns>true if they do, false if they don't.</returns> 457 /// <returns>true if they do, false if they don't.</returns>
422 private bool CheckPermissions(NPCAvatar av, UUID callerID) 458 private bool CheckPermissions(NPCAvatar av, UUID callerID)
423 { 459 {
424 return callerID == UUID.Zero || av.OwnerID == UUID.Zero || 460 return callerID == UUID.Zero || av.OwnerID == UUID.Zero ||
425 av.OwnerID == callerID; 461 av.OwnerID == callerID || av.AgentId == callerID;
426 } 462 }
427 } 463 }
428} 464}
diff --git a/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs b/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs
index bf23040..77dfd40 100644
--- a/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs
+++ b/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs
@@ -33,7 +33,6 @@ using Nini.Config;
33using NUnit.Framework; 33using NUnit.Framework;
34using OpenMetaverse; 34using OpenMetaverse;
35using OpenSim.Framework; 35using OpenSim.Framework;
36using OpenSim.Framework.Communications;
37using OpenSim.Region.CoreModules.Avatar.Attachments; 36using OpenSim.Region.CoreModules.Avatar.Attachments;
38using OpenSim.Region.CoreModules.Avatar.AvatarFactory; 37using OpenSim.Region.CoreModules.Avatar.AvatarFactory;
39using OpenSim.Region.CoreModules.Framework.InventoryAccess; 38using OpenSim.Region.CoreModules.Framework.InventoryAccess;
@@ -43,7 +42,6 @@ using OpenSim.Region.Framework.Interfaces;
43using OpenSim.Region.Framework.Scenes; 42using OpenSim.Region.Framework.Scenes;
44using OpenSim.Services.AvatarService; 43using OpenSim.Services.AvatarService;
45using OpenSim.Tests.Common; 44using OpenSim.Tests.Common;
46using OpenSim.Tests.Common.Mock;
47 45
48namespace OpenSim.Region.OptionalModules.World.NPC.Tests 46namespace OpenSim.Region.OptionalModules.World.NPC.Tests
49{ 47{
@@ -71,11 +69,13 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests
71 Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod; 69 Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod;
72 } 70 }
73 71
74 [SetUp] 72 public void SetUpScene()
75 public void Init()
76 { 73 {
77 base.SetUp(); 74 SetUpScene(256, 256);
75 }
78 76
77 public void SetUpScene(uint sizeX, uint sizeY)
78 {
79 IConfigSource config = new IniConfigSource(); 79 IConfigSource config = new IniConfigSource();
80 config.AddConfig("NPC"); 80 config.AddConfig("NPC");
81 config.Configs["NPC"].Set("Enabled", "true"); 81 config.Configs["NPC"].Set("Enabled", "true");
@@ -87,7 +87,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests
87 m_attMod = new AttachmentsModule(); 87 m_attMod = new AttachmentsModule();
88 m_npcMod = new NPCModule(); 88 m_npcMod = new NPCModule();
89 89
90 m_scene = new SceneHelpers().SetupScene(); 90 m_scene = new SceneHelpers().SetupScene("test scene", UUID.Random(), 1000, 1000, sizeX, sizeY, config);
91 SceneHelpers.SetupSceneModules(m_scene, config, m_afMod, m_umMod, m_attMod, m_npcMod, new BasicInventoryAccessModule()); 91 SceneHelpers.SetupSceneModules(m_scene, config, m_afMod, m_umMod, m_attMod, m_npcMod, new BasicInventoryAccessModule());
92 } 92 }
93 93
@@ -97,6 +97,8 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests
97 TestHelpers.InMethod(); 97 TestHelpers.InMethod();
98// log4net.Config.XmlConfigurator.Configure(); 98// log4net.Config.XmlConfigurator.Configure();
99 99
100 SetUpScene();
101
100 ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, TestHelpers.ParseTail(0x1)); 102 ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, TestHelpers.ParseTail(0x1));
101// ScenePresence originalAvatar = scene.GetScenePresence(originalClient.AgentId); 103// ScenePresence originalAvatar = scene.GetScenePresence(originalClient.AgentId);
102 104
@@ -110,7 +112,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests
110 // ScenePresence.SendInitialData() to reset our entire appearance. 112 // ScenePresence.SendInitialData() to reset our entire appearance.
111 m_scene.AssetService.Store(AssetHelpers.CreateNotecardAsset(originalFace8TextureId)); 113 m_scene.AssetService.Store(AssetHelpers.CreateNotecardAsset(originalFace8TextureId));
112 114
113 m_afMod.SetAppearance(sp, originalTe, null); 115 m_afMod.SetAppearance(sp, originalTe, null, null);
114 116
115 UUID npcId = m_npcMod.CreateNPC("John", "Smith", new Vector3(128, 128, 30), UUID.Zero, true, m_scene, sp.Appearance); 117 UUID npcId = m_npcMod.CreateNPC("John", "Smith", new Vector3(128, 128, 30), UUID.Zero, true, m_scene, sp.Appearance);
116 118
@@ -133,6 +135,8 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests
133 TestHelpers.InMethod(); 135 TestHelpers.InMethod();
134// log4net.Config.XmlConfigurator.Configure(); 136// log4net.Config.XmlConfigurator.Configure();
135 137
138 SetUpScene();
139
136 ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, TestHelpers.ParseTail(0x1)); 140 ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, TestHelpers.ParseTail(0x1));
137// ScenePresence originalAvatar = scene.GetScenePresence(originalClient.AgentId); 141// ScenePresence originalAvatar = scene.GetScenePresence(originalClient.AgentId);
138 142
@@ -155,7 +159,9 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests
155 public void TestCreateWithAttachments() 159 public void TestCreateWithAttachments()
156 { 160 {
157 TestHelpers.InMethod(); 161 TestHelpers.InMethod();
158// log4net.Config.XmlConfigurator.Configure(); 162// TestHelpers.EnableLogging();
163
164 SetUpScene();
159 165
160 UUID userId = TestHelpers.ParseTail(0x1); 166 UUID userId = TestHelpers.ParseTail(0x1);
161 UserAccountHelpers.CreateUserWithInventory(m_scene, userId); 167 UserAccountHelpers.CreateUserWithInventory(m_scene, userId);
@@ -191,11 +197,66 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests
191 } 197 }
192 198
193 [Test] 199 [Test]
200 public void TestCreateWithMultiAttachments()
201 {
202 TestHelpers.InMethod();
203// TestHelpers.EnableLogging();
204
205 SetUpScene();
206// m_attMod.DebugLevel = 1;
207
208 UUID userId = TestHelpers.ParseTail(0x1);
209 UserAccountHelpers.CreateUserWithInventory(m_scene, userId);
210 ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, userId);
211
212 InventoryItemBase att1Item
213 = UserInventoryHelpers.CreateInventoryItem(
214 m_scene, "att1", TestHelpers.ParseTail(0x2), TestHelpers.ParseTail(0x3), sp.UUID, InventoryType.Object);
215 InventoryItemBase att2Item
216 = UserInventoryHelpers.CreateInventoryItem(
217 m_scene, "att2", TestHelpers.ParseTail(0x12), TestHelpers.ParseTail(0x13), sp.UUID, InventoryType.Object);
218
219 m_attMod.RezSingleAttachmentFromInventory(sp, att1Item.ID, (uint)AttachmentPoint.Chest);
220 m_attMod.RezSingleAttachmentFromInventory(sp, att2Item.ID, (uint)AttachmentPoint.Chest | 0x80);
221
222 UUID npcId = m_npcMod.CreateNPC("John", "Smith", new Vector3(128, 128, 30), UUID.Zero, true, m_scene, sp.Appearance);
223
224 ScenePresence npc = m_scene.GetScenePresence(npcId);
225
226 // Check scene presence status
227 Assert.That(npc.HasAttachments(), Is.True);
228 List<SceneObjectGroup> attachments = npc.GetAttachments();
229 Assert.That(attachments.Count, Is.EqualTo(2));
230
231 // Just for now, we won't test the name since this is (wrongly) the asset part name rather than the item
232 // name. TODO: Do need to fix ultimately since the item may be renamed before being passed on to an NPC.
233// Assert.That(attSo.Name, Is.EqualTo(attName));
234
235 TestAttachedObject(attachments[0], AttachmentPoint.Chest, npc.UUID);
236 TestAttachedObject(attachments[1], AttachmentPoint.Chest, npc.UUID);
237
238 // Attached objects on the same point must have different FromItemIDs to be shown to other avatars, at least
239 // on Singularity 1.8.5. Otherwise, only one (the first ObjectUpdate sent) appears.
240 Assert.AreNotEqual(attachments[0].FromItemID, attachments[1].FromItemID);
241 }
242
243 private void TestAttachedObject(SceneObjectGroup attSo, AttachmentPoint attPoint, UUID ownerId)
244 {
245 Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)attPoint));
246 Assert.That(attSo.IsAttachment);
247 Assert.That(attSo.UsesPhysics, Is.False);
248 Assert.That(attSo.IsTemporary, Is.False);
249 Assert.That(attSo.OwnerID, Is.EqualTo(ownerId));
250 }
251
252 [Test]
194 public void TestLoadAppearance() 253 public void TestLoadAppearance()
195 { 254 {
196 TestHelpers.InMethod(); 255 TestHelpers.InMethod();
197// log4net.Config.XmlConfigurator.Configure(); 256// log4net.Config.XmlConfigurator.Configure();
198 257
258 SetUpScene();
259
199 UUID userId = TestHelpers.ParseTail(0x1); 260 UUID userId = TestHelpers.ParseTail(0x1);
200 UserAccountHelpers.CreateUserWithInventory(m_scene, userId); 261 UserAccountHelpers.CreateUserWithInventory(m_scene, userId);
201 ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, userId); 262 ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, userId);
@@ -237,7 +298,9 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests
237 public void TestMove() 298 public void TestMove()
238 { 299 {
239 TestHelpers.InMethod(); 300 TestHelpers.InMethod();
240// log4net.Config.XmlConfigurator.Configure(); 301// TestHelpers.EnableLogging();
302
303 SetUpScene();
241 304
242 ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, TestHelpers.ParseTail(0x1)); 305 ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, TestHelpers.ParseTail(0x1));
243// ScenePresence originalAvatar = scene.GetScenePresence(originalClient.AgentId); 306// ScenePresence originalAvatar = scene.GetScenePresence(originalClient.AgentId);
@@ -303,11 +366,64 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests
303 } 366 }
304 367
305 [Test] 368 [Test]
369 public void TestMoveInVarRegion()
370 {
371 TestHelpers.InMethod();
372// TestHelpers.EnableLogging();
373
374 SetUpScene(512, 512);
375
376 ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, TestHelpers.ParseTail(0x1));
377// ScenePresence originalAvatar = scene.GetScenePresence(originalClient.AgentId);
378
379 Vector3 startPos = new Vector3(128, 246, 30);
380 UUID npcId = m_npcMod.CreateNPC("John", "Smith", startPos, UUID.Zero, true, m_scene, sp.Appearance);
381
382 ScenePresence npc = m_scene.GetScenePresence(npcId);
383 Assert.That(npc.AbsolutePosition, Is.EqualTo(startPos));
384
385 // For now, we'll make the scene presence fly to simplify this test, but this needs to change.
386 npc.Flying = true;
387
388 m_scene.Update(1);
389 Assert.That(npc.AbsolutePosition, Is.EqualTo(startPos));
390
391 Vector3 targetPos = startPos + new Vector3(0, 20, 0);
392 m_npcMod.MoveToTarget(npc.UUID, m_scene, targetPos, false, false, false);
393
394 Assert.That(npc.AbsolutePosition, Is.EqualTo(startPos));
395 //Assert.That(npc.Rotation, Is.EqualTo(new Quaternion(0, 0, 0.7071068f, 0.7071068f)));
396 Assert.That(
397 npc.Rotation, new QuaternionToleranceConstraint(new Quaternion(0, 0, 0.7071068f, 0.7071068f), 0.000001));
398
399 m_scene.Update(1);
400
401 // We should really check the exact figure.
402 Assert.That(npc.AbsolutePosition.X, Is.EqualTo(startPos.X));
403 Assert.That(npc.AbsolutePosition.Y, Is.GreaterThan(startPos.Y));
404 Assert.That(npc.AbsolutePosition.Z, Is.EqualTo(startPos.Z));
405 Assert.That(npc.AbsolutePosition.Z, Is.LessThan(targetPos.X));
406
407 for (int i = 0; i < 20; i++)
408 {
409 m_scene.Update(1);
410// Console.WriteLine("pos: {0}", npc.AbsolutePosition);
411 }
412
413 double distanceToTarget = Util.GetDistanceTo(npc.AbsolutePosition, targetPos);
414 Assert.That(distanceToTarget, Is.LessThan(1), "NPC not within 1 unit of target position on first move");
415 Assert.That(npc.AbsolutePosition, Is.EqualTo(targetPos));
416 Assert.That(npc.AgentControlFlags, Is.EqualTo((uint)AgentManager.ControlFlags.NONE));
417 }
418
419 [Test]
306 public void TestSitAndStandWithSitTarget() 420 public void TestSitAndStandWithSitTarget()
307 { 421 {
308 TestHelpers.InMethod(); 422 TestHelpers.InMethod();
309// log4net.Config.XmlConfigurator.Configure(); 423// log4net.Config.XmlConfigurator.Configure();
310 424
425 SetUpScene();
426
311 ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, TestHelpers.ParseTail(0x1)); 427 ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, TestHelpers.ParseTail(0x1));
312 428
313 Vector3 startPos = new Vector3(128, 128, 30); 429 Vector3 startPos = new Vector3(128, 128, 30);
@@ -321,9 +437,9 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests
321 437
322 Assert.That(part.SitTargetAvatar, Is.EqualTo(npcId)); 438 Assert.That(part.SitTargetAvatar, Is.EqualTo(npcId));
323 Assert.That(npc.ParentID, Is.EqualTo(part.LocalId)); 439 Assert.That(npc.ParentID, Is.EqualTo(part.LocalId));
324 Assert.That( 440// Assert.That(
325 npc.AbsolutePosition, 441// npc.AbsolutePosition,
326 Is.EqualTo(part.AbsolutePosition + part.SitTargetPosition + ScenePresence.SIT_TARGET_ADJUSTMENT)); 442// Is.EqualTo(part.AbsolutePosition + part.SitTargetPosition + ScenePresence.SIT_TARGET_ADJUSTMENT));
327 443
328 m_npcMod.Stand(npc.UUID, m_scene); 444 m_npcMod.Stand(npc.UUID, m_scene);
329 445
@@ -335,7 +451,9 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests
335 public void TestSitAndStandWithNoSitTarget() 451 public void TestSitAndStandWithNoSitTarget()
336 { 452 {
337 TestHelpers.InMethod(); 453 TestHelpers.InMethod();
338// log4net.Config.XmlConfigurator.Configure(); 454// TestHelpers.EnableLogging();
455
456 SetUpScene();
339 457
340 ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, TestHelpers.ParseTail(0x1)); 458 ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, TestHelpers.ParseTail(0x1));
341 459
@@ -353,13 +471,11 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests
353 Assert.That(part.SitTargetAvatar, Is.EqualTo(UUID.Zero)); 471 Assert.That(part.SitTargetAvatar, Is.EqualTo(UUID.Zero));
354 Assert.That(npc.ParentID, Is.EqualTo(part.LocalId)); 472 Assert.That(npc.ParentID, Is.EqualTo(part.LocalId));
355 473
356 // FIXME: This is different for live avatars - z position is adjusted. This is half the height of the 474 // We should really be using the NPC size but this would mean preserving the physics actor since it is
357 // default avatar. 475 // removed on sit.
358 // Curiously, Vector3.ToString() will not display the last two places of the float. For example,
359 // printing out npc.AbsolutePosition will give <0, 0, 0.8454993> not <0, 0, 0.845499337>
360 Assert.That( 476 Assert.That(
361 npc.AbsolutePosition, 477 npc.AbsolutePosition,
362 Is.EqualTo(part.AbsolutePosition + new Vector3(0, 0, 0.845499337f))); 478 Is.EqualTo(part.AbsolutePosition + new Vector3(0, 0, sp.PhysicsActor.Size.Z / 2)));
363 479
364 m_npcMod.Stand(npc.UUID, m_scene); 480 m_npcMod.Stand(npc.UUID, m_scene);
365 481
@@ -367,4 +483,4 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests
367 Assert.That(npc.ParentID, Is.EqualTo(0)); 483 Assert.That(npc.ParentID, Is.EqualTo(0));
368 } 484 }
369 } 485 }
370} 486} \ No newline at end of file
diff --git a/OpenSim/Region/OptionalModules/World/SceneCommands/SceneCommandsModule.cs b/OpenSim/Region/OptionalModules/World/SceneCommands/SceneCommandsModule.cs
index 12169ab..0927c4f 100644
--- a/OpenSim/Region/OptionalModules/World/SceneCommands/SceneCommandsModule.cs
+++ b/OpenSim/Region/OptionalModules/World/SceneCommands/SceneCommandsModule.cs
@@ -30,6 +30,7 @@ using System.Collections.Generic;
30using System.Linq; 30using System.Linq;
31using System.Reflection; 31using System.Reflection;
32using System.Text; 32using System.Text;
33using System.Threading;
33using log4net; 34using log4net;
34using Mono.Addins; 35using Mono.Addins;
35using Nini.Config; 36using Nini.Config;
@@ -48,7 +49,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments
48 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "SceneCommandsModule")] 49 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "SceneCommandsModule")]
49 public class SceneCommandsModule : ISceneCommandsModule, INonSharedRegionModule 50 public class SceneCommandsModule : ISceneCommandsModule, INonSharedRegionModule
50 { 51 {
51 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 52// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
52 53
53 private Scene m_scene; 54 private Scene m_scene;
54 55
@@ -93,28 +94,44 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments
93 "Debug", this, "debug scene get", 94 "Debug", this, "debug scene get",
94 "debug scene get", 95 "debug scene get",
95 "List current scene options.", 96 "List current scene options.",
96 "If active is false then main scene update and maintenance loops are suspended.\n" 97 "active - if false then main scene update and maintenance loops are suspended.\n"
97 + "If animations is true then extra animations debug information is logged.\n" 98 + "animations - if true then extra animations debug information is logged.\n"
98 + "If collisions is false then collisions with other objects are turned off.\n" 99 + "appear-refresh - if true then appearance is resent to other avatars every 60 seconds.\n"
99 + "If pbackup is false then periodic scene backup is turned off.\n" 100 + "child-repri - how far an avatar must move in meters before we update the position of its child agents in neighbouring regions.\n"
100 + "If physics is false then all physics objects are non-physical.\n" 101 + "client-pos-upd - the tolerance before clients are updated with new rotation information for an avatar.\n"
101 + "If scripting is false then no scripting operations happen.\n" 102 + "client-rot-upd - the tolerance before clients are updated with new rotation information for an avatar.\n"
102 + "If teleport is true then some extra teleport debug information is logged.\n" 103 + "client-vel-upd - the tolerance before clients are updated with new velocity information for an avatar.\n"
103 + "If updates is true then any frame which exceeds double the maximum desired frame time is logged.", 104 + "root-upd-per - if greater than 1, terse updates are only sent to root agents other than the originator on every n updates.\n"
105 + "child-upd-per - if greater than 1, terse updates are only sent to child agents on every n updates.\n"
106 + "collisions - if false then collisions with other objects are turned off.\n"
107 + "pbackup - if false then periodic scene backup is turned off.\n"
108 + "physics - if false then all physics objects are non-physical.\n"
109 + "scripting - if false then no scripting operations happen.\n"
110 + "teleport - if true then some extra teleport debug information is logged.\n"
111 + "update-on-timer - If true then the scene is updated via a timer. If false then a thread with sleep is used.\n"
112 + "updates - if true then any frame which exceeds double the maximum desired frame time is logged.",
104 HandleDebugSceneGetCommand); 113 HandleDebugSceneGetCommand);
105 114
106 scene.AddCommand( 115 scene.AddCommand(
107 "Debug", this, "debug scene set", 116 "Debug", this, "debug scene set",
108 "debug scene set active|collisions|pbackup|physics|scripting|teleport|updates true|false", 117 "debug scene set <param> <value>",
109 "Turn on scene debugging options.", 118 "Turn on scene debugging options.",
110 "If active is false then main scene update and maintenance loops are suspended.\n" 119 "active - if false then main scene update and maintenance loops are suspended.\n"
111 + "If animations is true then extra animations debug information is logged.\n" 120 + "animations - if true then extra animations debug information is logged.\n"
112 + "If collisions is false then collisions with other objects are turned off.\n" 121 + "appear-refresh - if true then appearance is resent to other avatars every 60 seconds.\n"
113 + "If pbackup is false then periodic scene backup is turned off.\n" 122 + "child-repri - how far an avatar must move in meters before we update the position of its child agents in neighbouring regions.\n"
114 + "If physics is false then all physics objects are non-physical.\n" 123 + "client-pos-upd - the tolerance before clients are updated with new rotation information for an avatar.\n"
115 + "If scripting is false then no scripting operations happen.\n" 124 + "client-rot-upd - the tolerance before clients are updated with new rotation information for an avatar.\n"
116 + "If teleport is true then some extra teleport debug information is logged.\n" 125 + "client-vel-upd - the tolerance before clients are updated with new velocity information for an avatar.\n"
117 + "If updates is true then any frame which exceeds double the maximum desired frame time is logged.", 126 + "root-upd-per - if greater than 1, terse updates are only sent to root agents other than the originator on every n updates.\n"
127 + "child-upd-per - if greater than 1, terse updates are only sent to child agents on every n updates.\n"
128 + "collisions - if false then collisions with other objects are turned off.\n"
129 + "pbackup - if false then periodic scene backup is turned off.\n"
130 + "physics - if false then all physics objects are non-physical.\n"
131 + "scripting - if false then no scripting operations happen.\n"
132 + "teleport - if true then some extra teleport debug information is logged.\n"
133 + "update-on-timer - If true then the scene is updated via a timer. If false then a thread with sleep is used.\n"
134 + "updates - if true then any frame which exceeds double the maximum desired frame time is logged.",
118 HandleDebugSceneSetCommand); 135 HandleDebugSceneSetCommand);
119 } 136 }
120 137
@@ -138,10 +155,18 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments
138 ConsoleDisplayList cdl = new ConsoleDisplayList(); 155 ConsoleDisplayList cdl = new ConsoleDisplayList();
139 cdl.AddRow("active", m_scene.Active); 156 cdl.AddRow("active", m_scene.Active);
140 cdl.AddRow("animations", m_scene.DebugAnimations); 157 cdl.AddRow("animations", m_scene.DebugAnimations);
158 cdl.AddRow("appear-refresh", m_scene.SendPeriodicAppearanceUpdates);
159 cdl.AddRow("child-repri", m_scene.ChildReprioritizationDistance);
160 cdl.AddRow("client-pos-upd", m_scene.RootPositionUpdateTolerance);
161 cdl.AddRow("client-rot-upd", m_scene.RootRotationUpdateTolerance);
162 cdl.AddRow("client-vel-upd", m_scene.RootVelocityUpdateTolerance);
163 cdl.AddRow("root-upd-per", m_scene.RootTerseUpdatePeriod);
164 cdl.AddRow("child-upd-per", m_scene.ChildTerseUpdatePeriod);
141 cdl.AddRow("pbackup", m_scene.PeriodicBackup); 165 cdl.AddRow("pbackup", m_scene.PeriodicBackup);
142 cdl.AddRow("physics", m_scene.PhysicsEnabled); 166 cdl.AddRow("physics", m_scene.PhysicsEnabled);
143 cdl.AddRow("scripting", m_scene.ScriptsEnabled); 167 cdl.AddRow("scripting", m_scene.ScriptsEnabled);
144 cdl.AddRow("teleport", m_scene.DebugTeleporting); 168 cdl.AddRow("teleport", m_scene.DebugTeleporting);
169 cdl.AddRow("update-on-timer", m_scene.UpdateOnTimer);
145 cdl.AddRow("updates", m_scene.DebugUpdates); 170 cdl.AddRow("updates", m_scene.DebugUpdates);
146 171
147 MainConsole.Instance.OutputFormat("Scene {0} options:", m_scene.Name); 172 MainConsole.Instance.OutputFormat("Scene {0} options:", m_scene.Name);
@@ -163,8 +188,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments
163 } 188 }
164 else 189 else
165 { 190 {
166 MainConsole.Instance.Output( 191 MainConsole.Instance.Output("Usage: debug scene set <param> <value>");
167 "Usage: debug scene set active|collisions|pbackup|physics|scripting|teleport|updates true|false");
168 } 192 }
169 } 193 }
170 194
@@ -186,6 +210,69 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments
186 m_scene.DebugAnimations = active; 210 m_scene.DebugAnimations = active;
187 } 211 }
188 212
213 if (options.ContainsKey("appear-refresh"))
214 {
215 bool newValue;
216
217 // FIXME: This can only come from the console at the moment but might not always be true.
218 if (ConsoleUtil.TryParseConsoleBool(MainConsole.Instance, options["appear-refresh"], out newValue))
219 m_scene.SendPeriodicAppearanceUpdates = newValue;
220 }
221
222 if (options.ContainsKey("child-repri"))
223 {
224 double newValue;
225
226 // FIXME: This can only come from the console at the moment but might not always be true.
227 if (ConsoleUtil.TryParseConsoleDouble(MainConsole.Instance, options["child-repri"], out newValue))
228 m_scene.ChildReprioritizationDistance = newValue;
229 }
230
231 if (options.ContainsKey("client-pos-upd"))
232 {
233 float newValue;
234
235 // FIXME: This can only come from the console at the moment but might not always be true.
236 if (ConsoleUtil.TryParseConsoleFloat(MainConsole.Instance, options["client-pos-upd"], out newValue))
237 m_scene.RootPositionUpdateTolerance = newValue;
238 }
239
240 if (options.ContainsKey("client-rot-upd"))
241 {
242 float newValue;
243
244 // FIXME: This can only come from the console at the moment but might not always be true.
245 if (ConsoleUtil.TryParseConsoleFloat(MainConsole.Instance, options["client-rot-upd"], out newValue))
246 m_scene.RootRotationUpdateTolerance = newValue;
247 }
248
249 if (options.ContainsKey("client-vel-upd"))
250 {
251 float newValue;
252
253 // FIXME: This can only come from the console at the moment but might not always be true.
254 if (ConsoleUtil.TryParseConsoleFloat(MainConsole.Instance, options["client-vel-upd"], out newValue))
255 m_scene.RootVelocityUpdateTolerance = newValue;
256 }
257
258 if (options.ContainsKey("root-upd-per"))
259 {
260 int newValue;
261
262 // FIXME: This can only come from the console at the moment but might not always be true.
263 if (ConsoleUtil.TryParseConsoleNaturalInt(MainConsole.Instance, options["root-upd-per"], out newValue))
264 m_scene.RootTerseUpdatePeriod = newValue;
265 }
266
267 if (options.ContainsKey("child-upd-per"))
268 {
269 int newValue;
270
271 // FIXME: This can only come from the console at the moment but might not always be true.
272 if (ConsoleUtil.TryParseConsoleNaturalInt(MainConsole.Instance, options["child-upd-per"], out newValue))
273 m_scene.ChildTerseUpdatePeriod = newValue;
274 }
275
189 if (options.ContainsKey("pbackup")) 276 if (options.ContainsKey("pbackup"))
190 { 277 {
191 bool active; 278 bool active;
@@ -221,6 +308,21 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments
221 m_scene.DebugTeleporting = enableTeleportDebugging; 308 m_scene.DebugTeleporting = enableTeleportDebugging;
222 } 309 }
223 310
311 if (options.ContainsKey("update-on-timer"))
312 {
313 bool enableUpdateOnTimer;
314 if (bool.TryParse(options["update-on-timer"], out enableUpdateOnTimer))
315 {
316 m_scene.UpdateOnTimer = enableUpdateOnTimer;
317 m_scene.Active = false;
318
319 while (m_scene.IsRunning)
320 Thread.Sleep(20);
321
322 m_scene.Active = true;
323 }
324 }
325
224 if (options.ContainsKey("updates")) 326 if (options.ContainsKey("updates"))
225 { 327 {
226 bool enableUpdateDebugging; 328 bool enableUpdateDebugging;
diff --git a/OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs b/OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs
index 8144870..e4a3382 100644
--- a/OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs
+++ b/OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs
@@ -748,8 +748,8 @@ namespace OpenSim.Region.OptionalModules.World.TreePopulator
748 position.X = s_tree.AbsolutePosition.X + (float)randX; 748 position.X = s_tree.AbsolutePosition.X + (float)randX;
749 position.Y = s_tree.AbsolutePosition.Y + (float)randY; 749 position.Y = s_tree.AbsolutePosition.Y + (float)randY;
750 750
751 if (position.X <= ((int)Constants.RegionSize - 1) && position.X >= 0 && 751 if (position.X <= (m_scene.RegionInfo.RegionSizeX - 1) && position.X >= 0 &&
752 position.Y <= ((int)Constants.RegionSize - 1) && position.Y >= 0 && 752 position.Y <= (m_scene.RegionInfo.RegionSizeY - 1) && position.Y >= 0 &&
753 Util.GetDistanceTo(position, copse.m_seed_point) <= copse.m_range) 753 Util.GetDistanceTo(position, copse.m_seed_point) <= copse.m_range)
754 { 754 {
755 UUID uuid = m_scene.RegionInfo.EstateSettings.EstateOwner; 755 UUID uuid = m_scene.RegionInfo.EstateSettings.EstateOwner;
diff --git a/OpenSim/Region/OptionalModules/World/WorldView/WorldViewRequestHandler.cs b/OpenSim/Region/OptionalModules/World/WorldView/WorldViewRequestHandler.cs
index 550b5d4..8720cc7 100644
--- a/OpenSim/Region/OptionalModules/World/WorldView/WorldViewRequestHandler.cs
+++ b/OpenSim/Region/OptionalModules/World/WorldView/WorldViewRequestHandler.cs
@@ -55,7 +55,7 @@ namespace OpenSim.Region.OptionalModules.World.WorldView
55 m_WorldViewModule = fmodule; 55 m_WorldViewModule = fmodule;
56 } 56 }
57 57
58 public override byte[] Handle(string path, Stream requestData, 58 protected override byte[] ProcessRequest(string path, Stream requestData,
59 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) 59 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
60 { 60 {
61 httpResponse.ContentType = "image/jpeg"; 61 httpResponse.ContentType = "image/jpeg";