diff options
Diffstat (limited to 'OpenSim/Region')
307 files changed, 25018 insertions, 8060 deletions
diff --git a/OpenSim/Region/Application/Application.cs b/OpenSim/Region/Application/Application.cs index 0f90d37..c3e7ec2 100644 --- a/OpenSim/Region/Application/Application.cs +++ b/OpenSim/Region/Application/Application.cs | |||
@@ -102,17 +102,50 @@ namespace OpenSim | |||
102 | m_log.InfoFormat( | 102 | m_log.InfoFormat( |
103 | "[OPENSIM MAIN]: Environment variable MONO_THREADS_PER_CPU is {0}", monoThreadsPerCpu ?? "unset"); | 103 | "[OPENSIM MAIN]: Environment variable MONO_THREADS_PER_CPU is {0}", monoThreadsPerCpu ?? "unset"); |
104 | 104 | ||
105 | // Increase the number of IOCP threads available. Mono defaults to a tragically low number | 105 | // Verify the Threadpool allocates or uses enough worker and IO completion threads |
106 | // .NET 2.0 workerthreads default to 50 * numcores | ||
107 | // .NET 3.0 workerthreads defaults to 250 * numcores | ||
108 | // .NET 4.0 workerthreads are dynamic based on bitness and OS resources | ||
109 | // Max IO Completion threads are 1000 on all 3 CLRs. | ||
110 | int workerThreadsMin = 500; | ||
111 | int workerThreadsMax = 1000; // may need further adjustment to match other CLR | ||
112 | int iocpThreadsMin = 1000; | ||
113 | int iocpThreadsMax = 2000; // may need further adjustment to match other CLR | ||
106 | int workerThreads, iocpThreads; | 114 | int workerThreads, iocpThreads; |
107 | System.Threading.ThreadPool.GetMaxThreads(out workerThreads, out iocpThreads); | 115 | System.Threading.ThreadPool.GetMaxThreads(out workerThreads, out iocpThreads); |
108 | m_log.InfoFormat("[OPENSIM MAIN]: Runtime gave us {0} worker threads and {1} IOCP threads", workerThreads, iocpThreads); | 116 | m_log.InfoFormat("[OPENSIM MAIN]: Runtime gave us {0} worker threads and {1} IOCP threads", workerThreads, iocpThreads); |
109 | if (workerThreads < 500 || iocpThreads < 1000) | 117 | if (workerThreads < workerThreadsMin) |
110 | { | 118 | { |
111 | workerThreads = 500; | 119 | workerThreads = workerThreadsMin; |
112 | iocpThreads = 1000; | 120 | m_log.InfoFormat("[OPENSIM MAIN]: Bumping up to worker threads to {0}",workerThreads); |
113 | m_log.Info("[OPENSIM MAIN]: Bumping up to 500 worker threads and 1000 IOCP threads"); | ||
114 | System.Threading.ThreadPool.SetMaxThreads(workerThreads, iocpThreads); | ||
115 | } | 121 | } |
122 | if (workerThreads > workerThreadsMax) | ||
123 | { | ||
124 | workerThreads = workerThreadsMax; | ||
125 | m_log.InfoFormat("[OPENSIM MAIN]: Limiting worker threads to {0}",workerThreads); | ||
126 | } | ||
127 | // Increase the number of IOCP threads available. | ||
128 | // Mono defaults to a tragically low number (24 on 6-core / 8GB Fedora 17) | ||
129 | if (iocpThreads < iocpThreadsMin) | ||
130 | { | ||
131 | iocpThreads = iocpThreadsMin; | ||
132 | m_log.InfoFormat("[OPENSIM MAIN]: Bumping up IO completion threads to {0}",iocpThreads); | ||
133 | } | ||
134 | // Make sure we don't overallocate IOCP threads and thrash system resources | ||
135 | if ( iocpThreads > iocpThreadsMax ) | ||
136 | { | ||
137 | iocpThreads = iocpThreadsMax; | ||
138 | m_log.InfoFormat("[OPENSIM MAIN]: Limiting IO completion threads to {0}",iocpThreads); | ||
139 | } | ||
140 | // set the resulting worker and IO completion thread counts back to ThreadPool | ||
141 | if ( System.Threading.ThreadPool.SetMaxThreads(workerThreads, iocpThreads) ) | ||
142 | { | ||
143 | m_log.InfoFormat("[OPENSIM MAIN]: Threadpool set to {0} worker threads and {1} IO completion threads", workerThreads, iocpThreads); | ||
144 | } | ||
145 | else | ||
146 | { | ||
147 | m_log.Info("[OPENSIM MAIN]: Threadpool reconfiguration failed, runtime defaults still in effect."); | ||
148 | } | ||
116 | 149 | ||
117 | // Check if the system is compatible with OpenSimulator. | 150 | // Check if the system is compatible with OpenSimulator. |
118 | // Ensures that the minimum system requirements are met | 151 | // Ensures that the minimum system requirements are met |
diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs index 08e4023..a7e7d03 100644 --- a/OpenSim/Region/Application/OpenSim.cs +++ b/OpenSim/Region/Application/OpenSim.cs | |||
@@ -30,6 +30,7 @@ using System.Collections; | |||
30 | using System.Collections.Generic; | 30 | using System.Collections.Generic; |
31 | using System.Diagnostics; | 31 | using System.Diagnostics; |
32 | using System.IO; | 32 | using System.IO; |
33 | using System.Linq; | ||
33 | using System.Reflection; | 34 | using System.Reflection; |
34 | using System.Text; | 35 | using System.Text; |
35 | using System.Text.RegularExpressions; | 36 | using System.Text.RegularExpressions; |
@@ -158,6 +159,7 @@ namespace OpenSim | |||
158 | 159 | ||
159 | MainConsole.Instance = m_console; | 160 | MainConsole.Instance = m_console; |
160 | 161 | ||
162 | LogEnvironmentInformation(); | ||
161 | RegisterCommonAppenders(Config.Configs["Startup"]); | 163 | RegisterCommonAppenders(Config.Configs["Startup"]); |
162 | RegisterConsoleCommands(); | 164 | RegisterConsoleCommands(); |
163 | 165 | ||
@@ -236,18 +238,6 @@ namespace OpenSim | |||
236 | + "If an avatar name is given then only packets from that avatar are logged", | 238 | + "If an avatar name is given then only packets from that avatar are logged", |
237 | Debug); | 239 | Debug); |
238 | 240 | ||
239 | m_console.Commands.AddCommand("Debug", false, "debug teleport", "debug teleport", "Toggle teleport route debugging", Debug); | ||
240 | |||
241 | m_console.Commands.AddCommand("Debug", false, "debug scene", | ||
242 | "debug scene active|collisions|physics|scripting|teleport true|false", | ||
243 | "Turn on scene debugging.", | ||
244 | "If active is false then main scene update and maintenance loops are suspended.\n" | ||
245 | + "If collisions is false then collisions with other objects are turned off.\n" | ||
246 | + "If physics is false then all physics objects are non-physical.\n" | ||
247 | + "If scripting is false then no scripting operations happen.\n" | ||
248 | + "If teleport is true then some extra teleport debug information is logged.", | ||
249 | Debug); | ||
250 | |||
251 | m_console.Commands.AddCommand("General", false, "change region", | 241 | m_console.Commands.AddCommand("General", false, "change region", |
252 | "change region <region name>", | 242 | "change region <region name>", |
253 | "Change current console region", ChangeSelectedRegion); | 243 | "Change current console region", ChangeSelectedRegion); |
@@ -744,31 +734,6 @@ namespace OpenSim | |||
744 | 734 | ||
745 | break; | 735 | break; |
746 | 736 | ||
747 | case "scene": | ||
748 | if (args.Length == 4) | ||
749 | { | ||
750 | if (SceneManager.CurrentScene == null) | ||
751 | { | ||
752 | MainConsole.Instance.Output("Please use 'change region <regioname>' first"); | ||
753 | } | ||
754 | else | ||
755 | { | ||
756 | string key = args[2]; | ||
757 | string value = args[3]; | ||
758 | SceneManager.CurrentScene.SetSceneCoreDebug( | ||
759 | new Dictionary<string, string>() { { key, value } }); | ||
760 | |||
761 | MainConsole.Instance.OutputFormat("Set debug scene {0} = {1}", key, value); | ||
762 | } | ||
763 | } | ||
764 | else | ||
765 | { | ||
766 | MainConsole.Instance.Output( | ||
767 | "Usage: debug scene active|scripting|collisions|physics|teleport true|false"); | ||
768 | } | ||
769 | |||
770 | break; | ||
771 | |||
772 | default: | 737 | default: |
773 | MainConsole.Instance.Output("Unknown debug command"); | 738 | MainConsole.Instance.Output("Unknown debug command"); |
774 | break; | 739 | break; |
@@ -845,16 +810,28 @@ namespace OpenSim | |||
845 | break; | 810 | break; |
846 | 811 | ||
847 | case "modules": | 812 | case "modules": |
848 | SceneManager.ForEachScene( | 813 | SceneManager.ForEachSelectedScene( |
849 | delegate(Scene scene) { | 814 | scene => |
850 | MainConsole.Instance.Output("Loaded region modules in" + scene.RegionInfo.RegionName + " are:"); | ||
851 | foreach (IRegionModuleBase module in scene.RegionModules.Values) | ||
852 | { | 815 | { |
853 | Type type = module.GetType().GetInterface("ISharedRegionModule"); | 816 | MainConsole.Instance.OutputFormat("Loaded region modules in {0} are:", scene.Name); |
854 | string module_type = type != null ? "Shared" : "Non-Shared"; | 817 | |
855 | MainConsole.Instance.OutputFormat("New Region Module ({0}): {1}", module_type, module.Name); | 818 | List<IRegionModuleBase> sharedModules = new List<IRegionModuleBase>(); |
819 | List<IRegionModuleBase> nonSharedModules = new List<IRegionModuleBase>(); | ||
820 | |||
821 | foreach (IRegionModuleBase module in scene.RegionModules.Values) | ||
822 | { | ||
823 | if (module.GetType().GetInterface("ISharedRegionModule") != null) | ||
824 | nonSharedModules.Add(module); | ||
825 | else | ||
826 | sharedModules.Add(module); | ||
827 | } | ||
828 | |||
829 | foreach (IRegionModuleBase module in sharedModules.OrderBy(m => m.Name)) | ||
830 | MainConsole.Instance.OutputFormat("New Region Module (Shared): {0}", module.Name); | ||
831 | |||
832 | foreach (IRegionModuleBase module in sharedModules.OrderBy(m => m.Name)) | ||
833 | MainConsole.Instance.OutputFormat("New Region Module (Non-Shared): {0}", module.Name); | ||
856 | } | 834 | } |
857 | } | ||
858 | ); | 835 | ); |
859 | 836 | ||
860 | MainConsole.Instance.Output(""); | 837 | MainConsole.Instance.Output(""); |
diff --git a/OpenSim/Region/Application/OpenSimBase.cs b/OpenSim/Region/Application/OpenSimBase.cs index bed9a49..7361f50 100644 --- a/OpenSim/Region/Application/OpenSimBase.cs +++ b/OpenSim/Region/Application/OpenSimBase.cs | |||
@@ -331,7 +331,7 @@ namespace OpenSim | |||
331 | /// <param name="regionInfo"></param> | 331 | /// <param name="regionInfo"></param> |
332 | /// <param name="portadd_flag"></param> | 332 | /// <param name="portadd_flag"></param> |
333 | /// <returns></returns> | 333 | /// <returns></returns> |
334 | public IClientNetworkServer CreateRegion(RegionInfo regionInfo, bool portadd_flag, out IScene scene) | 334 | public List<IClientNetworkServer> CreateRegion(RegionInfo regionInfo, bool portadd_flag, out IScene scene) |
335 | { | 335 | { |
336 | return CreateRegion(regionInfo, portadd_flag, false, out scene); | 336 | return CreateRegion(regionInfo, portadd_flag, false, out scene); |
337 | } | 337 | } |
@@ -341,7 +341,7 @@ namespace OpenSim | |||
341 | /// </summary> | 341 | /// </summary> |
342 | /// <param name="regionInfo"></param> | 342 | /// <param name="regionInfo"></param> |
343 | /// <returns></returns> | 343 | /// <returns></returns> |
344 | public IClientNetworkServer CreateRegion(RegionInfo regionInfo, out IScene scene) | 344 | public List<IClientNetworkServer> CreateRegion(RegionInfo regionInfo, out IScene scene) |
345 | { | 345 | { |
346 | return CreateRegion(regionInfo, false, true, out scene); | 346 | return CreateRegion(regionInfo, false, true, out scene); |
347 | } | 347 | } |
@@ -353,7 +353,7 @@ namespace OpenSim | |||
353 | /// <param name="portadd_flag"></param> | 353 | /// <param name="portadd_flag"></param> |
354 | /// <param name="do_post_init"></param> | 354 | /// <param name="do_post_init"></param> |
355 | /// <returns></returns> | 355 | /// <returns></returns> |
356 | public IClientNetworkServer CreateRegion(RegionInfo regionInfo, bool portadd_flag, bool do_post_init, out IScene mscene) | 356 | public List<IClientNetworkServer> CreateRegion(RegionInfo regionInfo, bool portadd_flag, bool do_post_init, out IScene mscene) |
357 | { | 357 | { |
358 | int port = regionInfo.InternalEndPoint.Port; | 358 | int port = regionInfo.InternalEndPoint.Port; |
359 | 359 | ||
@@ -378,8 +378,8 @@ namespace OpenSim | |||
378 | Util.XmlRpcCommand(proxyUrl, "AddPort", port, port + proxyOffset, regionInfo.ExternalHostName); | 378 | Util.XmlRpcCommand(proxyUrl, "AddPort", port, port + proxyOffset, regionInfo.ExternalHostName); |
379 | } | 379 | } |
380 | 380 | ||
381 | IClientNetworkServer clientServer; | 381 | List<IClientNetworkServer> clientServers; |
382 | Scene scene = SetupScene(regionInfo, proxyOffset, Config, out clientServer); | 382 | Scene scene = SetupScene(regionInfo, proxyOffset, Config, out clientServers); |
383 | 383 | ||
384 | m_log.Info("[MODULES]: Loading Region's modules (old style)"); | 384 | m_log.Info("[MODULES]: Loading Region's modules (old style)"); |
385 | 385 | ||
@@ -483,8 +483,11 @@ namespace OpenSim | |||
483 | 483 | ||
484 | if (m_autoCreateClientStack) | 484 | if (m_autoCreateClientStack) |
485 | { | 485 | { |
486 | m_clientServers.Add(clientServer); | 486 | foreach (IClientNetworkServer clientserver in clientServers) |
487 | clientServer.Start(); | 487 | { |
488 | m_clientServers.Add(clientserver); | ||
489 | clientserver.Start(); | ||
490 | } | ||
488 | } | 491 | } |
489 | 492 | ||
490 | if (scene.SnmpService != null) | 493 | if (scene.SnmpService != null) |
@@ -504,7 +507,7 @@ namespace OpenSim | |||
504 | scene.Start(); | 507 | scene.Start(); |
505 | scene.StartScripts(); | 508 | scene.StartScripts(); |
506 | 509 | ||
507 | return clientServer; | 510 | return clientServers; |
508 | } | 511 | } |
509 | 512 | ||
510 | /// <summary> | 513 | /// <summary> |
@@ -725,7 +728,7 @@ namespace OpenSim | |||
725 | /// <param name="regionInfo"></param> | 728 | /// <param name="regionInfo"></param> |
726 | /// <param name="clientServer"> </param> | 729 | /// <param name="clientServer"> </param> |
727 | /// <returns></returns> | 730 | /// <returns></returns> |
728 | protected Scene SetupScene(RegionInfo regionInfo, out IClientNetworkServer clientServer) | 731 | protected Scene SetupScene(RegionInfo regionInfo, out List<IClientNetworkServer> clientServer) |
729 | { | 732 | { |
730 | return SetupScene(regionInfo, 0, null, out clientServer); | 733 | return SetupScene(regionInfo, 0, null, out clientServer); |
731 | } | 734 | } |
@@ -739,8 +742,10 @@ namespace OpenSim | |||
739 | /// <param name="clientServer"> </param> | 742 | /// <param name="clientServer"> </param> |
740 | /// <returns></returns> | 743 | /// <returns></returns> |
741 | protected Scene SetupScene( | 744 | protected Scene SetupScene( |
742 | RegionInfo regionInfo, int proxyOffset, IConfigSource configSource, out IClientNetworkServer clientServer) | 745 | RegionInfo regionInfo, int proxyOffset, IConfigSource configSource, out List<IClientNetworkServer> clientServer) |
743 | { | 746 | { |
747 | List<IClientNetworkServer> clientNetworkServers = null; | ||
748 | |||
744 | AgentCircuitManager circuitManager = new AgentCircuitManager(); | 749 | AgentCircuitManager circuitManager = new AgentCircuitManager(); |
745 | IPAddress listenIP = regionInfo.InternalEndPoint.Address; | 750 | IPAddress listenIP = regionInfo.InternalEndPoint.Address; |
746 | //if (!IPAddress.TryParse(regionInfo.InternalEndPoint, out listenIP)) | 751 | //if (!IPAddress.TryParse(regionInfo.InternalEndPoint, out listenIP)) |
@@ -750,8 +755,7 @@ namespace OpenSim | |||
750 | 755 | ||
751 | if (m_autoCreateClientStack) | 756 | if (m_autoCreateClientStack) |
752 | { | 757 | { |
753 | clientServer | 758 | clientNetworkServers = m_clientStackManager.CreateServers( |
754 | = m_clientStackManager.CreateServer( | ||
755 | listenIP, ref port, proxyOffset, regionInfo.m_allow_alternate_ports, configSource, | 759 | listenIP, ref port, proxyOffset, regionInfo.m_allow_alternate_ports, configSource, |
756 | circuitManager); | 760 | circuitManager); |
757 | } | 761 | } |
@@ -766,9 +770,12 @@ namespace OpenSim | |||
766 | 770 | ||
767 | if (m_autoCreateClientStack) | 771 | if (m_autoCreateClientStack) |
768 | { | 772 | { |
769 | clientServer.AddScene(scene); | 773 | foreach (IClientNetworkServer clientnetserver in clientNetworkServers) |
774 | { | ||
775 | clientnetserver.AddScene(scene); | ||
776 | } | ||
770 | } | 777 | } |
771 | 778 | clientServer = clientNetworkServers; | |
772 | scene.LoadWorldMap(); | 779 | scene.LoadWorldMap(); |
773 | 780 | ||
774 | scene.PhysicsScene = GetPhysicsScene(scene.RegionInfo.RegionName); | 781 | scene.PhysicsScene = GetPhysicsScene(scene.RegionInfo.RegionName); |
@@ -791,7 +798,7 @@ namespace OpenSim | |||
791 | 798 | ||
792 | return new Scene( | 799 | return new Scene( |
793 | regionInfo, circuitManager, sceneGridService, | 800 | regionInfo, circuitManager, sceneGridService, |
794 | simDataService, estateDataService, false, | 801 | simDataService, estateDataService, |
795 | Config, m_version); | 802 | Config, m_version); |
796 | } | 803 | } |
797 | 804 | ||
diff --git a/OpenSim/Region/ClientStack/ClientStackManager.cs b/OpenSim/Region/ClientStack/ClientStackManager.cs index 84ea0b3..299aabd 100644 --- a/OpenSim/Region/ClientStack/ClientStackManager.cs +++ b/OpenSim/Region/ClientStack/ClientStackManager.cs | |||
@@ -26,6 +26,7 @@ | |||
26 | */ | 26 | */ |
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Collections.Generic; | ||
29 | using System.Net; | 30 | using System.Net; |
30 | using System.Reflection; | 31 | using System.Reflection; |
31 | using log4net; | 32 | using log4net; |
@@ -38,39 +39,53 @@ namespace OpenSim.Region.ClientStack | |||
38 | { | 39 | { |
39 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 40 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
40 | 41 | ||
41 | private Type plugin; | 42 | private List<Type> plugin = new List<Type>(); |
42 | private Assembly pluginAssembly; | 43 | private List<Assembly> pluginAssembly = new List<Assembly>(); |
43 | 44 | ||
44 | public ClientStackManager(string dllName) | 45 | public ClientStackManager(string pDllName) |
45 | { | 46 | { |
46 | m_log.Info("[CLIENTSTACK]: Attempting to load " + dllName); | 47 | List<string> clientstacks = new List<string>(); |
47 | 48 | if (pDllName.Contains(",")) | |
48 | try | 49 | { |
50 | clientstacks = new List<string>(pDllName.Split(',')); | ||
51 | } | ||
52 | else | ||
49 | { | 53 | { |
50 | plugin = null; | 54 | clientstacks.Add(pDllName); |
51 | pluginAssembly = Assembly.LoadFrom(dllName); | 55 | } |
56 | foreach (string dllName in clientstacks) | ||
57 | { | ||
58 | m_log.Info("[CLIENTSTACK]: Attempting to load " + dllName); | ||
52 | 59 | ||
53 | foreach (Type pluginType in pluginAssembly.GetTypes()) | 60 | try |
54 | { | 61 | { |
55 | if (pluginType.IsPublic) | 62 | //plugin = null; |
56 | { | 63 | Assembly itemAssembly = Assembly.LoadFrom(dllName); |
57 | Type typeInterface = pluginType.GetInterface("IClientNetworkServer", true); | 64 | pluginAssembly.Add(itemAssembly); |
58 | 65 | ||
59 | if (typeInterface != null) | 66 | foreach (Type pluginType in itemAssembly.GetTypes()) |
67 | { | ||
68 | if (pluginType.IsPublic) | ||
60 | { | 69 | { |
61 | m_log.Info("[CLIENTSTACK]: Added IClientNetworkServer Interface"); | 70 | Type typeInterface = pluginType.GetInterface("IClientNetworkServer", true); |
62 | plugin = pluginType; | 71 | |
63 | return; | 72 | if (typeInterface != null) |
73 | { | ||
74 | m_log.Info("[CLIENTSTACK]: Added IClientNetworkServer Interface"); | ||
75 | plugin.Add(pluginType); | ||
76 | break; | ||
77 | } | ||
64 | } | 78 | } |
65 | } | 79 | } |
66 | } | 80 | } |
67 | } catch (ReflectionTypeLoadException e) | 81 | catch (ReflectionTypeLoadException e) |
68 | { | ||
69 | foreach (Exception e2 in e.LoaderExceptions) | ||
70 | { | 82 | { |
71 | m_log.Error(e2.ToString()); | 83 | foreach (Exception e2 in e.LoaderExceptions) |
84 | { | ||
85 | m_log.Error(e2.ToString()); | ||
86 | } | ||
87 | throw e; | ||
72 | } | 88 | } |
73 | throw e; | ||
74 | } | 89 | } |
75 | } | 90 | } |
76 | 91 | ||
@@ -84,11 +99,11 @@ namespace OpenSim.Region.ClientStack | |||
84 | /// <param name="assetCache"></param> | 99 | /// <param name="assetCache"></param> |
85 | /// <param name="authenticateClass"></param> | 100 | /// <param name="authenticateClass"></param> |
86 | /// <returns></returns> | 101 | /// <returns></returns> |
87 | public IClientNetworkServer CreateServer( | 102 | public List<IClientNetworkServer> CreateServers( |
88 | IPAddress _listenIP, ref uint port, int proxyPortOffset, bool allow_alternate_port, | 103 | IPAddress _listenIP, ref uint port, int proxyPortOffset, bool allow_alternate_port, |
89 | AgentCircuitManager authenticateClass) | 104 | AgentCircuitManager authenticateClass) |
90 | { | 105 | { |
91 | return CreateServer( | 106 | return CreateServers( |
92 | _listenIP, ref port, proxyPortOffset, allow_alternate_port, null, authenticateClass); | 107 | _listenIP, ref port, proxyPortOffset, allow_alternate_port, null, authenticateClass); |
93 | } | 108 | } |
94 | 109 | ||
@@ -105,20 +120,24 @@ namespace OpenSim.Region.ClientStack | |||
105 | /// <param name="assetCache"></param> | 120 | /// <param name="assetCache"></param> |
106 | /// <param name="authenticateClass"></param> | 121 | /// <param name="authenticateClass"></param> |
107 | /// <returns></returns> | 122 | /// <returns></returns> |
108 | public IClientNetworkServer CreateServer( | 123 | public List<IClientNetworkServer> CreateServers( |
109 | IPAddress _listenIP, ref uint port, int proxyPortOffset, bool allow_alternate_port, IConfigSource configSource, | 124 | IPAddress _listenIP, ref uint port, int proxyPortOffset, bool allow_alternate_port, IConfigSource configSource, |
110 | AgentCircuitManager authenticateClass) | 125 | AgentCircuitManager authenticateClass) |
111 | { | 126 | { |
127 | List<IClientNetworkServer> servers = new List<IClientNetworkServer>(); | ||
112 | if (plugin != null) | 128 | if (plugin != null) |
113 | { | 129 | { |
114 | IClientNetworkServer server = | 130 | for (int i = 0; i < plugin.Count; i++) |
115 | (IClientNetworkServer)Activator.CreateInstance(pluginAssembly.GetType(plugin.ToString())); | 131 | { |
116 | 132 | IClientNetworkServer server = | |
117 | server.Initialise( | 133 | (IClientNetworkServer) Activator.CreateInstance(pluginAssembly[i].GetType(plugin[i].ToString())); |
118 | _listenIP, ref port, proxyPortOffset, allow_alternate_port, | 134 | |
119 | configSource, authenticateClass); | 135 | server.Initialise( |
120 | 136 | _listenIP, ref port, proxyPortOffset, allow_alternate_port, | |
121 | return server; | 137 | configSource, authenticateClass); |
138 | servers.Add(server); | ||
139 | } | ||
140 | return servers; | ||
122 | } | 141 | } |
123 | 142 | ||
124 | m_log.Error("[CLIENTSTACK]: Couldn't initialize a new server"); | 143 | m_log.Error("[CLIENTSTACK]: Couldn't initialize a new server"); |
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs index b06788b..921d3bf 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs | |||
@@ -50,6 +50,7 @@ using OpenSim.Services.Interfaces; | |||
50 | using Caps = OpenSim.Framework.Capabilities.Caps; | 50 | using Caps = OpenSim.Framework.Capabilities.Caps; |
51 | using OSDArray = OpenMetaverse.StructuredData.OSDArray; | 51 | using OSDArray = OpenMetaverse.StructuredData.OSDArray; |
52 | using OSDMap = OpenMetaverse.StructuredData.OSDMap; | 52 | using OSDMap = OpenMetaverse.StructuredData.OSDMap; |
53 | using PermissionMask = OpenSim.Framework.PermissionMask; | ||
53 | 54 | ||
54 | namespace OpenSim.Region.ClientStack.Linden | 55 | namespace OpenSim.Region.ClientStack.Linden |
55 | { | 56 | { |
@@ -105,7 +106,6 @@ namespace OpenSim.Region.ClientStack.Linden | |||
105 | private static readonly string m_ResourceCostSelectedPath = "0103/"; | 106 | private static readonly string m_ResourceCostSelectedPath = "0103/"; |
106 | private static readonly string m_UpdateAgentInformationPath = "0500/"; | 107 | private static readonly string m_UpdateAgentInformationPath = "0500/"; |
107 | 108 | ||
108 | |||
109 | // These are callbacks which will be setup by the scene so that we can update scene data when we | 109 | // These are callbacks which will be setup by the scene so that we can update scene data when we |
110 | // receive capability calls | 110 | // receive capability calls |
111 | public NewInventoryItem AddNewInventoryItem = null; | 111 | public NewInventoryItem AddNewInventoryItem = null; |
@@ -343,6 +343,9 @@ namespace OpenSim.Region.ClientStack.Linden | |||
343 | m_log.DebugFormat( | 343 | m_log.DebugFormat( |
344 | "[CAPS]: Received SEED caps request in {0} for agent {1}", m_regionName, m_HostCapsObj.AgentID); | 344 | "[CAPS]: Received SEED caps request in {0} for agent {1}", m_regionName, m_HostCapsObj.AgentID); |
345 | 345 | ||
346 | if (!m_HostCapsObj.WaitForActivation()) | ||
347 | return string.Empty; | ||
348 | |||
346 | if (!m_Scene.CheckClient(m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint)) | 349 | if (!m_Scene.CheckClient(m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint)) |
347 | { | 350 | { |
348 | m_log.WarnFormat( | 351 | m_log.WarnFormat( |
@@ -828,9 +831,9 @@ namespace OpenSim.Region.ClientStack.Linden | |||
828 | texitem.Folder = texturesFolder; | 831 | texitem.Folder = texturesFolder; |
829 | 832 | ||
830 | texitem.CurrentPermissions | 833 | texitem.CurrentPermissions |
831 | = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer); | 834 | = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer | PermissionMask.Export); |
832 | 835 | ||
833 | texitem.BasePermissions = (uint)PermissionMask.All; | 836 | texitem.BasePermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export; |
834 | texitem.EveryOnePermissions = 0; | 837 | texitem.EveryOnePermissions = 0; |
835 | texitem.NextPermissions = (uint)PermissionMask.All; | 838 | texitem.NextPermissions = (uint)PermissionMask.All; |
836 | texitem.CreationDate = Util.UnixTimeSinceEpoch(); | 839 | texitem.CreationDate = Util.UnixTimeSinceEpoch(); |
@@ -1095,9 +1098,9 @@ namespace OpenSim.Region.ClientStack.Linden | |||
1095 | else | 1098 | else |
1096 | { | 1099 | { |
1097 | item.CurrentPermissions | 1100 | item.CurrentPermissions |
1098 | = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer); | 1101 | = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer | PermissionMask.Export); |
1099 | 1102 | ||
1100 | item.BasePermissions = (uint)PermissionMask.All; | 1103 | item.BasePermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export; |
1101 | item.EveryOnePermissions = 0; | 1104 | item.EveryOnePermissions = 0; |
1102 | item.NextPermissions = (uint)PermissionMask.All; | 1105 | item.NextPermissions = (uint)PermissionMask.All; |
1103 | } | 1106 | } |
@@ -1317,7 +1320,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
1317 | object_data["PhysicsShapeType"] = obj.PhysicsShapeType; | 1320 | object_data["PhysicsShapeType"] = obj.PhysicsShapeType; |
1318 | object_data["Density"] = obj.Density; | 1321 | object_data["Density"] = obj.Density; |
1319 | object_data["Friction"] = obj.Friction; | 1322 | object_data["Friction"] = obj.Friction; |
1320 | object_data["Restitution"] = obj.Bounciness; | 1323 | object_data["Restitution"] = obj.Restitution; |
1321 | object_data["GravityMultiplier"] = obj.GravityModifier; | 1324 | object_data["GravityMultiplier"] = obj.GravityModifier; |
1322 | 1325 | ||
1323 | resp[uuid.ToString()] = object_data; | 1326 | resp[uuid.ToString()] = object_data; |
@@ -1446,7 +1449,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
1446 | string param, IOSHttpRequest httpRequest, | 1449 | string param, IOSHttpRequest httpRequest, |
1447 | IOSHttpResponse httpResponse) | 1450 | IOSHttpResponse httpResponse) |
1448 | { | 1451 | { |
1449 | OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request); | 1452 | // OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request); |
1450 | OSDMap resp = new OSDMap(); | 1453 | OSDMap resp = new OSDMap(); |
1451 | 1454 | ||
1452 | OSDMap accessPrefs = new OSDMap(); | 1455 | OSDMap accessPrefs = new OSDMap(); |
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs index 986a665..37285e3 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs | |||
@@ -97,6 +97,14 @@ namespace OpenSim.Region.ClientStack.Linden | |||
97 | + " >= 1 - turns on outgoing event logging\n" | 97 | + " >= 1 - turns on outgoing event logging\n" |
98 | + " >= 2 - turns on poll notification", | 98 | + " >= 2 - turns on poll notification", |
99 | HandleDebugEq); | 99 | HandleDebugEq); |
100 | |||
101 | MainConsole.Instance.Commands.AddCommand( | ||
102 | "Debug", | ||
103 | false, | ||
104 | "show eq", | ||
105 | "show eq", | ||
106 | "Show contents of event queues for logged in avatars. Used for debugging.", | ||
107 | HandleShowEq); | ||
100 | } | 108 | } |
101 | 109 | ||
102 | public void RemoveRegion(Scene scene) | 110 | public void RemoveRegion(Scene scene) |
@@ -138,7 +146,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
138 | 146 | ||
139 | if (!(args.Length == 3 && int.TryParse(args[2], out debugLevel))) | 147 | if (!(args.Length == 3 && int.TryParse(args[2], out debugLevel))) |
140 | { | 148 | { |
141 | MainConsole.Instance.OutputFormat("Usage: debug eq [0|1]"); | 149 | MainConsole.Instance.OutputFormat("Usage: debug eq [0|1|2]"); |
142 | } | 150 | } |
143 | else | 151 | else |
144 | { | 152 | { |
@@ -148,6 +156,21 @@ namespace OpenSim.Region.ClientStack.Linden | |||
148 | } | 156 | } |
149 | } | 157 | } |
150 | 158 | ||
159 | protected void HandleShowEq(string module, string[] args) | ||
160 | { | ||
161 | MainConsole.Instance.OutputFormat("For scene {0}", m_scene.Name); | ||
162 | |||
163 | lock (queues) | ||
164 | { | ||
165 | foreach (KeyValuePair<UUID, Queue<OSD>> kvp in queues) | ||
166 | { | ||
167 | MainConsole.Instance.OutputFormat( | ||
168 | "For agent {0} there are {1} messages queued for send.", | ||
169 | kvp.Key, kvp.Value.Count); | ||
170 | } | ||
171 | } | ||
172 | } | ||
173 | |||
151 | /// <summary> | 174 | /// <summary> |
152 | /// Always returns a valid queue | 175 | /// Always returns a valid queue |
153 | /// </summary> | 176 | /// </summary> |
@@ -467,8 +490,8 @@ namespace OpenSim.Region.ClientStack.Linden | |||
467 | responsedata["content_type"] = "text/plain"; | 490 | responsedata["content_type"] = "text/plain"; |
468 | responsedata["keepalive"] = false; | 491 | responsedata["keepalive"] = false; |
469 | responsedata["reusecontext"] = false; | 492 | responsedata["reusecontext"] = false; |
470 | responsedata["str_response_string"] = "Upstream error: "; | 493 | responsedata["str_response_string"] = "<llsd></llsd>"; |
471 | responsedata["error_status_text"] = "Upstream error:"; | 494 | responsedata["error_status_text"] = "<llsd></llsd>"; |
472 | responsedata["http_protocol_version"] = "HTTP/1.0"; | 495 | responsedata["http_protocol_version"] = "HTTP/1.0"; |
473 | return responsedata; | 496 | return responsedata; |
474 | } | 497 | } |
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs index d604cf6..141af8a 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs | |||
@@ -44,13 +44,15 @@ using OpenSim.Tests.Common.Mock; | |||
44 | namespace OpenSim.Region.ClientStack.Linden.Tests | 44 | namespace OpenSim.Region.ClientStack.Linden.Tests |
45 | { | 45 | { |
46 | [TestFixture] | 46 | [TestFixture] |
47 | public class EventQueueTests | 47 | public class EventQueueTests : OpenSimTestCase |
48 | { | 48 | { |
49 | private TestScene m_scene; | 49 | private TestScene m_scene; |
50 | 50 | ||
51 | [SetUp] | 51 | [SetUp] |
52 | public void SetUp() | 52 | public override void SetUp() |
53 | { | 53 | { |
54 | base.SetUp(); | ||
55 | |||
54 | uint port = 9999; | 56 | uint port = 9999; |
55 | uint sslPort = 9998; | 57 | uint sslPort = 9998; |
56 | 58 | ||
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs index d4dbfb9..a42c96c 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs | |||
@@ -56,6 +56,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
56 | public PollServiceTextureEventArgs thepoll; | 56 | public PollServiceTextureEventArgs thepoll; |
57 | public UUID reqID; | 57 | public UUID reqID; |
58 | public Hashtable request; | 58 | public Hashtable request; |
59 | public bool send503; | ||
59 | } | 60 | } |
60 | 61 | ||
61 | public class aPollResponse | 62 | public class aPollResponse |
@@ -244,7 +245,19 @@ namespace OpenSim.Region.ClientStack.Linden | |||
244 | reqinfo.thepoll = this; | 245 | reqinfo.thepoll = this; |
245 | reqinfo.reqID = x; | 246 | reqinfo.reqID = x; |
246 | reqinfo.request = y; | 247 | reqinfo.request = y; |
248 | reqinfo.send503 = false; | ||
247 | 249 | ||
250 | lock (responses) | ||
251 | { | ||
252 | if (responses.Count > 0) | ||
253 | { | ||
254 | if (m_queue.Count >= 4) | ||
255 | { | ||
256 | // Never allow more than 4 fetches to wait | ||
257 | reqinfo.send503 = true; | ||
258 | } | ||
259 | } | ||
260 | } | ||
248 | m_queue.Enqueue(reqinfo); | 261 | m_queue.Enqueue(reqinfo); |
249 | }; | 262 | }; |
250 | 263 | ||
@@ -276,6 +289,22 @@ namespace OpenSim.Region.ClientStack.Linden | |||
276 | 289 | ||
277 | UUID requestID = requestinfo.reqID; | 290 | UUID requestID = requestinfo.reqID; |
278 | 291 | ||
292 | if (requestinfo.send503) | ||
293 | { | ||
294 | response = new Hashtable(); | ||
295 | |||
296 | response["int_response_code"] = 503; | ||
297 | response["str_response_string"] = "Throttled"; | ||
298 | response["content_type"] = "text/plain"; | ||
299 | response["keepalive"] = false; | ||
300 | response["reusecontext"] = false; | ||
301 | |||
302 | lock (responses) | ||
303 | responses[requestID] = new aPollResponse() {bytes = 0, response = response}; | ||
304 | |||
305 | return; | ||
306 | } | ||
307 | |||
279 | // If the avatar is gone, don't bother to get the texture | 308 | // If the avatar is gone, don't bother to get the texture |
280 | if (m_scene.GetScenePresence(Id) == null) | 309 | if (m_scene.GetScenePresence(Id) == null) |
281 | { | 310 | { |
@@ -385,6 +414,9 @@ namespace OpenSim.Region.ClientStack.Linden | |||
385 | GetTextureModule.aPollResponse response; | 414 | GetTextureModule.aPollResponse response; |
386 | if (responses.TryGetValue(key, out response)) | 415 | if (responses.TryGetValue(key, out response)) |
387 | { | 416 | { |
417 | // This is any error response | ||
418 | if (response.bytes == 0) | ||
419 | return true; | ||
388 | 420 | ||
389 | // Normal | 421 | // Normal |
390 | if (BytesSent + response.bytes <= ThrottleBytes) | 422 | if (BytesSent + response.bytes <= ThrottleBytes) |
@@ -411,12 +443,12 @@ namespace OpenSim.Region.ClientStack.Linden | |||
411 | 443 | ||
412 | return haskey; | 444 | return haskey; |
413 | } | 445 | } |
446 | |||
414 | public void ProcessTime() | 447 | public void ProcessTime() |
415 | { | 448 | { |
416 | PassTime(); | 449 | PassTime(); |
417 | } | 450 | } |
418 | 451 | ||
419 | |||
420 | private void PassTime() | 452 | private void PassTime() |
421 | { | 453 | { |
422 | currenttime = Util.EnvironmentTickCount(); | 454 | currenttime = Util.EnvironmentTickCount(); |
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs index 60c1814..1b68603 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs | |||
@@ -57,7 +57,6 @@ namespace OpenSim.Region.ClientStack.Linden | |||
57 | public bool Enabled { get; private set; } | 57 | public bool Enabled { get; private set; } |
58 | 58 | ||
59 | private Scene m_scene; | 59 | private Scene m_scene; |
60 | private UUID m_agentID; | ||
61 | 60 | ||
62 | #region ISharedRegionModule Members | 61 | #region ISharedRegionModule Members |
63 | 62 | ||
@@ -118,13 +117,14 @@ namespace OpenSim.Region.ClientStack.Linden | |||
118 | public void RegisterCaps(UUID agentID, Caps caps) | 117 | public void RegisterCaps(UUID agentID, Caps caps) |
119 | { | 118 | { |
120 | IRequestHandler reqHandler | 119 | IRequestHandler reqHandler |
121 | = new RestHTTPHandler("GET", "/CAPS/" + UUID.Random(), MeshUploadFlag, "MeshUploadFlag", agentID.ToString()); | 120 | = new RestHTTPHandler( |
121 | "GET", "/CAPS/" + UUID.Random(), ht => MeshUploadFlag(ht, agentID), "MeshUploadFlag", agentID.ToString()); | ||
122 | 122 | ||
123 | caps.RegisterHandler("MeshUploadFlag", reqHandler); | 123 | caps.RegisterHandler("MeshUploadFlag", reqHandler); |
124 | m_agentID = agentID; | 124 | |
125 | } | 125 | } |
126 | 126 | ||
127 | private Hashtable MeshUploadFlag(Hashtable mDhttpMethod) | 127 | private Hashtable MeshUploadFlag(Hashtable mDhttpMethod, UUID agentID) |
128 | { | 128 | { |
129 | // m_log.DebugFormat("[MESH UPLOAD FLAG MODULE]: MeshUploadFlag request"); | 129 | // m_log.DebugFormat("[MESH UPLOAD FLAG MODULE]: MeshUploadFlag request"); |
130 | 130 | ||
@@ -148,4 +148,4 @@ namespace OpenSim.Region.ClientStack.Linden | |||
148 | return responsedata; | 148 | return responsedata; |
149 | } | 149 | } |
150 | } | 150 | } |
151 | } \ No newline at end of file | 151 | } |
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs b/OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs index 060a61c..595d01a 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs | |||
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices; | |||
29 | // Build Number | 29 | // Build Number |
30 | // Revision | 30 | // Revision |
31 | // | 31 | // |
32 | [assembly: AssemblyVersion("0.7.5.*")] | 32 | [assembly: AssemblyVersion("0.7.6.*")] |
33 | [assembly: AssemblyFileVersion("1.0.0.0")] | 33 | |
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs index fcac182..79d56c4 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs | |||
@@ -56,8 +56,8 @@ namespace OpenSim.Region.ClientStack.Linden | |||
56 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "RegionConsoleModule")] | 56 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "RegionConsoleModule")] |
57 | public class RegionConsoleModule : INonSharedRegionModule, IRegionConsole | 57 | public class RegionConsoleModule : INonSharedRegionModule, IRegionConsole |
58 | { | 58 | { |
59 | private static readonly ILog m_log = | 59 | // private static readonly ILog m_log = |
60 | LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 60 | // LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
61 | 61 | ||
62 | private Scene m_scene; | 62 | private Scene m_scene; |
63 | private IEventQueue m_eventQueue; | 63 | private IEventQueue m_eventQueue; |
@@ -164,8 +164,8 @@ namespace OpenSim.Region.ClientStack.Linden | |||
164 | 164 | ||
165 | public class ConsoleHandler : BaseStreamHandler | 165 | public class ConsoleHandler : BaseStreamHandler |
166 | { | 166 | { |
167 | private static readonly ILog m_log = | 167 | // private static readonly ILog m_log = |
168 | LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 168 | // LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
169 | 169 | ||
170 | private RegionConsoleModule m_consoleModule; | 170 | private RegionConsoleModule m_consoleModule; |
171 | private UUID m_agentID; | 171 | private UUID m_agentID; |
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs index 191bccf..7d9f935 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs | |||
@@ -59,6 +59,8 @@ namespace OpenSim.Region.ClientStack.Linden | |||
59 | // private static readonly ILog m_log = | 59 | // private static readonly ILog m_log = |
60 | // LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 60 | // LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
61 | 61 | ||
62 | public event SimulatorFeaturesRequestDelegate OnSimulatorFeaturesRequest; | ||
63 | |||
62 | private Scene m_scene; | 64 | private Scene m_scene; |
63 | 65 | ||
64 | /// <summary> | 66 | /// <summary> |
@@ -68,6 +70,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
68 | 70 | ||
69 | private string m_MapImageServerURL = string.Empty; | 71 | private string m_MapImageServerURL = string.Empty; |
70 | private string m_SearchURL = string.Empty; | 72 | private string m_SearchURL = string.Empty; |
73 | private bool m_ExportSupported = false; | ||
71 | 74 | ||
72 | #region ISharedRegionModule Members | 75 | #region ISharedRegionModule Members |
73 | 76 | ||
@@ -85,6 +88,8 @@ namespace OpenSim.Region.ClientStack.Linden | |||
85 | } | 88 | } |
86 | 89 | ||
87 | m_SearchURL = config.GetString("SearchServerURI", string.Empty); | 90 | m_SearchURL = config.GetString("SearchServerURI", string.Empty); |
91 | |||
92 | m_ExportSupported = config.GetBoolean("ExportSupported", m_ExportSupported); | ||
88 | } | 93 | } |
89 | 94 | ||
90 | AddDefaultFeatures(); | 95 | AddDefaultFeatures(); |
@@ -94,6 +99,8 @@ namespace OpenSim.Region.ClientStack.Linden | |||
94 | { | 99 | { |
95 | m_scene = s; | 100 | m_scene = s; |
96 | m_scene.EventManager.OnRegisterCaps += RegisterCaps; | 101 | m_scene.EventManager.OnRegisterCaps += RegisterCaps; |
102 | |||
103 | m_scene.RegisterModuleInterface<ISimulatorFeaturesModule>(this); | ||
97 | } | 104 | } |
98 | 105 | ||
99 | public void RemoveRegion(Scene s) | 106 | public void RemoveRegion(Scene s) |
@@ -148,6 +155,9 @@ namespace OpenSim.Region.ClientStack.Linden | |||
148 | if (m_SearchURL != string.Empty) | 155 | if (m_SearchURL != string.Empty) |
149 | gridServicesMap["search"] = m_SearchURL; | 156 | gridServicesMap["search"] = m_SearchURL; |
150 | m_features["GridServices"] = gridServicesMap; | 157 | m_features["GridServices"] = gridServicesMap; |
158 | |||
159 | if (m_ExportSupported) | ||
160 | m_features["ExportSupported"] = true; | ||
151 | } | 161 | } |
152 | } | 162 | } |
153 | 163 | ||
@@ -156,7 +166,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
156 | IRequestHandler reqHandler | 166 | IRequestHandler reqHandler |
157 | = new RestHTTPHandler( | 167 | = new RestHTTPHandler( |
158 | "GET", "/CAPS/" + UUID.Random(), | 168 | "GET", "/CAPS/" + UUID.Random(), |
159 | HandleSimulatorFeaturesRequest, "SimulatorFeatures", agentID.ToString()); | 169 | x => { return HandleSimulatorFeaturesRequest(x, agentID); }, "SimulatorFeatures", agentID.ToString()); |
160 | 170 | ||
161 | caps.RegisterHandler("SimulatorFeatures", reqHandler); | 171 | caps.RegisterHandler("SimulatorFeatures", reqHandler); |
162 | } | 172 | } |
@@ -185,18 +195,33 @@ namespace OpenSim.Region.ClientStack.Linden | |||
185 | return new OSDMap(m_features); | 195 | return new OSDMap(m_features); |
186 | } | 196 | } |
187 | 197 | ||
188 | private Hashtable HandleSimulatorFeaturesRequest(Hashtable mDhttpMethod) | 198 | private OSDMap DeepCopy() |
199 | { | ||
200 | // This isn't the cheapest way of doing this but the rate | ||
201 | // of occurrence is low (on sim entry only) and it's a sure | ||
202 | // way to get a true deep copy. | ||
203 | OSD copy = OSDParser.DeserializeLLSDXml(OSDParser.SerializeLLSDXmlString(m_features)); | ||
204 | |||
205 | return (OSDMap)copy; | ||
206 | } | ||
207 | |||
208 | private Hashtable HandleSimulatorFeaturesRequest(Hashtable mDhttpMethod, UUID agentID) | ||
189 | { | 209 | { |
190 | // m_log.DebugFormat("[SIMULATOR FEATURES MODULE]: SimulatorFeatures request"); | 210 | // m_log.DebugFormat("[SIMULATOR FEATURES MODULE]: SimulatorFeatures request"); |
191 | 211 | ||
212 | OSDMap copy = DeepCopy(); | ||
213 | |||
214 | SimulatorFeaturesRequestDelegate handlerOnSimulatorFeaturesRequest = OnSimulatorFeaturesRequest; | ||
215 | if (handlerOnSimulatorFeaturesRequest != null) | ||
216 | handlerOnSimulatorFeaturesRequest(agentID, ref copy); | ||
217 | |||
192 | //Send back data | 218 | //Send back data |
193 | Hashtable responsedata = new Hashtable(); | 219 | Hashtable responsedata = new Hashtable(); |
194 | responsedata["int_response_code"] = 200; | 220 | responsedata["int_response_code"] = 200; |
195 | responsedata["content_type"] = "text/plain"; | 221 | responsedata["content_type"] = "text/plain"; |
196 | responsedata["keepalive"] = false; | 222 | responsedata["keepalive"] = false; |
197 | 223 | ||
198 | lock (m_features) | 224 | responsedata["str_response_string"] = OSDParser.SerializeLLSDXmlString(copy); |
199 | responsedata["str_response_string"] = OSDParser.SerializeLLSDXmlString(m_features); | ||
200 | 225 | ||
201 | return responsedata; | 226 | return responsedata; |
202 | } | 227 | } |
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs index 6bed95f..eca576d 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs | |||
@@ -190,8 +190,15 @@ namespace OpenSim.Region.ClientStack.Linden | |||
190 | { | 190 | { |
191 | if (textureEntry.FaceTextures.Length > cacheItems[i].TextureIndex) | 191 | if (textureEntry.FaceTextures.Length > cacheItems[i].TextureIndex) |
192 | { | 192 | { |
193 | cacheItems[i].TextureID = | 193 | Primitive.TextureEntryFace face = textureEntry.FaceTextures[cacheItems[i].TextureIndex]; |
194 | textureEntry.FaceTextures[cacheItems[i].TextureIndex].TextureID; | 194 | if (face == null) |
195 | { | ||
196 | textureEntry.CreateFace(cacheItems[i].TextureIndex); | ||
197 | textureEntry.FaceTextures[cacheItems[i].TextureIndex].TextureID = | ||
198 | AppearanceManager.DEFAULT_AVATAR_TEXTURE; | ||
199 | continue; | ||
200 | } | ||
201 | cacheItems[i].TextureID =face.TextureID; | ||
195 | if (m_scene.AssetService != null) | 202 | if (m_scene.AssetService != null) |
196 | cacheItems[i].TextureAsset = | 203 | cacheItems[i].TextureAsset = |
197 | m_scene.AssetService.GetCached(cacheItems[i].TextureID.ToString()); | 204 | m_scene.AssetService.GetCached(cacheItems[i].TextureID.ToString()); |
@@ -213,8 +220,16 @@ namespace OpenSim.Region.ClientStack.Linden | |||
213 | { | 220 | { |
214 | if (textureEntry.FaceTextures.Length > cacheItems[i].TextureIndex) | 221 | if (textureEntry.FaceTextures.Length > cacheItems[i].TextureIndex) |
215 | { | 222 | { |
223 | Primitive.TextureEntryFace face = textureEntry.FaceTextures[cacheItems[i].TextureIndex]; | ||
224 | if (face == null) | ||
225 | { | ||
226 | textureEntry.CreateFace(cacheItems[i].TextureIndex); | ||
227 | textureEntry.FaceTextures[cacheItems[i].TextureIndex].TextureID = | ||
228 | AppearanceManager.DEFAULT_AVATAR_TEXTURE; | ||
229 | continue; | ||
230 | } | ||
216 | cacheItems[i].TextureID = | 231 | cacheItems[i].TextureID = |
217 | textureEntry.FaceTextures[cacheItems[i].TextureIndex].TextureID; | 232 | face.TextureID; |
218 | } | 233 | } |
219 | else | 234 | else |
220 | { | 235 | { |
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs index 04cd474..707cc93 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs | |||
@@ -39,10 +39,13 @@ using OpenSim.Framework.Servers; | |||
39 | using OpenSim.Framework.Servers.HttpServer; | 39 | using OpenSim.Framework.Servers.HttpServer; |
40 | using OpenSim.Region.Framework.Interfaces; | 40 | using OpenSim.Region.Framework.Interfaces; |
41 | using OpenSim.Region.Framework.Scenes; | 41 | using OpenSim.Region.Framework.Scenes; |
42 | using OpenSim.Framework.Capabilities; | ||
42 | using OpenSim.Services.Interfaces; | 43 | using OpenSim.Services.Interfaces; |
43 | using Caps = OpenSim.Framework.Capabilities.Caps; | 44 | using Caps = OpenSim.Framework.Capabilities.Caps; |
44 | using OpenSim.Capabilities.Handlers; | 45 | using OpenSim.Capabilities.Handlers; |
45 | using OpenSim.Framework.Monitoring; | 46 | using OpenSim.Framework.Monitoring; |
47 | using OpenMetaverse; | ||
48 | using OpenMetaverse.StructuredData; | ||
46 | 49 | ||
47 | namespace OpenSim.Region.ClientStack.Linden | 50 | namespace OpenSim.Region.ClientStack.Linden |
48 | { | 51 | { |
@@ -52,11 +55,13 @@ namespace OpenSim.Region.ClientStack.Linden | |||
52 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "WebFetchInvDescModule")] | 55 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "WebFetchInvDescModule")] |
53 | public class WebFetchInvDescModule : INonSharedRegionModule | 56 | public class WebFetchInvDescModule : INonSharedRegionModule |
54 | { | 57 | { |
55 | struct aPollRequest | 58 | class aPollRequest |
56 | { | 59 | { |
57 | public PollServiceInventoryEventArgs thepoll; | 60 | public PollServiceInventoryEventArgs thepoll; |
58 | public UUID reqID; | 61 | public UUID reqID; |
59 | public Hashtable request; | 62 | public Hashtable request; |
63 | public ScenePresence presence; | ||
64 | public List<UUID> folders; | ||
60 | } | 65 | } |
61 | 66 | ||
62 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 67 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
@@ -71,8 +76,8 @@ namespace OpenSim.Region.ClientStack.Linden | |||
71 | private Dictionary<UUID, string> m_capsDict = new Dictionary<UUID, string>(); | 76 | private Dictionary<UUID, string> m_capsDict = new Dictionary<UUID, string>(); |
72 | private static Thread[] m_workerThreads = null; | 77 | private static Thread[] m_workerThreads = null; |
73 | 78 | ||
74 | private static OpenMetaverse.BlockingQueue<aPollRequest> m_queue = | 79 | private static DoubleQueue<aPollRequest> m_queue = |
75 | new OpenMetaverse.BlockingQueue<aPollRequest>(); | 80 | new DoubleQueue<aPollRequest>(); |
76 | 81 | ||
77 | #region ISharedRegionModule Members | 82 | #region ISharedRegionModule Members |
78 | 83 | ||
@@ -143,12 +148,18 @@ namespace OpenSim.Region.ClientStack.Linden | |||
143 | 148 | ||
144 | private class PollServiceInventoryEventArgs : PollServiceEventArgs | 149 | private class PollServiceInventoryEventArgs : PollServiceEventArgs |
145 | { | 150 | { |
151 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
152 | |||
146 | private Dictionary<UUID, Hashtable> responses = | 153 | private Dictionary<UUID, Hashtable> responses = |
147 | new Dictionary<UUID, Hashtable>(); | 154 | new Dictionary<UUID, Hashtable>(); |
148 | 155 | ||
149 | public PollServiceInventoryEventArgs(UUID pId) : | 156 | private Scene m_scene; |
157 | |||
158 | public PollServiceInventoryEventArgs(Scene scene, UUID pId) : | ||
150 | base(null, null, null, null, pId, int.MaxValue) | 159 | base(null, null, null, null, pId, int.MaxValue) |
151 | { | 160 | { |
161 | m_scene = scene; | ||
162 | |||
152 | HasEvents = (x, y) => { lock (responses) return responses.ContainsKey(x); }; | 163 | HasEvents = (x, y) => { lock (responses) return responses.ContainsKey(x); }; |
153 | GetEvents = (x, y) => | 164 | GetEvents = (x, y) => |
154 | { | 165 | { |
@@ -167,12 +178,68 @@ namespace OpenSim.Region.ClientStack.Linden | |||
167 | 178 | ||
168 | Request = (x, y) => | 179 | Request = (x, y) => |
169 | { | 180 | { |
181 | ScenePresence sp = m_scene.GetScenePresence(Id); | ||
182 | if (sp == null) | ||
183 | { | ||
184 | m_log.ErrorFormat("[INVENTORY]: Unable to find ScenePresence for {0}", Id); | ||
185 | return; | ||
186 | } | ||
187 | |||
170 | aPollRequest reqinfo = new aPollRequest(); | 188 | aPollRequest reqinfo = new aPollRequest(); |
171 | reqinfo.thepoll = this; | 189 | reqinfo.thepoll = this; |
172 | reqinfo.reqID = x; | 190 | reqinfo.reqID = x; |
173 | reqinfo.request = y; | 191 | reqinfo.request = y; |
192 | reqinfo.presence = sp; | ||
193 | reqinfo.folders = new List<UUID>(); | ||
194 | |||
195 | // Decode the request here | ||
196 | string request = y["body"].ToString(); | ||
197 | |||
198 | request = request.Replace("<string>00000000-0000-0000-0000-000000000000</string>", "<uuid>00000000-0000-0000-0000-000000000000</uuid>"); | ||
199 | |||
200 | request = request.Replace("<key>fetch_folders</key><integer>0</integer>", "<key>fetch_folders</key><boolean>0</boolean>"); | ||
201 | request = request.Replace("<key>fetch_folders</key><integer>1</integer>", "<key>fetch_folders</key><boolean>1</boolean>"); | ||
202 | |||
203 | Hashtable hash = new Hashtable(); | ||
204 | try | ||
205 | { | ||
206 | hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request)); | ||
207 | } | ||
208 | catch (LLSD.LLSDParseException e) | ||
209 | { | ||
210 | m_log.ErrorFormat("[INVENTORY]: Fetch error: {0}{1}" + e.Message, e.StackTrace); | ||
211 | m_log.Error("Request: " + request); | ||
212 | return; | ||
213 | } | ||
214 | catch (System.Xml.XmlException) | ||
215 | { | ||
216 | m_log.ErrorFormat("[INVENTORY]: XML Format error"); | ||
217 | } | ||
218 | |||
219 | ArrayList foldersrequested = (ArrayList)hash["folders"]; | ||
220 | |||
221 | bool highPriority = false; | ||
222 | |||
223 | for (int i = 0; i < foldersrequested.Count; i++) | ||
224 | { | ||
225 | Hashtable inventoryhash = (Hashtable)foldersrequested[i]; | ||
226 | string folder = inventoryhash["folder_id"].ToString(); | ||
227 | UUID folderID; | ||
228 | if (UUID.TryParse(folder, out folderID)) | ||
229 | { | ||
230 | if (!reqinfo.folders.Contains(folderID)) | ||
231 | { | ||
232 | if (sp.COF != UUID.Zero && sp.COF == folderID) | ||
233 | highPriority = true; | ||
234 | reqinfo.folders.Add(folderID); | ||
235 | } | ||
236 | } | ||
237 | } | ||
174 | 238 | ||
175 | m_queue.Enqueue(reqinfo); | 239 | if (highPriority) |
240 | m_queue.EnqueueHigh(reqinfo); | ||
241 | else | ||
242 | m_queue.EnqueueLow(reqinfo); | ||
176 | }; | 243 | }; |
177 | 244 | ||
178 | NoEvents = (x, y) => | 245 | NoEvents = (x, y) => |
@@ -208,7 +275,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
208 | response["reusecontext"] = false; | 275 | response["reusecontext"] = false; |
209 | 276 | ||
210 | response["str_response_string"] = m_webFetchHandler.FetchInventoryDescendentsRequest( | 277 | response["str_response_string"] = m_webFetchHandler.FetchInventoryDescendentsRequest( |
211 | requestinfo.request["body"].ToString(), String.Empty, String.Empty, null, null); | 278 | requestinfo.request["body"].ToString(), String.Empty, String.Empty, null, null); |
212 | 279 | ||
213 | lock (responses) | 280 | lock (responses) |
214 | responses[requestID] = response; | 281 | responses[requestID] = response; |
@@ -220,7 +287,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
220 | string capUrl = "/CAPS/" + UUID.Random() + "/"; | 287 | string capUrl = "/CAPS/" + UUID.Random() + "/"; |
221 | 288 | ||
222 | // Register this as a poll service | 289 | // Register this as a poll service |
223 | PollServiceInventoryEventArgs args = new PollServiceInventoryEventArgs(agentID); | 290 | PollServiceInventoryEventArgs args = new PollServiceInventoryEventArgs(m_scene, agentID); |
224 | 291 | ||
225 | args.Type = PollServiceEventArgs.EventType.Inventory; | 292 | args.Type = PollServiceEventArgs.EventType.Inventory; |
226 | MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args); | 293 | MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args); |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index fd82db7..98160c9 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | |||
@@ -51,6 +51,7 @@ using RegionFlags = OpenMetaverse.RegionFlags; | |||
51 | using Nini.Config; | 51 | using Nini.Config; |
52 | 52 | ||
53 | using System.IO; | 53 | using System.IO; |
54 | using PermissionMask = OpenSim.Framework.PermissionMask; | ||
54 | 55 | ||
55 | namespace OpenSim.Region.ClientStack.LindenUDP | 56 | namespace OpenSim.Region.ClientStack.LindenUDP |
56 | { | 57 | { |
@@ -822,6 +823,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
822 | handshake.RegionInfo3.ProductName = Util.StringToBytes256(regionInfo.RegionType); | 823 | handshake.RegionInfo3.ProductName = Util.StringToBytes256(regionInfo.RegionType); |
823 | handshake.RegionInfo3.ProductSKU = Utils.EmptyBytes; | 824 | handshake.RegionInfo3.ProductSKU = Utils.EmptyBytes; |
824 | 825 | ||
826 | handshake.RegionInfo4 = new RegionHandshakePacket.RegionInfo4Block[0]; | ||
825 | // OutPacket(handshake, ThrottleOutPacketType.Task); | 827 | // OutPacket(handshake, ThrottleOutPacketType.Task); |
826 | // use same as MoveAgentIntoRegion (both should be task ) | 828 | // use same as MoveAgentIntoRegion (both should be task ) |
827 | OutPacket(handshake, ThrottleOutPacketType.Unknown); | 829 | OutPacket(handshake, ThrottleOutPacketType.Unknown); |
@@ -901,9 +903,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
901 | } | 903 | } |
902 | } | 904 | } |
903 | 905 | ||
904 | public void SendGenericMessage(string method, List<string> message) | 906 | public void SendGenericMessage(string method, UUID invoice, List<string> message) |
905 | { | 907 | { |
906 | GenericMessagePacket gmp = new GenericMessagePacket(); | 908 | GenericMessagePacket gmp = new GenericMessagePacket(); |
909 | |||
910 | gmp.AgentData.AgentID = AgentId; | ||
911 | gmp.AgentData.SessionID = m_sessionId; | ||
912 | gmp.AgentData.TransactionID = invoice; | ||
913 | |||
907 | gmp.MethodData.Method = Util.StringToBytes256(method); | 914 | gmp.MethodData.Method = Util.StringToBytes256(method); |
908 | gmp.ParamList = new GenericMessagePacket.ParamListBlock[message.Count]; | 915 | gmp.ParamList = new GenericMessagePacket.ParamListBlock[message.Count]; |
909 | int i = 0; | 916 | int i = 0; |
@@ -916,9 +923,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
916 | OutPacket(gmp, ThrottleOutPacketType.Task); | 923 | OutPacket(gmp, ThrottleOutPacketType.Task); |
917 | } | 924 | } |
918 | 925 | ||
919 | public void SendGenericMessage(string method, List<byte[]> message) | 926 | public void SendGenericMessage(string method, UUID invoice, List<byte[]> message) |
920 | { | 927 | { |
921 | GenericMessagePacket gmp = new GenericMessagePacket(); | 928 | GenericMessagePacket gmp = new GenericMessagePacket(); |
929 | |||
930 | gmp.AgentData.AgentID = AgentId; | ||
931 | gmp.AgentData.SessionID = m_sessionId; | ||
932 | gmp.AgentData.TransactionID = invoice; | ||
933 | |||
922 | gmp.MethodData.Method = Util.StringToBytes256(method); | 934 | gmp.MethodData.Method = Util.StringToBytes256(method); |
923 | gmp.ParamList = new GenericMessagePacket.ParamListBlock[message.Count]; | 935 | gmp.ParamList = new GenericMessagePacket.ParamListBlock[message.Count]; |
924 | int i = 0; | 936 | int i = 0; |
@@ -1801,7 +1813,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1801 | 1813 | ||
1802 | public void SendInventoryItemDetails(UUID ownerID, InventoryItemBase item) | 1814 | public void SendInventoryItemDetails(UUID ownerID, InventoryItemBase item) |
1803 | { | 1815 | { |
1804 | const uint FULL_MASK_PERMISSIONS = (uint)PermissionMask.All; | 1816 | // Fudge this value. It's only needed to make the CRC anyway |
1817 | const uint FULL_MASK_PERMISSIONS = (uint)0x7fffffff; | ||
1805 | 1818 | ||
1806 | FetchInventoryReplyPacket inventoryReply = (FetchInventoryReplyPacket)PacketPool.Instance.GetPacket(PacketType.FetchInventoryReply); | 1819 | FetchInventoryReplyPacket inventoryReply = (FetchInventoryReplyPacket)PacketPool.Instance.GetPacket(PacketType.FetchInventoryReply); |
1807 | // TODO: don't create new blocks if recycling an old packet | 1820 | // TODO: don't create new blocks if recycling an old packet |
@@ -2006,7 +2019,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
2006 | 2019 | ||
2007 | protected void SendBulkUpdateInventoryItem(InventoryItemBase item) | 2020 | protected void SendBulkUpdateInventoryItem(InventoryItemBase item) |
2008 | { | 2021 | { |
2009 | const uint FULL_MASK_PERMISSIONS = (uint)PermissionMask.All; | 2022 | const uint FULL_MASK_PERMISSIONS = (uint)0x7ffffff; |
2010 | 2023 | ||
2011 | BulkUpdateInventoryPacket bulkUpdate | 2024 | BulkUpdateInventoryPacket bulkUpdate |
2012 | = (BulkUpdateInventoryPacket)PacketPool.Instance.GetPacket(PacketType.BulkUpdateInventory); | 2025 | = (BulkUpdateInventoryPacket)PacketPool.Instance.GetPacket(PacketType.BulkUpdateInventory); |
@@ -2065,7 +2078,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
2065 | /// <see>IClientAPI.SendInventoryItemCreateUpdate(InventoryItemBase)</see> | 2078 | /// <see>IClientAPI.SendInventoryItemCreateUpdate(InventoryItemBase)</see> |
2066 | public void SendInventoryItemCreateUpdate(InventoryItemBase Item, UUID transactionID, uint callbackId) | 2079 | public void SendInventoryItemCreateUpdate(InventoryItemBase Item, UUID transactionID, uint callbackId) |
2067 | { | 2080 | { |
2068 | const uint FULL_MASK_PERMISSIONS = (uint)PermissionMask.All; | 2081 | const uint FULL_MASK_PERMISSIONS = (uint)0x7fffffff; |
2069 | 2082 | ||
2070 | UpdateCreateInventoryItemPacket InventoryReply | 2083 | UpdateCreateInventoryItemPacket InventoryReply |
2071 | = (UpdateCreateInventoryItemPacket)PacketPool.Instance.GetPacket( | 2084 | = (UpdateCreateInventoryItemPacket)PacketPool.Instance.GetPacket( |
@@ -2654,7 +2667,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
2654 | byte physshapetype = part.PhysicsShapeType; | 2667 | byte physshapetype = part.PhysicsShapeType; |
2655 | float density = part.Density; | 2668 | float density = part.Density; |
2656 | float friction = part.Friction; | 2669 | float friction = part.Friction; |
2657 | float bounce = part.Bounciness; | 2670 | float bounce = part.Restitution; |
2658 | float gravmod = part.GravityModifier; | 2671 | float gravmod = part.GravityModifier; |
2659 | 2672 | ||
2660 | eq.partPhysicsProperties(localid, physshapetype, density, friction, bounce, gravmod,AgentId); | 2673 | eq.partPhysicsProperties(localid, physshapetype, density, friction, bounce, gravmod,AgentId); |
@@ -3604,7 +3617,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3604 | 3617 | ||
3605 | avp.Sender.IsTrial = false; | 3618 | avp.Sender.IsTrial = false; |
3606 | avp.Sender.ID = agentID; | 3619 | avp.Sender.ID = agentID; |
3607 | m_log.DebugFormat("[CLIENT]: Sending appearance for {0} to {1}", agentID.ToString(), AgentId.ToString()); | 3620 | avp.AppearanceData = new AvatarAppearancePacket.AppearanceDataBlock[0]; |
3621 | //m_log.DebugFormat("[CLIENT]: Sending appearance for {0} to {1}", agentID.ToString(), AgentId.ToString()); | ||
3608 | OutPacket(avp, ThrottleOutPacketType.Task); | 3622 | OutPacket(avp, ThrottleOutPacketType.Task); |
3609 | } | 3623 | } |
3610 | 3624 | ||
@@ -3892,6 +3906,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3892 | { | 3906 | { |
3893 | part.Shape.LightEntry = false; | 3907 | part.Shape.LightEntry = false; |
3894 | } | 3908 | } |
3909 | |||
3910 | if (part.Shape != null && (part.Shape.SculptType == (byte)SculptType.Mesh)) | ||
3911 | { | ||
3912 | // Ensure that mesh has at least 8 valid faces | ||
3913 | part.Shape.ProfileBegin = 12500; | ||
3914 | part.Shape.ProfileEnd = 0; | ||
3915 | part.Shape.ProfileHollow = 27500; | ||
3916 | } | ||
3917 | } | ||
3918 | |||
3919 | if (part.Shape != null && (part.Shape.SculptType == (byte)SculptType.Mesh)) | ||
3920 | { | ||
3921 | // Ensure that mesh has at least 8 valid faces | ||
3922 | part.Shape.ProfileBegin = 12500; | ||
3923 | part.Shape.ProfileEnd = 0; | ||
3924 | part.Shape.ProfileHollow = 27500; | ||
3895 | } | 3925 | } |
3896 | } | 3926 | } |
3897 | 3927 | ||
@@ -4208,7 +4238,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4208 | pack.Stat = stats.StatsBlock; | 4238 | pack.Stat = stats.StatsBlock; |
4209 | 4239 | ||
4210 | pack.Header.Reliable = false; | 4240 | pack.Header.Reliable = false; |
4211 | 4241 | pack.RegionInfo = new SimStatsPacket.RegionInfoBlock[0]; | |
4212 | OutPacket(pack, ThrottleOutPacketType.Task); | 4242 | OutPacket(pack, ThrottleOutPacketType.Task); |
4213 | } | 4243 | } |
4214 | 4244 | ||
@@ -4599,7 +4629,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4599 | rinfopack.AgentData = new RegionInfoPacket.AgentDataBlock(); | 4629 | rinfopack.AgentData = new RegionInfoPacket.AgentDataBlock(); |
4600 | rinfopack.AgentData.AgentID = AgentId; | 4630 | rinfopack.AgentData.AgentID = AgentId; |
4601 | rinfopack.AgentData.SessionID = SessionId; | 4631 | rinfopack.AgentData.SessionID = SessionId; |
4602 | 4632 | rinfopack.RegionInfo3 = new RegionInfoPacket.RegionInfo3Block[0]; | |
4603 | 4633 | ||
4604 | OutPacket(rinfopack, ThrottleOutPacketType.Task); | 4634 | OutPacket(rinfopack, ThrottleOutPacketType.Task); |
4605 | } | 4635 | } |
@@ -4952,6 +4982,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4952 | position = part.OffsetPosition + presence.OffsetPosition * part.RotationOffset; | 4982 | position = part.OffsetPosition + presence.OffsetPosition * part.RotationOffset; |
4953 | rotation = part.RotationOffset * presence.Rotation; | 4983 | rotation = part.RotationOffset * presence.Rotation; |
4954 | } | 4984 | } |
4985 | angularVelocity = Vector3.Zero; | ||
4986 | } | ||
4987 | else | ||
4988 | { | ||
4989 | angularVelocity = presence.AngularVelocity; | ||
4990 | rotation = presence.Rotation; | ||
4955 | } | 4991 | } |
4956 | 4992 | ||
4957 | attachPoint = 0; | 4993 | attachPoint = 0; |
@@ -4963,9 +4999,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4963 | // in that direction, even though we don't model this on the server. Implementing this in the future | 4999 | // in that direction, even though we don't model this on the server. Implementing this in the future |
4964 | // may improve movement smoothness. | 5000 | // may improve movement smoothness. |
4965 | // acceleration = new Vector3(1, 0, 0); | 5001 | // acceleration = new Vector3(1, 0, 0); |
4966 | 5002 | ||
4967 | angularVelocity = Vector3.Zero; | ||
4968 | |||
4969 | if (sendTexture) | 5003 | if (sendTexture) |
4970 | textureEntry = presence.Appearance.Texture.GetBytes(); | 5004 | textureEntry = presence.Appearance.Texture.GetBytes(); |
4971 | else | 5005 | else |
@@ -6575,19 +6609,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
6575 | #endregion | 6609 | #endregion |
6576 | 6610 | ||
6577 | AgentRequestSit handlerAgentRequestSit = OnAgentRequestSit; | 6611 | AgentRequestSit handlerAgentRequestSit = OnAgentRequestSit; |
6578 | if (handlerAgentRequestSit != null) | ||
6579 | if (!(agentRequestSit.AgentData == null | ||
6580 | || agentRequestSit.TargetObject == null | ||
6581 | || agentRequestSit.TargetObject.TargetID == null | ||
6582 | || agentRequestSit.TargetObject.Offset == null)) | ||
6583 | { | ||
6584 | var sp = m_scene.GetScenePresence(agentRequestSit.AgentData.AgentID); | ||
6585 | if (sp == null || sp.ParentID != 0) // ignore packet if agent is already sitting | ||
6586 | return true; | ||
6587 | 6612 | ||
6588 | handlerAgentRequestSit(this, agentRequestSit.AgentData.AgentID, | 6613 | if (handlerAgentRequestSit != null) |
6589 | agentRequestSit.TargetObject.TargetID, agentRequestSit.TargetObject.Offset); | 6614 | handlerAgentRequestSit(this, agentRequestSit.AgentData.AgentID, |
6590 | } | 6615 | agentRequestSit.TargetObject.TargetID, agentRequestSit.TargetObject.Offset); |
6591 | } | 6616 | } |
6592 | return true; | 6617 | return true; |
6593 | } | 6618 | } |
@@ -7193,7 +7218,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
7193 | 7218 | ||
7194 | if (handlerUpdatePrimFlags != null) | 7219 | if (handlerUpdatePrimFlags != null) |
7195 | { | 7220 | { |
7196 | byte[] data = Pack.ToBytes(); | 7221 | // byte[] data = Pack.ToBytes(); |
7197 | // 46,47,48 are special positions within the packet | 7222 | // 46,47,48 are special positions within the packet |
7198 | // This may change so perhaps we need a better way | 7223 | // This may change so perhaps we need a better way |
7199 | // of storing this (OMV.FlagUpdatePacket.UsePhysics,etc?) | 7224 | // of storing this (OMV.FlagUpdatePacket.UsePhysics,etc?) |
@@ -9835,7 +9860,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
9835 | EconomyDataRequest handlerEconomoyDataRequest = OnEconomyDataRequest; | 9860 | EconomyDataRequest handlerEconomoyDataRequest = OnEconomyDataRequest; |
9836 | if (handlerEconomoyDataRequest != null) | 9861 | if (handlerEconomoyDataRequest != null) |
9837 | { | 9862 | { |
9838 | handlerEconomoyDataRequest(AgentId); | 9863 | handlerEconomoyDataRequest(this); |
9839 | } | 9864 | } |
9840 | return true; | 9865 | return true; |
9841 | } | 9866 | } |
@@ -12242,11 +12267,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
12242 | if (logPacket) | 12267 | if (logPacket) |
12243 | m_log.DebugFormat( | 12268 | m_log.DebugFormat( |
12244 | "[CLIENT]: PACKET IN from {0} ({1}) in {2} - {3}", | 12269 | "[CLIENT]: PACKET IN from {0} ({1}) in {2} - {3}", |
12245 | Name, SceneAgent.IsChildAgent ? "child" : "root ", m_scene.RegionInfo.RegionName, packet.Type); | 12270 | Name, SceneAgent.IsChildAgent ? "child" : "root ", Scene.Name, packet.Type); |
12246 | } | 12271 | } |
12247 | 12272 | ||
12248 | if (!ProcessPacketMethod(packet)) | 12273 | if (!ProcessPacketMethod(packet)) |
12249 | m_log.Warn("[CLIENT]: unhandled packet " + packet.Type); | 12274 | m_log.WarnFormat( |
12275 | "[CLIENT]: Unhandled packet {0} from {1} ({2}) in {3}. Ignoring.", | ||
12276 | packet.Type, Name, SceneAgent.IsChildAgent ? "child" : "root ", Scene.Name); | ||
12250 | } | 12277 | } |
12251 | 12278 | ||
12252 | private static PrimitiveBaseShape GetShapeFromAddPacket(ObjectAddPacket addPacket) | 12279 | private static PrimitiveBaseShape GetShapeFromAddPacket(ObjectAddPacket addPacket) |
@@ -12454,6 +12481,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
12454 | return String.Empty; | 12481 | return String.Empty; |
12455 | } | 12482 | } |
12456 | 12483 | ||
12484 | public OSDMap OReport(string uptime, string version) | ||
12485 | { | ||
12486 | return new OSDMap(); | ||
12487 | } | ||
12488 | |||
12457 | /// <summary> | 12489 | /// <summary> |
12458 | /// Make an asset request to the asset service in response to a client request. | 12490 | /// Make an asset request to the asset service in response to a client request. |
12459 | /// </summary> | 12491 | /// </summary> |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index da1ccb3..4154ef2 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | |||
@@ -281,25 +281,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
281 | m_shouldCollectStats = false; | 281 | m_shouldCollectStats = false; |
282 | if (config != null) | 282 | if (config != null) |
283 | { | 283 | { |
284 | if (config.Contains("enabled") && config.GetBoolean("enabled")) | 284 | m_shouldCollectStats = config.GetBoolean("Enabled", false); |
285 | { | 285 | binStatsMaxFilesize = TimeSpan.FromSeconds(config.GetInt("packet_headers_period_seconds", 300)); |
286 | if (config.Contains("collect_packet_headers")) | 286 | binStatsDir = config.GetString("stats_dir", "."); |
287 | m_shouldCollectStats = config.GetBoolean("collect_packet_headers"); | 287 | m_aggregatedBWStats = config.GetBoolean("aggregatedBWStats", false); |
288 | if (config.Contains("packet_headers_period_seconds")) | 288 | } |
289 | { | 289 | #endregion BinaryStats |
290 | binStatsMaxFilesize = TimeSpan.FromSeconds(config.GetInt("region_stats_period_seconds")); | ||
291 | } | ||
292 | if (config.Contains("stats_dir")) | ||
293 | { | ||
294 | binStatsDir = config.GetString("stats_dir"); | ||
295 | } | ||
296 | } | ||
297 | else | ||
298 | { | ||
299 | m_shouldCollectStats = false; | ||
300 | } | ||
301 | } | ||
302 | #endregion BinaryStats | ||
303 | 290 | ||
304 | m_throttle = new TokenBucket(null, sceneThrottleBps); | 291 | m_throttle = new TokenBucket(null, sceneThrottleBps); |
305 | ThrottleRates = new ThrottleRates(configSource); | 292 | ThrottleRates = new ThrottleRates(configSource); |
@@ -1309,8 +1296,34 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1309 | static object binStatsLogLock = new object(); | 1296 | static object binStatsLogLock = new object(); |
1310 | static string binStatsDir = ""; | 1297 | static string binStatsDir = ""; |
1311 | 1298 | ||
1299 | //for Aggregated In/Out BW logging | ||
1300 | static bool m_aggregatedBWStats = false; | ||
1301 | static long m_aggregatedBytesIn = 0; | ||
1302 | static long m_aggregatedByestOut = 0; | ||
1303 | static object aggBWStatsLock = new object(); | ||
1304 | |||
1305 | public static long AggregatedLLUDPBytesIn | ||
1306 | { | ||
1307 | get { return m_aggregatedBytesIn; } | ||
1308 | } | ||
1309 | public static long AggregatedLLUDPBytesOut | ||
1310 | { | ||
1311 | get {return m_aggregatedByestOut;} | ||
1312 | } | ||
1313 | |||
1312 | public static void LogPacketHeader(bool incoming, uint circuit, byte flags, PacketType packetType, ushort size) | 1314 | public static void LogPacketHeader(bool incoming, uint circuit, byte flags, PacketType packetType, ushort size) |
1313 | { | 1315 | { |
1316 | if (m_aggregatedBWStats) | ||
1317 | { | ||
1318 | lock (aggBWStatsLock) | ||
1319 | { | ||
1320 | if (incoming) | ||
1321 | m_aggregatedBytesIn += size; | ||
1322 | else | ||
1323 | m_aggregatedByestOut += size; | ||
1324 | } | ||
1325 | } | ||
1326 | |||
1314 | if (!m_shouldCollectStats) return; | 1327 | if (!m_shouldCollectStats) return; |
1315 | 1328 | ||
1316 | // Binary logging format is TTTTTTTTCCCCFPPPSS, T=Time, C=Circuit, F=Flags, P=PacketType, S=size | 1329 | // Binary logging format is TTTTTTTTCCCCFPPPSS, T=Time, C=Circuit, F=Flags, P=PacketType, S=size |
@@ -1903,112 +1916,4 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1903 | } | 1916 | } |
1904 | } | 1917 | } |
1905 | } | 1918 | } |
1906 | |||
1907 | internal class DoubleQueue<T> where T:class | ||
1908 | { | ||
1909 | private Queue<T> m_lowQueue = new Queue<T>(); | ||
1910 | private Queue<T> m_highQueue = new Queue<T>(); | ||
1911 | |||
1912 | private object m_syncRoot = new object(); | ||
1913 | private Semaphore m_s = new Semaphore(0, 1); | ||
1914 | |||
1915 | public DoubleQueue() | ||
1916 | { | ||
1917 | } | ||
1918 | |||
1919 | public virtual int Count | ||
1920 | { | ||
1921 | get { return m_highQueue.Count + m_lowQueue.Count; } | ||
1922 | } | ||
1923 | |||
1924 | public virtual void Enqueue(T data) | ||
1925 | { | ||
1926 | Enqueue(m_lowQueue, data); | ||
1927 | } | ||
1928 | |||
1929 | public virtual void EnqueueLow(T data) | ||
1930 | { | ||
1931 | Enqueue(m_lowQueue, data); | ||
1932 | } | ||
1933 | |||
1934 | public virtual void EnqueueHigh(T data) | ||
1935 | { | ||
1936 | Enqueue(m_highQueue, data); | ||
1937 | } | ||
1938 | |||
1939 | private void Enqueue(Queue<T> q, T data) | ||
1940 | { | ||
1941 | lock (m_syncRoot) | ||
1942 | { | ||
1943 | m_lowQueue.Enqueue(data); | ||
1944 | m_s.WaitOne(0); | ||
1945 | m_s.Release(); | ||
1946 | } | ||
1947 | } | ||
1948 | |||
1949 | public virtual T Dequeue() | ||
1950 | { | ||
1951 | return Dequeue(Timeout.Infinite); | ||
1952 | } | ||
1953 | |||
1954 | public virtual T Dequeue(int tmo) | ||
1955 | { | ||
1956 | return Dequeue(TimeSpan.FromMilliseconds(tmo)); | ||
1957 | } | ||
1958 | |||
1959 | public virtual T Dequeue(TimeSpan wait) | ||
1960 | { | ||
1961 | T res = null; | ||
1962 | |||
1963 | if (!Dequeue(wait, ref res)) | ||
1964 | return null; | ||
1965 | |||
1966 | return res; | ||
1967 | } | ||
1968 | |||
1969 | public bool Dequeue(int timeout, ref T res) | ||
1970 | { | ||
1971 | return Dequeue(TimeSpan.FromMilliseconds(timeout), ref res); | ||
1972 | } | ||
1973 | |||
1974 | public bool Dequeue(TimeSpan wait, ref T res) | ||
1975 | { | ||
1976 | if (!m_s.WaitOne(wait)) | ||
1977 | return false; | ||
1978 | |||
1979 | lock (m_syncRoot) | ||
1980 | { | ||
1981 | if (m_highQueue.Count > 0) | ||
1982 | res = m_highQueue.Dequeue(); | ||
1983 | else | ||
1984 | res = m_lowQueue.Dequeue(); | ||
1985 | |||
1986 | if (m_highQueue.Count == 0 && m_lowQueue.Count == 0) | ||
1987 | return true; | ||
1988 | |||
1989 | try | ||
1990 | { | ||
1991 | m_s.Release(); | ||
1992 | } | ||
1993 | catch | ||
1994 | { | ||
1995 | } | ||
1996 | |||
1997 | return true; | ||
1998 | } | ||
1999 | } | ||
2000 | |||
2001 | public virtual void Clear() | ||
2002 | { | ||
2003 | |||
2004 | lock (m_syncRoot) | ||
2005 | { | ||
2006 | // Make sure sem count is 0 | ||
2007 | m_s.WaitOne(0); | ||
2008 | |||
2009 | m_lowQueue.Clear(); | ||
2010 | m_highQueue.Clear(); | ||
2011 | } | ||
2012 | } | ||
2013 | } | ||
2014 | } | 1919 | } |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs index 2aeb4cc..7035e38 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs | |||
@@ -204,9 +204,12 @@ namespace OpenMetaverse | |||
204 | { | 204 | { |
205 | UDPPacketBuffer buf; | 205 | UDPPacketBuffer buf; |
206 | 206 | ||
207 | if (UsePools) | 207 | // FIXME: Disabled for now as this causes issues with reused packet objects interfering with each other |
208 | buf = Pool.GetObject(); | 208 | // on Windows with m_asyncPacketHandling = true, though this has not been seen on Linux. |
209 | else | 209 | // Possibly some unexpected issue with fetching UDP data concurrently with multiple threads. Requires more investigation. |
210 | // if (UsePools) | ||
211 | // buf = Pool.GetObject(); | ||
212 | // else | ||
210 | buf = new UDPPacketBuffer(); | 213 | buf = new UDPPacketBuffer(); |
211 | 214 | ||
212 | if (IsRunningInbound) | 215 | if (IsRunningInbound) |
@@ -287,8 +290,8 @@ namespace OpenMetaverse | |||
287 | catch (ObjectDisposedException) { } | 290 | catch (ObjectDisposedException) { } |
288 | finally | 291 | finally |
289 | { | 292 | { |
290 | if (UsePools) | 293 | // if (UsePools) |
291 | Pool.ReturnObject(buffer); | 294 | // Pool.ReturnObject(buffer); |
292 | 295 | ||
293 | // Synchronous mode waits until the packet callback completes | 296 | // Synchronous mode waits until the packet callback completes |
294 | // before starting the receive to fetch another packet | 297 | // before starting the receive to fetch another packet |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs b/OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs index af2f6f8..98ef72f 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs | |||
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices; | |||
29 | // Build Number | 29 | // Build Number |
30 | // Revision | 30 | // Revision |
31 | // | 31 | // |
32 | [assembly: AssemblyVersion("0.7.5.*")] | 32 | [assembly: AssemblyVersion("0.7.6.*")] |
33 | [assembly: AssemblyFileVersion("1.0.0.0")] | 33 | |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs index 5fcf376..7d9f581 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs | |||
@@ -43,7 +43,7 @@ using OpenSim.Tests.Common.Mock; | |||
43 | namespace OpenSim.Region.ClientStack.LindenUDP.Tests | 43 | namespace OpenSim.Region.ClientStack.LindenUDP.Tests |
44 | { | 44 | { |
45 | [TestFixture] | 45 | [TestFixture] |
46 | public class LLImageManagerTests | 46 | public class LLImageManagerTests : OpenSimTestCase |
47 | { | 47 | { |
48 | private AssetBase m_testImageAsset; | 48 | private AssetBase m_testImageAsset; |
49 | private Scene scene; | 49 | private Scene scene; |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/PacketHandlerTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/PacketHandlerTests.cs index 0f88ec6..5f73a94 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/PacketHandlerTests.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/PacketHandlerTests.cs | |||
@@ -39,7 +39,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests | |||
39 | /// Tests for the LL packet handler | 39 | /// Tests for the LL packet handler |
40 | /// </summary> | 40 | /// </summary> |
41 | [TestFixture] | 41 | [TestFixture] |
42 | public class PacketHandlerTests | 42 | public class PacketHandlerTests : OpenSimTestCase |
43 | { | 43 | { |
44 | // [Test] | 44 | // [Test] |
45 | // /// <summary> | 45 | // /// <summary> |
diff --git a/OpenSim/Region/ClientStack/Properties/AssemblyInfo.cs b/OpenSim/Region/ClientStack/Properties/AssemblyInfo.cs index e72bd86..0b6ee2f 100644 --- a/OpenSim/Region/ClientStack/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/ClientStack/Properties/AssemblyInfo.cs | |||
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices; | |||
29 | // Build Number | 29 | // Build Number |
30 | // Revision | 30 | // Revision |
31 | // | 31 | // |
32 | [assembly: AssemblyVersion("0.7.5.*")] | 32 | [assembly: AssemblyVersion("0.7.6.*")] |
33 | [assembly: AssemblyFileVersion("1.0.0.0")] | 33 | [assembly: AssemblyFileVersion("1.0.0.0")] |
diff --git a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetTransactionModule.cs b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetTransactionModule.cs index 7332415..f489262 100644 --- a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetTransactionModule.cs +++ b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetTransactionModule.cs | |||
@@ -42,7 +42,7 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction | |||
42 | public class AssetTransactionModule : INonSharedRegionModule, | 42 | public class AssetTransactionModule : INonSharedRegionModule, |
43 | IAgentAssetTransactions | 43 | IAgentAssetTransactions |
44 | { | 44 | { |
45 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 45 | // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
46 | 46 | ||
47 | protected Scene m_Scene; | 47 | protected Scene m_Scene; |
48 | private bool m_dumpAssetsToFile = false; | 48 | private bool m_dumpAssetsToFile = false; |
@@ -214,9 +214,9 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction | |||
214 | public void HandleTaskItemUpdateFromTransaction( | 214 | public void HandleTaskItemUpdateFromTransaction( |
215 | IClientAPI remoteClient, SceneObjectPart part, UUID transactionID, TaskInventoryItem item) | 215 | IClientAPI remoteClient, SceneObjectPart part, UUID transactionID, TaskInventoryItem item) |
216 | { | 216 | { |
217 | m_log.DebugFormat( | 217 | // m_log.DebugFormat( |
218 | "[ASSET TRANSACTION MODULE] Called HandleTaskItemUpdateFromTransaction with item {0} in {1} for {2} in {3}", | 218 | // "[ASSET TRANSACTION MODULE]: Called HandleTaskItemUpdateFromTransaction with item {0} in {1} for {2} in {3}", |
219 | item.Name, part.Name, remoteClient.Name, m_Scene.RegionInfo.RegionName); | 219 | // item.Name, part.Name, remoteClient.Name, m_Scene.RegionInfo.RegionName); |
220 | 220 | ||
221 | AgentAssetTransactions transactions = | 221 | AgentAssetTransactions transactions = |
222 | GetUserTransactions(remoteClient.AgentId); | 222 | GetUserTransactions(remoteClient.AgentId); |
@@ -230,15 +230,17 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction | |||
230 | /// </summary> | 230 | /// </summary> |
231 | /// <param name="remoteClient"></param> | 231 | /// <param name="remoteClient"></param> |
232 | /// <param name="assetID"></param> | 232 | /// <param name="assetID"></param> |
233 | /// <param name="transaction"></param> | 233 | /// <param name="transactionID"></param> |
234 | /// <param name="type"></param> | 234 | /// <param name="type"></param> |
235 | /// <param name="data"></param></param> | 235 | /// <param name="data"></param></param> |
236 | /// <param name="tempFile"></param> | 236 | /// <param name="tempFile"></param> |
237 | public void HandleUDPUploadRequest(IClientAPI remoteClient, | 237 | public void HandleUDPUploadRequest(IClientAPI remoteClient, |
238 | UUID assetID, UUID transaction, sbyte type, byte[] data, | 238 | UUID assetID, UUID transactionID, sbyte type, byte[] data, |
239 | bool storeLocal, bool tempFile) | 239 | bool storeLocal, bool tempFile) |
240 | { | 240 | { |
241 | // m_log.Debug("HandleUDPUploadRequest - assetID: " + assetID.ToString() + " transaction: " + transaction.ToString() + " type: " + type.ToString() + " storelocal: " + storeLocal + " tempFile: " + tempFile); | 241 | // m_log.DebugFormat( |
242 | // "[ASSET TRANSACTION MODULE]: HandleUDPUploadRequest - assetID: {0}, transaction {1}, type {2}, storeLocal {3}, tempFile {4}, data.Length {5}", | ||
243 | // assetID, transactionID, type, storeLocal, tempFile, data.Length); | ||
242 | 244 | ||
243 | if (((AssetType)type == AssetType.Texture || | 245 | if (((AssetType)type == AssetType.Texture || |
244 | (AssetType)type == AssetType.Sound || | 246 | (AssetType)type == AssetType.Sound || |
@@ -274,8 +276,8 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction | |||
274 | } | 276 | } |
275 | 277 | ||
276 | AgentAssetTransactions transactions = GetUserTransactions(remoteClient.AgentId); | 278 | AgentAssetTransactions transactions = GetUserTransactions(remoteClient.AgentId); |
277 | AssetXferUploader uploader = transactions.RequestXferUploader(transaction); | 279 | AssetXferUploader uploader = transactions.RequestXferUploader(transactionID); |
278 | uploader.StartUpload(remoteClient, assetID, transaction, type, data, storeLocal, tempFile); | 280 | uploader.StartUpload(remoteClient, assetID, transactionID, type, data, storeLocal, tempFile); |
279 | } | 281 | } |
280 | 282 | ||
281 | /// <summary> | 283 | /// <summary> |
diff --git a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs index 0aa4693..ffff37d 100644 --- a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs +++ b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs | |||
@@ -34,6 +34,7 @@ using OpenMetaverse; | |||
34 | using OpenSim.Framework; | 34 | using OpenSim.Framework; |
35 | using OpenSim.Region.Framework.Scenes; | 35 | using OpenSim.Region.Framework.Scenes; |
36 | using OpenSim.Services.Interfaces; | 36 | using OpenSim.Services.Interfaces; |
37 | using PermissionMask = OpenSim.Framework.PermissionMask; | ||
37 | 38 | ||
38 | namespace OpenSim.Region.CoreModules.Agent.AssetTransaction | 39 | namespace OpenSim.Region.CoreModules.Agent.AssetTransaction |
39 | { | 40 | { |
@@ -260,10 +261,10 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction | |||
260 | { | 261 | { |
261 | CompleteTaskItemUpdate(m_updateTaskItemData); | 262 | CompleteTaskItemUpdate(m_updateTaskItemData); |
262 | } | 263 | } |
263 | // else if (m_storeLocal) | 264 | else if (m_asset.Local) |
264 | // { | 265 | { |
265 | // m_Scene.AssetService.Store(m_asset); | 266 | m_Scene.AssetService.Store(m_asset); |
266 | // } | 267 | } |
267 | } | 268 | } |
268 | 269 | ||
269 | m_log.DebugFormat( | 270 | m_log.DebugFormat( |
@@ -339,7 +340,8 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction | |||
339 | // to avoid a race condition when the appearance module retrieves the item to set the asset id in | 340 | // to avoid a race condition when the appearance module retrieves the item to set the asset id in |
340 | // the AvatarAppearance structure. | 341 | // the AvatarAppearance structure. |
341 | item.AssetID = m_asset.FullID; | 342 | item.AssetID = m_asset.FullID; |
342 | m_Scene.InventoryService.UpdateItem(item); | 343 | if (item.AssetID != UUID.Zero) |
344 | m_Scene.InventoryService.UpdateItem(item); | ||
343 | 345 | ||
344 | if (m_uploadState == UploadState.Complete) | 346 | if (m_uploadState == UploadState.Complete) |
345 | { | 347 | { |
@@ -390,6 +392,11 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction | |||
390 | // m_asset.FullID, item.Name, ourClient.Name); | 392 | // m_asset.FullID, item.Name, ourClient.Name); |
391 | 393 | ||
392 | m_Scene.AssetService.Store(m_asset); | 394 | m_Scene.AssetService.Store(m_asset); |
395 | if (m_asset.FullID != UUID.Zero) | ||
396 | { | ||
397 | item.AssetID = m_asset.FullID; | ||
398 | m_Scene.InventoryService.UpdateItem(item); | ||
399 | } | ||
393 | 400 | ||
394 | m_transactions.RemoveXferUploader(m_transactionID); | 401 | m_transactions.RemoveXferUploader(m_transactionID); |
395 | } | 402 | } |
@@ -424,8 +431,8 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction | |||
424 | item.AssetType = type; | 431 | item.AssetType = type; |
425 | item.InvType = invType; | 432 | item.InvType = invType; |
426 | item.Folder = InventFolder; | 433 | item.Folder = InventFolder; |
427 | item.BasePermissions = 0x7fffffff; | 434 | item.BasePermissions = (uint)(PermissionMask.All | PermissionMask.Export); |
428 | item.CurrentPermissions = 0x7fffffff; | 435 | item.CurrentPermissions = item.BasePermissions; |
429 | item.GroupPermissions=0; | 436 | item.GroupPermissions=0; |
430 | item.EveryOnePermissions=0; | 437 | item.EveryOnePermissions=0; |
431 | item.NextPermissions = nextPerm; | 438 | item.NextPermissions = nextPerm; |
diff --git a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs index a0f1e8c..d510d82 100644 --- a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs | |||
@@ -363,12 +363,37 @@ namespace OpenSim.Region.CoreModules.Asset | |||
363 | /// Try to get an asset from the file cache. | 363 | /// Try to get an asset from the file cache. |
364 | /// </summary> | 364 | /// </summary> |
365 | /// <param name="id"></param> | 365 | /// <param name="id"></param> |
366 | /// <returns></returns> | 366 | /// <returns>An asset retrieved from the file cache. null if there was a problem retrieving an asset.</returns> |
367 | private AssetBase GetFromFileCache(string id) | 367 | private AssetBase GetFromFileCache(string id) |
368 | { | 368 | { |
369 | string filename = GetFileName(id); | ||
370 | |||
371 | #if WAIT_ON_INPROGRESS_REQUESTS | ||
372 | // Check if we're already downloading this asset. If so, try to wait for it to | ||
373 | // download. | ||
374 | if (m_WaitOnInprogressTimeout > 0) | ||
375 | { | ||
376 | m_RequestsForInprogress++; | ||
377 | |||
378 | ManualResetEvent waitEvent; | ||
379 | if (m_CurrentlyWriting.TryGetValue(filename, out waitEvent)) | ||
380 | { | ||
381 | waitEvent.WaitOne(m_WaitOnInprogressTimeout); | ||
382 | return Get(id); | ||
383 | } | ||
384 | } | ||
385 | #else | ||
386 | // Track how often we have the problem that an asset is requested while | ||
387 | // it is still being downloaded by a previous request. | ||
388 | if (m_CurrentlyWriting.Contains(filename)) | ||
389 | { | ||
390 | m_RequestsForInprogress++; | ||
391 | return null; | ||
392 | } | ||
393 | #endif | ||
394 | |||
369 | AssetBase asset = null; | 395 | AssetBase asset = null; |
370 | 396 | ||
371 | string filename = GetFileName(id); | ||
372 | if (File.Exists(filename)) | 397 | if (File.Exists(filename)) |
373 | { | 398 | { |
374 | FileStream stream = null; | 399 | FileStream stream = null; |
@@ -383,7 +408,7 @@ namespace OpenSim.Region.CoreModules.Asset | |||
383 | } | 408 | } |
384 | catch (System.Runtime.Serialization.SerializationException e) | 409 | catch (System.Runtime.Serialization.SerializationException e) |
385 | { | 410 | { |
386 | m_log.ErrorFormat( | 411 | m_log.WarnFormat( |
387 | "[FLOTSAM ASSET CACHE]: Failed to get file {0} for asset {1}. Exception {2} {3}", | 412 | "[FLOTSAM ASSET CACHE]: Failed to get file {0} for asset {1}. Exception {2} {3}", |
388 | filename, id, e.Message, e.StackTrace); | 413 | filename, id, e.Message, e.StackTrace); |
389 | 414 | ||
@@ -395,9 +420,10 @@ namespace OpenSim.Region.CoreModules.Asset | |||
395 | } | 420 | } |
396 | catch (Exception e) | 421 | catch (Exception e) |
397 | { | 422 | { |
398 | m_log.ErrorFormat( | 423 | m_log.WarnFormat( |
399 | "[FLOTSAM ASSET CACHE]: Failed to get file {0} for asset {1}. Exception {2} {3}", | 424 | "[FLOTSAM ASSET CACHE]: Failed to get file {0} for asset {1}. Exception {2} {3}", |
400 | filename, id, e.Message, e.StackTrace); | 425 | filename, id, e.Message, e.StackTrace); |
426 | |||
401 | } | 427 | } |
402 | finally | 428 | finally |
403 | { | 429 | { |
@@ -406,28 +432,6 @@ namespace OpenSim.Region.CoreModules.Asset | |||
406 | } | 432 | } |
407 | } | 433 | } |
408 | 434 | ||
409 | #if WAIT_ON_INPROGRESS_REQUESTS | ||
410 | // Check if we're already downloading this asset. If so, try to wait for it to | ||
411 | // download. | ||
412 | if (m_WaitOnInprogressTimeout > 0) | ||
413 | { | ||
414 | m_RequestsForInprogress++; | ||
415 | |||
416 | ManualResetEvent waitEvent; | ||
417 | if (m_CurrentlyWriting.TryGetValue(filename, out waitEvent)) | ||
418 | { | ||
419 | waitEvent.WaitOne(m_WaitOnInprogressTimeout); | ||
420 | return Get(id); | ||
421 | } | ||
422 | } | ||
423 | #else | ||
424 | // Track how often we have the problem that an asset is requested while | ||
425 | // it is still being downloaded by a previous request. | ||
426 | if (m_CurrentlyWriting.Contains(filename)) | ||
427 | { | ||
428 | m_RequestsForInprogress++; | ||
429 | } | ||
430 | #endif | ||
431 | return asset; | 435 | return asset; |
432 | } | 436 | } |
433 | 437 | ||
@@ -552,7 +556,7 @@ namespace OpenSim.Region.CoreModules.Asset | |||
552 | } | 556 | } |
553 | catch (Exception e) | 557 | catch (Exception e) |
554 | { | 558 | { |
555 | m_log.ErrorFormat( | 559 | m_log.WarnFormat( |
556 | "[FLOTSAM ASSET CACHE]: Failed to expire cached file {0}. Exception {1} {2}", | 560 | "[FLOTSAM ASSET CACHE]: Failed to expire cached file {0}. Exception {1} {2}", |
557 | id, e.Message, e.StackTrace); | 561 | id, e.Message, e.StackTrace); |
558 | } | 562 | } |
@@ -603,29 +607,39 @@ namespace OpenSim.Region.CoreModules.Asset | |||
603 | /// <param name="purgeLine"></param> | 607 | /// <param name="purgeLine"></param> |
604 | private void CleanExpiredFiles(string dir, DateTime purgeLine) | 608 | private void CleanExpiredFiles(string dir, DateTime purgeLine) |
605 | { | 609 | { |
606 | foreach (string file in Directory.GetFiles(dir)) | 610 | try |
607 | { | 611 | { |
608 | if (File.GetLastAccessTime(file) < purgeLine) | 612 | foreach (string file in Directory.GetFiles(dir)) |
609 | { | 613 | { |
610 | File.Delete(file); | 614 | if (File.GetLastAccessTime(file) < purgeLine) |
615 | { | ||
616 | File.Delete(file); | ||
617 | } | ||
611 | } | 618 | } |
612 | } | ||
613 | 619 | ||
614 | // Recurse into lower tiers | 620 | // Recurse into lower tiers |
615 | foreach (string subdir in Directory.GetDirectories(dir)) | 621 | foreach (string subdir in Directory.GetDirectories(dir)) |
616 | { | 622 | { |
617 | CleanExpiredFiles(subdir, purgeLine); | 623 | CleanExpiredFiles(subdir, purgeLine); |
618 | } | 624 | } |
619 | 625 | ||
620 | // Check if a tier directory is empty, if so, delete it | 626 | // Check if a tier directory is empty, if so, delete it |
621 | int dirSize = Directory.GetFiles(dir).Length + Directory.GetDirectories(dir).Length; | 627 | int dirSize = Directory.GetFiles(dir).Length + Directory.GetDirectories(dir).Length; |
622 | if (dirSize == 0) | 628 | if (dirSize == 0) |
623 | { | 629 | { |
624 | Directory.Delete(dir); | 630 | Directory.Delete(dir); |
631 | } | ||
632 | else if (dirSize >= m_CacheWarnAt) | ||
633 | { | ||
634 | m_log.WarnFormat( | ||
635 | "[FLOTSAM ASSET CACHE]: Cache folder exceeded CacheWarnAt limit {0} {1}. Suggest increasing tiers, tier length, or reducing cache expiration", | ||
636 | dir, dirSize); | ||
637 | } | ||
625 | } | 638 | } |
626 | else if (dirSize >= m_CacheWarnAt) | 639 | catch (Exception e) |
627 | { | 640 | { |
628 | m_log.WarnFormat("[FLOTSAM ASSET CACHE]: Cache folder exceeded CacheWarnAt limit {0} {1}. Suggest increasing tiers, tier length, or reducing cache expiration", dir, dirSize); | 641 | m_log.Warn( |
642 | string.Format("[FLOTSAM ASSET CACHE]: Could not complete clean of expired files in {0}, exception ", dir), e); | ||
629 | } | 643 | } |
630 | } | 644 | } |
631 | 645 | ||
@@ -684,7 +698,7 @@ namespace OpenSim.Region.CoreModules.Asset | |||
684 | } | 698 | } |
685 | catch (IOException e) | 699 | catch (IOException e) |
686 | { | 700 | { |
687 | m_log.ErrorFormat( | 701 | m_log.WarnFormat( |
688 | "[FLOTSAM ASSET CACHE]: Failed to write asset {0} to temporary location {1} (final {2}) on cache in {3}. Exception {4} {5}.", | 702 | "[FLOTSAM ASSET CACHE]: Failed to write asset {0} to temporary location {1} (final {2}) on cache in {3}. Exception {4} {5}.", |
689 | asset.ID, tempname, filename, directory, e.Message, e.StackTrace); | 703 | asset.ID, tempname, filename, directory, e.Message, e.StackTrace); |
690 | 704 | ||
@@ -763,17 +777,31 @@ namespace OpenSim.Region.CoreModules.Asset | |||
763 | /// <summary> | 777 | /// <summary> |
764 | /// This notes the last time the Region had a deep asset scan performed on it. | 778 | /// This notes the last time the Region had a deep asset scan performed on it. |
765 | /// </summary> | 779 | /// </summary> |
766 | /// <param name="RegionID"></param> | 780 | /// <param name="regionID"></param> |
767 | private void StampRegionStatusFile(UUID RegionID) | 781 | private void StampRegionStatusFile(UUID regionID) |
768 | { | 782 | { |
769 | string RegionCacheStatusFile = Path.Combine(m_CacheDirectory, "RegionStatus_" + RegionID.ToString() + ".fac"); | 783 | string RegionCacheStatusFile = Path.Combine(m_CacheDirectory, "RegionStatus_" + regionID.ToString() + ".fac"); |
770 | if (File.Exists(RegionCacheStatusFile)) | 784 | |
785 | try | ||
771 | { | 786 | { |
772 | File.SetLastWriteTime(RegionCacheStatusFile, DateTime.Now); | 787 | if (File.Exists(RegionCacheStatusFile)) |
788 | { | ||
789 | File.SetLastWriteTime(RegionCacheStatusFile, DateTime.Now); | ||
790 | } | ||
791 | else | ||
792 | { | ||
793 | File.WriteAllText( | ||
794 | RegionCacheStatusFile, | ||
795 | "Please do not delete this file unless you are manually clearing your Flotsam Asset Cache."); | ||
796 | } | ||
773 | } | 797 | } |
774 | else | 798 | catch (Exception e) |
775 | { | 799 | { |
776 | File.WriteAllText(RegionCacheStatusFile, "Please do not delete this file unless you are manually clearing your Flotsam Asset Cache."); | 800 | m_log.Warn( |
801 | string.Format( | ||
802 | "[FLOTSAM ASSET CACHE]: Could not stamp region status file for region {0}. Exception ", | ||
803 | regionID), | ||
804 | e); | ||
777 | } | 805 | } |
778 | } | 806 | } |
779 | 807 | ||
@@ -790,32 +818,43 @@ namespace OpenSim.Region.CoreModules.Asset | |||
790 | { | 818 | { |
791 | UuidGatherer gatherer = new UuidGatherer(m_AssetService); | 819 | UuidGatherer gatherer = new UuidGatherer(m_AssetService); |
792 | 820 | ||
821 | HashSet<UUID> uniqueUuids = new HashSet<UUID>(); | ||
793 | Dictionary<UUID, AssetType> assets = new Dictionary<UUID, AssetType>(); | 822 | Dictionary<UUID, AssetType> assets = new Dictionary<UUID, AssetType>(); |
823 | |||
794 | foreach (Scene s in m_Scenes) | 824 | foreach (Scene s in m_Scenes) |
795 | { | 825 | { |
796 | StampRegionStatusFile(s.RegionInfo.RegionID); | 826 | StampRegionStatusFile(s.RegionInfo.RegionID); |
797 | 827 | ||
798 | s.ForEachSOG(delegate(SceneObjectGroup e) | 828 | s.ForEachSOG(delegate(SceneObjectGroup e) |
799 | { | 829 | { |
800 | gatherer.GatherAssetUuids(e, assets); | 830 | gatherer.GatherAssetUuids(e, assets); |
801 | }); | ||
802 | } | ||
803 | 831 | ||
804 | foreach (UUID assetID in assets.Keys) | 832 | foreach (UUID assetID in assets.Keys) |
805 | { | 833 | { |
806 | string filename = GetFileName(assetID.ToString()); | 834 | uniqueUuids.Add(assetID); |
807 | 835 | ||
808 | if (File.Exists(filename)) | 836 | string filename = GetFileName(assetID.ToString()); |
809 | { | 837 | |
810 | File.SetLastAccessTime(filename, DateTime.Now); | 838 | if (File.Exists(filename)) |
811 | } | 839 | { |
812 | else if (storeUncached) | 840 | File.SetLastAccessTime(filename, DateTime.Now); |
813 | { | 841 | } |
814 | m_AssetService.Get(assetID.ToString()); | 842 | else if (storeUncached) |
815 | } | 843 | { |
844 | AssetBase cachedAsset = m_AssetService.Get(assetID.ToString()); | ||
845 | if (cachedAsset == null && assets[assetID] != AssetType.Unknown) | ||
846 | m_log.DebugFormat( | ||
847 | "[FLOTSAM ASSET CACHE]: Could not find asset {0}, type {1} referenced by object {2} at {3} in scene {4} when pre-caching all scene assets", | ||
848 | assetID, assets[assetID], e.Name, e.AbsolutePosition, s.Name); | ||
849 | } | ||
850 | } | ||
851 | |||
852 | assets.Clear(); | ||
853 | }); | ||
816 | } | 854 | } |
817 | 855 | ||
818 | return assets.Keys.Count; | 856 | |
857 | return uniqueUuids.Count; | ||
819 | } | 858 | } |
820 | 859 | ||
821 | /// <summary> | 860 | /// <summary> |
@@ -831,7 +870,7 @@ namespace OpenSim.Region.CoreModules.Asset | |||
831 | } | 870 | } |
832 | catch (Exception e) | 871 | catch (Exception e) |
833 | { | 872 | { |
834 | m_log.ErrorFormat( | 873 | m_log.WarnFormat( |
835 | "[FLOTSAM ASSET CACHE]: Couldn't clear asset cache directory {0} from {1}. Exception {2} {3}", | 874 | "[FLOTSAM ASSET CACHE]: Couldn't clear asset cache directory {0} from {1}. Exception {2} {3}", |
836 | dir, m_CacheDirectory, e.Message, e.StackTrace); | 875 | dir, m_CacheDirectory, e.Message, e.StackTrace); |
837 | } | 876 | } |
@@ -845,7 +884,7 @@ namespace OpenSim.Region.CoreModules.Asset | |||
845 | } | 884 | } |
846 | catch (Exception e) | 885 | catch (Exception e) |
847 | { | 886 | { |
848 | m_log.ErrorFormat( | 887 | m_log.WarnFormat( |
849 | "[FLOTSAM ASSET CACHE]: Couldn't clear asset cache file {0} from {1}. Exception {1} {2}", | 888 | "[FLOTSAM ASSET CACHE]: Couldn't clear asset cache file {0} from {1}. Exception {1} {2}", |
850 | file, m_CacheDirectory, e.Message, e.StackTrace); | 889 | file, m_CacheDirectory, e.Message, e.StackTrace); |
851 | } | 890 | } |
diff --git a/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs b/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs index 1c2bfd0..fd02b08 100644 --- a/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs +++ b/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs | |||
@@ -47,14 +47,16 @@ namespace OpenSim.Region.CoreModules.Asset.Tests | |||
47 | /// At the moment we're only test the in-memory part of the FlotsamAssetCache. This is a considerable weakness. | 47 | /// At the moment we're only test the in-memory part of the FlotsamAssetCache. This is a considerable weakness. |
48 | /// </summary> | 48 | /// </summary> |
49 | [TestFixture] | 49 | [TestFixture] |
50 | public class FlotsamAssetCacheTests | 50 | public class FlotsamAssetCacheTests : OpenSimTestCase |
51 | { | 51 | { |
52 | protected TestScene m_scene; | 52 | protected TestScene m_scene; |
53 | protected FlotsamAssetCache m_cache; | 53 | protected FlotsamAssetCache m_cache; |
54 | 54 | ||
55 | [SetUp] | 55 | [SetUp] |
56 | public void SetUp() | 56 | public override void SetUp() |
57 | { | 57 | { |
58 | base.SetUp(); | ||
59 | |||
58 | IConfigSource config = new IniConfigSource(); | 60 | IConfigSource config = new IniConfigSource(); |
59 | 61 | ||
60 | config.AddConfig("Modules"); | 62 | config.AddConfig("Modules"); |
diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index acd156e..cb724aa 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs | |||
@@ -49,6 +49,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
49 | { | 49 | { |
50 | #region INonSharedRegionModule | 50 | #region INonSharedRegionModule |
51 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 51 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
52 | |||
53 | public int DebugLevel { get; set; } | ||
52 | 54 | ||
53 | private Scene m_scene; | 55 | private Scene m_scene; |
54 | private IInventoryAccessModule m_invAccessModule; | 56 | private IInventoryAccessModule m_invAccessModule; |
@@ -76,10 +78,66 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
76 | m_scene.RegisterModuleInterface<IAttachmentsModule>(this); | 78 | m_scene.RegisterModuleInterface<IAttachmentsModule>(this); |
77 | 79 | ||
78 | if (Enabled) | 80 | if (Enabled) |
81 | { | ||
79 | m_scene.EventManager.OnNewClient += SubscribeToClientEvents; | 82 | m_scene.EventManager.OnNewClient += SubscribeToClientEvents; |
83 | m_scene.EventManager.OnStartScript += (localID, itemID) => HandleScriptStateChange(localID, true); | ||
84 | m_scene.EventManager.OnStopScript += (localID, itemID) => HandleScriptStateChange(localID, false); | ||
85 | |||
86 | MainConsole.Instance.Commands.AddCommand( | ||
87 | "Debug", | ||
88 | false, | ||
89 | "debug attachments", | ||
90 | "debug attachments [0|1]", | ||
91 | "Turn on attachments debugging\n" | ||
92 | + " <= 0 - turns off debugging\n" | ||
93 | + " >= 1 - turns on attachment message logging\n", | ||
94 | HandleDebugAttachments); | ||
95 | } | ||
80 | 96 | ||
81 | // TODO: Should probably be subscribing to CloseClient too, but this doesn't yet give us IClientAPI | 97 | // TODO: Should probably be subscribing to CloseClient too, but this doesn't yet give us IClientAPI |
82 | } | 98 | } |
99 | |||
100 | private void HandleDebugAttachments(string module, string[] args) | ||
101 | { | ||
102 | int debugLevel; | ||
103 | |||
104 | if (!(args.Length == 3 && int.TryParse(args[2], out debugLevel))) | ||
105 | { | ||
106 | MainConsole.Instance.OutputFormat("Usage: debug attachments [0|1]"); | ||
107 | } | ||
108 | else | ||
109 | { | ||
110 | DebugLevel = debugLevel; | ||
111 | MainConsole.Instance.OutputFormat( | ||
112 | "Set event queue debug level to {0} in {1}", DebugLevel, m_scene.Name); | ||
113 | } | ||
114 | } | ||
115 | |||
116 | /// <summary> | ||
117 | /// Listen for client triggered running state changes so that we can persist the script's object if necessary. | ||
118 | /// </summary> | ||
119 | /// <param name='localID'></param> | ||
120 | /// <param name='itemID'></param> | ||
121 | private void HandleScriptStateChange(uint localID, bool started) | ||
122 | { | ||
123 | SceneObjectGroup sog = m_scene.GetGroupByPrim(localID); | ||
124 | if (sog != null && sog.IsAttachment) | ||
125 | { | ||
126 | if (!started) | ||
127 | { | ||
128 | // FIXME: This is a convoluted way for working out whether the script state has changed to stop | ||
129 | // because it has been manually stopped or because the stop was called in UpdateDetachedObject() below | ||
130 | // This needs to be handled in a less tangled way. | ||
131 | ScenePresence sp = m_scene.GetScenePresence(sog.AttachedAvatar); | ||
132 | if (sp.ControllingClient.IsActive) | ||
133 | sog.HasGroupChanged = true; | ||
134 | } | ||
135 | else | ||
136 | { | ||
137 | sog.HasGroupChanged = true; | ||
138 | } | ||
139 | } | ||
140 | } | ||
83 | 141 | ||
84 | public void RemoveRegion(Scene scene) | 142 | public void RemoveRegion(Scene scene) |
85 | { | 143 | { |
@@ -153,10 +211,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
153 | } | 211 | } |
154 | } | 212 | } |
155 | 213 | ||
156 | /// <summary> | ||
157 | /// RezAttachments. This should only be called upon login on the first region. | ||
158 | /// Attachment rezzings on crossings and TPs are done in a different way. | ||
159 | /// </summary> | ||
160 | public void RezAttachments(IScenePresence sp) | 214 | public void RezAttachments(IScenePresence sp) |
161 | { | 215 | { |
162 | if (!Enabled) | 216 | if (!Enabled) |
@@ -165,10 +219,22 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
165 | if (null == sp.Appearance) | 219 | if (null == sp.Appearance) |
166 | { | 220 | { |
167 | m_log.WarnFormat("[ATTACHMENTS MODULE]: Appearance has not been initialized for agent {0}", sp.UUID); | 221 | m_log.WarnFormat("[ATTACHMENTS MODULE]: Appearance has not been initialized for agent {0}", sp.UUID); |
222 | |||
168 | return; | 223 | return; |
169 | } | 224 | } |
170 | 225 | ||
171 | // m_log.DebugFormat("[ATTACHMENTS MODULE]: Rezzing any attachments for {0}", sp.Name); | 226 | if (sp.GetAttachments().Count > 0) |
227 | { | ||
228 | if (DebugLevel > 0) | ||
229 | m_log.DebugFormat( | ||
230 | "[ATTACHMENTS MODULE]: Not doing simulator-side attachment rez for {0} in {1} as their viewer has already rezzed attachments", | ||
231 | m_scene.Name, sp.Name); | ||
232 | |||
233 | return; | ||
234 | } | ||
235 | |||
236 | if (DebugLevel > 0) | ||
237 | m_log.DebugFormat("[ATTACHMENTS MODULE]: Rezzing any attachments for {0} from simulator-side", sp.Name); | ||
172 | 238 | ||
173 | XmlDocument doc = new XmlDocument(); | 239 | XmlDocument doc = new XmlDocument(); |
174 | string stateData = String.Empty; | 240 | string stateData = String.Empty; |
@@ -235,10 +301,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
235 | 301 | ||
236 | // If we're an NPC then skip all the item checks and manipulations since we don't have an | 302 | // If we're an NPC then skip all the item checks and manipulations since we don't have an |
237 | // inventory right now. | 303 | // inventory right now. |
238 | if (sp.PresenceType == PresenceType.Npc) | 304 | RezSingleAttachmentFromInventoryInternal( |
239 | RezSingleAttachmentFromInventoryInternal(sp, UUID.Zero, attach.AssetID, p, null); | 305 | sp, sp.PresenceType == PresenceType.Npc ? UUID.Zero : attach.ItemID, attach.AssetID, p, true, null); |
240 | else | ||
241 | RezSingleAttachmentFromInventory(sp, attach.ItemID, p, d); | ||
242 | } | 306 | } |
243 | catch (Exception e) | 307 | catch (Exception e) |
244 | { | 308 | { |
@@ -254,14 +318,30 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
254 | if (!Enabled) | 318 | if (!Enabled) |
255 | return; | 319 | return; |
256 | 320 | ||
257 | // m_log.DebugFormat("[ATTACHMENTS MODULE]: Saving changed attachments for {0}", sp.Name); | 321 | if (DebugLevel > 0) |
322 | m_log.DebugFormat("[ATTACHMENTS MODULE]: Saving changed attachments for {0}", sp.Name); | ||
323 | |||
324 | List<SceneObjectGroup> attachments = sp.GetAttachments(); | ||
325 | |||
326 | if (attachments.Count <= 0) | ||
327 | return; | ||
328 | |||
329 | Dictionary<SceneObjectGroup, string> scriptStates = new Dictionary<SceneObjectGroup, string>(); | ||
330 | |||
331 | foreach (SceneObjectGroup so in attachments) | ||
332 | { | ||
333 | // Scripts MUST be snapshotted before the object is | ||
334 | // removed from the scene because doing otherwise will | ||
335 | // clobber the run flag | ||
336 | // This must be done outside the sp.AttachmentSyncLock so that there is no risk of a deadlock from | ||
337 | // scripts performing attachment operations at the same time. Getting object states stops the scripts. | ||
338 | scriptStates[so] = PrepareScriptInstanceForSave(so, false); | ||
339 | } | ||
258 | 340 | ||
259 | lock (sp.AttachmentsSyncLock) | 341 | lock (sp.AttachmentsSyncLock) |
260 | { | 342 | { |
261 | foreach (SceneObjectGroup so in sp.GetAttachments()) | 343 | foreach (SceneObjectGroup so in attachments) |
262 | { | 344 | UpdateDetachedObject(sp, so, scriptStates[so]); |
263 | UpdateDetachedObject(sp, so); | ||
264 | } | ||
265 | 345 | ||
266 | sp.ClearAttachments(); | 346 | sp.ClearAttachments(); |
267 | } | 347 | } |
@@ -272,9 +352,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
272 | if (!Enabled) | 352 | if (!Enabled) |
273 | return; | 353 | return; |
274 | 354 | ||
275 | // m_log.DebugFormat( | 355 | if (DebugLevel > 0) |
276 | // "[ATTACHMENTS MODULE]: Deleting attachments from scene {0} for {1}, silent = {2}", | 356 | m_log.DebugFormat( |
277 | // m_scene.RegionInfo.RegionName, sp.Name, silent); | 357 | "[ATTACHMENTS MODULE]: Deleting attachments from scene {0} for {1}, silent = {2}", |
358 | m_scene.RegionInfo.RegionName, sp.Name, silent); | ||
278 | 359 | ||
279 | foreach (SceneObjectGroup sop in sp.GetAttachments()) | 360 | foreach (SceneObjectGroup sop in sp.GetAttachments()) |
280 | { | 361 | { |
@@ -284,131 +365,141 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
284 | sp.ClearAttachments(); | 365 | sp.ClearAttachments(); |
285 | } | 366 | } |
286 | 367 | ||
287 | public bool AttachObject(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool useAttachData, bool temp) | 368 | public bool AttachObject(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool useAttachData, bool addToInventory, bool append) |
288 | { | 369 | { |
289 | if (!Enabled) | 370 | if (!Enabled) |
290 | return false; | 371 | return false; |
291 | 372 | ||
292 | if (AttachObjectInternal(sp, group, attachmentPt, silent, useAttachData, temp)) | 373 | return AttachObjectInternal(sp, group, attachmentPt, silent, useAttachData, addToInventory, false, append); |
293 | { | ||
294 | m_scene.EventManager.TriggerOnAttach(group.LocalId, group.FromItemID, sp.UUID); | ||
295 | return true; | ||
296 | } | ||
297 | |||
298 | return false; | ||
299 | } | 374 | } |
300 | 375 | ||
301 | private bool AttachObjectInternal(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool useAttachData, bool temp) | 376 | /// <summary> |
377 | /// Internal method which actually does all the work for attaching an object. | ||
378 | /// </summary> | ||
379 | /// <returns>The object attached.</returns> | ||
380 | /// <param name='sp'></param> | ||
381 | /// <param name='group'>The object to attach.</param> | ||
382 | /// <param name='attachmentPt'></param> | ||
383 | /// <param name='silent'></param> | ||
384 | /// <param name='addToInventory'>If true then add object to user inventory.</param> | ||
385 | /// <param name='resumeScripts'>If true then scripts are resumed on the attached object.</param> | ||
386 | private bool AttachObjectInternal(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool useAttachData, bool addToInventory, bool resumeScripts, bool append) | ||
302 | { | 387 | { |
303 | lock (sp.AttachmentsSyncLock) | ||
304 | { | ||
305 | // m_log.DebugFormat( | 388 | // m_log.DebugFormat( |
306 | // "[ATTACHMENTS MODULE]: Attaching object {0} {1} to {2} point {3} from ground (silent = {4})", | 389 | // "[ATTACHMENTS MODULE]: Attaching object {0} {1} to {2} point {3} from ground (silent = {4})", |
307 | // group.Name, group.LocalId, sp.Name, attachmentPt, silent); | 390 | // group.Name, group.LocalId, sp.Name, attachmentPt, silent); |
308 | 391 | ||
309 | if (group.GetSittingAvatarsCount() != 0) | 392 | if (sp.GetAttachments().Contains(group)) |
310 | { | 393 | { |
311 | // m_log.WarnFormat( | 394 | // m_log.WarnFormat( |
312 | // "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since {4} avatars are still sitting on it", | 395 | // "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since it's already attached", |
313 | // group.Name, group.LocalId, sp.Name, attachmentPt, group.GetSittingAvatarsCount()); | 396 | // group.Name, group.LocalId, sp.Name, AttachmentPt); |
314 | 397 | ||
315 | return false; | 398 | return false; |
316 | } | 399 | } |
317 | 400 | ||
318 | if (sp.GetAttachments(attachmentPt).Contains(group)) | 401 | if (group.GetSittingAvatarsCount() != 0) |
319 | { | 402 | { |
320 | // m_log.WarnFormat( | 403 | if (DebugLevel > 0) |
321 | // "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since it's already attached", | 404 | m_log.WarnFormat( |
322 | // group.Name, group.LocalId, sp.Name, AttachmentPt); | 405 | "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since {4} avatars are still sitting on it", |
323 | 406 | group.Name, group.LocalId, sp.Name, attachmentPt, group.GetSittingAvatarsCount()); | |
324 | return false; | 407 | |
325 | } | 408 | return false; |
326 | 409 | } | |
327 | Vector3 attachPos = group.AbsolutePosition; | 410 | |
328 | 411 | Vector3 attachPos = group.AbsolutePosition; | |
329 | // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should | 412 | |
330 | // be removed when that functionality is implemented in opensim | 413 | // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should |
331 | attachmentPt &= 0x7f; | 414 | // be removed when that functionality is implemented in opensim |
332 | 415 | attachmentPt &= 0x7f; | |
333 | // If the attachment point isn't the same as the one previously used | 416 | |
334 | // set it's offset position = 0 so that it appears on the attachment point | 417 | // If the attachment point isn't the same as the one previously used |
335 | // and not in a weird location somewhere unknown. | 418 | // set it's offset position = 0 so that it appears on the attachment point |
336 | if (attachmentPt != 0 && attachmentPt != group.AttachmentPoint) | 419 | // and not in a weird location somewhere unknown. |
337 | { | 420 | if (attachmentPt != (uint)AttachmentPoint.Default && attachmentPt != group.AttachmentPoint) |
338 | attachPos = Vector3.Zero; | 421 | { |
339 | } | 422 | attachPos = Vector3.Zero; |
340 | 423 | } | |
341 | // AttachmentPt 0 means the client chose to 'wear' the attachment. | 424 | |
342 | if (attachmentPt == 0) | 425 | // AttachmentPt 0 (default) means the client chose to 'wear' the attachment. |
343 | { | 426 | if (attachmentPt == (uint)AttachmentPoint.Default) |
344 | // Check object for stored attachment point | 427 | { |
345 | attachmentPt = group.AttachmentPoint; | 428 | // Check object for stored attachment point |
346 | } | 429 | attachmentPt = group.AttachmentPoint; |
347 | 430 | } | |
348 | // if we still didn't find a suitable attachment point....... | 431 | |
349 | if (attachmentPt == 0) | 432 | // if we still didn't find a suitable attachment point....... |
350 | { | 433 | if (attachmentPt == 0) |
351 | // Stick it on left hand with Zero Offset from the attachment point. | 434 | { |
352 | attachmentPt = (uint)AttachmentPoint.LeftHand; | 435 | // Stick it on left hand with Zero Offset from the attachment point. |
353 | attachPos = Vector3.Zero; | 436 | attachmentPt = (uint)AttachmentPoint.LeftHand; |
354 | } | 437 | attachPos = Vector3.Zero; |
355 | 438 | } | |
356 | if (useAttachData) | 439 | |
440 | List<SceneObjectGroup> attachments = sp.GetAttachments(attachmentPt); | ||
441 | |||
442 | if (attachments.Contains(group)) | ||
443 | { | ||
444 | if (DebugLevel > 0) | ||
445 | m_log.WarnFormat( | ||
446 | "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since it's already attached", | ||
447 | group.Name, group.LocalId, sp.Name, attachmentPt); | ||
448 | |||
449 | return false; | ||
450 | } | ||
451 | |||
452 | // If we already have 5, remove the oldest until only 4 are left. Skip over temp ones | ||
453 | while (attachments.Count >= 5) | ||
454 | { | ||
455 | if (attachments[0].FromItemID != UUID.Zero) | ||
456 | DetachSingleAttachmentToInv(sp, attachments[0]); | ||
457 | attachments.RemoveAt(0); | ||
458 | } | ||
459 | |||
460 | // If we're not appending, remove the rest as well | ||
461 | if (attachments.Count != 0 && !append) | ||
462 | { | ||
463 | foreach (SceneObjectGroup g in attachments) | ||
357 | { | 464 | { |
358 | group.RootPart.RotationOffset = group.RootPart.AttachRotation; | 465 | if (g.FromItemID != UUID.Zero) |
359 | attachPos = group.RootPart.AttachOffset; | 466 | DetachSingleAttachmentToInv(sp, g); |
360 | if (attachmentPt == 0) | ||
361 | { | ||
362 | attachmentPt = group.RootPart.AttachPoint; | ||
363 | if (attachmentPt == 0) | ||
364 | { | ||
365 | attachmentPt = (uint)AttachmentPoint.LeftHand; | ||
366 | attachPos = Vector3.Zero; | ||
367 | } | ||
368 | } | ||
369 | else if (group.RootPart.AttachPoint != attachmentPt) | ||
370 | { | ||
371 | attachPos = Vector3.Zero; | ||
372 | } | ||
373 | } | 467 | } |
468 | } | ||
469 | |||
470 | lock (sp.AttachmentsSyncLock) | ||
471 | { | ||
374 | group.AttachmentPoint = attachmentPt; | 472 | group.AttachmentPoint = attachmentPt; |
375 | group.AbsolutePosition = attachPos; | 473 | group.AbsolutePosition = attachPos; |
376 | 474 | ||
377 | if (sp.PresenceType != PresenceType.Npc) | 475 | if (addToInventory && sp.PresenceType != PresenceType.Npc) |
378 | UpdateUserInventoryWithAttachment(sp, group, attachmentPt, temp); | 476 | UpdateUserInventoryWithAttachment(sp, group, attachmentPt, append); |
379 | 477 | ||
380 | AttachToAgent(sp, group, attachmentPt, attachPos, silent); | 478 | AttachToAgent(sp, group, attachmentPt, attachPos, silent); |
479 | |||
480 | if (resumeScripts) | ||
481 | { | ||
482 | // Fire after attach, so we don't get messy perms dialogs | ||
483 | // 4 == AttachedRez | ||
484 | group.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 4); | ||
485 | group.ResumeScripts(); | ||
486 | } | ||
487 | |||
488 | // Do this last so that event listeners have access to all the effects of the attachment | ||
489 | m_scene.EventManager.TriggerOnAttach(group.LocalId, group.FromItemID, sp.UUID); | ||
381 | } | 490 | } |
382 | 491 | ||
383 | return true; | 492 | return true; |
384 | } | 493 | } |
385 | 494 | ||
386 | private void UpdateUserInventoryWithAttachment(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool temp) | 495 | private void UpdateUserInventoryWithAttachment(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool append) |
387 | { | 496 | { |
388 | // Remove any previous attachments | ||
389 | List<SceneObjectGroup> attachments = sp.GetAttachments(attachmentPt); | ||
390 | |||
391 | // At the moment we can only deal with a single attachment | ||
392 | if (attachments.Count != 0) | ||
393 | { | ||
394 | if (attachments[0].FromItemID != UUID.Zero) | ||
395 | DetachSingleAttachmentToInvInternal(sp, attachments[0]); | ||
396 | // Error logging commented because UUID.Zero now means temp attachment | ||
397 | // else | ||
398 | // m_log.WarnFormat( | ||
399 | // "[ATTACHMENTS MODULE]: When detaching existing attachment {0} {1} at point {2} to make way for {3} {4} for {5}, couldn't find the associated item ID to adjust inventory attachment record!", | ||
400 | // attachments[0].Name, attachments[0].LocalId, attachmentPt, group.Name, group.LocalId, sp.Name); | ||
401 | } | ||
402 | |||
403 | // Add the new attachment to inventory if we don't already have it. | 497 | // Add the new attachment to inventory if we don't already have it. |
404 | if (!temp) | 498 | UUID newAttachmentItemID = group.FromItemID; |
405 | { | 499 | if (newAttachmentItemID == UUID.Zero) |
406 | UUID newAttachmentItemID = group.FromItemID; | 500 | newAttachmentItemID = AddSceneObjectAsNewAttachmentInInv(sp, group).ID; |
407 | if (newAttachmentItemID == UUID.Zero) | ||
408 | newAttachmentItemID = AddSceneObjectAsNewAttachmentInInv(sp, group).ID; | ||
409 | 501 | ||
410 | ShowAttachInUserInventory(sp, attachmentPt, newAttachmentItemID, group); | 502 | ShowAttachInUserInventory(sp, attachmentPt, newAttachmentItemID, group, append); |
411 | } | ||
412 | } | 503 | } |
413 | 504 | ||
414 | public ISceneEntity RezSingleAttachmentFromInventory(IScenePresence sp, UUID itemID, uint AttachmentPt) | 505 | public ISceneEntity RezSingleAttachmentFromInventory(IScenePresence sp, UUID itemID, uint AttachmentPt) |
@@ -421,41 +512,40 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
421 | if (!Enabled) | 512 | if (!Enabled) |
422 | return null; | 513 | return null; |
423 | 514 | ||
424 | // m_log.DebugFormat( | 515 | if (DebugLevel > 0) |
425 | // "[ATTACHMENTS MODULE]: RezSingleAttachmentFromInventory to point {0} from item {1} for {2}", | 516 | m_log.DebugFormat( |
426 | // (AttachmentPoint)AttachmentPt, itemID, sp.Name); | 517 | "[ATTACHMENTS MODULE]: RezSingleAttachmentFromInventory to point {0} from item {1} for {2} in {3}", |
427 | 518 | (AttachmentPoint)AttachmentPt, itemID, sp.Name, m_scene.Name); | |
428 | // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should | ||
429 | // be removed when that functionality is implemented in opensim | ||
430 | AttachmentPt &= 0x7f; | ||
431 | 519 | ||
432 | // Viewer 2/3 sometimes asks to re-wear items that are already worn (and show up in it's inventory as such). | 520 | // We check the attachments in the avatar appearance here rather than the objects attached to the |
433 | // This often happens during login - not sure the exact reason. | 521 | // ScenePresence itself so that we can ignore calls by viewer 2/3 to attach objects on startup. We are |
434 | // For now, we will ignore the request. Unfortunately, this means that we need to dig through all the | 522 | // already doing this in ScenePresence.MakeRootAgent(). Simulator-side attaching needs to be done |
435 | // ScenePresence attachments. We can't use the data in AvatarAppearance because that's present at login | 523 | // because pre-outfit folder viewers (most version 1 viewers) require it. |
436 | // before anything has actually been attached. | ||
437 | bool alreadyOn = false; | 524 | bool alreadyOn = false; |
438 | List<SceneObjectGroup> existingAttachments = sp.GetAttachments(); | 525 | List<AvatarAttachment> existingAttachments = sp.Appearance.GetAttachments(); |
439 | foreach (SceneObjectGroup so in existingAttachments) | 526 | foreach (AvatarAttachment existingAttachment in existingAttachments) |
440 | { | 527 | { |
441 | if (so.FromItemID == itemID) | 528 | if (existingAttachment.ItemID == itemID) |
442 | { | 529 | { |
443 | alreadyOn = true; | 530 | alreadyOn = true; |
444 | break; | 531 | break; |
445 | } | 532 | } |
446 | } | 533 | } |
447 | 534 | ||
448 | // if (sp.Appearance.GetAttachmentForItem(itemID) != null) | ||
449 | if (alreadyOn) | 535 | if (alreadyOn) |
450 | { | 536 | { |
451 | // m_log.WarnFormat( | 537 | if (DebugLevel > 0) |
452 | // "[ATTACHMENTS MODULE]: Ignoring request by {0} to wear item {1} at {2} since it is already worn", | 538 | m_log.DebugFormat( |
453 | // sp.Name, itemID, AttachmentPt); | 539 | "[ATTACHMENTS MODULE]: Ignoring request by {0} to wear item {1} at {2} since it is already worn", |
540 | sp.Name, itemID, AttachmentPt); | ||
454 | 541 | ||
455 | return null; | 542 | return null; |
456 | } | 543 | } |
457 | 544 | ||
458 | return RezSingleAttachmentFromInventoryInternal(sp, itemID, UUID.Zero, AttachmentPt, doc); | 545 | bool append = (AttachmentPt & 0x80) != 0; |
546 | AttachmentPt &= 0x7f; | ||
547 | |||
548 | return RezSingleAttachmentFromInventoryInternal(sp, itemID, UUID.Zero, AttachmentPt, append, doc); | ||
459 | } | 549 | } |
460 | 550 | ||
461 | public void RezMultipleAttachmentsFromInventory(IScenePresence sp, List<KeyValuePair<UUID, uint>> rezlist) | 551 | public void RezMultipleAttachmentsFromInventory(IScenePresence sp, List<KeyValuePair<UUID, uint>> rezlist) |
@@ -463,13 +553,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
463 | if (!Enabled) | 553 | if (!Enabled) |
464 | return; | 554 | return; |
465 | 555 | ||
466 | // m_log.DebugFormat("[ATTACHMENTS MODULE]: Rezzing multiple attachments from inventory for {0}", sp.Name); | 556 | if (DebugLevel > 0) |
467 | lock (sp.AttachmentsSyncLock) | 557 | m_log.DebugFormat( |
558 | "[ATTACHMENTS MODULE]: Rezzing {0} attachments from inventory for {1} in {2}", | ||
559 | rezlist.Count, sp.Name, m_scene.Name); | ||
560 | |||
561 | foreach (KeyValuePair<UUID, uint> rez in rezlist) | ||
468 | { | 562 | { |
469 | foreach (KeyValuePair<UUID, uint> rez in rezlist) | 563 | RezSingleAttachmentFromInventory(sp, rez.Key, rez.Value); |
470 | { | ||
471 | RezSingleAttachmentFromInventory(sp, rez.Key, rez.Value); | ||
472 | } | ||
473 | } | 564 | } |
474 | } | 565 | } |
475 | 566 | ||
@@ -483,9 +574,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
483 | if (!Enabled) | 574 | if (!Enabled) |
484 | return; | 575 | return; |
485 | 576 | ||
486 | // m_log.DebugFormat( | 577 | if (DebugLevel > 0) |
487 | // "[ATTACHMENTS MODULE]: DetachSingleAttachmentToGround() for {0}, object {1}", | 578 | m_log.DebugFormat( |
488 | // sp.UUID, soLocalId); | 579 | "[ATTACHMENTS MODULE]: DetachSingleAttachmentToGround() for {0}, object {1}", |
580 | sp.UUID, soLocalId); | ||
489 | 581 | ||
490 | SceneObjectGroup so = m_scene.GetGroupByPrim(soLocalId); | 582 | SceneObjectGroup so = m_scene.GetGroupByPrim(soLocalId); |
491 | 583 | ||
@@ -501,9 +593,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
501 | if (inventoryID == UUID.Zero) | 593 | if (inventoryID == UUID.Zero) |
502 | return; | 594 | return; |
503 | 595 | ||
504 | // m_log.DebugFormat( | 596 | if (DebugLevel > 0) |
505 | // "[ATTACHMENTS MODULE]: In DetachSingleAttachmentToGround(), object is {0} {1}, associated item is {2}", | 597 | m_log.DebugFormat( |
506 | // so.Name, so.LocalId, inventoryID); | 598 | "[ATTACHMENTS MODULE]: In DetachSingleAttachmentToGround(), object is {0} {1}, associated item is {2}", |
599 | so.Name, so.LocalId, inventoryID); | ||
507 | 600 | ||
508 | lock (sp.AttachmentsSyncLock) | 601 | lock (sp.AttachmentsSyncLock) |
509 | { | 602 | { |
@@ -549,25 +642,38 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
549 | 642 | ||
550 | public void DetachSingleAttachmentToInv(IScenePresence sp, SceneObjectGroup so) | 643 | public void DetachSingleAttachmentToInv(IScenePresence sp, SceneObjectGroup so) |
551 | { | 644 | { |
645 | if (so.AttachedAvatar != sp.UUID) | ||
646 | { | ||
647 | m_log.WarnFormat( | ||
648 | "[ATTACHMENTS MODULE]: Tried to detach object {0} from {1} {2} but attached avatar id was {3} in {4}", | ||
649 | so.Name, sp.Name, sp.UUID, so.AttachedAvatar, m_scene.RegionInfo.RegionName); | ||
650 | |||
651 | return; | ||
652 | } | ||
653 | |||
654 | if (DebugLevel > 0) | ||
655 | m_log.DebugFormat( | ||
656 | "[ATTACHMENTS MODULE]: Detaching object {0} {1} (FromItemID {2}) for {3} in {4}", | ||
657 | so.Name, so.LocalId, so.FromItemID, sp.Name, m_scene.Name); | ||
658 | |||
659 | // Scripts MUST be snapshotted before the object is | ||
660 | // removed from the scene because doing otherwise will | ||
661 | // clobber the run flag | ||
662 | // This must be done outside the sp.AttachmentSyncLock so that there is no risk of a deadlock from | ||
663 | // scripts performing attachment operations at the same time. Getting object states stops the scripts. | ||
664 | string scriptedState = PrepareScriptInstanceForSave(so, true); | ||
665 | |||
552 | lock (sp.AttachmentsSyncLock) | 666 | lock (sp.AttachmentsSyncLock) |
553 | { | 667 | { |
554 | // Save avatar attachment information | 668 | // Save avatar attachment information |
555 | // m_log.Debug("[ATTACHMENTS MODULE]: Detaching from UserID: " + sp.UUID + ", ItemID: " + itemID); | 669 | // m_log.Debug("[ATTACHMENTS MODULE]: Detaching from UserID: " + sp.UUID + ", ItemID: " + itemID); |
556 | 670 | ||
557 | if (so.AttachedAvatar != sp.UUID) | ||
558 | { | ||
559 | m_log.WarnFormat( | ||
560 | "[ATTACHMENTS MODULE]: Tried to detach object {0} from {1} {2} but attached avatar id was {3} in {4}", | ||
561 | so.Name, sp.Name, sp.UUID, so.AttachedAvatar, m_scene.RegionInfo.RegionName); | ||
562 | |||
563 | return; | ||
564 | } | ||
565 | |||
566 | bool changed = sp.Appearance.DetachAttachment(so.FromItemID); | 671 | bool changed = sp.Appearance.DetachAttachment(so.FromItemID); |
567 | if (changed && m_scene.AvatarFactory != null) | 672 | if (changed && m_scene.AvatarFactory != null) |
568 | m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID); | 673 | m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID); |
569 | 674 | ||
570 | DetachSingleAttachmentToInvInternal(sp, so); | 675 | sp.RemoveAttachment(so); |
676 | UpdateDetachedObject(sp, so, scriptedState); | ||
571 | } | 677 | } |
572 | } | 678 | } |
573 | 679 | ||
@@ -674,12 +780,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
674 | 780 | ||
675 | grp.HasGroupChanged = false; // Prevent it being saved over and over | 781 | grp.HasGroupChanged = false; // Prevent it being saved over and over |
676 | } | 782 | } |
677 | // else | 783 | else if (DebugLevel > 0) |
678 | // { | 784 | { |
679 | // m_log.DebugFormat( | 785 | m_log.DebugFormat( |
680 | // "[ATTACHMENTS MODULE]: Don't need to update asset for unchanged attachment {0}, attachpoint {1}", | 786 | "[ATTACHMENTS MODULE]: Don't need to update asset for unchanged attachment {0}, attachpoint {1}", |
681 | // grp.UUID, grp.AttachmentPoint); | 787 | grp.UUID, grp.AttachmentPoint); |
682 | // } | 788 | } |
683 | } | 789 | } |
684 | 790 | ||
685 | /// <summary> | 791 | /// <summary> |
@@ -697,9 +803,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
697 | private void AttachToAgent( | 803 | private void AttachToAgent( |
698 | IScenePresence sp, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent) | 804 | IScenePresence sp, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent) |
699 | { | 805 | { |
700 | // m_log.DebugFormat( | 806 | if (DebugLevel > 0) |
701 | // "[ATTACHMENTS MODULE]: Adding attachment {0} to avatar {1} in pt {2} pos {3} {4}", | 807 | m_log.DebugFormat( |
702 | // so.Name, sp.Name, attachmentpoint, attachOffset, so.RootPart.AttachedPos); | 808 | "[ATTACHMENTS MODULE]: Adding attachment {0} to avatar {1} in pt {2} pos {3} {4}", |
809 | so.Name, sp.Name, attachmentpoint, attachOffset, so.RootPart.AttachedPos); | ||
703 | 810 | ||
704 | so.DetachFromBackup(); | 811 | so.DetachFromBackup(); |
705 | 812 | ||
@@ -722,19 +829,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
722 | 829 | ||
723 | if (!silent) | 830 | if (!silent) |
724 | { | 831 | { |
725 | // Killing it here will cause the client to deselect it | 832 | if (so.HasPrivateAttachmentPoint) |
726 | // It then reappears on the avatar, deselected | ||
727 | // through the full update below | ||
728 | // | ||
729 | if (so.IsSelected) | ||
730 | { | 833 | { |
731 | m_scene.SendKillObject(new List<uint> { so.RootPart.LocalId }); | 834 | if (DebugLevel > 0) |
732 | } | 835 | m_log.DebugFormat( |
733 | else if (so.HasPrivateAttachmentPoint) | 836 | "[ATTACHMENTS MODULE]: Killing private HUD {0} for avatars other than {1} at attachment point {2}", |
734 | { | 837 | so.Name, sp.Name, so.AttachmentPoint); |
735 | // m_log.DebugFormat( | ||
736 | // "[ATTACHMENTS MODULE]: Killing private HUD {0} for avatars other than {1} at attachment point {2}", | ||
737 | // so.Name, sp.Name, so.AttachmentPoint); | ||
738 | 838 | ||
739 | // As this scene object can now only be seen by the attaching avatar, tell everybody else in the | 839 | // As this scene object can now only be seen by the attaching avatar, tell everybody else in the |
740 | // scene that it's no longer in their awareness. | 840 | // scene that it's no longer in their awareness. |
@@ -745,7 +845,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
745 | }); | 845 | }); |
746 | } | 846 | } |
747 | 847 | ||
748 | so.IsSelected = false; // fudge.... | 848 | // Fudge below is an extremely unhelpful comment. It's probably here so that the scheduled full update |
849 | // will succeed, as that will not update if an attachment is selected. | ||
850 | so.IsSelected = false; // fudge.... | ||
851 | |||
749 | so.ScheduleGroupForFullUpdate(); | 852 | so.ScheduleGroupForFullUpdate(); |
750 | } | 853 | } |
751 | 854 | ||
@@ -765,9 +868,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
765 | if (m_invAccessModule == null) | 868 | if (m_invAccessModule == null) |
766 | return null; | 869 | return null; |
767 | 870 | ||
768 | // m_log.DebugFormat( | 871 | if (DebugLevel > 0) |
769 | // "[ATTACHMENTS MODULE]: Called AddSceneObjectAsAttachment for object {0} {1} for {2}", | 872 | m_log.DebugFormat( |
770 | // grp.Name, grp.LocalId, remoteClient.Name); | 873 | "[ATTACHMENTS MODULE]: Called AddSceneObjectAsAttachment for object {0} {1} for {2}", |
874 | grp.Name, grp.LocalId, sp.Name); | ||
771 | 875 | ||
772 | InventoryItemBase newItem | 876 | InventoryItemBase newItem |
773 | = m_invAccessModule.CopyToInventory( | 877 | = m_invAccessModule.CopyToInventory( |
@@ -782,8 +886,27 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
782 | return newItem; | 886 | return newItem; |
783 | } | 887 | } |
784 | 888 | ||
785 | private string GetObjectScriptStates(SceneObjectGroup grp) | 889 | /// <summary> |
890 | /// Prepares the script instance for save. | ||
891 | /// </summary> | ||
892 | /// <remarks> | ||
893 | /// This involves triggering the detach event and getting the script state (which also stops the script) | ||
894 | /// This MUST be done outside sp.AttachmentsSyncLock, since otherwise there is a chance of deadlock if a | ||
895 | /// running script is performing attachment operations. | ||
896 | /// </remarks> | ||
897 | /// <returns> | ||
898 | /// The script state ready for persistence. | ||
899 | /// </returns> | ||
900 | /// <param name='grp'> | ||
901 | /// </param> | ||
902 | /// <param name='fireDetachEvent'> | ||
903 | /// If true, then fire the script event before we save its state. | ||
904 | /// </param> | ||
905 | private string PrepareScriptInstanceForSave(SceneObjectGroup grp, bool fireDetachEvent) | ||
786 | { | 906 | { |
907 | if (fireDetachEvent) | ||
908 | m_scene.EventManager.TriggerOnAttach(grp.LocalId, grp.FromItemID, UUID.Zero); | ||
909 | |||
787 | using (StringWriter sw = new StringWriter()) | 910 | using (StringWriter sw = new StringWriter()) |
788 | { | 911 | { |
789 | using (XmlTextWriter writer = new XmlTextWriter(sw)) | 912 | using (XmlTextWriter writer = new XmlTextWriter(sw)) |
@@ -795,7 +918,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
795 | } | 918 | } |
796 | } | 919 | } |
797 | 920 | ||
798 | private void UpdateDetachedObject(IScenePresence sp, SceneObjectGroup so) | 921 | private void UpdateDetachedObject(IScenePresence sp, SceneObjectGroup so, string scriptedState) |
799 | { | 922 | { |
800 | // Don't save attachments for HG visitors, it | 923 | // Don't save attachments for HG visitors, it |
801 | // messes up their inventory. When a HG visitor logs | 924 | // messes up their inventory. When a HG visitor logs |
@@ -808,11 +931,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
808 | && (m_scene.UserManagementModule == null | 931 | && (m_scene.UserManagementModule == null |
809 | || m_scene.UserManagementModule.IsLocalGridUser(sp.UUID)); | 932 | || m_scene.UserManagementModule.IsLocalGridUser(sp.UUID)); |
810 | 933 | ||
811 | // Scripts MUST be snapshotted before the object is | ||
812 | // removed from the scene because doing otherwise will | ||
813 | // clobber the run flag | ||
814 | string scriptedState = GetObjectScriptStates(so); | ||
815 | |||
816 | // Remove the object from the scene so no more updates | 934 | // Remove the object from the scene so no more updates |
817 | // are sent. Doing this before the below changes will ensure | 935 | // are sent. Doing this before the below changes will ensure |
818 | // updates can't cause "HUD artefacts" | 936 | // updates can't cause "HUD artefacts" |
@@ -836,97 +954,75 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
836 | so.RemoveScriptInstances(true); | 954 | so.RemoveScriptInstances(true); |
837 | } | 955 | } |
838 | 956 | ||
839 | private void DetachSingleAttachmentToInvInternal(IScenePresence sp, SceneObjectGroup so) | ||
840 | { | ||
841 | // m_log.DebugFormat("[ATTACHMENTS MODULE]: Detaching item {0} to inventory for {1}", itemID, sp.Name); | ||
842 | |||
843 | m_scene.EventManager.TriggerOnAttach(so.LocalId, so.FromItemID, UUID.Zero); | ||
844 | sp.RemoveAttachment(so); | ||
845 | |||
846 | UpdateDetachedObject(sp, so); | ||
847 | } | ||
848 | |||
849 | protected SceneObjectGroup RezSingleAttachmentFromInventoryInternal( | 957 | protected SceneObjectGroup RezSingleAttachmentFromInventoryInternal( |
850 | IScenePresence sp, UUID itemID, UUID assetID, uint attachmentPt, XmlDocument doc) | 958 | IScenePresence sp, UUID itemID, UUID assetID, uint attachmentPt, bool append, XmlDocument doc) |
851 | { | 959 | { |
852 | if (m_invAccessModule == null) | 960 | if (m_invAccessModule == null) |
853 | return null; | 961 | return null; |
854 | 962 | ||
855 | lock (sp.AttachmentsSyncLock) | 963 | SceneObjectGroup objatt; |
964 | |||
965 | if (itemID != UUID.Zero) | ||
966 | objatt = m_invAccessModule.RezObject(sp.ControllingClient, | ||
967 | itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, | ||
968 | false, false, sp.UUID, true); | ||
969 | else | ||
970 | objatt = m_invAccessModule.RezObject(sp.ControllingClient, | ||
971 | null, assetID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, | ||
972 | false, false, sp.UUID, true); | ||
973 | |||
974 | if (objatt == null) | ||
856 | { | 975 | { |
857 | SceneObjectGroup objatt; | 976 | m_log.WarnFormat( |
977 | "[ATTACHMENTS MODULE]: Could not retrieve item {0} for attaching to avatar {1} at point {2}", | ||
978 | itemID, sp.Name, attachmentPt); | ||
858 | 979 | ||
859 | if (itemID != UUID.Zero) | 980 | return null; |
860 | objatt = m_invAccessModule.RezObject(sp.ControllingClient, | 981 | } |
861 | itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, | ||
862 | false, false, sp.UUID, true); | ||
863 | else | ||
864 | objatt = m_invAccessModule.RezObject(sp.ControllingClient, | ||
865 | null, assetID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, | ||
866 | false, false, sp.UUID, true); | ||
867 | 982 | ||
868 | if (objatt != null) | 983 | if (DebugLevel > 0) |
984 | m_log.DebugFormat( | ||
985 | "[ATTACHMENTS MODULE]: Rezzed single object {0} for attachment to {1} on point {2} in {3}", | ||
986 | objatt.Name, sp.Name, attachmentPt, m_scene.Name); | ||
987 | |||
988 | // HasGroupChanged is being set from within RezObject. Ideally it would be set by the caller. | ||
989 | objatt.HasGroupChanged = false; | ||
990 | bool tainted = false; | ||
991 | if (attachmentPt != 0 && attachmentPt != objatt.AttachmentPoint) | ||
992 | tainted = true; | ||
993 | |||
994 | // FIXME: Detect whether it's really likely for AttachObject to throw an exception in the normal | ||
995 | // course of events. If not, then it's probably not worth trying to recover the situation | ||
996 | // since this is more likely to trigger further exceptions and confuse later debugging. If | ||
997 | // exceptions can be thrown in expected error conditions (not NREs) then make this consistent | ||
998 | // since other normal error conditions will simply return false instead. | ||
999 | // This will throw if the attachment fails | ||
1000 | try | ||
1001 | { | ||
1002 | if (doc != null) | ||
869 | { | 1003 | { |
870 | // m_log.DebugFormat( | 1004 | objatt.LoadScriptState(doc); |
871 | // "[ATTACHMENTS MODULE]: Rezzed single object {0} for attachment to {1} on point {2} in {3}", | 1005 | objatt.ResetOwnerChangeFlag(); |
872 | // objatt.Name, sp.Name, attachmentPt, m_scene.Name); | 1006 | } |
873 | |||
874 | // HasGroupChanged is being set from within RezObject. Ideally it would be set by the caller. | ||
875 | objatt.HasGroupChanged = false; | ||
876 | bool tainted = false; | ||
877 | if (attachmentPt != 0 && attachmentPt != objatt.AttachmentPoint) | ||
878 | tainted = true; | ||
879 | |||
880 | // FIXME: Detect whether it's really likely for AttachObject to throw an exception in the normal | ||
881 | // course of events. If not, then it's probably not worth trying to recover the situation | ||
882 | // since this is more likely to trigger further exceptions and confuse later debugging. If | ||
883 | // exceptions can be thrown in expected error conditions (not NREs) then make this consistent | ||
884 | // since other normal error conditions will simply return false instead. | ||
885 | // This will throw if the attachment fails | ||
886 | try | ||
887 | { | ||
888 | AttachObjectInternal(sp, objatt, attachmentPt, false, false, false); | ||
889 | } | ||
890 | catch (Exception e) | ||
891 | { | ||
892 | m_log.ErrorFormat( | ||
893 | "[ATTACHMENTS MODULE]: Failed to attach {0} {1} for {2}, exception {3}{4}", | ||
894 | objatt.Name, objatt.UUID, sp.Name, e.Message, e.StackTrace); | ||
895 | |||
896 | // Make sure the object doesn't stick around and bail | ||
897 | sp.RemoveAttachment(objatt); | ||
898 | m_scene.DeleteSceneObject(objatt, false); | ||
899 | return null; | ||
900 | } | ||
901 | |||
902 | if (tainted) | ||
903 | objatt.HasGroupChanged = true; | ||
904 | 1007 | ||
905 | if (doc != null) | 1008 | AttachObjectInternal(sp, objatt, attachmentPt, false, true, true, true, append); |
906 | { | 1009 | } |
907 | objatt.LoadScriptState(doc); | 1010 | catch (Exception e) |
908 | objatt.ResetOwnerChangeFlag(); | 1011 | { |
909 | } | 1012 | m_log.ErrorFormat( |
1013 | "[ATTACHMENTS MODULE]: Failed to attach {0} {1} for {2}, exception {3}{4}", | ||
1014 | objatt.Name, objatt.UUID, sp.Name, e.Message, e.StackTrace); | ||
910 | 1015 | ||
911 | // Fire after attach, so we don't get messy perms dialogs | 1016 | // Make sure the object doesn't stick around and bail |
912 | // 4 == AttachedRez | 1017 | sp.RemoveAttachment(objatt); |
913 | objatt.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 4); | 1018 | m_scene.DeleteSceneObject(objatt, false); |
914 | objatt.ResumeScripts(); | 1019 | return null; |
1020 | } | ||
915 | 1021 | ||
916 | // Do this last so that event listeners have access to all the effects of the attachment | 1022 | if (tainted) |
917 | m_scene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, sp.UUID); | 1023 | objatt.HasGroupChanged = true; |
918 | 1024 | ||
919 | return objatt; | 1025 | return objatt; |
920 | } | ||
921 | else | ||
922 | { | ||
923 | m_log.WarnFormat( | ||
924 | "[ATTACHMENTS MODULE]: Could not retrieve item {0} for attaching to avatar {1} at point {2}", | ||
925 | itemID, sp.Name, attachmentPt); | ||
926 | } | ||
927 | } | ||
928 | |||
929 | return null; | ||
930 | } | 1026 | } |
931 | 1027 | ||
932 | /// <summary> | 1028 | /// <summary> |
@@ -936,7 +1032,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
936 | /// <param name="AttachmentPt"></param> | 1032 | /// <param name="AttachmentPt"></param> |
937 | /// <param name="itemID"></param> | 1033 | /// <param name="itemID"></param> |
938 | /// <param name="att"></param> | 1034 | /// <param name="att"></param> |
939 | private void ShowAttachInUserInventory(IScenePresence sp, uint AttachmentPt, UUID itemID, SceneObjectGroup att) | 1035 | private void ShowAttachInUserInventory(IScenePresence sp, uint AttachmentPt, UUID itemID, SceneObjectGroup att, bool append) |
940 | { | 1036 | { |
941 | // m_log.DebugFormat( | 1037 | // m_log.DebugFormat( |
942 | // "[USER INVENTORY]: Updating attachment {0} for {1} at {2} using item ID {3}", | 1038 | // "[USER INVENTORY]: Updating attachment {0} for {1} at {2} using item ID {3}", |
@@ -959,12 +1055,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
959 | if (item == null) | 1055 | if (item == null) |
960 | return; | 1056 | return; |
961 | 1057 | ||
962 | bool changed = sp.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID); | 1058 | int attFlag = append ? 0x80 : 0; |
1059 | bool changed = sp.Appearance.SetAttachment((int)AttachmentPt | attFlag, itemID, item.AssetID); | ||
963 | if (changed && m_scene.AvatarFactory != null) | 1060 | if (changed && m_scene.AvatarFactory != null) |
964 | { | 1061 | { |
965 | // m_log.DebugFormat( | 1062 | if (DebugLevel > 0) |
966 | // "[ATTACHMENTS MODULE]: Queueing appearance save for {0}, attachment {1} point {2} in ShowAttachInUserInventory()", | 1063 | m_log.DebugFormat( |
967 | // sp.Name, att.Name, AttachmentPt); | 1064 | "[ATTACHMENTS MODULE]: Queueing appearance save for {0}, attachment {1} point {2} in ShowAttachInUserInventory()", |
1065 | sp.Name, att.Name, AttachmentPt); | ||
968 | 1066 | ||
969 | m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID); | 1067 | m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID); |
970 | } | 1068 | } |
@@ -979,9 +1077,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
979 | if (!Enabled) | 1077 | if (!Enabled) |
980 | return null; | 1078 | return null; |
981 | 1079 | ||
982 | // m_log.DebugFormat( | 1080 | if (DebugLevel > 0) |
983 | // "[ATTACHMENTS MODULE]: Rezzing attachment to point {0} from item {1} for {2}", | 1081 | m_log.DebugFormat( |
984 | // (AttachmentPoint)AttachmentPt, itemID, remoteClient.Name); | 1082 | "[ATTACHMENTS MODULE]: Rezzing attachment to point {0} from item {1} for {2}", |
1083 | (AttachmentPoint)AttachmentPt, itemID, remoteClient.Name); | ||
985 | 1084 | ||
986 | ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId); | 1085 | ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId); |
987 | 1086 | ||
@@ -1012,9 +1111,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
1012 | 1111 | ||
1013 | private void Client_OnObjectAttach(IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, bool silent) | 1112 | private void Client_OnObjectAttach(IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, bool silent) |
1014 | { | 1113 | { |
1015 | // m_log.DebugFormat( | 1114 | if (DebugLevel > 0) |
1016 | // "[ATTACHMENTS MODULE]: Attaching object local id {0} to {1} point {2} from ground (silent = {3})", | 1115 | m_log.DebugFormat( |
1017 | // objectLocalID, remoteClient.Name, AttachmentPt, silent); | 1116 | "[ATTACHMENTS MODULE]: Attaching object local id {0} to {1} point {2} from ground (silent = {3})", |
1117 | objectLocalID, remoteClient.Name, AttachmentPt, silent); | ||
1018 | 1118 | ||
1019 | if (!Enabled) | 1119 | if (!Enabled) |
1020 | return; | 1120 | return; |
@@ -1043,16 +1143,16 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
1043 | return; | 1143 | return; |
1044 | } | 1144 | } |
1045 | 1145 | ||
1046 | // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should | 1146 | bool append = (AttachmentPt & 0x80) != 0; |
1047 | // be removed when that functionality is implemented in opensim | ||
1048 | AttachmentPt &= 0x7f; | 1147 | AttachmentPt &= 0x7f; |
1049 | 1148 | ||
1050 | // Calls attach with a Zero position | 1149 | // Calls attach with a Zero position |
1051 | if (AttachObject(sp, part.ParentGroup, AttachmentPt, false, true, false)) | 1150 | if (AttachObject(sp, part.ParentGroup, AttachmentPt, false, false, false, append)) |
1052 | { | 1151 | { |
1053 | // m_log.Debug( | 1152 | if (DebugLevel > 0) |
1054 | // "[ATTACHMENTS MODULE]: Saving avatar attachment. AgentID: " + remoteClient.AgentId | 1153 | m_log.Debug( |
1055 | // + ", AttachmentPoint: " + AttachmentPt); | 1154 | "[ATTACHMENTS MODULE]: Saving avatar attachment. AgentID: " + remoteClient.AgentId |
1155 | + ", AttachmentPoint: " + AttachmentPt); | ||
1056 | 1156 | ||
1057 | // Save avatar attachment information | 1157 | // Save avatar attachment information |
1058 | m_scene.EventManager.TriggerOnAttach(objectLocalID, part.ParentGroup.FromItemID, remoteClient.AgentId); | 1158 | m_scene.EventManager.TriggerOnAttach(objectLocalID, part.ParentGroup.FromItemID, remoteClient.AgentId); |
@@ -1084,17 +1184,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
1084 | ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId); | 1184 | ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId); |
1085 | if (sp != null) | 1185 | if (sp != null) |
1086 | { | 1186 | { |
1087 | lock (sp.AttachmentsSyncLock) | 1187 | List<SceneObjectGroup> attachments = sp.GetAttachments(); |
1188 | |||
1189 | foreach (SceneObjectGroup group in attachments) | ||
1088 | { | 1190 | { |
1089 | List<SceneObjectGroup> attachments = sp.GetAttachments(); | 1191 | if (group.FromItemID == itemID && group.FromItemID != UUID.Zero) |
1090 | |||
1091 | foreach (SceneObjectGroup group in attachments) | ||
1092 | { | 1192 | { |
1093 | if (group.FromItemID == itemID && group.FromItemID != UUID.Zero) | 1193 | DetachSingleAttachmentToInv(sp, group); |
1094 | { | 1194 | return; |
1095 | DetachSingleAttachmentToInv(sp, group); | ||
1096 | return; | ||
1097 | } | ||
1098 | } | 1195 | } |
1099 | } | 1196 | } |
1100 | } | 1197 | } |
diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs index 4e9d3f9..1a38619 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs | |||
@@ -130,7 +130,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests | |||
130 | config.AddConfig("Modules"); | 130 | config.AddConfig("Modules"); |
131 | config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule"); | 131 | config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule"); |
132 | 132 | ||
133 | modules.Add(new AttachmentsModule()); | 133 | AttachmentsModule attMod = new AttachmentsModule(); |
134 | attMod.DebugLevel = 1; | ||
135 | modules.Add(attMod); | ||
134 | modules.Add(new BasicInventoryAccessModule()); | 136 | modules.Add(new BasicInventoryAccessModule()); |
135 | } | 137 | } |
136 | 138 | ||
@@ -197,7 +199,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests | |||
197 | SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, attName, sp.UUID); | 199 | SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, attName, sp.UUID); |
198 | 200 | ||
199 | m_numberOfAttachEventsFired = 0; | 201 | m_numberOfAttachEventsFired = 0; |
200 | scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Chest, false, false, false); | 202 | scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Chest, false, true, false, false); |
201 | 203 | ||
202 | // Check status on scene presence | 204 | // Check status on scene presence |
203 | Assert.That(sp.HasAttachments(), Is.True); | 205 | Assert.That(sp.HasAttachments(), Is.True); |
@@ -228,6 +230,120 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests | |||
228 | Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1)); | 230 | Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1)); |
229 | } | 231 | } |
230 | 232 | ||
233 | [Test] | ||
234 | public void TestWearAttachmentFromGround() | ||
235 | { | ||
236 | TestHelpers.InMethod(); | ||
237 | // TestHelpers.EnableLogging(); | ||
238 | |||
239 | Scene scene = CreateTestScene(); | ||
240 | UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1); | ||
241 | ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1); | ||
242 | |||
243 | SceneObjectGroup so2 = SceneHelpers.AddSceneObject(scene, "att2", sp.UUID); | ||
244 | |||
245 | { | ||
246 | SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, "att1", sp.UUID); | ||
247 | |||
248 | m_numberOfAttachEventsFired = 0; | ||
249 | scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Default, false, true, false, false); | ||
250 | |||
251 | // Check status on scene presence | ||
252 | Assert.That(sp.HasAttachments(), Is.True); | ||
253 | List<SceneObjectGroup> attachments = sp.GetAttachments(); | ||
254 | Assert.That(attachments.Count, Is.EqualTo(1)); | ||
255 | SceneObjectGroup attSo = attachments[0]; | ||
256 | Assert.That(attSo.Name, Is.EqualTo(so.Name)); | ||
257 | Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand)); | ||
258 | Assert.That(attSo.IsAttachment); | ||
259 | Assert.That(attSo.UsesPhysics, Is.False); | ||
260 | Assert.That(attSo.IsTemporary, Is.False); | ||
261 | |||
262 | // Check item status | ||
263 | Assert.That( | ||
264 | sp.Appearance.GetAttachpoint(attSo.FromItemID), | ||
265 | Is.EqualTo((int)AttachmentPoint.LeftHand)); | ||
266 | |||
267 | InventoryItemBase attachmentItem = scene.InventoryService.GetItem(new InventoryItemBase(attSo.FromItemID)); | ||
268 | Assert.That(attachmentItem, Is.Not.Null); | ||
269 | Assert.That(attachmentItem.Name, Is.EqualTo(so.Name)); | ||
270 | |||
271 | InventoryFolderBase targetFolder = scene.InventoryService.GetFolderForType(sp.UUID, AssetType.Object); | ||
272 | Assert.That(attachmentItem.Folder, Is.EqualTo(targetFolder.ID)); | ||
273 | |||
274 | Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(2)); | ||
275 | |||
276 | // Check events | ||
277 | Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1)); | ||
278 | } | ||
279 | |||
280 | // Test wearing a different attachment from the ground. | ||
281 | { | ||
282 | scene.AttachmentsModule.AttachObject(sp, so2, (uint)AttachmentPoint.Default, false, true, false, false); | ||
283 | |||
284 | // Check status on scene presence | ||
285 | Assert.That(sp.HasAttachments(), Is.True); | ||
286 | List<SceneObjectGroup> attachments = sp.GetAttachments(); | ||
287 | Assert.That(attachments.Count, Is.EqualTo(1)); | ||
288 | SceneObjectGroup attSo = attachments[0]; | ||
289 | Assert.That(attSo.Name, Is.EqualTo(so2.Name)); | ||
290 | Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand)); | ||
291 | Assert.That(attSo.IsAttachment); | ||
292 | Assert.That(attSo.UsesPhysics, Is.False); | ||
293 | Assert.That(attSo.IsTemporary, Is.False); | ||
294 | |||
295 | // Check item status | ||
296 | Assert.That( | ||
297 | sp.Appearance.GetAttachpoint(attSo.FromItemID), | ||
298 | Is.EqualTo((int)AttachmentPoint.LeftHand)); | ||
299 | |||
300 | InventoryItemBase attachmentItem = scene.InventoryService.GetItem(new InventoryItemBase(attSo.FromItemID)); | ||
301 | Assert.That(attachmentItem, Is.Not.Null); | ||
302 | Assert.That(attachmentItem.Name, Is.EqualTo(so2.Name)); | ||
303 | |||
304 | InventoryFolderBase targetFolder = scene.InventoryService.GetFolderForType(sp.UUID, AssetType.Object); | ||
305 | Assert.That(attachmentItem.Folder, Is.EqualTo(targetFolder.ID)); | ||
306 | |||
307 | Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); | ||
308 | |||
309 | // Check events | ||
310 | Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(3)); | ||
311 | } | ||
312 | |||
313 | // Test rewearing an already worn attachment from ground. Nothing should happen. | ||
314 | { | ||
315 | scene.AttachmentsModule.AttachObject(sp, so2, (uint)AttachmentPoint.Default, false, true, false, false); | ||
316 | |||
317 | // Check status on scene presence | ||
318 | Assert.That(sp.HasAttachments(), Is.True); | ||
319 | List<SceneObjectGroup> attachments = sp.GetAttachments(); | ||
320 | Assert.That(attachments.Count, Is.EqualTo(1)); | ||
321 | SceneObjectGroup attSo = attachments[0]; | ||
322 | Assert.That(attSo.Name, Is.EqualTo(so2.Name)); | ||
323 | Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand)); | ||
324 | Assert.That(attSo.IsAttachment); | ||
325 | Assert.That(attSo.UsesPhysics, Is.False); | ||
326 | Assert.That(attSo.IsTemporary, Is.False); | ||
327 | |||
328 | // Check item status | ||
329 | Assert.That( | ||
330 | sp.Appearance.GetAttachpoint(attSo.FromItemID), | ||
331 | Is.EqualTo((int)AttachmentPoint.LeftHand)); | ||
332 | |||
333 | InventoryItemBase attachmentItem = scene.InventoryService.GetItem(new InventoryItemBase(attSo.FromItemID)); | ||
334 | Assert.That(attachmentItem, Is.Not.Null); | ||
335 | Assert.That(attachmentItem.Name, Is.EqualTo(so2.Name)); | ||
336 | |||
337 | InventoryFolderBase targetFolder = scene.InventoryService.GetFolderForType(sp.UUID, AssetType.Object); | ||
338 | Assert.That(attachmentItem.Folder, Is.EqualTo(targetFolder.ID)); | ||
339 | |||
340 | Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); | ||
341 | |||
342 | // Check events | ||
343 | Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(3)); | ||
344 | } | ||
345 | } | ||
346 | |||
231 | /// <summary> | 347 | /// <summary> |
232 | /// Test that we do not attempt to attach an in-world object that someone else is sitting on. | 348 | /// Test that we do not attempt to attach an in-world object that someone else is sitting on. |
233 | /// </summary> | 349 | /// </summary> |
@@ -254,7 +370,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests | |||
254 | sp2.AbsolutePosition = new Vector3(0, 0, 0); | 370 | sp2.AbsolutePosition = new Vector3(0, 0, 0); |
255 | sp2.HandleAgentRequestSit(sp2.ControllingClient, sp2.UUID, so.UUID, Vector3.Zero); | 371 | sp2.HandleAgentRequestSit(sp2.ControllingClient, sp2.UUID, so.UUID, Vector3.Zero); |
256 | 372 | ||
257 | scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Chest, false, false, false); | 373 | scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Chest, false, true, false, false); |
258 | 374 | ||
259 | Assert.That(sp.HasAttachments(), Is.False); | 375 | Assert.That(sp.HasAttachments(), Is.False); |
260 | Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); | 376 | Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); |
@@ -275,29 +391,140 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests | |||
275 | 391 | ||
276 | InventoryItemBase attItem = CreateAttachmentItem(scene, ua1.PrincipalID, "att", 0x10, 0x20); | 392 | InventoryItemBase attItem = CreateAttachmentItem(scene, ua1.PrincipalID, "att", 0x10, 0x20); |
277 | 393 | ||
278 | m_numberOfAttachEventsFired = 0; | 394 | { |
279 | scene.AttachmentsModule.RezSingleAttachmentFromInventory( | 395 | scene.AttachmentsModule.RezSingleAttachmentFromInventory( |
280 | sp, attItem.ID, (uint)AttachmentPoint.Chest); | 396 | sp, attItem.ID, (uint)AttachmentPoint.Chest); |
281 | 397 | ||
282 | // Check scene presence status | 398 | // Check scene presence status |
283 | Assert.That(sp.HasAttachments(), Is.True); | 399 | Assert.That(sp.HasAttachments(), Is.True); |
284 | List<SceneObjectGroup> attachments = sp.GetAttachments(); | 400 | List<SceneObjectGroup> attachments = sp.GetAttachments(); |
285 | Assert.That(attachments.Count, Is.EqualTo(1)); | 401 | Assert.That(attachments.Count, Is.EqualTo(1)); |
286 | SceneObjectGroup attSo = attachments[0]; | 402 | SceneObjectGroup attSo = attachments[0]; |
287 | Assert.That(attSo.Name, Is.EqualTo(attItem.Name)); | 403 | Assert.That(attSo.Name, Is.EqualTo(attItem.Name)); |
288 | Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.Chest)); | 404 | Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.Chest)); |
289 | Assert.That(attSo.IsAttachment); | 405 | Assert.That(attSo.IsAttachment); |
290 | Assert.That(attSo.UsesPhysics, Is.False); | 406 | Assert.That(attSo.UsesPhysics, Is.False); |
291 | Assert.That(attSo.IsTemporary, Is.False); | 407 | Assert.That(attSo.IsTemporary, Is.False); |
408 | |||
409 | // Check appearance status | ||
410 | Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1)); | ||
411 | Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest)); | ||
412 | Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); | ||
413 | |||
414 | // Check events | ||
415 | Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1)); | ||
416 | } | ||
417 | |||
418 | // Test attaching an already attached attachment | ||
419 | { | ||
420 | scene.AttachmentsModule.RezSingleAttachmentFromInventory( | ||
421 | sp, attItem.ID, (uint)AttachmentPoint.Chest); | ||
292 | 422 | ||
293 | // Check appearance status | 423 | // Check scene presence status |
294 | Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1)); | 424 | Assert.That(sp.HasAttachments(), Is.True); |
295 | Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest)); | 425 | List<SceneObjectGroup> attachments = sp.GetAttachments(); |
426 | Assert.That(attachments.Count, Is.EqualTo(1)); | ||
427 | SceneObjectGroup attSo = attachments[0]; | ||
428 | Assert.That(attSo.Name, Is.EqualTo(attItem.Name)); | ||
429 | Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.Chest)); | ||
430 | Assert.That(attSo.IsAttachment); | ||
431 | Assert.That(attSo.UsesPhysics, Is.False); | ||
432 | Assert.That(attSo.IsTemporary, Is.False); | ||
433 | |||
434 | // Check appearance status | ||
435 | Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1)); | ||
436 | Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest)); | ||
437 | Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); | ||
438 | |||
439 | // Check events | ||
440 | Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1)); | ||
441 | } | ||
442 | } | ||
296 | 443 | ||
297 | Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); | 444 | /// <summary> |
445 | /// Test wearing an attachment from inventory, as opposed to explicit choosing the rez point | ||
446 | /// </summary> | ||
447 | [Test] | ||
448 | public void TestWearAttachmentFromInventory() | ||
449 | { | ||
450 | TestHelpers.InMethod(); | ||
451 | // TestHelpers.EnableLogging(); | ||
298 | 452 | ||
299 | // Check events | 453 | Scene scene = CreateTestScene(); |
300 | Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1)); | 454 | UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1); |
455 | ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1.PrincipalID); | ||
456 | |||
457 | InventoryItemBase attItem1 = CreateAttachmentItem(scene, ua1.PrincipalID, "att1", 0x10, 0x20); | ||
458 | InventoryItemBase attItem2 = CreateAttachmentItem(scene, ua1.PrincipalID, "att2", 0x11, 0x21); | ||
459 | |||
460 | { | ||
461 | m_numberOfAttachEventsFired = 0; | ||
462 | scene.AttachmentsModule.RezSingleAttachmentFromInventory(sp, attItem1.ID, (uint)AttachmentPoint.Default); | ||
463 | |||
464 | // default attachment point is currently the left hand. | ||
465 | Assert.That(sp.HasAttachments(), Is.True); | ||
466 | List<SceneObjectGroup> attachments = sp.GetAttachments(); | ||
467 | Assert.That(attachments.Count, Is.EqualTo(1)); | ||
468 | SceneObjectGroup attSo = attachments[0]; | ||
469 | Assert.That(attSo.Name, Is.EqualTo(attItem1.Name)); | ||
470 | Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand)); | ||
471 | Assert.That(attSo.IsAttachment); | ||
472 | |||
473 | // Check appearance status | ||
474 | Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1)); | ||
475 | Assert.That(sp.Appearance.GetAttachpoint(attItem1.ID), Is.EqualTo((int)AttachmentPoint.LeftHand)); | ||
476 | Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); | ||
477 | |||
478 | // Check events | ||
479 | Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1)); | ||
480 | } | ||
481 | |||
482 | // Test wearing a second attachment at the same position | ||
483 | // Until multiple attachments at one point is implemented, this will remove the first attachment | ||
484 | // This test relies on both attachments having the same default attachment point (in this case LeftHand | ||
485 | // since none other has been set). | ||
486 | { | ||
487 | scene.AttachmentsModule.RezSingleAttachmentFromInventory(sp, attItem2.ID, (uint)AttachmentPoint.Default); | ||
488 | |||
489 | // default attachment point is currently the left hand. | ||
490 | Assert.That(sp.HasAttachments(), Is.True); | ||
491 | List<SceneObjectGroup> attachments = sp.GetAttachments(); | ||
492 | Assert.That(attachments.Count, Is.EqualTo(1)); | ||
493 | SceneObjectGroup attSo = attachments[0]; | ||
494 | Assert.That(attSo.Name, Is.EqualTo(attItem2.Name)); | ||
495 | Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand)); | ||
496 | Assert.That(attSo.IsAttachment); | ||
497 | |||
498 | // Check appearance status | ||
499 | Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1)); | ||
500 | Assert.That(sp.Appearance.GetAttachpoint(attItem2.ID), Is.EqualTo((int)AttachmentPoint.LeftHand)); | ||
501 | Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); | ||
502 | |||
503 | // Check events | ||
504 | Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(3)); | ||
505 | } | ||
506 | |||
507 | // Test wearing an already attached attachment | ||
508 | { | ||
509 | scene.AttachmentsModule.RezSingleAttachmentFromInventory(sp, attItem2.ID, (uint)AttachmentPoint.Default); | ||
510 | |||
511 | // default attachment point is currently the left hand. | ||
512 | Assert.That(sp.HasAttachments(), Is.True); | ||
513 | List<SceneObjectGroup> attachments = sp.GetAttachments(); | ||
514 | Assert.That(attachments.Count, Is.EqualTo(1)); | ||
515 | SceneObjectGroup attSo = attachments[0]; | ||
516 | Assert.That(attSo.Name, Is.EqualTo(attItem2.Name)); | ||
517 | Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand)); | ||
518 | Assert.That(attSo.IsAttachment); | ||
519 | |||
520 | // Check appearance status | ||
521 | Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1)); | ||
522 | Assert.That(sp.Appearance.GetAttachpoint(attItem2.ID), Is.EqualTo((int)AttachmentPoint.LeftHand)); | ||
523 | Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); | ||
524 | |||
525 | // Check events | ||
526 | Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(3)); | ||
527 | } | ||
301 | } | 528 | } |
302 | 529 | ||
303 | /// <summary> | 530 | /// <summary> |
@@ -503,7 +730,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests | |||
503 | public void TestRezAttachmentsOnAvatarEntrance() | 730 | public void TestRezAttachmentsOnAvatarEntrance() |
504 | { | 731 | { |
505 | TestHelpers.InMethod(); | 732 | TestHelpers.InMethod(); |
506 | // log4net.Config.XmlConfigurator.Configure(); | 733 | // TestHelpers.EnableLogging(); |
507 | 734 | ||
508 | Scene scene = CreateTestScene(); | 735 | Scene scene = CreateTestScene(); |
509 | UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1); | 736 | UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1); |
@@ -604,7 +831,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests | |||
604 | sceneB, config, new CapabilitiesModule(), etmB, attModB, new BasicInventoryAccessModule()); | 831 | sceneB, config, new CapabilitiesModule(), etmB, attModB, new BasicInventoryAccessModule()); |
605 | 832 | ||
606 | UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(sceneA, 0x1); | 833 | UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(sceneA, 0x1); |
607 | ScenePresence beforeTeleportSp = SceneHelpers.AddScenePresence(sceneA, ua1.PrincipalID, sh.SceneManager); | 834 | |
835 | AgentCircuitData acd = SceneHelpers.GenerateAgentData(ua1.PrincipalID); | ||
836 | TestClient tc = new TestClient(acd, sceneA, sh.SceneManager); | ||
837 | List<TestClient> destinationTestClients = new List<TestClient>(); | ||
838 | EntityTransferHelpers.SetUpInformClientOfNeighbour(tc, destinationTestClients); | ||
839 | |||
840 | ScenePresence beforeTeleportSp = SceneHelpers.AddScenePresence(sceneA, tc, acd, sh.SceneManager); | ||
608 | beforeTeleportSp.AbsolutePosition = new Vector3(30, 31, 32); | 841 | beforeTeleportSp.AbsolutePosition = new Vector3(30, 31, 32); |
609 | 842 | ||
610 | InventoryItemBase attItem = CreateAttachmentItem(sceneA, ua1.PrincipalID, "att", 0x10, 0x20); | 843 | InventoryItemBase attItem = CreateAttachmentItem(sceneA, ua1.PrincipalID, "att", 0x10, 0x20); |
@@ -623,7 +856,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests | |||
623 | teleportLookAt, | 856 | teleportLookAt, |
624 | (uint)TeleportFlags.ViaLocation); | 857 | (uint)TeleportFlags.ViaLocation); |
625 | 858 | ||
626 | ((TestClient)beforeTeleportSp.ControllingClient).CompleteTeleportClientSide(); | 859 | destinationTestClients[0].CompleteMovement(); |
627 | 860 | ||
628 | // Check attachments have made it into sceneB | 861 | // Check attachments have made it into sceneB |
629 | ScenePresence afterTeleportSceneBSp = sceneB.GetScenePresence(ua1.PrincipalID); | 862 | ScenePresence afterTeleportSceneBSp = sceneB.GetScenePresence(ua1.PrincipalID); |
diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs index 7ec2860..bc79944 100644 --- a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs | |||
@@ -40,6 +40,7 @@ using OpenSim.Region.Framework.Scenes; | |||
40 | using OpenSim.Services.Interfaces; | 40 | using OpenSim.Services.Interfaces; |
41 | 41 | ||
42 | using Mono.Addins; | 42 | using Mono.Addins; |
43 | using PermissionMask = OpenSim.Framework.PermissionMask; | ||
43 | 44 | ||
44 | namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | 45 | namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory |
45 | { | 46 | { |
@@ -322,6 +323,9 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
322 | 323 | ||
323 | if (asset != null) | 324 | if (asset != null) |
324 | { | 325 | { |
326 | // Replace an HG ID with the simple asset ID so that we can persist textures for foreign HG avatars | ||
327 | asset.ID = asset.FullID.ToString(); | ||
328 | |||
325 | asset.Temporary = false; | 329 | asset.Temporary = false; |
326 | asset.Local = false; | 330 | asset.Local = false; |
327 | m_scene.AssetService.Store(asset); | 331 | m_scene.AssetService.Store(asset); |
@@ -358,7 +362,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
358 | 362 | ||
359 | public void QueueAppearanceSave(UUID agentid) | 363 | public void QueueAppearanceSave(UUID agentid) |
360 | { | 364 | { |
361 | // m_log.WarnFormat("[AVFACTORY]: Queue appearance save for {0}", agentid); | 365 | // m_log.DebugFormat("[AVFACTORY]: Queueing appearance save for {0}", agentid); |
362 | 366 | ||
363 | // 10000 ticks per millisecond, 1000 milliseconds per second | 367 | // 10000 ticks per millisecond, 1000 milliseconds per second |
364 | long timestamp = DateTime.Now.Ticks + Convert.ToInt64(m_savetime * 1000 * 10000); | 368 | long timestamp = DateTime.Now.Ticks + Convert.ToInt64(m_savetime * 1000 * 10000); |
@@ -655,7 +659,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
655 | return; | 659 | return; |
656 | } | 660 | } |
657 | 661 | ||
658 | // m_log.WarnFormat("[AVFACTORY] avatar {0} save appearance",agentid); | 662 | // m_log.DebugFormat("[AVFACTORY]: Saving appearance for avatar {0}", agentid); |
659 | 663 | ||
660 | // This could take awhile since it needs to pull inventory | 664 | // This could take awhile since it needs to pull inventory |
661 | // We need to do it at the point of save so that there is a sufficient delay for any upload of new body part/shape | 665 | // We need to do it at the point of save so that there is a sufficient delay for any upload of new body part/shape |
@@ -664,6 +668,14 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
664 | // multiple save requests. | 668 | // multiple save requests. |
665 | SetAppearanceAssets(sp.UUID, sp.Appearance); | 669 | SetAppearanceAssets(sp.UUID, sp.Appearance); |
666 | 670 | ||
671 | // List<AvatarAttachment> attachments = sp.Appearance.GetAttachments(); | ||
672 | // foreach (AvatarAttachment att in attachments) | ||
673 | // { | ||
674 | // m_log.DebugFormat( | ||
675 | // "[AVFACTORY]: For {0} saving attachment {1} at point {2}", | ||
676 | // sp.Name, att.ItemID, att.AttachPoint); | ||
677 | // } | ||
678 | |||
667 | m_scene.AvatarService.SetAppearance(agentid, sp.Appearance); | 679 | m_scene.AvatarService.SetAppearance(agentid, sp.Appearance); |
668 | 680 | ||
669 | // Trigger this here because it's the final step in the set/queue/save process for appearance setting. | 681 | // Trigger this here because it's the final step in the set/queue/save process for appearance setting. |
@@ -674,26 +686,70 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
674 | private void SetAppearanceAssets(UUID userID, AvatarAppearance appearance) | 686 | private void SetAppearanceAssets(UUID userID, AvatarAppearance appearance) |
675 | { | 687 | { |
676 | IInventoryService invService = m_scene.InventoryService; | 688 | IInventoryService invService = m_scene.InventoryService; |
677 | 689 | bool resetwearable = false; | |
678 | if (invService.GetRootFolder(userID) != null) | 690 | if (invService.GetRootFolder(userID) != null) |
679 | { | 691 | { |
680 | for (int i = 0; i < AvatarWearable.MAX_WEARABLES; i++) | 692 | for (int i = 0; i < AvatarWearable.MAX_WEARABLES; i++) |
681 | { | 693 | { |
682 | for (int j = 0; j < appearance.Wearables[i].Count; j++) | 694 | for (int j = 0; j < appearance.Wearables[i].Count; j++) |
683 | { | 695 | { |
696 | // Check if the default wearables are not set | ||
684 | if (appearance.Wearables[i][j].ItemID == UUID.Zero) | 697 | if (appearance.Wearables[i][j].ItemID == UUID.Zero) |
698 | { | ||
699 | switch ((WearableType) i) | ||
700 | { | ||
701 | case WearableType.Eyes: | ||
702 | case WearableType.Hair: | ||
703 | case WearableType.Shape: | ||
704 | case WearableType.Skin: | ||
705 | //case WearableType.Underpants: | ||
706 | TryAndRepairBrokenWearable((WearableType)i, invService, userID, appearance); | ||
707 | resetwearable = true; | ||
708 | m_log.Warn("[AVFACTORY]: UUID.Zero Wearables, passing fake values."); | ||
709 | resetwearable = true; | ||
710 | break; | ||
711 | |||
712 | } | ||
685 | continue; | 713 | continue; |
714 | } | ||
686 | 715 | ||
687 | // Ignore ruth's assets | 716 | // Ignore ruth's assets except for the body parts! missing body parts fail avatar appearance on V1 |
688 | if (appearance.Wearables[i][j].ItemID == AvatarWearable.DefaultWearables[i][0].ItemID) | 717 | if (appearance.Wearables[i][j].ItemID == AvatarWearable.DefaultWearables[i][0].ItemID) |
718 | { | ||
719 | switch ((WearableType)i) | ||
720 | { | ||
721 | case WearableType.Eyes: | ||
722 | case WearableType.Hair: | ||
723 | case WearableType.Shape: | ||
724 | case WearableType.Skin: | ||
725 | //case WearableType.Underpants: | ||
726 | TryAndRepairBrokenWearable((WearableType)i, invService, userID, appearance); | ||
727 | |||
728 | m_log.WarnFormat("[AVFACTORY]: {0} Default Wearables, passing existing values.", (WearableType)i); | ||
729 | resetwearable = true; | ||
730 | break; | ||
731 | |||
732 | } | ||
689 | continue; | 733 | continue; |
690 | 734 | } | |
735 | |||
691 | InventoryItemBase baseItem = new InventoryItemBase(appearance.Wearables[i][j].ItemID, userID); | 736 | InventoryItemBase baseItem = new InventoryItemBase(appearance.Wearables[i][j].ItemID, userID); |
692 | baseItem = invService.GetItem(baseItem); | 737 | baseItem = invService.GetItem(baseItem); |
693 | 738 | ||
694 | if (baseItem != null) | 739 | if (baseItem != null) |
695 | { | 740 | { |
696 | appearance.Wearables[i].Add(appearance.Wearables[i][j].ItemID, baseItem.AssetID); | 741 | appearance.Wearables[i].Add(appearance.Wearables[i][j].ItemID, baseItem.AssetID); |
742 | int unmodifiedWearableIndexForClosure = i; | ||
743 | m_scene.AssetService.Get(baseItem.AssetID.ToString(), this, | ||
744 | delegate(string x, object y, AssetBase z) | ||
745 | { | ||
746 | if (z == null) | ||
747 | { | ||
748 | TryAndRepairBrokenWearable( | ||
749 | (WearableType)unmodifiedWearableIndexForClosure, invService, | ||
750 | userID, appearance); | ||
751 | } | ||
752 | }); | ||
697 | } | 753 | } |
698 | else | 754 | else |
699 | { | 755 | { |
@@ -701,17 +757,236 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
701 | "[AVFACTORY]: Can't find inventory item {0} for {1}, setting to default", | 757 | "[AVFACTORY]: Can't find inventory item {0} for {1}, setting to default", |
702 | appearance.Wearables[i][j].ItemID, (WearableType)i); | 758 | appearance.Wearables[i][j].ItemID, (WearableType)i); |
703 | 759 | ||
704 | appearance.Wearables[i].RemoveItem(appearance.Wearables[i][j].ItemID); | 760 | TryAndRepairBrokenWearable((WearableType)i, invService, userID, appearance); |
761 | resetwearable = true; | ||
762 | |||
705 | } | 763 | } |
706 | } | 764 | } |
707 | } | 765 | } |
766 | |||
767 | // I don't know why we have to test for this again... but the above switches do not capture these scenarios for some reason.... | ||
768 | if (appearance.Wearables[(int) WearableType.Eyes] == null) | ||
769 | { | ||
770 | m_log.WarnFormat("[AVFACTORY]: {0} Eyes are Null, passing existing values.", (WearableType.Eyes)); | ||
771 | |||
772 | TryAndRepairBrokenWearable(WearableType.Eyes, invService, userID, appearance); | ||
773 | resetwearable = true; | ||
774 | } | ||
775 | else | ||
776 | { | ||
777 | if (appearance.Wearables[(int) WearableType.Eyes][0].ItemID == UUID.Zero) | ||
778 | { | ||
779 | m_log.WarnFormat("[AVFACTORY]: Eyes are UUID.Zero are broken, {0} {1}", | ||
780 | appearance.Wearables[(int) WearableType.Eyes][0].ItemID, | ||
781 | appearance.Wearables[(int) WearableType.Eyes][0].AssetID); | ||
782 | TryAndRepairBrokenWearable(WearableType.Eyes, invService, userID, appearance); | ||
783 | resetwearable = true; | ||
784 | |||
785 | } | ||
786 | |||
787 | } | ||
788 | // I don't know why we have to test for this again... but the above switches do not capture these scenarios for some reason.... | ||
789 | if (appearance.Wearables[(int)WearableType.Shape] == null) | ||
790 | { | ||
791 | m_log.WarnFormat("[AVFACTORY]: {0} shape is Null, passing existing values.", (WearableType.Shape)); | ||
792 | |||
793 | TryAndRepairBrokenWearable(WearableType.Shape, invService, userID, appearance); | ||
794 | resetwearable = true; | ||
795 | } | ||
796 | else | ||
797 | { | ||
798 | if (appearance.Wearables[(int)WearableType.Shape][0].ItemID == UUID.Zero) | ||
799 | { | ||
800 | m_log.WarnFormat("[AVFACTORY]: Shape is UUID.Zero and broken, {0} {1}", | ||
801 | appearance.Wearables[(int)WearableType.Shape][0].ItemID, | ||
802 | appearance.Wearables[(int)WearableType.Shape][0].AssetID); | ||
803 | TryAndRepairBrokenWearable(WearableType.Shape, invService, userID, appearance); | ||
804 | resetwearable = true; | ||
805 | |||
806 | } | ||
807 | |||
808 | } | ||
809 | // I don't know why we have to test for this again... but the above switches do not capture these scenarios for some reason.... | ||
810 | if (appearance.Wearables[(int)WearableType.Hair] == null) | ||
811 | { | ||
812 | m_log.WarnFormat("[AVFACTORY]: {0} Hair is Null, passing existing values.", (WearableType.Hair)); | ||
813 | |||
814 | TryAndRepairBrokenWearable(WearableType.Hair, invService, userID, appearance); | ||
815 | resetwearable = true; | ||
816 | } | ||
817 | else | ||
818 | { | ||
819 | if (appearance.Wearables[(int)WearableType.Hair][0].ItemID == UUID.Zero) | ||
820 | { | ||
821 | m_log.WarnFormat("[AVFACTORY]: Hair is UUID.Zero and broken, {0} {1}", | ||
822 | appearance.Wearables[(int)WearableType.Hair][0].ItemID, | ||
823 | appearance.Wearables[(int)WearableType.Hair][0].AssetID); | ||
824 | TryAndRepairBrokenWearable(WearableType.Hair, invService, userID, appearance); | ||
825 | resetwearable = true; | ||
826 | |||
827 | } | ||
828 | |||
829 | } | ||
830 | // I don't know why we have to test for this again... but the above switches do not capture these scenarios for some reason.... | ||
831 | if (appearance.Wearables[(int)WearableType.Skin] == null) | ||
832 | { | ||
833 | m_log.WarnFormat("[AVFACTORY]: {0} Skin is Null, passing existing values.", (WearableType.Skin)); | ||
834 | |||
835 | TryAndRepairBrokenWearable(WearableType.Skin, invService, userID, appearance); | ||
836 | resetwearable = true; | ||
837 | } | ||
838 | else | ||
839 | { | ||
840 | if (appearance.Wearables[(int)WearableType.Skin][0].ItemID == UUID.Zero) | ||
841 | { | ||
842 | m_log.WarnFormat("[AVFACTORY]: Skin is UUID.Zero and broken, {0} {1}", | ||
843 | appearance.Wearables[(int)WearableType.Skin][0].ItemID, | ||
844 | appearance.Wearables[(int)WearableType.Skin][0].AssetID); | ||
845 | TryAndRepairBrokenWearable(WearableType.Skin, invService, userID, appearance); | ||
846 | resetwearable = true; | ||
847 | |||
848 | } | ||
849 | |||
850 | } | ||
851 | if (resetwearable) | ||
852 | { | ||
853 | ScenePresence presence = null; | ||
854 | if (m_scene.TryGetScenePresence(userID, out presence)) | ||
855 | { | ||
856 | presence.ControllingClient.SendWearables(presence.Appearance.Wearables, | ||
857 | presence.Appearance.Serial++); | ||
858 | } | ||
859 | } | ||
860 | |||
708 | } | 861 | } |
709 | else | 862 | else |
710 | { | 863 | { |
711 | m_log.WarnFormat("[AVFACTORY]: user {0} has no inventory, appearance isn't going to work", userID); | 864 | m_log.WarnFormat("[AVFACTORY]: user {0} has no inventory, appearance isn't going to work", userID); |
712 | } | 865 | } |
713 | } | 866 | } |
867 | private void TryAndRepairBrokenWearable(WearableType type, IInventoryService invService, UUID userID,AvatarAppearance appearance) | ||
868 | { | ||
869 | UUID defaultwearable = GetDefaultItem(type); | ||
870 | if (defaultwearable != UUID.Zero) | ||
871 | { | ||
872 | UUID newInvItem = UUID.Random(); | ||
873 | InventoryItemBase itembase = new InventoryItemBase(newInvItem, userID) | ||
874 | { | ||
875 | AssetID = | ||
876 | defaultwearable, | ||
877 | AssetType | ||
878 | = | ||
879 | (int) | ||
880 | AssetType | ||
881 | .Bodypart, | ||
882 | CreatorId | ||
883 | = | ||
884 | userID | ||
885 | .ToString | ||
886 | (), | ||
887 | //InvType = (int)InventoryType.Wearable, | ||
888 | |||
889 | Description | ||
890 | = | ||
891 | "Failed Wearable Replacement", | ||
892 | Folder = | ||
893 | invService | ||
894 | .GetFolderForType | ||
895 | (userID, | ||
896 | AssetType | ||
897 | .Bodypart) | ||
898 | .ID, | ||
899 | Flags = (uint) type, | ||
900 | Name = Enum.GetName(typeof (WearableType), type), | ||
901 | BasePermissions = (uint) PermissionMask.Copy, | ||
902 | CurrentPermissions = (uint) PermissionMask.Copy, | ||
903 | EveryOnePermissions = (uint) PermissionMask.Copy, | ||
904 | GroupPermissions = (uint) PermissionMask.Copy, | ||
905 | NextPermissions = (uint) PermissionMask.Copy | ||
906 | }; | ||
907 | invService.AddItem(itembase); | ||
908 | UUID LinkInvItem = UUID.Random(); | ||
909 | itembase = new InventoryItemBase(LinkInvItem, userID) | ||
910 | { | ||
911 | AssetID = | ||
912 | newInvItem, | ||
913 | AssetType | ||
914 | = | ||
915 | (int) | ||
916 | AssetType | ||
917 | .Link, | ||
918 | CreatorId | ||
919 | = | ||
920 | userID | ||
921 | .ToString | ||
922 | (), | ||
923 | InvType = (int) InventoryType.Wearable, | ||
924 | |||
925 | Description | ||
926 | = | ||
927 | "Failed Wearable Replacement", | ||
928 | Folder = | ||
929 | invService | ||
930 | .GetFolderForType | ||
931 | (userID, | ||
932 | AssetType | ||
933 | .CurrentOutfitFolder) | ||
934 | .ID, | ||
935 | Flags = (uint) type, | ||
936 | Name = Enum.GetName(typeof (WearableType), type), | ||
937 | BasePermissions = (uint) PermissionMask.Copy, | ||
938 | CurrentPermissions = (uint) PermissionMask.Copy, | ||
939 | EveryOnePermissions = (uint) PermissionMask.Copy, | ||
940 | GroupPermissions = (uint) PermissionMask.Copy, | ||
941 | NextPermissions = (uint) PermissionMask.Copy | ||
942 | }; | ||
943 | invService.AddItem(itembase); | ||
944 | appearance.Wearables[(int)type] = new AvatarWearable(newInvItem, GetDefaultItem(type)); | ||
945 | ScenePresence presence = null; | ||
946 | if (m_scene.TryGetScenePresence(userID, out presence)) | ||
947 | { | ||
948 | m_scene.SendInventoryUpdate(presence.ControllingClient, | ||
949 | invService.GetFolderForType(userID, | ||
950 | AssetType | ||
951 | .CurrentOutfitFolder), | ||
952 | false, true); | ||
953 | } | ||
954 | } | ||
955 | } | ||
956 | private UUID GetDefaultItem(WearableType wearable) | ||
957 | { | ||
958 | // These are ruth | ||
959 | UUID ret = UUID.Zero; | ||
960 | switch (wearable) | ||
961 | { | ||
962 | case WearableType.Eyes: | ||
963 | ret = new UUID("4bb6fa4d-1cd2-498a-a84c-95c1a0e745a7"); | ||
964 | break; | ||
965 | case WearableType.Hair: | ||
966 | ret = new UUID("d342e6c0-b9d2-11dc-95ff-0800200c9a66"); | ||
967 | break; | ||
968 | case WearableType.Pants: | ||
969 | ret = new UUID("00000000-38f9-1111-024e-222222111120"); | ||
970 | break; | ||
971 | case WearableType.Shape: | ||
972 | ret = new UUID("66c41e39-38f9-f75a-024e-585989bfab73"); | ||
973 | break; | ||
974 | case WearableType.Shirt: | ||
975 | ret = new UUID("00000000-38f9-1111-024e-222222111110"); | ||
976 | break; | ||
977 | case WearableType.Skin: | ||
978 | ret = new UUID("77c41e39-38f9-f75a-024e-585989bbabbb"); | ||
979 | break; | ||
980 | case WearableType.Undershirt: | ||
981 | ret = new UUID("16499ebb-3208-ec27-2def-481881728f47"); | ||
982 | break; | ||
983 | case WearableType.Underpants: | ||
984 | ret = new UUID("4ac2e9c7-3671-d229-316a-67717730841d"); | ||
985 | break; | ||
986 | } | ||
714 | 987 | ||
988 | return ret; | ||
989 | } | ||
715 | #endregion | 990 | #endregion |
716 | 991 | ||
717 | #region Client Event Handlers | 992 | #region Client Event Handlers |
@@ -824,7 +1099,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
824 | } | 1099 | } |
825 | 1100 | ||
826 | bool bakedTextureValid = m_scene.AvatarFactory.ValidateBakedTextureCache(sp); | 1101 | bool bakedTextureValid = m_scene.AvatarFactory.ValidateBakedTextureCache(sp); |
827 | outputAction("{0} baked appearance texture is {1}", sp.Name, bakedTextureValid ? "OK" : "corrupt"); | 1102 | outputAction("{0} baked appearance texture is {1}", sp.Name, bakedTextureValid ? "OK" : "incomplete"); |
828 | } | 1103 | } |
829 | } | 1104 | } |
830 | } | 1105 | } |
diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs index e21547c..f090e15 100644 --- a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs | |||
@@ -39,7 +39,7 @@ using OpenSim.Tests.Common.Mock; | |||
39 | namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | 39 | namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory |
40 | { | 40 | { |
41 | [TestFixture] | 41 | [TestFixture] |
42 | public class AvatarFactoryModuleTests | 42 | public class AvatarFactoryModuleTests : OpenSimTestCase |
43 | { | 43 | { |
44 | /// <summary> | 44 | /// <summary> |
45 | /// Only partial right now since we don't yet test that it's ended up in the avatar appearance service. | 45 | /// Only partial right now since we don't yet test that it's ended up in the avatar appearance service. |
diff --git a/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs b/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs index 4c3f1cc..174642d 100644 --- a/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs | |||
@@ -256,7 +256,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat | |||
256 | // If camera is moved into client, then camera position can be used | 256 | // If camera is moved into client, then camera position can be used |
257 | // MT: No, it can't, as chat is heard from the avatar position, not | 257 | // MT: No, it can't, as chat is heard from the avatar position, not |
258 | // the camera position. | 258 | // the camera position. |
259 | s.ForEachRootScenePresence( | 259 | s.ForEachScenePresence( |
260 | delegate(ScenePresence presence) | 260 | delegate(ScenePresence presence) |
261 | { | 261 | { |
262 | if (destination != UUID.Zero && presence.UUID != destination) | 262 | if (destination != UUID.Zero && presence.UUID != destination) |
diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/CallingCardModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/CallingCardModule.cs index 5ec0ea9..b44a5c9 100644 --- a/OpenSim/Region/CoreModules/Avatar/Friends/CallingCardModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Friends/CallingCardModule.cs | |||
@@ -36,6 +36,7 @@ using OpenSim.Region.Framework.Interfaces; | |||
36 | using OpenSim.Region.Framework.Scenes; | 36 | using OpenSim.Region.Framework.Scenes; |
37 | using OpenSim.Services.Interfaces; | 37 | using OpenSim.Services.Interfaces; |
38 | using Mono.Addins; | 38 | using Mono.Addins; |
39 | using PermissionMask = OpenSim.Framework.PermissionMask; | ||
39 | 40 | ||
40 | namespace OpenSim.Region.CoreModules.Avatar.Friends | 41 | namespace OpenSim.Region.CoreModules.Avatar.Friends |
41 | { | 42 | { |
diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/Tests/FriendModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Friends/Tests/FriendModuleTests.cs index 7a197f7..961117e 100644 --- a/OpenSim/Region/CoreModules/Avatar/Friends/Tests/FriendModuleTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Friends/Tests/FriendModuleTests.cs | |||
@@ -40,7 +40,7 @@ using OpenSim.Tests.Common.Mock; | |||
40 | namespace OpenSim.Region.CoreModules.Avatar.Friends.Tests | 40 | namespace OpenSim.Region.CoreModules.Avatar.Friends.Tests |
41 | { | 41 | { |
42 | [TestFixture] | 42 | [TestFixture] |
43 | public class FriendsModuleTests | 43 | public class FriendsModuleTests : OpenSimTestCase |
44 | { | 44 | { |
45 | private FriendsModule m_fm; | 45 | private FriendsModule m_fm; |
46 | private TestScene m_scene; | 46 | private TestScene m_scene; |
diff --git a/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs b/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs index 9fa9be1..fa8c3f3 100644 --- a/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs | |||
@@ -67,9 +67,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods | |||
67 | protected Scene m_scene; | 67 | protected Scene m_scene; |
68 | protected IDialogModule m_dialogModule; | 68 | protected IDialogModule m_dialogModule; |
69 | 69 | ||
70 | protected Dictionary<UUID, string> m_capsDict = | ||
71 | new Dictionary<UUID, string>(); | ||
72 | |||
73 | protected IDialogModule DialogModule | 70 | protected IDialogModule DialogModule |
74 | { | 71 | { |
75 | get | 72 | get |
@@ -91,7 +88,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods | |||
91 | m_scene.RegisterModuleInterface<IGodsModule>(this); | 88 | m_scene.RegisterModuleInterface<IGodsModule>(this); |
92 | m_scene.EventManager.OnNewClient += SubscribeToClientEvents; | 89 | m_scene.EventManager.OnNewClient += SubscribeToClientEvents; |
93 | m_scene.EventManager.OnRegisterCaps += OnRegisterCaps; | 90 | m_scene.EventManager.OnRegisterCaps += OnRegisterCaps; |
94 | m_scene.EventManager.OnClientClosed += OnClientClosed; | ||
95 | scene.EventManager.OnIncomingInstantMessage += | 91 | scene.EventManager.OnIncomingInstantMessage += |
96 | OnIncomingInstantMessage; | 92 | OnIncomingInstantMessage; |
97 | } | 93 | } |
@@ -127,15 +123,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods | |||
127 | client.OnRequestGodlikePowers -= RequestGodlikePowers; | 123 | client.OnRequestGodlikePowers -= RequestGodlikePowers; |
128 | } | 124 | } |
129 | 125 | ||
130 | private void OnClientClosed(UUID agentID, Scene scene) | ||
131 | { | ||
132 | m_capsDict.Remove(agentID); | ||
133 | } | ||
134 | |||
135 | private void OnRegisterCaps(UUID agentID, Caps caps) | 126 | private void OnRegisterCaps(UUID agentID, Caps caps) |
136 | { | 127 | { |
137 | string uri = "/CAPS/" + UUID.Random(); | 128 | string uri = "/CAPS/" + UUID.Random(); |
138 | m_capsDict[agentID] = uri; | ||
139 | 129 | ||
140 | caps.RegisterHandler("UntrustedSimulatorMessage", | 130 | caps.RegisterHandler("UntrustedSimulatorMessage", |
141 | new RestStreamHandler("POST", uri, | 131 | new RestStreamHandler("POST", uri, |
@@ -288,8 +278,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods | |||
288 | if (sp.IsChildAgent) | 278 | if (sp.IsChildAgent) |
289 | return; | 279 | return; |
290 | sp.ControllingClient.Kick(reason); | 280 | sp.ControllingClient.Kick(reason); |
291 | sp.MakeChildAgent(); | 281 | sp.Scene.IncomingCloseAgent(sp.UUID, true); |
292 | sp.ControllingClient.Close(); | ||
293 | } | 282 | } |
294 | 283 | ||
295 | private void OnIncomingInstantMessage(GridInstantMessage msg) | 284 | private void OnIncomingInstantMessage(GridInstantMessage msg) |
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs index cc266df..1627f6c 100644 --- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs | |||
@@ -153,7 +153,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | |||
153 | if (sp != null && !sp.IsChildAgent) | 153 | if (sp != null && !sp.IsChildAgent) |
154 | { | 154 | { |
155 | // Local message | 155 | // Local message |
156 | m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to root agent {0} {1}", sp.Name, toAgentID); | 156 | // m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to root agent {0} {1}", sp.Name, toAgentID); |
157 | 157 | ||
158 | sp.ControllingClient.SendInstantMessage(im); | 158 | sp.ControllingClient.SendInstantMessage(im); |
159 | 159 | ||
@@ -166,14 +166,14 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | |||
166 | // try child avatar second | 166 | // try child avatar second |
167 | foreach (Scene scene in m_Scenes) | 167 | foreach (Scene scene in m_Scenes) |
168 | { | 168 | { |
169 | //m_log.DebugFormat( | 169 | // m_log.DebugFormat( |
170 | // "[INSTANT MESSAGE]: Looking for child of {0} in {1}", toAgentID, scene.RegionInfo.RegionName); | 170 | // "[INSTANT MESSAGE]: Looking for child of {0} in {1}", toAgentID, scene.RegionInfo.RegionName); |
171 | 171 | ||
172 | ScenePresence sp = scene.GetScenePresence(toAgentID); | 172 | ScenePresence sp = scene.GetScenePresence(toAgentID); |
173 | if (sp != null) | 173 | if (sp != null) |
174 | { | 174 | { |
175 | // Local message | 175 | // Local message |
176 | m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to child agent {0} {1}", sp.Name, toAgentID); | 176 | // m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to child agent {0} {1}", sp.Name, toAgentID); |
177 | 177 | ||
178 | sp.ControllingClient.SendInstantMessage(im); | 178 | sp.ControllingClient.SendInstantMessage(im); |
179 | 179 | ||
@@ -183,7 +183,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | |||
183 | } | 183 | } |
184 | } | 184 | } |
185 | 185 | ||
186 | m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to {0} via XMLRPC", im.toAgentID); | 186 | // m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to {0} via XMLRPC", im.toAgentID); |
187 | 187 | ||
188 | SendGridInstantMessageViaXMLRPC(im, result); | 188 | SendGridInstantMessageViaXMLRPC(im, result); |
189 | } | 189 | } |
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs index 3a44cc5..2d46276 100644 --- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs | |||
@@ -189,20 +189,24 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | |||
189 | { | 189 | { |
190 | foreach (GridInstantMessage im in msglist) | 190 | foreach (GridInstantMessage im in msglist) |
191 | { | 191 | { |
192 | // client.SendInstantMessage(im); | 192 | if (im.dialog == (byte)InstantMessageDialog.InventoryOffered) |
193 | 193 | // send it directly or else the item will be given twice | |
194 | // Send through scene event manager so all modules get a chance | 194 | client.SendInstantMessage(im); |
195 | // to look at this message before it gets delivered. | 195 | else |
196 | // | 196 | { |
197 | // Needed for proper state management for stored group | 197 | // Send through scene event manager so all modules get a chance |
198 | // invitations | 198 | // to look at this message before it gets delivered. |
199 | // | 199 | // |
200 | 200 | // Needed for proper state management for stored group | |
201 | im.offline = 1; | 201 | // invitations |
202 | 202 | // | |
203 | Scene s = FindScene(client.AgentId); | 203 | |
204 | if (s != null) | 204 | im.offline = 1; |
205 | s.EventManager.TriggerIncomingInstantMessage(im); | 205 | |
206 | Scene s = FindScene(client.AgentId); | ||
207 | if (s != null) | ||
208 | s.EventManager.TriggerIncomingInstantMessage(im); | ||
209 | } | ||
206 | } | 210 | } |
207 | } | 211 | } |
208 | } | 212 | } |
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs index dc2b0e0..659b178 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs | |||
@@ -161,7 +161,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver | |||
161 | string filePath = "ERROR"; | 161 | string filePath = "ERROR"; |
162 | 162 | ||
163 | List<InventoryFolderBase> folderCandidates | 163 | List<InventoryFolderBase> folderCandidates |
164 | = InventoryArchiveUtils.FindFolderByPath( | 164 | = InventoryArchiveUtils.FindFoldersByPath( |
165 | m_scene.InventoryService, m_userInfo.PrincipalID, m_invPath); | 165 | m_scene.InventoryService, m_userInfo.PrincipalID, m_invPath); |
166 | 166 | ||
167 | if (folderCandidates.Count == 0) | 167 | if (folderCandidates.Count == 0) |
@@ -296,7 +296,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver | |||
296 | // iar name and try to find that instead. | 296 | // iar name and try to find that instead. |
297 | string plainPath = ArchiveConstants.ExtractPlainPathFromIarPath(archivePath); | 297 | string plainPath = ArchiveConstants.ExtractPlainPathFromIarPath(archivePath); |
298 | List<InventoryFolderBase> folderCandidates | 298 | List<InventoryFolderBase> folderCandidates |
299 | = InventoryArchiveUtils.FindFolderByPath( | 299 | = InventoryArchiveUtils.FindFoldersByPath( |
300 | m_scene.InventoryService, m_userInfo.PrincipalID, plainPath); | 300 | m_scene.InventoryService, m_userInfo.PrincipalID, plainPath); |
301 | 301 | ||
302 | if (folderCandidates.Count != 0) | 302 | if (folderCandidates.Count != 0) |
@@ -487,6 +487,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver | |||
487 | { | 487 | { |
488 | // m_log.DebugFormat( | 488 | // m_log.DebugFormat( |
489 | // "[INVENTORY ARCHIVER]: Loaded coalescence {0} has {1} objects", assetId, coa.Count); | 489 | // "[INVENTORY ARCHIVER]: Loaded coalescence {0} has {1} objects", assetId, coa.Count); |
490 | |||
491 | if (coa.Objects.Count == 0) | ||
492 | { | ||
493 | m_log.WarnFormat( | ||
494 | "[INVENTORY ARCHIVE READ REQUEST]: Aborting load of coalesced object from asset {0} as it has zero loaded components", | ||
495 | assetId); | ||
496 | return false; | ||
497 | } | ||
490 | 498 | ||
491 | sceneObjects.AddRange(coa.Objects); | 499 | sceneObjects.AddRange(coa.Objects); |
492 | } | 500 | } |
@@ -495,7 +503,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver | |||
495 | SceneObjectGroup deserializedObject = SceneObjectSerializer.FromOriginalXmlFormat(xmlData); | 503 | SceneObjectGroup deserializedObject = SceneObjectSerializer.FromOriginalXmlFormat(xmlData); |
496 | 504 | ||
497 | if (deserializedObject != null) | 505 | if (deserializedObject != null) |
506 | { | ||
498 | sceneObjects.Add(deserializedObject); | 507 | sceneObjects.Add(deserializedObject); |
508 | } | ||
509 | else | ||
510 | { | ||
511 | m_log.WarnFormat( | ||
512 | "[INVENTORY ARCHIVE READ REQUEST]: Aborting load of object from asset {0} as deserialization failed", | ||
513 | assetId); | ||
514 | |||
515 | return false; | ||
516 | } | ||
499 | } | 517 | } |
500 | 518 | ||
501 | foreach (SceneObjectGroup sog in sceneObjects) | 519 | foreach (SceneObjectGroup sog in sceneObjects) |
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveUtils.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveUtils.cs index 0d90a15..dbaf2aa 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveUtils.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveUtils.cs | |||
@@ -52,13 +52,82 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver | |||
52 | /// <summary> | 52 | /// <summary> |
53 | /// Find a folder given a PATH_DELIMITER delimited path starting from a user's root folder | 53 | /// Find a folder given a PATH_DELIMITER delimited path starting from a user's root folder |
54 | /// </summary> | 54 | /// </summary> |
55 | /// <remarks> | ||
56 | /// This method does not handle paths that contain multiple delimitors | ||
57 | /// | ||
58 | /// FIXME: We have no way of distinguishing folders with the same path | ||
55 | /// | 59 | /// |
60 | /// FIXME: Delimitors which occur in names themselves are not currently escapable. | ||
61 | /// </remarks> | ||
62 | /// <param name="inventoryService"> | ||
63 | /// Inventory service to query | ||
64 | /// </param> | ||
65 | /// <param name="userId"> | ||
66 | /// User id to search | ||
67 | /// </param> | ||
68 | /// <param name="path"> | ||
69 | /// The path to the required folder. | ||
70 | /// It this is empty or consists only of the PATH_DELIMTER then this folder itself is returned. | ||
71 | /// </param> | ||
72 | /// <returns>The folder found. Please note that if there are multiple folders with the same name then an | ||
73 | /// unspecified one will be returned. If no such folder eixsts then null is returned</returns> | ||
74 | public static InventoryFolderBase FindFolderByPath( | ||
75 | IInventoryService inventoryService, UUID userId, string path) | ||
76 | { | ||
77 | List<InventoryFolderBase> folders = FindFoldersByPath(inventoryService, userId, path); | ||
78 | |||
79 | if (folders.Count == 0) | ||
80 | return null; | ||
81 | else | ||
82 | return folders[0]; | ||
83 | } | ||
84 | |||
85 | /// <summary> | ||
86 | /// Find a folder given a PATH_DELIMITER delimited path starting from a given folder | ||
87 | /// </summary> | ||
88 | /// <remarks> | ||
56 | /// This method does not handle paths that contain multiple delimitors | 89 | /// This method does not handle paths that contain multiple delimitors |
57 | /// | 90 | /// |
58 | /// FIXME: We have no way of distinguishing folders with the same path | 91 | /// FIXME: We have no way of distinguishing folders with the same path |
59 | /// | 92 | /// |
60 | /// FIXME: Delimitors which occur in names themselves are not currently escapable. | 93 | /// FIXME: Delimitors which occur in names themselves are not currently escapable. |
94 | /// </remarks> | ||
95 | /// <param name="inventoryService"> | ||
96 | /// Inventory service to query | ||
97 | /// </param> | ||
98 | /// <param name="startFolder"> | ||
99 | /// The folder from which the path starts | ||
100 | /// </param> | ||
101 | /// <param name="path"> | ||
102 | /// The path to the required folder. | ||
103 | /// It this is empty or consists only of the PATH_DELIMTER then this folder itself is returned. | ||
104 | /// </param> | ||
105 | /// <returns>The folder found. Please note that if there are multiple folders with the same name then an | ||
106 | /// unspecified one will be returned. If no such folder eixsts then null is returned</returns> | ||
107 | public static InventoryFolderBase FindFolderByPath( | ||
108 | IInventoryService inventoryService, InventoryFolderBase startFolder, string path) | ||
109 | { | ||
110 | if (null == startFolder) | ||
111 | return null; | ||
112 | |||
113 | List<InventoryFolderBase> folders = FindFoldersByPath(inventoryService, startFolder, path); | ||
114 | |||
115 | if (folders.Count == 0) | ||
116 | return null; | ||
117 | else | ||
118 | return folders[0]; | ||
119 | } | ||
120 | |||
121 | /// <summary> | ||
122 | /// Find a set of folders given a PATH_DELIMITER delimited path starting from a user's root folder | ||
123 | /// </summary> | ||
124 | /// <remarks> | ||
125 | /// This method does not handle paths that contain multiple delimitors | ||
126 | /// | ||
127 | /// FIXME: We have no way of distinguishing folders with the same path | ||
61 | /// | 128 | /// |
129 | /// FIXME: Delimitors which occur in names themselves are not currently escapable. | ||
130 | /// </remarks> | ||
62 | /// <param name="inventoryService"> | 131 | /// <param name="inventoryService"> |
63 | /// Inventory service to query | 132 | /// Inventory service to query |
64 | /// </param> | 133 | /// </param> |
@@ -70,7 +139,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver | |||
70 | /// It this is empty or consists only of the PATH_DELIMTER then this folder itself is returned. | 139 | /// It this is empty or consists only of the PATH_DELIMTER then this folder itself is returned. |
71 | /// </param> | 140 | /// </param> |
72 | /// <returns>An empty list if the folder is not found, otherwise a list of all folders that match the name</returns> | 141 | /// <returns>An empty list if the folder is not found, otherwise a list of all folders that match the name</returns> |
73 | public static List<InventoryFolderBase> FindFolderByPath( | 142 | public static List<InventoryFolderBase> FindFoldersByPath( |
74 | IInventoryService inventoryService, UUID userId, string path) | 143 | IInventoryService inventoryService, UUID userId, string path) |
75 | { | 144 | { |
76 | InventoryFolderBase rootFolder = inventoryService.GetRootFolder(userId); | 145 | InventoryFolderBase rootFolder = inventoryService.GetRootFolder(userId); |
@@ -78,19 +147,19 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver | |||
78 | if (null == rootFolder) | 147 | if (null == rootFolder) |
79 | return new List<InventoryFolderBase>(); | 148 | return new List<InventoryFolderBase>(); |
80 | 149 | ||
81 | return FindFolderByPath(inventoryService, rootFolder, path); | 150 | return FindFoldersByPath(inventoryService, rootFolder, path); |
82 | } | 151 | } |
83 | 152 | ||
84 | /// <summary> | 153 | /// <summary> |
85 | /// Find a folder given a PATH_DELIMITER delimited path starting from this folder | 154 | /// Find a set of folders given a PATH_DELIMITER delimited path starting from this folder |
86 | /// </summary> | 155 | /// </summary> |
87 | /// | 156 | /// <remarks> |
88 | /// This method does not handle paths that contain multiple delimitors | 157 | /// This method does not handle paths that contain multiple delimitors |
89 | /// | 158 | /// |
90 | /// FIXME: We have no way of distinguishing folders with the same path. | 159 | /// FIXME: We have no way of distinguishing folders with the same path. |
91 | /// | 160 | /// |
92 | /// FIXME: Delimitors which occur in names themselves are not currently escapable. | 161 | /// FIXME: Delimitors which occur in names themselves are not currently escapable. |
93 | /// | 162 | /// </remarks> |
94 | /// <param name="inventoryService"> | 163 | /// <param name="inventoryService"> |
95 | /// Inventory service to query | 164 | /// Inventory service to query |
96 | /// </param> | 165 | /// </param> |
@@ -102,7 +171,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver | |||
102 | /// It this is empty or consists only of the PATH_DELIMTER then this folder itself is returned. | 171 | /// It this is empty or consists only of the PATH_DELIMTER then this folder itself is returned. |
103 | /// </param> | 172 | /// </param> |
104 | /// <returns>An empty list if the folder is not found, otherwise a list of all folders that match the name</returns> | 173 | /// <returns>An empty list if the folder is not found, otherwise a list of all folders that match the name</returns> |
105 | public static List<InventoryFolderBase> FindFolderByPath( | 174 | public static List<InventoryFolderBase> FindFoldersByPath( |
106 | IInventoryService inventoryService, InventoryFolderBase startFolder, string path) | 175 | IInventoryService inventoryService, InventoryFolderBase startFolder, string path) |
107 | { | 176 | { |
108 | List<InventoryFolderBase> foundFolders = new List<InventoryFolderBase>(); | 177 | List<InventoryFolderBase> foundFolders = new List<InventoryFolderBase>(); |
@@ -133,12 +202,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver | |||
133 | 202 | ||
134 | InventoryCollection contents = inventoryService.GetFolderContent(startFolder.Owner, startFolder.ID); | 203 | InventoryCollection contents = inventoryService.GetFolderContent(startFolder.Owner, startFolder.ID); |
135 | 204 | ||
205 | // m_log.DebugFormat( | ||
206 | // "Found {0} folders in {1} for {2}", contents.Folders.Count, startFolder.Name, startFolder.Owner); | ||
207 | |||
136 | foreach (InventoryFolderBase folder in contents.Folders) | 208 | foreach (InventoryFolderBase folder in contents.Folders) |
137 | { | 209 | { |
138 | if (folder.Name == components[0]) | 210 | if (folder.Name == components[0]) |
139 | { | 211 | { |
140 | if (components.Length > 1) | 212 | if (components.Length > 1) |
141 | foundFolders.AddRange(FindFolderByPath(inventoryService, folder, components[1])); | 213 | foundFolders.AddRange(FindFoldersByPath(inventoryService, folder, components[1])); |
142 | else | 214 | else |
143 | foundFolders.Add(folder); | 215 | foundFolders.Add(folder); |
144 | } | 216 | } |
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs index d0e88f6..4ec8ae7 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs | |||
@@ -124,7 +124,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver | |||
124 | SaveAssets = true; | 124 | SaveAssets = true; |
125 | } | 125 | } |
126 | 126 | ||
127 | protected void ReceivedAllAssets(ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids) | 127 | protected void ReceivedAllAssets(ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids, bool timedOut) |
128 | { | 128 | { |
129 | Exception reportedException = null; | 129 | Exception reportedException = null; |
130 | bool succeeded = true; | 130 | bool succeeded = true; |
@@ -143,6 +143,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver | |||
143 | m_saveStream.Close(); | 143 | m_saveStream.Close(); |
144 | } | 144 | } |
145 | 145 | ||
146 | if (timedOut) | ||
147 | { | ||
148 | succeeded = false; | ||
149 | reportedException = new Exception("Loading assets timed out"); | ||
150 | } | ||
151 | |||
146 | m_module.TriggerInventoryArchiveSaved( | 152 | m_module.TriggerInventoryArchiveSaved( |
147 | m_id, succeeded, m_userInfo, m_invPath, m_saveStream, reportedException); | 153 | m_id, succeeded, m_userInfo, m_invPath, m_saveStream, reportedException); |
148 | } | 154 | } |
@@ -266,6 +272,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver | |||
266 | saveFolderContentsOnly = true; | 272 | saveFolderContentsOnly = true; |
267 | maxComponentIndex--; | 273 | maxComponentIndex--; |
268 | } | 274 | } |
275 | else if (maxComponentIndex == -1) | ||
276 | { | ||
277 | // If the user has just specified "/", then don't save the root "My Inventory" folder. This is | ||
278 | // more intuitive then requiring the user to specify "/*" for this. | ||
279 | saveFolderContentsOnly = true; | ||
280 | } | ||
269 | 281 | ||
270 | m_invPath = String.Empty; | 282 | m_invPath = String.Empty; |
271 | for (int i = 0; i <= maxComponentIndex; i++) | 283 | for (int i = 0; i <= maxComponentIndex; i++) |
@@ -283,7 +295,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver | |||
283 | { | 295 | { |
284 | m_invPath = m_invPath.Remove(m_invPath.LastIndexOf(InventoryFolderImpl.PATH_DELIMITER)); | 296 | m_invPath = m_invPath.Remove(m_invPath.LastIndexOf(InventoryFolderImpl.PATH_DELIMITER)); |
285 | List<InventoryFolderBase> candidateFolders | 297 | List<InventoryFolderBase> candidateFolders |
286 | = InventoryArchiveUtils.FindFolderByPath(m_scene.InventoryService, rootFolder, m_invPath); | 298 | = InventoryArchiveUtils.FindFoldersByPath(m_scene.InventoryService, rootFolder, m_invPath); |
287 | if (candidateFolders.Count > 0) | 299 | if (candidateFolders.Count > 0) |
288 | inventoryFolder = candidateFolders[0]; | 300 | inventoryFolder = candidateFolders[0]; |
289 | } | 301 | } |
@@ -350,7 +362,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver | |||
350 | { | 362 | { |
351 | m_log.DebugFormat("[INVENTORY ARCHIVER]: Not saving assets since --noassets was specified"); | 363 | m_log.DebugFormat("[INVENTORY ARCHIVER]: Not saving assets since --noassets was specified"); |
352 | 364 | ||
353 | ReceivedAllAssets(new List<UUID>(), new List<UUID>()); | 365 | ReceivedAllAssets(new List<UUID>(), new List<UUID>(), false); |
354 | } | 366 | } |
355 | } | 367 | } |
356 | catch (Exception) | 368 | catch (Exception) |
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/PathTests.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveLoadPathTests.cs index 6eb3605..95f562e 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/PathTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveLoadPathTests.cs | |||
@@ -48,125 +48,9 @@ using OpenSim.Tests.Common.Mock; | |||
48 | namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests | 48 | namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests |
49 | { | 49 | { |
50 | [TestFixture] | 50 | [TestFixture] |
51 | public class PathTests : InventoryArchiveTestCase | 51 | public class InventoryArchiveLoadPathTests : InventoryArchiveTestCase |
52 | { | 52 | { |
53 | /// <summary> | 53 | /// <summary> |
54 | /// Test saving an inventory path to a V0.1 OpenSim Inventory Archive | ||
55 | /// (subject to change since there is no fixed format yet). | ||
56 | /// </summary> | ||
57 | [Test] | ||
58 | public void TestSavePathToIarV0_1() | ||
59 | { | ||
60 | TestHelpers.InMethod(); | ||
61 | // log4net.Config.XmlConfigurator.Configure(); | ||
62 | |||
63 | InventoryArchiverModule archiverModule = new InventoryArchiverModule(); | ||
64 | |||
65 | Scene scene = new SceneHelpers().SetupScene(); | ||
66 | SceneHelpers.SetupSceneModules(scene, archiverModule); | ||
67 | |||
68 | // Create user | ||
69 | string userFirstName = "Jock"; | ||
70 | string userLastName = "Stirrup"; | ||
71 | string userPassword = "troll"; | ||
72 | UUID userId = UUID.Parse("00000000-0000-0000-0000-000000000020"); | ||
73 | UserAccountHelpers.CreateUserWithInventory(scene, userFirstName, userLastName, userId, userPassword); | ||
74 | |||
75 | // Create asset | ||
76 | SceneObjectGroup object1; | ||
77 | SceneObjectPart part1; | ||
78 | { | ||
79 | string partName = "My Little Dog Object"; | ||
80 | UUID ownerId = UUID.Parse("00000000-0000-0000-0000-000000000040"); | ||
81 | PrimitiveBaseShape shape = PrimitiveBaseShape.CreateSphere(); | ||
82 | Vector3 groupPosition = new Vector3(10, 20, 30); | ||
83 | Quaternion rotationOffset = new Quaternion(20, 30, 40, 50); | ||
84 | Vector3 offsetPosition = new Vector3(5, 10, 15); | ||
85 | |||
86 | part1 = new SceneObjectPart(ownerId, shape, groupPosition, rotationOffset, offsetPosition); | ||
87 | part1.Name = partName; | ||
88 | |||
89 | object1 = new SceneObjectGroup(part1); | ||
90 | scene.AddNewSceneObject(object1, false); | ||
91 | } | ||
92 | |||
93 | UUID asset1Id = UUID.Parse("00000000-0000-0000-0000-000000000060"); | ||
94 | AssetBase asset1 = AssetHelpers.CreateAsset(asset1Id, object1); | ||
95 | scene.AssetService.Store(asset1); | ||
96 | |||
97 | // Create item | ||
98 | UUID item1Id = UUID.Parse("00000000-0000-0000-0000-000000000080"); | ||
99 | InventoryItemBase item1 = new InventoryItemBase(); | ||
100 | item1.Name = "My Little Dog"; | ||
101 | item1.AssetID = asset1.FullID; | ||
102 | item1.ID = item1Id; | ||
103 | InventoryFolderBase objsFolder | ||
104 | = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, userId, "Objects")[0]; | ||
105 | item1.Folder = objsFolder.ID; | ||
106 | scene.AddInventoryItem(item1); | ||
107 | |||
108 | MemoryStream archiveWriteStream = new MemoryStream(); | ||
109 | archiverModule.OnInventoryArchiveSaved += SaveCompleted; | ||
110 | |||
111 | // Test saving a particular path | ||
112 | mre.Reset(); | ||
113 | archiverModule.ArchiveInventory( | ||
114 | Guid.NewGuid(), userFirstName, userLastName, "Objects", userPassword, archiveWriteStream); | ||
115 | mre.WaitOne(60000, false); | ||
116 | |||
117 | byte[] archive = archiveWriteStream.ToArray(); | ||
118 | MemoryStream archiveReadStream = new MemoryStream(archive); | ||
119 | TarArchiveReader tar = new TarArchiveReader(archiveReadStream); | ||
120 | |||
121 | //bool gotControlFile = false; | ||
122 | bool gotObject1File = false; | ||
123 | //bool gotObject2File = false; | ||
124 | string expectedObject1FileName = InventoryArchiveWriteRequest.CreateArchiveItemName(item1); | ||
125 | string expectedObject1FilePath = string.Format( | ||
126 | "{0}{1}{2}", | ||
127 | ArchiveConstants.INVENTORY_PATH, | ||
128 | InventoryArchiveWriteRequest.CreateArchiveFolderName(objsFolder), | ||
129 | expectedObject1FileName); | ||
130 | |||
131 | string filePath; | ||
132 | TarArchiveReader.TarEntryType tarEntryType; | ||
133 | |||
134 | // Console.WriteLine("Reading archive"); | ||
135 | |||
136 | while (tar.ReadEntry(out filePath, out tarEntryType) != null) | ||
137 | { | ||
138 | // Console.WriteLine("Got {0}", filePath); | ||
139 | |||
140 | // if (ArchiveConstants.CONTROL_FILE_PATH == filePath) | ||
141 | // { | ||
142 | // gotControlFile = true; | ||
143 | // } | ||
144 | |||
145 | if (filePath.StartsWith(ArchiveConstants.INVENTORY_PATH) && filePath.EndsWith(".xml")) | ||
146 | { | ||
147 | // string fileName = filePath.Remove(0, "Objects/".Length); | ||
148 | // | ||
149 | // if (fileName.StartsWith(part1.Name)) | ||
150 | // { | ||
151 | Assert.That(expectedObject1FilePath, Is.EqualTo(filePath)); | ||
152 | gotObject1File = true; | ||
153 | // } | ||
154 | // else if (fileName.StartsWith(part2.Name)) | ||
155 | // { | ||
156 | // Assert.That(fileName, Is.EqualTo(expectedObject2FileName)); | ||
157 | // gotObject2File = true; | ||
158 | // } | ||
159 | } | ||
160 | } | ||
161 | |||
162 | // Assert.That(gotControlFile, Is.True, "No control file in archive"); | ||
163 | Assert.That(gotObject1File, Is.True, "No item1 file in archive"); | ||
164 | // Assert.That(gotObject2File, Is.True, "No object2 file in archive"); | ||
165 | |||
166 | // TODO: Test presence of more files and contents of files. | ||
167 | } | ||
168 | |||
169 | /// <summary> | ||
170 | /// Test loading an IAR to various different inventory paths. | 54 | /// Test loading an IAR to various different inventory paths. |
171 | /// </summary> | 55 | /// </summary> |
172 | [Test] | 56 | [Test] |
@@ -193,7 +77,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests | |||
193 | Assert.That(foundItem1, Is.Not.Null, "Didn't find loaded item 1"); | 77 | Assert.That(foundItem1, Is.Not.Null, "Didn't find loaded item 1"); |
194 | 78 | ||
195 | // Now try loading to a root child folder | 79 | // Now try loading to a root child folder |
196 | UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, m_uaMT.PrincipalID, "xA"); | 80 | UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, m_uaMT.PrincipalID, "xA", false); |
197 | MemoryStream archiveReadStream = new MemoryStream(m_iarStream.ToArray()); | 81 | MemoryStream archiveReadStream = new MemoryStream(m_iarStream.ToArray()); |
198 | archiverModule.DearchiveInventory(m_uaMT.FirstName, m_uaMT.LastName, "xA", "meowfood", archiveReadStream); | 82 | archiverModule.DearchiveInventory(m_uaMT.FirstName, m_uaMT.LastName, "xA", "meowfood", archiveReadStream); |
199 | 83 | ||
@@ -202,7 +86,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests | |||
202 | Assert.That(foundItem2, Is.Not.Null, "Didn't find loaded item 2"); | 86 | Assert.That(foundItem2, Is.Not.Null, "Didn't find loaded item 2"); |
203 | 87 | ||
204 | // Now try loading to a more deeply nested folder | 88 | // Now try loading to a more deeply nested folder |
205 | UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, m_uaMT.PrincipalID, "xB/xC"); | 89 | UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, m_uaMT.PrincipalID, "xB/xC", false); |
206 | archiveReadStream = new MemoryStream(archiveReadStream.ToArray()); | 90 | archiveReadStream = new MemoryStream(archiveReadStream.ToArray()); |
207 | archiverModule.DearchiveInventory(m_uaMT.FirstName, m_uaMT.LastName, "xB/xC", "meowfood", archiveReadStream); | 91 | archiverModule.DearchiveInventory(m_uaMT.FirstName, m_uaMT.LastName, "xB/xC", "meowfood", archiveReadStream); |
208 | 92 | ||
@@ -287,7 +171,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests | |||
287 | item1.AssetID = asset1.FullID; | 171 | item1.AssetID = asset1.FullID; |
288 | item1.ID = item1Id; | 172 | item1.ID = item1Id; |
289 | InventoryFolderBase objsFolder | 173 | InventoryFolderBase objsFolder |
290 | = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, userId, "Objects")[0]; | 174 | = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, userId, "Objects")[0]; |
291 | item1.Folder = objsFolder.ID; | 175 | item1.Folder = objsFolder.ID; |
292 | scene.AddInventoryItem(item1); | 176 | scene.AddInventoryItem(item1); |
293 | 177 | ||
@@ -351,12 +235,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests | |||
351 | foldersCreated, nodesLoaded); | 235 | foldersCreated, nodesLoaded); |
352 | 236 | ||
353 | List<InventoryFolderBase> folder1Candidates | 237 | List<InventoryFolderBase> folder1Candidates |
354 | = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, ua1.PrincipalID, folder1Name); | 238 | = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, ua1.PrincipalID, folder1Name); |
355 | Assert.That(folder1Candidates.Count, Is.EqualTo(1)); | 239 | Assert.That(folder1Candidates.Count, Is.EqualTo(1)); |
356 | 240 | ||
357 | InventoryFolderBase folder1 = folder1Candidates[0]; | 241 | InventoryFolderBase folder1 = folder1Candidates[0]; |
358 | List<InventoryFolderBase> folder2aCandidates | 242 | List<InventoryFolderBase> folder2aCandidates |
359 | = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, folder1, folder2aName); | 243 | = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, folder1, folder2aName); |
360 | Assert.That(folder2aCandidates.Count, Is.EqualTo(1)); | 244 | Assert.That(folder2aCandidates.Count, Is.EqualTo(1)); |
361 | } | 245 | } |
362 | 246 | ||
@@ -368,17 +252,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests | |||
368 | foldersCreated, nodesLoaded); | 252 | foldersCreated, nodesLoaded); |
369 | 253 | ||
370 | List<InventoryFolderBase> folder1Candidates | 254 | List<InventoryFolderBase> folder1Candidates |
371 | = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, ua1.PrincipalID, folder1Name); | 255 | = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, ua1.PrincipalID, folder1Name); |
372 | Assert.That(folder1Candidates.Count, Is.EqualTo(1)); | 256 | Assert.That(folder1Candidates.Count, Is.EqualTo(1)); |
373 | 257 | ||
374 | InventoryFolderBase folder1 = folder1Candidates[0]; | 258 | InventoryFolderBase folder1 = folder1Candidates[0]; |
375 | 259 | ||
376 | List<InventoryFolderBase> folder2aCandidates | 260 | List<InventoryFolderBase> folder2aCandidates |
377 | = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, folder1, folder2aName); | 261 | = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, folder1, folder2aName); |
378 | Assert.That(folder2aCandidates.Count, Is.EqualTo(1)); | 262 | Assert.That(folder2aCandidates.Count, Is.EqualTo(1)); |
379 | 263 | ||
380 | List<InventoryFolderBase> folder2bCandidates | 264 | List<InventoryFolderBase> folder2bCandidates |
381 | = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, folder1, folder2bName); | 265 | = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, folder1, folder2bName); |
382 | Assert.That(folder2bCandidates.Count, Is.EqualTo(1)); | 266 | Assert.That(folder2bCandidates.Count, Is.EqualTo(1)); |
383 | } | 267 | } |
384 | } | 268 | } |
@@ -401,7 +285,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests | |||
401 | 285 | ||
402 | InventoryFolderBase folder1 | 286 | InventoryFolderBase folder1 |
403 | = UserInventoryHelpers.CreateInventoryFolder( | 287 | = UserInventoryHelpers.CreateInventoryFolder( |
404 | scene.InventoryService, ua1.PrincipalID, folder1ExistingName); | 288 | scene.InventoryService, ua1.PrincipalID, folder1ExistingName, false); |
405 | 289 | ||
406 | string folder1ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder1ExistingName, UUID.Random()); | 290 | string folder1ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder1ExistingName, UUID.Random()); |
407 | string folder2ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder2Name, UUID.Random()); | 291 | string folder2ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder2Name, UUID.Random()); |
@@ -414,7 +298,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests | |||
414 | new Dictionary<string, InventoryFolderBase>(), new HashSet<InventoryNodeBase>()); | 298 | new Dictionary<string, InventoryFolderBase>(), new HashSet<InventoryNodeBase>()); |
415 | 299 | ||
416 | List<InventoryFolderBase> folder1PostCandidates | 300 | List<InventoryFolderBase> folder1PostCandidates |
417 | = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, ua1.PrincipalID, folder1ExistingName); | 301 | = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, ua1.PrincipalID, folder1ExistingName); |
418 | Assert.That(folder1PostCandidates.Count, Is.EqualTo(2)); | 302 | Assert.That(folder1PostCandidates.Count, Is.EqualTo(2)); |
419 | 303 | ||
420 | // FIXME: Temporarily, we're going to do something messy to make sure we pick up the created folder. | 304 | // FIXME: Temporarily, we're going to do something messy to make sure we pick up the created folder. |
@@ -430,7 +314,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests | |||
430 | // Assert.That(folder1Post.ID, Is.EqualTo(folder1.ID)); | 314 | // Assert.That(folder1Post.ID, Is.EqualTo(folder1.ID)); |
431 | 315 | ||
432 | List<InventoryFolderBase> folder2PostCandidates | 316 | List<InventoryFolderBase> folder2PostCandidates |
433 | = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, folder1Post, "b"); | 317 | = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, folder1Post, "b"); |
434 | Assert.That(folder2PostCandidates.Count, Is.EqualTo(1)); | 318 | Assert.That(folder2PostCandidates.Count, Is.EqualTo(1)); |
435 | } | 319 | } |
436 | 320 | ||
@@ -452,7 +336,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests | |||
452 | 336 | ||
453 | InventoryFolderBase folder1 | 337 | InventoryFolderBase folder1 |
454 | = UserInventoryHelpers.CreateInventoryFolder( | 338 | = UserInventoryHelpers.CreateInventoryFolder( |
455 | scene.InventoryService, ua1.PrincipalID, folder1ExistingName); | 339 | scene.InventoryService, ua1.PrincipalID, folder1ExistingName, false); |
456 | 340 | ||
457 | string folder1ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder1ExistingName, UUID.Random()); | 341 | string folder1ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder1ExistingName, UUID.Random()); |
458 | string folder2ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder2Name, UUID.Random()); | 342 | string folder2ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder2Name, UUID.Random()); |
@@ -465,13 +349,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests | |||
465 | new Dictionary<string, InventoryFolderBase>(), new HashSet<InventoryNodeBase>()); | 349 | new Dictionary<string, InventoryFolderBase>(), new HashSet<InventoryNodeBase>()); |
466 | 350 | ||
467 | List<InventoryFolderBase> folder1PostCandidates | 351 | List<InventoryFolderBase> folder1PostCandidates |
468 | = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, ua1.PrincipalID, folder1ExistingName); | 352 | = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, ua1.PrincipalID, folder1ExistingName); |
469 | Assert.That(folder1PostCandidates.Count, Is.EqualTo(1)); | 353 | Assert.That(folder1PostCandidates.Count, Is.EqualTo(1)); |
470 | Assert.That(folder1PostCandidates[0].ID, Is.EqualTo(folder1.ID)); | 354 | Assert.That(folder1PostCandidates[0].ID, Is.EqualTo(folder1.ID)); |
471 | 355 | ||
472 | List<InventoryFolderBase> folder2PostCandidates | 356 | List<InventoryFolderBase> folder2PostCandidates |
473 | = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, folder1PostCandidates[0], "b"); | 357 | = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, folder1PostCandidates[0], "b"); |
474 | Assert.That(folder2PostCandidates.Count, Is.EqualTo(1)); | 358 | Assert.That(folder2PostCandidates.Count, Is.EqualTo(1)); |
475 | } | 359 | } |
476 | } | 360 | } |
477 | } \ No newline at end of file | 361 | } |
362 | |||
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveLoadTests.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveLoadTests.cs new file mode 100644 index 0000000..1b521fc --- /dev/null +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveLoadTests.cs | |||
@@ -0,0 +1,194 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.IO; | ||
31 | using System.Reflection; | ||
32 | using System.Threading; | ||
33 | using NUnit.Framework; | ||
34 | using OpenMetaverse; | ||
35 | using OpenSim.Data; | ||
36 | using OpenSim.Framework; | ||
37 | using OpenSim.Framework.Serialization; | ||
38 | using OpenSim.Framework.Serialization.External; | ||
39 | using OpenSim.Framework.Communications; | ||
40 | using OpenSim.Region.CoreModules.Avatar.Inventory.Archiver; | ||
41 | using OpenSim.Region.CoreModules.World.Serialiser; | ||
42 | using OpenSim.Region.Framework.Scenes; | ||
43 | using OpenSim.Region.Framework.Scenes.Serialization; | ||
44 | using OpenSim.Services.Interfaces; | ||
45 | using OpenSim.Tests.Common; | ||
46 | using OpenSim.Tests.Common.Mock; | ||
47 | |||
48 | namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests | ||
49 | { | ||
50 | [TestFixture] | ||
51 | public class InventoryArchiveLoadTests : InventoryArchiveTestCase | ||
52 | { | ||
53 | protected TestScene m_scene; | ||
54 | protected InventoryArchiverModule m_archiverModule; | ||
55 | |||
56 | [SetUp] | ||
57 | public override void SetUp() | ||
58 | { | ||
59 | base.SetUp(); | ||
60 | |||
61 | SerialiserModule serialiserModule = new SerialiserModule(); | ||
62 | m_archiverModule = new InventoryArchiverModule(); | ||
63 | |||
64 | m_scene = new SceneHelpers().SetupScene(); | ||
65 | SceneHelpers.SetupSceneModules(m_scene, serialiserModule, m_archiverModule); | ||
66 | } | ||
67 | |||
68 | [Test] | ||
69 | public void TestLoadCoalesecedItem() | ||
70 | { | ||
71 | TestHelpers.InMethod(); | ||
72 | // TestHelpers.EnableLogging(); | ||
73 | |||
74 | UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaLL1, "password"); | ||
75 | m_archiverModule.DearchiveInventory(m_uaLL1.FirstName, m_uaLL1.LastName, "/", "password", m_iarStream); | ||
76 | |||
77 | InventoryItemBase coaItem | ||
78 | = InventoryArchiveUtils.FindItemByPath(m_scene.InventoryService, m_uaLL1.PrincipalID, m_coaItemName); | ||
79 | |||
80 | Assert.That(coaItem, Is.Not.Null, "Didn't find loaded item 1"); | ||
81 | |||
82 | string assetXml = AssetHelpers.ReadAssetAsString(m_scene.AssetService, coaItem.AssetID); | ||
83 | |||
84 | CoalescedSceneObjects coa; | ||
85 | bool readResult = CoalescedSceneObjectsSerializer.TryFromXml(assetXml, out coa); | ||
86 | |||
87 | Assert.That(readResult, Is.True); | ||
88 | Assert.That(coa.Count, Is.EqualTo(2)); | ||
89 | |||
90 | List<SceneObjectGroup> coaObjects = coa.Objects; | ||
91 | Assert.That(coaObjects[0].UUID, Is.EqualTo(UUID.Parse("00000000-0000-0000-0000-000000000120"))); | ||
92 | Assert.That(coaObjects[0].AbsolutePosition, Is.EqualTo(new Vector3(15, 30, 45))); | ||
93 | |||
94 | Assert.That(coaObjects[1].UUID, Is.EqualTo(UUID.Parse("00000000-0000-0000-0000-000000000140"))); | ||
95 | Assert.That(coaObjects[1].AbsolutePosition, Is.EqualTo(new Vector3(25, 50, 75))); | ||
96 | } | ||
97 | |||
98 | /// <summary> | ||
99 | /// Test case where a creator account exists for the creator UUID embedded in item metadata and serialized | ||
100 | /// objects. | ||
101 | /// </summary> | ||
102 | [Test] | ||
103 | public void TestLoadIarCreatorAccountPresent() | ||
104 | { | ||
105 | TestHelpers.InMethod(); | ||
106 | // log4net.Config.XmlConfigurator.Configure(); | ||
107 | |||
108 | UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaLL1, "meowfood"); | ||
109 | |||
110 | m_archiverModule.DearchiveInventory(m_uaLL1.FirstName, m_uaLL1.LastName, "/", "meowfood", m_iarStream); | ||
111 | InventoryItemBase foundItem1 | ||
112 | = InventoryArchiveUtils.FindItemByPath(m_scene.InventoryService, m_uaLL1.PrincipalID, m_item1Name); | ||
113 | |||
114 | Assert.That( | ||
115 | foundItem1.CreatorId, Is.EqualTo(m_uaLL1.PrincipalID.ToString()), | ||
116 | "Loaded item non-uuid creator doesn't match original"); | ||
117 | Assert.That( | ||
118 | foundItem1.CreatorIdAsUuid, Is.EqualTo(m_uaLL1.PrincipalID), | ||
119 | "Loaded item uuid creator doesn't match original"); | ||
120 | Assert.That(foundItem1.Owner, Is.EqualTo(m_uaLL1.PrincipalID), | ||
121 | "Loaded item owner doesn't match inventory reciever"); | ||
122 | |||
123 | AssetBase asset1 = m_scene.AssetService.Get(foundItem1.AssetID.ToString()); | ||
124 | string xmlData = Utils.BytesToString(asset1.Data); | ||
125 | SceneObjectGroup sog1 = SceneObjectSerializer.FromOriginalXmlFormat(xmlData); | ||
126 | |||
127 | Assert.That(sog1.RootPart.CreatorID, Is.EqualTo(m_uaLL1.PrincipalID)); | ||
128 | } | ||
129 | |||
130 | // /// <summary> | ||
131 | // /// Test loading a V0.1 OpenSim Inventory Archive (subject to change since there is no fixed format yet) where | ||
132 | // /// an account exists with the same name as the creator, though not the same id. | ||
133 | // /// </summary> | ||
134 | // [Test] | ||
135 | // public void TestLoadIarV0_1SameNameCreator() | ||
136 | // { | ||
137 | // TestHelpers.InMethod(); | ||
138 | // TestHelpers.EnableLogging(); | ||
139 | // | ||
140 | // UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaMT, "meowfood"); | ||
141 | // UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaLL2, "hampshire"); | ||
142 | // | ||
143 | // m_archiverModule.DearchiveInventory(m_uaMT.FirstName, m_uaMT.LastName, "/", "meowfood", m_iarStream); | ||
144 | // InventoryItemBase foundItem1 | ||
145 | // = InventoryArchiveUtils.FindItemByPath(m_scene.InventoryService, m_uaMT.PrincipalID, m_item1Name); | ||
146 | // | ||
147 | // Assert.That( | ||
148 | // foundItem1.CreatorId, Is.EqualTo(m_uaLL2.PrincipalID.ToString()), | ||
149 | // "Loaded item non-uuid creator doesn't match original"); | ||
150 | // Assert.That( | ||
151 | // foundItem1.CreatorIdAsUuid, Is.EqualTo(m_uaLL2.PrincipalID), | ||
152 | // "Loaded item uuid creator doesn't match original"); | ||
153 | // Assert.That(foundItem1.Owner, Is.EqualTo(m_uaMT.PrincipalID), | ||
154 | // "Loaded item owner doesn't match inventory reciever"); | ||
155 | // | ||
156 | // AssetBase asset1 = m_scene.AssetService.Get(foundItem1.AssetID.ToString()); | ||
157 | // string xmlData = Utils.BytesToString(asset1.Data); | ||
158 | // SceneObjectGroup sog1 = SceneObjectSerializer.FromOriginalXmlFormat(xmlData); | ||
159 | // | ||
160 | // Assert.That(sog1.RootPart.CreatorID, Is.EqualTo(m_uaLL2.PrincipalID)); | ||
161 | // } | ||
162 | |||
163 | /// <summary> | ||
164 | /// Test loading a V0.1 OpenSim Inventory Archive (subject to change since there is no fixed format yet) where | ||
165 | /// the creator or an account with the creator's name does not exist within the system. | ||
166 | /// </summary> | ||
167 | [Test] | ||
168 | public void TestLoadIarV0_1AbsentCreator() | ||
169 | { | ||
170 | TestHelpers.InMethod(); | ||
171 | // log4net.Config.XmlConfigurator.Configure(); | ||
172 | |||
173 | UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaMT, "password"); | ||
174 | m_archiverModule.DearchiveInventory(m_uaMT.FirstName, m_uaMT.LastName, "/", "password", m_iarStream); | ||
175 | |||
176 | InventoryItemBase foundItem1 | ||
177 | = InventoryArchiveUtils.FindItemByPath(m_scene.InventoryService, m_uaMT.PrincipalID, m_item1Name); | ||
178 | |||
179 | Assert.That(foundItem1, Is.Not.Null, "Didn't find loaded item 1"); | ||
180 | Assert.That( | ||
181 | foundItem1.CreatorId, Is.EqualTo(m_uaMT.PrincipalID.ToString()), | ||
182 | "Loaded item non-uuid creator doesn't match that of the loading user"); | ||
183 | Assert.That( | ||
184 | foundItem1.CreatorIdAsUuid, Is.EqualTo(m_uaMT.PrincipalID), | ||
185 | "Loaded item uuid creator doesn't match that of the loading user"); | ||
186 | |||
187 | AssetBase asset1 = m_scene.AssetService.Get(foundItem1.AssetID.ToString()); | ||
188 | string xmlData = Utils.BytesToString(asset1.Data); | ||
189 | SceneObjectGroup sog1 = SceneObjectSerializer.FromOriginalXmlFormat(xmlData); | ||
190 | |||
191 | Assert.That(sog1.RootPart.CreatorID, Is.EqualTo(m_uaMT.PrincipalID)); | ||
192 | } | ||
193 | } | ||
194 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveSaveTests.cs index 06f6e49..5e7e24c 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveSaveTests.cs | |||
@@ -48,7 +48,7 @@ using OpenSim.Tests.Common.Mock; | |||
48 | namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests | 48 | namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests |
49 | { | 49 | { |
50 | [TestFixture] | 50 | [TestFixture] |
51 | public class InventoryArchiverTests : InventoryArchiveTestCase | 51 | public class InventoryArchiveSaveTests : InventoryArchiveTestCase |
52 | { | 52 | { |
53 | protected TestScene m_scene; | 53 | protected TestScene m_scene; |
54 | protected InventoryArchiverModule m_archiverModule; | 54 | protected InventoryArchiverModule m_archiverModule; |
@@ -64,36 +64,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests | |||
64 | m_scene = new SceneHelpers().SetupScene(); | 64 | m_scene = new SceneHelpers().SetupScene(); |
65 | SceneHelpers.SetupSceneModules(m_scene, serialiserModule, m_archiverModule); | 65 | SceneHelpers.SetupSceneModules(m_scene, serialiserModule, m_archiverModule); |
66 | } | 66 | } |
67 | |||
68 | [Test] | ||
69 | public void TestLoadCoalesecedItem() | ||
70 | { | ||
71 | TestHelpers.InMethod(); | ||
72 | // TestHelpers.EnableLogging(); | ||
73 | |||
74 | UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaLL1, "password"); | ||
75 | m_archiverModule.DearchiveInventory(m_uaLL1.FirstName, m_uaLL1.LastName, "/", "password", m_iarStream); | ||
76 | |||
77 | InventoryItemBase coaItem | ||
78 | = InventoryArchiveUtils.FindItemByPath(m_scene.InventoryService, m_uaLL1.PrincipalID, m_coaItemName); | ||
79 | |||
80 | Assert.That(coaItem, Is.Not.Null, "Didn't find loaded item 1"); | ||
81 | |||
82 | string assetXml = AssetHelpers.ReadAssetAsString(m_scene.AssetService, coaItem.AssetID); | ||
83 | |||
84 | CoalescedSceneObjects coa; | ||
85 | bool readResult = CoalescedSceneObjectsSerializer.TryFromXml(assetXml, out coa); | ||
86 | |||
87 | Assert.That(readResult, Is.True); | ||
88 | Assert.That(coa.Count, Is.EqualTo(2)); | ||
89 | |||
90 | List<SceneObjectGroup> coaObjects = coa.Objects; | ||
91 | Assert.That(coaObjects[0].UUID, Is.EqualTo(UUID.Parse("00000000-0000-0000-0000-000000000120"))); | ||
92 | Assert.That(coaObjects[0].AbsolutePosition, Is.EqualTo(new Vector3(15, 30, 45))); | ||
93 | |||
94 | Assert.That(coaObjects[1].UUID, Is.EqualTo(UUID.Parse("00000000-0000-0000-0000-000000000140"))); | ||
95 | Assert.That(coaObjects[1].AbsolutePosition, Is.EqualTo(new Vector3(25, 50, 75))); | ||
96 | } | ||
97 | 67 | ||
98 | /// <summary> | 68 | /// <summary> |
99 | /// Test that the IAR has the required files in the right order. | 69 | /// Test that the IAR has the required files in the right order. |
@@ -121,6 +91,139 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests | |||
121 | 91 | ||
122 | Assert.That(iarr.ControlFileLoaded, Is.True); | 92 | Assert.That(iarr.ControlFileLoaded, Is.True); |
123 | } | 93 | } |
94 | |||
95 | [Test] | ||
96 | public void TestSaveRootFolderToIar() | ||
97 | { | ||
98 | TestHelpers.InMethod(); | ||
99 | // TestHelpers.EnableLogging(); | ||
100 | |||
101 | string userFirstName = "Jock"; | ||
102 | string userLastName = "Stirrup"; | ||
103 | string userPassword = "troll"; | ||
104 | UUID userId = TestHelpers.ParseTail(0x20); | ||
105 | |||
106 | UserAccountHelpers.CreateUserWithInventory(m_scene, userFirstName, userLastName, userId, userPassword); | ||
107 | |||
108 | MemoryStream archiveWriteStream = new MemoryStream(); | ||
109 | m_archiverModule.OnInventoryArchiveSaved += SaveCompleted; | ||
110 | |||
111 | mre.Reset(); | ||
112 | m_archiverModule.ArchiveInventory( | ||
113 | Guid.NewGuid(), userFirstName, userLastName, "/", userPassword, archiveWriteStream); | ||
114 | mre.WaitOne(60000, false); | ||
115 | |||
116 | // Test created iar | ||
117 | byte[] archive = archiveWriteStream.ToArray(); | ||
118 | MemoryStream archiveReadStream = new MemoryStream(archive); | ||
119 | TarArchiveReader tar = new TarArchiveReader(archiveReadStream); | ||
120 | |||
121 | // InventoryArchiveUtils. | ||
122 | bool gotObjectsFolder = false; | ||
123 | |||
124 | string objectsFolderName | ||
125 | = string.Format( | ||
126 | "{0}{1}", | ||
127 | ArchiveConstants.INVENTORY_PATH, | ||
128 | InventoryArchiveWriteRequest.CreateArchiveFolderName( | ||
129 | UserInventoryHelpers.GetInventoryFolder(m_scene.InventoryService, userId, "Objects"))); | ||
130 | |||
131 | string filePath; | ||
132 | TarArchiveReader.TarEntryType tarEntryType; | ||
133 | |||
134 | while (tar.ReadEntry(out filePath, out tarEntryType) != null) | ||
135 | { | ||
136 | // Console.WriteLine("Got {0}", filePath); | ||
137 | |||
138 | // Lazily, we only bother to look for the system objects folder created when we call CreateUserWithInventory() | ||
139 | // XXX: But really we need to stop all that stuff being created in tests or check for such folders | ||
140 | // more thoroughly | ||
141 | if (filePath == objectsFolderName) | ||
142 | gotObjectsFolder = true; | ||
143 | } | ||
144 | |||
145 | Assert.That(gotObjectsFolder, Is.True); | ||
146 | } | ||
147 | |||
148 | [Test] | ||
149 | public void TestSaveNonRootFolderToIar() | ||
150 | { | ||
151 | TestHelpers.InMethod(); | ||
152 | // TestHelpers.EnableLogging(); | ||
153 | |||
154 | string userFirstName = "Jock"; | ||
155 | string userLastName = "Stirrup"; | ||
156 | string userPassword = "troll"; | ||
157 | UUID userId = TestHelpers.ParseTail(0x20); | ||
158 | |||
159 | UserAccountHelpers.CreateUserWithInventory(m_scene, userFirstName, userLastName, userId, userPassword); | ||
160 | |||
161 | // Create base folder | ||
162 | InventoryFolderBase f1 | ||
163 | = UserInventoryHelpers.CreateInventoryFolder(m_scene.InventoryService, userId, "f1", true); | ||
164 | |||
165 | // Create item1 | ||
166 | SceneObjectGroup so1 = SceneHelpers.CreateSceneObject(1, userId, "My Little Dog Object", 0x5); | ||
167 | InventoryItemBase i1 = UserInventoryHelpers.AddInventoryItem(m_scene, so1, 0x50, 0x60, "f1"); | ||
168 | |||
169 | // Create embedded folder | ||
170 | InventoryFolderBase f1_1 | ||
171 | = UserInventoryHelpers.CreateInventoryFolder(m_scene.InventoryService, userId, "f1/f1.1", true); | ||
172 | |||
173 | // Create embedded item | ||
174 | SceneObjectGroup so1_1 = SceneHelpers.CreateSceneObject(1, userId, "My Little Cat Object", 0x6); | ||
175 | InventoryItemBase i2 = UserInventoryHelpers.AddInventoryItem(m_scene, so1_1, 0x500, 0x600, "f1/f1.1"); | ||
176 | |||
177 | MemoryStream archiveWriteStream = new MemoryStream(); | ||
178 | m_archiverModule.OnInventoryArchiveSaved += SaveCompleted; | ||
179 | |||
180 | mre.Reset(); | ||
181 | m_archiverModule.ArchiveInventory( | ||
182 | Guid.NewGuid(), userFirstName, userLastName, "f1", userPassword, archiveWriteStream); | ||
183 | mre.WaitOne(60000, false); | ||
184 | |||
185 | // Test created iar | ||
186 | byte[] archive = archiveWriteStream.ToArray(); | ||
187 | MemoryStream archiveReadStream = new MemoryStream(archive); | ||
188 | TarArchiveReader tar = new TarArchiveReader(archiveReadStream); | ||
189 | |||
190 | // InventoryArchiveUtils. | ||
191 | bool gotf1 = false, gotf1_1 = false, gotso1 = false, gotso2 = false; | ||
192 | |||
193 | string f1FileName | ||
194 | = string.Format("{0}{1}", ArchiveConstants.INVENTORY_PATH, InventoryArchiveWriteRequest.CreateArchiveFolderName(f1)); | ||
195 | string f1_1FileName | ||
196 | = string.Format("{0}{1}", f1FileName, InventoryArchiveWriteRequest.CreateArchiveFolderName(f1_1)); | ||
197 | string so1FileName | ||
198 | = string.Format("{0}{1}", f1FileName, InventoryArchiveWriteRequest.CreateArchiveItemName(i1)); | ||
199 | string so2FileName | ||
200 | = string.Format("{0}{1}", f1_1FileName, InventoryArchiveWriteRequest.CreateArchiveItemName(i2)); | ||
201 | |||
202 | string filePath; | ||
203 | TarArchiveReader.TarEntryType tarEntryType; | ||
204 | |||
205 | while (tar.ReadEntry(out filePath, out tarEntryType) != null) | ||
206 | { | ||
207 | // Console.WriteLine("Got {0}", filePath); | ||
208 | |||
209 | if (filePath == f1FileName) | ||
210 | gotf1 = true; | ||
211 | else if (filePath == f1_1FileName) | ||
212 | gotf1_1 = true; | ||
213 | else if (filePath == so1FileName) | ||
214 | gotso1 = true; | ||
215 | else if (filePath == so2FileName) | ||
216 | gotso2 = true; | ||
217 | } | ||
218 | |||
219 | // Assert.That(gotControlFile, Is.True, "No control file in archive"); | ||
220 | Assert.That(gotf1, Is.True); | ||
221 | Assert.That(gotf1_1, Is.True); | ||
222 | Assert.That(gotso1, Is.True); | ||
223 | Assert.That(gotso2, Is.True); | ||
224 | |||
225 | // TODO: Test presence of more files and contents of files. | ||
226 | } | ||
124 | 227 | ||
125 | /// <summary> | 228 | /// <summary> |
126 | /// Test saving a single inventory item to an IAR | 229 | /// Test saving a single inventory item to an IAR |
@@ -155,7 +258,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests | |||
155 | item1.AssetID = asset1.FullID; | 258 | item1.AssetID = asset1.FullID; |
156 | item1.ID = item1Id; | 259 | item1.ID = item1Id; |
157 | InventoryFolderBase objsFolder | 260 | InventoryFolderBase objsFolder |
158 | = InventoryArchiveUtils.FindFolderByPath(m_scene.InventoryService, userId, "Objects")[0]; | 261 | = InventoryArchiveUtils.FindFoldersByPath(m_scene.InventoryService, userId, "Objects")[0]; |
159 | item1.Folder = objsFolder.ID; | 262 | item1.Folder = objsFolder.ID; |
160 | m_scene.AddInventoryItem(item1); | 263 | m_scene.AddInventoryItem(item1); |
161 | 264 | ||
@@ -250,7 +353,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests | |||
250 | item1.AssetID = asset1.FullID; | 353 | item1.AssetID = asset1.FullID; |
251 | item1.ID = item1Id; | 354 | item1.ID = item1Id; |
252 | InventoryFolderBase objsFolder | 355 | InventoryFolderBase objsFolder |
253 | = InventoryArchiveUtils.FindFolderByPath(m_scene.InventoryService, userId, "Objects")[0]; | 356 | = InventoryArchiveUtils.FindFoldersByPath(m_scene.InventoryService, userId, "Objects")[0]; |
254 | item1.Folder = objsFolder.ID; | 357 | item1.Folder = objsFolder.ID; |
255 | m_scene.AddInventoryItem(item1); | 358 | m_scene.AddInventoryItem(item1); |
256 | 359 | ||
@@ -317,101 +420,5 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests | |||
317 | 420 | ||
318 | // TODO: Test presence of more files and contents of files. | 421 | // TODO: Test presence of more files and contents of files. |
319 | } | 422 | } |
320 | |||
321 | /// <summary> | ||
322 | /// Test case where a creator account exists for the creator UUID embedded in item metadata and serialized | ||
323 | /// objects. | ||
324 | /// </summary> | ||
325 | [Test] | ||
326 | public void TestLoadIarCreatorAccountPresent() | ||
327 | { | ||
328 | TestHelpers.InMethod(); | ||
329 | // log4net.Config.XmlConfigurator.Configure(); | ||
330 | |||
331 | UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaLL1, "meowfood"); | ||
332 | |||
333 | m_archiverModule.DearchiveInventory(m_uaLL1.FirstName, m_uaLL1.LastName, "/", "meowfood", m_iarStream); | ||
334 | InventoryItemBase foundItem1 | ||
335 | = InventoryArchiveUtils.FindItemByPath(m_scene.InventoryService, m_uaLL1.PrincipalID, m_item1Name); | ||
336 | |||
337 | Assert.That( | ||
338 | foundItem1.CreatorId, Is.EqualTo(m_uaLL1.PrincipalID.ToString()), | ||
339 | "Loaded item non-uuid creator doesn't match original"); | ||
340 | Assert.That( | ||
341 | foundItem1.CreatorIdAsUuid, Is.EqualTo(m_uaLL1.PrincipalID), | ||
342 | "Loaded item uuid creator doesn't match original"); | ||
343 | Assert.That(foundItem1.Owner, Is.EqualTo(m_uaLL1.PrincipalID), | ||
344 | "Loaded item owner doesn't match inventory reciever"); | ||
345 | |||
346 | AssetBase asset1 = m_scene.AssetService.Get(foundItem1.AssetID.ToString()); | ||
347 | string xmlData = Utils.BytesToString(asset1.Data); | ||
348 | SceneObjectGroup sog1 = SceneObjectSerializer.FromOriginalXmlFormat(xmlData); | ||
349 | |||
350 | Assert.That(sog1.RootPart.CreatorID, Is.EqualTo(m_uaLL1.PrincipalID)); | ||
351 | } | ||
352 | |||
353 | // /// <summary> | ||
354 | // /// Test loading a V0.1 OpenSim Inventory Archive (subject to change since there is no fixed format yet) where | ||
355 | // /// an account exists with the same name as the creator, though not the same id. | ||
356 | // /// </summary> | ||
357 | // [Test] | ||
358 | // public void TestLoadIarV0_1SameNameCreator() | ||
359 | // { | ||
360 | // TestHelpers.InMethod(); | ||
361 | // TestHelpers.EnableLogging(); | ||
362 | // | ||
363 | // UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaMT, "meowfood"); | ||
364 | // UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaLL2, "hampshire"); | ||
365 | // | ||
366 | // m_archiverModule.DearchiveInventory(m_uaMT.FirstName, m_uaMT.LastName, "/", "meowfood", m_iarStream); | ||
367 | // InventoryItemBase foundItem1 | ||
368 | // = InventoryArchiveUtils.FindItemByPath(m_scene.InventoryService, m_uaMT.PrincipalID, m_item1Name); | ||
369 | // | ||
370 | // Assert.That( | ||
371 | // foundItem1.CreatorId, Is.EqualTo(m_uaLL2.PrincipalID.ToString()), | ||
372 | // "Loaded item non-uuid creator doesn't match original"); | ||
373 | // Assert.That( | ||
374 | // foundItem1.CreatorIdAsUuid, Is.EqualTo(m_uaLL2.PrincipalID), | ||
375 | // "Loaded item uuid creator doesn't match original"); | ||
376 | // Assert.That(foundItem1.Owner, Is.EqualTo(m_uaMT.PrincipalID), | ||
377 | // "Loaded item owner doesn't match inventory reciever"); | ||
378 | // | ||
379 | // AssetBase asset1 = m_scene.AssetService.Get(foundItem1.AssetID.ToString()); | ||
380 | // string xmlData = Utils.BytesToString(asset1.Data); | ||
381 | // SceneObjectGroup sog1 = SceneObjectSerializer.FromOriginalXmlFormat(xmlData); | ||
382 | // | ||
383 | // Assert.That(sog1.RootPart.CreatorID, Is.EqualTo(m_uaLL2.PrincipalID)); | ||
384 | // } | ||
385 | |||
386 | /// <summary> | ||
387 | /// Test loading a V0.1 OpenSim Inventory Archive (subject to change since there is no fixed format yet) where | ||
388 | /// the creator or an account with the creator's name does not exist within the system. | ||
389 | /// </summary> | ||
390 | [Test] | ||
391 | public void TestLoadIarV0_1AbsentCreator() | ||
392 | { | ||
393 | TestHelpers.InMethod(); | ||
394 | // log4net.Config.XmlConfigurator.Configure(); | ||
395 | |||
396 | UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaMT, "password"); | ||
397 | m_archiverModule.DearchiveInventory(m_uaMT.FirstName, m_uaMT.LastName, "/", "password", m_iarStream); | ||
398 | |||
399 | InventoryItemBase foundItem1 | ||
400 | = InventoryArchiveUtils.FindItemByPath(m_scene.InventoryService, m_uaMT.PrincipalID, m_item1Name); | ||
401 | |||
402 | Assert.That(foundItem1, Is.Not.Null, "Didn't find loaded item 1"); | ||
403 | Assert.That( | ||
404 | foundItem1.CreatorId, Is.EqualTo(m_uaMT.PrincipalID.ToString()), | ||
405 | "Loaded item non-uuid creator doesn't match that of the loading user"); | ||
406 | Assert.That( | ||
407 | foundItem1.CreatorIdAsUuid, Is.EqualTo(m_uaMT.PrincipalID), | ||
408 | "Loaded item uuid creator doesn't match that of the loading user"); | ||
409 | |||
410 | AssetBase asset1 = m_scene.AssetService.Get(foundItem1.AssetID.ToString()); | ||
411 | string xmlData = Utils.BytesToString(asset1.Data); | ||
412 | SceneObjectGroup sog1 = SceneObjectSerializer.FromOriginalXmlFormat(xmlData); | ||
413 | |||
414 | Assert.That(sog1.RootPart.CreatorID, Is.EqualTo(m_uaMT.PrincipalID)); | ||
415 | } | ||
416 | } | 423 | } |
417 | } \ No newline at end of file | 424 | } \ No newline at end of file |
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs index 4cfa33d..ae58dfd 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs | |||
@@ -316,76 +316,74 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer | |||
316 | } | 316 | } |
317 | } | 317 | } |
318 | 318 | ||
319 | // Disabled for now as it looks like http://opensimulator.org/mantis/view.php?id=6311 was fixed by fixes | 319 | // XXX: This code was placed here to try and accomodate RLV which moves given folders named #RLV/~<name> |
320 | // to inventory folder versioning allowing the viewer to move the received folder itself as happens on the | 320 | // to the requested folder, which in this case is #RLV. However, it is the viewer that appears to be |
321 | // LL grid. Doing it again server-side then wrongly does a second create and move | 321 | // response from renaming the #RLV/~example folder to ~example. For some reason this is not yet |
322 | // // XXX: This code was placed here to try and accomdate RLV which moves given folders named #RLV/~<name> | 322 | // happening, possibly because we are not sending the correct inventory update messages with the correct |
323 | // // to a folder called name in #RLV. However, this approach may not be ultimately correct - from analysis | 323 | // transaction IDs |
324 | // // of Firestorm 4.2.2 on sending an InventoryOffered instead of TaskInventoryOffered (as was previously | 324 | else if (im.dialog == (byte) InstantMessageDialog.TaskInventoryAccepted) |
325 | // // done), the viewer itself would appear to move and rename the folder, rather than the simulator doing it here. | 325 | { |
326 | // else if (im.dialog == (byte) InstantMessageDialog.TaskInventoryAccepted) | 326 | UUID destinationFolderID = UUID.Zero; |
327 | // { | 327 | |
328 | // UUID destinationFolderID = UUID.Zero; | 328 | if (im.binaryBucket != null && im.binaryBucket.Length >= 16) |
329 | // | 329 | { |
330 | // if (im.binaryBucket != null && im.binaryBucket.Length >= 16) | 330 | destinationFolderID = new UUID(im.binaryBucket, 0); |
331 | // { | 331 | } |
332 | // destinationFolderID = new UUID(im.binaryBucket, 0); | 332 | |
333 | // } | 333 | if (destinationFolderID != UUID.Zero) |
334 | // | 334 | { |
335 | // if (destinationFolderID != UUID.Zero) | 335 | InventoryFolderBase destinationFolder = new InventoryFolderBase(destinationFolderID, client.AgentId); |
336 | // { | 336 | if (destinationFolder == null) |
337 | // InventoryFolderBase destinationFolder = new InventoryFolderBase(destinationFolderID, client.AgentId); | 337 | { |
338 | // if (destinationFolder == null) | 338 | m_log.WarnFormat( |
339 | // { | 339 | "[INVENTORY TRANSFER]: TaskInventoryAccepted message from {0} in {1} specified folder {2} which does not exist", |
340 | // m_log.WarnFormat( | 340 | client.Name, scene.Name, destinationFolderID); |
341 | // "[INVENTORY TRANSFER]: TaskInventoryAccepted message from {0} in {1} specified folder {2} which does not exist", | 341 | |
342 | // client.Name, scene.Name, destinationFolderID); | 342 | return; |
343 | // | 343 | } |
344 | // return; | 344 | |
345 | // } | 345 | IInventoryService invService = scene.InventoryService; |
346 | // | 346 | |
347 | // IInventoryService invService = scene.InventoryService; | 347 | UUID inventoryID = new UUID(im.imSessionID); // The inventory item/folder, back from it's trip |
348 | // | 348 | |
349 | // UUID inventoryID = new UUID(im.imSessionID); // The inventory item/folder, back from it's trip | 349 | InventoryItemBase item = new InventoryItemBase(inventoryID, client.AgentId); |
350 | // | 350 | item = invService.GetItem(item); |
351 | // InventoryItemBase item = new InventoryItemBase(inventoryID, client.AgentId); | 351 | InventoryFolderBase folder = null; |
352 | // item = invService.GetItem(item); | 352 | UUID? previousParentFolderID = null; |
353 | // InventoryFolderBase folder = null; | 353 | |
354 | // UUID? previousParentFolderID = null; | 354 | if (item != null) // It's an item |
355 | // | 355 | { |
356 | // if (item != null) // It's an item | 356 | previousParentFolderID = item.Folder; |
357 | // { | 357 | item.Folder = destinationFolderID; |
358 | // previousParentFolderID = item.Folder; | 358 | |
359 | // item.Folder = destinationFolderID; | 359 | invService.DeleteItems(item.Owner, new List<UUID>() { item.ID }); |
360 | // | 360 | scene.AddInventoryItem(client, item); |
361 | // invService.DeleteItems(item.Owner, new List<UUID>() { item.ID }); | 361 | } |
362 | // scene.AddInventoryItem(client, item); | 362 | else |
363 | // } | 363 | { |
364 | // else | 364 | folder = new InventoryFolderBase(inventoryID, client.AgentId); |
365 | // { | 365 | folder = invService.GetFolder(folder); |
366 | // folder = new InventoryFolderBase(inventoryID, client.AgentId); | 366 | |
367 | // folder = invService.GetFolder(folder); | 367 | if (folder != null) // It's a folder |
368 | // | 368 | { |
369 | // if (folder != null) // It's a folder | 369 | previousParentFolderID = folder.ParentID; |
370 | // { | 370 | folder.ParentID = destinationFolderID; |
371 | // previousParentFolderID = folder.ParentID; | 371 | invService.MoveFolder(folder); |
372 | // folder.ParentID = destinationFolderID; | 372 | } |
373 | // invService.MoveFolder(folder); | 373 | } |
374 | // } | 374 | |
375 | // } | 375 | // Tell client about updates to original parent and new parent (this should probably be factored with existing move item/folder code). |
376 | // | 376 | if (previousParentFolderID != null) |
377 | // // Tell client about updates to original parent and new parent (this should probably be factored with existing move item/folder code). | 377 | { |
378 | // if (previousParentFolderID != null) | 378 | InventoryFolderBase previousParentFolder |
379 | // { | 379 | = new InventoryFolderBase((UUID)previousParentFolderID, client.AgentId); |
380 | // InventoryFolderBase previousParentFolder | 380 | previousParentFolder = invService.GetFolder(previousParentFolder); |
381 | // = new InventoryFolderBase((UUID)previousParentFolderID, client.AgentId); | 381 | scene.SendInventoryUpdate(client, previousParentFolder, true, true); |
382 | // previousParentFolder = invService.GetFolder(previousParentFolder); | 382 | |
383 | // scene.SendInventoryUpdate(client, previousParentFolder, true, true); | 383 | scene.SendInventoryUpdate(client, destinationFolder, true, true); |
384 | // | 384 | } |
385 | // scene.SendInventoryUpdate(client, destinationFolder, true, true); | 385 | } |
386 | // } | 386 | } |
387 | // } | ||
388 | // } | ||
389 | else if ( | 387 | else if ( |
390 | im.dialog == (byte)InstantMessageDialog.InventoryDeclined | 388 | im.dialog == (byte)InstantMessageDialog.InventoryDeclined |
391 | || im.dialog == (byte)InstantMessageDialog.TaskInventoryDeclined) | 389 | || im.dialog == (byte)InstantMessageDialog.TaskInventoryDeclined) |
diff --git a/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs b/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs index 232a4fe..a34f2d2 100644 --- a/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs | |||
@@ -65,7 +65,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure | |||
65 | { | 65 | { |
66 | m_Enabled = true; | 66 | m_Enabled = true; |
67 | 67 | ||
68 | m_ThisGridURL = config.Configs["Messaging"].GetString("Gatekeeper", string.Empty); | 68 | m_ThisGridURL = Util.GetConfigVarFromSections<string>(config, "GatekeeperURI", |
69 | new string[] { "Startup", "Hypergrid", "Messaging" }, String.Empty); | ||
70 | // Legacy. Remove soon! | ||
71 | m_ThisGridURL = config.Configs["Messaging"].GetString("Gatekeeper", m_ThisGridURL); | ||
69 | m_log.DebugFormat("[LURE MODULE]: {0} enabled", Name); | 72 | m_log.DebugFormat("[LURE MODULE]: {0} enabled", Name); |
70 | } | 73 | } |
71 | } | 74 | } |
@@ -151,7 +154,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure | |||
151 | 154 | ||
152 | void OnIncomingInstantMessage(GridInstantMessage im) | 155 | void OnIncomingInstantMessage(GridInstantMessage im) |
153 | { | 156 | { |
154 | if (im.dialog == (byte)InstantMessageDialog.RequestTeleport) | 157 | if (im.dialog == (byte)InstantMessageDialog.RequestTeleport |
158 | || im.dialog == (byte)InstantMessageDialog.GodLikeRequestTeleport) | ||
155 | { | 159 | { |
156 | UUID sessionID = new UUID(im.imSessionID); | 160 | UUID sessionID = new UUID(im.imSessionID); |
157 | 161 | ||
diff --git a/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs b/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs index f3adb95..0c64f19 100644 --- a/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs | |||
@@ -165,7 +165,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure | |||
165 | (uint)presence.AbsolutePosition.Y, | 165 | (uint)presence.AbsolutePosition.Y, |
166 | (uint)presence.AbsolutePosition.Z + 2); | 166 | (uint)presence.AbsolutePosition.Z + 2); |
167 | 167 | ||
168 | m_log.DebugFormat("[LURE]: TP invite with message {0}", message); | 168 | m_log.DebugFormat("TP invite with message {0}, type {1}", message, lureType); |
169 | 169 | ||
170 | GridInstantMessage m; | 170 | GridInstantMessage m; |
171 | 171 | ||
diff --git a/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs b/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs index 7f30e5a..2eb9bfb 100644 --- a/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs +++ b/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs | |||
@@ -55,7 +55,7 @@ namespace OpenSim.Region.CoreModules.Framework | |||
55 | /// <summary> | 55 | /// <summary> |
56 | /// Each agent has its own capabilities handler. | 56 | /// Each agent has its own capabilities handler. |
57 | /// </summary> | 57 | /// </summary> |
58 | protected Dictionary<UUID, Caps> m_capsObjects = new Dictionary<UUID, Caps>(); | 58 | protected Dictionary<uint, Caps> m_capsObjects = new Dictionary<uint, Caps>(); |
59 | 59 | ||
60 | protected Dictionary<UUID, string> capsPaths = new Dictionary<UUID, string>(); | 60 | protected Dictionary<UUID, string> capsPaths = new Dictionary<UUID, string>(); |
61 | protected Dictionary<UUID, Dictionary<ulong, string>> childrenSeeds | 61 | protected Dictionary<UUID, Dictionary<ulong, string>> childrenSeeds |
@@ -100,7 +100,7 @@ namespace OpenSim.Region.CoreModules.Framework | |||
100 | get { return null; } | 100 | get { return null; } |
101 | } | 101 | } |
102 | 102 | ||
103 | public void CreateCaps(UUID agentId) | 103 | public void CreateCaps(UUID agentId, uint circuitCode) |
104 | { | 104 | { |
105 | int flags = m_scene.GetUserFlags(agentId); | 105 | int flags = m_scene.GetUserFlags(agentId); |
106 | if (m_scene.RegionInfo.EstateSettings.IsBanned(agentId, flags)) | 106 | if (m_scene.RegionInfo.EstateSettings.IsBanned(agentId, flags)) |
@@ -108,9 +108,9 @@ namespace OpenSim.Region.CoreModules.Framework | |||
108 | 108 | ||
109 | String capsObjectPath = GetCapsPath(agentId); | 109 | String capsObjectPath = GetCapsPath(agentId); |
110 | 110 | ||
111 | if (m_capsObjects.ContainsKey(agentId)) | 111 | if (m_capsObjects.ContainsKey(circuitCode)) |
112 | { | 112 | { |
113 | Caps oldCaps = m_capsObjects[agentId]; | 113 | Caps oldCaps = m_capsObjects[circuitCode]; |
114 | 114 | ||
115 | m_log.DebugFormat( | 115 | m_log.DebugFormat( |
116 | "[CAPS]: Recreating caps for agent {0}. Old caps path {1}, new caps path {2}. ", | 116 | "[CAPS]: Recreating caps for agent {0}. Old caps path {1}, new caps path {2}. ", |
@@ -125,12 +125,12 @@ namespace OpenSim.Region.CoreModules.Framework | |||
125 | (MainServer.Instance == null) ? 0: MainServer.Instance.Port, | 125 | (MainServer.Instance == null) ? 0: MainServer.Instance.Port, |
126 | capsObjectPath, agentId, m_scene.RegionInfo.RegionName); | 126 | capsObjectPath, agentId, m_scene.RegionInfo.RegionName); |
127 | 127 | ||
128 | m_capsObjects[agentId] = caps; | 128 | m_capsObjects[circuitCode] = caps; |
129 | 129 | ||
130 | m_scene.EventManager.TriggerOnRegisterCaps(agentId, caps); | 130 | m_scene.EventManager.TriggerOnRegisterCaps(agentId, caps); |
131 | } | 131 | } |
132 | 132 | ||
133 | public void RemoveCaps(UUID agentId) | 133 | public void RemoveCaps(UUID agentId, uint circuitCode) |
134 | { | 134 | { |
135 | if (childrenSeeds.ContainsKey(agentId)) | 135 | if (childrenSeeds.ContainsKey(agentId)) |
136 | { | 136 | { |
@@ -139,11 +139,11 @@ namespace OpenSim.Region.CoreModules.Framework | |||
139 | 139 | ||
140 | lock (m_capsObjects) | 140 | lock (m_capsObjects) |
141 | { | 141 | { |
142 | if (m_capsObjects.ContainsKey(agentId)) | 142 | if (m_capsObjects.ContainsKey(circuitCode)) |
143 | { | 143 | { |
144 | m_capsObjects[agentId].DeregisterHandlers(); | 144 | m_capsObjects[circuitCode].DeregisterHandlers(); |
145 | m_scene.EventManager.TriggerOnDeregisterCaps(agentId, m_capsObjects[agentId]); | 145 | m_scene.EventManager.TriggerOnDeregisterCaps(agentId, m_capsObjects[circuitCode]); |
146 | m_capsObjects.Remove(agentId); | 146 | m_capsObjects.Remove(circuitCode); |
147 | } | 147 | } |
148 | else | 148 | else |
149 | { | 149 | { |
@@ -154,19 +154,30 @@ namespace OpenSim.Region.CoreModules.Framework | |||
154 | } | 154 | } |
155 | } | 155 | } |
156 | 156 | ||
157 | public Caps GetCapsForUser(UUID agentId) | 157 | public Caps GetCapsForUser(uint circuitCode) |
158 | { | 158 | { |
159 | lock (m_capsObjects) | 159 | lock (m_capsObjects) |
160 | { | 160 | { |
161 | if (m_capsObjects.ContainsKey(agentId)) | 161 | if (m_capsObjects.ContainsKey(circuitCode)) |
162 | { | 162 | { |
163 | return m_capsObjects[agentId]; | 163 | return m_capsObjects[circuitCode]; |
164 | } | 164 | } |
165 | } | 165 | } |
166 | 166 | ||
167 | return null; | 167 | return null; |
168 | } | 168 | } |
169 | 169 | ||
170 | public void ActivateCaps(uint circuitCode) | ||
171 | { | ||
172 | lock (m_capsObjects) | ||
173 | { | ||
174 | if (m_capsObjects.ContainsKey(circuitCode)) | ||
175 | { | ||
176 | m_capsObjects[circuitCode].Activate(); | ||
177 | } | ||
178 | } | ||
179 | } | ||
180 | |||
170 | public void SetAgentCapsSeeds(AgentCircuitData agent) | 181 | public void SetAgentCapsSeeds(AgentCircuitData agent) |
171 | { | 182 | { |
172 | capsPaths[agent.AgentID] = agent.CapsPath; | 183 | capsPaths[agent.AgentID] = agent.CapsPath; |
@@ -237,9 +248,9 @@ namespace OpenSim.Region.CoreModules.Framework | |||
237 | StringBuilder caps = new StringBuilder(); | 248 | StringBuilder caps = new StringBuilder(); |
238 | caps.AppendFormat("Region {0}:\n", m_scene.RegionInfo.RegionName); | 249 | caps.AppendFormat("Region {0}:\n", m_scene.RegionInfo.RegionName); |
239 | 250 | ||
240 | foreach (KeyValuePair<UUID, Caps> kvp in m_capsObjects) | 251 | foreach (KeyValuePair<uint, Caps> kvp in m_capsObjects) |
241 | { | 252 | { |
242 | caps.AppendFormat("** User {0}:\n", kvp.Key); | 253 | caps.AppendFormat("** Circuit {0}:\n", kvp.Key); |
243 | 254 | ||
244 | for (IDictionaryEnumerator kvp2 = kvp.Value.CapsHandlers.GetCapsDetails(false).GetEnumerator(); kvp2.MoveNext(); ) | 255 | for (IDictionaryEnumerator kvp2 = kvp.Value.CapsHandlers.GetCapsDetails(false).GetEnumerator(); kvp2.MoveNext(); ) |
245 | { | 256 | { |
diff --git a/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs b/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs new file mode 100644 index 0000000..1f1568f --- /dev/null +++ b/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs | |||
@@ -0,0 +1,119 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Reflection; | ||
31 | using log4net; | ||
32 | using Mono.Addins; | ||
33 | using Nini.Config; | ||
34 | using OpenMetaverse; | ||
35 | using OpenMetaverse.Packets; | ||
36 | using OpenMetaverse.StructuredData; | ||
37 | using OpenSim.Framework; | ||
38 | using OpenSim.Region.Framework; | ||
39 | using OpenSim.Region.Framework.Interfaces; | ||
40 | using OpenSim.Region.Framework.Scenes; | ||
41 | |||
42 | namespace OpenSim.Region.CoreModules.Framework.DynamicAttributes.DAExampleModule | ||
43 | { | ||
44 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DAExampleModule")] | ||
45 | public class DAExampleModule : INonSharedRegionModule | ||
46 | { | ||
47 | // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
48 | |||
49 | private static readonly bool ENABLED = false; // enable for testing | ||
50 | |||
51 | public const string DANamespace = "DAExample Module"; | ||
52 | |||
53 | protected Scene m_scene; | ||
54 | protected IDialogModule m_dialogMod; | ||
55 | |||
56 | public string Name { get { return "DAExample Module"; } } | ||
57 | public Type ReplaceableInterface { get { return null; } } | ||
58 | |||
59 | public void Initialise(IConfigSource source) {} | ||
60 | |||
61 | public void AddRegion(Scene scene) | ||
62 | { | ||
63 | if (ENABLED) | ||
64 | { | ||
65 | m_scene = scene; | ||
66 | m_scene.EventManager.OnSceneGroupMove += OnSceneGroupMove; | ||
67 | m_dialogMod = m_scene.RequestModuleInterface<IDialogModule>(); | ||
68 | } | ||
69 | } | ||
70 | |||
71 | public void RemoveRegion(Scene scene) | ||
72 | { | ||
73 | if (ENABLED) | ||
74 | { | ||
75 | m_scene.EventManager.OnSceneGroupMove -= OnSceneGroupMove; | ||
76 | } | ||
77 | } | ||
78 | |||
79 | public void RegionLoaded(Scene scene) {} | ||
80 | |||
81 | public void Close() | ||
82 | { | ||
83 | RemoveRegion(m_scene); | ||
84 | } | ||
85 | |||
86 | protected bool OnSceneGroupMove(UUID groupId, Vector3 delta) | ||
87 | { | ||
88 | OSDMap attrs = null; | ||
89 | SceneObjectPart sop = m_scene.GetSceneObjectPart(groupId); | ||
90 | |||
91 | if (sop == null) | ||
92 | return true; | ||
93 | |||
94 | if (!sop.DynAttrs.TryGetValue(DANamespace, out attrs)) | ||
95 | attrs = new OSDMap(); | ||
96 | |||
97 | OSDInteger newValue; | ||
98 | |||
99 | // We have to lock on the entire dynamic attributes map to avoid race conditions with serialization code. | ||
100 | lock (sop.DynAttrs) | ||
101 | { | ||
102 | if (!attrs.ContainsKey("moves")) | ||
103 | newValue = new OSDInteger(1); | ||
104 | else | ||
105 | newValue = new OSDInteger(attrs["moves"].AsInteger() + 1); | ||
106 | |||
107 | attrs["moves"] = newValue; | ||
108 | |||
109 | sop.DynAttrs[DANamespace] = attrs; | ||
110 | } | ||
111 | |||
112 | sop.ParentGroup.HasGroupChanged = true; | ||
113 | |||
114 | m_dialogMod.SendGeneralAlert(string.Format("{0} {1} moved {2} times", sop.Name, sop.UUID, newValue)); | ||
115 | |||
116 | return true; | ||
117 | } | ||
118 | } | ||
119 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DOExampleModule.cs b/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DOExampleModule.cs new file mode 100644 index 0000000..650aa35 --- /dev/null +++ b/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DOExampleModule.cs | |||
@@ -0,0 +1,139 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Reflection; | ||
31 | using log4net; | ||
32 | using Mono.Addins; | ||
33 | using Nini.Config; | ||
34 | using OpenMetaverse; | ||
35 | using OpenMetaverse.Packets; | ||
36 | using OpenMetaverse.StructuredData; | ||
37 | using OpenSim.Framework; | ||
38 | using OpenSim.Region.Framework; | ||
39 | using OpenSim.Region.CoreModules.Framework.DynamicAttributes.DAExampleModule; | ||
40 | using OpenSim.Region.Framework.Interfaces; | ||
41 | using OpenSim.Region.Framework.Scenes; | ||
42 | |||
43 | namespace OpenSim.Region.Framework.DynamicAttributes.DOExampleModule | ||
44 | { | ||
45 | /// <summary> | ||
46 | /// Example module for experimenting with and demonstrating dynamic object ideas. | ||
47 | /// </summary> | ||
48 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DOExampleModule")] | ||
49 | public class DOExampleModule : INonSharedRegionModule | ||
50 | { | ||
51 | public class MyObject | ||
52 | { | ||
53 | public int Moves { get; set; } | ||
54 | |||
55 | public MyObject(int moves) | ||
56 | { | ||
57 | Moves = moves; | ||
58 | } | ||
59 | } | ||
60 | |||
61 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
62 | |||
63 | private static readonly bool ENABLED = false; // enable for testing | ||
64 | |||
65 | private Scene m_scene; | ||
66 | private IDialogModule m_dialogMod; | ||
67 | |||
68 | public string Name { get { return "DOExample Module"; } } | ||
69 | public Type ReplaceableInterface { get { return null; } } | ||
70 | |||
71 | public void Initialise(IConfigSource source) {} | ||
72 | |||
73 | public void AddRegion(Scene scene) | ||
74 | { | ||
75 | if (ENABLED) | ||
76 | { | ||
77 | m_scene = scene; | ||
78 | m_scene.EventManager.OnObjectAddedToScene += OnObjectAddedToScene; | ||
79 | m_scene.EventManager.OnSceneGroupMove += OnSceneGroupMove; | ||
80 | m_dialogMod = m_scene.RequestModuleInterface<IDialogModule>(); | ||
81 | } | ||
82 | } | ||
83 | |||
84 | public void RemoveRegion(Scene scene) | ||
85 | { | ||
86 | if (ENABLED) | ||
87 | { | ||
88 | m_scene.EventManager.OnSceneGroupMove -= OnSceneGroupMove; | ||
89 | } | ||
90 | } | ||
91 | |||
92 | public void RegionLoaded(Scene scene) {} | ||
93 | |||
94 | public void Close() | ||
95 | { | ||
96 | RemoveRegion(m_scene); | ||
97 | } | ||
98 | |||
99 | private void OnObjectAddedToScene(SceneObjectGroup so) | ||
100 | { | ||
101 | SceneObjectPart rootPart = so.RootPart; | ||
102 | |||
103 | OSDMap attrs; | ||
104 | |||
105 | int movesSoFar = 0; | ||
106 | |||
107 | // Console.WriteLine("Here for {0}", so.Name); | ||
108 | |||
109 | if (rootPart.DynAttrs.TryGetValue(DAExampleModule.DANamespace, out attrs)) | ||
110 | { | ||
111 | movesSoFar = attrs["moves"].AsInteger(); | ||
112 | |||
113 | m_log.DebugFormat( | ||
114 | "[DO EXAMPLE MODULE]: Found saved moves {0} for {1} in {2}", movesSoFar, so.Name, m_scene.Name); | ||
115 | } | ||
116 | |||
117 | rootPart.DynObjs.Add(Name, new MyObject(movesSoFar)); | ||
118 | } | ||
119 | |||
120 | private bool OnSceneGroupMove(UUID groupId, Vector3 delta) | ||
121 | { | ||
122 | SceneObjectGroup so = m_scene.GetSceneObjectGroup(groupId); | ||
123 | |||
124 | if (so == null) | ||
125 | return true; | ||
126 | |||
127 | object rawObj = so.RootPart.DynObjs.Get(Name); | ||
128 | |||
129 | if (rawObj != null) | ||
130 | { | ||
131 | MyObject myObj = (MyObject)rawObj; | ||
132 | |||
133 | m_dialogMod.SendGeneralAlert(string.Format("{0} {1} moved {2} times", so.Name, so.UUID, ++myObj.Moves)); | ||
134 | } | ||
135 | |||
136 | return true; | ||
137 | } | ||
138 | } | ||
139 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index cb09047..b70aeb7 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs | |||
@@ -33,6 +33,7 @@ using System.Threading; | |||
33 | using OpenSim.Framework; | 33 | using OpenSim.Framework; |
34 | using OpenSim.Framework.Capabilities; | 34 | using OpenSim.Framework.Capabilities; |
35 | using OpenSim.Framework.Client; | 35 | using OpenSim.Framework.Client; |
36 | using OpenSim.Framework.Monitoring; | ||
36 | using OpenSim.Region.Framework.Interfaces; | 37 | using OpenSim.Region.Framework.Interfaces; |
37 | using OpenSim.Region.Framework.Scenes; | 38 | using OpenSim.Region.Framework.Scenes; |
38 | using OpenSim.Region.Physics.Manager; | 39 | using OpenSim.Region.Physics.Manager; |
@@ -66,6 +67,42 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
66 | /// </summary> | 67 | /// </summary> |
67 | public bool WaitForAgentArrivedAtDestination { get; set; } | 68 | public bool WaitForAgentArrivedAtDestination { get; set; } |
68 | 69 | ||
70 | /// <summary> | ||
71 | /// If true then we ask the viewer to disable teleport cancellation and ignore teleport requests. | ||
72 | /// </summary> | ||
73 | /// <remarks> | ||
74 | /// This is useful in situations where teleport is very likely to always succeed and we want to avoid a | ||
75 | /// situation where avatars can be come 'stuck' due to a failed teleport cancellation. Unfortunately, the | ||
76 | /// nature of the teleport protocol makes it extremely difficult (maybe impossible) to make teleport | ||
77 | /// cancellation consistently suceed. | ||
78 | /// </remarks> | ||
79 | public bool DisableInterRegionTeleportCancellation { get; set; } | ||
80 | |||
81 | /// <summary> | ||
82 | /// Number of times inter-region teleport was attempted. | ||
83 | /// </summary> | ||
84 | private Stat m_interRegionTeleportAttempts; | ||
85 | |||
86 | /// <summary> | ||
87 | /// Number of times inter-region teleport was aborted (due to simultaneous client logout). | ||
88 | /// </summary> | ||
89 | private Stat m_interRegionTeleportAborts; | ||
90 | |||
91 | /// <summary> | ||
92 | /// Number of times inter-region teleport was successfully cancelled by the client. | ||
93 | /// </summary> | ||
94 | private Stat m_interRegionTeleportCancels; | ||
95 | |||
96 | /// <summary> | ||
97 | /// Number of times inter-region teleport failed due to server/client/network problems (e.g. viewer failed to | ||
98 | /// connect with destination region). | ||
99 | /// </summary> | ||
100 | /// <remarks> | ||
101 | /// This is not necessarily a problem for this simulator - in open-grid/hg conditions, viewer connectivity to | ||
102 | /// destination simulator is unknown. | ||
103 | /// </remarks> | ||
104 | private Stat m_interRegionTeleportFailures; | ||
105 | |||
69 | protected bool m_Enabled = false; | 106 | protected bool m_Enabled = false; |
70 | 107 | ||
71 | public Scene Scene { get; private set; } | 108 | public Scene Scene { get; private set; } |
@@ -80,6 +117,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
80 | new ExpiringCache<UUID, ExpiringCache<ulong, DateTime>>(); | 117 | new ExpiringCache<UUID, ExpiringCache<ulong, DateTime>>(); |
81 | 118 | ||
82 | private IEventQueue m_eqModule; | 119 | private IEventQueue m_eqModule; |
120 | private IRegionCombinerModule m_regionCombinerModule; | ||
83 | 121 | ||
84 | #region ISharedRegionModule | 122 | #region ISharedRegionModule |
85 | 123 | ||
@@ -116,6 +154,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
116 | IConfig transferConfig = source.Configs["EntityTransfer"]; | 154 | IConfig transferConfig = source.Configs["EntityTransfer"]; |
117 | if (transferConfig != null) | 155 | if (transferConfig != null) |
118 | { | 156 | { |
157 | DisableInterRegionTeleportCancellation | ||
158 | = transferConfig.GetBoolean("DisableInterRegionTeleportCancellation", false); | ||
159 | |||
119 | WaitForAgentArrivedAtDestination | 160 | WaitForAgentArrivedAtDestination |
120 | = transferConfig.GetBoolean("wait_for_callback", WaitForAgentArrivedAtDestinationDefault); | 161 | = transferConfig.GetBoolean("wait_for_callback", WaitForAgentArrivedAtDestinationDefault); |
121 | 162 | ||
@@ -142,6 +183,60 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
142 | 183 | ||
143 | Scene = scene; | 184 | Scene = scene; |
144 | 185 | ||
186 | m_interRegionTeleportAttempts = | ||
187 | new Stat( | ||
188 | "InterRegionTeleportAttempts", | ||
189 | "Number of inter-region teleports attempted.", | ||
190 | "This does not count attempts which failed due to pre-conditions (e.g. target simulator refused access).\n" | ||
191 | + "You can get successfully teleports by subtracting aborts, cancels and teleport failures from this figure.", | ||
192 | "", | ||
193 | "entitytransfer", | ||
194 | Scene.Name, | ||
195 | StatType.Push, | ||
196 | null, | ||
197 | StatVerbosity.Debug); | ||
198 | |||
199 | m_interRegionTeleportAborts = | ||
200 | new Stat( | ||
201 | "InterRegionTeleportAborts", | ||
202 | "Number of inter-region teleports aborted due to client actions.", | ||
203 | "The chief action is simultaneous logout whilst teleporting.", | ||
204 | "", | ||
205 | "entitytransfer", | ||
206 | Scene.Name, | ||
207 | StatType.Push, | ||
208 | null, | ||
209 | StatVerbosity.Debug); | ||
210 | |||
211 | m_interRegionTeleportCancels = | ||
212 | new Stat( | ||
213 | "InterRegionTeleportCancels", | ||
214 | "Number of inter-region teleports cancelled by the client.", | ||
215 | null, | ||
216 | "", | ||
217 | "entitytransfer", | ||
218 | Scene.Name, | ||
219 | StatType.Push, | ||
220 | null, | ||
221 | StatVerbosity.Debug); | ||
222 | |||
223 | m_interRegionTeleportFailures = | ||
224 | new Stat( | ||
225 | "InterRegionTeleportFailures", | ||
226 | "Number of inter-region teleports that failed due to server/client/network issues.", | ||
227 | "This number may not be very helpful in open-grid/hg situations as the network connectivity/quality of destinations is uncontrollable.", | ||
228 | "", | ||
229 | "entitytransfer", | ||
230 | Scene.Name, | ||
231 | StatType.Push, | ||
232 | null, | ||
233 | StatVerbosity.Debug); | ||
234 | |||
235 | StatsManager.RegisterStat(m_interRegionTeleportAttempts); | ||
236 | StatsManager.RegisterStat(m_interRegionTeleportAborts); | ||
237 | StatsManager.RegisterStat(m_interRegionTeleportCancels); | ||
238 | StatsManager.RegisterStat(m_interRegionTeleportFailures); | ||
239 | |||
145 | scene.RegisterModuleInterface<IEntityTransferModule>(this); | 240 | scene.RegisterModuleInterface<IEntityTransferModule>(this); |
146 | scene.EventManager.OnNewClient += OnNewClient; | 241 | scene.EventManager.OnNewClient += OnNewClient; |
147 | } | 242 | } |
@@ -150,12 +245,25 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
150 | { | 245 | { |
151 | client.OnTeleportHomeRequest += TriggerTeleportHome; | 246 | client.OnTeleportHomeRequest += TriggerTeleportHome; |
152 | client.OnTeleportLandmarkRequest += RequestTeleportLandmark; | 247 | client.OnTeleportLandmarkRequest += RequestTeleportLandmark; |
153 | client.OnTeleportCancel += TeleportCancel; | 248 | |
249 | if (!DisableInterRegionTeleportCancellation) | ||
250 | client.OnTeleportCancel += OnClientCancelTeleport; | ||
251 | |||
252 | client.OnConnectionClosed += OnConnectionClosed; | ||
154 | } | 253 | } |
155 | 254 | ||
156 | public virtual void Close() {} | 255 | public virtual void Close() {} |
157 | 256 | ||
158 | public virtual void RemoveRegion(Scene scene) {} | 257 | public virtual void RemoveRegion(Scene scene) |
258 | { | ||
259 | if (m_Enabled) | ||
260 | { | ||
261 | StatsManager.DeregisterStat(m_interRegionTeleportAttempts); | ||
262 | StatsManager.DeregisterStat(m_interRegionTeleportAborts); | ||
263 | StatsManager.DeregisterStat(m_interRegionTeleportCancels); | ||
264 | StatsManager.DeregisterStat(m_interRegionTeleportFailures); | ||
265 | } | ||
266 | } | ||
159 | 267 | ||
160 | public virtual void RegionLoaded(Scene scene) | 268 | public virtual void RegionLoaded(Scene scene) |
161 | { | 269 | { |
@@ -163,12 +271,33 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
163 | return; | 271 | return; |
164 | 272 | ||
165 | m_eqModule = Scene.RequestModuleInterface<IEventQueue>(); | 273 | m_eqModule = Scene.RequestModuleInterface<IEventQueue>(); |
274 | m_regionCombinerModule = Scene.RequestModuleInterface<IRegionCombinerModule>(); | ||
166 | } | 275 | } |
167 | 276 | ||
168 | #endregion | 277 | #endregion |
169 | 278 | ||
170 | #region Agent Teleports | 279 | #region Agent Teleports |
171 | 280 | ||
281 | private void OnConnectionClosed(IClientAPI client) | ||
282 | { | ||
283 | if (client.IsLoggingOut) | ||
284 | { | ||
285 | m_entityTransferStateMachine.UpdateInTransit(client.AgentId, AgentTransferState.Aborting); | ||
286 | |||
287 | m_log.DebugFormat( | ||
288 | "[ENTITY TRANSFER MODULE]: Aborted teleport request from {0} in {1} due to simultaneous logout", | ||
289 | client.Name, Scene.Name); | ||
290 | } | ||
291 | } | ||
292 | |||
293 | private void OnClientCancelTeleport(IClientAPI client) | ||
294 | { | ||
295 | m_entityTransferStateMachine.UpdateInTransit(client.AgentId, AgentTransferState.Cancelling); | ||
296 | |||
297 | m_log.DebugFormat( | ||
298 | "[ENTITY TRANSFER MODULE]: Received teleport cancel request from {0} in {1}", client.Name, Scene.Name); | ||
299 | } | ||
300 | |||
172 | public void Teleport(ScenePresence sp, ulong regionHandle, Vector3 position, Vector3 lookAt, uint teleportFlags) | 301 | public void Teleport(ScenePresence sp, ulong regionHandle, Vector3 position, Vector3 lookAt, uint teleportFlags) |
173 | { | 302 | { |
174 | if (sp.Scene.Permissions.IsGridGod(sp.UUID)) | 303 | if (sp.Scene.Permissions.IsGridGod(sp.UUID)) |
@@ -180,13 +309,24 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
180 | if (!sp.Scene.Permissions.CanTeleport(sp.UUID)) | 309 | if (!sp.Scene.Permissions.CanTeleport(sp.UUID)) |
181 | return; | 310 | return; |
182 | 311 | ||
183 | // Reset animations; the viewer does that in teleports. | ||
184 | sp.Animator.ResetAnimations(); | ||
185 | |||
186 | string destinationRegionName = "(not found)"; | 312 | string destinationRegionName = "(not found)"; |
187 | 313 | ||
314 | // Record that this agent is in transit so that we can prevent simultaneous requests and do later detection | ||
315 | // of whether the destination region completes the teleport. | ||
316 | if (!m_entityTransferStateMachine.SetInTransit(sp.UUID)) | ||
317 | { | ||
318 | m_log.DebugFormat( | ||
319 | "[ENTITY TRANSFER MODULE]: Ignoring teleport request of {0} {1} to {2}@{3} - agent is already in transit.", | ||
320 | sp.Name, sp.UUID, position, regionHandle); | ||
321 | |||
322 | return; | ||
323 | } | ||
324 | |||
188 | try | 325 | try |
189 | { | 326 | { |
327 | // Reset animations; the viewer does that in teleports. | ||
328 | sp.Animator.ResetAnimations(); | ||
329 | |||
190 | if (regionHandle == sp.Scene.RegionInfo.RegionHandle) | 330 | if (regionHandle == sp.Scene.RegionInfo.RegionHandle) |
191 | { | 331 | { |
192 | destinationRegionName = sp.Scene.RegionInfo.RegionName; | 332 | destinationRegionName = sp.Scene.RegionInfo.RegionName; |
@@ -195,12 +335,17 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
195 | } | 335 | } |
196 | else // Another region possibly in another simulator | 336 | else // Another region possibly in another simulator |
197 | { | 337 | { |
198 | GridRegion finalDestination; | 338 | GridRegion finalDestination = null; |
199 | TeleportAgentToDifferentRegion( | 339 | try |
200 | sp, regionHandle, position, lookAt, teleportFlags, out finalDestination); | 340 | { |
201 | 341 | TeleportAgentToDifferentRegion( | |
202 | if (finalDestination != null) | 342 | sp, regionHandle, position, lookAt, teleportFlags, out finalDestination); |
203 | destinationRegionName = finalDestination.RegionName; | 343 | } |
344 | finally | ||
345 | { | ||
346 | if (finalDestination != null) | ||
347 | destinationRegionName = finalDestination.RegionName; | ||
348 | } | ||
204 | } | 349 | } |
205 | } | 350 | } |
206 | catch (Exception e) | 351 | catch (Exception e) |
@@ -210,11 +355,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
210 | sp.Name, sp.AbsolutePosition, sp.Scene.RegionInfo.RegionName, position, destinationRegionName, | 355 | sp.Name, sp.AbsolutePosition, sp.Scene.RegionInfo.RegionName, position, destinationRegionName, |
211 | e.Message, e.StackTrace); | 356 | e.Message, e.StackTrace); |
212 | 357 | ||
213 | // Make sure that we clear the in-transit flag so that future teleport attempts don't always fail. | ||
214 | m_entityTransferStateMachine.ResetFromTransit(sp.UUID); | ||
215 | |||
216 | sp.ControllingClient.SendTeleportFailed("Internal error"); | 358 | sp.ControllingClient.SendTeleportFailed("Internal error"); |
217 | } | 359 | } |
360 | finally | ||
361 | { | ||
362 | m_entityTransferStateMachine.ResetFromTransit(sp.UUID); | ||
363 | } | ||
218 | } | 364 | } |
219 | 365 | ||
220 | /// <summary> | 366 | /// <summary> |
@@ -230,23 +376,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
230 | "[ENTITY TRANSFER MODULE]: Teleport for {0} to {1} within {2}", | 376 | "[ENTITY TRANSFER MODULE]: Teleport for {0} to {1} within {2}", |
231 | sp.Name, position, sp.Scene.RegionInfo.RegionName); | 377 | sp.Name, position, sp.Scene.RegionInfo.RegionName); |
232 | 378 | ||
233 | if (!m_entityTransferStateMachine.SetInTransit(sp.UUID)) | ||
234 | { | ||
235 | m_log.DebugFormat( | ||
236 | "[ENTITY TRANSFER MODULE]: Ignoring within region teleport request of {0} {1} to {2} - agent is already in transit.", | ||
237 | sp.Name, sp.UUID, position); | ||
238 | |||
239 | return; | ||
240 | } | ||
241 | |||
242 | // Teleport within the same region | 379 | // Teleport within the same region |
243 | if (IsOutsideRegion(sp.Scene, position) || position.Z < 0) | 380 | if (IsOutsideRegion(sp.Scene, position) || position.Z < 0) |
244 | { | 381 | { |
245 | Vector3 emergencyPos = new Vector3(128, 128, 128); | 382 | Vector3 emergencyPos = new Vector3(128, 128, 128); |
246 | 383 | ||
247 | m_log.WarnFormat( | 384 | m_log.WarnFormat( |
248 | "[ENTITY TRANSFER MODULE]: RequestTeleportToLocation() was given an illegal position of {0} for avatar {1}, {2}. Substituting {3}", | 385 | "[ENTITY TRANSFER MODULE]: RequestTeleportToLocation() was given an illegal position of {0} for avatar {1}, {2} in {3}. Substituting {4}", |
249 | position, sp.Name, sp.UUID, emergencyPos); | 386 | position, sp.Name, sp.UUID, Scene.Name, emergencyPos); |
250 | 387 | ||
251 | position = emergencyPos; | 388 | position = emergencyPos; |
252 | } | 389 | } |
@@ -287,7 +424,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
287 | } | 424 | } |
288 | 425 | ||
289 | m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); | 426 | m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); |
290 | m_entityTransferStateMachine.ResetFromTransit(sp.UUID); | ||
291 | } | 427 | } |
292 | 428 | ||
293 | /// <summary> | 429 | /// <summary> |
@@ -341,7 +477,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
341 | // | 477 | // |
342 | // This is it | 478 | // This is it |
343 | // | 479 | // |
344 | DoTeleport(sp, reg, finalDestination, position, lookAt, teleportFlags); | 480 | DoTeleportInternal(sp, reg, finalDestination, position, lookAt, teleportFlags); |
345 | // | 481 | // |
346 | // | 482 | // |
347 | // | 483 | // |
@@ -396,27 +532,54 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
396 | && Math.Abs(sourceRegion.RegionLocY - destRegion.RegionCoordY) <= MaxTransferDistance; | 532 | && Math.Abs(sourceRegion.RegionLocY - destRegion.RegionCoordY) <= MaxTransferDistance; |
397 | } | 533 | } |
398 | 534 | ||
535 | /// <summary> | ||
536 | /// Wraps DoTeleportInternal() and manages the transfer state. | ||
537 | /// </summary> | ||
399 | public void DoTeleport( | 538 | public void DoTeleport( |
400 | ScenePresence sp, GridRegion reg, GridRegion finalDestination, | 539 | ScenePresence sp, GridRegion reg, GridRegion finalDestination, |
401 | Vector3 position, Vector3 lookAt, uint teleportFlags) | 540 | Vector3 position, Vector3 lookAt, uint teleportFlags) |
402 | { | 541 | { |
403 | // Record that this agent is in transit so that we can prevent simultaneous requests and do later detection | 542 | // Record that this agent is in transit so that we can prevent simultaneous requests and do later detection |
404 | // of whether the destination region completes the teleport. | 543 | // of whether the destination region completes the teleport. |
405 | m_entityTransferStateMachine.SetInTransit(sp.UUID); | 544 | if (!m_entityTransferStateMachine.SetInTransit(sp.UUID)) |
406 | // if (!m_entityTransferStateMachine.SetInTransit(sp.UUID)) | 545 | { |
407 | // { | 546 | m_log.DebugFormat( |
408 | // m_log.DebugFormat( | 547 | "[ENTITY TRANSFER MODULE]: Ignoring teleport request of {0} {1} to {2} ({3}) {4}/{5} - agent is already in transit.", |
409 | // "[ENTITY TRANSFER MODULE]: Ignoring teleport request of {0} {1} to {2} ({3}) {4}/{5} - agent is already in transit.", | 548 | sp.Name, sp.UUID, reg.ServerURI, finalDestination.ServerURI, finalDestination.RegionName, position); |
410 | // sp.Name, sp.UUID, reg.ServerURI, finalDestination.ServerURI, finalDestination.RegionName, position); | ||
411 | // | ||
412 | // return; | ||
413 | // } | ||
414 | 549 | ||
415 | if (reg == null || finalDestination == null) | 550 | return; |
551 | } | ||
552 | |||
553 | try | ||
554 | { | ||
555 | DoTeleportInternal(sp, reg, finalDestination, position, lookAt, teleportFlags); | ||
556 | } | ||
557 | catch (Exception e) | ||
558 | { | ||
559 | m_log.ErrorFormat( | ||
560 | "[ENTITY TRANSFER MODULE]: Exception on teleport of {0} from {1}@{2} to {3}@{4}: {5}{6}", | ||
561 | sp.Name, sp.AbsolutePosition, sp.Scene.RegionInfo.RegionName, position, finalDestination.RegionName, | ||
562 | e.Message, e.StackTrace); | ||
563 | |||
564 | sp.ControllingClient.SendTeleportFailed("Internal error"); | ||
565 | } | ||
566 | finally | ||
416 | { | 567 | { |
417 | sp.ControllingClient.SendTeleportFailed("Unable to locate destination"); | ||
418 | m_entityTransferStateMachine.ResetFromTransit(sp.UUID); | 568 | m_entityTransferStateMachine.ResetFromTransit(sp.UUID); |
569 | } | ||
570 | } | ||
419 | 571 | ||
572 | /// <summary> | ||
573 | /// Teleports the agent to another region. | ||
574 | /// This method doesn't manage the transfer state; the caller must do that. | ||
575 | /// </summary> | ||
576 | private void DoTeleportInternal( | ||
577 | ScenePresence sp, GridRegion reg, GridRegion finalDestination, | ||
578 | Vector3 position, Vector3 lookAt, uint teleportFlags) | ||
579 | { | ||
580 | if (reg == null || finalDestination == null) | ||
581 | { | ||
582 | sp.ControllingClient.SendTeleportFailed("Unable to locate destination"); | ||
420 | return; | 583 | return; |
421 | } | 584 | } |
422 | 585 | ||
@@ -436,8 +599,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
436 | sourceRegion.RegionName, sourceRegion.RegionLocX, sourceRegion.RegionLocY, | 599 | sourceRegion.RegionName, sourceRegion.RegionLocX, sourceRegion.RegionLocY, |
437 | MaxTransferDistance)); | 600 | MaxTransferDistance)); |
438 | 601 | ||
439 | m_entityTransferStateMachine.ResetFromTransit(sp.UUID); | ||
440 | |||
441 | return; | 602 | return; |
442 | } | 603 | } |
443 | 604 | ||
@@ -455,7 +616,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
455 | if (endPoint == null || endPoint.Address == null) | 616 | if (endPoint == null || endPoint.Address == null) |
456 | { | 617 | { |
457 | sp.ControllingClient.SendTeleportFailed("Remote Region appears to be down"); | 618 | sp.ControllingClient.SendTeleportFailed("Remote Region appears to be down"); |
458 | m_entityTransferStateMachine.ResetFromTransit(sp.UUID); | ||
459 | 619 | ||
460 | return; | 620 | return; |
461 | } | 621 | } |
@@ -465,19 +625,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
465 | "[ENTITY TRANSFER MODULE]: Failed validation of all attachments for teleport of {0} from {1} to {2}. Continuing.", | 625 | "[ENTITY TRANSFER MODULE]: Failed validation of all attachments for teleport of {0} from {1} to {2}. Continuing.", |
466 | sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName); | 626 | sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName); |
467 | 627 | ||
468 | // if (!sp.ValidateAttachments()) | ||
469 | // { | ||
470 | // sp.ControllingClient.SendTeleportFailed("Inconsistent attachment state"); | ||
471 | // return; | ||
472 | // } | ||
473 | |||
474 | string reason; | 628 | string reason; |
475 | string version; | 629 | string version; |
476 | if (!Scene.SimulationService.QueryAccess( | 630 | if (!Scene.SimulationService.QueryAccess( |
477 | finalDestination, sp.ControllingClient.AgentId, Vector3.Zero, out version, out reason)) | 631 | finalDestination, sp.ControllingClient.AgentId, Vector3.Zero, out version, out reason)) |
478 | { | 632 | { |
479 | sp.ControllingClient.SendTeleportFailed(reason); | 633 | sp.ControllingClient.SendTeleportFailed(reason); |
480 | m_entityTransferStateMachine.ResetFromTransit(sp.UUID); | ||
481 | 634 | ||
482 | m_log.DebugFormat( | 635 | m_log.DebugFormat( |
483 | "[ENTITY TRANSFER MODULE]: {0} was stopped from teleporting from {1} to {2} because {3}", | 636 | "[ENTITY TRANSFER MODULE]: {0} was stopped from teleporting from {1} to {2} because {3}", |
@@ -486,6 +639,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
486 | return; | 639 | return; |
487 | } | 640 | } |
488 | 641 | ||
642 | // Before this point, teleport 'failure' is due to checkable pre-conditions such as whether the target | ||
643 | // simulator can be found and is explicitly prepared to allow access. Therefore, we will not count these | ||
644 | // as server attempts. | ||
645 | m_interRegionTeleportAttempts.Value++; | ||
646 | |||
489 | m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Destination is running version {0}", version); | 647 | m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Destination is running version {0}", version); |
490 | 648 | ||
491 | // Fixing a bug where teleporting while sitting results in the avatar ending up removed from | 649 | // Fixing a bug where teleporting while sitting results in the avatar ending up removed from |
@@ -495,6 +653,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
495 | else if (sp.Flying) | 653 | else if (sp.Flying) |
496 | teleportFlags |= (uint)TeleportFlags.IsFlying; | 654 | teleportFlags |= (uint)TeleportFlags.IsFlying; |
497 | 655 | ||
656 | if (DisableInterRegionTeleportCancellation) | ||
657 | teleportFlags |= (uint)TeleportFlags.DisableCancel; | ||
658 | |||
498 | // At least on LL 3.3.4, this is not strictly necessary - a teleport will succeed without sending this to | 659 | // At least on LL 3.3.4, this is not strictly necessary - a teleport will succeed without sending this to |
499 | // the viewer. However, it might mean that the viewer does not see the black teleport screen (untested). | 660 | // the viewer. However, it might mean that the viewer does not see the black teleport screen (untested). |
500 | sp.ControllingClient.SendTeleportStart(teleportFlags); | 661 | sp.ControllingClient.SendTeleportStart(teleportFlags); |
@@ -531,11 +692,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
531 | } | 692 | } |
532 | 693 | ||
533 | // Let's create an agent there if one doesn't exist yet. | 694 | // Let's create an agent there if one doesn't exist yet. |
695 | // NOTE: logout will always be false for a non-HG teleport. | ||
534 | bool logout = false; | 696 | bool logout = false; |
535 | if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason, out logout)) | 697 | if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason, out logout)) |
536 | { | 698 | { |
699 | m_interRegionTeleportFailures.Value++; | ||
700 | |||
537 | sp.ControllingClient.SendTeleportFailed(String.Format("Teleport refused: {0}", reason)); | 701 | sp.ControllingClient.SendTeleportFailed(String.Format("Teleport refused: {0}", reason)); |
538 | m_entityTransferStateMachine.ResetFromTransit(sp.UUID); | ||
539 | 702 | ||
540 | m_log.DebugFormat( | 703 | m_log.DebugFormat( |
541 | "[ENTITY TRANSFER MODULE]: Teleport of {0} from {1} to {2} was refused because {3}", | 704 | "[ENTITY TRANSFER MODULE]: Teleport of {0} from {1} to {2} was refused because {3}", |
@@ -544,6 +707,27 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
544 | return; | 707 | return; |
545 | } | 708 | } |
546 | 709 | ||
710 | if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Cancelling) | ||
711 | { | ||
712 | m_interRegionTeleportCancels.Value++; | ||
713 | |||
714 | m_log.DebugFormat( | ||
715 | "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after CreateAgent on client request", | ||
716 | sp.Name, finalDestination.RegionName, sp.Scene.Name); | ||
717 | |||
718 | return; | ||
719 | } | ||
720 | else if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting) | ||
721 | { | ||
722 | m_interRegionTeleportAborts.Value++; | ||
723 | |||
724 | m_log.DebugFormat( | ||
725 | "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after CreateAgent due to previous client close.", | ||
726 | sp.Name, finalDestination.RegionName, sp.Scene.Name); | ||
727 | |||
728 | return; | ||
729 | } | ||
730 | |||
547 | // Past this point we have to attempt clean up if the teleport fails, so update transfer state. | 731 | // Past this point we have to attempt clean up if the teleport fails, so update transfer state. |
548 | m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring); | 732 | m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring); |
549 | 733 | ||
@@ -553,6 +737,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
553 | IClientIPEndpoint ipepClient; | 737 | IClientIPEndpoint ipepClient; |
554 | if (NeedsNewAgent(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY)) | 738 | if (NeedsNewAgent(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY)) |
555 | { | 739 | { |
740 | m_log.DebugFormat( | ||
741 | "[ENTITY TRANSFER MODULE]: Determined that region {0} at {1},{2} needs new child agent for incoming agent {3} from {4}", | ||
742 | finalDestination.RegionName, newRegionX, newRegionY, sp.Name, Scene.Name); | ||
743 | |||
556 | //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Creating agent..."); | 744 | //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Creating agent..."); |
557 | #region IP Translation for NAT | 745 | #region IP Translation for NAT |
558 | // Uses ipepClient above | 746 | // Uses ipepClient above |
@@ -565,11 +753,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
565 | 753 | ||
566 | if (m_eqModule != null) | 754 | if (m_eqModule != null) |
567 | { | 755 | { |
756 | // The EnableSimulator message makes the client establish a connection with the destination | ||
757 | // simulator by sending the initial UseCircuitCode UDP packet to the destination containing the | ||
758 | // correct circuit code. | ||
568 | m_eqModule.EnableSimulator(destinationHandle, endPoint, sp.UUID); | 759 | m_eqModule.EnableSimulator(destinationHandle, endPoint, sp.UUID); |
569 | 760 | ||
570 | // ES makes the client send a UseCircuitCode message to the destination, | 761 | // XXX: Is this wait necessary? We will always end up waiting on UpdateAgent for the destination |
571 | // which triggers a bunch of things there. | 762 | // simulator to confirm that it has established communication with the viewer. |
572 | // So let's wait | ||
573 | Thread.Sleep(200); | 763 | Thread.Sleep(200); |
574 | 764 | ||
575 | // At least on LL 3.3.4 for teleports between different regions on the same simulator this appears | 765 | // At least on LL 3.3.4 for teleports between different regions on the same simulator this appears |
@@ -580,6 +770,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
580 | } | 770 | } |
581 | else | 771 | else |
582 | { | 772 | { |
773 | // XXX: This is a little misleading since we're information the client of its avatar destination, | ||
774 | // which may or may not be a neighbour region of the source region. This path is probably little | ||
775 | // used anyway (with EQ being the one used). But it is currently being used for test code. | ||
583 | sp.ControllingClient.InformClientOfNeighbour(destinationHandle, endPoint); | 776 | sp.ControllingClient.InformClientOfNeighbour(destinationHandle, endPoint); |
584 | } | 777 | } |
585 | } | 778 | } |
@@ -597,23 +790,66 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
597 | 790 | ||
598 | //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Updating agent..."); | 791 | //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Updating agent..."); |
599 | 792 | ||
793 | // We will check for an abort before UpdateAgent since UpdateAgent will require an active viewer to | ||
794 | // establish th econnection to the destination which makes it return true. | ||
795 | if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting) | ||
796 | { | ||
797 | m_interRegionTeleportAborts.Value++; | ||
798 | |||
799 | m_log.DebugFormat( | ||
800 | "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} before UpdateAgent", | ||
801 | sp.Name, finalDestination.RegionName, sp.Scene.Name); | ||
802 | |||
803 | return; | ||
804 | } | ||
805 | |||
806 | // A common teleport failure occurs when we can send CreateAgent to the | ||
807 | // destination region but the viewer cannot establish the connection (e.g. due to network issues between | ||
808 | // the viewer and the destination). In this case, UpdateAgent timesout after 10 seconds, although then | ||
809 | // there's a further 10 second wait whilst we attempt to tell the destination to delete the agent in Fail(). | ||
600 | if (!UpdateAgent(reg, finalDestination, agent, sp)) | 810 | if (!UpdateAgent(reg, finalDestination, agent, sp)) |
601 | { | 811 | { |
602 | // Region doesn't take it | 812 | if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting) |
813 | { | ||
814 | m_interRegionTeleportAborts.Value++; | ||
815 | |||
816 | m_log.DebugFormat( | ||
817 | "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after UpdateAgent due to previous client close.", | ||
818 | sp.Name, finalDestination.RegionName, sp.Scene.Name); | ||
819 | |||
820 | return; | ||
821 | } | ||
822 | |||
603 | m_log.WarnFormat( | 823 | m_log.WarnFormat( |
604 | "[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1} from {2}. Returning avatar to source region.", | 824 | "[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1} from {2}. Keeping avatar in source region.", |
605 | sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); | 825 | sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); |
606 | 826 | ||
607 | Fail(sp, finalDestination, logout); | 827 | Fail(sp, finalDestination, logout, "Connection between viewer and destination region could not be established."); |
608 | return; | 828 | return; |
609 | } | 829 | } |
610 | 830 | ||
611 | sp.ControllingClient.SendTeleportProgress(teleportFlags | (uint)TeleportFlags.DisableCancel, "sending_dest"); | 831 | if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Cancelling) |
832 | { | ||
833 | m_interRegionTeleportCancels.Value++; | ||
834 | |||
835 | m_log.DebugFormat( | ||
836 | "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after UpdateAgent on client request", | ||
837 | sp.Name, finalDestination.RegionName, sp.Scene.Name); | ||
838 | |||
839 | CleanupFailedInterRegionTeleport(sp, finalDestination); | ||
840 | |||
841 | return; | ||
842 | } | ||
612 | 843 | ||
613 | m_log.DebugFormat( | 844 | m_log.DebugFormat( |
614 | "[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} from {1} to {2}", | 845 | "[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} from {1} to {2}", |
615 | capsPath, sp.Scene.RegionInfo.RegionName, sp.Name); | 846 | capsPath, sp.Scene.RegionInfo.RegionName, sp.Name); |
616 | 847 | ||
848 | // We need to set this here to avoid an unlikely race condition when teleporting to a neighbour simulator, | ||
849 | // where that neighbour simulator could otherwise request a child agent create on the source which then | ||
850 | // closes our existing agent which is still signalled as root. | ||
851 | sp.IsChildAgent = true; | ||
852 | |||
617 | if (m_eqModule != null) | 853 | if (m_eqModule != null) |
618 | { | 854 | { |
619 | m_eqModule.TeleportFinishEvent(destinationHandle, 13, endPoint, 0, teleportFlags, capsPath, sp.UUID); | 855 | m_eqModule.TeleportFinishEvent(destinationHandle, 13, endPoint, 0, teleportFlags, capsPath, sp.UUID); |
@@ -624,19 +860,28 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
624 | teleportFlags, capsPath); | 860 | teleportFlags, capsPath); |
625 | } | 861 | } |
626 | 862 | ||
627 | // Let's set this to true tentatively. This does not trigger OnChildAgent | ||
628 | sp.IsChildAgent = true; | ||
629 | |||
630 | // TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which | 863 | // TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which |
631 | // trigers a whole shebang of things there, including MakeRoot. So let's wait for confirmation | 864 | // trigers a whole shebang of things there, including MakeRoot. So let's wait for confirmation |
632 | // that the client contacted the destination before we close things here. | 865 | // that the client contacted the destination before we close things here. |
633 | if (!m_entityTransferStateMachine.WaitForAgentArrivedAtDestination(sp.UUID)) | 866 | if (!m_entityTransferStateMachine.WaitForAgentArrivedAtDestination(sp.UUID)) |
634 | { | 867 | { |
868 | if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting) | ||
869 | { | ||
870 | m_interRegionTeleportAborts.Value++; | ||
871 | |||
872 | m_log.DebugFormat( | ||
873 | "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after WaitForAgentArrivedAtDestination due to previous client close.", | ||
874 | sp.Name, finalDestination.RegionName, sp.Scene.Name); | ||
875 | |||
876 | return; | ||
877 | } | ||
878 | |||
635 | m_log.WarnFormat( | 879 | m_log.WarnFormat( |
636 | "[ENTITY TRANSFER MODULE]: Teleport of {0} to {1} from {2} failed due to no callback from destination region. Returning avatar to source region.", | 880 | "[ENTITY TRANSFER MODULE]: Teleport of {0} to {1} from {2} failed due to no callback from destination region. Returning avatar to source region.", |
637 | sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); | 881 | sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); |
638 | 882 | ||
639 | Fail(sp, finalDestination, logout); | 883 | Fail(sp, finalDestination, logout, "Destination region did not signal teleport completion."); |
884 | |||
640 | return; | 885 | return; |
641 | } | 886 | } |
642 | 887 | ||
@@ -659,8 +904,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
659 | // Now let's make it officially a child agent | 904 | // Now let's make it officially a child agent |
660 | sp.MakeChildAgent(); | 905 | sp.MakeChildAgent(); |
661 | 906 | ||
662 | // sp.Scene.CleanDroppedAttachments(); | ||
663 | |||
664 | // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone | 907 | // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone |
665 | 908 | ||
666 | if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) | 909 | if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) |
@@ -680,27 +923,21 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
680 | // now we have a child agent in this region. | 923 | // now we have a child agent in this region. |
681 | sp.Reset(); | 924 | sp.Reset(); |
682 | } | 925 | } |
683 | |||
684 | // Commented pending deletion since this method no longer appears to do anything at all | ||
685 | // // REFACTORING PROBLEM. Well, not a problem, but this method is HORRIBLE! | ||
686 | // if (sp.Scene.NeedSceneCacheClear(sp.UUID)) | ||
687 | // { | ||
688 | // m_log.DebugFormat( | ||
689 | // "[ENTITY TRANSFER MODULE]: User {0} is going to another region, profile cache removed", | ||
690 | // sp.UUID); | ||
691 | // } | ||
692 | |||
693 | m_entityTransferStateMachine.ResetFromTransit(sp.UUID); | ||
694 | } | 926 | } |
695 | 927 | ||
696 | protected virtual void Fail(ScenePresence sp, GridRegion finalDestination, bool logout) | 928 | /// <summary> |
929 | /// Clean up an inter-region teleport that did not complete, either because of simulator failure or cancellation. | ||
930 | /// </summary> | ||
931 | /// <remarks> | ||
932 | /// All operations here must be idempotent so that we can call this method at any point in the teleport process | ||
933 | /// up until we send the TeleportFinish event quene event to the viewer. | ||
934 | /// <remarks> | ||
935 | /// <param name='sp'> </param> | ||
936 | /// <param name='finalDestination'></param> | ||
937 | protected virtual void CleanupFailedInterRegionTeleport(ScenePresence sp, GridRegion finalDestination) | ||
697 | { | 938 | { |
698 | m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); | 939 | m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); |
699 | 940 | ||
700 | // Client never contacted destination. Let's restore everything back | ||
701 | sp.ControllingClient.SendTeleportFailed("Problems connecting to destination."); | ||
702 | |||
703 | // Fail. Reset it back | ||
704 | sp.IsChildAgent = false; | 941 | sp.IsChildAgent = false; |
705 | ReInstantiateScripts(sp); | 942 | ReInstantiateScripts(sp); |
706 | 943 | ||
@@ -708,10 +945,26 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
708 | 945 | ||
709 | // Finally, kill the agent we just created at the destination. | 946 | // Finally, kill the agent we just created at the destination. |
710 | Scene.SimulationService.CloseAgent(finalDestination, sp.UUID); | 947 | Scene.SimulationService.CloseAgent(finalDestination, sp.UUID); |
948 | } | ||
711 | 949 | ||
712 | sp.Scene.EventManager.TriggerTeleportFail(sp.ControllingClient, logout); | 950 | /// <summary> |
951 | /// Signal that the inter-region teleport failed and perform cleanup. | ||
952 | /// </summary> | ||
953 | /// <param name='sp'></param> | ||
954 | /// <param name='finalDestination'></param> | ||
955 | /// <param name='logout'></param> | ||
956 | /// <param name='reason'>Human readable reason for teleport failure. Will be sent to client.</param> | ||
957 | protected virtual void Fail(ScenePresence sp, GridRegion finalDestination, bool logout, string reason) | ||
958 | { | ||
959 | CleanupFailedInterRegionTeleport(sp, finalDestination); | ||
960 | |||
961 | m_interRegionTeleportFailures.Value++; | ||
713 | 962 | ||
714 | m_entityTransferStateMachine.ResetFromTransit(sp.UUID); | 963 | sp.ControllingClient.SendTeleportFailed( |
964 | string.Format( | ||
965 | "Problems connecting to destination {0}, reason: {1}", finalDestination.RegionName, reason)); | ||
966 | |||
967 | sp.Scene.EventManager.TriggerTeleportFail(sp.ControllingClient, logout); | ||
715 | } | 968 | } |
716 | 969 | ||
717 | protected virtual bool CreateAgent(ScenePresence sp, GridRegion reg, GridRegion finalDestination, AgentCircuitData agentCircuit, uint teleportFlags, out string reason, out bool logout) | 970 | protected virtual bool CreateAgent(ScenePresence sp, GridRegion reg, GridRegion finalDestination, AgentCircuitData agentCircuit, uint teleportFlags, out string reason, out bool logout) |
@@ -762,7 +1015,21 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
762 | 1015 | ||
763 | protected virtual bool NeedsNewAgent(float drawdist, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY) | 1016 | protected virtual bool NeedsNewAgent(float drawdist, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY) |
764 | { | 1017 | { |
765 | return Util.IsOutsideView(drawdist, oldRegionX, newRegionX, oldRegionY, newRegionY); | 1018 | if (m_regionCombinerModule != null && m_regionCombinerModule.IsRootForMegaregion(Scene.RegionInfo.RegionID)) |
1019 | { | ||
1020 | Vector2 swCorner, neCorner; | ||
1021 | GetMegaregionViewRange(out swCorner, out neCorner); | ||
1022 | |||
1023 | m_log.DebugFormat( | ||
1024 | "[ENTITY TRANSFER MODULE]: Megaregion view of {0} is from {1} to {2} with new agent check for {3},{4}", | ||
1025 | Scene.Name, swCorner, neCorner, newRegionX, newRegionY); | ||
1026 | |||
1027 | return !(newRegionX >= swCorner.X && newRegionX <= neCorner.X && newRegionY >= swCorner.Y && newRegionY <= neCorner.Y); | ||
1028 | } | ||
1029 | else | ||
1030 | { | ||
1031 | return Util.IsOutsideView(drawdist, oldRegionX, newRegionX, oldRegionY, newRegionY); | ||
1032 | } | ||
766 | } | 1033 | } |
767 | 1034 | ||
768 | protected virtual bool NeedsClosing(float drawdist, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY, GridRegion reg) | 1035 | protected virtual bool NeedsClosing(float drawdist, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY, GridRegion reg) |
@@ -866,6 +1133,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
866 | { | 1133 | { |
867 | version = String.Empty; | 1134 | version = String.Empty; |
868 | newpos = new Vector3(pos.X, pos.Y, pos.Z); | 1135 | newpos = new Vector3(pos.X, pos.Y, pos.Z); |
1136 | |||
1137 | // m_log.DebugFormat( | ||
1138 | // "[ENTITY TRANSFER MODULE]: Crossing agent {0} at pos {1} in {2}", agent.Name, pos, scene.Name); | ||
1139 | |||
869 | uint neighbourx = scene.RegionInfo.RegionLocX; | 1140 | uint neighbourx = scene.RegionInfo.RegionLocX; |
870 | uint neighboury = scene.RegionInfo.RegionLocY; | 1141 | uint neighboury = scene.RegionInfo.RegionLocY; |
871 | const float boundaryDistance = 1.7f; | 1142 | const float boundaryDistance = 1.7f; |
@@ -995,11 +1266,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
995 | return neighbourRegion; | 1266 | return neighbourRegion; |
996 | } | 1267 | } |
997 | 1268 | ||
998 | private void TeleportCancel(IClientAPI remoteClient) | ||
999 | { | ||
1000 | m_entityTransferStateMachine.ResetFromTransit(remoteClient.AgentId); | ||
1001 | } | ||
1002 | |||
1003 | public bool Cross(ScenePresence agent, bool isFlying) | 1269 | public bool Cross(ScenePresence agent, bool isFlying) |
1004 | { | 1270 | { |
1005 | uint x; | 1271 | uint x; |
@@ -1023,16 +1289,16 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1023 | } | 1289 | } |
1024 | 1290 | ||
1025 | 1291 | ||
1026 | public delegate void InformClientToInitateTeleportToLocationDelegate(ScenePresence agent, uint regionX, uint regionY, | 1292 | public delegate void InformClientToInitiateTeleportToLocationDelegate(ScenePresence agent, uint regionX, uint regionY, |
1027 | Vector3 position, | 1293 | Vector3 position, |
1028 | Scene initiatingScene); | 1294 | Scene initiatingScene); |
1029 | 1295 | ||
1030 | private void InformClientToInitateTeleportToLocation(ScenePresence agent, uint regionX, uint regionY, Vector3 position, Scene initiatingScene) | 1296 | private void InformClientToInitiateTeleportToLocation(ScenePresence agent, uint regionX, uint regionY, Vector3 position, Scene initiatingScene) |
1031 | { | 1297 | { |
1032 | 1298 | ||
1033 | // This assumes that we know what our neighbours are. | 1299 | // This assumes that we know what our neighbours are. |
1034 | 1300 | ||
1035 | InformClientToInitateTeleportToLocationDelegate d = InformClientToInitiateTeleportToLocationAsync; | 1301 | InformClientToInitiateTeleportToLocationDelegate d = InformClientToInitiateTeleportToLocationAsync; |
1036 | d.BeginInvoke(agent, regionX, regionY, position, initiatingScene, | 1302 | d.BeginInvoke(agent, regionX, regionY, position, initiatingScene, |
1037 | InformClientToInitiateTeleportToLocationCompleted, | 1303 | InformClientToInitiateTeleportToLocationCompleted, |
1038 | d); | 1304 | d); |
@@ -1042,7 +1308,19 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1042 | Scene initiatingScene) | 1308 | Scene initiatingScene) |
1043 | { | 1309 | { |
1044 | Thread.Sleep(10000); | 1310 | Thread.Sleep(10000); |
1045 | 1311 | ||
1312 | m_log.DebugFormat( | ||
1313 | "[ENTITY TRANSFER MODULE]: Auto-reteleporting {0} to correct megaregion location {1},{2},{3} from {4}", | ||
1314 | agent.Name, regionX, regionY, position, initiatingScene.Name); | ||
1315 | |||
1316 | agent.Scene.RequestTeleportLocation( | ||
1317 | agent.ControllingClient, | ||
1318 | Utils.UIntsToLong(regionX * (uint)Constants.RegionSize, regionY * (uint)Constants.RegionSize), | ||
1319 | position, | ||
1320 | agent.Lookat, | ||
1321 | (uint)Constants.TeleportFlags.ViaLocation); | ||
1322 | |||
1323 | /* | ||
1046 | IMessageTransferModule im = initiatingScene.RequestModuleInterface<IMessageTransferModule>(); | 1324 | IMessageTransferModule im = initiatingScene.RequestModuleInterface<IMessageTransferModule>(); |
1047 | if (im != null) | 1325 | if (im != null) |
1048 | { | 1326 | { |
@@ -1077,12 +1355,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1077 | }); | 1355 | }); |
1078 | 1356 | ||
1079 | } | 1357 | } |
1358 | */ | ||
1080 | } | 1359 | } |
1081 | 1360 | ||
1082 | private void InformClientToInitiateTeleportToLocationCompleted(IAsyncResult iar) | 1361 | private void InformClientToInitiateTeleportToLocationCompleted(IAsyncResult iar) |
1083 | { | 1362 | { |
1084 | InformClientToInitateTeleportToLocationDelegate icon = | 1363 | InformClientToInitiateTeleportToLocationDelegate icon = |
1085 | (InformClientToInitateTeleportToLocationDelegate)iar.AsyncState; | 1364 | (InformClientToInitiateTeleportToLocationDelegate)iar.AsyncState; |
1086 | icon.EndInvoke(iar); | 1365 | icon.EndInvoke(iar); |
1087 | } | 1366 | } |
1088 | 1367 | ||
@@ -1107,10 +1386,16 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1107 | bool isFlying, string version) | 1386 | bool isFlying, string version) |
1108 | { | 1387 | { |
1109 | if (!CrossAgentToNewRegionPrep(agent, neighbourRegion)) | 1388 | if (!CrossAgentToNewRegionPrep(agent, neighbourRegion)) |
1389 | { | ||
1390 | m_entityTransferStateMachine.ResetFromTransit(agent.UUID); | ||
1110 | return agent; | 1391 | return agent; |
1392 | } | ||
1111 | 1393 | ||
1112 | if (!CrossAgentIntoNewRegionMain(agent, pos, neighbourRegion, isFlying)) | 1394 | if (!CrossAgentIntoNewRegionMain(agent, pos, neighbourRegion, isFlying)) |
1395 | { | ||
1396 | m_entityTransferStateMachine.ResetFromTransit(agent.UUID); | ||
1113 | return agent; | 1397 | return agent; |
1398 | } | ||
1114 | 1399 | ||
1115 | CrossAgentToNewRegionPost(agent, pos, neighbourRegion, isFlying, version); | 1400 | CrossAgentToNewRegionPost(agent, pos, neighbourRegion, isFlying, version); |
1116 | return agent; | 1401 | return agent; |
@@ -1137,9 +1422,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1137 | // region doesn't take it | 1422 | // region doesn't take it |
1138 | m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.CleaningUp); | 1423 | m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.CleaningUp); |
1139 | 1424 | ||
1425 | m_log.WarnFormat( | ||
1426 | "[ENTITY TRANSFER MODULE]: Region {0} would not accept update for agent {1} on cross attempt. Returning to original region.", | ||
1427 | neighbourRegion.RegionName, agent.Name); | ||
1428 | |||
1140 | ReInstantiateScripts(agent); | 1429 | ReInstantiateScripts(agent); |
1141 | agent.AddToPhysicalScene(isFlying); | 1430 | agent.AddToPhysicalScene(isFlying); |
1142 | m_entityTransferStateMachine.ResetFromTransit(agent.UUID); | ||
1143 | 1431 | ||
1144 | return false; | 1432 | return false; |
1145 | } | 1433 | } |
@@ -1576,6 +1864,37 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1576 | } | 1864 | } |
1577 | 1865 | ||
1578 | /// <summary> | 1866 | /// <summary> |
1867 | /// Gets the range considered in view of this megaregion (assuming this is a megaregion). | ||
1868 | /// </summary> | ||
1869 | /// <remarks>Expressed in 256m units</remarks> | ||
1870 | /// <param name='swCorner'></param> | ||
1871 | /// <param name='neCorner'></param> | ||
1872 | private void GetMegaregionViewRange(out Vector2 swCorner, out Vector2 neCorner) | ||
1873 | { | ||
1874 | Border[] northBorders = Scene.NorthBorders.ToArray(); | ||
1875 | Border[] eastBorders = Scene.EastBorders.ToArray(); | ||
1876 | |||
1877 | Vector2 extent = Vector2.Zero; | ||
1878 | for (int i = 0; i < eastBorders.Length; i++) | ||
1879 | { | ||
1880 | extent.X = (eastBorders[i].BorderLine.Z > extent.X) ? eastBorders[i].BorderLine.Z : extent.X; | ||
1881 | } | ||
1882 | for (int i = 0; i < northBorders.Length; i++) | ||
1883 | { | ||
1884 | extent.Y = (northBorders[i].BorderLine.Z > extent.Y) ? northBorders[i].BorderLine.Z : extent.Y; | ||
1885 | } | ||
1886 | |||
1887 | // Loss of fraction on purpose | ||
1888 | extent.X = ((int)extent.X / (int)Constants.RegionSize); | ||
1889 | extent.Y = ((int)extent.Y / (int)Constants.RegionSize); | ||
1890 | |||
1891 | swCorner.X = Scene.RegionInfo.RegionLocX - 1; | ||
1892 | swCorner.Y = Scene.RegionInfo.RegionLocY - 1; | ||
1893 | neCorner.X = Scene.RegionInfo.RegionLocX + extent.X; | ||
1894 | neCorner.Y = Scene.RegionInfo.RegionLocY + extent.Y; | ||
1895 | } | ||
1896 | |||
1897 | /// <summary> | ||
1579 | /// Return the list of regions that are considered to be neighbours to the given scene. | 1898 | /// Return the list of regions that are considered to be neighbours to the given scene. |
1580 | /// </summary> | 1899 | /// </summary> |
1581 | /// <param name="pScene"></param> | 1900 | /// <param name="pScene"></param> |
@@ -1587,15 +1906,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1587 | Scene pScene = avatar.Scene; | 1906 | Scene pScene = avatar.Scene; |
1588 | RegionInfo m_regionInfo = pScene.RegionInfo; | 1907 | RegionInfo m_regionInfo = pScene.RegionInfo; |
1589 | 1908 | ||
1590 | Border[] northBorders = pScene.NorthBorders.ToArray(); | ||
1591 | Border[] southBorders = pScene.SouthBorders.ToArray(); | ||
1592 | Border[] eastBorders = pScene.EastBorders.ToArray(); | ||
1593 | Border[] westBorders = pScene.WestBorders.ToArray(); | ||
1594 | |||
1595 | // Leaving this as a "megaregions" computation vs "non-megaregions" computation; it isn't | 1909 | // Leaving this as a "megaregions" computation vs "non-megaregions" computation; it isn't |
1596 | // clear what should be done with a "far view" given that megaregions already extended the | 1910 | // clear what should be done with a "far view" given that megaregions already extended the |
1597 | // view to include everything in the megaregion | 1911 | // view to include everything in the megaregion |
1598 | if (northBorders.Length <= 1 && southBorders.Length <= 1 && eastBorders.Length <= 1 && westBorders.Length <= 1) | 1912 | if (m_regionCombinerModule == null || !m_regionCombinerModule.IsRootForMegaregion(Scene.RegionInfo.RegionID)) |
1599 | { | 1913 | { |
1600 | int dd = avatar.DrawDistance < Constants.RegionSize ? (int)Constants.RegionSize : (int)avatar.DrawDistance; | 1914 | int dd = avatar.DrawDistance < Constants.RegionSize ? (int)Constants.RegionSize : (int)avatar.DrawDistance; |
1601 | 1915 | ||
@@ -1613,27 +1927,17 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1613 | } | 1927 | } |
1614 | else | 1928 | else |
1615 | { | 1929 | { |
1616 | Vector2 extent = Vector2.Zero; | 1930 | Vector2 swCorner, neCorner; |
1617 | for (int i = 0; i < eastBorders.Length; i++) | 1931 | GetMegaregionViewRange(out swCorner, out neCorner); |
1618 | { | ||
1619 | extent.X = (eastBorders[i].BorderLine.Z > extent.X) ? eastBorders[i].BorderLine.Z : extent.X; | ||
1620 | } | ||
1621 | for (int i = 0; i < northBorders.Length; i++) | ||
1622 | { | ||
1623 | extent.Y = (northBorders[i].BorderLine.Z > extent.Y) ? northBorders[i].BorderLine.Z : extent.Y; | ||
1624 | } | ||
1625 | |||
1626 | // Loss of fraction on purpose | ||
1627 | extent.X = ((int)extent.X / (int)Constants.RegionSize) + 1; | ||
1628 | extent.Y = ((int)extent.Y / (int)Constants.RegionSize) + 1; | ||
1629 | |||
1630 | int startX = (int)(pRegionLocX - 1) * (int)Constants.RegionSize; | ||
1631 | int startY = (int)(pRegionLocY - 1) * (int)Constants.RegionSize; | ||
1632 | 1932 | ||
1633 | int endX = ((int)pRegionLocX + (int)extent.X) * (int)Constants.RegionSize; | 1933 | List<GridRegion> neighbours |
1634 | int endY = ((int)pRegionLocY + (int)extent.Y) * (int)Constants.RegionSize; | 1934 | = pScene.GridService.GetRegionRange( |
1935 | m_regionInfo.ScopeID, | ||
1936 | (int)swCorner.X * (int)Constants.RegionSize, | ||
1937 | (int)neCorner.X * (int)Constants.RegionSize, | ||
1938 | (int)swCorner.Y * (int)Constants.RegionSize, | ||
1939 | (int)neCorner.Y * (int)Constants.RegionSize); | ||
1635 | 1940 | ||
1636 | List<GridRegion> neighbours = pScene.GridService.GetRegionRange(m_regionInfo.ScopeID, startX, endX, startY, endY); | ||
1637 | neighbours.RemoveAll(delegate(GridRegion r) { return r.RegionID == m_regionInfo.RegionID; }); | 1941 | neighbours.RemoveAll(delegate(GridRegion r) { return r.RegionID == m_regionInfo.RegionID; }); |
1638 | 1942 | ||
1639 | return neighbours; | 1943 | return neighbours; |
@@ -2054,7 +2358,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
2054 | 2358 | ||
2055 | public bool IsInTransit(UUID id) | 2359 | public bool IsInTransit(UUID id) |
2056 | { | 2360 | { |
2057 | return m_entityTransferStateMachine.IsInTransit(id); | 2361 | return m_entityTransferStateMachine.GetAgentTransferState(id) != null; |
2058 | } | 2362 | } |
2059 | 2363 | ||
2060 | protected void ReInstantiateScripts(ScenePresence sp) | 2364 | protected void ReInstantiateScripts(ScenePresence sp) |
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs index 70dd1bc..e903383 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs | |||
@@ -51,10 +51,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
51 | /// This is a state machine. | 51 | /// This is a state machine. |
52 | /// | 52 | /// |
53 | /// [Entry] => Preparing | 53 | /// [Entry] => Preparing |
54 | /// Preparing => { Transferring || CleaningUp || [Exit] } | 54 | /// Preparing => { Transferring || Cancelling || CleaningUp || Aborting || [Exit] } |
55 | /// Transferring => { ReceivedAtDestination || CleaningUp } | 55 | /// Transferring => { ReceivedAtDestination || Cancelling || CleaningUp || Aborting } |
56 | /// ReceivedAtDestination => CleaningUp | 56 | /// Cancelling => CleaningUp || Aborting |
57 | /// ReceivedAtDestination => CleaningUp || Aborting | ||
57 | /// CleaningUp => [Exit] | 58 | /// CleaningUp => [Exit] |
59 | /// Aborting => [Exit] | ||
58 | /// | 60 | /// |
59 | /// In other words, agents normally travel throwing Preparing => Transferring => ReceivedAtDestination => CleaningUp | 61 | /// In other words, agents normally travel throwing Preparing => Transferring => ReceivedAtDestination => CleaningUp |
60 | /// However, any state can transition to CleaningUp if the teleport has failed. | 62 | /// However, any state can transition to CleaningUp if the teleport has failed. |
@@ -64,7 +66,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
64 | Preparing, // The agent is being prepared for transfer | 66 | Preparing, // The agent is being prepared for transfer |
65 | Transferring, // The agent is in the process of being transferred to a destination | 67 | Transferring, // The agent is in the process of being transferred to a destination |
66 | ReceivedAtDestination, // The destination has notified us that the agent has been successfully received | 68 | ReceivedAtDestination, // The destination has notified us that the agent has been successfully received |
67 | CleaningUp // The agent is being changed to child/removed after a transfer | 69 | CleaningUp, // The agent is being changed to child/removed after a transfer |
70 | Cancelling, // The user has cancelled the teleport but we have yet to act upon this. | ||
71 | Aborting // The transfer is aborting. Unlike Cancelling, no compensating actions should be performed | ||
68 | } | 72 | } |
69 | 73 | ||
70 | /// <summary> | 74 | /// <summary> |
@@ -115,42 +119,114 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
115 | /// <param name='newState'></param> | 119 | /// <param name='newState'></param> |
116 | /// <returns></returns> | 120 | /// <returns></returns> |
117 | /// <exception cref='Exception'>Illegal transitions will throw an Exception</exception> | 121 | /// <exception cref='Exception'>Illegal transitions will throw an Exception</exception> |
118 | internal void UpdateInTransit(UUID id, AgentTransferState newState) | 122 | internal bool UpdateInTransit(UUID id, AgentTransferState newState) |
119 | { | 123 | { |
124 | bool transitionOkay = false; | ||
125 | |||
126 | // We don't want to throw an exception on cancel since this can come it at any time. | ||
127 | bool failIfNotOkay = true; | ||
128 | |||
129 | // Should be a failure message if failure is not okay. | ||
130 | string failureMessage = null; | ||
131 | |||
132 | AgentTransferState? oldState = null; | ||
133 | |||
120 | lock (m_agentsInTransit) | 134 | lock (m_agentsInTransit) |
121 | { | 135 | { |
122 | // Illegal to try and update an agent that's not actually in transit. | 136 | // Illegal to try and update an agent that's not actually in transit. |
123 | if (!m_agentsInTransit.ContainsKey(id)) | 137 | if (!m_agentsInTransit.ContainsKey(id)) |
124 | throw new Exception( | 138 | { |
125 | string.Format( | 139 | if (newState != AgentTransferState.Cancelling && newState != AgentTransferState.Aborting) |
126 | "Agent with ID {0} is not registered as in transit in {1}", | 140 | failureMessage = string.Format( |
127 | id, m_mod.Scene.RegionInfo.RegionName)); | 141 | "Agent with ID {0} is not registered as in transit in {1}", |
128 | 142 | id, m_mod.Scene.RegionInfo.RegionName); | |
129 | AgentTransferState oldState = m_agentsInTransit[id]; | 143 | else |
144 | failIfNotOkay = false; | ||
145 | } | ||
146 | else | ||
147 | { | ||
148 | oldState = m_agentsInTransit[id]; | ||
130 | 149 | ||
131 | bool transitionOkay = false; | 150 | if (newState == AgentTransferState.Aborting) |
151 | { | ||
152 | transitionOkay = true; | ||
153 | } | ||
154 | else if (newState == AgentTransferState.CleaningUp && oldState != AgentTransferState.CleaningUp) | ||
155 | { | ||
156 | transitionOkay = true; | ||
157 | } | ||
158 | else if (newState == AgentTransferState.Transferring && oldState == AgentTransferState.Preparing) | ||
159 | { | ||
160 | transitionOkay = true; | ||
161 | } | ||
162 | else if (newState == AgentTransferState.ReceivedAtDestination && oldState == AgentTransferState.Transferring) | ||
163 | { | ||
164 | transitionOkay = true; | ||
165 | } | ||
166 | else | ||
167 | { | ||
168 | if (newState == AgentTransferState.Cancelling | ||
169 | && (oldState == AgentTransferState.Preparing || oldState == AgentTransferState.Transferring)) | ||
170 | { | ||
171 | transitionOkay = true; | ||
172 | } | ||
173 | else | ||
174 | { | ||
175 | failIfNotOkay = false; | ||
176 | } | ||
177 | } | ||
132 | 178 | ||
133 | if (newState == AgentTransferState.CleaningUp && oldState != AgentTransferState.CleaningUp) | 179 | if (!transitionOkay) |
134 | transitionOkay = true; | 180 | failureMessage |
135 | else if (newState == AgentTransferState.Transferring && oldState == AgentTransferState.Preparing) | 181 | = string.Format( |
136 | transitionOkay = true; | 182 | "Agent with ID {0} is not allowed to move from old transit state {1} to new state {2} in {3}", |
137 | else if (newState == AgentTransferState.ReceivedAtDestination && oldState == AgentTransferState.Transferring) | 183 | id, oldState, newState, m_mod.Scene.RegionInfo.RegionName); |
138 | transitionOkay = true; | 184 | } |
139 | 185 | ||
140 | if (transitionOkay) | 186 | if (transitionOkay) |
187 | { | ||
141 | m_agentsInTransit[id] = newState; | 188 | m_agentsInTransit[id] = newState; |
142 | else | 189 | |
143 | throw new Exception( | 190 | // m_log.DebugFormat( |
144 | string.Format( | 191 | // "[ENTITY TRANSFER STATE MACHINE]: Changed agent with id {0} from state {1} to {2} in {3}", |
145 | "Agent with ID {0} is not allowed to move from old transit state {1} to new state {2} in {3}", | 192 | // id, oldState, newState, m_mod.Scene.Name); |
146 | id, oldState, newState, m_mod.Scene.RegionInfo.RegionName)); | 193 | } |
194 | else if (failIfNotOkay) | ||
195 | { | ||
196 | throw new Exception(failureMessage); | ||
197 | } | ||
198 | // else | ||
199 | // { | ||
200 | // if (oldState != null) | ||
201 | // m_log.DebugFormat( | ||
202 | // "[ENTITY TRANSFER STATE MACHINE]: Ignored change of agent with id {0} from state {1} to {2} in {3}", | ||
203 | // id, oldState, newState, m_mod.Scene.Name); | ||
204 | // else | ||
205 | // m_log.DebugFormat( | ||
206 | // "[ENTITY TRANSFER STATE MACHINE]: Ignored change of agent with id {0} to state {1} in {2} since agent not in transit", | ||
207 | // id, newState, m_mod.Scene.Name); | ||
208 | // } | ||
147 | } | 209 | } |
210 | |||
211 | return transitionOkay; | ||
148 | } | 212 | } |
149 | 213 | ||
150 | internal bool IsInTransit(UUID id) | 214 | /// <summary> |
215 | /// Gets the current agent transfer state. | ||
216 | /// </summary> | ||
217 | /// <returns>Null if the agent is not in transit</returns> | ||
218 | /// <param name='id'> | ||
219 | /// Identifier. | ||
220 | /// </param> | ||
221 | internal AgentTransferState? GetAgentTransferState(UUID id) | ||
151 | { | 222 | { |
152 | lock (m_agentsInTransit) | 223 | lock (m_agentsInTransit) |
153 | return m_agentsInTransit.ContainsKey(id); | 224 | { |
225 | if (!m_agentsInTransit.ContainsKey(id)) | ||
226 | return null; | ||
227 | else | ||
228 | return m_agentsInTransit[id]; | ||
229 | } | ||
154 | } | 230 | } |
155 | 231 | ||
156 | /// <summary> | 232 | /// <summary> |
@@ -203,14 +279,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
203 | 279 | ||
204 | lock (m_agentsInTransit) | 280 | lock (m_agentsInTransit) |
205 | { | 281 | { |
206 | if (!IsInTransit(id)) | 282 | AgentTransferState? currentState = GetAgentTransferState(id); |
283 | |||
284 | if (currentState == null) | ||
207 | throw new Exception( | 285 | throw new Exception( |
208 | string.Format( | 286 | string.Format( |
209 | "Asked to wait for destination callback for agent with ID {0} in {1} but agent is not in transit", | 287 | "Asked to wait for destination callback for agent with ID {0} in {1} but agent is not in transit", |
210 | id, m_mod.Scene.RegionInfo.RegionName)); | 288 | id, m_mod.Scene.RegionInfo.RegionName)); |
211 | 289 | ||
212 | AgentTransferState currentState = m_agentsInTransit[id]; | ||
213 | |||
214 | if (currentState != AgentTransferState.Transferring && currentState != AgentTransferState.ReceivedAtDestination) | 290 | if (currentState != AgentTransferState.Transferring && currentState != AgentTransferState.ReceivedAtDestination) |
215 | throw new Exception( | 291 | throw new Exception( |
216 | string.Format( | 292 | string.Format( |
@@ -222,8 +298,15 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
222 | 298 | ||
223 | // There should be no race condition here since no other code should be removing the agent transfer or | 299 | // There should be no race condition here since no other code should be removing the agent transfer or |
224 | // changing the state to another other than Transferring => ReceivedAtDestination. | 300 | // changing the state to another other than Transferring => ReceivedAtDestination. |
225 | while (m_agentsInTransit[id] != AgentTransferState.ReceivedAtDestination && count-- > 0) | 301 | |
302 | while (count-- > 0) | ||
226 | { | 303 | { |
304 | lock (m_agentsInTransit) | ||
305 | { | ||
306 | if (m_agentsInTransit[id] == AgentTransferState.ReceivedAtDestination) | ||
307 | break; | ||
308 | } | ||
309 | |||
227 | // m_log.Debug(" >>> Waiting... " + count); | 310 | // m_log.Debug(" >>> Waiting... " + count); |
228 | Thread.Sleep(100); | 311 | Thread.Sleep(100); |
229 | } | 312 | } |
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs index f3a0b01..d372c0e 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs | |||
@@ -199,7 +199,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
199 | 199 | ||
200 | public override void RemoveRegion(Scene scene) | 200 | public override void RemoveRegion(Scene scene) |
201 | { | 201 | { |
202 | base.AddRegion(scene); | 202 | base.RemoveRegion(scene); |
203 | 203 | ||
204 | if (m_Enabled) | 204 | if (m_Enabled) |
205 | scene.UnregisterModuleInterface<IUserAgentVerificationModule>(this); | 205 | scene.UnregisterModuleInterface<IUserAgentVerificationModule>(this); |
@@ -212,11 +212,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
212 | protected override GridRegion GetFinalDestination(GridRegion region) | 212 | protected override GridRegion GetFinalDestination(GridRegion region) |
213 | { | 213 | { |
214 | int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, region.RegionID); | 214 | int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, region.RegionID); |
215 | m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: region {0} flags: {1}", region.RegionID, flags); | 215 | m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: region {0} flags: {1}", region.RegionName, flags); |
216 | 216 | ||
217 | if ((flags & (int)OpenSim.Framework.RegionFlags.Hyperlink) != 0) | 217 | if ((flags & (int)OpenSim.Framework.RegionFlags.Hyperlink) != 0) |
218 | { | 218 | { |
219 | m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Destination region {0} is hyperlink", region.RegionID); | 219 | m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Destination region is hyperlink"); |
220 | GridRegion real_destination = m_GatekeeperConnector.GetHyperlinkRegion(region, region.RegionID); | 220 | GridRegion real_destination = m_GatekeeperConnector.GetHyperlinkRegion(region, region.RegionID); |
221 | if (real_destination != null) | 221 | if (real_destination != null) |
222 | m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: GetFinalDestination serveruri -> {0}", real_destination.ServerURI); | 222 | m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: GetFinalDestination serveruri -> {0}", real_destination.ServerURI); |
diff --git a/OpenSim/Region/CoreModules/Framework/InterfaceCommander/Command.cs b/OpenSim/Region/CoreModules/Framework/InterfaceCommander/Command.cs index 4004135..b9786ae 100644 --- a/OpenSim/Region/CoreModules/Framework/InterfaceCommander/Command.cs +++ b/OpenSim/Region/CoreModules/Framework/InterfaceCommander/Command.cs | |||
@@ -28,6 +28,7 @@ | |||
28 | using System; | 28 | using System; |
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using OpenSim.Region.Framework.Interfaces; | 30 | using OpenSim.Region.Framework.Interfaces; |
31 | using OpenMetaverse; | ||
31 | 32 | ||
32 | namespace OpenSim.Region.CoreModules.Framework.InterfaceCommander | 33 | namespace OpenSim.Region.CoreModules.Framework.InterfaceCommander |
33 | { | 34 | { |
@@ -152,6 +153,9 @@ namespace OpenSim.Region.CoreModules.Framework.InterfaceCommander | |||
152 | case "Boolean": | 153 | case "Boolean": |
153 | m_args[i].ArgumentValue = Boolean.Parse(arg.ToString()); | 154 | m_args[i].ArgumentValue = Boolean.Parse(arg.ToString()); |
154 | break; | 155 | break; |
156 | case "UUID": | ||
157 | m_args[i].ArgumentValue = UUID.Parse(arg.ToString()); | ||
158 | break; | ||
155 | default: | 159 | default: |
156 | Console.WriteLine("ERROR: Unknown desired type for argument " + m_args[i].Name + " on command " + m_name); | 160 | Console.WriteLine("ERROR: Unknown desired type for argument " + m_args[i].Name + " on command " + m_name); |
157 | break; | 161 | break; |
diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs index f8ec6de..7871eda 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs | |||
@@ -71,7 +71,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
71 | 71 | ||
72 | #region Internal functions | 72 | #region Internal functions |
73 | 73 | ||
74 | public AssetMetadata FetchMetadata(string url, UUID assetID) | 74 | private AssetMetadata FetchMetadata(string url, UUID assetID) |
75 | { | 75 | { |
76 | if (!url.EndsWith("/") && !url.EndsWith("=")) | 76 | if (!url.EndsWith("/") && !url.EndsWith("=")) |
77 | url = url + "/"; | 77 | url = url + "/"; |
@@ -86,6 +86,27 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
86 | return meta; | 86 | return meta; |
87 | } | 87 | } |
88 | 88 | ||
89 | private AssetBase FetchAsset(string url, UUID assetID) | ||
90 | { | ||
91 | // Test if it's already here | ||
92 | AssetBase asset = m_scene.AssetService.Get(assetID.ToString()); | ||
93 | if (asset == null) | ||
94 | { | ||
95 | if (!url.EndsWith("/") && !url.EndsWith("=")) | ||
96 | url = url + "/"; | ||
97 | |||
98 | asset = m_scene.AssetService.Get(url + assetID.ToString()); | ||
99 | |||
100 | //if (asset != null) | ||
101 | // m_log.DebugFormat("[HG ASSET MAPPER]: Fetched asset {0} of type {1} from {2} ", assetID, asset.Metadata.Type, url); | ||
102 | //else | ||
103 | // m_log.DebugFormat("[HG ASSET MAPPER]: Unable to fetch asset {0} from {1} ", assetID, url); | ||
104 | |||
105 | } | ||
106 | |||
107 | return asset; | ||
108 | } | ||
109 | |||
89 | public bool PostAsset(string url, AssetBase asset) | 110 | public bool PostAsset(string url, AssetBase asset) |
90 | { | 111 | { |
91 | if (asset != null) | 112 | if (asset != null) |
@@ -228,11 +249,22 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
228 | if (meta == null) | 249 | if (meta == null) |
229 | return; | 250 | return; |
230 | 251 | ||
231 | // The act of gathering UUIDs downloads the assets from the remote server | 252 | // The act of gathering UUIDs downloads some assets from the remote server |
253 | // but not all... | ||
232 | Dictionary<UUID, AssetType> ids = new Dictionary<UUID, AssetType>(); | 254 | Dictionary<UUID, AssetType> ids = new Dictionary<UUID, AssetType>(); |
233 | HGUuidGatherer uuidGatherer = new HGUuidGatherer(m_scene.AssetService, userAssetURL); | 255 | HGUuidGatherer uuidGatherer = new HGUuidGatherer(m_scene.AssetService, userAssetURL); |
234 | uuidGatherer.GatherAssetUuids(assetID, (AssetType)meta.Type, ids); | 256 | uuidGatherer.GatherAssetUuids(assetID, (AssetType)meta.Type, ids); |
235 | 257 | m_log.DebugFormat("[HG ASSET MAPPER]: Preparing to get {0} assets", ids.Count); | |
258 | bool success = true; | ||
259 | foreach (UUID uuid in ids.Keys) | ||
260 | if (FetchAsset(userAssetURL, uuid) == null) | ||
261 | success = false; | ||
262 | |||
263 | // maybe all pieces got here... | ||
264 | if (!success) | ||
265 | m_log.DebugFormat("[HG ASSET MAPPER]: Problems getting item {0} from asset server {1}", assetID, userAssetURL); | ||
266 | else | ||
267 | m_log.DebugFormat("[HG ASSET MAPPER]: Successfully got item {0} from asset server {1}", assetID, userAssetURL); | ||
236 | } | 268 | } |
237 | 269 | ||
238 | 270 | ||
diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs index 964efda..b2b628d 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs | |||
@@ -88,12 +88,14 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
88 | IConfig thisModuleConfig = source.Configs["HGInventoryAccessModule"]; | 88 | IConfig thisModuleConfig = source.Configs["HGInventoryAccessModule"]; |
89 | if (thisModuleConfig != null) | 89 | if (thisModuleConfig != null) |
90 | { | 90 | { |
91 | // legacy configuration [obsolete] | 91 | m_HomeURI = Util.GetConfigVarFromSections<string>(source, "HomeURI", |
92 | m_HomeURI = thisModuleConfig.GetString("ProfileServerURI", string.Empty); | 92 | new string[] { "Startup", "Hypergrid", "HGInventoryAccessModule" }, String.Empty); |
93 | // preferred | 93 | m_ThisGatekeeper = Util.GetConfigVarFromSections<string>(source, "GatekeeperURI", |
94 | m_HomeURI = thisModuleConfig.GetString("HomeURI", m_HomeURI); | 94 | new string[] { "Startup", "Hypergrid", "HGInventoryAccessModule" }, String.Empty); |
95 | // Legacy. Renove soon! | ||
96 | m_ThisGatekeeper = thisModuleConfig.GetString("Gatekeeper", m_ThisGatekeeper); | ||
97 | |||
95 | m_OutboundPermission = thisModuleConfig.GetBoolean("OutboundPermission", true); | 98 | m_OutboundPermission = thisModuleConfig.GetBoolean("OutboundPermission", true); |
96 | m_ThisGatekeeper = thisModuleConfig.GetString("Gatekeeper", string.Empty); | ||
97 | m_RestrictInventoryAccessAbroad = thisModuleConfig.GetBoolean("RestrictInventoryAccessAbroad", true); | 99 | m_RestrictInventoryAccessAbroad = thisModuleConfig.GetBoolean("RestrictInventoryAccessAbroad", true); |
98 | } | 100 | } |
99 | else | 101 | else |
diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs index 6e5a4a5..5aad7f0 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs | |||
@@ -47,6 +47,7 @@ using OpenMetaverse; | |||
47 | using log4net; | 47 | using log4net; |
48 | using Nini.Config; | 48 | using Nini.Config; |
49 | using Mono.Addins; | 49 | using Mono.Addins; |
50 | using PermissionMask = OpenSim.Framework.PermissionMask; | ||
50 | 51 | ||
51 | namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | 52 | namespace OpenSim.Region.CoreModules.Framework.InventoryAccess |
52 | { | 53 | { |
@@ -398,7 +399,8 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
398 | objectGroup.RootPart.NextOwnerMask &= | 399 | objectGroup.RootPart.NextOwnerMask &= |
399 | ((uint)PermissionMask.Copy | | 400 | ((uint)PermissionMask.Copy | |
400 | (uint)PermissionMask.Transfer | | 401 | (uint)PermissionMask.Transfer | |
401 | (uint)PermissionMask.Modify); | 402 | (uint)PermissionMask.Modify | |
403 | (uint)PermissionMask.Export); | ||
402 | objectGroup.RootPart.NextOwnerMask |= | 404 | objectGroup.RootPart.NextOwnerMask |= |
403 | (uint)PermissionMask.Move; | 405 | (uint)PermissionMask.Move; |
404 | 406 | ||
@@ -506,7 +508,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
506 | InventoryItemBase item, SceneObjectGroup so, List<SceneObjectGroup> objsForEffectivePermissions, | 508 | InventoryItemBase item, SceneObjectGroup so, List<SceneObjectGroup> objsForEffectivePermissions, |
507 | IClientAPI remoteClient) | 509 | IClientAPI remoteClient) |
508 | { | 510 | { |
509 | uint effectivePerms = (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify | PermissionMask.Move) | 7; | 511 | uint effectivePerms = (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify | PermissionMask.Move | PermissionMask.Export) | 7; |
510 | // For the porposes of inventory, an object is modify if the prims | 512 | // For the porposes of inventory, an object is modify if the prims |
511 | // are modify. This allows renaming an object that contains no | 513 | // are modify. This allows renaming an object that contains no |
512 | // mod items. | 514 | // mod items. |
@@ -555,6 +557,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
555 | (uint)PermissionMask.Transfer | | 557 | (uint)PermissionMask.Transfer | |
556 | (uint)PermissionMask.Modify | | 558 | (uint)PermissionMask.Modify | |
557 | (uint)PermissionMask.Move | | 559 | (uint)PermissionMask.Move | |
560 | (uint)PermissionMask.Export | | ||
558 | 7); // Preserve folded permissions | 561 | 7); // Preserve folded permissions |
559 | } | 562 | } |
560 | 563 | ||
diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs index 21d8bd7..ad1a0e1 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs | |||
@@ -49,7 +49,7 @@ using OpenSim.Tests.Common.Mock; | |||
49 | namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests | 49 | namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests |
50 | { | 50 | { |
51 | [TestFixture] | 51 | [TestFixture] |
52 | public class InventoryAccessModuleTests | 52 | public class InventoryAccessModuleTests : OpenSimTestCase |
53 | { | 53 | { |
54 | protected TestScene m_scene; | 54 | protected TestScene m_scene; |
55 | protected BasicInventoryAccessModule m_iam; | 55 | protected BasicInventoryAccessModule m_iam; |
@@ -57,8 +57,10 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests | |||
57 | protected TestClient m_tc; | 57 | protected TestClient m_tc; |
58 | 58 | ||
59 | [SetUp] | 59 | [SetUp] |
60 | public void SetUp() | 60 | public override void SetUp() |
61 | { | 61 | { |
62 | base.SetUp(); | ||
63 | |||
62 | m_iam = new BasicInventoryAccessModule(); | 64 | m_iam = new BasicInventoryAccessModule(); |
63 | 65 | ||
64 | IConfigSource config = new IniConfigSource(); | 66 | IConfigSource config = new IniConfigSource(); |
@@ -107,7 +109,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests | |||
107 | item1.AssetID = asset1.FullID; | 109 | item1.AssetID = asset1.FullID; |
108 | item1.ID = item1Id; | 110 | item1.ID = item1Id; |
109 | InventoryFolderBase objsFolder | 111 | InventoryFolderBase objsFolder |
110 | = InventoryArchiveUtils.FindFolderByPath(m_scene.InventoryService, m_userId, "Objects")[0]; | 112 | = InventoryArchiveUtils.FindFoldersByPath(m_scene.InventoryService, m_userId, "Objects")[0]; |
111 | item1.Folder = objsFolder.ID; | 113 | item1.Folder = objsFolder.ID; |
112 | m_scene.AddInventoryItem(item1); | 114 | m_scene.AddInventoryItem(item1); |
113 | 115 | ||
@@ -157,7 +159,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests | |||
157 | item1.AssetID = asset1.FullID; | 159 | item1.AssetID = asset1.FullID; |
158 | item1.ID = item1Id; | 160 | item1.ID = item1Id; |
159 | InventoryFolderBase objsFolder | 161 | InventoryFolderBase objsFolder |
160 | = InventoryArchiveUtils.FindFolderByPath(m_scene.InventoryService, m_userId, "Objects")[0]; | 162 | = InventoryArchiveUtils.FindFoldersByPath(m_scene.InventoryService, m_userId, "Objects")[0]; |
161 | item1.Folder = objsFolder.ID; | 163 | item1.Folder = objsFolder.ID; |
162 | m_scene.AddInventoryItem(item1); | 164 | m_scene.AddInventoryItem(item1); |
163 | 165 | ||
diff --git a/OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs b/OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs index ec22146..d07cff4 100644 --- a/OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs +++ b/OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs | |||
@@ -43,6 +43,7 @@ using OpenMetaverse; | |||
43 | using log4net; | 43 | using log4net; |
44 | using Mono.Addins; | 44 | using Mono.Addins; |
45 | using Nini.Config; | 45 | using Nini.Config; |
46 | using PermissionMask = OpenSim.Framework.PermissionMask; | ||
46 | 47 | ||
47 | namespace OpenSim.Region.CoreModules.Framework.Library | 48 | namespace OpenSim.Region.CoreModules.Framework.Library |
48 | { | 49 | { |
diff --git a/OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs b/OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs index d84460a..64feec1 100644 --- a/OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs +++ b/OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs | |||
@@ -33,6 +33,7 @@ using log4net; | |||
33 | using Nini.Config; | 33 | using Nini.Config; |
34 | using OpenMetaverse; | 34 | using OpenMetaverse; |
35 | using OpenSim.Framework; | 35 | using OpenSim.Framework; |
36 | using OpenSim.Framework.Monitoring; | ||
36 | using OpenSim.Framework.Servers; | 37 | using OpenSim.Framework.Servers; |
37 | using OpenSim.Region.CoreModules.Framework.Monitoring.Alerts; | 38 | using OpenSim.Region.CoreModules.Framework.Monitoring.Alerts; |
38 | using OpenSim.Region.CoreModules.Framework.Monitoring.Monitors; | 39 | using OpenSim.Region.CoreModules.Framework.Monitoring.Monitors; |
@@ -100,6 +101,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring | |||
100 | "/monitorstats/" + Uri.EscapeDataString(m_scene.RegionInfo.RegionName), StatsPage); | 101 | "/monitorstats/" + Uri.EscapeDataString(m_scene.RegionInfo.RegionName), StatsPage); |
101 | 102 | ||
102 | AddMonitors(); | 103 | AddMonitors(); |
104 | RegisterStatsManagerRegionStatistics(); | ||
103 | } | 105 | } |
104 | 106 | ||
105 | public void RemoveRegion(Scene scene) | 107 | public void RemoveRegion(Scene scene) |
@@ -109,6 +111,9 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring | |||
109 | 111 | ||
110 | MainServer.Instance.RemoveHTTPHandler("GET", "/monitorstats/" + m_scene.RegionInfo.RegionID); | 112 | MainServer.Instance.RemoveHTTPHandler("GET", "/monitorstats/" + m_scene.RegionInfo.RegionID); |
111 | MainServer.Instance.RemoveHTTPHandler("GET", "/monitorstats/" + Uri.EscapeDataString(m_scene.RegionInfo.RegionName)); | 113 | MainServer.Instance.RemoveHTTPHandler("GET", "/monitorstats/" + Uri.EscapeDataString(m_scene.RegionInfo.RegionName)); |
114 | |||
115 | UnRegisterStatsManagerRegionStatistics(); | ||
116 | |||
112 | m_scene = null; | 117 | m_scene = null; |
113 | } | 118 | } |
114 | 119 | ||
@@ -399,6 +404,45 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring | |||
399 | { | 404 | { |
400 | m_log.Error("[Monitor] " + reporter.Name + " for " + m_scene.RegionInfo.RegionName + " reports " + reason + " (Fatal: " + fatal + ")"); | 405 | m_log.Error("[Monitor] " + reporter.Name + " for " + m_scene.RegionInfo.RegionName + " reports " + reason + " (Fatal: " + fatal + ")"); |
401 | } | 406 | } |
407 | |||
408 | private List<Stat> registeredStats = new List<Stat>(); | ||
409 | private void MakeStat(string pName, string pUnitName, Action<Stat> act) | ||
410 | { | ||
411 | Stat tempStat = new Stat(pName, pName, pName, pUnitName, "scene", m_scene.RegionInfo.RegionName, StatType.Pull, act, StatVerbosity.Info); | ||
412 | StatsManager.RegisterStat(tempStat); | ||
413 | registeredStats.Add(tempStat); | ||
414 | } | ||
415 | private void RegisterStatsManagerRegionStatistics() | ||
416 | { | ||
417 | MakeStat("RootAgents", "avatars", (s) => { s.Value = m_scene.SceneGraph.GetRootAgentCount(); }); | ||
418 | MakeStat("ChildAgents", "avatars", (s) => { s.Value = m_scene.SceneGraph.GetChildAgentCount(); }); | ||
419 | MakeStat("TotalPrims", "objects", (s) => { s.Value = m_scene.SceneGraph.GetTotalObjectsCount(); }); | ||
420 | MakeStat("ActivePrims", "objects", (s) => { s.Value = m_scene.SceneGraph.GetActiveObjectsCount(); }); | ||
421 | MakeStat("ActiveScripts", "scripts", (s) => { s.Value = m_scene.SceneGraph.GetActiveScriptsCount(); }); | ||
422 | |||
423 | MakeStat("TimeDilation", "sec/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[0]; }); | ||
424 | MakeStat("SimFPS", "fps", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[1]; }); | ||
425 | MakeStat("PhysicsFPS", "fps", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[2]; }); | ||
426 | MakeStat("AgentUpdates", "updates/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[3]; }); | ||
427 | MakeStat("FrameTime", "ms/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[8]; }); | ||
428 | MakeStat("NetTime", "ms/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[9]; }); | ||
429 | MakeStat("OtherTime", "ms/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[12]; }); | ||
430 | MakeStat("PhysicsTime", "ms/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[10]; }); | ||
431 | MakeStat("AgentTime", "ms/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[16]; }); | ||
432 | MakeStat("ImageTime", "ms/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[11]; }); | ||
433 | MakeStat("ScriptLines", "lines/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[20]; }); | ||
434 | MakeStat("SimSpareMS", "ms/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[21]; }); | ||
435 | } | ||
436 | |||
437 | private void UnRegisterStatsManagerRegionStatistics() | ||
438 | { | ||
439 | foreach (Stat stat in registeredStats) | ||
440 | { | ||
441 | StatsManager.DeregisterStat(stat); | ||
442 | stat.Dispose(); | ||
443 | } | ||
444 | registeredStats.Clear(); | ||
445 | } | ||
402 | 446 | ||
403 | } | 447 | } |
404 | } | 448 | } \ No newline at end of file |
diff --git a/OpenSim/Region/CoreModules/Framework/Statistics/Logging/BinaryLoggingModule.cs b/OpenSim/Region/CoreModules/Framework/Statistics/Logging/BinaryLoggingModule.cs index fb74cc6..f3436d1 100644 --- a/OpenSim/Region/CoreModules/Framework/Statistics/Logging/BinaryLoggingModule.cs +++ b/OpenSim/Region/CoreModules/Framework/Statistics/Logging/BinaryLoggingModule.cs | |||
@@ -57,7 +57,7 @@ namespace OpenSim.Region.CoreModules.Framework.Statistics.Logging | |||
57 | try | 57 | try |
58 | { | 58 | { |
59 | IConfig statConfig = source.Configs["Statistics.Binary"]; | 59 | IConfig statConfig = source.Configs["Statistics.Binary"]; |
60 | if (statConfig.Contains("enabled") && statConfig.GetBoolean("enabled")) | 60 | if (statConfig != null && statConfig.Contains("enabled") && statConfig.GetBoolean("enabled")) |
61 | { | 61 | { |
62 | if (statConfig.Contains("collect_region_stats")) | 62 | if (statConfig.Contains("collect_region_stats")) |
63 | { | 63 | { |
diff --git a/OpenSim/Region/CoreModules/Framework/Statistics/Logging/LogWriter.cs b/OpenSim/Region/CoreModules/Framework/Statistics/Logging/LogWriter.cs index fd8d5e3..2fe9026 100755 --- a/OpenSim/Region/CoreModules/Framework/Statistics/Logging/LogWriter.cs +++ b/OpenSim/Region/CoreModules/Framework/Statistics/Logging/LogWriter.cs | |||
@@ -52,6 +52,7 @@ namespace OpenSim.Region.CoreModules.Framework.Statistics.Logging | |||
52 | private TimeSpan m_logFileLife; | 52 | private TimeSpan m_logFileLife; |
53 | private DateTime m_logFileEndTime; | 53 | private DateTime m_logFileEndTime; |
54 | private Object m_logFileWriteLock = new Object(); | 54 | private Object m_logFileWriteLock = new Object(); |
55 | private bool m_flushWrite; | ||
55 | 56 | ||
56 | // set externally when debugging. If let 'null', this does not write any error messages. | 57 | // set externally when debugging. If let 'null', this does not write any error messages. |
57 | public ILog ErrorLogger = null; | 58 | public ILog ErrorLogger = null; |
@@ -73,7 +74,9 @@ namespace OpenSim.Region.CoreModules.Framework.Statistics.Logging | |||
73 | /// <param name="dir">The directory to create the log file in. May be 'null' for default.</param> | 74 | /// <param name="dir">The directory to create the log file in. May be 'null' for default.</param> |
74 | /// <param name="headr">The characters that begin the log file name. May be 'null' for default.</param> | 75 | /// <param name="headr">The characters that begin the log file name. May be 'null' for default.</param> |
75 | /// <param name="maxFileTime">Maximum age of a log file in minutes. If zero, will set default.</param> | 76 | /// <param name="maxFileTime">Maximum age of a log file in minutes. If zero, will set default.</param> |
76 | public LogWriter(string dir, string headr, int maxFileTime) | 77 | /// <param name="flushWrite">Whether to do a flush after every log write. Best left off but |
78 | /// if one is looking for a crash, this is a good thing to turn on.</param> | ||
79 | public LogWriter(string dir, string headr, int maxFileTime, bool flushWrite) | ||
77 | { | 80 | { |
78 | m_logDirectory = dir == null ? "." : dir; | 81 | m_logDirectory = dir == null ? "." : dir; |
79 | 82 | ||
@@ -86,8 +89,14 @@ namespace OpenSim.Region.CoreModules.Framework.Statistics.Logging | |||
86 | m_logFileLife = new TimeSpan(0, m_logMaxFileTimeMin, 0); | 89 | m_logFileLife = new TimeSpan(0, m_logMaxFileTimeMin, 0); |
87 | m_logFileEndTime = DateTime.Now + m_logFileLife; | 90 | m_logFileEndTime = DateTime.Now + m_logFileLife; |
88 | 91 | ||
92 | m_flushWrite = flushWrite; | ||
93 | |||
89 | Enabled = true; | 94 | Enabled = true; |
90 | } | 95 | } |
96 | // Constructor that assumes flushWrite is off. | ||
97 | public LogWriter(string dir, string headr, int maxFileTime) : this(dir, headr, maxFileTime, false) | ||
98 | { | ||
99 | } | ||
91 | 100 | ||
92 | public void Dispose() | 101 | public void Dispose() |
93 | { | 102 | { |
@@ -127,7 +136,7 @@ namespace OpenSim.Region.CoreModules.Framework.Statistics.Logging | |||
127 | { | 136 | { |
128 | lock (m_logFileWriteLock) | 137 | lock (m_logFileWriteLock) |
129 | { | 138 | { |
130 | DateTime now = DateTime.Now; | 139 | DateTime now = DateTime.UtcNow; |
131 | if (m_logFile == null || now > m_logFileEndTime) | 140 | if (m_logFile == null || now > m_logFileEndTime) |
132 | { | 141 | { |
133 | if (m_logFile != null) | 142 | if (m_logFile != null) |
@@ -153,6 +162,8 @@ namespace OpenSim.Region.CoreModules.Framework.Statistics.Logging | |||
153 | buff.Append(line); | 162 | buff.Append(line); |
154 | buff.Append("\r\n"); | 163 | buff.Append("\r\n"); |
155 | m_logFile.Write(buff.ToString()); | 164 | m_logFile.Write(buff.ToString()); |
165 | if (m_flushWrite) | ||
166 | m_logFile.Flush(); | ||
156 | } | 167 | } |
157 | } | 168 | } |
158 | } | 169 | } |
diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index 86e7004..77e8b00 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs | |||
@@ -181,6 +181,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement | |||
181 | 181 | ||
182 | m_log.DebugFormat("[USER MANAGEMENT MODULE]: HandleAvatarPickerRequest for {0}", query); | 182 | m_log.DebugFormat("[USER MANAGEMENT MODULE]: HandleAvatarPickerRequest for {0}", query); |
183 | 183 | ||
184 | // searhc the user accounts service | ||
184 | List<UserAccount> accs = m_Scenes[0].UserAccountService.GetUserAccounts(m_Scenes[0].RegionInfo.ScopeID, query); | 185 | List<UserAccount> accs = m_Scenes[0].UserAccountService.GetUserAccounts(m_Scenes[0].RegionInfo.ScopeID, query); |
185 | 186 | ||
186 | List<UserData> users = new List<UserData>(); | 187 | List<UserData> users = new List<UserData>(); |
@@ -196,6 +197,12 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement | |||
196 | } | 197 | } |
197 | } | 198 | } |
198 | 199 | ||
200 | // search the local cache | ||
201 | foreach (UserData data in m_UserCache.Values) | ||
202 | if (users.Find(delegate(UserData d) { return d.Id == data.Id; }) == null && | ||
203 | (data.FirstName.StartsWith(query) || data.LastName.StartsWith(query))) | ||
204 | users.Add(data); | ||
205 | |||
199 | AddAdditionalUsers(avatarID, query, users); | 206 | AddAdditionalUsers(avatarID, query, users); |
200 | 207 | ||
201 | AvatarPickerReplyPacket replyPacket = (AvatarPickerReplyPacket)PacketPool.Instance.GetPacket(PacketType.AvatarPickerReply); | 208 | AvatarPickerReplyPacket replyPacket = (AvatarPickerReplyPacket)PacketPool.Instance.GetPacket(PacketType.AvatarPickerReply); |
@@ -433,6 +440,9 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement | |||
433 | public void AddUser(UUID uuid, string first, string last, string homeURL) | 440 | public void AddUser(UUID uuid, string first, string last, string homeURL) |
434 | { | 441 | { |
435 | //m_log.DebugFormat("[USER MANAGEMENT MODULE]: Adding user with id {0}, first {1}, last {2}, url {3}", uuid, first, last, homeURL); | 442 | //m_log.DebugFormat("[USER MANAGEMENT MODULE]: Adding user with id {0}, first {1}, last {2}, url {3}", uuid, first, last, homeURL); |
443 | if (homeURL == string.Empty) | ||
444 | return; | ||
445 | |||
436 | AddUser(uuid, homeURL + ";" + first + " " + last); | 446 | AddUser(uuid, homeURL + ";" + first + " " + last); |
437 | } | 447 | } |
438 | 448 | ||
diff --git a/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs b/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs index ec94420..7b11658 100644 --- a/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs +++ b/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs | |||
@@ -52,8 +52,8 @@ namespace OpenSim.Region.CoreModules.Hypergrid | |||
52 | 52 | ||
53 | public override void Initialise(IConfigSource config) | 53 | public override void Initialise(IConfigSource config) |
54 | { | 54 | { |
55 | IConfig startupConfig = config.Configs["Startup"]; | 55 | if (Util.GetConfigVarFromSections<string>( |
56 | if (startupConfig.GetString("WorldMapModule", "WorldMap") == "HGWorldMap") | 56 | config, "WorldMapModule", new string[] { "Map", "Startup" }, "WorldMap") == "HGWorldMap") |
57 | m_Enabled = true; | 57 | m_Enabled = true; |
58 | } | 58 | } |
59 | 59 | ||
diff --git a/OpenSim/Region/CoreModules/Properties/AssemblyInfo.cs b/OpenSim/Region/CoreModules/Properties/AssemblyInfo.cs index 5a8c4a2..bfe0383 100644 --- a/OpenSim/Region/CoreModules/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/CoreModules/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.7.6.*")] |
34 | [assembly: AssemblyFileVersion("1.0.0.0")] | 34 | |
35 | 35 | ||
36 | [assembly: Addin("OpenSim.Region.CoreModules", "0.1")] | 36 | [assembly: Addin("OpenSim.Region.CoreModules", "0.1")] |
37 | [assembly: AddinDependency("OpenSim", "0.5")] | 37 | [assembly: AddinDependency("OpenSim", "0.5")] |
diff --git a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs index 0276267..2b13a8b 100644 --- a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs +++ b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs | |||
@@ -189,6 +189,45 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest | |||
189 | case (int)HttpRequestConstants.HTTP_VERIFY_CERT: | 189 | case (int)HttpRequestConstants.HTTP_VERIFY_CERT: |
190 | htc.HttpVerifyCert = (int.Parse(parms[i + 1]) != 0); | 190 | htc.HttpVerifyCert = (int.Parse(parms[i + 1]) != 0); |
191 | break; | 191 | break; |
192 | |||
193 | case (int)HttpRequestConstants.HTTP_VERBOSE_THROTTLE: | ||
194 | |||
195 | // TODO implement me | ||
196 | break; | ||
197 | |||
198 | case (int)HttpRequestConstants.HTTP_CUSTOM_HEADER: | ||
199 | //Parameters are in pairs and custom header takes | ||
200 | //arguments in pairs so adjust for header marker. | ||
201 | ++i; | ||
202 | |||
203 | //Maximum of 8 headers are allowed based on the | ||
204 | //Second Life documentation for llHTTPRequest. | ||
205 | for (int count = 1; count <= 8; ++count) | ||
206 | { | ||
207 | //Not enough parameters remaining for a header? | ||
208 | if (parms.Length - i < 2) | ||
209 | break; | ||
210 | |||
211 | //Have we reached the end of the list of headers? | ||
212 | //End is marked by a string with a single digit. | ||
213 | //We already know we have at least one parameter | ||
214 | //so it is safe to do this check at top of loop. | ||
215 | if (Char.IsDigit(parms[i][0])) | ||
216 | break; | ||
217 | |||
218 | if (htc.HttpCustomHeaders == null) | ||
219 | htc.HttpCustomHeaders = new List<string>(); | ||
220 | |||
221 | htc.HttpCustomHeaders.Add(parms[i]); | ||
222 | htc.HttpCustomHeaders.Add(parms[i+1]); | ||
223 | |||
224 | i += 2; | ||
225 | } | ||
226 | break; | ||
227 | |||
228 | case (int)HttpRequestConstants.HTTP_PRAGMA_NO_CACHE: | ||
229 | htc.HttpPragmaNoCache = (int.Parse(parms[i + 1]) != 0); | ||
230 | break; | ||
192 | } | 231 | } |
193 | } | 232 | } |
194 | } | 233 | } |
@@ -353,9 +392,12 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest | |||
353 | // public const int HTTP_METHOD = 0; | 392 | // public const int HTTP_METHOD = 0; |
354 | // public const int HTTP_MIMETYPE = 1; | 393 | // public const int HTTP_MIMETYPE = 1; |
355 | // public const int HTTP_VERIFY_CERT = 3; | 394 | // public const int HTTP_VERIFY_CERT = 3; |
395 | // public const int HTTP_VERBOSE_THROTTLE = 4; | ||
396 | // public const int HTTP_CUSTOM_HEADER = 5; | ||
397 | // public const int HTTP_PRAGMA_NO_CACHE = 6; | ||
356 | private bool _finished; | 398 | private bool _finished; |
357 | public bool Finished | 399 | public bool Finished |
358 | { | 400 | { |
359 | get { return _finished; } | 401 | get { return _finished; } |
360 | } | 402 | } |
361 | // public int HttpBodyMaxLen = 2048; // not implemented | 403 | // public int HttpBodyMaxLen = 2048; // not implemented |
@@ -367,9 +409,14 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest | |||
367 | public bool HttpVerifyCert = true; | 409 | public bool HttpVerifyCert = true; |
368 | public IWorkItemResult WorkItem = null; | 410 | public IWorkItemResult WorkItem = null; |
369 | 411 | ||
412 | //public bool HttpVerboseThrottle = true; // not implemented | ||
413 | public List<string> HttpCustomHeaders = null; | ||
414 | public bool HttpPragmaNoCache = true; | ||
415 | private Thread httpThread; | ||
416 | |||
370 | // Request info | 417 | // Request info |
371 | private UUID _itemID; | 418 | private UUID _itemID; |
372 | public UUID ItemID | 419 | public UUID ItemID |
373 | { | 420 | { |
374 | get { return _itemID; } | 421 | get { return _itemID; } |
375 | set { _itemID = value; } | 422 | set { _itemID = value; } |
@@ -385,7 +432,7 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest | |||
385 | public string proxyexcepts; | 432 | public string proxyexcepts; |
386 | public string OutboundBody; | 433 | public string OutboundBody; |
387 | private UUID _reqID; | 434 | private UUID _reqID; |
388 | public UUID ReqID | 435 | public UUID ReqID |
389 | { | 436 | { |
390 | get { return _reqID; } | 437 | get { return _reqID; } |
391 | set { _reqID = value; } | 438 | set { _reqID = value; } |
@@ -434,20 +481,34 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest | |||
434 | Request.Method = HttpMethod; | 481 | Request.Method = HttpMethod; |
435 | Request.ContentType = HttpMIMEType; | 482 | Request.ContentType = HttpMIMEType; |
436 | 483 | ||
437 | if(!HttpVerifyCert) | 484 | if (!HttpVerifyCert) |
438 | { | 485 | { |
439 | // We could hijack Connection Group Name to identify | 486 | // We could hijack Connection Group Name to identify |
440 | // a desired security exception. But at the moment we'll use a dummy header instead. | 487 | // a desired security exception. But at the moment we'll use a dummy header instead. |
441 | Request.Headers.Add("NoVerifyCert", "true"); | 488 | Request.Headers.Add("NoVerifyCert", "true"); |
442 | } | 489 | } |
443 | if (proxyurl != null && proxyurl.Length > 0) | 490 | // else |
491 | // { | ||
492 | // Request.ConnectionGroupName="Verify"; | ||
493 | // } | ||
494 | if (!HttpPragmaNoCache) | ||
495 | { | ||
496 | Request.Headers.Add("Pragma", "no-cache"); | ||
497 | } | ||
498 | if (HttpCustomHeaders != null) | ||
444 | { | 499 | { |
445 | if (proxyexcepts != null && proxyexcepts.Length > 0) | 500 | for (int i = 0; i < HttpCustomHeaders.Count; i += 2) |
501 | Request.Headers.Add(HttpCustomHeaders[i], | ||
502 | HttpCustomHeaders[i+1]); | ||
503 | } | ||
504 | if (proxyurl != null && proxyurl.Length > 0) | ||
505 | { | ||
506 | if (proxyexcepts != null && proxyexcepts.Length > 0) | ||
446 | { | 507 | { |
447 | string[] elist = proxyexcepts.Split(';'); | 508 | string[] elist = proxyexcepts.Split(';'); |
448 | Request.Proxy = new WebProxy(proxyurl, true, elist); | 509 | Request.Proxy = new WebProxy(proxyurl, true, elist); |
449 | } | 510 | } |
450 | else | 511 | else |
451 | { | 512 | { |
452 | Request.Proxy = new WebProxy(proxyurl, true); | 513 | Request.Proxy = new WebProxy(proxyurl, true); |
453 | } | 514 | } |
@@ -460,7 +521,7 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest | |||
460 | Request.Headers[entry.Key] = entry.Value; | 521 | Request.Headers[entry.Key] = entry.Value; |
461 | 522 | ||
462 | // Encode outbound data | 523 | // Encode outbound data |
463 | if (OutboundBody.Length > 0) | 524 | if (OutboundBody.Length > 0) |
464 | { | 525 | { |
465 | byte[] data = Util.UTF8.GetBytes(OutboundBody); | 526 | byte[] data = Util.UTF8.GetBytes(OutboundBody); |
466 | 527 | ||
diff --git a/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs b/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs index da59eab..f2922d6 100644 --- a/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs +++ b/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs | |||
@@ -50,6 +50,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp | |||
50 | public string url; | 50 | public string url; |
51 | public UUID urlcode; | 51 | public UUID urlcode; |
52 | public Dictionary<UUID, RequestData> requests; | 52 | public Dictionary<UUID, RequestData> requests; |
53 | public bool isSsl; | ||
53 | } | 54 | } |
54 | 55 | ||
55 | public class RequestData | 56 | public class RequestData |
@@ -83,20 +84,21 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp | |||
83 | private Dictionary<string, UrlData> m_UrlMap = | 84 | private Dictionary<string, UrlData> m_UrlMap = |
84 | new Dictionary<string, UrlData>(); | 85 | new Dictionary<string, UrlData>(); |
85 | 86 | ||
86 | /// <summary> | 87 | private uint m_HttpsPort = 0; |
87 | /// Maximum number of external urls that can be set up by this module. | ||
88 | /// </summary> | ||
89 | private int m_TotalUrls = 15000; | ||
90 | |||
91 | private uint https_port = 0; | ||
92 | private IHttpServer m_HttpServer = null; | 88 | private IHttpServer m_HttpServer = null; |
93 | private IHttpServer m_HttpsServer = null; | 89 | private IHttpServer m_HttpsServer = null; |
94 | 90 | ||
95 | private string m_ExternalHostNameForLSL = ""; | 91 | public string ExternalHostNameForLSL { get; private set; } |
96 | public string ExternalHostNameForLSL | 92 | |
97 | { | 93 | /// <summary> |
98 | get { return m_ExternalHostNameForLSL; } | 94 | /// The default maximum number of urls |
99 | } | 95 | /// </summary> |
96 | public const int DefaultTotalUrls = 15000; | ||
97 | |||
98 | /// <summary> | ||
99 | /// Maximum number of external urls that can be set up by this module. | ||
100 | /// </summary> | ||
101 | public int TotalUrls { get; set; } | ||
100 | 102 | ||
101 | public Type ReplaceableInterface | 103 | public Type ReplaceableInterface |
102 | { | 104 | { |
@@ -110,17 +112,27 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp | |||
110 | 112 | ||
111 | public void Initialise(IConfigSource config) | 113 | public void Initialise(IConfigSource config) |
112 | { | 114 | { |
113 | m_ExternalHostNameForLSL = config.Configs["Network"].GetString("ExternalHostNameForLSL", System.Environment.MachineName); | 115 | IConfig networkConfig = config.Configs["Network"]; |
114 | bool ssl_enabled = config.Configs["Network"].GetBoolean("https_listener",false); | 116 | |
115 | if (ssl_enabled) | 117 | if (networkConfig != null) |
116 | { | 118 | { |
117 | https_port = (uint) config.Configs["Network"].GetInt("https_port",0); | 119 | ExternalHostNameForLSL = config.Configs["Network"].GetString("ExternalHostNameForLSL", null); |
120 | |||
121 | bool ssl_enabled = config.Configs["Network"].GetBoolean("https_listener", false); | ||
122 | |||
123 | if (ssl_enabled) | ||
124 | m_HttpsPort = (uint)config.Configs["Network"].GetInt("https_port", (int)m_HttpsPort); | ||
118 | } | 125 | } |
119 | 126 | ||
127 | if (ExternalHostNameForLSL == null) | ||
128 | ExternalHostNameForLSL = System.Environment.MachineName; | ||
129 | |||
120 | IConfig llFunctionsConfig = config.Configs["LL-Functions"]; | 130 | IConfig llFunctionsConfig = config.Configs["LL-Functions"]; |
121 | 131 | ||
122 | if (llFunctionsConfig != null) | 132 | if (llFunctionsConfig != null) |
123 | m_TotalUrls = llFunctionsConfig.GetInt("max_external_urls_per_simulator", m_TotalUrls); | 133 | TotalUrls = llFunctionsConfig.GetInt("max_external_urls_per_simulator", DefaultTotalUrls); |
134 | else | ||
135 | TotalUrls = DefaultTotalUrls; | ||
124 | } | 136 | } |
125 | 137 | ||
126 | public void PostInitialise() | 138 | public void PostInitialise() |
@@ -136,9 +148,9 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp | |||
136 | m_HttpServer = MainServer.Instance; | 148 | m_HttpServer = MainServer.Instance; |
137 | // | 149 | // |
138 | // We can use the https if it is enabled | 150 | // We can use the https if it is enabled |
139 | if (https_port > 0) | 151 | if (m_HttpsPort > 0) |
140 | { | 152 | { |
141 | m_HttpsServer = MainServer.GetHttpServer(https_port); | 153 | m_HttpsServer = MainServer.GetHttpServer(m_HttpsPort); |
142 | } | 154 | } |
143 | } | 155 | } |
144 | 156 | ||
@@ -171,12 +183,12 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp | |||
171 | 183 | ||
172 | lock (m_UrlMap) | 184 | lock (m_UrlMap) |
173 | { | 185 | { |
174 | if (m_UrlMap.Count >= m_TotalUrls) | 186 | if (m_UrlMap.Count >= TotalUrls) |
175 | { | 187 | { |
176 | engine.PostScriptEvent(itemID, "http_request", new Object[] { urlcode.ToString(), "URL_REQUEST_DENIED", "" }); | 188 | engine.PostScriptEvent(itemID, "http_request", new Object[] { urlcode.ToString(), "URL_REQUEST_DENIED", "" }); |
177 | return urlcode; | 189 | return urlcode; |
178 | } | 190 | } |
179 | string url = "http://" + m_ExternalHostNameForLSL + ":" + m_HttpServer.Port.ToString() + "/lslhttp/" + urlcode.ToString(); | 191 | string url = "http://" + ExternalHostNameForLSL + ":" + m_HttpServer.Port.ToString() + "/lslhttp/" + urlcode.ToString(); |
180 | 192 | ||
181 | UrlData urlData = new UrlData(); | 193 | UrlData urlData = new UrlData(); |
182 | urlData.hostID = host.UUID; | 194 | urlData.hostID = host.UUID; |
@@ -184,6 +196,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp | |||
184 | urlData.engine = engine; | 196 | urlData.engine = engine; |
185 | urlData.url = url; | 197 | urlData.url = url; |
186 | urlData.urlcode = urlcode; | 198 | urlData.urlcode = urlcode; |
199 | urlData.isSsl = false; | ||
187 | urlData.requests = new Dictionary<UUID, RequestData>(); | 200 | urlData.requests = new Dictionary<UUID, RequestData>(); |
188 | 201 | ||
189 | m_UrlMap[url] = urlData; | 202 | m_UrlMap[url] = urlData; |
@@ -216,12 +229,12 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp | |||
216 | 229 | ||
217 | lock (m_UrlMap) | 230 | lock (m_UrlMap) |
218 | { | 231 | { |
219 | if (m_UrlMap.Count >= m_TotalUrls) | 232 | if (m_UrlMap.Count >= TotalUrls) |
220 | { | 233 | { |
221 | engine.PostScriptEvent(itemID, "http_request", new Object[] { urlcode.ToString(), "URL_REQUEST_DENIED", "" }); | 234 | engine.PostScriptEvent(itemID, "http_request", new Object[] { urlcode.ToString(), "URL_REQUEST_DENIED", "" }); |
222 | return urlcode; | 235 | return urlcode; |
223 | } | 236 | } |
224 | string url = "https://" + m_ExternalHostNameForLSL + ":" + m_HttpsServer.Port.ToString() + "/lslhttps/" + urlcode.ToString(); | 237 | string url = "https://" + ExternalHostNameForLSL + ":" + m_HttpsServer.Port.ToString() + "/lslhttps/" + urlcode.ToString(); |
225 | 238 | ||
226 | UrlData urlData = new UrlData(); | 239 | UrlData urlData = new UrlData(); |
227 | urlData.hostID = host.UUID; | 240 | urlData.hostID = host.UUID; |
@@ -229,6 +242,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp | |||
229 | urlData.engine = engine; | 242 | urlData.engine = engine; |
230 | urlData.url = url; | 243 | urlData.url = url; |
231 | urlData.urlcode = urlcode; | 244 | urlData.urlcode = urlcode; |
245 | urlData.isSsl = true; | ||
232 | urlData.requests = new Dictionary<UUID, RequestData>(); | 246 | urlData.requests = new Dictionary<UUID, RequestData>(); |
233 | 247 | ||
234 | 248 | ||
@@ -301,6 +315,21 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp | |||
301 | UrlData urlData = m_RequestMap[request]; | 315 | UrlData urlData = m_RequestMap[request]; |
302 | if (!urlData.requests[request].responseSent) | 316 | if (!urlData.requests[request].responseSent) |
303 | { | 317 | { |
318 | string responseBody = body; | ||
319 | if (urlData.requests[request].responseType.Equals("text/plain")) | ||
320 | { | ||
321 | string value; | ||
322 | if (urlData.requests[request].headers.TryGetValue("user-agent", out value)) | ||
323 | { | ||
324 | if (value != null && value.IndexOf("MSIE") >= 0) | ||
325 | { | ||
326 | // wrap the html escaped response if the target client is IE | ||
327 | // It ignores "text/plain" if the body is html | ||
328 | responseBody = "<html>" + System.Web.HttpUtility.HtmlEncode(body) + "</html>"; | ||
329 | } | ||
330 | } | ||
331 | } | ||
332 | |||
304 | urlData.requests[request].responseCode = status; | 333 | urlData.requests[request].responseCode = status; |
305 | urlData.requests[request].responseBody = body; | 334 | urlData.requests[request].responseBody = body; |
306 | //urlData.requests[request].ev.Set(); | 335 | //urlData.requests[request].ev.Set(); |
@@ -336,7 +365,8 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp | |||
336 | 365 | ||
337 | public int GetFreeUrls() | 366 | public int GetFreeUrls() |
338 | { | 367 | { |
339 | return m_TotalUrls - m_UrlMap.Count; | 368 | lock (m_UrlMap) |
369 | return TotalUrls - m_UrlMap.Count; | ||
340 | } | 370 | } |
341 | 371 | ||
342 | public void ScriptRemoved(UUID itemID) | 372 | public void ScriptRemoved(UUID itemID) |
@@ -394,7 +424,10 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp | |||
394 | 424 | ||
395 | private void RemoveUrl(UrlData data) | 425 | private void RemoveUrl(UrlData data) |
396 | { | 426 | { |
397 | m_HttpServer.RemoveHTTPHandler("", "/lslhttp/"+data.urlcode.ToString()+"/"); | 427 | if (data.isSsl) |
428 | m_HttpsServer.RemoveHTTPHandler("", "/lslhttps/"+data.urlcode.ToString()+"/"); | ||
429 | else | ||
430 | m_HttpServer.RemoveHTTPHandler("", "/lslhttp/"+data.urlcode.ToString()+"/"); | ||
398 | } | 431 | } |
399 | 432 | ||
400 | private Hashtable NoEvents(UUID requestID, UUID sessionID) | 433 | private Hashtable NoEvents(UUID requestID, UUID sessionID) |
@@ -527,7 +560,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp | |||
527 | { | 560 | { |
528 | Hashtable headers = (Hashtable)request["headers"]; | 561 | Hashtable headers = (Hashtable)request["headers"]; |
529 | 562 | ||
530 | // string uri_full = "http://" + m_ExternalHostNameForLSL + ":" + m_HttpServer.Port.ToString() + uri;// "/lslhttp/" + urlcode.ToString() + "/"; | 563 | // string uri_full = "http://" + ExternalHostNameForLSL + ":" + m_HttpServer.Port.ToString() + uri;// "/lslhttp/" + urlcode.ToString() + "/"; |
531 | 564 | ||
532 | int pos1 = uri.IndexOf("/");// /lslhttp | 565 | int pos1 = uri.IndexOf("/");// /lslhttp |
533 | int pos2 = uri.IndexOf("/", pos1 + 1);// /lslhttp/ | 566 | int pos2 = uri.IndexOf("/", pos1 + 1);// /lslhttp/ |
@@ -543,10 +576,10 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp | |||
543 | UrlData url = null; | 576 | UrlData url = null; |
544 | string urlkey; | 577 | string urlkey; |
545 | if (!is_ssl) | 578 | if (!is_ssl) |
546 | urlkey = "http://" + m_ExternalHostNameForLSL + ":" + m_HttpServer.Port.ToString() + uri_tmp; | 579 | urlkey = "http://" + ExternalHostNameForLSL + ":" + m_HttpServer.Port.ToString() + uri_tmp; |
547 | //m_UrlMap[]; | 580 | //m_UrlMap[]; |
548 | else | 581 | else |
549 | urlkey = "https://" + m_ExternalHostNameForLSL + ":" + m_HttpsServer.Port.ToString() + uri_tmp; | 582 | urlkey = "https://" + ExternalHostNameForLSL + ":" + m_HttpsServer.Port.ToString() + uri_tmp; |
550 | 583 | ||
551 | if (m_UrlMap.ContainsKey(urlkey)) | 584 | if (m_UrlMap.ContainsKey(urlkey)) |
552 | { | 585 | { |
diff --git a/OpenSim/Region/CoreModules/Scripting/ScriptModuleComms/ScriptModuleCommsModule.cs b/OpenSim/Region/CoreModules/Scripting/ScriptModuleComms/ScriptModuleCommsModule.cs index f6e1d39..fccf053 100644 --- a/OpenSim/Region/CoreModules/Scripting/ScriptModuleComms/ScriptModuleCommsModule.cs +++ b/OpenSim/Region/CoreModules/Scripting/ScriptModuleComms/ScriptModuleCommsModule.cs | |||
@@ -41,7 +41,7 @@ using System.Linq.Expressions; | |||
41 | namespace OpenSim.Region.CoreModules.Scripting.ScriptModuleComms | 41 | namespace OpenSim.Region.CoreModules.Scripting.ScriptModuleComms |
42 | { | 42 | { |
43 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "ScriptModuleCommsModule")] | 43 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "ScriptModuleCommsModule")] |
44 | class ScriptModuleCommsModule : INonSharedRegionModule, IScriptModuleComms | 44 | public class ScriptModuleCommsModule : INonSharedRegionModule, IScriptModuleComms |
45 | { | 45 | { |
46 | private static readonly ILog m_log = | 46 | private static readonly ILog m_log = |
47 | LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 47 | LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
@@ -262,6 +262,8 @@ namespace OpenSim.Region.CoreModules.Scripting.ScriptModuleComms | |||
262 | return "modInvokeR"; | 262 | return "modInvokeR"; |
263 | else if (sid.ReturnType == typeof(object[])) | 263 | else if (sid.ReturnType == typeof(object[])) |
264 | return "modInvokeL"; | 264 | return "modInvokeL"; |
265 | else if (sid.ReturnType == typeof(void)) | ||
266 | return "modInvokeN"; | ||
265 | 267 | ||
266 | m_log.WarnFormat("[MODULE COMMANDS] failed to find match for {0} with return type {1}",fname,sid.ReturnType.Name); | 268 | m_log.WarnFormat("[MODULE COMMANDS] failed to find match for {0} with return type {1}",fname,sid.ReturnType.Name); |
267 | } | 269 | } |
diff --git a/OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs b/OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs index f395441..2fc89fc 100644 --- a/OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs +++ b/OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs | |||
@@ -516,6 +516,9 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender | |||
516 | foreach (string line in GetLines(data, dataDelim)) | 516 | foreach (string line in GetLines(data, dataDelim)) |
517 | { | 517 | { |
518 | string nextLine = line.Trim(); | 518 | string nextLine = line.Trim(); |
519 | |||
520 | // m_log.DebugFormat("[VECTOR RENDER MODULE]: Processing line '{0}'", nextLine); | ||
521 | |||
519 | //replace with switch, or even better, do some proper parsing | 522 | //replace with switch, or even better, do some proper parsing |
520 | if (nextLine.StartsWith("MoveTo")) | 523 | if (nextLine.StartsWith("MoveTo")) |
521 | { | 524 | { |
@@ -829,6 +832,8 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender | |||
829 | float y = Convert.ToSingle(yVal, CultureInfo.InvariantCulture); | 832 | float y = Convert.ToSingle(yVal, CultureInfo.InvariantCulture); |
830 | PointF point = new PointF(x, y); | 833 | PointF point = new PointF(x, y); |
831 | points[i / 2] = point; | 834 | points[i / 2] = point; |
835 | |||
836 | // m_log.DebugFormat("[VECTOR RENDER MODULE]: Got point {0}", points[i / 2]); | ||
832 | } | 837 | } |
833 | } | 838 | } |
834 | } | 839 | } |
@@ -838,13 +843,17 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender | |||
838 | try | 843 | try |
839 | { | 844 | { |
840 | WebRequest request = HttpWebRequest.Create(url); | 845 | WebRequest request = HttpWebRequest.Create(url); |
841 | //Ckrinke: Comment out for now as 'str' is unused. Bring it back into play later when it is used. | 846 | |
842 | //Ckrinke Stream str = null; | 847 | using (HttpWebResponse response = (HttpWebResponse)(request).GetResponse()) |
843 | HttpWebResponse response = (HttpWebResponse)(request).GetResponse(); | ||
844 | if (response.StatusCode == HttpStatusCode.OK) | ||
845 | { | 848 | { |
846 | Bitmap image = new Bitmap(response.GetResponseStream()); | 849 | if (response.StatusCode == HttpStatusCode.OK) |
847 | return image; | 850 | { |
851 | using (Stream s = response.GetResponseStream()) | ||
852 | { | ||
853 | Bitmap image = new Bitmap(s); | ||
854 | return image; | ||
855 | } | ||
856 | } | ||
848 | } | 857 | } |
849 | } | 858 | } |
850 | catch { } | 859 | catch { } |
diff --git a/OpenSim/Region/CoreModules/Scripting/XMLRPC/XMLRPCModule.cs b/OpenSim/Region/CoreModules/Scripting/XMLRPC/XMLRPCModule.cs index 385f5ad..cbffca7 100644 --- a/OpenSim/Region/CoreModules/Scripting/XMLRPC/XMLRPCModule.cs +++ b/OpenSim/Region/CoreModules/Scripting/XMLRPC/XMLRPCModule.cs | |||
@@ -111,13 +111,15 @@ namespace OpenSim.Region.CoreModules.Scripting.XMLRPC | |||
111 | m_rpcPending = new Dictionary<UUID, RPCRequestInfo>(); | 111 | m_rpcPending = new Dictionary<UUID, RPCRequestInfo>(); |
112 | m_rpcPendingResponses = new Dictionary<UUID, RPCRequestInfo>(); | 112 | m_rpcPendingResponses = new Dictionary<UUID, RPCRequestInfo>(); |
113 | m_pendingSRDResponses = new Dictionary<UUID, SendRemoteDataRequest>(); | 113 | m_pendingSRDResponses = new Dictionary<UUID, SendRemoteDataRequest>(); |
114 | 114 | if (config.Configs["XMLRPC"] != null) | |
115 | try | ||
116 | { | ||
117 | m_remoteDataPort = config.Configs["XMLRPC"].GetInt("XmlRpcPort", m_remoteDataPort); | ||
118 | } | ||
119 | catch (Exception) | ||
120 | { | 115 | { |
116 | try | ||
117 | { | ||
118 | m_remoteDataPort = config.Configs["XMLRPC"].GetInt("XmlRpcPort", m_remoteDataPort); | ||
119 | } | ||
120 | catch (Exception) | ||
121 | { | ||
122 | } | ||
121 | } | 123 | } |
122 | } | 124 | } |
123 | 125 | ||
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs index 5836eb9..b61062f 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs | |||
@@ -75,7 +75,6 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage | |||
75 | public void Close() { } | 75 | public void Close() { } |
76 | public void PostInitialise() { } | 76 | public void PostInitialise() { } |
77 | 77 | ||
78 | |||
79 | ///<summary> | 78 | ///<summary> |
80 | /// | 79 | /// |
81 | ///</summary> | 80 | ///</summary> |
@@ -136,7 +135,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage | |||
136 | ///</summary> | 135 | ///</summary> |
137 | public void AddRegion(Scene scene) | 136 | public void AddRegion(Scene scene) |
138 | { | 137 | { |
139 | if (! m_enabled) | 138 | if (!m_enabled) |
140 | return; | 139 | return; |
141 | 140 | ||
142 | // Every shared region module has to maintain an indepedent list of | 141 | // Every shared region module has to maintain an indepedent list of |
@@ -209,6 +208,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage | |||
209 | 208 | ||
210 | using (Image mapTile = tileGenerator.CreateMapTile()) | 209 | using (Image mapTile = tileGenerator.CreateMapTile()) |
211 | { | 210 | { |
211 | // XXX: The MapImageModule will return a null if the user has chosen not to create map tiles and there | ||
212 | // is no static map tile. | ||
213 | if (mapTile == null) | ||
214 | return; | ||
215 | |||
212 | using (MemoryStream stream = new MemoryStream()) | 216 | using (MemoryStream stream = new MemoryStream()) |
213 | { | 217 | { |
214 | mapTile.Save(stream, ImageFormat.Jpeg); | 218 | mapTile.Save(stream, ImageFormat.Jpeg); |
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/Tests/PresenceConnectorsTests.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/Tests/PresenceConnectorsTests.cs index 32e47f9..69bac82 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/Tests/PresenceConnectorsTests.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/Tests/PresenceConnectorsTests.cs | |||
@@ -35,7 +35,6 @@ using NUnit.Framework; | |||
35 | using OpenMetaverse; | 35 | using OpenMetaverse; |
36 | using OpenSim.Framework; | 36 | using OpenSim.Framework; |
37 | using Nini.Config; | 37 | using Nini.Config; |
38 | |||
39 | using OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence; | 38 | using OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence; |
40 | using OpenSim.Region.Framework.Scenes; | 39 | using OpenSim.Region.Framework.Scenes; |
41 | using PresenceInfo = OpenSim.Services.Interfaces.PresenceInfo; | 40 | using PresenceInfo = OpenSim.Services.Interfaces.PresenceInfo; |
@@ -44,11 +43,14 @@ using OpenSim.Tests.Common; | |||
44 | namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence.Tests | 43 | namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence.Tests |
45 | { | 44 | { |
46 | [TestFixture] | 45 | [TestFixture] |
47 | public class PresenceConnectorsTests | 46 | public class PresenceConnectorsTests : OpenSimTestCase |
48 | { | 47 | { |
49 | LocalPresenceServicesConnector m_LocalConnector; | 48 | LocalPresenceServicesConnector m_LocalConnector; |
50 | private void SetUp() | 49 | |
50 | public override void SetUp() | ||
51 | { | 51 | { |
52 | base.SetUp(); | ||
53 | |||
52 | IConfigSource config = new IniConfigSource(); | 54 | IConfigSource config = new IniConfigSource(); |
53 | config.AddConfig("Modules"); | 55 | config.AddConfig("Modules"); |
54 | config.AddConfig("PresenceService"); | 56 | config.AddConfig("PresenceService"); |
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs index b485194..8b8bb37 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs | |||
@@ -219,12 +219,15 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation | |||
219 | { | 219 | { |
220 | // m_log.DebugFormat( | 220 | // m_log.DebugFormat( |
221 | // "[LOCAL SIMULATION CONNECTOR]: Found region {0} {1} to send AgentUpdate", | 221 | // "[LOCAL SIMULATION CONNECTOR]: Found region {0} {1} to send AgentUpdate", |
222 | // s.RegionInfo.RegionName, destination.RegionHandle); | 222 | // destination.RegionName, destination.RegionID); |
223 | 223 | ||
224 | return m_scenes[destination.RegionID].IncomingChildAgentDataUpdate(cAgentData); | 224 | return m_scenes[destination.RegionID].IncomingChildAgentDataUpdate(cAgentData); |
225 | } | 225 | } |
226 | 226 | ||
227 | // m_log.DebugFormat("[LOCAL COMMS]: Did not find region {0} for ChildAgentUpdate", regionHandle); | 227 | // m_log.DebugFormat( |
228 | // "[LOCAL COMMS]: Did not find region {0} {1} for ChildAgentUpdate", | ||
229 | // destination.RegionName, destination.RegionID); | ||
230 | |||
228 | return false; | 231 | return false; |
229 | } | 232 | } |
230 | 233 | ||
@@ -239,7 +242,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation | |||
239 | // note that we really don't need the GridRegion for this call | 242 | // note that we really don't need the GridRegion for this call |
240 | foreach (Scene s in m_scenes.Values) | 243 | foreach (Scene s in m_scenes.Values) |
241 | { | 244 | { |
242 | //m_log.Debug("[LOCAL COMMS]: Found region to send ChildAgentUpdate"); | 245 | // m_log.Debug("[LOCAL COMMS]: Found region to send ChildAgentUpdate"); |
243 | s.IncomingChildAgentDataUpdate(cAgentData); | 246 | s.IncomingChildAgentDataUpdate(cAgentData); |
244 | } | 247 | } |
245 | 248 | ||
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs index ade5e76..fcfdf7c 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs | |||
@@ -570,13 +570,22 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
570 | 570 | ||
571 | // Validate User and Group UUID's | 571 | // Validate User and Group UUID's |
572 | 572 | ||
573 | if (!ResolveUserUuid(scene, parcel.OwnerID)) | 573 | if (parcel.IsGroupOwned) |
574 | parcel.OwnerID = m_rootScene.RegionInfo.EstateSettings.EstateOwner; | 574 | { |
575 | 575 | if (!ResolveGroupUuid(parcel.GroupID)) | |
576 | if (!ResolveGroupUuid(parcel.GroupID)) | 576 | { |
577 | parcel.OwnerID = m_rootScene.RegionInfo.EstateSettings.EstateOwner; | ||
578 | parcel.GroupID = UUID.Zero; | ||
579 | parcel.IsGroupOwned = false; | ||
580 | } | ||
581 | } | ||
582 | else | ||
577 | { | 583 | { |
578 | parcel.GroupID = UUID.Zero; | 584 | if (!ResolveUserUuid(scene, parcel.OwnerID)) |
579 | parcel.IsGroupOwned = false; | 585 | parcel.OwnerID = m_rootScene.RegionInfo.EstateSettings.EstateOwner; |
586 | |||
587 | if (!ResolveGroupUuid(parcel.GroupID)) | ||
588 | parcel.GroupID = UUID.Zero; | ||
580 | } | 589 | } |
581 | 590 | ||
582 | List<LandAccessEntry> accessList = new List<LandAccessEntry>(); | 591 | List<LandAccessEntry> accessList = new List<LandAccessEntry>(); |
@@ -589,8 +598,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
589 | parcel.ParcelAccessList = accessList; | 598 | parcel.ParcelAccessList = accessList; |
590 | 599 | ||
591 | // m_log.DebugFormat( | 600 | // m_log.DebugFormat( |
592 | // "[ARCHIVER]: Adding parcel {0}, local id {1}, area {2}", | 601 | // "[ARCHIVER]: Adding parcel {0}, local id {1}, owner {2}, group {3}, isGroupOwned {4}, area {5}", |
593 | // parcel.Name, parcel.LocalID, parcel.Area); | 602 | // parcel.Name, parcel.LocalID, parcel.OwnerID, parcel.GroupID, parcel.IsGroupOwned, parcel.Area); |
594 | 603 | ||
595 | landData.Add(parcel); | 604 | landData.Add(parcel); |
596 | } | 605 | } |
@@ -613,13 +622,18 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
613 | /// <returns></returns> | 622 | /// <returns></returns> |
614 | private bool ResolveUserUuid(Scene scene, UUID uuid) | 623 | private bool ResolveUserUuid(Scene scene, UUID uuid) |
615 | { | 624 | { |
616 | if (!m_validUserUuids.ContainsKey(uuid)) | 625 | lock (m_validUserUuids) |
617 | { | 626 | { |
618 | UserAccount account = scene.UserAccountService.GetUserAccount(scene.RegionInfo.ScopeID, uuid); | 627 | if (!m_validUserUuids.ContainsKey(uuid)) |
619 | m_validUserUuids.Add(uuid, account != null); | 628 | { |
620 | } | 629 | // Note: we call GetUserAccount() inside the lock because this UserID is likely |
630 | // to occur many times, and we only want to query the users service once. | ||
631 | UserAccount account = scene.UserAccountService.GetUserAccount(scene.RegionInfo.ScopeID, uuid); | ||
632 | m_validUserUuids.Add(uuid, account != null); | ||
633 | } | ||
621 | 634 | ||
622 | return m_validUserUuids[uuid]; | 635 | return m_validUserUuids[uuid]; |
636 | } | ||
623 | } | 637 | } |
624 | 638 | ||
625 | /// <summary> | 639 | /// <summary> |
@@ -632,19 +646,26 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
632 | if (uuid == UUID.Zero) | 646 | if (uuid == UUID.Zero) |
633 | return true; // this means the object has no group | 647 | return true; // this means the object has no group |
634 | 648 | ||
635 | if (!m_validGroupUuids.ContainsKey(uuid)) | 649 | lock (m_validGroupUuids) |
636 | { | 650 | { |
637 | bool exists; | 651 | if (!m_validGroupUuids.ContainsKey(uuid)) |
638 | 652 | { | |
639 | if (m_groupsModule == null) | 653 | bool exists; |
640 | exists = false; | 654 | if (m_groupsModule == null) |
641 | else | 655 | { |
642 | exists = (m_groupsModule.GetGroupRecord(uuid) != null); | 656 | exists = false; |
657 | } | ||
658 | else | ||
659 | { | ||
660 | // Note: we call GetGroupRecord() inside the lock because this GroupID is likely | ||
661 | // to occur many times, and we only want to query the groups service once. | ||
662 | exists = (m_groupsModule.GetGroupRecord(uuid) != null); | ||
663 | } | ||
664 | m_validGroupUuids.Add(uuid, exists); | ||
665 | } | ||
643 | 666 | ||
644 | m_validGroupUuids.Add(uuid, exists); | 667 | return m_validGroupUuids[uuid]; |
645 | } | 668 | } |
646 | |||
647 | return m_validGroupUuids[uuid]; | ||
648 | } | 669 | } |
649 | 670 | ||
650 | /// Load an asset | 671 | /// Load an asset |
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs index d751b1c..a990898 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs | |||
@@ -44,6 +44,7 @@ using Ionic.Zlib; | |||
44 | using GZipStream = Ionic.Zlib.GZipStream; | 44 | using GZipStream = Ionic.Zlib.GZipStream; |
45 | using CompressionMode = Ionic.Zlib.CompressionMode; | 45 | using CompressionMode = Ionic.Zlib.CompressionMode; |
46 | using OpenSim.Framework.Serialization.External; | 46 | using OpenSim.Framework.Serialization.External; |
47 | using PermissionMask = OpenSim.Framework.PermissionMask; | ||
47 | 48 | ||
48 | namespace OpenSim.Region.CoreModules.World.Archiver | 49 | namespace OpenSim.Region.CoreModules.World.Archiver |
49 | { | 50 | { |
@@ -167,7 +168,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
167 | } | 168 | } |
168 | scenesGroup.CalcSceneLocations(); | 169 | scenesGroup.CalcSceneLocations(); |
169 | 170 | ||
170 | |||
171 | m_archiveWriter = new TarArchiveWriter(m_saveStream); | 171 | m_archiveWriter = new TarArchiveWriter(m_saveStream); |
172 | 172 | ||
173 | try | 173 | try |
@@ -216,7 +216,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
216 | } | 216 | } |
217 | } | 217 | } |
218 | 218 | ||
219 | |||
220 | private void ArchiveOneRegion(Scene scene, string regionDir, Dictionary<UUID, AssetType> assetUuids) | 219 | private void ArchiveOneRegion(Scene scene, string regionDir, Dictionary<UUID, AssetType> assetUuids) |
221 | { | 220 | { |
222 | m_log.InfoFormat("[ARCHIVER]: Writing region {0}", scene.RegionInfo.RegionName); | 221 | m_log.InfoFormat("[ARCHIVER]: Writing region {0}", scene.RegionInfo.RegionName); |
@@ -540,7 +539,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
540 | xtw.WriteElementString("size_in_meters", string.Format("{0},{1}", size.X, size.Y)); | 539 | xtw.WriteElementString("size_in_meters", string.Format("{0},{1}", size.X, size.Y)); |
541 | } | 540 | } |
542 | 541 | ||
543 | |||
544 | protected void Save(Scene scene, List<SceneObjectGroup> sceneObjects, string regionDir) | 542 | protected void Save(Scene scene, List<SceneObjectGroup> sceneObjects, string regionDir) |
545 | { | 543 | { |
546 | if (regionDir != string.Empty) | 544 | if (regionDir != string.Empty) |
@@ -560,8 +558,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
560 | foreach (ILandObject lo in landObjects) | 558 | foreach (ILandObject lo in landObjects) |
561 | { | 559 | { |
562 | LandData landData = lo.LandData; | 560 | LandData landData = lo.LandData; |
563 | string landDataPath = String.Format("{0}{1}{2}.xml", | 561 | string landDataPath |
564 | regionDir, ArchiveConstants.LANDDATA_PATH, landData.GlobalID.ToString()); | 562 | = String.Format("{0}{1}", regionDir, ArchiveConstants.CreateOarLandDataPath(landData)); |
565 | m_archiveWriter.WriteFile(landDataPath, LandDataSerializer.Serialize(landData, m_options)); | 563 | m_archiveWriter.WriteFile(landDataPath, LandDataSerializer.Serialize(landData, m_options)); |
566 | } | 564 | } |
567 | 565 | ||
@@ -590,21 +588,30 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
590 | } | 588 | } |
591 | } | 589 | } |
592 | 590 | ||
593 | protected void ReceivedAllAssets( | 591 | protected void ReceivedAllAssets(ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids, bool timedOut) |
594 | ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids) | ||
595 | { | 592 | { |
596 | foreach (UUID uuid in assetsNotFoundUuids) | 593 | string errorMessage; |
594 | |||
595 | if (timedOut) | ||
597 | { | 596 | { |
598 | m_log.DebugFormat("[ARCHIVER]: Could not find asset {0}", uuid); | 597 | errorMessage = "Loading assets timed out"; |
599 | } | 598 | } |
599 | else | ||
600 | { | ||
601 | foreach (UUID uuid in assetsNotFoundUuids) | ||
602 | { | ||
603 | m_log.DebugFormat("[ARCHIVER]: Could not find asset {0}", uuid); | ||
604 | } | ||
600 | 605 | ||
601 | // m_log.InfoFormat( | 606 | // m_log.InfoFormat( |
602 | // "[ARCHIVER]: Received {0} of {1} assets requested", | 607 | // "[ARCHIVER]: Received {0} of {1} assets requested", |
603 | // assetsFoundUuids.Count, assetsFoundUuids.Count + assetsNotFoundUuids.Count); | 608 | // assetsFoundUuids.Count, assetsFoundUuids.Count + assetsNotFoundUuids.Count); |
604 | 609 | ||
605 | CloseArchive(String.Empty); | 610 | errorMessage = String.Empty; |
611 | } | ||
612 | |||
613 | CloseArchive(errorMessage); | ||
606 | } | 614 | } |
607 | |||
608 | 615 | ||
609 | /// <summary> | 616 | /// <summary> |
610 | /// Closes the archive and notifies that we're done. | 617 | /// Closes the archive and notifies that we're done. |
@@ -629,6 +636,5 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
629 | 636 | ||
630 | m_rootScene.EventManager.TriggerOarFileSaved(m_requestId, errorMessage); | 637 | m_rootScene.EventManager.TriggerOarFileSaved(m_requestId, errorMessage); |
631 | } | 638 | } |
632 | |||
633 | } | 639 | } |
634 | } | 640 | } |
diff --git a/OpenSim/Region/CoreModules/World/Archiver/AssetsArchiver.cs b/OpenSim/Region/CoreModules/World/Archiver/AssetsArchiver.cs index 95d109c..c1ff94d 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/AssetsArchiver.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/AssetsArchiver.cs | |||
@@ -150,12 +150,5 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
150 | m_log.InfoFormat("[ARCHIVER]: Added {0} assets to archive", m_assetsWritten); | 150 | m_log.InfoFormat("[ARCHIVER]: Added {0} assets to archive", m_assetsWritten); |
151 | } | 151 | } |
152 | 152 | ||
153 | /// <summary> | ||
154 | /// Only call this if you need to force a close on the underlying writer. | ||
155 | /// </summary> | ||
156 | public void ForceClose() | ||
157 | { | ||
158 | m_archiveWriter.Close(); | ||
159 | } | ||
160 | } | 153 | } |
161 | } | 154 | } |
diff --git a/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs index e2f8833..ada7ecc 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs | |||
@@ -50,7 +50,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
50 | /// Method called when all the necessary assets for an archive request have been received. | 50 | /// Method called when all the necessary assets for an archive request have been received. |
51 | /// </summary> | 51 | /// </summary> |
52 | public delegate void AssetsRequestCallback( | 52 | public delegate void AssetsRequestCallback( |
53 | ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids); | 53 | ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids, bool timedOut); |
54 | 54 | ||
55 | enum RequestState | 55 | enum RequestState |
56 | { | 56 | { |
@@ -148,7 +148,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
148 | if (m_repliesRequired == 0) | 148 | if (m_repliesRequired == 0) |
149 | { | 149 | { |
150 | m_requestState = RequestState.Completed; | 150 | m_requestState = RequestState.Completed; |
151 | PerformAssetsRequestCallback(null); | 151 | PerformAssetsRequestCallback(false); |
152 | return; | 152 | return; |
153 | } | 153 | } |
154 | 154 | ||
@@ -156,6 +156,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
156 | 156 | ||
157 | foreach (KeyValuePair<UUID, AssetType> kvp in m_uuids) | 157 | foreach (KeyValuePair<UUID, AssetType> kvp in m_uuids) |
158 | { | 158 | { |
159 | // m_log.DebugFormat("[ARCHIVER]: Requesting asset {0}", kvp.Key); | ||
160 | |||
159 | // m_assetService.Get(kvp.Key.ToString(), kvp.Value, PreAssetRequestCallback); | 161 | // m_assetService.Get(kvp.Key.ToString(), kvp.Value, PreAssetRequestCallback); |
160 | AssetBase asset = m_assetService.Get(kvp.Key.ToString()); | 162 | AssetBase asset = m_assetService.Get(kvp.Key.ToString()); |
161 | PreAssetRequestCallback(kvp.Key.ToString(), kvp.Value, asset); | 163 | PreAssetRequestCallback(kvp.Key.ToString(), kvp.Value, asset); |
@@ -164,7 +166,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
164 | 166 | ||
165 | protected void OnRequestCallbackTimeout(object source, ElapsedEventArgs args) | 167 | protected void OnRequestCallbackTimeout(object source, ElapsedEventArgs args) |
166 | { | 168 | { |
167 | bool close = true; | 169 | bool timedOut = true; |
168 | 170 | ||
169 | try | 171 | try |
170 | { | 172 | { |
@@ -174,7 +176,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
174 | // the final request came in (assuming that such a thing is possible) | 176 | // the final request came in (assuming that such a thing is possible) |
175 | if (m_requestState == RequestState.Completed) | 177 | if (m_requestState == RequestState.Completed) |
176 | { | 178 | { |
177 | close = false; | 179 | timedOut = false; |
178 | return; | 180 | return; |
179 | } | 181 | } |
180 | 182 | ||
@@ -223,8 +225,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
223 | } | 225 | } |
224 | finally | 226 | finally |
225 | { | 227 | { |
226 | if (close) | 228 | if (timedOut) |
227 | m_assetsArchiver.ForceClose(); | 229 | Util.FireAndForget(PerformAssetsRequestCallback, true); |
228 | } | 230 | } |
229 | } | 231 | } |
230 | 232 | ||
@@ -290,7 +292,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
290 | 292 | ||
291 | // We want to stop using the asset cache thread asap | 293 | // We want to stop using the asset cache thread asap |
292 | // as we now need to do the work of producing the rest of the archive | 294 | // as we now need to do the work of producing the rest of the archive |
293 | Util.FireAndForget(PerformAssetsRequestCallback); | 295 | Util.FireAndForget(PerformAssetsRequestCallback, false); |
294 | } | 296 | } |
295 | else | 297 | else |
296 | { | 298 | { |
@@ -311,9 +313,11 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
311 | { | 313 | { |
312 | Culture.SetCurrentCulture(); | 314 | Culture.SetCurrentCulture(); |
313 | 315 | ||
316 | Boolean timedOut = (Boolean)o; | ||
317 | |||
314 | try | 318 | try |
315 | { | 319 | { |
316 | m_assetsRequestCallback(m_foundAssetUuids, m_notFoundAssetUuids); | 320 | m_assetsRequestCallback(m_foundAssetUuids, m_notFoundAssetUuids, timedOut); |
317 | } | 321 | } |
318 | catch (Exception e) | 322 | catch (Exception e) |
319 | { | 323 | { |
diff --git a/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs b/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs index 82f49b0..eec1cec 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs | |||
@@ -31,16 +31,19 @@ using System.IO; | |||
31 | using System.Reflection; | 31 | using System.Reflection; |
32 | using System.Threading; | 32 | using System.Threading; |
33 | using log4net.Config; | 33 | using log4net.Config; |
34 | using Nini.Config; | ||
34 | using NUnit.Framework; | 35 | using NUnit.Framework; |
35 | using OpenMetaverse; | 36 | using OpenMetaverse; |
36 | using OpenMetaverse.Assets; | 37 | using OpenMetaverse.Assets; |
37 | using OpenSim.Framework; | 38 | using OpenSim.Framework; |
38 | using OpenSim.Framework.Serialization; | 39 | using OpenSim.Framework.Serialization; |
39 | using OpenSim.Framework.Serialization.External; | 40 | using OpenSim.Framework.Serialization.External; |
41 | using OpenSim.Region.CoreModules.World.Land; | ||
40 | using OpenSim.Region.CoreModules.World.Serialiser; | 42 | using OpenSim.Region.CoreModules.World.Serialiser; |
41 | using OpenSim.Region.CoreModules.World.Terrain; | 43 | using OpenSim.Region.CoreModules.World.Terrain; |
42 | using OpenSim.Region.Framework.Scenes; | 44 | using OpenSim.Region.Framework.Scenes; |
43 | using OpenSim.Region.Framework.Scenes.Serialization; | 45 | using OpenSim.Region.Framework.Scenes.Serialization; |
46 | using OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups; | ||
44 | using OpenSim.Tests.Common; | 47 | using OpenSim.Tests.Common; |
45 | using OpenSim.Tests.Common.Mock; | 48 | using OpenSim.Tests.Common.Mock; |
46 | using ArchiveConstants = OpenSim.Framework.Serialization.ArchiveConstants; | 49 | using ArchiveConstants = OpenSim.Framework.Serialization.ArchiveConstants; |
@@ -69,9 +72,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests | |||
69 | { | 72 | { |
70 | base.SetUp(); | 73 | base.SetUp(); |
71 | 74 | ||
72 | // FIXME: Do something about this - relying on statics in unit tests causes trouble sooner or later | ||
73 | new SceneManager(); | ||
74 | |||
75 | m_archiverModule = new ArchiverModule(); | 75 | m_archiverModule = new ArchiverModule(); |
76 | m_serialiserModule = new SerialiserModule(); | 76 | m_serialiserModule = new SerialiserModule(); |
77 | TerrainModule terrainModule = new TerrainModule(); | 77 | TerrainModule terrainModule = new TerrainModule(); |
@@ -127,6 +127,53 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests | |||
127 | 127 | ||
128 | return new SceneObjectPart(ownerId, shape, groupPosition, rotationOffset, offsetPosition) { Name = partName }; | 128 | return new SceneObjectPart(ownerId, shape, groupPosition, rotationOffset, offsetPosition) { Name = partName }; |
129 | } | 129 | } |
130 | |||
131 | private void CreateTestObjects(Scene scene, out SceneObjectGroup sog1, out SceneObjectGroup sog2, out UUID ncAssetUuid) | ||
132 | { | ||
133 | SceneObjectPart part1 = CreateSceneObjectPart1(); | ||
134 | sog1 = new SceneObjectGroup(part1); | ||
135 | scene.AddNewSceneObject(sog1, false); | ||
136 | |||
137 | AssetNotecard nc = new AssetNotecard(); | ||
138 | nc.BodyText = "Hello World!"; | ||
139 | nc.Encode(); | ||
140 | ncAssetUuid = UUID.Random(); | ||
141 | UUID ncItemUuid = UUID.Random(); | ||
142 | AssetBase ncAsset | ||
143 | = AssetHelpers.CreateAsset(ncAssetUuid, AssetType.Notecard, nc.AssetData, UUID.Zero); | ||
144 | m_scene.AssetService.Store(ncAsset); | ||
145 | |||
146 | TaskInventoryItem ncItem | ||
147 | = new TaskInventoryItem { Name = "ncItem", AssetID = ncAssetUuid, ItemID = ncItemUuid }; | ||
148 | SceneObjectPart part2 = CreateSceneObjectPart2(); | ||
149 | sog2 = new SceneObjectGroup(part2); | ||
150 | part2.Inventory.AddInventoryItem(ncItem, true); | ||
151 | |||
152 | scene.AddNewSceneObject(sog2, false); | ||
153 | } | ||
154 | |||
155 | private static void CreateSoundAsset(TarArchiveWriter tar, Assembly assembly, string soundDataResourceName, out byte[] soundData, out UUID soundUuid) | ||
156 | { | ||
157 | using (Stream resource = assembly.GetManifestResourceStream(soundDataResourceName)) | ||
158 | { | ||
159 | using (BinaryReader br = new BinaryReader(resource)) | ||
160 | { | ||
161 | // FIXME: Use the inspector instead | ||
162 | soundData = br.ReadBytes(99999999); | ||
163 | soundUuid = UUID.Parse("00000000-0000-0000-0000-000000000001"); | ||
164 | string soundAssetFileName | ||
165 | = ArchiveConstants.ASSETS_PATH + soundUuid | ||
166 | + ArchiveConstants.ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.SoundWAV]; | ||
167 | tar.WriteFile(soundAssetFileName, soundData); | ||
168 | |||
169 | /* | ||
170 | AssetBase soundAsset = AssetHelpers.CreateAsset(soundUuid, soundData); | ||
171 | scene.AssetService.Store(soundAsset); | ||
172 | asset1FileName = ArchiveConstants.ASSETS_PATH + soundUuid + ".wav"; | ||
173 | */ | ||
174 | } | ||
175 | } | ||
176 | } | ||
130 | 177 | ||
131 | /// <summary> | 178 | /// <summary> |
132 | /// Test saving an OpenSim Region Archive. | 179 | /// Test saving an OpenSim Region Archive. |
@@ -204,30 +251,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests | |||
204 | // TODO: Test presence of more files and contents of files. | 251 | // TODO: Test presence of more files and contents of files. |
205 | } | 252 | } |
206 | 253 | ||
207 | private void CreateTestObjects(Scene scene, out SceneObjectGroup sog1, out SceneObjectGroup sog2, out UUID ncAssetUuid) | ||
208 | { | ||
209 | SceneObjectPart part1 = CreateSceneObjectPart1(); | ||
210 | sog1 = new SceneObjectGroup(part1); | ||
211 | scene.AddNewSceneObject(sog1, false); | ||
212 | |||
213 | AssetNotecard nc = new AssetNotecard(); | ||
214 | nc.BodyText = "Hello World!"; | ||
215 | nc.Encode(); | ||
216 | ncAssetUuid = UUID.Random(); | ||
217 | UUID ncItemUuid = UUID.Random(); | ||
218 | AssetBase ncAsset | ||
219 | = AssetHelpers.CreateAsset(ncAssetUuid, AssetType.Notecard, nc.AssetData, UUID.Zero); | ||
220 | m_scene.AssetService.Store(ncAsset); | ||
221 | |||
222 | TaskInventoryItem ncItem | ||
223 | = new TaskInventoryItem { Name = "ncItem", AssetID = ncAssetUuid, ItemID = ncItemUuid }; | ||
224 | SceneObjectPart part2 = CreateSceneObjectPart2(); | ||
225 | sog2 = new SceneObjectGroup(part2); | ||
226 | part2.Inventory.AddInventoryItem(ncItem, true); | ||
227 | |||
228 | scene.AddNewSceneObject(sog2, false); | ||
229 | } | ||
230 | |||
231 | /// <summary> | 254 | /// <summary> |
232 | /// Test saving an OpenSim Region Archive with the no assets option | 255 | /// Test saving an OpenSim Region Archive with the no assets option |
233 | /// </summary> | 256 | /// </summary> |
@@ -309,59 +332,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests | |||
309 | } | 332 | } |
310 | 333 | ||
311 | /// <summary> | 334 | /// <summary> |
312 | /// Test loading an OpenSim Region Archive where the scene object parts are not ordered by link number (e.g. | ||
313 | /// 2 can come after 3). | ||
314 | /// </summary> | ||
315 | [Test] | ||
316 | public void TestLoadOarUnorderedParts() | ||
317 | { | ||
318 | TestHelpers.InMethod(); | ||
319 | |||
320 | UUID ownerId = TestHelpers.ParseTail(0xaaaa); | ||
321 | |||
322 | MemoryStream archiveWriteStream = new MemoryStream(); | ||
323 | TarArchiveWriter tar = new TarArchiveWriter(archiveWriteStream); | ||
324 | |||
325 | tar.WriteFile( | ||
326 | ArchiveConstants.CONTROL_FILE_PATH, | ||
327 | new ArchiveWriteRequest(m_scene, (Stream)null, Guid.Empty).CreateControlFile(new ArchiveScenesGroup())); | ||
328 | |||
329 | SceneObjectGroup sog1 = SceneHelpers.CreateSceneObject(1, ownerId, "obj1-", 0x11); | ||
330 | SceneObjectPart sop2 | ||
331 | = SceneHelpers.CreateSceneObjectPart("obj1-Part2", TestHelpers.ParseTail(0x12), ownerId); | ||
332 | SceneObjectPart sop3 | ||
333 | = SceneHelpers.CreateSceneObjectPart("obj1-Part3", TestHelpers.ParseTail(0x13), ownerId); | ||
334 | |||
335 | // Add the parts so they will be written out in reverse order to the oar | ||
336 | sog1.AddPart(sop3); | ||
337 | sop3.LinkNum = 3; | ||
338 | sog1.AddPart(sop2); | ||
339 | sop2.LinkNum = 2; | ||
340 | |||
341 | tar.WriteFile( | ||
342 | ArchiveConstants.CreateOarObjectPath(sog1.Name, sog1.UUID, sog1.AbsolutePosition), | ||
343 | SceneObjectSerializer.ToXml2Format(sog1)); | ||
344 | |||
345 | tar.Close(); | ||
346 | |||
347 | MemoryStream archiveReadStream = new MemoryStream(archiveWriteStream.ToArray()); | ||
348 | |||
349 | lock (this) | ||
350 | { | ||
351 | m_scene.EventManager.OnOarFileLoaded += LoadCompleted; | ||
352 | m_archiverModule.DearchiveRegion(archiveReadStream); | ||
353 | } | ||
354 | |||
355 | Assert.That(m_lastErrorMessage, Is.Null); | ||
356 | |||
357 | SceneObjectPart part2 = m_scene.GetSceneObjectPart("obj1-Part2"); | ||
358 | Assert.That(part2.LinkNum, Is.EqualTo(2)); | ||
359 | |||
360 | SceneObjectPart part3 = m_scene.GetSceneObjectPart("obj1-Part3"); | ||
361 | Assert.That(part3.LinkNum, Is.EqualTo(3)); | ||
362 | } | ||
363 | |||
364 | /// <summary> | ||
365 | /// Test loading an OpenSim Region Archive. | 335 | /// Test loading an OpenSim Region Archive. |
366 | /// </summary> | 336 | /// </summary> |
367 | [Test] | 337 | [Test] |
@@ -435,50 +405,57 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests | |||
435 | TestLoadedRegion(part1, soundItemName, soundData); | 405 | TestLoadedRegion(part1, soundItemName, soundData); |
436 | } | 406 | } |
437 | 407 | ||
438 | private static void CreateSoundAsset(TarArchiveWriter tar, Assembly assembly, string soundDataResourceName, out byte[] soundData, out UUID soundUuid) | 408 | /// <summary> |
409 | /// Test loading an OpenSim Region Archive where the scene object parts are not ordered by link number (e.g. | ||
410 | /// 2 can come after 3). | ||
411 | /// </summary> | ||
412 | [Test] | ||
413 | public void TestLoadOarUnorderedParts() | ||
439 | { | 414 | { |
440 | using (Stream resource = assembly.GetManifestResourceStream(soundDataResourceName)) | 415 | TestHelpers.InMethod(); |
441 | { | ||
442 | using (BinaryReader br = new BinaryReader(resource)) | ||
443 | { | ||
444 | // FIXME: Use the inspector instead | ||
445 | soundData = br.ReadBytes(99999999); | ||
446 | soundUuid = UUID.Parse("00000000-0000-0000-0000-000000000001"); | ||
447 | string soundAssetFileName | ||
448 | = ArchiveConstants.ASSETS_PATH + soundUuid | ||
449 | + ArchiveConstants.ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.SoundWAV]; | ||
450 | tar.WriteFile(soundAssetFileName, soundData); | ||
451 | 416 | ||
452 | /* | 417 | UUID ownerId = TestHelpers.ParseTail(0xaaaa); |
453 | AssetBase soundAsset = AssetHelpers.CreateAsset(soundUuid, soundData); | ||
454 | scene.AssetService.Store(soundAsset); | ||
455 | asset1FileName = ArchiveConstants.ASSETS_PATH + soundUuid + ".wav"; | ||
456 | */ | ||
457 | } | ||
458 | } | ||
459 | } | ||
460 | 418 | ||
461 | private void TestLoadedRegion(SceneObjectPart part1, string soundItemName, byte[] soundData) | 419 | MemoryStream archiveWriteStream = new MemoryStream(); |
462 | { | 420 | TarArchiveWriter tar = new TarArchiveWriter(archiveWriteStream); |
463 | SceneObjectPart object1PartLoaded = m_scene.GetSceneObjectPart(part1.Name); | ||
464 | 421 | ||
465 | Assert.That(object1PartLoaded, Is.Not.Null, "object1 was not loaded"); | 422 | tar.WriteFile( |
466 | Assert.That(object1PartLoaded.Name, Is.EqualTo(part1.Name), "object1 names not identical"); | 423 | ArchiveConstants.CONTROL_FILE_PATH, |
467 | Assert.That(object1PartLoaded.GroupPosition, Is.EqualTo(part1.GroupPosition), "object1 group position not equal"); | 424 | new ArchiveWriteRequest(m_scene, (Stream)null, Guid.Empty).CreateControlFile(new ArchiveScenesGroup())); |
468 | Assert.That( | ||
469 | object1PartLoaded.RotationOffset, Is.EqualTo(part1.RotationOffset), "object1 rotation offset not equal"); | ||
470 | Assert.That( | ||
471 | object1PartLoaded.OffsetPosition, Is.EqualTo(part1.OffsetPosition), "object1 offset position not equal"); | ||
472 | Assert.That(object1PartLoaded.SitTargetOrientation, Is.EqualTo(part1.SitTargetOrientation)); | ||
473 | Assert.That(object1PartLoaded.SitTargetPosition, Is.EqualTo(part1.SitTargetPosition)); | ||
474 | 425 | ||
475 | TaskInventoryItem loadedSoundItem = object1PartLoaded.Inventory.GetInventoryItems(soundItemName)[0]; | 426 | SceneObjectGroup sog1 = SceneHelpers.CreateSceneObject(1, ownerId, "obj1-", 0x11); |
476 | Assert.That(loadedSoundItem, Is.Not.Null, "loaded sound item was null"); | 427 | SceneObjectPart sop2 |
477 | AssetBase loadedSoundAsset = m_scene.AssetService.Get(loadedSoundItem.AssetID.ToString()); | 428 | = SceneHelpers.CreateSceneObjectPart("obj1-Part2", TestHelpers.ParseTail(0x12), ownerId); |
478 | Assert.That(loadedSoundAsset, Is.Not.Null, "loaded sound asset was null"); | 429 | SceneObjectPart sop3 |
479 | Assert.That(loadedSoundAsset.Data, Is.EqualTo(soundData), "saved and loaded sound data do not match"); | 430 | = SceneHelpers.CreateSceneObjectPart("obj1-Part3", TestHelpers.ParseTail(0x13), ownerId); |
480 | 431 | ||
481 | Assert.Greater(m_scene.LandChannel.AllParcels().Count, 0, "incorrect number of parcels"); | 432 | // Add the parts so they will be written out in reverse order to the oar |
433 | sog1.AddPart(sop3); | ||
434 | sop3.LinkNum = 3; | ||
435 | sog1.AddPart(sop2); | ||
436 | sop2.LinkNum = 2; | ||
437 | |||
438 | tar.WriteFile( | ||
439 | ArchiveConstants.CreateOarObjectPath(sog1.Name, sog1.UUID, sog1.AbsolutePosition), | ||
440 | SceneObjectSerializer.ToXml2Format(sog1)); | ||
441 | |||
442 | tar.Close(); | ||
443 | |||
444 | MemoryStream archiveReadStream = new MemoryStream(archiveWriteStream.ToArray()); | ||
445 | |||
446 | lock (this) | ||
447 | { | ||
448 | m_scene.EventManager.OnOarFileLoaded += LoadCompleted; | ||
449 | m_archiverModule.DearchiveRegion(archiveReadStream); | ||
450 | } | ||
451 | |||
452 | Assert.That(m_lastErrorMessage, Is.Null); | ||
453 | |||
454 | SceneObjectPart part2 = m_scene.GetSceneObjectPart("obj1-Part2"); | ||
455 | Assert.That(part2.LinkNum, Is.EqualTo(2)); | ||
456 | |||
457 | SceneObjectPart part3 = m_scene.GetSceneObjectPart("obj1-Part3"); | ||
458 | Assert.That(part3.LinkNum, Is.EqualTo(3)); | ||
482 | } | 459 | } |
483 | 460 | ||
484 | /// <summary> | 461 | /// <summary> |
@@ -538,8 +515,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests | |||
538 | SerialiserModule serialiserModule = new SerialiserModule(); | 515 | SerialiserModule serialiserModule = new SerialiserModule(); |
539 | TerrainModule terrainModule = new TerrainModule(); | 516 | TerrainModule terrainModule = new TerrainModule(); |
540 | 517 | ||
541 | m_sceneHelpers = new SceneHelpers(); | 518 | SceneHelpers m_sceneHelpers2 = new SceneHelpers(); |
542 | TestScene scene2 = m_sceneHelpers.SetupScene(); | 519 | TestScene scene2 = m_sceneHelpers2.SetupScene(); |
543 | SceneHelpers.SetupSceneModules(scene2, archiverModule, serialiserModule, terrainModule); | 520 | SceneHelpers.SetupSceneModules(scene2, archiverModule, serialiserModule, terrainModule); |
544 | 521 | ||
545 | // Make sure there's a valid owner for the owner we saved (this should have been wiped if the code is | 522 | // Make sure there's a valid owner for the owner we saved (this should have been wiped if the code is |
@@ -563,6 +540,71 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests | |||
563 | } | 540 | } |
564 | 541 | ||
565 | /// <summary> | 542 | /// <summary> |
543 | /// Test OAR loading where the land parcel is group deeded. | ||
544 | /// </summary> | ||
545 | /// <remarks> | ||
546 | /// In this situation, the owner ID is set to the group ID. | ||
547 | /// </remarks> | ||
548 | [Test] | ||
549 | public void TestLoadOarDeededLand() | ||
550 | { | ||
551 | TestHelpers.InMethod(); | ||
552 | // TestHelpers.EnableLogging(); | ||
553 | |||
554 | UUID landID = TestHelpers.ParseTail(0x10); | ||
555 | |||
556 | MockGroupsServicesConnector groupsService = new MockGroupsServicesConnector(); | ||
557 | |||
558 | IConfigSource configSource = new IniConfigSource(); | ||
559 | IConfig config = configSource.AddConfig("Groups"); | ||
560 | config.Set("Enabled", true); | ||
561 | config.Set("Module", "GroupsModule"); | ||
562 | config.Set("DebugEnabled", true); | ||
563 | SceneHelpers.SetupSceneModules( | ||
564 | m_scene, configSource, new object[] { new GroupsModule(), groupsService, new LandManagementModule() }); | ||
565 | |||
566 | // Create group in scene for loading | ||
567 | // FIXME: For now we'll put up with the issue that we'll get a group ID that varies across tests. | ||
568 | UUID groupID | ||
569 | = groupsService.CreateGroup(UUID.Zero, "group1", "", true, UUID.Zero, 3, true, true, true, UUID.Zero); | ||
570 | |||
571 | // Construct OAR | ||
572 | MemoryStream oarStream = new MemoryStream(); | ||
573 | TarArchiveWriter tar = new TarArchiveWriter(oarStream); | ||
574 | |||
575 | tar.WriteDir(ArchiveConstants.LANDDATA_PATH); | ||
576 | tar.WriteFile( | ||
577 | ArchiveConstants.CONTROL_FILE_PATH, | ||
578 | new ArchiveWriteRequest(m_scene, (Stream)null, Guid.Empty).CreateControlFile(new ArchiveScenesGroup())); | ||
579 | |||
580 | LandObject lo = new LandObject(groupID, true, null); | ||
581 | lo.SetLandBitmap(lo.BasicFullRegionLandBitmap()); | ||
582 | LandData ld = lo.LandData; | ||
583 | ld.GlobalID = landID; | ||
584 | |||
585 | string ldPath = ArchiveConstants.CreateOarLandDataPath(ld); | ||
586 | tar.WriteFile(ldPath, LandDataSerializer.Serialize(ld, null)); | ||
587 | tar.Close(); | ||
588 | |||
589 | oarStream = new MemoryStream(oarStream.ToArray()); | ||
590 | |||
591 | // Load OAR | ||
592 | lock (this) | ||
593 | { | ||
594 | m_scene.EventManager.OnOarFileLoaded += LoadCompleted; | ||
595 | m_archiverModule.DearchiveRegion(oarStream); | ||
596 | } | ||
597 | |||
598 | ILandObject rLo = m_scene.LandChannel.GetLandObject(16, 16); | ||
599 | LandData rLd = rLo.LandData; | ||
600 | |||
601 | Assert.That(rLd.GlobalID, Is.EqualTo(landID)); | ||
602 | Assert.That(rLd.OwnerID, Is.EqualTo(groupID)); | ||
603 | Assert.That(rLd.GroupID, Is.EqualTo(groupID)); | ||
604 | Assert.That(rLd.IsGroupOwned, Is.EqualTo(true)); | ||
605 | } | ||
606 | |||
607 | /// <summary> | ||
566 | /// Test loading the region settings of an OpenSim Region Archive. | 608 | /// Test loading the region settings of an OpenSim Region Archive. |
567 | /// </summary> | 609 | /// </summary> |
568 | [Test] | 610 | [Test] |
@@ -781,9 +823,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests | |||
781 | } | 823 | } |
782 | } | 824 | } |
783 | 825 | ||
784 | |||
785 | // Save OAR | 826 | // Save OAR |
786 | |||
787 | MemoryStream archiveWriteStream = new MemoryStream(); | 827 | MemoryStream archiveWriteStream = new MemoryStream(); |
788 | m_scene.EventManager.OnOarFileSaved += SaveCompleted; | 828 | m_scene.EventManager.OnOarFileSaved += SaveCompleted; |
789 | 829 | ||
@@ -800,7 +840,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests | |||
800 | 840 | ||
801 | 841 | ||
802 | // Check that the OAR contains the expected data | 842 | // Check that the OAR contains the expected data |
803 | |||
804 | Assert.That(m_lastRequestId, Is.EqualTo(requestId)); | 843 | Assert.That(m_lastRequestId, Is.EqualTo(requestId)); |
805 | 844 | ||
806 | byte[] archive = archiveWriteStream.ToArray(); | 845 | byte[] archive = archiveWriteStream.ToArray(); |
@@ -892,7 +931,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests | |||
892 | } | 931 | } |
893 | 932 | ||
894 | ArchiveScenesGroup scenesGroup = new ArchiveScenesGroup(); | 933 | ArchiveScenesGroup scenesGroup = new ArchiveScenesGroup(); |
895 | SceneManager.Instance.ForEachScene(delegate(Scene scene) | 934 | m_sceneHelpers.SceneManager.ForEachScene(delegate(Scene scene) |
896 | { | 935 | { |
897 | scenesGroup.AddScene(scene); | 936 | scenesGroup.AddScene(scene); |
898 | }); | 937 | }); |
@@ -950,13 +989,13 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests | |||
950 | 989 | ||
951 | // Delete the current objects, to test that they're loaded from the OAR and didn't | 990 | // Delete the current objects, to test that they're loaded from the OAR and didn't |
952 | // just remain in the scene. | 991 | // just remain in the scene. |
953 | SceneManager.Instance.ForEachScene(delegate(Scene scene) | 992 | m_sceneHelpers.SceneManager.ForEachScene(delegate(Scene scene) |
954 | { | 993 | { |
955 | scene.DeleteAllSceneObjects(); | 994 | scene.DeleteAllSceneObjects(); |
956 | }); | 995 | }); |
957 | 996 | ||
958 | // Create a "hole", to test that that the corresponding region isn't loaded from the OAR | 997 | // Create a "hole", to test that that the corresponding region isn't loaded from the OAR |
959 | SceneManager.Instance.CloseScene(SceneManager.Instance.Scenes[1]); | 998 | m_sceneHelpers.SceneManager.CloseScene(SceneManager.Instance.Scenes[1]); |
960 | 999 | ||
961 | 1000 | ||
962 | // Check thay the OAR file contains the expected data | 1001 | // Check thay the OAR file contains the expected data |
@@ -971,10 +1010,32 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests | |||
971 | 1010 | ||
972 | Assert.That(m_lastErrorMessage, Is.Null); | 1011 | Assert.That(m_lastErrorMessage, Is.Null); |
973 | 1012 | ||
974 | Assert.AreEqual(3, SceneManager.Instance.Scenes.Count); | 1013 | Assert.AreEqual(3, m_sceneHelpers.SceneManager.Scenes.Count); |
975 | 1014 | ||
976 | TestLoadedRegion(part1, soundItemName, soundData); | 1015 | TestLoadedRegion(part1, soundItemName, soundData); |
977 | } | 1016 | } |
978 | 1017 | ||
1018 | private void TestLoadedRegion(SceneObjectPart part1, string soundItemName, byte[] soundData) | ||
1019 | { | ||
1020 | SceneObjectPart object1PartLoaded = m_scene.GetSceneObjectPart(part1.Name); | ||
1021 | |||
1022 | Assert.That(object1PartLoaded, Is.Not.Null, "object1 was not loaded"); | ||
1023 | Assert.That(object1PartLoaded.Name, Is.EqualTo(part1.Name), "object1 names not identical"); | ||
1024 | Assert.That(object1PartLoaded.GroupPosition, Is.EqualTo(part1.GroupPosition), "object1 group position not equal"); | ||
1025 | Assert.That( | ||
1026 | object1PartLoaded.RotationOffset, Is.EqualTo(part1.RotationOffset), "object1 rotation offset not equal"); | ||
1027 | Assert.That( | ||
1028 | object1PartLoaded.OffsetPosition, Is.EqualTo(part1.OffsetPosition), "object1 offset position not equal"); | ||
1029 | Assert.That(object1PartLoaded.SitTargetOrientation, Is.EqualTo(part1.SitTargetOrientation)); | ||
1030 | Assert.That(object1PartLoaded.SitTargetPosition, Is.EqualTo(part1.SitTargetPosition)); | ||
1031 | |||
1032 | TaskInventoryItem loadedSoundItem = object1PartLoaded.Inventory.GetInventoryItems(soundItemName)[0]; | ||
1033 | Assert.That(loadedSoundItem, Is.Not.Null, "loaded sound item was null"); | ||
1034 | AssetBase loadedSoundAsset = m_scene.AssetService.Get(loadedSoundItem.AssetID.ToString()); | ||
1035 | Assert.That(loadedSoundAsset, Is.Not.Null, "loaded sound asset was null"); | ||
1036 | Assert.That(loadedSoundAsset.Data, Is.EqualTo(soundData), "saved and loaded sound data do not match"); | ||
1037 | |||
1038 | Assert.Greater(m_scene.LandChannel.AllParcels().Count, 0, "incorrect number of parcels"); | ||
1039 | } | ||
979 | } | 1040 | } |
980 | } | 1041 | } \ No newline at end of file |
diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateManagementCommands.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementCommands.cs index 3b84d57..4d49794 100644 --- a/OpenSim/Region/CoreModules/World/Estate/EstateManagementCommands.cs +++ b/OpenSim/Region/CoreModules/World/Estate/EstateManagementCommands.cs | |||
@@ -117,7 +117,7 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
117 | 117 | ||
118 | m_module.Scene.RegionInfo.RegionSettings.Save(); | 118 | m_module.Scene.RegionInfo.RegionSettings.Save(); |
119 | m_module.TriggerRegionInfoChange(); | 119 | m_module.TriggerRegionInfoChange(); |
120 | m_module.sendRegionInfoPacketToAll(); | 120 | m_module.sendRegionHandshakeToAll(); |
121 | } | 121 | } |
122 | } | 122 | } |
123 | } | 123 | } |
diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs index dc062b6..a5f5749 100644 --- a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs | |||
@@ -55,6 +55,11 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
55 | 55 | ||
56 | protected EstateManagementCommands m_commands; | 56 | protected EstateManagementCommands m_commands; |
57 | 57 | ||
58 | /// <summary> | ||
59 | /// If false, region restart requests from the client are blocked even if they are otherwise legitimate. | ||
60 | /// </summary> | ||
61 | public bool AllowRegionRestartFromClient { get; set; } | ||
62 | |||
58 | private EstateTerrainXferHandler TerrainUploader; | 63 | private EstateTerrainXferHandler TerrainUploader; |
59 | public TelehubManager m_Telehub; | 64 | public TelehubManager m_Telehub; |
60 | 65 | ||
@@ -64,6 +69,53 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
64 | 69 | ||
65 | private int m_delayCount = 0; | 70 | private int m_delayCount = 0; |
66 | 71 | ||
72 | #region Region Module interface | ||
73 | |||
74 | public string Name { get { return "EstateManagementModule"; } } | ||
75 | |||
76 | public Type ReplaceableInterface { get { return null; } } | ||
77 | |||
78 | public void Initialise(IConfigSource source) | ||
79 | { | ||
80 | AllowRegionRestartFromClient = true; | ||
81 | |||
82 | IConfig config = source.Configs["EstateManagement"]; | ||
83 | |||
84 | if (config != null) | ||
85 | AllowRegionRestartFromClient = config.GetBoolean("AllowRegionRestartFromClient", true); | ||
86 | } | ||
87 | |||
88 | public void AddRegion(Scene scene) | ||
89 | { | ||
90 | Scene = scene; | ||
91 | Scene.RegisterModuleInterface<IEstateModule>(this); | ||
92 | Scene.EventManager.OnNewClient += EventManager_OnNewClient; | ||
93 | Scene.EventManager.OnRequestChangeWaterHeight += changeWaterHeight; | ||
94 | |||
95 | m_Telehub = new TelehubManager(scene); | ||
96 | |||
97 | m_commands = new EstateManagementCommands(this); | ||
98 | m_commands.Initialise(); | ||
99 | } | ||
100 | |||
101 | public void RemoveRegion(Scene scene) {} | ||
102 | |||
103 | public void RegionLoaded(Scene scene) | ||
104 | { | ||
105 | // Sets up the sun module based no the saved Estate and Region Settings | ||
106 | // DO NOT REMOVE or the sun will stop working | ||
107 | scene.TriggerEstateSunUpdate(); | ||
108 | |||
109 | UserManager = scene.RequestModuleInterface<IUserManagement>(); | ||
110 | } | ||
111 | |||
112 | public void Close() | ||
113 | { | ||
114 | m_commands.Close(); | ||
115 | } | ||
116 | |||
117 | #endregion | ||
118 | |||
67 | #region Packet Data Responders | 119 | #region Packet Data Responders |
68 | 120 | ||
69 | private void clientSendDetailedEstateData(IClientAPI remote_client, UUID invoice) | 121 | private void clientSendDetailedEstateData(IClientAPI remote_client, UUID invoice) |
@@ -76,7 +128,7 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
76 | { | 128 | { |
77 | uint sun = 0; | 129 | uint sun = 0; |
78 | 130 | ||
79 | if (!Scene.RegionInfo.EstateSettings.UseGlobalTime) | 131 | if (Scene.RegionInfo.EstateSettings.FixedSun) |
80 | sun = (uint)(Scene.RegionInfo.EstateSettings.SunPosition * 1024.0) + 0x1800; | 132 | sun = (uint)(Scene.RegionInfo.EstateSettings.SunPosition * 1024.0) + 0x1800; |
81 | UUID estateOwner; | 133 | UUID estateOwner; |
82 | estateOwner = Scene.RegionInfo.EstateSettings.EstateOwner; | 134 | estateOwner = Scene.RegionInfo.EstateSettings.EstateOwner; |
@@ -197,6 +249,7 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
197 | Scene.RegionInfo.RegionSettings.TerrainTexture4 = texture; | 249 | Scene.RegionInfo.RegionSettings.TerrainTexture4 = texture; |
198 | break; | 250 | break; |
199 | } | 251 | } |
252 | |||
200 | Scene.RegionInfo.RegionSettings.Save(); | 253 | Scene.RegionInfo.RegionSettings.Save(); |
201 | TriggerRegionInfoChange(); | 254 | TriggerRegionInfoChange(); |
202 | sendRegionInfoPacketToAll(); | 255 | sendRegionInfoPacketToAll(); |
@@ -228,6 +281,7 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
228 | Scene.RegionInfo.RegionSettings.Elevation2NE = highValue; | 281 | Scene.RegionInfo.RegionSettings.Elevation2NE = highValue; |
229 | break; | 282 | break; |
230 | } | 283 | } |
284 | |||
231 | Scene.RegionInfo.RegionSettings.Save(); | 285 | Scene.RegionInfo.RegionSettings.Save(); |
232 | TriggerRegionInfoChange(); | 286 | TriggerRegionInfoChange(); |
233 | sendRegionHandshakeToAll(); | 287 | sendRegionHandshakeToAll(); |
@@ -268,6 +322,12 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
268 | 322 | ||
269 | private void handleEstateRestartSimRequest(IClientAPI remoteClient, int timeInSeconds) | 323 | private void handleEstateRestartSimRequest(IClientAPI remoteClient, int timeInSeconds) |
270 | { | 324 | { |
325 | if (!AllowRegionRestartFromClient) | ||
326 | { | ||
327 | remoteClient.SendAlertMessage("Region restart has been disabled on this simulator."); | ||
328 | return; | ||
329 | } | ||
330 | |||
271 | IRestartModule restartModule = Scene.RequestModuleInterface<IRestartModule>(); | 331 | IRestartModule restartModule = Scene.RequestModuleInterface<IRestartModule>(); |
272 | if (restartModule != null) | 332 | if (restartModule != null) |
273 | { | 333 | { |
@@ -352,6 +412,7 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
352 | } | 412 | } |
353 | 413 | ||
354 | } | 414 | } |
415 | |||
355 | if ((estateAccessType & 8) != 0) // User remove | 416 | if ((estateAccessType & 8) != 0) // User remove |
356 | { | 417 | { |
357 | if (Scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, true)) | 418 | if (Scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, true)) |
@@ -383,6 +444,7 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
383 | remote_client.SendAlertMessage("Method EstateAccessDelta Failed, you don't have permissions"); | 444 | remote_client.SendAlertMessage("Method EstateAccessDelta Failed, you don't have permissions"); |
384 | } | 445 | } |
385 | } | 446 | } |
447 | |||
386 | if ((estateAccessType & 16) != 0) // Group add | 448 | if ((estateAccessType & 16) != 0) // Group add |
387 | { | 449 | { |
388 | if (Scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, true)) | 450 | if (Scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, true)) |
@@ -650,7 +712,7 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
650 | } | 712 | } |
651 | } | 713 | } |
652 | 714 | ||
653 | public void handleOnEstateManageTelehub (IClientAPI client, UUID invoice, UUID senderID, string cmd, uint param1) | 715 | public void handleOnEstateManageTelehub(IClientAPI client, UUID invoice, UUID senderID, string cmd, uint param1) |
654 | { | 716 | { |
655 | SceneObjectPart part; | 717 | SceneObjectPart part; |
656 | 718 | ||
@@ -718,13 +780,18 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
718 | Scene.RegionInfo.RegionSettings.Save(); | 780 | Scene.RegionInfo.RegionSettings.Save(); |
719 | TriggerRegionInfoChange(); | 781 | TriggerRegionInfoChange(); |
720 | 782 | ||
721 | Scene.SetSceneCoreDebug( | 783 | ISceneCommandsModule scm = Scene.RequestModuleInterface<ISceneCommandsModule>(); |
722 | new Dictionary<string, string>() { | 784 | |
723 | { "scripting", (!disableScripts).ToString() }, | 785 | if (scm != null) |
724 | { "collisions", (!disableCollisions).ToString() }, | 786 | { |
725 | { "physics", (!disablePhysics).ToString() } | 787 | scm.SetSceneDebugOptions( |
726 | } | 788 | new Dictionary<string, string>() { |
727 | ); | 789 | { "scripting", (!disableScripts).ToString() }, |
790 | { "collisions", (!disableCollisions).ToString() }, | ||
791 | { "physics", (!disablePhysics).ToString() } | ||
792 | } | ||
793 | ); | ||
794 | } | ||
728 | } | 795 | } |
729 | 796 | ||
730 | private void handleEstateTeleportOneUserHomeRequest(IClientAPI remover_client, UUID invoice, UUID senderID, UUID prey) | 797 | private void handleEstateTeleportOneUserHomeRequest(IClientAPI remover_client, UUID invoice, UUID senderID, UUID prey) |
@@ -1066,6 +1133,7 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
1066 | { | 1133 | { |
1067 | Scene.RegionInfo.EstateSettings.UseGlobalTime = false; | 1134 | Scene.RegionInfo.EstateSettings.UseGlobalTime = false; |
1068 | Scene.RegionInfo.EstateSettings.SunPosition = (parms2 - 0x1800)/1024.0; | 1135 | Scene.RegionInfo.EstateSettings.SunPosition = (parms2 - 0x1800)/1024.0; |
1136 | // Warning: FixedSun should be set to True, otherwise this sun position won't be used. | ||
1069 | } | 1137 | } |
1070 | 1138 | ||
1071 | if ((parms1 & 0x00000010) != 0) | 1139 | if ((parms1 & 0x00000010) != 0) |
@@ -1118,49 +1186,6 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
1118 | 1186 | ||
1119 | #endregion | 1187 | #endregion |
1120 | 1188 | ||
1121 | #region Region Module interface | ||
1122 | |||
1123 | public string Name { get { return "EstateManagementModule"; } } | ||
1124 | |||
1125 | public Type ReplaceableInterface { get { return null; } } | ||
1126 | |||
1127 | public void Initialise(IConfigSource source) {} | ||
1128 | |||
1129 | public void AddRegion(Scene scene) | ||
1130 | { | ||
1131 | m_regionChangeTimer.AutoReset = false; | ||
1132 | m_regionChangeTimer.Interval = 2000; | ||
1133 | m_regionChangeTimer.Elapsed += RaiseRegionInfoChange; | ||
1134 | |||
1135 | Scene = scene; | ||
1136 | Scene.RegisterModuleInterface<IEstateModule>(this); | ||
1137 | Scene.EventManager.OnNewClient += EventManager_OnNewClient; | ||
1138 | Scene.EventManager.OnRequestChangeWaterHeight += changeWaterHeight; | ||
1139 | |||
1140 | m_Telehub = new TelehubManager(scene); | ||
1141 | |||
1142 | m_commands = new EstateManagementCommands(this); | ||
1143 | m_commands.Initialise(); | ||
1144 | } | ||
1145 | |||
1146 | public void RemoveRegion(Scene scene) {} | ||
1147 | |||
1148 | public void RegionLoaded(Scene scene) | ||
1149 | { | ||
1150 | // Sets up the sun module based no the saved Estate and Region Settings | ||
1151 | // DO NOT REMOVE or the sun will stop working | ||
1152 | scene.TriggerEstateSunUpdate(); | ||
1153 | |||
1154 | UserManager = scene.RequestModuleInterface<IUserManagement>(); | ||
1155 | } | ||
1156 | |||
1157 | public void Close() | ||
1158 | { | ||
1159 | m_commands.Close(); | ||
1160 | } | ||
1161 | |||
1162 | #endregion | ||
1163 | |||
1164 | #region Other Functions | 1189 | #region Other Functions |
1165 | 1190 | ||
1166 | public void changeWaterHeight(float height) | 1191 | public void changeWaterHeight(float height) |
diff --git a/OpenSim/Region/CoreModules/World/Land/LandChannel.cs b/OpenSim/Region/CoreModules/World/Land/LandChannel.cs index 7fc358d..73c592d 100644 --- a/OpenSim/Region/CoreModules/World/Land/LandChannel.cs +++ b/OpenSim/Region/CoreModules/World/Land/LandChannel.cs | |||
@@ -95,6 +95,11 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
95 | return null; | 95 | return null; |
96 | } | 96 | } |
97 | 97 | ||
98 | public ILandObject GetLandObject(Vector3 position) | ||
99 | { | ||
100 | return GetLandObject(position.X, position.Y); | ||
101 | } | ||
102 | |||
98 | public ILandObject GetLandObject(int x, int y) | 103 | public ILandObject GetLandObject(int x, int y) |
99 | { | 104 | { |
100 | if (m_landManagementModule != null) | 105 | if (m_landManagementModule != null) |
diff --git a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs index 1193057..b4f7d51 100644 --- a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs | |||
@@ -141,6 +141,7 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
141 | m_scene.EventManager.OnValidateLandBuy += EventManagerOnValidateLandBuy; | 141 | m_scene.EventManager.OnValidateLandBuy += EventManagerOnValidateLandBuy; |
142 | m_scene.EventManager.OnLandBuy += EventManagerOnLandBuy; | 142 | m_scene.EventManager.OnLandBuy += EventManagerOnLandBuy; |
143 | m_scene.EventManager.OnNewClient += EventManagerOnNewClient; | 143 | m_scene.EventManager.OnNewClient += EventManagerOnNewClient; |
144 | m_scene.EventManager.OnMakeChildAgent += EventMakeChildAgent; | ||
144 | m_scene.EventManager.OnSignificantClientMovement += EventManagerOnSignificantClientMovement; | 145 | m_scene.EventManager.OnSignificantClientMovement += EventManagerOnSignificantClientMovement; |
145 | m_scene.EventManager.OnNoticeNoLandDataFromStorage += EventManagerOnNoLandDataFromStorage; | 146 | m_scene.EventManager.OnNoticeNoLandDataFromStorage += EventManagerOnNoLandDataFromStorage; |
146 | m_scene.EventManager.OnIncomingLandDataFromStorage += EventManagerOnIncomingLandDataFromStorage; | 147 | m_scene.EventManager.OnIncomingLandDataFromStorage += EventManagerOnIncomingLandDataFromStorage; |
@@ -221,6 +222,11 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
221 | } | 222 | } |
222 | } | 223 | } |
223 | 224 | ||
225 | public void EventMakeChildAgent(ScenePresence avatar) | ||
226 | { | ||
227 | avatar.currentParcelUUID = UUID.Zero; | ||
228 | } | ||
229 | |||
224 | void ClientOnPreAgentUpdate(IClientAPI remoteClient, AgentUpdateArgs agentData) | 230 | void ClientOnPreAgentUpdate(IClientAPI remoteClient, AgentUpdateArgs agentData) |
225 | { | 231 | { |
226 | } | 232 | } |
@@ -249,17 +255,15 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
249 | newData.LocalID = local_id; | 255 | newData.LocalID = local_id; |
250 | ILandObject landobj = null; | 256 | ILandObject landobj = null; |
251 | 257 | ||
258 | ILandObject land; | ||
252 | lock (m_landList) | 259 | lock (m_landList) |
253 | { | 260 | { |
254 | if (m_landList.ContainsKey(local_id)) | 261 | if (m_landList.TryGetValue(local_id, out land)) |
255 | { | 262 | land.LandData = newData; |
256 | m_landList[local_id].LandData = newData; | ||
257 | landobj = m_landList[local_id]; | ||
258 | // m_scene.EventManager.TriggerLandObjectUpdated((uint)local_id, m_landList[local_id]); | ||
259 | } | ||
260 | } | 263 | } |
261 | if(landobj != null) | 264 | |
262 | m_scene.EventManager.TriggerLandObjectUpdated((uint)local_id, landobj); | 265 | if (land != null) |
266 | m_scene.EventManager.TriggerLandObjectUpdated((uint)local_id, land); | ||
263 | } | 267 | } |
264 | 268 | ||
265 | public bool AllowedForcefulBans | 269 | public bool AllowedForcefulBans |
@@ -584,7 +588,7 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
584 | // Only now can we add the prim counts to the land object - we rely on the global ID which is generated | 588 | // Only now can we add the prim counts to the land object - we rely on the global ID which is generated |
585 | // as a random UUID inside LandData initialization | 589 | // as a random UUID inside LandData initialization |
586 | if (m_primCountModule != null) | 590 | if (m_primCountModule != null) |
587 | new_land.PrimCounts = m_primCountModule.GetPrimCounts(new_land.LandData.GlobalID); | 591 | new_land.PrimCounts = m_primCountModule.GetPrimCounts(new_land.LandData.GlobalID); |
588 | 592 | ||
589 | lock (m_landList) | 593 | lock (m_landList) |
590 | { | 594 | { |
@@ -621,6 +625,7 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
621 | /// <param name="local_id">Land.localID of the peice of land to remove.</param> | 625 | /// <param name="local_id">Land.localID of the peice of land to remove.</param> |
622 | public void removeLandObject(int local_id) | 626 | public void removeLandObject(int local_id) |
623 | { | 627 | { |
628 | ILandObject land; | ||
624 | lock (m_landList) | 629 | lock (m_landList) |
625 | { | 630 | { |
626 | for (int x = 0; x < 64; x++) | 631 | for (int x = 0; x < 64; x++) |
@@ -637,9 +642,11 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
637 | } | 642 | } |
638 | } | 643 | } |
639 | 644 | ||
640 | m_scene.EventManager.TriggerLandObjectRemoved(m_landList[local_id].LandData.GlobalID); | 645 | land = m_landList[local_id]; |
641 | m_landList.Remove(local_id); | 646 | m_landList.Remove(local_id); |
642 | } | 647 | } |
648 | |||
649 | m_scene.EventManager.TriggerLandObjectRemoved(land.LandData.GlobalID); | ||
643 | } | 650 | } |
644 | 651 | ||
645 | /// <summary> | 652 | /// <summary> |
@@ -1384,9 +1391,7 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
1384 | } | 1391 | } |
1385 | 1392 | ||
1386 | for (int i = 0; i < data.Count; i++) | 1393 | for (int i = 0; i < data.Count; i++) |
1387 | { | ||
1388 | IncomingLandObjectFromStorage(data[i]); | 1394 | IncomingLandObjectFromStorage(data[i]); |
1389 | } | ||
1390 | } | 1395 | } |
1391 | 1396 | ||
1392 | public void IncomingLandObjectFromStorage(LandData data) | 1397 | public void IncomingLandObjectFromStorage(LandData data) |
@@ -1401,25 +1406,72 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
1401 | 1406 | ||
1402 | public void ReturnObjectsInParcel(int localID, uint returnType, UUID[] agentIDs, UUID[] taskIDs, IClientAPI remoteClient) | 1407 | public void ReturnObjectsInParcel(int localID, uint returnType, UUID[] agentIDs, UUID[] taskIDs, IClientAPI remoteClient) |
1403 | { | 1408 | { |
1404 | ILandObject selectedParcel = null; | 1409 | if (localID != -1) |
1405 | lock (m_landList) | ||
1406 | { | 1410 | { |
1407 | m_landList.TryGetValue(localID, out selectedParcel); | 1411 | ILandObject selectedParcel = null; |
1412 | lock (m_landList) | ||
1413 | { | ||
1414 | m_landList.TryGetValue(localID, out selectedParcel); | ||
1415 | } | ||
1416 | |||
1417 | if (selectedParcel == null) | ||
1418 | return; | ||
1419 | |||
1420 | selectedParcel.ReturnLandObjects(returnType, agentIDs, taskIDs, remoteClient); | ||
1408 | } | 1421 | } |
1422 | else | ||
1423 | { | ||
1424 | if (returnType != 1) | ||
1425 | { | ||
1426 | m_log.WarnFormat("[LAND MANAGEMENT MODULE]: ReturnObjectsInParcel: unknown return type {0}", returnType); | ||
1427 | return; | ||
1428 | } | ||
1429 | |||
1430 | // We get here when the user returns objects from the list of Top Colliders or Top Scripts. | ||
1431 | // In that case we receive specific object UUID's, but no parcel ID. | ||
1432 | |||
1433 | Dictionary<UUID, HashSet<SceneObjectGroup>> returns = new Dictionary<UUID, HashSet<SceneObjectGroup>>(); | ||
1434 | |||
1435 | foreach (UUID groupID in taskIDs) | ||
1436 | { | ||
1437 | SceneObjectGroup obj = m_scene.GetSceneObjectGroup(groupID); | ||
1438 | if (obj != null) | ||
1439 | { | ||
1440 | if (!returns.ContainsKey(obj.OwnerID)) | ||
1441 | returns[obj.OwnerID] = new HashSet<SceneObjectGroup>(); | ||
1442 | returns[obj.OwnerID].Add(obj); | ||
1443 | } | ||
1444 | else | ||
1445 | { | ||
1446 | m_log.WarnFormat("[LAND MANAGEMENT MODULE]: ReturnObjectsInParcel: unknown object {0}", groupID); | ||
1447 | } | ||
1448 | } | ||
1409 | 1449 | ||
1410 | if (selectedParcel == null) return; | 1450 | int num = 0; |
1451 | foreach (HashSet<SceneObjectGroup> objs in returns.Values) | ||
1452 | num += objs.Count; | ||
1453 | m_log.DebugFormat("[LAND MANAGEMENT MODULE]: Returning {0} specific object(s)", num); | ||
1411 | 1454 | ||
1412 | selectedParcel.ReturnLandObjects(returnType, agentIDs, taskIDs, remoteClient); | 1455 | foreach (HashSet<SceneObjectGroup> objs in returns.Values) |
1456 | { | ||
1457 | List<SceneObjectGroup> objs2 = new List<SceneObjectGroup>(objs); | ||
1458 | if (m_scene.Permissions.CanReturnObjects(null, remoteClient.AgentId, objs2)) | ||
1459 | { | ||
1460 | m_scene.returnObjects(objs2.ToArray(), remoteClient.AgentId); | ||
1461 | } | ||
1462 | else | ||
1463 | { | ||
1464 | m_log.WarnFormat("[LAND MANAGEMENT MODULE]: ReturnObjectsInParcel: not permitted to return {0} object(s) belonging to user {1}", | ||
1465 | objs2.Count, objs2[0].OwnerID); | ||
1466 | } | ||
1467 | } | ||
1468 | } | ||
1413 | } | 1469 | } |
1414 | 1470 | ||
1415 | public void EventManagerOnNoLandDataFromStorage() | 1471 | public void EventManagerOnNoLandDataFromStorage() |
1416 | { | 1472 | { |
1417 | // called methods already have locks | 1473 | ResetSimLandObjects(); |
1418 | // lock (m_landList) | 1474 | CreateDefaultParcel(); |
1419 | { | ||
1420 | ResetSimLandObjects(); | ||
1421 | CreateDefaultParcel(); | ||
1422 | } | ||
1423 | } | 1475 | } |
1424 | 1476 | ||
1425 | #endregion | 1477 | #endregion |
diff --git a/OpenSim/Region/CoreModules/World/Land/LandObject.cs b/OpenSim/Region/CoreModules/World/Land/LandObject.cs index fdac418..07d00c0 100644 --- a/OpenSim/Region/CoreModules/World/Land/LandObject.cs +++ b/OpenSim/Region/CoreModules/World/Land/LandObject.cs | |||
@@ -761,9 +761,10 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
761 | int ty = min_y * 4; | 761 | int ty = min_y * 4; |
762 | if (ty > ((int)Constants.RegionSize - 1)) | 762 | if (ty > ((int)Constants.RegionSize - 1)) |
763 | ty = ((int)Constants.RegionSize - 1); | 763 | ty = ((int)Constants.RegionSize - 1); |
764 | |||
764 | LandData.AABBMin = | 765 | LandData.AABBMin = |
765 | new Vector3((float) (min_x * 4), (float) (min_y * 4), | 766 | new Vector3( |
766 | (float) m_scene.Heightmap[tx, ty]); | 767 | (float)(min_x * 4), (float)(min_y * 4), m_scene != null ? (float)m_scene.Heightmap[tx, ty] : 0); |
767 | 768 | ||
768 | tx = max_x * 4; | 769 | tx = max_x * 4; |
769 | if (tx > ((int)Constants.RegionSize - 1)) | 770 | if (tx > ((int)Constants.RegionSize - 1)) |
@@ -771,9 +772,11 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
771 | ty = max_y * 4; | 772 | ty = max_y * 4; |
772 | if (ty > ((int)Constants.RegionSize - 1)) | 773 | if (ty > ((int)Constants.RegionSize - 1)) |
773 | ty = ((int)Constants.RegionSize - 1); | 774 | ty = ((int)Constants.RegionSize - 1); |
774 | LandData.AABBMax = | 775 | |
775 | new Vector3((float) (max_x * 4), (float) (max_y * 4), | 776 | LandData.AABBMax |
776 | (float) m_scene.Heightmap[tx, ty]); | 777 | = new Vector3( |
778 | (float)(max_x * 4), (float)(max_y * 4), m_scene != null ? (float)m_scene.Heightmap[tx, ty] : 0); | ||
779 | |||
777 | LandData.Area = tempArea; | 780 | LandData.Area = tempArea; |
778 | } | 781 | } |
779 | 782 | ||
diff --git a/OpenSim/Region/CoreModules/World/Land/PrimCountModule.cs b/OpenSim/Region/CoreModules/World/Land/PrimCountModule.cs index 55b8227..771fdd2 100644 --- a/OpenSim/Region/CoreModules/World/Land/PrimCountModule.cs +++ b/OpenSim/Region/CoreModules/World/Land/PrimCountModule.cs | |||
@@ -490,11 +490,14 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
490 | 490 | ||
491 | m_Scene.ForEachSOG(AddObject); | 491 | m_Scene.ForEachSOG(AddObject); |
492 | 492 | ||
493 | List<UUID> primcountKeys = new List<UUID>(m_PrimCounts.Keys); | 493 | lock (m_PrimCounts) |
494 | foreach (UUID k in primcountKeys) | ||
495 | { | 494 | { |
496 | if (!m_OwnerMap.ContainsKey(k)) | 495 | List<UUID> primcountKeys = new List<UUID>(m_PrimCounts.Keys); |
497 | m_PrimCounts.Remove(k); | 496 | foreach (UUID k in primcountKeys) |
497 | { | ||
498 | if (!m_OwnerMap.ContainsKey(k)) | ||
499 | m_PrimCounts.Remove(k); | ||
500 | } | ||
498 | } | 501 | } |
499 | 502 | ||
500 | m_Tainted = false; | 503 | m_Tainted = false; |
diff --git a/OpenSim/Region/CoreModules/World/Land/Tests/PrimCountModuleTests.cs b/OpenSim/Region/CoreModules/World/Land/Tests/PrimCountModuleTests.cs index b5ee4d2..0945b43 100644 --- a/OpenSim/Region/CoreModules/World/Land/Tests/PrimCountModuleTests.cs +++ b/OpenSim/Region/CoreModules/World/Land/Tests/PrimCountModuleTests.cs | |||
@@ -41,7 +41,7 @@ using OpenSim.Tests.Common.Mock; | |||
41 | namespace OpenSim.Region.CoreModules.World.Land.Tests | 41 | namespace OpenSim.Region.CoreModules.World.Land.Tests |
42 | { | 42 | { |
43 | [TestFixture] | 43 | [TestFixture] |
44 | public class PrimCountModuleTests | 44 | public class PrimCountModuleTests : OpenSimTestCase |
45 | { | 45 | { |
46 | protected UUID m_userId = new UUID("00000000-0000-0000-0000-100000000000"); | 46 | protected UUID m_userId = new UUID("00000000-0000-0000-0000-100000000000"); |
47 | protected UUID m_groupId = new UUID("00000000-0000-0000-8888-000000000000"); | 47 | protected UUID m_groupId = new UUID("00000000-0000-0000-8888-000000000000"); |
@@ -60,8 +60,10 @@ namespace OpenSim.Region.CoreModules.World.Land.Tests | |||
60 | protected ILandObject m_lo2; | 60 | protected ILandObject m_lo2; |
61 | 61 | ||
62 | [SetUp] | 62 | [SetUp] |
63 | public void SetUp() | 63 | public override void SetUp() |
64 | { | 64 | { |
65 | base.SetUp(); | ||
66 | |||
65 | m_pcm = new PrimCountModule(); | 67 | m_pcm = new PrimCountModule(); |
66 | LandManagementModule lmm = new LandManagementModule(); | 68 | LandManagementModule lmm = new LandManagementModule(); |
67 | m_scene = new SceneHelpers().SetupScene(); | 69 | m_scene = new SceneHelpers().SetupScene(); |
diff --git a/OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs b/OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs index 8a422b0..40638f8 100644 --- a/OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs +++ b/OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs | |||
@@ -77,42 +77,48 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap | |||
77 | { | 77 | { |
78 | bool drawPrimVolume = true; | 78 | bool drawPrimVolume = true; |
79 | bool textureTerrain = false; | 79 | bool textureTerrain = false; |
80 | bool generateMaptiles = true; | ||
81 | Bitmap mapbmp; | ||
80 | 82 | ||
81 | try | 83 | string[] configSections = new string[] { "Map", "Startup" }; |
82 | { | ||
83 | IConfig startupConfig = m_config.Configs["Startup"]; | ||
84 | drawPrimVolume = startupConfig.GetBoolean("DrawPrimOnMapTile", drawPrimVolume); | ||
85 | textureTerrain = startupConfig.GetBoolean("TextureOnMapTile", textureTerrain); | ||
86 | } | ||
87 | catch | ||
88 | { | ||
89 | m_log.Warn("[MAPTILE]: Failed to load StartupConfig"); | ||
90 | } | ||
91 | 84 | ||
92 | if (textureTerrain) | 85 | drawPrimVolume |
93 | { | 86 | = Util.GetConfigVarFromSections<bool>(m_config, "DrawPrimOnMapTile", configSections, drawPrimVolume); |
94 | terrainRenderer = new TexturedMapTileRenderer(); | 87 | textureTerrain |
95 | } | 88 | = Util.GetConfigVarFromSections<bool>(m_config, "TextureOnMapTile", configSections, textureTerrain); |
96 | else | 89 | generateMaptiles |
90 | = Util.GetConfigVarFromSections<bool>(m_config, "GenerateMaptiles", configSections, generateMaptiles); | ||
91 | |||
92 | if (generateMaptiles) | ||
97 | { | 93 | { |
98 | terrainRenderer = new ShadedMapTileRenderer(); | 94 | if (textureTerrain) |
99 | } | 95 | { |
100 | terrainRenderer.Initialise(m_scene, m_config); | 96 | terrainRenderer = new TexturedMapTileRenderer(); |
97 | } | ||
98 | else | ||
99 | { | ||
100 | terrainRenderer = new ShadedMapTileRenderer(); | ||
101 | } | ||
101 | 102 | ||
102 | Bitmap mapbmp = new Bitmap((int)Constants.RegionSize, (int)Constants.RegionSize, System.Drawing.Imaging.PixelFormat.Format24bppRgb); | 103 | terrainRenderer.Initialise(m_scene, m_config); |
103 | //long t = System.Environment.TickCount; | ||
104 | //for (int i = 0; i < 10; ++i) { | ||
105 | terrainRenderer.TerrainToBitmap(mapbmp); | ||
106 | //} | ||
107 | //t = System.Environment.TickCount - t; | ||
108 | //m_log.InfoFormat("[MAPTILE] generation of 10 maptiles needed {0} ms", t); | ||
109 | 104 | ||
105 | mapbmp = new Bitmap((int)Constants.RegionSize, (int)Constants.RegionSize, System.Drawing.Imaging.PixelFormat.Format24bppRgb); | ||
106 | //long t = System.Environment.TickCount; | ||
107 | //for (int i = 0; i < 10; ++i) { | ||
108 | terrainRenderer.TerrainToBitmap(mapbmp); | ||
109 | //} | ||
110 | //t = System.Environment.TickCount - t; | ||
111 | //m_log.InfoFormat("[MAPTILE] generation of 10 maptiles needed {0} ms", t); | ||
110 | 112 | ||
111 | if (drawPrimVolume) | 113 | if (drawPrimVolume) |
114 | { | ||
115 | DrawObjectVolume(m_scene, mapbmp); | ||
116 | } | ||
117 | } | ||
118 | else | ||
112 | { | 119 | { |
113 | DrawObjectVolume(m_scene, mapbmp); | 120 | mapbmp = FetchTexture(m_scene.RegionInfo.RegionSettings.TerrainImageID); |
114 | } | 121 | } |
115 | |||
116 | return mapbmp; | 122 | return mapbmp; |
117 | } | 123 | } |
118 | 124 | ||
@@ -139,9 +145,8 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap | |||
139 | { | 145 | { |
140 | m_config = source; | 146 | m_config = source; |
141 | 147 | ||
142 | IConfig startupConfig = m_config.Configs["Startup"]; | 148 | if (Util.GetConfigVarFromSections<string>( |
143 | if (startupConfig.GetString("MapImageModule", "MapImageModule") != | 149 | m_config, "MapImageModule", new string[] { "Startup", "Map" }, "MapImageModule") != "MapImageModule") |
144 | "MapImageModule") | ||
145 | return; | 150 | return; |
146 | 151 | ||
147 | m_Enabled = true; | 152 | m_Enabled = true; |
@@ -222,6 +227,49 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap | |||
222 | // } | 227 | // } |
223 | // } | 228 | // } |
224 | 229 | ||
230 | private Bitmap FetchTexture(UUID id) | ||
231 | { | ||
232 | AssetBase asset = m_scene.AssetService.Get(id.ToString()); | ||
233 | |||
234 | if (asset != null) | ||
235 | { | ||
236 | m_log.DebugFormat("[MAPTILE]: Static map image texture {0} found for {1}", id, m_scene.Name); | ||
237 | } | ||
238 | else | ||
239 | { | ||
240 | m_log.WarnFormat("[MAPTILE]: Static map image texture {0} not found for {1}", id, m_scene.Name); | ||
241 | return null; | ||
242 | } | ||
243 | |||
244 | ManagedImage managedImage; | ||
245 | Image image; | ||
246 | |||
247 | try | ||
248 | { | ||
249 | if (OpenJPEG.DecodeToImage(asset.Data, out managedImage, out image)) | ||
250 | return new Bitmap(image); | ||
251 | else | ||
252 | return null; | ||
253 | } | ||
254 | catch (DllNotFoundException) | ||
255 | { | ||
256 | m_log.ErrorFormat("[MAPTILE]: OpenJpeg is not installed correctly on this system. Asset Data is empty for {0}", id); | ||
257 | |||
258 | } | ||
259 | catch (IndexOutOfRangeException) | ||
260 | { | ||
261 | m_log.ErrorFormat("[MAPTILE]: OpenJpeg was unable to decode this. Asset Data is empty for {0}", id); | ||
262 | |||
263 | } | ||
264 | catch (Exception) | ||
265 | { | ||
266 | m_log.ErrorFormat("[MAPTILE]: OpenJpeg was unable to decode this. Asset Data is empty for {0}", id); | ||
267 | |||
268 | } | ||
269 | return null; | ||
270 | |||
271 | } | ||
272 | |||
225 | private Bitmap DrawObjectVolume(Scene whichScene, Bitmap mapbmp) | 273 | private Bitmap DrawObjectVolume(Scene whichScene, Bitmap mapbmp) |
226 | { | 274 | { |
227 | int tc = 0; | 275 | int tc = 0; |
diff --git a/OpenSim/Region/CoreModules/World/LightShare/LightShareModule.cs b/OpenSim/Region/CoreModules/World/LightShare/LightShareModule.cs index 6f92ef6..f13d648 100644 --- a/OpenSim/Region/CoreModules/World/LightShare/LightShareModule.cs +++ b/OpenSim/Region/CoreModules/World/LightShare/LightShareModule.cs | |||
@@ -198,12 +198,12 @@ namespace OpenSim.Region.CoreModules.World.LightShare | |||
198 | if (m_scene.RegionInfo.WindlightSettings.valid) | 198 | if (m_scene.RegionInfo.WindlightSettings.valid) |
199 | { | 199 | { |
200 | List<byte[]> param = compileWindlightSettings(wl); | 200 | List<byte[]> param = compileWindlightSettings(wl); |
201 | client.SendGenericMessage("Windlight", param); | 201 | client.SendGenericMessage("Windlight", UUID.Random(), param); |
202 | } | 202 | } |
203 | else | 203 | else |
204 | { | 204 | { |
205 | List<byte[]> param = new List<byte[]>(); | 205 | List<byte[]> param = new List<byte[]>(); |
206 | client.SendGenericMessage("WindlightReset", param); | 206 | client.SendGenericMessage("WindlightReset", UUID.Random(), param); |
207 | } | 207 | } |
208 | } | 208 | } |
209 | } | 209 | } |
diff --git a/OpenSim/Region/CoreModules/World/Media/Moap/Tests/MoapTests.cs b/OpenSim/Region/CoreModules/World/Media/Moap/Tests/MoapTests.cs index 396095a..03a96a4 100644 --- a/OpenSim/Region/CoreModules/World/Media/Moap/Tests/MoapTests.cs +++ b/OpenSim/Region/CoreModules/World/Media/Moap/Tests/MoapTests.cs | |||
@@ -44,14 +44,16 @@ using OpenSim.Tests.Common.Mock; | |||
44 | namespace OpenSim.Region.CoreModules.World.Media.Moap.Tests | 44 | namespace OpenSim.Region.CoreModules.World.Media.Moap.Tests |
45 | { | 45 | { |
46 | [TestFixture] | 46 | [TestFixture] |
47 | public class MoapTests | 47 | public class MoapTests : OpenSimTestCase |
48 | { | 48 | { |
49 | protected TestScene m_scene; | 49 | protected TestScene m_scene; |
50 | protected MoapModule m_module; | 50 | protected MoapModule m_module; |
51 | 51 | ||
52 | [SetUp] | 52 | [SetUp] |
53 | public void SetUp() | 53 | public override void SetUp() |
54 | { | 54 | { |
55 | base.SetUp(); | ||
56 | |||
55 | m_module = new MoapModule(); | 57 | m_module = new MoapModule(); |
56 | m_scene = new SceneHelpers().SetupScene(); | 58 | m_scene = new SceneHelpers().SetupScene(); |
57 | SceneHelpers.SetupSceneModules(m_scene, m_module); | 59 | SceneHelpers.SetupSceneModules(m_scene, m_module); |
diff --git a/OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs b/OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs index eb4731c..28daf2f 100644 --- a/OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs +++ b/OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs | |||
@@ -38,6 +38,7 @@ using OpenSim.Region.Framework; | |||
38 | using OpenSim.Region.Framework.Interfaces; | 38 | using OpenSim.Region.Framework.Interfaces; |
39 | using OpenSim.Region.Framework.Scenes; | 39 | using OpenSim.Region.Framework.Scenes; |
40 | using OpenSim.Region.Framework.Scenes.Serialization; | 40 | using OpenSim.Region.Framework.Scenes.Serialization; |
41 | using PermissionMask = OpenSim.Framework.PermissionMask; | ||
41 | 42 | ||
42 | namespace OpenSim.Region.CoreModules.World.Objects.BuySell | 43 | namespace OpenSim.Region.CoreModules.World.Objects.BuySell |
43 | { | 44 | { |
diff --git a/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs b/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs index ab8f143..e434b2e 100644 --- a/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs +++ b/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs | |||
@@ -365,7 +365,8 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands | |||
365 | 365 | ||
366 | if (mainParams.Count < 4) | 366 | if (mainParams.Count < 4) |
367 | { | 367 | { |
368 | m_console.OutputFormat("Usage: show part id [--full] <UUID-or-localID>"); | 368 | //m_console.OutputFormat("Usage: show part id [--full] <UUID-or-localID>"); |
369 | m_console.OutputFormat("Usage: show part id <UUID-or-localID>"); | ||
369 | return; | 370 | return; |
370 | } | 371 | } |
371 | 372 | ||
@@ -405,6 +406,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands | |||
405 | 406 | ||
406 | if (mainParams.Count < 5) | 407 | if (mainParams.Count < 5) |
407 | { | 408 | { |
409 | //m_console.OutputFormat("Usage: show part pos <start-coord> to <end-coord>"); | ||
408 | m_console.OutputFormat("Usage: show part pos [--full] <start-coord> to <end-coord>"); | 410 | m_console.OutputFormat("Usage: show part pos [--full] <start-coord> to <end-coord>"); |
409 | return; | 411 | return; |
410 | } | 412 | } |
@@ -414,7 +416,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands | |||
414 | 416 | ||
415 | if (!ConsoleUtil.TryParseConsoleMinVector(rawConsoleStartVector, out startVector)) | 417 | if (!ConsoleUtil.TryParseConsoleMinVector(rawConsoleStartVector, out startVector)) |
416 | { | 418 | { |
417 | m_console.OutputFormat("Error: Start vector {0} does not have a valid format", rawConsoleStartVector); | 419 | m_console.OutputFormat("Error: Start vector '{0}' does not have a valid format", rawConsoleStartVector); |
418 | return; | 420 | return; |
419 | } | 421 | } |
420 | 422 | ||
@@ -423,7 +425,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands | |||
423 | 425 | ||
424 | if (!ConsoleUtil.TryParseConsoleMaxVector(rawConsoleEndVector, out endVector)) | 426 | if (!ConsoleUtil.TryParseConsoleMaxVector(rawConsoleEndVector, out endVector)) |
425 | { | 427 | { |
426 | m_console.OutputFormat("Error: End vector {0} does not have a valid format", rawConsoleEndVector); | 428 | m_console.OutputFormat("Error: End vector '{0}' does not have a valid format", rawConsoleEndVector); |
427 | return; | 429 | return; |
428 | } | 430 | } |
429 | 431 | ||
@@ -445,7 +447,8 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands | |||
445 | 447 | ||
446 | if (mainParams.Count < 4) | 448 | if (mainParams.Count < 4) |
447 | { | 449 | { |
448 | m_console.OutputFormat("Usage: show part name [--full] [--regex] <name>"); | 450 | m_console.OutputFormat("Usage: show part name [--regex] <name>"); |
451 | //m_console.OutputFormat("Usage: show part name [--full] [--regex] <name>"); | ||
449 | return; | 452 | return; |
450 | } | 453 | } |
451 | 454 | ||
@@ -577,6 +580,61 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands | |||
577 | cdl.AddRow("Link number", sop.LinkNum); | 580 | cdl.AddRow("Link number", sop.LinkNum); |
578 | cdl.AddRow("Flags", sop.Flags); | 581 | cdl.AddRow("Flags", sop.Flags); |
579 | 582 | ||
583 | if (showFull) | ||
584 | { | ||
585 | PrimitiveBaseShape s = sop.Shape; | ||
586 | cdl.AddRow("FlexiDrag", s.FlexiDrag); | ||
587 | cdl.AddRow("FlexiEntry", s.FlexiEntry); | ||
588 | cdl.AddRow("FlexiForce", string.Format("<{0},{1},{2}>", s.FlexiForceX, s.FlexiForceY, s.FlexiForceZ)); | ||
589 | cdl.AddRow("FlexiGravity", s.FlexiGravity); | ||
590 | cdl.AddRow("FlexiSoftness", s.FlexiSoftness); | ||
591 | cdl.AddRow("HollowShape", s.HollowShape); | ||
592 | cdl.AddRow( | ||
593 | "LightColor", | ||
594 | string.Format("<{0},{1},{2},{3}>", s.LightColorR, s.LightColorB, s.LightColorG, s.LightColorA)); | ||
595 | cdl.AddRow("LightCutoff", s.LightCutoff); | ||
596 | cdl.AddRow("LightEntry", s.LightEntry); | ||
597 | cdl.AddRow("LightFalloff", s.LightFalloff); | ||
598 | cdl.AddRow("LightIntensity", s.LightIntensity); | ||
599 | cdl.AddRow("LightRadius", s.LightRadius); | ||
600 | cdl.AddRow("Location (relative)", sop.RelativePosition); | ||
601 | cdl.AddRow("Media", string.Format("{0} entries", s.Media != null ? s.Media.Count.ToString() : "n/a")); | ||
602 | cdl.AddRow("PathBegin", s.PathBegin); | ||
603 | cdl.AddRow("PathEnd", s.PathEnd); | ||
604 | cdl.AddRow("PathCurve", s.PathCurve); | ||
605 | cdl.AddRow("PathRadiusOffset", s.PathRadiusOffset); | ||
606 | cdl.AddRow("PathRevolutions", s.PathRevolutions); | ||
607 | cdl.AddRow("PathScale", string.Format("<{0},{1}>", s.PathScaleX, s.PathScaleY)); | ||
608 | cdl.AddRow("PathSkew", string.Format("<{0},{1}>", s.PathShearX, s.PathShearY)); | ||
609 | cdl.AddRow("FlexiDrag", s.PathSkew); | ||
610 | cdl.AddRow("PathTaper", string.Format("<{0},{1}>", s.PathTaperX, s.PathTaperY)); | ||
611 | cdl.AddRow("PathTwist", s.PathTwist); | ||
612 | cdl.AddRow("PathTwistBegin", s.PathTwistBegin); | ||
613 | cdl.AddRow("PCode", s.PCode); | ||
614 | cdl.AddRow("ProfileBegin", s.ProfileBegin); | ||
615 | cdl.AddRow("ProfileEnd", s.ProfileEnd); | ||
616 | cdl.AddRow("ProfileHollow", s.ProfileHollow); | ||
617 | cdl.AddRow("ProfileShape", s.ProfileShape); | ||
618 | cdl.AddRow("ProjectionAmbiance", s.ProjectionAmbiance); | ||
619 | cdl.AddRow("ProjectionEntry", s.ProjectionEntry); | ||
620 | cdl.AddRow("ProjectionFocus", s.ProjectionFocus); | ||
621 | cdl.AddRow("ProjectionFOV", s.ProjectionFOV); | ||
622 | cdl.AddRow("ProjectionTextureUUID", s.ProjectionTextureUUID); | ||
623 | cdl.AddRow("Rotation (Relative)", sop.RotationOffset); | ||
624 | cdl.AddRow("Rotation (World)", sop.GetWorldRotation()); | ||
625 | cdl.AddRow("Scale", s.Scale); | ||
626 | cdl.AddRow( | ||
627 | "SculptData", | ||
628 | string.Format("{0} bytes", s.SculptData != null ? s.SculptData.Length.ToString() : "n/a")); | ||
629 | cdl.AddRow("SculptEntry", s.SculptEntry); | ||
630 | cdl.AddRow("SculptTexture", s.SculptTexture); | ||
631 | cdl.AddRow("SculptType", s.SculptType); | ||
632 | cdl.AddRow("State", s.State); | ||
633 | |||
634 | // TODO, unpack and display texture entries | ||
635 | //cdl.AddRow("Textures", string.Format("{0} entries", s.Textures. | ||
636 | } | ||
637 | |||
580 | object itemsOutput; | 638 | object itemsOutput; |
581 | if (showFull) | 639 | if (showFull) |
582 | { | 640 | { |
@@ -588,7 +646,6 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands | |||
588 | itemsOutput = sop.Inventory.Count; | 646 | itemsOutput = sop.Inventory.Count; |
589 | } | 647 | } |
590 | 648 | ||
591 | |||
592 | cdl.AddRow("Items", itemsOutput); | 649 | cdl.AddRow("Items", itemsOutput); |
593 | 650 | ||
594 | return sb.Append(cdl.ToString()); | 651 | return sb.Append(cdl.ToString()); |
@@ -842,17 +899,17 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands | |||
842 | 899 | ||
843 | if (!ConsoleUtil.TryParseConsoleMinVector(rawConsoleStartVector, out startVector)) | 900 | if (!ConsoleUtil.TryParseConsoleMinVector(rawConsoleStartVector, out startVector)) |
844 | { | 901 | { |
845 | m_console.OutputFormat("Error: Start vector {0} does not have a valid format", rawConsoleStartVector); | 902 | m_console.OutputFormat("Error: Start vector '{0}' does not have a valid format", rawConsoleStartVector); |
846 | endVector = Vector3.Zero; | 903 | endVector = Vector3.Zero; |
847 | 904 | ||
848 | return false; | 905 | return false; |
849 | } | 906 | } |
850 | 907 | ||
851 | string rawConsoleEndVector = rawComponents.Skip(1).Take(1).Single(); | 908 | string rawConsoleEndVector = rawComponents.Skip(2).Take(1).Single(); |
852 | 909 | ||
853 | if (!ConsoleUtil.TryParseConsoleMaxVector(rawConsoleEndVector, out endVector)) | 910 | if (!ConsoleUtil.TryParseConsoleMaxVector(rawConsoleEndVector, out endVector)) |
854 | { | 911 | { |
855 | m_console.OutputFormat("Error: End vector {0} does not have a valid format", rawConsoleEndVector); | 912 | m_console.OutputFormat("Error: End vector '{0}' does not have a valid format", rawConsoleEndVector); |
856 | return false; | 913 | return false; |
857 | } | 914 | } |
858 | 915 | ||
diff --git a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs index ddaa227..79dd4a0 100644 --- a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs +++ b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs | |||
@@ -38,6 +38,7 @@ using OpenSim.Region.Framework.Scenes; | |||
38 | using OpenSim.Services.Interfaces; | 38 | using OpenSim.Services.Interfaces; |
39 | 39 | ||
40 | using Mono.Addins; | 40 | using Mono.Addins; |
41 | using PermissionMask = OpenSim.Framework.PermissionMask; | ||
41 | 42 | ||
42 | namespace OpenSim.Region.CoreModules.World.Permissions | 43 | namespace OpenSim.Region.CoreModules.World.Permissions |
43 | { | 44 | { |
@@ -156,9 +157,8 @@ namespace OpenSim.Region.CoreModules.World.Permissions | |||
156 | 157 | ||
157 | public void Initialise(IConfigSource config) | 158 | public void Initialise(IConfigSource config) |
158 | { | 159 | { |
159 | IConfig myConfig = config.Configs["Startup"]; | 160 | string permissionModules = Util.GetConfigVarFromSections<string>(config, "permissionmodules", |
160 | 161 | new string[] { "Startup", "Permissions" }, "DefaultPermissionsModule"); | |
161 | string permissionModules = myConfig.GetString("permissionmodules", "DefaultPermissionsModule"); | ||
162 | 162 | ||
163 | List<string> modules = new List<string>(permissionModules.Split(',')); | 163 | List<string> modules = new List<string>(permissionModules.Split(',')); |
164 | 164 | ||
@@ -167,26 +167,34 @@ namespace OpenSim.Region.CoreModules.World.Permissions | |||
167 | 167 | ||
168 | m_Enabled = true; | 168 | m_Enabled = true; |
169 | 169 | ||
170 | m_allowGridGods = myConfig.GetBoolean("allow_grid_gods", false); | 170 | m_allowGridGods = Util.GetConfigVarFromSections<bool>(config, "allow_grid_gods", |
171 | m_bypassPermissions = !myConfig.GetBoolean("serverside_object_permissions", true); | 171 | new string[] { "Startup", "Permissions" }, false); |
172 | m_propagatePermissions = myConfig.GetBoolean("propagate_permissions", true); | 172 | m_bypassPermissions = !Util.GetConfigVarFromSections<bool>(config, "serverside_object_permissions", |
173 | m_RegionOwnerIsGod = myConfig.GetBoolean("region_owner_is_god", true); | 173 | new string[] { "Startup", "Permissions" }, true); |
174 | m_RegionManagerIsGod = myConfig.GetBoolean("region_manager_is_god", false); | 174 | m_propagatePermissions = Util.GetConfigVarFromSections<bool>(config, "propagate_permissions", |
175 | m_ParcelOwnerIsGod = myConfig.GetBoolean("parcel_owner_is_god", true); | 175 | new string[] { "Startup", "Permissions" }, true); |
176 | 176 | m_RegionOwnerIsGod = Util.GetConfigVarFromSections<bool>(config, "region_owner_is_god", | |
177 | m_SimpleBuildPermissions = myConfig.GetBoolean("simple_build_permissions", false); | 177 | new string[] { "Startup", "Permissions" }, true); |
178 | m_RegionManagerIsGod = Util.GetConfigVarFromSections<bool>(config, "region_manager_is_god", | ||
179 | new string[] { "Startup", "Permissions" }, false); | ||
180 | m_ParcelOwnerIsGod = Util.GetConfigVarFromSections<bool>(config, "parcel_owner_is_god", | ||
181 | new string[] { "Startup", "Permissions" }, true); | ||
182 | |||
183 | m_SimpleBuildPermissions = Util.GetConfigVarFromSections<bool>(config, "simple_build_permissions", | ||
184 | new string[] { "Startup", "Permissions" }, false); | ||
178 | 185 | ||
179 | m_allowedScriptCreators | 186 | m_allowedScriptCreators |
180 | = ParseUserSetConfigSetting(myConfig, "allowed_script_creators", m_allowedScriptCreators); | 187 | = ParseUserSetConfigSetting(config, "allowed_script_creators", m_allowedScriptCreators); |
181 | m_allowedScriptEditors | 188 | m_allowedScriptEditors |
182 | = ParseUserSetConfigSetting(myConfig, "allowed_script_editors", m_allowedScriptEditors); | 189 | = ParseUserSetConfigSetting(config, "allowed_script_editors", m_allowedScriptEditors); |
183 | 190 | ||
184 | if (m_bypassPermissions) | 191 | if (m_bypassPermissions) |
185 | m_log.Info("[PERMISSIONS]: serverside_object_permissions = false in ini file so disabling all region service permission checks"); | 192 | m_log.Info("[PERMISSIONS]: serverside_object_permissions = false in ini file so disabling all region service permission checks"); |
186 | else | 193 | else |
187 | m_log.Debug("[PERMISSIONS]: Enabling all region service permission checks"); | 194 | m_log.Debug("[PERMISSIONS]: Enabling all region service permission checks"); |
188 | 195 | ||
189 | string grant = myConfig.GetString("GrantLSL", ""); | 196 | string grant = Util.GetConfigVarFromSections<string>(config, "GrantLSL", |
197 | new string[] { "Startup", "Permissions" }, string.Empty); | ||
190 | if (grant.Length > 0) | 198 | if (grant.Length > 0) |
191 | { | 199 | { |
192 | foreach (string uuidl in grant.Split(',')) | 200 | foreach (string uuidl in grant.Split(',')) |
@@ -196,7 +204,8 @@ namespace OpenSim.Region.CoreModules.World.Permissions | |||
196 | } | 204 | } |
197 | } | 205 | } |
198 | 206 | ||
199 | grant = myConfig.GetString("GrantCS", ""); | 207 | grant = Util.GetConfigVarFromSections<string>(config, "GrantCS", |
208 | new string[] { "Startup", "Permissions" }, string.Empty); | ||
200 | if (grant.Length > 0) | 209 | if (grant.Length > 0) |
201 | { | 210 | { |
202 | foreach (string uuidl in grant.Split(',')) | 211 | foreach (string uuidl in grant.Split(',')) |
@@ -206,7 +215,8 @@ namespace OpenSim.Region.CoreModules.World.Permissions | |||
206 | } | 215 | } |
207 | } | 216 | } |
208 | 217 | ||
209 | grant = myConfig.GetString("GrantVB", ""); | 218 | grant = Util.GetConfigVarFromSections<string>(config, "GrantVB", |
219 | new string[] { "Startup", "Permissions" }, string.Empty); | ||
210 | if (grant.Length > 0) | 220 | if (grant.Length > 0) |
211 | { | 221 | { |
212 | foreach (string uuidl in grant.Split(',')) | 222 | foreach (string uuidl in grant.Split(',')) |
@@ -216,7 +226,8 @@ namespace OpenSim.Region.CoreModules.World.Permissions | |||
216 | } | 226 | } |
217 | } | 227 | } |
218 | 228 | ||
219 | grant = myConfig.GetString("GrantJS", ""); | 229 | grant = Util.GetConfigVarFromSections<string>(config, "GrantJS", |
230 | new string[] { "Startup", "Permissions" }, string.Empty); | ||
220 | if (grant.Length > 0) | 231 | if (grant.Length > 0) |
221 | { | 232 | { |
222 | foreach (string uuidl in grant.Split(',')) | 233 | foreach (string uuidl in grant.Split(',')) |
@@ -226,7 +237,8 @@ namespace OpenSim.Region.CoreModules.World.Permissions | |||
226 | } | 237 | } |
227 | } | 238 | } |
228 | 239 | ||
229 | grant = myConfig.GetString("GrantYP", ""); | 240 | grant = Util.GetConfigVarFromSections<string>(config, "GrantYP", |
241 | new string[] { "Startup", "Permissions" }, string.Empty); | ||
230 | if (grant.Length > 0) | 242 | if (grant.Length > 0) |
231 | { | 243 | { |
232 | foreach (string uuidl in grant.Split(',')) | 244 | foreach (string uuidl in grant.Split(',')) |
@@ -464,11 +476,12 @@ namespace OpenSim.Region.CoreModules.World.Permissions | |||
464 | /// <param name="settingName"></param> | 476 | /// <param name="settingName"></param> |
465 | /// <param name="defaultValue">The default value for this attribute</param> | 477 | /// <param name="defaultValue">The default value for this attribute</param> |
466 | /// <returns>The parsed value</returns> | 478 | /// <returns>The parsed value</returns> |
467 | private static UserSet ParseUserSetConfigSetting(IConfig config, string settingName, UserSet defaultValue) | 479 | private static UserSet ParseUserSetConfigSetting(IConfigSource config, string settingName, UserSet defaultValue) |
468 | { | 480 | { |
469 | UserSet userSet = defaultValue; | 481 | UserSet userSet = defaultValue; |
470 | 482 | ||
471 | string rawSetting = config.GetString(settingName, defaultValue.ToString()); | 483 | string rawSetting = Util.GetConfigVarFromSections<string>(config, settingName, |
484 | new string[] {"Startup", "Permissions"}, defaultValue.ToString()); | ||
472 | 485 | ||
473 | // Temporary measure to allow 'gods' to be specified in config for consistency's sake. In the long term | 486 | // Temporary measure to allow 'gods' to be specified in config for consistency's sake. In the long term |
474 | // this should disappear. | 487 | // this should disappear. |
diff --git a/OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs b/OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs index 7825e3e..b4348c9 100644 --- a/OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs +++ b/OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs | |||
@@ -35,11 +35,12 @@ using OpenSim.Framework; | |||
35 | using OpenSim.Region.Framework.Scenes; | 35 | using OpenSim.Region.Framework.Scenes; |
36 | using OpenSim.Region.Framework.Scenes.Serialization; | 36 | using OpenSim.Region.Framework.Scenes.Serialization; |
37 | using OpenSim.Tests.Common; | 37 | using OpenSim.Tests.Common; |
38 | using OpenMetaverse.StructuredData; | ||
38 | 39 | ||
39 | namespace OpenSim.Region.CoreModules.World.Serialiser.Tests | 40 | namespace OpenSim.Region.CoreModules.World.Serialiser.Tests |
40 | { | 41 | { |
41 | [TestFixture] | 42 | [TestFixture] |
42 | public class SerialiserTests | 43 | public class SerialiserTests : OpenSimTestCase |
43 | { | 44 | { |
44 | private string xml = @" | 45 | private string xml = @" |
45 | <SceneObjectGroup> | 46 | <SceneObjectGroup> |
@@ -143,6 +144,7 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests | |||
143 | <Flags>None</Flags> | 144 | <Flags>None</Flags> |
144 | <CollisionSound><Guid>00000000-0000-0000-0000-000000000000</Guid></CollisionSound> | 145 | <CollisionSound><Guid>00000000-0000-0000-0000-000000000000</Guid></CollisionSound> |
145 | <CollisionSoundVolume>0</CollisionSoundVolume> | 146 | <CollisionSoundVolume>0</CollisionSoundVolume> |
147 | <DynAttrs><llsd><map><key>MyStore</key><map><key>the answer</key><integer>42</integer></map></map></llsd></DynAttrs> | ||
146 | </SceneObjectPart> | 148 | </SceneObjectPart> |
147 | </RootPart> | 149 | </RootPart> |
148 | <OtherParts /> | 150 | <OtherParts /> |
@@ -331,6 +333,7 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests | |||
331 | <EveryoneMask>0</EveryoneMask> | 333 | <EveryoneMask>0</EveryoneMask> |
332 | <NextOwnerMask>2147483647</NextOwnerMask> | 334 | <NextOwnerMask>2147483647</NextOwnerMask> |
333 | <Flags>None</Flags> | 335 | <Flags>None</Flags> |
336 | <DynAttrs><llsd><map><key>MyStore</key><map><key>last words</key><string>Rosebud</string></map></map></llsd></DynAttrs> | ||
334 | <SitTargetAvatar><UUID>00000000-0000-0000-0000-000000000000</UUID></SitTargetAvatar> | 337 | <SitTargetAvatar><UUID>00000000-0000-0000-0000-000000000000</UUID></SitTargetAvatar> |
335 | </SceneObjectPart> | 338 | </SceneObjectPart> |
336 | <OtherParts /> | 339 | <OtherParts /> |
@@ -359,6 +362,8 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests | |||
359 | Assert.That(rootPart.UUID, Is.EqualTo(new UUID("e6a5a05e-e8cc-4816-8701-04165e335790"))); | 362 | Assert.That(rootPart.UUID, Is.EqualTo(new UUID("e6a5a05e-e8cc-4816-8701-04165e335790"))); |
360 | Assert.That(rootPart.CreatorID, Is.EqualTo(new UUID("a6dacf01-4636-4bb9-8a97-30609438af9d"))); | 363 | Assert.That(rootPart.CreatorID, Is.EqualTo(new UUID("a6dacf01-4636-4bb9-8a97-30609438af9d"))); |
361 | Assert.That(rootPart.Name, Is.EqualTo("PrimMyRide")); | 364 | Assert.That(rootPart.Name, Is.EqualTo("PrimMyRide")); |
365 | OSDMap store = rootPart.DynAttrs["MyStore"]; | ||
366 | Assert.AreEqual(42, store["the answer"].AsInteger()); | ||
362 | 367 | ||
363 | // TODO: Check other properties | 368 | // TODO: Check other properties |
364 | } | 369 | } |
@@ -409,6 +414,14 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests | |||
409 | rp.CreatorID = rpCreatorId; | 414 | rp.CreatorID = rpCreatorId; |
410 | rp.Shape = shape; | 415 | rp.Shape = shape; |
411 | 416 | ||
417 | string daStoreName = "MyStore"; | ||
418 | string daKey = "foo"; | ||
419 | string daValue = "bar"; | ||
420 | OSDMap myStore = new OSDMap(); | ||
421 | myStore.Add(daKey, daValue); | ||
422 | rp.DynAttrs = new DAMap(); | ||
423 | rp.DynAttrs[daStoreName] = myStore; | ||
424 | |||
412 | SceneObjectGroup so = new SceneObjectGroup(rp); | 425 | SceneObjectGroup so = new SceneObjectGroup(rp); |
413 | 426 | ||
414 | // Need to add the object to the scene so that the request to get script state succeeds | 427 | // Need to add the object to the scene so that the request to get script state succeeds |
@@ -424,6 +437,7 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests | |||
424 | UUID uuid = UUID.Zero; | 437 | UUID uuid = UUID.Zero; |
425 | string name = null; | 438 | string name = null; |
426 | UUID creatorId = UUID.Zero; | 439 | UUID creatorId = UUID.Zero; |
440 | DAMap daMap = null; | ||
427 | 441 | ||
428 | while (xtr.Read() && xtr.Name != "SceneObjectPart") | 442 | while (xtr.Read() && xtr.Name != "SceneObjectPart") |
429 | { | 443 | { |
@@ -449,6 +463,10 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests | |||
449 | creatorId = UUID.Parse(xtr.ReadElementString("UUID")); | 463 | creatorId = UUID.Parse(xtr.ReadElementString("UUID")); |
450 | xtr.ReadEndElement(); | 464 | xtr.ReadEndElement(); |
451 | break; | 465 | break; |
466 | case "DynAttrs": | ||
467 | daMap = new DAMap(); | ||
468 | daMap.ReadXml(xtr); | ||
469 | break; | ||
452 | } | 470 | } |
453 | } | 471 | } |
454 | 472 | ||
@@ -462,6 +480,8 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests | |||
462 | Assert.That(uuid, Is.EqualTo(rpUuid)); | 480 | Assert.That(uuid, Is.EqualTo(rpUuid)); |
463 | Assert.That(name, Is.EqualTo(rpName)); | 481 | Assert.That(name, Is.EqualTo(rpName)); |
464 | Assert.That(creatorId, Is.EqualTo(rpCreatorId)); | 482 | Assert.That(creatorId, Is.EqualTo(rpCreatorId)); |
483 | Assert.NotNull(daMap); | ||
484 | Assert.AreEqual(daValue, daMap[daStoreName][daKey].AsString()); | ||
465 | } | 485 | } |
466 | 486 | ||
467 | [Test] | 487 | [Test] |
@@ -476,6 +496,8 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests | |||
476 | Assert.That(rootPart.UUID, Is.EqualTo(new UUID("9be68fdd-f740-4a0f-9675-dfbbb536b946"))); | 496 | Assert.That(rootPart.UUID, Is.EqualTo(new UUID("9be68fdd-f740-4a0f-9675-dfbbb536b946"))); |
477 | Assert.That(rootPart.CreatorID, Is.EqualTo(new UUID("b46ef588-411e-4a8b-a284-d7dcfe8e74ef"))); | 497 | Assert.That(rootPart.CreatorID, Is.EqualTo(new UUID("b46ef588-411e-4a8b-a284-d7dcfe8e74ef"))); |
478 | Assert.That(rootPart.Name, Is.EqualTo("PrimFun")); | 498 | Assert.That(rootPart.Name, Is.EqualTo("PrimFun")); |
499 | OSDMap store = rootPart.DynAttrs["MyStore"]; | ||
500 | Assert.AreEqual("Rosebud", store["last words"].AsString()); | ||
479 | 501 | ||
480 | // TODO: Check other properties | 502 | // TODO: Check other properties |
481 | } | 503 | } |
@@ -500,6 +522,14 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests | |||
500 | rp.CreatorID = rpCreatorId; | 522 | rp.CreatorID = rpCreatorId; |
501 | rp.Shape = shape; | 523 | rp.Shape = shape; |
502 | 524 | ||
525 | string daStoreName = "MyStore"; | ||
526 | string daKey = "foo"; | ||
527 | string daValue = "bar"; | ||
528 | OSDMap myStore = new OSDMap(); | ||
529 | myStore.Add(daKey, daValue); | ||
530 | rp.DynAttrs = new DAMap(); | ||
531 | rp.DynAttrs[daStoreName] = myStore; | ||
532 | |||
503 | SceneObjectGroup so = new SceneObjectGroup(rp); | 533 | SceneObjectGroup so = new SceneObjectGroup(rp); |
504 | 534 | ||
505 | // Need to add the object to the scene so that the request to get script state succeeds | 535 | // Need to add the object to the scene so that the request to get script state succeeds |
@@ -516,6 +546,7 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests | |||
516 | UUID uuid = UUID.Zero; | 546 | UUID uuid = UUID.Zero; |
517 | string name = null; | 547 | string name = null; |
518 | UUID creatorId = UUID.Zero; | 548 | UUID creatorId = UUID.Zero; |
549 | DAMap daMap = null; | ||
519 | 550 | ||
520 | while (xtr.Read() && xtr.Name != "SceneObjectPart") | 551 | while (xtr.Read() && xtr.Name != "SceneObjectPart") |
521 | { | 552 | { |
@@ -537,6 +568,10 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests | |||
537 | creatorId = UUID.Parse(xtr.ReadElementString("Guid")); | 568 | creatorId = UUID.Parse(xtr.ReadElementString("Guid")); |
538 | xtr.ReadEndElement(); | 569 | xtr.ReadEndElement(); |
539 | break; | 570 | break; |
571 | case "DynAttrs": | ||
572 | daMap = new DAMap(); | ||
573 | daMap.ReadXml(xtr); | ||
574 | break; | ||
540 | } | 575 | } |
541 | } | 576 | } |
542 | 577 | ||
@@ -549,6 +584,8 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests | |||
549 | Assert.That(uuid, Is.EqualTo(rpUuid)); | 584 | Assert.That(uuid, Is.EqualTo(rpUuid)); |
550 | Assert.That(name, Is.EqualTo(rpName)); | 585 | Assert.That(name, Is.EqualTo(rpName)); |
551 | Assert.That(creatorId, Is.EqualTo(rpCreatorId)); | 586 | Assert.That(creatorId, Is.EqualTo(rpCreatorId)); |
587 | Assert.NotNull(daMap); | ||
588 | Assert.AreEqual(daValue, daMap[daStoreName][daKey].AsString()); | ||
552 | } | 589 | } |
553 | } | 590 | } |
554 | } \ No newline at end of file | 591 | } \ No newline at end of file |
diff --git a/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs b/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs index 513a8f5..883045a 100644 --- a/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs +++ b/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs | |||
@@ -43,8 +43,8 @@ namespace OpenSim.Region.CoreModules.World.Sound | |||
43 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "SoundModule")] | 43 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "SoundModule")] |
44 | public class SoundModule : INonSharedRegionModule, ISoundModule | 44 | public class SoundModule : INonSharedRegionModule, ISoundModule |
45 | { | 45 | { |
46 | private static readonly ILog m_log = LogManager.GetLogger( | 46 | // private static readonly ILog m_log = LogManager.GetLogger( |
47 | MethodBase.GetCurrentMethod().DeclaringType); | 47 | // MethodBase.GetCurrentMethod().DeclaringType); |
48 | 48 | ||
49 | private Scene m_scene; | 49 | private Scene m_scene; |
50 | 50 | ||
@@ -76,7 +76,7 @@ namespace OpenSim.Region.CoreModules.World.Sound | |||
76 | 76 | ||
77 | public void RemoveRegion(Scene scene) | 77 | public void RemoveRegion(Scene scene) |
78 | { | 78 | { |
79 | m_scene.EventManager.OnClientLogin -= OnNewClient; | 79 | m_scene.EventManager.OnNewClient -= OnNewClient; |
80 | } | 80 | } |
81 | 81 | ||
82 | public void RegionLoaded(Scene scene) | 82 | public void RegionLoaded(Scene scene) |
@@ -85,7 +85,7 @@ namespace OpenSim.Region.CoreModules.World.Sound | |||
85 | return; | 85 | return; |
86 | 86 | ||
87 | m_scene = scene; | 87 | m_scene = scene; |
88 | m_scene.EventManager.OnClientLogin += OnNewClient; | 88 | m_scene.EventManager.OnNewClient += OnNewClient; |
89 | 89 | ||
90 | m_scene.RegisterModuleInterface<ISoundModule>(this); | 90 | m_scene.RegisterModuleInterface<ISoundModule>(this); |
91 | } | 91 | } |
diff --git a/OpenSim/Region/CoreModules/World/Sun/SunModule.cs b/OpenSim/Region/CoreModules/World/Sun/SunModule.cs index a321c09..6f344c8 100644 --- a/OpenSim/Region/CoreModules/World/Sun/SunModule.cs +++ b/OpenSim/Region/CoreModules/World/Sun/SunModule.cs | |||
@@ -252,12 +252,11 @@ namespace OpenSim.Region.CoreModules | |||
252 | } | 252 | } |
253 | 253 | ||
254 | // TODO: Decouple this, so we can get rid of Linden Hour info | 254 | // TODO: Decouple this, so we can get rid of Linden Hour info |
255 | // Update Region infor with new Sun Position and Hour | 255 | // Update Region with new Sun Vector |
256 | // set estate settings for region access to sun position | 256 | // set estate settings for region access to sun position |
257 | if (receivedEstateToolsSunUpdate) | 257 | if (receivedEstateToolsSunUpdate) |
258 | { | 258 | { |
259 | m_scene.RegionInfo.RegionSettings.SunVector = Position; | 259 | m_scene.RegionInfo.RegionSettings.SunVector = Position; |
260 | m_scene.RegionInfo.RegionSettings.SunPosition = GetCurrentTimeAsLindenSunHour(); | ||
261 | } | 260 | } |
262 | } | 261 | } |
263 | 262 | ||
@@ -395,7 +394,7 @@ namespace OpenSim.Region.CoreModules | |||
395 | ready = false; | 394 | ready = false; |
396 | 395 | ||
397 | // Remove our hooks | 396 | // Remove our hooks |
398 | m_scene.EventManager.OnFrame -= SunUpdate; | 397 | m_scene.EventManager.OnFrame -= SunUpdate; |
399 | m_scene.EventManager.OnAvatarEnteringNewParcel -= AvatarEnteringParcel; | 398 | m_scene.EventManager.OnAvatarEnteringNewParcel -= AvatarEnteringParcel; |
400 | m_scene.EventManager.OnEstateToolsSunUpdate -= EstateToolsSunUpdate; | 399 | m_scene.EventManager.OnEstateToolsSunUpdate -= EstateToolsSunUpdate; |
401 | m_scene.EventManager.OnGetCurrentTimeAsLindenSunHour -= GetCurrentTimeAsLindenSunHour; | 400 | m_scene.EventManager.OnGetCurrentTimeAsLindenSunHour -= GetCurrentTimeAsLindenSunHour; |
@@ -459,26 +458,33 @@ namespace OpenSim.Region.CoreModules | |||
459 | SunToClient(avatar.ControllingClient); | 458 | SunToClient(avatar.ControllingClient); |
460 | } | 459 | } |
461 | 460 | ||
462 | /// <summary> | 461 | public void EstateToolsSunUpdate(ulong regionHandle) |
463 | /// | ||
464 | /// </summary> | ||
465 | /// <param name="regionHandle"></param> | ||
466 | /// <param name="FixedTime">Is the sun's position fixed?</param> | ||
467 | /// <param name="useEstateTime">Use the Region or Estate Sun hour?</param> | ||
468 | /// <param name="FixedSunHour">What hour of the day is the Sun Fixed at?</param> | ||
469 | public void EstateToolsSunUpdate(ulong regionHandle, bool FixedSun, bool useEstateTime, float FixedSunHour) | ||
470 | { | 462 | { |
471 | if (m_scene.RegionInfo.RegionHandle == regionHandle) | 463 | if (m_scene.RegionInfo.RegionHandle == regionHandle) |
472 | { | 464 | { |
473 | // Must limit the Sun Hour to 0 ... 24 | 465 | float sunFixedHour; |
474 | while (FixedSunHour > 24.0f) | 466 | bool fixedSun; |
475 | FixedSunHour -= 24; | ||
476 | 467 | ||
477 | while (FixedSunHour < 0) | 468 | if (m_scene.RegionInfo.RegionSettings.UseEstateSun) |
478 | FixedSunHour += 24; | 469 | { |
470 | sunFixedHour = (float)m_scene.RegionInfo.EstateSettings.SunPosition; | ||
471 | fixedSun = m_scene.RegionInfo.EstateSettings.FixedSun; | ||
472 | } | ||
473 | else | ||
474 | { | ||
475 | sunFixedHour = (float)m_scene.RegionInfo.RegionSettings.SunPosition - 6.0f; | ||
476 | fixedSun = m_scene.RegionInfo.RegionSettings.FixedSun; | ||
477 | } | ||
478 | |||
479 | // Must limit the Sun Hour to 0 ... 24 | ||
480 | while (sunFixedHour > 24.0f) | ||
481 | sunFixedHour -= 24; | ||
479 | 482 | ||
480 | m_SunFixedHour = FixedSunHour; | 483 | while (sunFixedHour < 0) |
481 | m_SunFixed = FixedSun; | 484 | sunFixedHour += 24; |
485 | |||
486 | m_SunFixedHour = sunFixedHour; | ||
487 | m_SunFixed = fixedSun; | ||
482 | 488 | ||
483 | // m_log.DebugFormat("[SUN]: Sun Settings Update: Fixed Sun? : {0}", m_SunFixed.ToString()); | 489 | // m_log.DebugFormat("[SUN]: Sun Settings Update: Fixed Sun? : {0}", m_SunFixed.ToString()); |
484 | // m_log.DebugFormat("[SUN]: Sun Settings Update: Sun Hour : {0}", m_SunFixedHour.ToString()); | 490 | // m_log.DebugFormat("[SUN]: Sun Settings Update: Sun Hour : {0}", m_SunFixedHour.ToString()); |
@@ -501,7 +507,7 @@ namespace OpenSim.Region.CoreModules | |||
501 | { | 507 | { |
502 | m_scene.ForEachRootClient(delegate(IClientAPI client) | 508 | m_scene.ForEachRootClient(delegate(IClientAPI client) |
503 | { | 509 | { |
504 | SunToClient(client); | 510 | SunToClient(client); |
505 | }); | 511 | }); |
506 | } | 512 | } |
507 | 513 | ||
diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs index 33aabe4..4d738a5 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs | |||
@@ -480,7 +480,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
480 | else | 480 | else |
481 | { | 481 | { |
482 | m_plugineffects[pluginName] = effect; | 482 | m_plugineffects[pluginName] = effect; |
483 | m_log.Warn("E ... " + pluginName + " (Replaced)"); | 483 | m_log.Info("E ... " + pluginName + " (Replaced)"); |
484 | } | 484 | } |
485 | } | 485 | } |
486 | } | 486 | } |
diff --git a/OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainTest.cs b/OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainTest.cs index 3d4f762..be719ea 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainTest.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainTest.cs | |||
@@ -30,11 +30,12 @@ using NUnit.Framework; | |||
30 | using OpenSim.Framework; | 30 | using OpenSim.Framework; |
31 | using OpenSim.Region.CoreModules.World.Terrain.PaintBrushes; | 31 | using OpenSim.Region.CoreModules.World.Terrain.PaintBrushes; |
32 | using OpenSim.Region.Framework.Scenes; | 32 | using OpenSim.Region.Framework.Scenes; |
33 | using OpenSim.Tests.Common; | ||
33 | 34 | ||
34 | namespace OpenSim.Region.CoreModules.World.Terrain.Tests | 35 | namespace OpenSim.Region.CoreModules.World.Terrain.Tests |
35 | { | 36 | { |
36 | [TestFixture] | 37 | [TestFixture] |
37 | public class TerrainTest | 38 | public class TerrainTest : OpenSimTestCase |
38 | { | 39 | { |
39 | [Test] | 40 | [Test] |
40 | public void BrushTest() | 41 | public void BrushTest() |
diff --git a/OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs b/OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs index 7ef44db..d38f34b 100644 --- a/OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs +++ b/OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs | |||
@@ -74,8 +74,8 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap | |||
74 | { | 74 | { |
75 | m_config = source; | 75 | m_config = source; |
76 | 76 | ||
77 | IConfig startupConfig = m_config.Configs["Startup"]; | 77 | if (Util.GetConfigVarFromSections<string>( |
78 | if (startupConfig.GetString("MapImageModule", "MapImageModule") != "Warp3DImageModule") | 78 | m_config, "MapImageModule", new string[] { "Startup", "Map" }, "MapImageModule") != "Warp3DImageModule") |
79 | return; | 79 | return; |
80 | 80 | ||
81 | m_Enabled = true; | 81 | m_Enabled = true; |
@@ -157,16 +157,12 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap | |||
157 | bool drawPrimVolume = true; | 157 | bool drawPrimVolume = true; |
158 | bool textureTerrain = true; | 158 | bool textureTerrain = true; |
159 | 159 | ||
160 | try | 160 | string[] configSections = new string[] { "Map", "Startup" }; |
161 | { | 161 | |
162 | IConfig startupConfig = m_config.Configs["Startup"]; | 162 | drawPrimVolume |
163 | drawPrimVolume = startupConfig.GetBoolean("DrawPrimOnMapTile", drawPrimVolume); | 163 | = Util.GetConfigVarFromSections<bool>(m_config, "DrawPrimOnMapTile", configSections, drawPrimVolume); |
164 | textureTerrain = startupConfig.GetBoolean("TextureOnMapTile", textureTerrain); | 164 | textureTerrain |
165 | } | 165 | = Util.GetConfigVarFromSections<bool>(m_config, "TextureOnMapTile", configSections, textureTerrain); |
166 | catch | ||
167 | { | ||
168 | m_log.Warn("[WARP 3D IMAGE MODULE]: Failed to load StartupConfig"); | ||
169 | } | ||
170 | 166 | ||
171 | m_colors.Clear(); | 167 | m_colors.Clear(); |
172 | 168 | ||
diff --git a/OpenSim/Region/CoreModules/World/Wind/WindModule.cs b/OpenSim/Region/CoreModules/World/Wind/WindModule.cs index fd8e2b4..9de588c 100644 --- a/OpenSim/Region/CoreModules/World/Wind/WindModule.cs +++ b/OpenSim/Region/CoreModules/World/Wind/WindModule.cs | |||
@@ -66,7 +66,7 @@ namespace OpenSim.Region.CoreModules | |||
66 | public void Initialise(IConfigSource config) | 66 | public void Initialise(IConfigSource config) |
67 | { | 67 | { |
68 | m_windConfig = config.Configs["Wind"]; | 68 | m_windConfig = config.Configs["Wind"]; |
69 | string desiredWindPlugin = m_dWindPluginName; | 69 | // string desiredWindPlugin = m_dWindPluginName; |
70 | 70 | ||
71 | if (m_windConfig != null) | 71 | if (m_windConfig != null) |
72 | { | 72 | { |
diff --git a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs index 2184a59..bf18616 100644 --- a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs +++ b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs | |||
@@ -89,11 +89,14 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
89 | #region INonSharedRegionModule Members | 89 | #region INonSharedRegionModule Members |
90 | public virtual void Initialise (IConfigSource config) | 90 | public virtual void Initialise (IConfigSource config) |
91 | { | 91 | { |
92 | IConfig startupConfig = config.Configs["Startup"]; | 92 | string[] configSections = new string[] { "Map", "Startup" }; |
93 | if (startupConfig.GetString("WorldMapModule", "WorldMap") == "WorldMap") | ||
94 | m_Enabled = true; | ||
95 | 93 | ||
96 | blacklistTimeout = startupConfig.GetInt("BlacklistTimeout", 10*60) * 1000; | 94 | if (Util.GetConfigVarFromSections<string>( |
95 | config, "WorldMapModule", configSections, "WorldMap") == "WorldMap") | ||
96 | m_Enabled = true; | ||
97 | |||
98 | blacklistTimeout | ||
99 | = Util.GetConfigVarFromSections<int>(config, "BlacklistTimeout", configSections, 10 * 60) * 1000; | ||
97 | } | 100 | } |
98 | 101 | ||
99 | public virtual void AddRegion (Scene scene) | 102 | public virtual void AddRegion (Scene scene) |
diff --git a/OpenSim/Region/DataSnapshot/DataSnapshotManager.cs b/OpenSim/Region/DataSnapshot/DataSnapshotManager.cs index 5e62f23..dd48dd5 100644 --- a/OpenSim/Region/DataSnapshot/DataSnapshotManager.cs +++ b/OpenSim/Region/DataSnapshot/DataSnapshotManager.cs | |||
@@ -113,9 +113,17 @@ namespace OpenSim.Region.DataSnapshot | |||
113 | try | 113 | try |
114 | { | 114 | { |
115 | m_enabled = config.Configs["DataSnapshot"].GetBoolean("index_sims", m_enabled); | 115 | m_enabled = config.Configs["DataSnapshot"].GetBoolean("index_sims", m_enabled); |
116 | IConfig conf = config.Configs["GridService"]; | 116 | string gatekeeper = Util.GetConfigVarFromSections<string>(config, "GatekeeperURI", |
117 | if (conf != null) | 117 | new string[] { "Startup", "Hypergrid", "GridService" }, String.Empty); |
118 | m_gridinfo.Add("gatekeeperURL", conf.GetString("Gatekeeper", String.Empty)); | 118 | // Legacy. Remove soon! |
119 | if (string.IsNullOrEmpty(gatekeeper)) | ||
120 | { | ||
121 | IConfig conf = config.Configs["GridService"]; | ||
122 | if (conf != null) | ||
123 | gatekeeper = conf.GetString("Gatekeeper", gatekeeper); | ||
124 | } | ||
125 | if (!string.IsNullOrEmpty(gatekeeper)) | ||
126 | m_gridinfo.Add("gatekeeperURL", gatekeeper); | ||
119 | 127 | ||
120 | m_gridinfo.Add( | 128 | m_gridinfo.Add( |
121 | "name", config.Configs["DataSnapshot"].GetString("gridname", "the lost continent of hippo")); | 129 | "name", config.Configs["DataSnapshot"].GetString("gridname", "the lost continent of hippo")); |
@@ -140,8 +148,6 @@ namespace OpenSim.Region.DataSnapshot | |||
140 | return; | 148 | return; |
141 | } | 149 | } |
142 | 150 | ||
143 | if (m_enabled) | ||
144 | m_snapStore = new SnapshotStore(m_snapsDir, m_gridinfo, m_listener_port, m_hostname); | ||
145 | } | 151 | } |
146 | 152 | ||
147 | } | 153 | } |
@@ -155,8 +161,22 @@ namespace OpenSim.Region.DataSnapshot | |||
155 | 161 | ||
156 | m_log.DebugFormat("[DATASNAPSHOT]: Module added to Scene {0}.", scene.RegionInfo.RegionName); | 162 | m_log.DebugFormat("[DATASNAPSHOT]: Module added to Scene {0}.", scene.RegionInfo.RegionName); |
157 | 163 | ||
158 | m_snapStore.AddScene(scene); | 164 | if (!m_servicesNotified) |
165 | { | ||
166 | m_hostname = scene.RegionInfo.ExternalHostName; | ||
167 | m_snapStore = new SnapshotStore(m_snapsDir, m_gridinfo, m_listener_port, m_hostname); | ||
168 | |||
169 | //Hand it the first scene, assuming that all scenes have the same BaseHTTPServer | ||
170 | new DataRequestHandler(scene, this); | ||
171 | |||
172 | if (m_dataServices != "" && m_dataServices != "noservices") | ||
173 | NotifyDataServices(m_dataServices, "online"); | ||
174 | |||
175 | m_servicesNotified = true; | ||
176 | } | ||
177 | |||
159 | m_scenes.Add(scene); | 178 | m_scenes.Add(scene); |
179 | m_snapStore.AddScene(scene); | ||
160 | 180 | ||
161 | Assembly currentasm = Assembly.GetExecutingAssembly(); | 181 | Assembly currentasm = Assembly.GetExecutingAssembly(); |
162 | 182 | ||
@@ -181,22 +201,6 @@ namespace OpenSim.Region.DataSnapshot | |||
181 | } | 201 | } |
182 | } | 202 | } |
183 | 203 | ||
184 | // Must be done here because on shared modules, PostInitialise() will run | ||
185 | // BEFORE any scenes are registered. There is no "all scenes have been loaded" | ||
186 | // kind of callback because scenes may be created dynamically, so we cannot | ||
187 | // have that info, ever. | ||
188 | if (!m_servicesNotified) | ||
189 | { | ||
190 | //Hand it the first scene, assuming that all scenes have the same BaseHTTPServer | ||
191 | new DataRequestHandler(m_scenes[0], this); | ||
192 | |||
193 | m_hostname = m_scenes[0].RegionInfo.ExternalHostName; | ||
194 | |||
195 | if (m_dataServices != "" && m_dataServices != "noservices") | ||
196 | NotifyDataServices(m_dataServices, "online"); | ||
197 | |||
198 | m_servicesNotified = true; | ||
199 | } | ||
200 | } | 204 | } |
201 | 205 | ||
202 | public void RemoveRegion(Scene scene) | 206 | public void RemoveRegion(Scene scene) |
diff --git a/OpenSim/Region/DataSnapshot/Properties/AssemblyInfo.cs b/OpenSim/Region/DataSnapshot/Properties/AssemblyInfo.cs index b926264..0e7df07 100644 --- a/OpenSim/Region/DataSnapshot/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/DataSnapshot/Properties/AssemblyInfo.cs | |||
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices; | |||
29 | // Build Number | 29 | // Build Number |
30 | // Revision | 30 | // Revision |
31 | // | 31 | // |
32 | [assembly: AssemblyVersion("0.7.5.*")] | 32 | [assembly: AssemblyVersion("0.7.6.*")] |
33 | [assembly: AssemblyFileVersion("1.0.0.0")] | 33 | |
diff --git a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs index d781eae..3c1247f 100644 --- a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs | |||
@@ -54,6 +54,10 @@ namespace OpenSim.Region.Framework.Interfaces | |||
54 | /// RezAttachments. This should only be called upon login on the first region. | 54 | /// RezAttachments. This should only be called upon login on the first region. |
55 | /// Attachment rezzings on crossings and TPs are done in a different way. | 55 | /// Attachment rezzings on crossings and TPs are done in a different way. |
56 | /// </summary> | 56 | /// </summary> |
57 | /// <remarks> | ||
58 | /// This is only actually necessary for viewers which do not have a current outfit folder (these viewers make | ||
59 | /// their own attachment calls on login) and agents which have attachments but no viewer (e.g. NPCs). | ||
60 | /// </remarks> | ||
57 | /// <param name="sp"></param> | 61 | /// <param name="sp"></param> |
58 | void RezAttachments(IScenePresence sp); | 62 | void RezAttachments(IScenePresence sp); |
59 | 63 | ||
@@ -77,14 +81,16 @@ namespace OpenSim.Region.Framework.Interfaces | |||
77 | void DeleteAttachmentsFromScene(IScenePresence sp, bool silent); | 81 | void DeleteAttachmentsFromScene(IScenePresence sp, bool silent); |
78 | 82 | ||
79 | /// <summary> | 83 | /// <summary> |
80 | /// Attach an object to an avatar | 84 | /// Attach an object to an avatar. |
81 | /// </summary> | 85 | /// </summary> |
82 | /// <param name="sp"></param> | 86 | /// <param name="sp"></param> |
83 | /// <param name="grp"></param> | 87 | /// <param name="grp"></param> |
84 | /// <param name="AttachmentPt"></param> | 88 | /// <param name="AttachmentPt"></param> |
85 | /// <param name="silent"></param> | 89 | /// <param name="silent"></param> |
90 | /// <param name="addToInventory">If true then add object to user inventory</param> | ||
91 | /// <param name="append">Append to attachment point rather than replace.</param> | ||
86 | /// <returns>true if the object was successfully attached, false otherwise</returns> | 92 | /// <returns>true if the object was successfully attached, false otherwise</returns> |
87 | bool AttachObject(IScenePresence sp, SceneObjectGroup grp, uint AttachmentPt, bool silent, bool useAttachmentInfo, bool temp); | 93 | bool AttachObject(IScenePresence sp, SceneObjectGroup grp, uint AttachmentPt, bool silent, bool useAttachmentInfo, bool addToInventory, bool append); |
88 | 94 | ||
89 | /// <summary> | 95 | /// <summary> |
90 | /// Rez an attachment from user inventory and change inventory status to match. | 96 | /// Rez an attachment from user inventory and change inventory status to match. |
diff --git a/OpenSim/Region/Framework/Interfaces/ICapabilitiesModule.cs b/OpenSim/Region/Framework/Interfaces/ICapabilitiesModule.cs index 522c82d..30d404e 100644 --- a/OpenSim/Region/Framework/Interfaces/ICapabilitiesModule.cs +++ b/OpenSim/Region/Framework/Interfaces/ICapabilitiesModule.cs | |||
@@ -40,19 +40,19 @@ namespace OpenSim.Region.Framework.Interfaces | |||
40 | /// </summary> | 40 | /// </summary> |
41 | /// <param name="agentId"></param> | 41 | /// <param name="agentId"></param> |
42 | /// <param name="capsObjectPath"></param> | 42 | /// <param name="capsObjectPath"></param> |
43 | void CreateCaps(UUID agentId); | 43 | void CreateCaps(UUID agentId, uint circuitCode); |
44 | 44 | ||
45 | /// <summary> | 45 | /// <summary> |
46 | /// Remove the caps handler for a given agent. | 46 | /// Remove the caps handler for a given agent. |
47 | /// </summary> | 47 | /// </summary> |
48 | /// <param name="agentId"></param> | 48 | /// <param name="agentId"></param> |
49 | void RemoveCaps(UUID agentId); | 49 | void RemoveCaps(UUID agentId, uint circuitCode); |
50 | 50 | ||
51 | /// <summary> | 51 | /// <summary> |
52 | /// Will return null if the agent doesn't have a caps handler registered | 52 | /// Will return null if the agent doesn't have a caps handler registered |
53 | /// </summary> | 53 | /// </summary> |
54 | /// <param name="agentId"></param> | 54 | /// <param name="agentId"></param> |
55 | Caps GetCapsForUser(UUID agentId); | 55 | Caps GetCapsForUser(uint circuitCode); |
56 | 56 | ||
57 | void SetAgentCapsSeeds(AgentCircuitData agent); | 57 | void SetAgentCapsSeeds(AgentCircuitData agent); |
58 | 58 | ||
@@ -65,5 +65,7 @@ namespace OpenSim.Region.Framework.Interfaces | |||
65 | void DropChildSeed(UUID agentID, ulong handle); | 65 | void DropChildSeed(UUID agentID, ulong handle); |
66 | 66 | ||
67 | string GetCapsPath(UUID agentId); | 67 | string GetCapsPath(UUID agentId); |
68 | |||
69 | void ActivateCaps(uint circuitCode); | ||
68 | } | 70 | } |
69 | } | 71 | } |
diff --git a/OpenSim/Region/Framework/Interfaces/IDynamicFloaterModule.cs b/OpenSim/Region/Framework/Interfaces/IDynamicFloaterModule.cs new file mode 100644 index 0000000..5e633e6 --- /dev/null +++ b/OpenSim/Region/Framework/Interfaces/IDynamicFloaterModule.cs | |||
@@ -0,0 +1,51 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System.Collections.Generic; | ||
29 | using OpenMetaverse; | ||
30 | using OpenSim.Framework; | ||
31 | using OpenSim.Region.Framework.Scenes; | ||
32 | |||
33 | namespace OpenSim.Region.Framework.Interfaces | ||
34 | { | ||
35 | public delegate bool HandlerDelegate(IClientAPI client, FloaterData data, string[] msg); | ||
36 | |||
37 | public abstract class FloaterData | ||
38 | { | ||
39 | public abstract int Channel { get; } | ||
40 | public abstract string FloaterName { get; } | ||
41 | public virtual string XmlName { get; set; } | ||
42 | public virtual HandlerDelegate Handler { get; set; } | ||
43 | } | ||
44 | |||
45 | |||
46 | public interface IDynamicFloaterModule | ||
47 | { | ||
48 | void DoUserFloater(UUID agentID, FloaterData dialogData, string configuration); | ||
49 | void FloaterControl(ScenePresence sp, FloaterData d, string msg); | ||
50 | } | ||
51 | } | ||
diff --git a/OpenSim/Region/Framework/Interfaces/IDynamicMenuModule.cs b/OpenSim/Region/Framework/Interfaces/IDynamicMenuModule.cs new file mode 100644 index 0000000..08b71e4 --- /dev/null +++ b/OpenSim/Region/Framework/Interfaces/IDynamicMenuModule.cs | |||
@@ -0,0 +1,57 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System.Collections.Generic; | ||
29 | using OpenMetaverse; | ||
30 | using OpenSim.Framework; | ||
31 | |||
32 | namespace OpenSim.Region.Framework.Interfaces | ||
33 | { | ||
34 | public enum InsertLocation : int | ||
35 | { | ||
36 | Agent = 1, | ||
37 | World = 2, | ||
38 | Tools = 3, | ||
39 | Advanced = 4, | ||
40 | Admin = 5 | ||
41 | } | ||
42 | |||
43 | public enum UserMode : int | ||
44 | { | ||
45 | Normal = 0, | ||
46 | God = 3 | ||
47 | } | ||
48 | |||
49 | public delegate void CustomMenuHandler(string action, UUID agentID, List<uint> selection); | ||
50 | |||
51 | public interface IDynamicMenuModule | ||
52 | { | ||
53 | void AddMenuItem(UUID agentID, string title, InsertLocation location, UserMode mode, CustomMenuHandler handler); | ||
54 | void AddMenuItem(string title, InsertLocation location, UserMode mode, CustomMenuHandler handler); | ||
55 | void RemoveMenuItem(string action); | ||
56 | } | ||
57 | } | ||
diff --git a/OpenSim/Region/Framework/Interfaces/IHttpRequests.cs b/OpenSim/Region/Framework/Interfaces/IHttpRequests.cs index de0f2a3..eb6c5ac 100644 --- a/OpenSim/Region/Framework/Interfaces/IHttpRequests.cs +++ b/OpenSim/Region/Framework/Interfaces/IHttpRequests.cs | |||
@@ -36,6 +36,9 @@ namespace OpenSim.Region.Framework.Interfaces | |||
36 | HTTP_MIMETYPE = 1, | 36 | HTTP_MIMETYPE = 1, |
37 | HTTP_BODY_MAXLENGTH = 2, | 37 | HTTP_BODY_MAXLENGTH = 2, |
38 | HTTP_VERIFY_CERT = 3, | 38 | HTTP_VERIFY_CERT = 3, |
39 | HTTP_VERBOSE_THROTTLE = 4, | ||
40 | HTTP_CUSTOM_HEADER = 5, | ||
41 | HTTP_PRAGMA_NO_CACHE = 6 | ||
39 | } | 42 | } |
40 | 43 | ||
41 | public interface IHttpRequestModule | 44 | public interface IHttpRequestModule |
diff --git a/OpenSim/Region/Framework/Interfaces/IJsonStoreModule.cs b/OpenSim/Region/Framework/Interfaces/IJsonStoreModule.cs index da39e95..b67312e 100644 --- a/OpenSim/Region/Framework/Interfaces/IJsonStoreModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IJsonStoreModule.cs | |||
@@ -31,18 +31,46 @@ using OpenMetaverse; | |||
31 | 31 | ||
32 | namespace OpenSim.Region.Framework.Interfaces | 32 | namespace OpenSim.Region.Framework.Interfaces |
33 | { | 33 | { |
34 | // these could be expanded at some point to provide more type information | ||
35 | // for now value accounts for all base types | ||
36 | public enum JsonStoreNodeType | ||
37 | { | ||
38 | Undefined = 0, | ||
39 | Object = 1, | ||
40 | Array = 2, | ||
41 | Value = 3 | ||
42 | } | ||
43 | |||
44 | public enum JsonStoreValueType | ||
45 | { | ||
46 | Undefined = 0, | ||
47 | Boolean = 1, | ||
48 | Integer = 2, | ||
49 | Float = 3, | ||
50 | String = 4, | ||
51 | UUID = 5 | ||
52 | } | ||
53 | |||
34 | public delegate void TakeValueCallback(string s); | 54 | public delegate void TakeValueCallback(string s); |
35 | 55 | ||
36 | public interface IJsonStoreModule | 56 | public interface IJsonStoreModule |
37 | { | 57 | { |
58 | bool AttachObjectStore(UUID objectID); | ||
38 | bool CreateStore(string value, ref UUID result); | 59 | bool CreateStore(string value, ref UUID result); |
39 | bool DestroyStore(UUID storeID); | 60 | bool DestroyStore(UUID storeID); |
40 | bool TestPath(UUID storeID, string path, bool useJson); | 61 | |
62 | JsonStoreNodeType GetNodeType(UUID storeID, string path); | ||
63 | JsonStoreValueType GetValueType(UUID storeID, string path); | ||
64 | |||
65 | bool TestStore(UUID storeID); | ||
66 | |||
41 | bool SetValue(UUID storeID, string path, string value, bool useJson); | 67 | bool SetValue(UUID storeID, string path, string value, bool useJson); |
42 | bool RemoveValue(UUID storeID, string path); | 68 | bool RemoveValue(UUID storeID, string path); |
43 | bool GetValue(UUID storeID, string path, bool useJson, out string value); | 69 | bool GetValue(UUID storeID, string path, bool useJson, out string value); |
44 | 70 | ||
45 | void TakeValue(UUID storeID, string path, bool useJson, TakeValueCallback cback); | 71 | void TakeValue(UUID storeID, string path, bool useJson, TakeValueCallback cback); |
46 | void ReadValue(UUID storeID, string path, bool useJson, TakeValueCallback cback); | 72 | void ReadValue(UUID storeID, string path, bool useJson, TakeValueCallback cback); |
73 | |||
74 | int GetArrayLength(UUID storeID, string path); | ||
47 | } | 75 | } |
48 | } | 76 | } |
diff --git a/OpenSim/Region/Framework/Scenes/Scripting/ScriptEngineInterface.cs b/OpenSim/Region/Framework/Interfaces/ISceneCommandsModule.cs index 812a21c..c5e678b 100644 --- a/OpenSim/Region/Framework/Scenes/Scripting/ScriptEngineInterface.cs +++ b/OpenSim/Region/Framework/Interfaces/ISceneCommandsModule.cs | |||
@@ -9,7 +9,7 @@ | |||
9 | * * Redistributions in binary form must reproduce the above copyright | 9 | * * Redistributions in binary form must reproduce the above copyright |
10 | * notice, this list of conditions and the following disclaimer in the | 10 | * notice, this list of conditions and the following disclaimer in the |
11 | * documentation and/or other materials provided with the distribution. | 11 | * documentation and/or other materials provided with the distribution. |
12 | * * Neither the name of the OpenSimulator Project nor the | 12 | * * Neither the name of the OpenSim Project nor the |
13 | * names of its contributors may be used to endorse or promote products | 13 | * names of its contributors may be used to endorse or promote products |
14 | * derived from this software without specific prior written permission. | 14 | * derived from this software without specific prior written permission. |
15 | * | 15 | * |
@@ -25,14 +25,19 @@ | |||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | */ | 26 | */ |
27 | 27 | ||
28 | //TODO: WHERE TO PLACE THIS? | 28 | using System; |
29 | using System.Collections.Generic; | ||
30 | using OpenMetaverse; | ||
31 | using OpenSim.Framework; | ||
32 | using OpenSim.Region.Framework.Scenes; | ||
29 | 33 | ||
30 | namespace OpenSim.Region.Framework.Scenes.Scripting | 34 | namespace OpenSim.Region.Framework.Interfaces |
31 | { | 35 | { |
32 | public interface ScriptEngineInterface | 36 | public interface ISceneCommandsModule |
33 | { | 37 | { |
34 | void InitializeEngine(Scene Sceneworld); | 38 | /// <summary> |
35 | void Shutdown(); | 39 | /// Sets the scene debug options. |
36 | // void StartScript(string ScriptID, IScriptHost ObjectID); | 40 | /// </summary> |
41 | void SetSceneDebugOptions(Dictionary<string, string> options); | ||
37 | } | 42 | } |
38 | } | 43 | } \ No newline at end of file |
diff --git a/OpenSim/Region/Framework/Interfaces/IScriptModule.cs b/OpenSim/Region/Framework/Interfaces/IScriptModule.cs index 143af48..ced4e91 100644 --- a/OpenSim/Region/Framework/Interfaces/IScriptModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IScriptModule.cs | |||
@@ -52,7 +52,18 @@ namespace OpenSim.Region.Framework.Interfaces | |||
52 | string GetXMLState(UUID itemID); | 52 | string GetXMLState(UUID itemID); |
53 | bool SetXMLState(UUID itemID, string xml); | 53 | bool SetXMLState(UUID itemID, string xml); |
54 | 54 | ||
55 | /// <summary> | ||
56 | /// Post a script event to a single script. | ||
57 | /// </summary> | ||
58 | /// <returns>true if the post suceeded, false if it did not</returns> | ||
59 | /// <param name='itemID'>The item ID of the script.</param> | ||
60 | /// <param name='name'>The name of the event.</param> | ||
61 | /// <param name='args'> | ||
62 | /// The arguments of the event. These are in the order in which they appear. | ||
63 | /// e.g. for http_request this will be an object array of key request_id, string method, string body | ||
64 | /// </param> | ||
55 | bool PostScriptEvent(UUID itemID, string name, Object[] args); | 65 | bool PostScriptEvent(UUID itemID, string name, Object[] args); |
66 | |||
56 | bool PostObjectEvent(UUID itemID, string name, Object[] args); | 67 | bool PostObjectEvent(UUID itemID, string name, Object[] args); |
57 | 68 | ||
58 | /// <summary> | 69 | /// <summary> |
diff --git a/OpenSim/Region/Framework/Interfaces/ISimulatorFeaturesModule.cs b/OpenSim/Region/Framework/Interfaces/ISimulatorFeaturesModule.cs index 8cef14e..6effcc1 100644 --- a/OpenSim/Region/Framework/Interfaces/ISimulatorFeaturesModule.cs +++ b/OpenSim/Region/Framework/Interfaces/ISimulatorFeaturesModule.cs | |||
@@ -26,18 +26,22 @@ | |||
26 | */ | 26 | */ |
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using OpenMetaverse; | ||
29 | using OpenMetaverse.StructuredData; | 30 | using OpenMetaverse.StructuredData; |
30 | 31 | ||
31 | namespace OpenSim.Region.Framework.Interfaces | 32 | namespace OpenSim.Region.Framework.Interfaces |
32 | { | 33 | { |
34 | public delegate void SimulatorFeaturesRequestDelegate(UUID agentID, ref OSDMap features); | ||
35 | |||
33 | /// <summary> | 36 | /// <summary> |
34 | /// Add remove or retrieve Simulator Features that will be given to a viewer via the SimulatorFeatures capability. | 37 | /// Add remove or retrieve Simulator Features that will be given to a viewer via the SimulatorFeatures capability. |
35 | /// </summary> | 38 | /// </summary> |
36 | public interface ISimulatorFeaturesModule | 39 | public interface ISimulatorFeaturesModule |
37 | { | 40 | { |
41 | event SimulatorFeaturesRequestDelegate OnSimulatorFeaturesRequest; | ||
38 | void AddFeature(string name, OSD value); | 42 | void AddFeature(string name, OSD value); |
39 | bool RemoveFeature(string name); | 43 | bool RemoveFeature(string name); |
40 | bool TryGetFeature(string name, out OSD value); | 44 | bool TryGetFeature(string name, out OSD value); |
41 | OSDMap GetFeatures(); | 45 | OSDMap GetFeatures(); |
42 | } | 46 | } |
43 | } \ No newline at end of file | 47 | } |
diff --git a/OpenSim/Region/Framework/Interfaces/IXmlRpcRouter.cs b/OpenSim/Region/Framework/Interfaces/IXmlRpcRouter.cs index 6db6674..093d3f0 100644 --- a/OpenSim/Region/Framework/Interfaces/IXmlRpcRouter.cs +++ b/OpenSim/Region/Framework/Interfaces/IXmlRpcRouter.cs | |||
@@ -34,5 +34,6 @@ namespace OpenSim.Region.Framework.Interfaces | |||
34 | void RegisterNewReceiver(IScriptModule scriptEngine, UUID channelID, UUID objectID, UUID itemID, string url); | 34 | void RegisterNewReceiver(IScriptModule scriptEngine, UUID channelID, UUID objectID, UUID itemID, string url); |
35 | void ScriptRemoved(UUID itemID); | 35 | void ScriptRemoved(UUID itemID); |
36 | void ObjectRemoved(UUID objectID); | 36 | void ObjectRemoved(UUID objectID); |
37 | void UnRegisterReceiver(string channelID, UUID itemID); | ||
37 | } | 38 | } |
38 | } | 39 | } |
diff --git a/OpenSim/Region/Framework/Properties/AssemblyInfo.cs b/OpenSim/Region/Framework/Properties/AssemblyInfo.cs index 9b504c0..167c248 100644 --- a/OpenSim/Region/Framework/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/Framework/Properties/AssemblyInfo.cs | |||
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices; | |||
29 | // Build Number | 29 | // Build Number |
30 | // Revision | 30 | // Revision |
31 | // | 31 | // |
32 | [assembly: AssemblyVersion("0.7.5.*")] | 32 | [assembly: AssemblyVersion("0.7.6.*")] |
33 | [assembly: AssemblyFileVersion("1.0.0.0")] | 33 | |
diff --git a/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs b/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs index 65ae445..66edfed 100644 --- a/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs +++ b/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs | |||
@@ -87,13 +87,24 @@ namespace OpenSim.Region.Framework.Scenes.Animation | |||
87 | return false; | 87 | return false; |
88 | } | 88 | } |
89 | 89 | ||
90 | public bool Remove(UUID animID) | 90 | /// <summary> |
91 | /// Remove the specified animation | ||
92 | /// </summary> | ||
93 | /// <param name='animID'></param> | ||
94 | /// <param name='allowNoDefault'> | ||
95 | /// If true, then the default animation can be entirely removed. | ||
96 | /// If false, then removing the default animation will reset it to the simulator default (currently STAND). | ||
97 | /// </param> | ||
98 | public bool Remove(UUID animID, bool allowNoDefault) | ||
91 | { | 99 | { |
92 | lock (m_animations) | 100 | lock (m_animations) |
93 | { | 101 | { |
94 | if (m_defaultAnimation.AnimID == animID) | 102 | if (m_defaultAnimation.AnimID == animID) |
95 | { | 103 | { |
96 | m_defaultAnimation = new OpenSim.Framework.Animation(UUID.Zero, 1, UUID.Zero); | 104 | if (allowNoDefault) |
105 | m_defaultAnimation = new OpenSim.Framework.Animation(UUID.Zero, 1, UUID.Zero); | ||
106 | else | ||
107 | ResetDefaultAnimation(); | ||
97 | } | 108 | } |
98 | else if (HasAnimation(animID)) | 109 | else if (HasAnimation(animID)) |
99 | { | 110 | { |
diff --git a/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs b/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs index 9458079..65c279e 100644 --- a/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs +++ b/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs | |||
@@ -26,9 +26,10 @@ | |||
26 | */ | 26 | */ |
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Threading; | ||
30 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.Linq; | ||
31 | using System.Reflection; | 31 | using System.Reflection; |
32 | using System.Threading; | ||
32 | using log4net; | 33 | using log4net; |
33 | using OpenMetaverse; | 34 | using OpenMetaverse; |
34 | using OpenSim.Framework; | 35 | using OpenSim.Framework; |
@@ -86,6 +87,10 @@ namespace OpenSim.Region.Framework.Scenes.Animation | |||
86 | return; | 87 | return; |
87 | 88 | ||
88 | // m_log.DebugFormat("[SCENE PRESENCE ANIMATOR]: Adding animation {0} for {1}", animID, m_scenePresence.Name); | 89 | // m_log.DebugFormat("[SCENE PRESENCE ANIMATOR]: Adding animation {0} for {1}", animID, m_scenePresence.Name); |
90 | if (m_scenePresence.Scene.DebugAnimations) | ||
91 | m_log.DebugFormat( | ||
92 | "[SCENE PRESENCE ANIMATOR]: Adding animation {0} {1} for {2}", | ||
93 | GetAnimName(animID), animID, m_scenePresence.Name); | ||
89 | 94 | ||
90 | if (m_animations.Add(animID, m_scenePresence.ControllingClient.NextAnimationSequenceNumber, objectID)) | 95 | if (m_animations.Add(animID, m_scenePresence.ControllingClient.NextAnimationSequenceNumber, objectID)) |
91 | SendAnimPack(); | 96 | SendAnimPack(); |
@@ -108,12 +113,25 @@ namespace OpenSim.Region.Framework.Scenes.Animation | |||
108 | AddAnimation(animID, objectID); | 113 | AddAnimation(animID, objectID); |
109 | } | 114 | } |
110 | 115 | ||
111 | public void RemoveAnimation(UUID animID) | 116 | /// <summary> |
117 | /// Remove the specified animation | ||
118 | /// </summary> | ||
119 | /// <param name='animID'></param> | ||
120 | /// <param name='allowNoDefault'> | ||
121 | /// If true, then the default animation can be entirely removed. | ||
122 | /// If false, then removing the default animation will reset it to the simulator default (currently STAND). | ||
123 | /// </param> | ||
124 | public void RemoveAnimation(UUID animID, bool allowNoDefault) | ||
112 | { | 125 | { |
113 | if (m_scenePresence.IsChildAgent) | 126 | if (m_scenePresence.IsChildAgent) |
114 | return; | 127 | return; |
115 | 128 | ||
116 | if (m_animations.Remove(animID)) | 129 | if (m_scenePresence.Scene.DebugAnimations) |
130 | m_log.DebugFormat( | ||
131 | "[SCENE PRESENCE ANIMATOR]: Removing animation {0} {1} for {2}", | ||
132 | GetAnimName(animID), animID, m_scenePresence.Name); | ||
133 | |||
134 | if (m_animations.Remove(animID, allowNoDefault)) | ||
117 | SendAnimPack(); | 135 | SendAnimPack(); |
118 | } | 136 | } |
119 | 137 | ||
@@ -127,7 +145,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation | |||
127 | if (addRemove) | 145 | if (addRemove) |
128 | m_animations.Add(animID, m_scenePresence.ControllingClient.NextAnimationSequenceNumber, UUID.Zero); | 146 | m_animations.Add(animID, m_scenePresence.ControllingClient.NextAnimationSequenceNumber, UUID.Zero); |
129 | else | 147 | else |
130 | m_animations.Remove(animID); | 148 | m_animations.Remove(animID, true); |
131 | } | 149 | } |
132 | if(sendPack) | 150 | if(sendPack) |
133 | SendAnimPack(); | 151 | SendAnimPack(); |
@@ -145,14 +163,15 @@ namespace OpenSim.Region.Framework.Scenes.Animation | |||
145 | if (animID == UUID.Zero) | 163 | if (animID == UUID.Zero) |
146 | return; | 164 | return; |
147 | 165 | ||
148 | RemoveAnimation(animID); | 166 | RemoveAnimation(animID, true); |
149 | } | 167 | } |
150 | 168 | ||
151 | public void ResetAnimations() | 169 | public void ResetAnimations() |
152 | { | 170 | { |
153 | // m_log.DebugFormat( | 171 | if (m_scenePresence.Scene.DebugAnimations) |
154 | // "[SCENE PRESENCE ANIMATOR]: Resetting animations for {0} in {1}", | 172 | m_log.DebugFormat( |
155 | // m_scenePresence.Name, m_scenePresence.Scene.RegionInfo.RegionName); | 173 | "[SCENE PRESENCE ANIMATOR]: Resetting animations for {0} in {1}", |
174 | m_scenePresence.Name, m_scenePresence.Scene.RegionInfo.RegionName); | ||
156 | 175 | ||
157 | m_animations.Clear(); | 176 | m_animations.Clear(); |
158 | } | 177 | } |
@@ -519,6 +538,12 @@ namespace OpenSim.Region.Framework.Scenes.Animation | |||
519 | if (m_scenePresence.IsChildAgent) | 538 | if (m_scenePresence.IsChildAgent) |
520 | return; | 539 | return; |
521 | 540 | ||
541 | // m_log.DebugFormat( | ||
542 | // "[SCENE PRESENCE ANIMATOR]: Sending anim pack with animations '{0}', sequence '{1}', uuids '{2}'", | ||
543 | // string.Join(",", Array.ConvertAll<UUID, string>(animations, a => a.ToString())), | ||
544 | // string.Join(",", Array.ConvertAll<int, string>(seqs, s => s.ToString())), | ||
545 | // string.Join(",", Array.ConvertAll<UUID, string>(objectIDs, o => o.ToString()))); | ||
546 | |||
522 | m_scenePresence.Scene.ForEachClient( | 547 | m_scenePresence.Scene.ForEachClient( |
523 | delegate(IClientAPI client) | 548 | delegate(IClientAPI client) |
524 | { | 549 | { |
@@ -557,5 +582,21 @@ namespace OpenSim.Region.Framework.Scenes.Animation | |||
557 | 582 | ||
558 | SendAnimPack(animIDs, sequenceNums, objectIDs); | 583 | SendAnimPack(animIDs, sequenceNums, objectIDs); |
559 | } | 584 | } |
585 | |||
586 | public string GetAnimName(UUID animId) | ||
587 | { | ||
588 | string animName; | ||
589 | |||
590 | if (!DefaultAvatarAnimations.AnimsNames.TryGetValue(animId, out animName)) | ||
591 | { | ||
592 | AssetMetadata amd = m_scenePresence.Scene.AssetService.GetMetadata(animId.ToString()); | ||
593 | if (amd != null) | ||
594 | animName = amd.Name; | ||
595 | else | ||
596 | animName = "Unknown"; | ||
597 | } | ||
598 | |||
599 | return animName; | ||
600 | } | ||
560 | } | 601 | } |
561 | } | 602 | } |
diff --git a/OpenSim/Region/Framework/Scenes/Border.cs b/OpenSim/Region/Framework/Scenes/Border.cs index c6a6511..08c0c31 100644 --- a/OpenSim/Region/Framework/Scenes/Border.cs +++ b/OpenSim/Region/Framework/Scenes/Border.cs | |||
@@ -33,8 +33,7 @@ using OpenMetaverse; | |||
33 | namespace OpenSim.Region.Framework.Scenes | 33 | namespace OpenSim.Region.Framework.Scenes |
34 | { | 34 | { |
35 | public class Border | 35 | public class Border |
36 | { | 36 | { |
37 | |||
38 | /// <summary> | 37 | /// <summary> |
39 | /// Line perpendicular to the Direction Cardinal. Z value is the | 38 | /// Line perpendicular to the Direction Cardinal. Z value is the |
40 | /// </summary> | 39 | /// </summary> |
@@ -81,6 +80,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
81 | TriggerRegionY = triggerRegionY; | 80 | TriggerRegionY = triggerRegionY; |
82 | } | 81 | } |
83 | 82 | ||
83 | /// <summary> | ||
84 | /// Tests to see if the given position would cross this border. | ||
85 | /// </summary> | ||
86 | /// <returns></returns> | ||
84 | public bool TestCross(Vector3 position) | 87 | public bool TestCross(Vector3 position) |
85 | { | 88 | { |
86 | bool result = false; | 89 | bool result = false; |
diff --git a/OpenSim/Region/Framework/Scenes/EntityManager.cs b/OpenSim/Region/Framework/Scenes/EntityManager.cs index b788a3c..7181313 100644 --- a/OpenSim/Region/Framework/Scenes/EntityManager.cs +++ b/OpenSim/Region/Framework/Scenes/EntityManager.cs | |||
@@ -31,6 +31,7 @@ using System.Collections.Generic; | |||
31 | using System.Reflection; | 31 | using System.Reflection; |
32 | using log4net; | 32 | using log4net; |
33 | using OpenMetaverse; | 33 | using OpenMetaverse; |
34 | using OpenSim.Framework; | ||
34 | 35 | ||
35 | namespace OpenSim.Region.Framework.Scenes | 36 | namespace OpenSim.Region.Framework.Scenes |
36 | { | 37 | { |
@@ -38,7 +39,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
38 | { | 39 | { |
39 | // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 40 | // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
40 | 41 | ||
41 | private readonly DoubleDictionary<UUID, uint, EntityBase> m_entities = new DoubleDictionary<UUID, uint, EntityBase>(); | 42 | private readonly DoubleDictionaryThreadAbortSafe<UUID, uint, EntityBase> m_entities |
43 | = new DoubleDictionaryThreadAbortSafe<UUID, uint, EntityBase>(); | ||
42 | 44 | ||
43 | public int Count | 45 | public int Count |
44 | { | 46 | { |
diff --git a/OpenSim/Region/Framework/Scenes/EventManager.cs b/OpenSim/Region/Framework/Scenes/EventManager.cs index 5b1c9f4..4733547 100644 --- a/OpenSim/Region/Framework/Scenes/EventManager.cs +++ b/OpenSim/Region/Framework/Scenes/EventManager.cs | |||
@@ -550,6 +550,20 @@ namespace OpenSim.Region.Framework.Scenes | |||
550 | /// </remarks> | 550 | /// </remarks> |
551 | public event ScriptControlEvent OnScriptControlEvent; | 551 | public event ScriptControlEvent OnScriptControlEvent; |
552 | 552 | ||
553 | public delegate void ScriptMovingStartEvent(uint localID); | ||
554 | |||
555 | /// <summary> | ||
556 | /// TODO: Should be triggered when a physics object starts moving. | ||
557 | /// </summary> | ||
558 | public event ScriptMovingStartEvent OnScriptMovingStartEvent; | ||
559 | |||
560 | public delegate void ScriptMovingEndEvent(uint localID); | ||
561 | |||
562 | /// <summary> | ||
563 | /// TODO: Should be triggered when a physics object stops moving. | ||
564 | /// </summary> | ||
565 | public event ScriptMovingEndEvent OnScriptMovingEndEvent; | ||
566 | |||
553 | public delegate void ScriptAtTargetEvent(uint localID, uint handle, Vector3 targetpos, Vector3 atpos); | 567 | public delegate void ScriptAtTargetEvent(uint localID, uint handle, Vector3 targetpos, Vector3 atpos); |
554 | 568 | ||
555 | /// <summary> | 569 | /// <summary> |
@@ -755,7 +769,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
755 | public event ScriptTimerEvent OnScriptTimerEvent; | 769 | public event ScriptTimerEvent OnScriptTimerEvent; |
756 | */ | 770 | */ |
757 | 771 | ||
758 | public delegate void EstateToolsSunUpdate(ulong regionHandle, bool FixedTime, bool EstateSun, float LindenHour); | 772 | public delegate void EstateToolsSunUpdate(ulong regionHandle); |
759 | public delegate void GetScriptRunning(IClientAPI controllingClient, UUID objectID, UUID itemID); | 773 | public delegate void GetScriptRunning(IClientAPI controllingClient, UUID objectID, UUID itemID); |
760 | 774 | ||
761 | public event EstateToolsSunUpdate OnEstateToolsSunUpdate; | 775 | public event EstateToolsSunUpdate OnEstateToolsSunUpdate; |
@@ -778,6 +792,19 @@ namespace OpenSim.Region.Framework.Scenes | |||
778 | public delegate void ObjectBeingRemovedFromScene(SceneObjectGroup obj); | 792 | public delegate void ObjectBeingRemovedFromScene(SceneObjectGroup obj); |
779 | 793 | ||
780 | /// <summary> | 794 | /// <summary> |
795 | /// Triggered when an object is placed into the physical scene (PhysicsActor created). | ||
796 | /// </summary> | ||
797 | public event Action<SceneObjectPart> OnObjectAddedToPhysicalScene; | ||
798 | /// <summary> | ||
799 | /// Triggered when an object is removed from the physical scene (PhysicsActor destroyed). | ||
800 | /// </summary> | ||
801 | /// <remarks> | ||
802 | /// Note: this is triggered just before the PhysicsActor is removed from the | ||
803 | /// physics engine so the receiver can do any necessary cleanup before its destruction. | ||
804 | /// </remarks> | ||
805 | public event Action<SceneObjectPart> OnObjectRemovedFromPhysicalScene; | ||
806 | |||
807 | /// <summary> | ||
781 | /// Triggered when an object is removed from the scene. | 808 | /// Triggered when an object is removed from the scene. |
782 | /// </summary> | 809 | /// </summary> |
783 | /// <remarks> | 810 | /// <remarks> |
@@ -1527,6 +1554,48 @@ namespace OpenSim.Region.Framework.Scenes | |||
1527 | } | 1554 | } |
1528 | } | 1555 | } |
1529 | 1556 | ||
1557 | public void TriggerObjectAddedToPhysicalScene(SceneObjectPart obj) | ||
1558 | { | ||
1559 | Action<SceneObjectPart> handler = OnObjectAddedToPhysicalScene; | ||
1560 | if (handler != null) | ||
1561 | { | ||
1562 | foreach (Action<SceneObjectPart> d in handler.GetInvocationList()) | ||
1563 | { | ||
1564 | try | ||
1565 | { | ||
1566 | d(obj); | ||
1567 | } | ||
1568 | catch (Exception e) | ||
1569 | { | ||
1570 | m_log.ErrorFormat( | ||
1571 | "[EVENT MANAGER]: Delegate for TriggerObjectAddedToPhysicalScene failed - continuing. {0} {1}", | ||
1572 | e.Message, e.StackTrace); | ||
1573 | } | ||
1574 | } | ||
1575 | } | ||
1576 | } | ||
1577 | |||
1578 | public void TriggerObjectRemovedFromPhysicalScene(SceneObjectPart obj) | ||
1579 | { | ||
1580 | Action<SceneObjectPart> handler = OnObjectRemovedFromPhysicalScene; | ||
1581 | if (handler != null) | ||
1582 | { | ||
1583 | foreach (Action<SceneObjectPart> d in handler.GetInvocationList()) | ||
1584 | { | ||
1585 | try | ||
1586 | { | ||
1587 | d(obj); | ||
1588 | } | ||
1589 | catch (Exception e) | ||
1590 | { | ||
1591 | m_log.ErrorFormat( | ||
1592 | "[EVENT MANAGER]: Delegate for TriggerObjectRemovedFromPhysicalScene failed - continuing. {0} {1}", | ||
1593 | e.Message, e.StackTrace); | ||
1594 | } | ||
1595 | } | ||
1596 | } | ||
1597 | } | ||
1598 | |||
1530 | public void TriggerShutdown() | 1599 | public void TriggerShutdown() |
1531 | { | 1600 | { |
1532 | Action handlerShutdown = OnShutdown; | 1601 | Action handlerShutdown = OnShutdown; |
@@ -2238,6 +2307,48 @@ namespace OpenSim.Region.Framework.Scenes | |||
2238 | } | 2307 | } |
2239 | } | 2308 | } |
2240 | 2309 | ||
2310 | public void TriggerMovingStartEvent(uint localID) | ||
2311 | { | ||
2312 | ScriptMovingStartEvent handlerScriptMovingStartEvent = OnScriptMovingStartEvent; | ||
2313 | if (handlerScriptMovingStartEvent != null) | ||
2314 | { | ||
2315 | foreach (ScriptMovingStartEvent d in handlerScriptMovingStartEvent.GetInvocationList()) | ||
2316 | { | ||
2317 | try | ||
2318 | { | ||
2319 | d(localID); | ||
2320 | } | ||
2321 | catch (Exception e) | ||
2322 | { | ||
2323 | m_log.ErrorFormat( | ||
2324 | "[EVENT MANAGER]: Delegate for TriggerMovingStartEvent failed - continuing. {0} {1}", | ||
2325 | e.Message, e.StackTrace); | ||
2326 | } | ||
2327 | } | ||
2328 | } | ||
2329 | } | ||
2330 | |||
2331 | public void TriggerMovingEndEvent(uint localID) | ||
2332 | { | ||
2333 | ScriptMovingEndEvent handlerScriptMovingEndEvent = OnScriptMovingEndEvent; | ||
2334 | if (handlerScriptMovingEndEvent != null) | ||
2335 | { | ||
2336 | foreach (ScriptMovingEndEvent d in handlerScriptMovingEndEvent.GetInvocationList()) | ||
2337 | { | ||
2338 | try | ||
2339 | { | ||
2340 | d(localID); | ||
2341 | } | ||
2342 | catch (Exception e) | ||
2343 | { | ||
2344 | m_log.ErrorFormat( | ||
2345 | "[EVENT MANAGER]: Delegate for TriggerMovingEndEvent failed - continuing. {0} {1}", | ||
2346 | e.Message, e.StackTrace); | ||
2347 | } | ||
2348 | } | ||
2349 | } | ||
2350 | } | ||
2351 | |||
2241 | public void TriggerRequestChangeWaterHeight(float height) | 2352 | public void TriggerRequestChangeWaterHeight(float height) |
2242 | { | 2353 | { |
2243 | if (height < 0) | 2354 | if (height < 0) |
@@ -2536,13 +2647,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
2536 | } | 2647 | } |
2537 | 2648 | ||
2538 | /// <summary> | 2649 | /// <summary> |
2539 | /// Updates the system as to how the position of the sun should be handled. | 2650 | /// Called when the sun's position parameters have changed in the Region and/or Estate |
2540 | /// </summary> | 2651 | /// </summary> |
2541 | /// <param name="regionHandle"></param> | 2652 | /// <param name="regionHandle">The region that changed</param> |
2542 | /// <param name="FixedTime">True if the Sun Position is fixed</param> | 2653 | public void TriggerEstateToolsSunUpdate(ulong regionHandle) |
2543 | /// <param name="useEstateTime">True if the Estate Settings should be used instead of region</param> | ||
2544 | /// <param name="FixedSunHour">The hour 0.0 <= FixedSunHour <= 24.0 at which the sun is fixed at. Sun Hour 0 is sun-rise, when Day/Night ratio is 1:1</param> | ||
2545 | public void TriggerEstateToolsSunUpdate(ulong regionHandle, bool FixedTime, bool useEstateTime, float FixedSunHour) | ||
2546 | { | 2654 | { |
2547 | EstateToolsSunUpdate handlerEstateToolsSunUpdate = OnEstateToolsSunUpdate; | 2655 | EstateToolsSunUpdate handlerEstateToolsSunUpdate = OnEstateToolsSunUpdate; |
2548 | if (handlerEstateToolsSunUpdate != null) | 2656 | if (handlerEstateToolsSunUpdate != null) |
@@ -2551,7 +2659,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2551 | { | 2659 | { |
2552 | try | 2660 | try |
2553 | { | 2661 | { |
2554 | d(regionHandle, FixedTime, useEstateTime, FixedSunHour); | 2662 | d(regionHandle); |
2555 | } | 2663 | } |
2556 | catch (Exception e) | 2664 | catch (Exception e) |
2557 | { | 2665 | { |
diff --git a/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs b/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs index 5cfba39..b102e48 100644 --- a/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs +++ b/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs | |||
@@ -22,6 +22,115 @@ using log4net; | |||
22 | 22 | ||
23 | namespace OpenSim.Region.Framework.Scenes | 23 | namespace OpenSim.Region.Framework.Scenes |
24 | { | 24 | { |
25 | public class KeyframeTimer | ||
26 | { | ||
27 | private static Dictionary<Scene, KeyframeTimer>m_timers = | ||
28 | new Dictionary<Scene, KeyframeTimer>(); | ||
29 | |||
30 | private Timer m_timer; | ||
31 | private Dictionary<KeyframeMotion, object> m_motions = new Dictionary<KeyframeMotion, object>(); | ||
32 | private object m_lockObject = new object(); | ||
33 | private object m_timerLock = new object(); | ||
34 | private const double m_tickDuration = 50.0; | ||
35 | private Scene m_scene; | ||
36 | |||
37 | public double TickDuration | ||
38 | { | ||
39 | get { return m_tickDuration; } | ||
40 | } | ||
41 | |||
42 | public KeyframeTimer(Scene scene) | ||
43 | { | ||
44 | m_timer = new Timer(); | ||
45 | m_timer.Interval = TickDuration; | ||
46 | m_timer.AutoReset = true; | ||
47 | m_timer.Elapsed += OnTimer; | ||
48 | |||
49 | m_scene = scene; | ||
50 | |||
51 | m_timer.Start(); | ||
52 | } | ||
53 | |||
54 | private void OnTimer(object sender, ElapsedEventArgs ea) | ||
55 | { | ||
56 | if (!Monitor.TryEnter(m_timerLock)) | ||
57 | return; | ||
58 | |||
59 | try | ||
60 | { | ||
61 | List<KeyframeMotion> motions; | ||
62 | |||
63 | lock (m_lockObject) | ||
64 | { | ||
65 | motions = new List<KeyframeMotion>(m_motions.Keys); | ||
66 | } | ||
67 | |||
68 | foreach (KeyframeMotion m in motions) | ||
69 | { | ||
70 | try | ||
71 | { | ||
72 | m.OnTimer(TickDuration); | ||
73 | } | ||
74 | catch (Exception inner) | ||
75 | { | ||
76 | // Don't stop processing | ||
77 | } | ||
78 | } | ||
79 | } | ||
80 | catch (Exception e) | ||
81 | { | ||
82 | // Keep running no matter what | ||
83 | } | ||
84 | finally | ||
85 | { | ||
86 | Monitor.Exit(m_timerLock); | ||
87 | } | ||
88 | } | ||
89 | |||
90 | public static void Add(KeyframeMotion motion) | ||
91 | { | ||
92 | KeyframeTimer timer; | ||
93 | |||
94 | if (motion.Scene == null) | ||
95 | return; | ||
96 | |||
97 | lock (m_timers) | ||
98 | { | ||
99 | if (!m_timers.TryGetValue(motion.Scene, out timer)) | ||
100 | { | ||
101 | timer = new KeyframeTimer(motion.Scene); | ||
102 | m_timers[motion.Scene] = timer; | ||
103 | } | ||
104 | } | ||
105 | |||
106 | lock (timer.m_lockObject) | ||
107 | { | ||
108 | timer.m_motions[motion] = null; | ||
109 | } | ||
110 | } | ||
111 | |||
112 | public static void Remove(KeyframeMotion motion) | ||
113 | { | ||
114 | KeyframeTimer timer; | ||
115 | |||
116 | if (motion.Scene == null) | ||
117 | return; | ||
118 | |||
119 | lock (m_timers) | ||
120 | { | ||
121 | if (!m_timers.TryGetValue(motion.Scene, out timer)) | ||
122 | { | ||
123 | return; | ||
124 | } | ||
125 | } | ||
126 | |||
127 | lock (timer.m_lockObject) | ||
128 | { | ||
129 | timer.m_motions.Remove(motion); | ||
130 | } | ||
131 | } | ||
132 | } | ||
133 | |||
25 | [Serializable] | 134 | [Serializable] |
26 | public class KeyframeMotion | 135 | public class KeyframeMotion |
27 | { | 136 | { |
@@ -63,18 +172,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
63 | 172 | ||
64 | private Keyframe[] m_keyframes; | 173 | private Keyframe[] m_keyframes; |
65 | 174 | ||
66 | [NonSerialized()] | ||
67 | protected Timer m_timer = null; | ||
68 | |||
69 | // timer lock | ||
70 | [NonSerialized()] | ||
71 | private object m_onTimerLock; | ||
72 | |||
73 | // timer overrun detect | ||
74 | // prevents overlap or timer events threads frozen on the lock | ||
75 | [NonSerialized()] | ||
76 | private bool m_inOnTimer; | ||
77 | |||
78 | // skip timer events. | 175 | // skip timer events. |
79 | //timer.stop doesn't assure there aren't event threads still being fired | 176 | //timer.stop doesn't assure there aren't event threads still being fired |
80 | [NonSerialized()] | 177 | [NonSerialized()] |
@@ -97,12 +194,21 @@ namespace OpenSim.Region.Framework.Scenes | |||
97 | private DataFormat m_data = DataFormat.Translation | DataFormat.Rotation; | 194 | private DataFormat m_data = DataFormat.Translation | DataFormat.Rotation; |
98 | 195 | ||
99 | private bool m_running = false; | 196 | private bool m_running = false; |
197 | |||
100 | [NonSerialized()] | 198 | [NonSerialized()] |
101 | private bool m_selected = false; | 199 | private bool m_selected = false; |
102 | 200 | ||
103 | private int m_iterations = 0; | 201 | private int m_iterations = 0; |
104 | 202 | ||
105 | private const double timerInterval = 50.0; | 203 | private int m_skipLoops = 0; |
204 | |||
205 | [NonSerialized()] | ||
206 | private Scene m_scene; | ||
207 | |||
208 | public Scene Scene | ||
209 | { | ||
210 | get { return m_scene; } | ||
211 | } | ||
106 | 212 | ||
107 | public DataFormat Data | 213 | public DataFormat Data |
108 | { | 214 | { |
@@ -139,31 +245,16 @@ namespace OpenSim.Region.Framework.Scenes | |||
139 | 245 | ||
140 | private void StartTimer() | 246 | private void StartTimer() |
141 | { | 247 | { |
142 | if (m_timer == null) | 248 | KeyframeTimer.Add(this); |
143 | return; | ||
144 | m_timerStopped = false; | 249 | m_timerStopped = false; |
145 | m_timer.Start(); | ||
146 | } | 250 | } |
147 | 251 | ||
148 | private void StopTimer() | 252 | private void StopTimer() |
149 | { | 253 | { |
150 | if (m_timer == null || m_timerStopped) | ||
151 | return; | ||
152 | m_timerStopped = true; | ||
153 | m_timer.Stop(); | ||
154 | } | ||
155 | |||
156 | private void RemoveTimer() | ||
157 | { | ||
158 | if (m_timer == null) | ||
159 | return; | ||
160 | m_timerStopped = true; | 254 | m_timerStopped = true; |
161 | m_timer.Stop(); | 255 | KeyframeTimer.Remove(this); |
162 | m_timer.Elapsed -= OnTimer; | ||
163 | m_timer = null; | ||
164 | } | 256 | } |
165 | 257 | ||
166 | |||
167 | public static KeyframeMotion FromData(SceneObjectGroup grp, Byte[] data) | 258 | public static KeyframeMotion FromData(SceneObjectGroup grp, Byte[] data) |
168 | { | 259 | { |
169 | KeyframeMotion newMotion = null; | 260 | KeyframeMotion newMotion = null; |
@@ -177,12 +268,15 @@ namespace OpenSim.Region.Framework.Scenes | |||
177 | 268 | ||
178 | newMotion.m_group = grp; | 269 | newMotion.m_group = grp; |
179 | 270 | ||
180 | if (grp != null && grp.IsSelected) | 271 | if (grp != null) |
181 | newMotion.m_selected = true; | 272 | { |
273 | newMotion.m_scene = grp.Scene; | ||
274 | if (grp.IsSelected) | ||
275 | newMotion.m_selected = true; | ||
276 | } | ||
182 | 277 | ||
183 | newMotion.m_onTimerLock = new object(); | ||
184 | newMotion.m_timerStopped = false; | 278 | newMotion.m_timerStopped = false; |
185 | newMotion.m_inOnTimer = false; | 279 | newMotion.m_running = true; |
186 | newMotion.m_isCrossing = false; | 280 | newMotion.m_isCrossing = false; |
187 | newMotion.m_waitingCrossing = false; | 281 | newMotion.m_waitingCrossing = false; |
188 | } | 282 | } |
@@ -196,37 +290,36 @@ namespace OpenSim.Region.Framework.Scenes | |||
196 | 290 | ||
197 | public void UpdateSceneObject(SceneObjectGroup grp) | 291 | public void UpdateSceneObject(SceneObjectGroup grp) |
198 | { | 292 | { |
199 | // lock (m_onTimerLock) | 293 | m_isCrossing = false; |
200 | { | 294 | m_waitingCrossing = false; |
201 | m_isCrossing = false; | 295 | StopTimer(); |
202 | m_waitingCrossing = false; | ||
203 | StopTimer(); | ||
204 | 296 | ||
205 | if (grp == null) | 297 | if (grp == null) |
206 | return; | 298 | return; |
207 | 299 | ||
208 | m_group = grp; | 300 | m_group = grp; |
209 | Vector3 grppos = grp.AbsolutePosition; | 301 | m_scene = grp.Scene; |
210 | Vector3 offset = grppos - m_serializedPosition; | ||
211 | // avoid doing it more than once | ||
212 | // current this will happen draging a prim to other region | ||
213 | m_serializedPosition = grppos; | ||
214 | 302 | ||
215 | m_basePosition += offset; | 303 | Vector3 grppos = grp.AbsolutePosition; |
216 | m_currentFrame.Position += offset; | 304 | Vector3 offset = grppos - m_serializedPosition; |
305 | // avoid doing it more than once | ||
306 | // current this will happen draging a prim to other region | ||
307 | m_serializedPosition = grppos; | ||
217 | 308 | ||
218 | m_nextPosition += offset; | 309 | m_basePosition += offset; |
310 | m_currentFrame.Position += offset; | ||
219 | 311 | ||
220 | for (int i = 0; i < m_frames.Count; i++) | 312 | m_nextPosition += offset; |
221 | { | ||
222 | Keyframe k = m_frames[i]; | ||
223 | k.Position += offset; | ||
224 | m_frames[i]=k; | ||
225 | } | ||
226 | 313 | ||
227 | if (m_running) | 314 | for (int i = 0; i < m_frames.Count; i++) |
228 | Start(); | 315 | { |
316 | Keyframe k = m_frames[i]; | ||
317 | k.Position += offset; | ||
318 | m_frames[i]=k; | ||
229 | } | 319 | } |
320 | |||
321 | if (m_running) | ||
322 | Start(); | ||
230 | } | 323 | } |
231 | 324 | ||
232 | public KeyframeMotion(SceneObjectGroup grp, PlayMode mode, DataFormat data) | 325 | public KeyframeMotion(SceneObjectGroup grp, PlayMode mode, DataFormat data) |
@@ -239,11 +332,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
239 | { | 332 | { |
240 | m_basePosition = grp.AbsolutePosition; | 333 | m_basePosition = grp.AbsolutePosition; |
241 | m_baseRotation = grp.GroupRotation; | 334 | m_baseRotation = grp.GroupRotation; |
335 | m_scene = grp.Scene; | ||
242 | } | 336 | } |
243 | 337 | ||
244 | m_onTimerLock = new object(); | ||
245 | m_timerStopped = true; | 338 | m_timerStopped = true; |
246 | m_inOnTimer = false; | ||
247 | m_isCrossing = false; | 339 | m_isCrossing = false; |
248 | m_waitingCrossing = false; | 340 | m_waitingCrossing = false; |
249 | } | 341 | } |
@@ -260,6 +352,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
260 | KeyframeMotion newmotion = new KeyframeMotion(null, m_mode, m_data); | 352 | KeyframeMotion newmotion = new KeyframeMotion(null, m_mode, m_data); |
261 | 353 | ||
262 | newmotion.m_group = newgrp; | 354 | newmotion.m_group = newgrp; |
355 | newmotion.m_scene = newgrp.Scene; | ||
263 | 356 | ||
264 | if (m_keyframes != null) | 357 | if (m_keyframes != null) |
265 | { | 358 | { |
@@ -296,7 +389,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
296 | public void Delete() | 389 | public void Delete() |
297 | { | 390 | { |
298 | m_running = false; | 391 | m_running = false; |
299 | RemoveTimer(); | 392 | StopTimer(); |
300 | m_isCrossing = false; | 393 | m_isCrossing = false; |
301 | m_waitingCrossing = false; | 394 | m_waitingCrossing = false; |
302 | m_frames.Clear(); | 395 | m_frames.Clear(); |
@@ -309,27 +402,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
309 | m_waitingCrossing = false; | 402 | m_waitingCrossing = false; |
310 | if (m_keyframes != null && m_group != null && m_keyframes.Length > 0) | 403 | if (m_keyframes != null && m_group != null && m_keyframes.Length > 0) |
311 | { | 404 | { |
312 | if (m_timer == null) | ||
313 | { | ||
314 | m_timer = new Timer(); | ||
315 | m_timer.Interval = timerInterval; | ||
316 | m_timer.AutoReset = true; | ||
317 | m_timer.Elapsed += OnTimer; | ||
318 | } | ||
319 | else | ||
320 | { | ||
321 | StopTimer(); | ||
322 | m_timer.Interval = timerInterval; | ||
323 | } | ||
324 | |||
325 | m_inOnTimer = false; | ||
326 | StartTimer(); | 405 | StartTimer(); |
327 | m_running = true; | 406 | m_running = true; |
328 | } | 407 | } |
329 | else | 408 | else |
330 | { | 409 | { |
331 | m_running = false; | 410 | m_running = false; |
332 | RemoveTimer(); | 411 | StopTimer(); |
333 | } | 412 | } |
334 | } | 413 | } |
335 | 414 | ||
@@ -339,7 +418,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
339 | m_isCrossing = false; | 418 | m_isCrossing = false; |
340 | m_waitingCrossing = false; | 419 | m_waitingCrossing = false; |
341 | 420 | ||
342 | RemoveTimer(); | 421 | StopTimer(); |
343 | 422 | ||
344 | m_basePosition = m_group.AbsolutePosition; | 423 | m_basePosition = m_group.AbsolutePosition; |
345 | m_baseRotation = m_group.GroupRotation; | 424 | m_baseRotation = m_group.GroupRotation; |
@@ -354,7 +433,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
354 | public void Pause() | 433 | public void Pause() |
355 | { | 434 | { |
356 | m_running = false; | 435 | m_running = false; |
357 | RemoveTimer(); | 436 | StopTimer(); |
358 | 437 | ||
359 | m_group.RootPart.Velocity = Vector3.Zero; | 438 | m_group.RootPart.Velocity = Vector3.Zero; |
360 | m_group.RootPart.AngularVelocity = Vector3.Zero; | 439 | m_group.RootPart.AngularVelocity = Vector3.Zero; |
@@ -377,15 +456,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
377 | 456 | ||
378 | int start = 0; | 457 | int start = 0; |
379 | int end = m_keyframes.Length; | 458 | int end = m_keyframes.Length; |
380 | // if (m_mode == PlayMode.PingPong && m_keyframes.Length > 1) | ||
381 | // end = m_keyframes.Length - 1; | ||
382 | 459 | ||
383 | if (direction < 0) | 460 | if (direction < 0) |
384 | { | 461 | { |
385 | start = m_keyframes.Length - 1; | 462 | start = m_keyframes.Length - 1; |
386 | end = -1; | 463 | end = -1; |
387 | // if (m_mode == PlayMode.PingPong && m_keyframes.Length > 1) | ||
388 | // end = 0; | ||
389 | } | 464 | } |
390 | 465 | ||
391 | for (int i = start; i != end ; i += direction) | 466 | for (int i = start; i != end ; i += direction) |
@@ -463,189 +538,172 @@ namespace OpenSim.Region.Framework.Scenes | |||
463 | } | 538 | } |
464 | } | 539 | } |
465 | 540 | ||
466 | protected void OnTimer(object sender, ElapsedEventArgs e) | 541 | public void OnTimer(double tickDuration) |
467 | { | 542 | { |
468 | if (m_timerStopped) // trap events still in air even after a timer.stop | 543 | if (m_skipLoops > 0) |
469 | return; | ||
470 | |||
471 | if (m_inOnTimer) // don't let overruns to happen | ||
472 | { | 544 | { |
473 | m_log.Warn("[KeyFrame]: timer overrun"); | 545 | m_skipLoops--; |
474 | return; | 546 | return; |
475 | } | 547 | } |
476 | 548 | ||
549 | if (m_timerStopped) // trap events still in air even after a timer.stop | ||
550 | return; | ||
551 | |||
477 | if (m_group == null) | 552 | if (m_group == null) |
478 | return; | 553 | return; |
479 | 554 | ||
480 | lock (m_onTimerLock) | 555 | bool update = false; |
481 | { | ||
482 | 556 | ||
483 | m_inOnTimer = true; | 557 | if (m_selected) |
558 | { | ||
559 | if (m_group.RootPart.Velocity != Vector3.Zero) | ||
560 | { | ||
561 | m_group.RootPart.Velocity = Vector3.Zero; | ||
562 | m_group.SendGroupRootTerseUpdate(); | ||
484 | 563 | ||
485 | bool update = false; | 564 | } |
565 | return; | ||
566 | } | ||
486 | 567 | ||
487 | try | 568 | if (m_isCrossing) |
569 | { | ||
570 | // if crossing and timer running then cross failed | ||
571 | // wait some time then | ||
572 | // retry to set the position that evtually caused the outbound | ||
573 | // if still outside region this will call startCrossing below | ||
574 | m_isCrossing = false; | ||
575 | m_group.AbsolutePosition = m_nextPosition; | ||
576 | if (!m_isCrossing) | ||
488 | { | 577 | { |
489 | if (m_selected) | 578 | StopTimer(); |
490 | { | 579 | StartTimer(); |
491 | if (m_group.RootPart.Velocity != Vector3.Zero) | 580 | } |
492 | { | 581 | return; |
493 | m_group.RootPart.Velocity = Vector3.Zero; | 582 | } |
494 | m_group.SendGroupRootTerseUpdate(); | ||
495 | // m_group.RootPart.ScheduleTerseUpdate(); | ||
496 | 583 | ||
497 | } | 584 | if (m_frames.Count == 0) |
498 | m_inOnTimer = false; | 585 | { |
499 | return; | 586 | GetNextList(); |
500 | } | ||
501 | 587 | ||
502 | if (m_isCrossing) | 588 | if (m_frames.Count == 0) |
503 | { | 589 | { |
504 | // if crossing and timer running then cross failed | 590 | Stop(); |
505 | // wait some time then | 591 | Scene scene = m_group.Scene; |
506 | // retry to set the position that evtually caused the outbound | ||
507 | // if still outside region this will call startCrossing below | ||
508 | m_isCrossing = false; | ||
509 | m_group.AbsolutePosition = m_nextPosition; | ||
510 | if (!m_isCrossing) | ||
511 | { | ||
512 | StopTimer(); | ||
513 | m_timer.Interval = timerInterval; | ||
514 | StartTimer(); | ||
515 | } | ||
516 | m_inOnTimer = false; | ||
517 | return; | ||
518 | } | ||
519 | 592 | ||
520 | if (m_frames.Count == 0) | 593 | IScriptModule[] scriptModules = scene.RequestModuleInterfaces<IScriptModule>(); |
594 | foreach (IScriptModule m in scriptModules) | ||
521 | { | 595 | { |
522 | GetNextList(); | 596 | if (m == null) |
597 | continue; | ||
598 | m.PostObjectEvent(m_group.RootPart.UUID, "moving_end", new object[0]); | ||
599 | } | ||
523 | 600 | ||
524 | if (m_frames.Count == 0) | 601 | return; |
525 | { | 602 | } |
526 | Stop(); | ||
527 | m_inOnTimer = false; | ||
528 | return; | ||
529 | } | ||
530 | 603 | ||
531 | m_currentFrame = m_frames[0]; | 604 | m_currentFrame = m_frames[0]; |
532 | m_currentFrame.TimeMS += (int)timerInterval; | 605 | m_currentFrame.TimeMS += (int)tickDuration; |
533 | 606 | ||
534 | //force a update on a keyframe transition | 607 | //force a update on a keyframe transition |
535 | update = true; | 608 | update = true; |
536 | } | 609 | } |
537 | 610 | ||
538 | m_currentFrame.TimeMS -= (int)timerInterval; | 611 | m_currentFrame.TimeMS -= (int)tickDuration; |
539 | 612 | ||
540 | // Do the frame processing | 613 | // Do the frame processing |
541 | double steps = (double)m_currentFrame.TimeMS / timerInterval; | 614 | double steps = (double)m_currentFrame.TimeMS / tickDuration; |
542 | 615 | ||
543 | if (steps <= 0.0) | 616 | if (steps <= 0.0) |
544 | { | 617 | { |
545 | m_group.RootPart.Velocity = Vector3.Zero; | 618 | m_group.RootPart.Velocity = Vector3.Zero; |
546 | m_group.RootPart.AngularVelocity = Vector3.Zero; | 619 | m_group.RootPart.AngularVelocity = Vector3.Zero; |
547 | 620 | ||
548 | m_nextPosition = (Vector3)m_currentFrame.Position; | 621 | m_nextPosition = (Vector3)m_currentFrame.Position; |
549 | m_group.AbsolutePosition = m_nextPosition; | 622 | m_group.AbsolutePosition = m_nextPosition; |
550 | 623 | ||
551 | // we are sending imediate updates, no doing force a extra terseUpdate | 624 | // we are sending imediate updates, no doing force a extra terseUpdate |
552 | // m_group.UpdateGroupRotationR((Quaternion)m_currentFrame.Rotation); | 625 | // m_group.UpdateGroupRotationR((Quaternion)m_currentFrame.Rotation); |
553 | 626 | ||
554 | m_group.RootPart.RotationOffset = (Quaternion)m_currentFrame.Rotation; | 627 | m_group.RootPart.RotationOffset = (Quaternion)m_currentFrame.Rotation; |
555 | m_frames.RemoveAt(0); | 628 | m_frames.RemoveAt(0); |
556 | if (m_frames.Count > 0) | 629 | if (m_frames.Count > 0) |
557 | m_currentFrame = m_frames[0]; | 630 | m_currentFrame = m_frames[0]; |
558 | 631 | ||
559 | update = true; | 632 | update = true; |
560 | } | 633 | } |
561 | else | 634 | else |
562 | { | 635 | { |
563 | float complete = ((float)m_currentFrame.TimeTotal - (float)m_currentFrame.TimeMS) / (float)m_currentFrame.TimeTotal; | 636 | float complete = ((float)m_currentFrame.TimeTotal - (float)m_currentFrame.TimeMS) / (float)m_currentFrame.TimeTotal; |
564 | 637 | ||
565 | Vector3 v = (Vector3)m_currentFrame.Position - m_group.AbsolutePosition; | 638 | Vector3 v = (Vector3)m_currentFrame.Position - m_group.AbsolutePosition; |
566 | Vector3 motionThisFrame = v / (float)steps; | 639 | Vector3 motionThisFrame = v / (float)steps; |
567 | v = v * 1000 / m_currentFrame.TimeMS; | 640 | v = v * 1000 / m_currentFrame.TimeMS; |
568 | 641 | ||
569 | if (Vector3.Mag(motionThisFrame) >= 0.05f) | 642 | if (Vector3.Mag(motionThisFrame) >= 0.05f) |
570 | { | 643 | { |
571 | // m_group.AbsolutePosition += motionThisFrame; | 644 | // m_group.AbsolutePosition += motionThisFrame; |
572 | m_nextPosition = m_group.AbsolutePosition + motionThisFrame; | 645 | m_nextPosition = m_group.AbsolutePosition + motionThisFrame; |
573 | m_group.AbsolutePosition = m_nextPosition; | 646 | m_group.AbsolutePosition = m_nextPosition; |
574 | 647 | ||
575 | m_group.RootPart.Velocity = v; | 648 | m_group.RootPart.Velocity = v; |
576 | update = true; | 649 | update = true; |
577 | } | 650 | } |
578 | 651 | ||
579 | if ((Quaternion)m_currentFrame.Rotation != m_group.GroupRotation) | 652 | if ((Quaternion)m_currentFrame.Rotation != m_group.GroupRotation) |
580 | { | 653 | { |
581 | Quaternion current = m_group.GroupRotation; | 654 | Quaternion current = m_group.GroupRotation; |
582 | 655 | ||
583 | Quaternion step = Quaternion.Slerp(m_currentFrame.StartRotation, (Quaternion)m_currentFrame.Rotation, complete); | 656 | Quaternion step = Quaternion.Slerp(m_currentFrame.StartRotation, (Quaternion)m_currentFrame.Rotation, complete); |
584 | step.Normalize(); | 657 | step.Normalize(); |
585 | /* use simpler change detection | 658 | /* use simpler change detection |
586 | * float angle = 0; | 659 | * float angle = 0; |
587 | |||
588 | float aa = current.X * current.X + current.Y * current.Y + current.Z * current.Z + current.W * current.W; | ||
589 | float bb = step.X * step.X + step.Y * step.Y + step.Z * step.Z + step.W * step.W; | ||
590 | float aa_bb = aa * bb; | ||
591 | |||
592 | if (aa_bb == 0) | ||
593 | { | ||
594 | angle = 0; | ||
595 | } | ||
596 | else | ||
597 | { | ||
598 | float ab = current.X * step.X + | ||
599 | current.Y * step.Y + | ||
600 | current.Z * step.Z + | ||
601 | current.W * step.W; | ||
602 | float q = (ab * ab) / aa_bb; | ||
603 | |||
604 | if (q > 1.0f) | ||
605 | { | ||
606 | angle = 0; | ||
607 | } | ||
608 | else | ||
609 | { | ||
610 | angle = (float)Math.Acos(2 * q - 1); | ||
611 | } | ||
612 | } | ||
613 | |||
614 | if (angle > 0.01f) | ||
615 | */ | ||
616 | if(Math.Abs(step.X - current.X) > 0.001f | ||
617 | || Math.Abs(step.Y - current.Y) > 0.001f | ||
618 | || Math.Abs(step.Z - current.Z) > 0.001f) | ||
619 | // assuming w is a dependente var | ||
620 | 660 | ||
621 | { | 661 | float aa = current.X * current.X + current.Y * current.Y + current.Z * current.Z + current.W * current.W; |
622 | // m_group.UpdateGroupRotationR(step); | 662 | float bb = step.X * step.X + step.Y * step.Y + step.Z * step.Z + step.W * step.W; |
623 | m_group.RootPart.RotationOffset = step; | 663 | float aa_bb = aa * bb; |
624 | 664 | ||
625 | //m_group.RootPart.UpdateAngularVelocity(m_currentFrame.AngularVelocity / 2); | 665 | if (aa_bb == 0) |
626 | update = true; | 666 | { |
627 | } | 667 | angle = 0; |
668 | } | ||
669 | else | ||
670 | { | ||
671 | float ab = current.X * step.X + | ||
672 | current.Y * step.Y + | ||
673 | current.Z * step.Z + | ||
674 | current.W * step.W; | ||
675 | float q = (ab * ab) / aa_bb; | ||
676 | |||
677 | if (q > 1.0f) | ||
678 | { | ||
679 | angle = 0; | ||
680 | } | ||
681 | else | ||
682 | { | ||
683 | angle = (float)Math.Acos(2 * q - 1); | ||
628 | } | 684 | } |
629 | } | 685 | } |
630 | 686 | ||
631 | if (update) | 687 | if (angle > 0.01f) |
632 | m_group.SendGroupRootTerseUpdate(); | 688 | */ |
633 | // m_group.RootPart.ScheduleTerseUpdate(); | 689 | if(Math.Abs(step.X - current.X) > 0.001f |
690 | || Math.Abs(step.Y - current.Y) > 0.001f | ||
691 | || Math.Abs(step.Z - current.Z) > 0.001f) | ||
692 | // assuming w is a dependente var | ||
634 | 693 | ||
694 | { | ||
695 | // m_group.UpdateGroupRotationR(step); | ||
696 | m_group.RootPart.RotationOffset = step; | ||
635 | 697 | ||
698 | //m_group.RootPart.UpdateAngularVelocity(m_currentFrame.AngularVelocity / 2); | ||
699 | update = true; | ||
700 | } | ||
636 | } | 701 | } |
637 | catch ( Exception ex) | 702 | } |
638 | { | ||
639 | // still happening sometimes | ||
640 | // lets try to see where | ||
641 | m_log.Warn("[KeyFrame]: timer overrun" + ex.Message); | ||
642 | } | ||
643 | 703 | ||
644 | finally | 704 | if (update) |
645 | { | 705 | { |
646 | // make sure we do not let this frozen | 706 | m_group.SendGroupRootTerseUpdate(); |
647 | m_inOnTimer = false; | ||
648 | } | ||
649 | } | 707 | } |
650 | } | 708 | } |
651 | 709 | ||
@@ -677,7 +735,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
677 | m_isCrossing = true; | 735 | m_isCrossing = true; |
678 | m_waitingCrossing = true; | 736 | m_waitingCrossing = true; |
679 | 737 | ||
680 | // to remove / retune to smoth crossings | 738 | // to remove / retune to smoth crossings |
681 | if (m_group.RootPart.Velocity != Vector3.Zero) | 739 | if (m_group.RootPart.Velocity != Vector3.Zero) |
682 | { | 740 | { |
683 | m_group.RootPart.Velocity = Vector3.Zero; | 741 | m_group.RootPart.Velocity = Vector3.Zero; |
@@ -696,9 +754,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
696 | m_group.SendGroupRootTerseUpdate(); | 754 | m_group.SendGroupRootTerseUpdate(); |
697 | // m_group.RootPart.ScheduleTerseUpdate(); | 755 | // m_group.RootPart.ScheduleTerseUpdate(); |
698 | 756 | ||
699 | if (m_running && m_timer != null) | 757 | if (m_running) |
700 | { | 758 | { |
701 | m_timer.Interval = 60000; | 759 | StopTimer(); |
760 | m_skipLoops = 1200; // 60 seconds | ||
702 | StartTimer(); | 761 | StartTimer(); |
703 | } | 762 | } |
704 | } | 763 | } |
diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index c9d1205..d2e41f8 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs | |||
@@ -39,6 +39,7 @@ using OpenSim.Region.Framework; | |||
39 | using OpenSim.Framework.Client; | 39 | using OpenSim.Framework.Client; |
40 | using OpenSim.Region.Framework.Interfaces; | 40 | using OpenSim.Region.Framework.Interfaces; |
41 | using OpenSim.Region.Framework.Scenes.Serialization; | 41 | using OpenSim.Region.Framework.Scenes.Serialization; |
42 | using PermissionMask = OpenSim.Framework.PermissionMask; | ||
42 | 43 | ||
43 | namespace OpenSim.Region.Framework.Scenes | 44 | namespace OpenSim.Region.Framework.Scenes |
44 | { | 45 | { |
@@ -401,29 +402,68 @@ namespace OpenSim.Region.Framework.Scenes | |||
401 | if (item.Owner != remoteClient.AgentId) | 402 | if (item.Owner != remoteClient.AgentId) |
402 | return; | 403 | return; |
403 | 404 | ||
404 | if (UUID.Zero == transactionID) | 405 | item.Flags = (item.Flags & ~(uint)255) | (itemUpd.Flags & (uint)255); |
405 | { | 406 | item.Name = itemUpd.Name; |
406 | item.Flags = (item.Flags & ~(uint)255) | (itemUpd.Flags & (uint)255); | 407 | item.Description = itemUpd.Description; |
407 | item.Name = itemUpd.Name; | ||
408 | item.Description = itemUpd.Description; | ||
409 | 408 | ||
410 | // m_log.DebugFormat( | 409 | // m_log.DebugFormat( |
411 | // "[USER INVENTORY]: itemUpd {0} {1} {2} {3}, item {4} {5} {6} {7}", | 410 | // "[USER INVENTORY]: itemUpd {0} {1} {2} {3}, item {4} {5} {6} {7}", |
412 | // itemUpd.NextPermissions, itemUpd.GroupPermissions, itemUpd.EveryOnePermissions, item.Flags, | 411 | // itemUpd.NextPermissions, itemUpd.GroupPermissions, itemUpd.EveryOnePermissions, item.Flags, |
413 | // item.NextPermissions, item.GroupPermissions, item.EveryOnePermissions, item.CurrentPermissions); | 412 | // item.NextPermissions, item.GroupPermissions, item.EveryOnePermissions, item.CurrentPermissions); |
414 | 413 | ||
414 | if (itemUpd.NextPermissions != 0) // Use this to determine validity. Can never be 0 if valid | ||
415 | { | ||
416 | // Create a set of base permissions that will not include export if the user | ||
417 | // is not allowed to change the export flag. | ||
418 | bool denyExportChange = false; | ||
419 | |||
420 | m_log.InfoFormat("[XXX]: B: {0} O: {1} E: {2}", itemUpd.BasePermissions, itemUpd.CurrentPermissions, itemUpd.EveryOnePermissions); | ||
421 | |||
422 | // If the user is not the creator or doesn't have "E" in both "B" and "O", deny setting export | ||
423 | if ((item.BasePermissions & (uint)(PermissionMask.All | PermissionMask.Export)) != (uint)(PermissionMask.All | PermissionMask.Export) || (item.CurrentPermissions & (uint)PermissionMask.Export) == 0 || item.CreatorIdAsUuid != item.Owner) | ||
424 | denyExportChange = true; | ||
425 | |||
426 | m_log.InfoFormat("[XXX]: Deny Export Update {0}", denyExportChange); | ||
427 | |||
428 | // If it is already set, force it set and also force full perm | ||
429 | // else prevent setting it. It can and should never be set unless | ||
430 | // set in base, so the condition above is valid | ||
431 | if (denyExportChange) | ||
432 | { | ||
433 | // If we are not allowed to change it, then force it to the | ||
434 | // original item's setting and if it was on, also force full perm | ||
435 | if ((item.EveryOnePermissions & (uint)PermissionMask.Export) != 0) | ||
436 | { | ||
437 | itemUpd.NextPermissions = (uint)(PermissionMask.All); | ||
438 | itemUpd.EveryOnePermissions |= (uint)PermissionMask.Export; | ||
439 | } | ||
440 | else | ||
441 | { | ||
442 | itemUpd.EveryOnePermissions &= ~(uint)PermissionMask.Export; | ||
443 | } | ||
444 | } | ||
445 | else | ||
446 | { | ||
447 | // If the new state is exportable, force full perm | ||
448 | if ((itemUpd.EveryOnePermissions & (uint)PermissionMask.Export) != 0) | ||
449 | { | ||
450 | m_log.InfoFormat("[XXX]: Force full perm"); | ||
451 | itemUpd.NextPermissions = (uint)(PermissionMask.All); | ||
452 | } | ||
453 | } | ||
454 | |||
415 | if (item.NextPermissions != (itemUpd.NextPermissions & item.BasePermissions)) | 455 | if (item.NextPermissions != (itemUpd.NextPermissions & item.BasePermissions)) |
416 | item.Flags |= (uint)InventoryItemFlags.ObjectOverwriteNextOwner; | 456 | item.Flags |= (uint)InventoryItemFlags.ObjectOverwriteNextOwner; |
417 | item.NextPermissions = itemUpd.NextPermissions & item.BasePermissions; | 457 | item.NextPermissions = itemUpd.NextPermissions & item.BasePermissions; |
458 | |||
418 | if (item.EveryOnePermissions != (itemUpd.EveryOnePermissions & item.BasePermissions)) | 459 | if (item.EveryOnePermissions != (itemUpd.EveryOnePermissions & item.BasePermissions)) |
419 | item.Flags |= (uint)InventoryItemFlags.ObjectOverwriteEveryone; | 460 | item.Flags |= (uint)InventoryItemFlags.ObjectOverwriteEveryone; |
420 | item.EveryOnePermissions = itemUpd.EveryOnePermissions & item.BasePermissions; | 461 | item.EveryOnePermissions = itemUpd.EveryOnePermissions & item.BasePermissions; |
462 | |||
421 | if (item.GroupPermissions != (itemUpd.GroupPermissions & item.BasePermissions)) | 463 | if (item.GroupPermissions != (itemUpd.GroupPermissions & item.BasePermissions)) |
422 | item.Flags |= (uint)InventoryItemFlags.ObjectOverwriteGroup; | 464 | item.Flags |= (uint)InventoryItemFlags.ObjectOverwriteGroup; |
423 | |||
424 | // m_log.DebugFormat("[USER INVENTORY]: item.Flags {0}", item.Flags); | ||
425 | |||
426 | item.GroupPermissions = itemUpd.GroupPermissions & item.BasePermissions; | 465 | item.GroupPermissions = itemUpd.GroupPermissions & item.BasePermissions; |
466 | |||
427 | item.GroupID = itemUpd.GroupID; | 467 | item.GroupID = itemUpd.GroupID; |
428 | item.GroupOwned = itemUpd.GroupOwned; | 468 | item.GroupOwned = itemUpd.GroupOwned; |
429 | item.CreationDate = itemUpd.CreationDate; | 469 | item.CreationDate = itemUpd.CreationDate; |
@@ -445,8 +485,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
445 | item.SaleType = itemUpd.SaleType; | 485 | item.SaleType = itemUpd.SaleType; |
446 | 486 | ||
447 | InventoryService.UpdateItem(item); | 487 | InventoryService.UpdateItem(item); |
488 | remoteClient.SendBulkUpdateInventory(item); | ||
448 | } | 489 | } |
449 | else | 490 | |
491 | if (UUID.Zero != transactionID) | ||
450 | { | 492 | { |
451 | if (AgentTransactionsModule != null) | 493 | if (AgentTransactionsModule != null) |
452 | { | 494 | { |
@@ -683,12 +725,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
683 | itemCopy.SalePrice = item.SalePrice; | 725 | itemCopy.SalePrice = item.SalePrice; |
684 | itemCopy.SaleType = item.SaleType; | 726 | itemCopy.SaleType = item.SaleType; |
685 | 727 | ||
686 | if (AddInventoryItem(itemCopy)) | 728 | IInventoryAccessModule invAccess = RequestModuleInterface<IInventoryAccessModule>(); |
687 | { | 729 | if (invAccess != null) |
688 | IInventoryAccessModule invAccess = RequestModuleInterface<IInventoryAccessModule>(); | 730 | invAccess.TransferInventoryAssets(itemCopy, senderId, recipient); |
689 | if (invAccess != null) | 731 | AddInventoryItem(itemCopy); |
690 | Util.FireAndForget(delegate { invAccess.TransferInventoryAssets(itemCopy, senderId, recipient); }); | ||
691 | } | ||
692 | 732 | ||
693 | if (!Permissions.BypassPermissions()) | 733 | if (!Permissions.BypassPermissions()) |
694 | { | 734 | { |
@@ -908,7 +948,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
908 | { | 948 | { |
909 | CreateNewInventoryItem( | 949 | CreateNewInventoryItem( |
910 | remoteClient, creatorID, creatorData, folderID, name, description, flags, callbackID, asset, invType, | 950 | remoteClient, creatorID, creatorData, folderID, name, description, flags, callbackID, asset, invType, |
911 | (uint)PermissionMask.All, (uint)PermissionMask.All, 0, nextOwnerMask, 0, creationDate, transationID); | 951 | (uint)PermissionMask.All | (uint)PermissionMask.Export, (uint)PermissionMask.All | (uint)PermissionMask.Export, 0, nextOwnerMask, 0, creationDate, transationID); |
912 | } | 952 | } |
913 | 953 | ||
914 | 954 | ||
@@ -1037,8 +1077,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
1037 | CreateNewInventoryItem( | 1077 | CreateNewInventoryItem( |
1038 | remoteClient, remoteClient.AgentId.ToString(), string.Empty, folderID, | 1078 | remoteClient, remoteClient.AgentId.ToString(), string.Empty, folderID, |
1039 | name, description, 0, callbackID, asset, invType, | 1079 | name, description, 0, callbackID, asset, invType, |
1040 | (uint)PermissionMask.All, (uint)PermissionMask.All, (uint)PermissionMask.All, | 1080 | (uint)PermissionMask.All | (uint)PermissionMask.Export, (uint)PermissionMask.All | (uint)PermissionMask.Export, (uint)PermissionMask.All, |
1041 | (uint)PermissionMask.All, (uint)PermissionMask.All, Util.UnixTimeSinceEpoch()); | 1081 | (uint)PermissionMask.All | (uint)PermissionMask.Export, (uint)PermissionMask.All | (uint)PermissionMask.Export, Util.UnixTimeSinceEpoch()); |
1042 | } | 1082 | } |
1043 | else | 1083 | else |
1044 | { | 1084 | { |
@@ -1785,6 +1825,21 @@ namespace OpenSim.Region.Framework.Scenes | |||
1785 | /// <returns>The part where the script was rezzed if successful. False otherwise.</returns> | 1825 | /// <returns>The part where the script was rezzed if successful. False otherwise.</returns> |
1786 | public SceneObjectPart RezNewScript(UUID agentID, InventoryItemBase itemBase) | 1826 | public SceneObjectPart RezNewScript(UUID agentID, InventoryItemBase itemBase) |
1787 | { | 1827 | { |
1828 | return RezNewScript( | ||
1829 | agentID, | ||
1830 | itemBase, | ||
1831 | "default\n{\n state_entry()\n {\n llSay(0, \"Script running\");\n }\n}"); | ||
1832 | } | ||
1833 | |||
1834 | /// <summary> | ||
1835 | /// Rez a new script from nothing with given script text. | ||
1836 | /// </summary> | ||
1837 | /// <param name="remoteClient"></param> | ||
1838 | /// <param name="itemBase">Template item.</param> | ||
1839 | /// <param name="scriptText"></param> | ||
1840 | /// <returns>The part where the script was rezzed if successful. False otherwise.</returns> | ||
1841 | public SceneObjectPart RezNewScript(UUID agentID, InventoryItemBase itemBase, string scriptText) | ||
1842 | { | ||
1788 | // The part ID is the folder ID! | 1843 | // The part ID is the folder ID! |
1789 | SceneObjectPart part = GetSceneObjectPart(itemBase.Folder); | 1844 | SceneObjectPart part = GetSceneObjectPart(itemBase.Folder); |
1790 | if (part == null) | 1845 | if (part == null) |
@@ -1804,9 +1859,14 @@ namespace OpenSim.Region.Framework.Scenes | |||
1804 | return null; | 1859 | return null; |
1805 | } | 1860 | } |
1806 | 1861 | ||
1807 | AssetBase asset = CreateAsset(itemBase.Name, itemBase.Description, (sbyte)itemBase.AssetType, | 1862 | AssetBase asset |
1808 | Encoding.ASCII.GetBytes("default\n{\n state_entry()\n {\n llSay(0, \"Script running\");\n }\n\n touch_start(integer num)\n {\n }\n}"), | 1863 | = CreateAsset( |
1809 | agentID); | 1864 | itemBase.Name, |
1865 | itemBase.Description, | ||
1866 | (sbyte)itemBase.AssetType, | ||
1867 | Encoding.ASCII.GetBytes(scriptText), | ||
1868 | agentID); | ||
1869 | |||
1810 | AssetService.Store(asset); | 1870 | AssetService.Store(asset); |
1811 | 1871 | ||
1812 | TaskInventoryItem taskItem = new TaskInventoryItem(); | 1872 | TaskInventoryItem taskItem = new TaskInventoryItem(); |
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index e3bc8c7..28fce53 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs | |||
@@ -51,6 +51,7 @@ using OpenSim.Region.Physics.Manager; | |||
51 | using Timer=System.Timers.Timer; | 51 | using Timer=System.Timers.Timer; |
52 | using TPFlags = OpenSim.Framework.Constants.TeleportFlags; | 52 | using TPFlags = OpenSim.Framework.Constants.TeleportFlags; |
53 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; | 53 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; |
54 | using PermissionMask = OpenSim.Framework.PermissionMask; | ||
54 | 55 | ||
55 | namespace OpenSim.Region.Framework.Scenes | 56 | namespace OpenSim.Region.Framework.Scenes |
56 | { | 57 | { |
@@ -68,14 +69,84 @@ namespace OpenSim.Region.Framework.Scenes | |||
68 | public bool EmergencyMonitoring = false; | 69 | public bool EmergencyMonitoring = false; |
69 | 70 | ||
70 | /// <summary> | 71 | /// <summary> |
72 | /// Show debug information about animations. | ||
73 | /// </summary> | ||
74 | public bool DebugAnimations { get; set; } | ||
75 | |||
76 | /// <summary> | ||
71 | /// Show debug information about teleports. | 77 | /// Show debug information about teleports. |
72 | /// </summary> | 78 | /// </summary> |
73 | public bool DebugTeleporting { get; private set; } | 79 | public bool DebugTeleporting { get; set; } |
74 | 80 | ||
75 | /// <summary> | 81 | /// <summary> |
76 | /// Show debug information about the scene loop. | 82 | /// Show debug information about the scene loop. |
77 | /// </summary> | 83 | /// </summary> |
78 | public bool DebugUpdates { get; private set; } | 84 | public bool DebugUpdates { get; set; } |
85 | |||
86 | /// <summary> | ||
87 | /// If true then the scene is saved to persistent storage periodically, every m_update_backup frames and | ||
88 | /// if objects meet required conditions (m_dontPersistBefore and m_dontPersistAfter). | ||
89 | /// </summary> | ||
90 | /// <remarks> | ||
91 | /// Even if false, the scene will still be saved on clean shutdown. | ||
92 | /// FIXME: Currently, setting this to false will mean that objects are not periodically returned from parcels. | ||
93 | /// This needs to be fixed. | ||
94 | /// </remarks> | ||
95 | public bool PeriodicBackup { get; set; } | ||
96 | |||
97 | /// <summary> | ||
98 | /// If false then the scene is never saved to persistence storage even if PeriodicBackup == true and even | ||
99 | /// if the scene is being shut down for the final time. | ||
100 | /// </summary> | ||
101 | public bool UseBackup { get; set; } | ||
102 | |||
103 | /// <summary> | ||
104 | /// If false then physical objects are disabled, though collisions will continue as normal. | ||
105 | /// </summary> | ||
106 | public bool PhysicsEnabled { get; set; } | ||
107 | |||
108 | /// <summary> | ||
109 | /// If false then scripts are not enabled on the smiulator | ||
110 | /// </summary> | ||
111 | public bool ScriptsEnabled | ||
112 | { | ||
113 | get { return m_scripts_enabled; } | ||
114 | set | ||
115 | { | ||
116 | if (m_scripts_enabled != value) | ||
117 | { | ||
118 | if (!value) | ||
119 | { | ||
120 | m_log.Info("Stopping all Scripts in Scene"); | ||
121 | |||
122 | EntityBase[] entities = Entities.GetEntities(); | ||
123 | foreach (EntityBase ent in entities) | ||
124 | { | ||
125 | if (ent is SceneObjectGroup) | ||
126 | ((SceneObjectGroup)ent).RemoveScriptInstances(false); | ||
127 | } | ||
128 | } | ||
129 | else | ||
130 | { | ||
131 | m_log.Info("Starting all Scripts in Scene"); | ||
132 | |||
133 | EntityBase[] entities = Entities.GetEntities(); | ||
134 | foreach (EntityBase ent in entities) | ||
135 | { | ||
136 | if (ent is SceneObjectGroup) | ||
137 | { | ||
138 | SceneObjectGroup sog = (SceneObjectGroup)ent; | ||
139 | sog.CreateScriptInstances(0, false, DefaultScriptEngine, 0); | ||
140 | sog.ResumeScripts(); | ||
141 | } | ||
142 | } | ||
143 | } | ||
144 | |||
145 | m_scripts_enabled = value; | ||
146 | } | ||
147 | } | ||
148 | } | ||
149 | private bool m_scripts_enabled; | ||
79 | 150 | ||
80 | public SynchronizeSceneHandler SynchronizeScene; | 151 | public SynchronizeSceneHandler SynchronizeScene; |
81 | 152 | ||
@@ -284,8 +355,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
284 | private Dictionary<UUID, ReturnInfo> m_returns = new Dictionary<UUID, ReturnInfo>(); | 355 | private Dictionary<UUID, ReturnInfo> m_returns = new Dictionary<UUID, ReturnInfo>(); |
285 | private Dictionary<UUID, int> m_groupsWithTargets = new Dictionary<UUID, int>(); | 356 | private Dictionary<UUID, int> m_groupsWithTargets = new Dictionary<UUID, int>(); |
286 | 357 | ||
287 | private bool m_physics_enabled = true; | ||
288 | private bool m_scripts_enabled = true; | ||
289 | private string m_defaultScriptEngine; | 358 | private string m_defaultScriptEngine; |
290 | 359 | ||
291 | /// <summary> | 360 | /// <summary> |
@@ -348,7 +417,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
348 | 417 | ||
349 | private Timer m_mapGenerationTimer = new Timer(); | 418 | private Timer m_mapGenerationTimer = new Timer(); |
350 | private bool m_generateMaptiles; | 419 | private bool m_generateMaptiles; |
351 | private bool m_useBackup = true; | ||
352 | 420 | ||
353 | #endregion Fields | 421 | #endregion Fields |
354 | 422 | ||
@@ -614,11 +682,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
614 | get { return m_authenticateHandler; } | 682 | get { return m_authenticateHandler; } |
615 | } | 683 | } |
616 | 684 | ||
617 | public bool UseBackup | ||
618 | { | ||
619 | get { return m_useBackup; } | ||
620 | } | ||
621 | |||
622 | // an instance to the physics plugin's Scene object. | 685 | // an instance to the physics plugin's Scene object. |
623 | public PhysicsScene PhysicsScene | 686 | public PhysicsScene PhysicsScene |
624 | { | 687 | { |
@@ -678,7 +741,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
678 | public Scene(RegionInfo regInfo, AgentCircuitManager authen, | 741 | public Scene(RegionInfo regInfo, AgentCircuitManager authen, |
679 | SceneCommunicationService sceneGridService, | 742 | SceneCommunicationService sceneGridService, |
680 | ISimulationDataService simDataService, IEstateDataService estateDataService, | 743 | ISimulationDataService simDataService, IEstateDataService estateDataService, |
681 | bool dumpAssetsToFile, | ||
682 | IConfigSource config, string simulatorVersion) | 744 | IConfigSource config, string simulatorVersion) |
683 | : this(regInfo) | 745 | : this(regInfo) |
684 | { | 746 | { |
@@ -762,15 +824,20 @@ namespace OpenSim.Region.Framework.Scenes | |||
762 | // | 824 | // |
763 | // Out of memory | 825 | // Out of memory |
764 | // Operating system has killed the plugin | 826 | // Operating system has killed the plugin |
765 | m_sceneGraph.UnRecoverableError += RestartNow; | 827 | m_sceneGraph.UnRecoverableError |
828 | += () => | ||
829 | { | ||
830 | m_log.ErrorFormat("[SCENE]: Restarting region {0} due to unrecoverable physics crash", Name); | ||
831 | RestartNow(); | ||
832 | }; | ||
766 | 833 | ||
767 | RegisterDefaultSceneEvents(); | 834 | RegisterDefaultSceneEvents(); |
768 | 835 | ||
769 | DumpAssetsToFile = dumpAssetsToFile; | 836 | // XXX: Don't set the public property since we don't want to activate here. This needs to be handled |
770 | 837 | // better in the future. | |
771 | m_scripts_enabled = !RegionInfo.RegionSettings.DisableScripts; | 838 | m_scripts_enabled = !RegionInfo.RegionSettings.DisableScripts; |
772 | 839 | ||
773 | m_physics_enabled = !RegionInfo.RegionSettings.DisablePhysics; | 840 | PhysicsEnabled = !RegionInfo.RegionSettings.DisablePhysics; |
774 | 841 | ||
775 | m_simulatorVersion = simulatorVersion + " (" + Util.GetRuntimeInformation() + ")"; | 842 | m_simulatorVersion = simulatorVersion + " (" + Util.GetRuntimeInformation() + ")"; |
776 | 843 | ||
@@ -778,141 +845,154 @@ namespace OpenSim.Region.Framework.Scenes | |||
778 | 845 | ||
779 | // Region config overrides global config | 846 | // Region config overrides global config |
780 | // | 847 | // |
781 | try | 848 | if (m_config.Configs["Startup"] != null) |
782 | { | 849 | { |
783 | if (m_config.Configs["Startup"] != null) | 850 | IConfig startupConfig = m_config.Configs["Startup"]; |
851 | |||
852 | StartDisabled = startupConfig.GetBoolean("StartDisabled", false); | ||
853 | |||
854 | m_defaultDrawDistance = startupConfig.GetFloat("DefaultDrawDistance",m_defaultDrawDistance); | ||
855 | UseBackup = startupConfig.GetBoolean("UseSceneBackup", UseBackup); | ||
856 | if (!UseBackup) | ||
857 | m_log.InfoFormat("[SCENE]: Backup has been disabled for {0}", RegionInfo.RegionName); | ||
858 | |||
859 | //Animation states | ||
860 | m_useFlySlow = startupConfig.GetBoolean("enableflyslow", false); | ||
861 | |||
862 | PhysicalPrims = startupConfig.GetBoolean("physical_prim", true); | ||
863 | CollidablePrims = startupConfig.GetBoolean("collidable_prim", true); | ||
864 | |||
865 | m_minNonphys = startupConfig.GetFloat("NonPhysicalPrimMin", m_minNonphys); | ||
866 | if (RegionInfo.NonphysPrimMin > 0) | ||
784 | { | 867 | { |
785 | IConfig startupConfig = m_config.Configs["Startup"]; | 868 | m_minNonphys = RegionInfo.NonphysPrimMin; |
869 | } | ||
786 | 870 | ||
787 | StartDisabled = startupConfig.GetBoolean("StartDisabled", false); | 871 | m_maxNonphys = startupConfig.GetFloat("NonPhysicalPrimMax", m_maxNonphys); |
872 | if (RegionInfo.NonphysPrimMax > 0) | ||
873 | { | ||
874 | m_maxNonphys = RegionInfo.NonphysPrimMax; | ||
875 | } | ||
788 | 876 | ||
789 | m_defaultDrawDistance = startupConfig.GetFloat("DefaultDrawDistance",m_defaultDrawDistance); | 877 | m_minPhys = startupConfig.GetFloat("PhysicalPrimMin", m_minPhys); |
790 | m_useBackup = startupConfig.GetBoolean("UseSceneBackup", m_useBackup); | 878 | if (RegionInfo.PhysPrimMin > 0) |
791 | if (!m_useBackup) | 879 | { |
792 | m_log.InfoFormat("[SCENE]: Backup has been disabled for {0}", RegionInfo.RegionName); | 880 | m_minPhys = RegionInfo.PhysPrimMin; |
793 | 881 | } | |
794 | //Animation states | ||
795 | m_useFlySlow = startupConfig.GetBoolean("enableflyslow", false); | ||
796 | 882 | ||
797 | PhysicalPrims = startupConfig.GetBoolean("physical_prim", true); | 883 | m_maxPhys = startupConfig.GetFloat("PhysicalPrimMax", m_maxPhys); |
798 | CollidablePrims = startupConfig.GetBoolean("collidable_prim", true); | ||
799 | 884 | ||
800 | m_minNonphys = startupConfig.GetFloat("NonPhysicalPrimMin", m_minNonphys); | 885 | if (RegionInfo.PhysPrimMax > 0) |
801 | if (RegionInfo.NonphysPrimMin > 0) | 886 | { |
802 | { | 887 | m_maxPhys = RegionInfo.PhysPrimMax; |
803 | m_minNonphys = RegionInfo.NonphysPrimMin; | 888 | } |
804 | } | ||
805 | 889 | ||
806 | m_maxNonphys = startupConfig.GetFloat("NonPhysicalPrimMax", m_maxNonphys); | 890 | m_linksetCapacity = startupConfig.GetInt("LinksetPrims", m_linksetCapacity); |
807 | if (RegionInfo.NonphysPrimMax > 0) | 891 | if (RegionInfo.LinksetCapacity > 0) |
808 | { | 892 | { |
809 | m_maxNonphys = RegionInfo.NonphysPrimMax; | 893 | m_linksetCapacity = RegionInfo.LinksetCapacity; |
810 | } | 894 | } |
811 | 895 | ||
812 | m_minPhys = startupConfig.GetFloat("PhysicalPrimMin", m_minPhys); | 896 | SpawnPointRouting = startupConfig.GetString("SpawnPointRouting", "closest"); |
813 | if (RegionInfo.PhysPrimMin > 0) | 897 | TelehubAllowLandmarks = startupConfig.GetBoolean("TelehubAllowLandmark", false); |
814 | { | ||
815 | m_minPhys = RegionInfo.PhysPrimMin; | ||
816 | } | ||
817 | 898 | ||
818 | m_maxPhys = startupConfig.GetFloat("PhysicalPrimMax", m_maxPhys); | 899 | // Here, if clamping is requested in either global or |
900 | // local config, it will be used | ||
901 | // | ||
902 | m_clampPrimSize = startupConfig.GetBoolean("ClampPrimSize", m_clampPrimSize); | ||
903 | if (RegionInfo.ClampPrimSize) | ||
904 | { | ||
905 | m_clampPrimSize = true; | ||
906 | } | ||
819 | 907 | ||
820 | if (RegionInfo.PhysPrimMax > 0) | 908 | m_useTrashOnDelete = startupConfig.GetBoolean("UseTrashOnDelete",m_useTrashOnDelete); |
821 | { | 909 | m_trustBinaries = startupConfig.GetBoolean("TrustBinaries", m_trustBinaries); |
822 | m_maxPhys = RegionInfo.PhysPrimMax; | 910 | m_allowScriptCrossings = startupConfig.GetBoolean("AllowScriptCrossing", m_allowScriptCrossings); |
823 | } | 911 | m_dontPersistBefore = |
912 | startupConfig.GetLong("MinimumTimeBeforePersistenceConsidered", DEFAULT_MIN_TIME_FOR_PERSISTENCE); | ||
913 | m_dontPersistBefore *= 10000000; | ||
914 | m_persistAfter = | ||
915 | startupConfig.GetLong("MaximumTimeBeforePersistenceConsidered", DEFAULT_MAX_TIME_FOR_PERSISTENCE); | ||
916 | m_persistAfter *= 10000000; | ||
824 | 917 | ||
825 | m_linksetCapacity = startupConfig.GetInt("LinksetPrims", m_linksetCapacity); | 918 | m_defaultScriptEngine = startupConfig.GetString("DefaultScriptEngine", "XEngine"); |
826 | if (RegionInfo.LinksetCapacity > 0) | 919 | m_log.InfoFormat("[SCENE]: Default script engine {0}", m_defaultScriptEngine); |
827 | { | ||
828 | m_linksetCapacity = RegionInfo.LinksetCapacity; | ||
829 | } | ||
830 | 920 | ||
831 | SpawnPointRouting = startupConfig.GetString("SpawnPointRouting", "closest"); | 921 | m_strictAccessControl = startupConfig.GetBoolean("StrictAccessControl", m_strictAccessControl); |
832 | TelehubAllowLandmarks = startupConfig.GetBoolean("TelehubAllowLandmark", false); | 922 | m_seeIntoBannedRegion = startupConfig.GetBoolean("SeeIntoBannedRegion", m_seeIntoBannedRegion); |
923 | CombineRegions = startupConfig.GetBoolean("CombineContiguousRegions", false); | ||
833 | 924 | ||
834 | // Here, if clamping is requested in either global or | 925 | string[] possibleMapConfigSections = new string[] { "Map", "Startup" }; |
835 | // local config, it will be used | 926 | |
836 | // | 927 | m_generateMaptiles |
837 | m_clampPrimSize = startupConfig.GetBoolean("ClampPrimSize", m_clampPrimSize); | 928 | = Util.GetConfigVarFromSections<bool>(config, "GenerateMaptiles", possibleMapConfigSections, true); |
838 | if (RegionInfo.ClampPrimSize) | 929 | |
930 | if (m_generateMaptiles) | ||
931 | { | ||
932 | int maptileRefresh = startupConfig.GetInt("MaptileRefresh", 0); | ||
933 | if (maptileRefresh != 0) | ||
839 | { | 934 | { |
840 | m_clampPrimSize = true; | 935 | m_mapGenerationTimer.Interval = maptileRefresh * 1000; |
936 | m_mapGenerationTimer.Elapsed += RegenerateMaptileAndReregister; | ||
937 | m_mapGenerationTimer.AutoReset = true; | ||
938 | m_mapGenerationTimer.Start(); | ||
841 | } | 939 | } |
940 | } | ||
941 | else | ||
942 | { | ||
943 | string tile | ||
944 | = Util.GetConfigVarFromSections<string>( | ||
945 | config, "MaptileStaticUUID", possibleMapConfigSections, UUID.Zero.ToString()); | ||
842 | 946 | ||
843 | m_useTrashOnDelete = startupConfig.GetBoolean("UseTrashOnDelete",m_useTrashOnDelete); | 947 | UUID tileID; |
844 | m_trustBinaries = startupConfig.GetBoolean("TrustBinaries", m_trustBinaries); | 948 | |
845 | m_allowScriptCrossings = startupConfig.GetBoolean("AllowScriptCrossing", m_allowScriptCrossings); | 949 | if (tile != UUID.Zero.ToString() && UUID.TryParse(tile, out tileID)) |
846 | m_dontPersistBefore = | ||
847 | startupConfig.GetLong("MinimumTimeBeforePersistenceConsidered", DEFAULT_MIN_TIME_FOR_PERSISTENCE); | ||
848 | m_dontPersistBefore *= 10000000; | ||
849 | m_persistAfter = | ||
850 | startupConfig.GetLong("MaximumTimeBeforePersistenceConsidered", DEFAULT_MAX_TIME_FOR_PERSISTENCE); | ||
851 | m_persistAfter *= 10000000; | ||
852 | |||
853 | m_defaultScriptEngine = startupConfig.GetString("DefaultScriptEngine", "XEngine"); | ||
854 | m_log.InfoFormat("[SCENE]: Default script engine {0}", m_defaultScriptEngine); | ||
855 | |||
856 | m_strictAccessControl = startupConfig.GetBoolean("StrictAccessControl", m_strictAccessControl); | ||
857 | m_seeIntoBannedRegion = startupConfig.GetBoolean("SeeIntoBannedRegion", m_seeIntoBannedRegion); | ||
858 | CombineRegions = startupConfig.GetBoolean("CombineContiguousRegions", false); | ||
859 | |||
860 | m_generateMaptiles = startupConfig.GetBoolean("GenerateMaptiles", true); | ||
861 | if (m_generateMaptiles) | ||
862 | { | 950 | { |
863 | int maptileRefresh = startupConfig.GetInt("MaptileRefresh", 0); | 951 | RegionInfo.RegionSettings.TerrainImageID = tileID; |
864 | if (maptileRefresh != 0) | ||
865 | { | ||
866 | m_mapGenerationTimer.Interval = maptileRefresh * 1000; | ||
867 | m_mapGenerationTimer.Elapsed += RegenerateMaptileAndReregister; | ||
868 | m_mapGenerationTimer.AutoReset = true; | ||
869 | m_mapGenerationTimer.Start(); | ||
870 | } | ||
871 | } | 952 | } |
872 | else | 953 | else |
873 | { | 954 | { |
874 | string tile = startupConfig.GetString("MaptileStaticUUID", UUID.Zero.ToString()); | 955 | RegionInfo.RegionSettings.TerrainImageID = RegionInfo.MaptileStaticUUID; |
875 | UUID tileID; | 956 | m_log.InfoFormat("[SCENE]: Region {0}, maptile set to {1}", RegionInfo.RegionName, RegionInfo.MaptileStaticUUID.ToString()); |
876 | |||
877 | if (UUID.TryParse(tile, out tileID)) | ||
878 | { | ||
879 | RegionInfo.RegionSettings.TerrainImageID = tileID; | ||
880 | } | ||
881 | } | 957 | } |
958 | } | ||
959 | |||
960 | string[] possibleAccessControlConfigSections = new string[] { "AccessControl", "Startup" }; | ||
882 | 961 | ||
883 | string grant = startupConfig.GetString("AllowedClients", String.Empty); | 962 | string grant |
884 | if (grant.Length > 0) | 963 | = Util.GetConfigVarFromSections<string>( |
964 | config, "AllowedClients", possibleAccessControlConfigSections, ""); | ||
965 | |||
966 | if (grant.Length > 0) | ||
967 | { | ||
968 | foreach (string viewer in grant.Split(',')) | ||
885 | { | 969 | { |
886 | foreach (string viewer in grant.Split(',')) | 970 | m_AllowedViewers.Add(viewer.Trim().ToLower()); |
887 | { | ||
888 | m_AllowedViewers.Add(viewer.Trim().ToLower()); | ||
889 | } | ||
890 | } | 971 | } |
972 | } | ||
973 | |||
974 | grant | ||
975 | = Util.GetConfigVarFromSections<string>( | ||
976 | config, "BannedClients", possibleAccessControlConfigSections, ""); | ||
891 | 977 | ||
892 | grant = startupConfig.GetString("BannedClients", String.Empty); | 978 | if (grant.Length > 0) |
893 | if (grant.Length > 0) | 979 | { |
980 | foreach (string viewer in grant.Split(',')) | ||
894 | { | 981 | { |
895 | foreach (string viewer in grant.Split(',')) | 982 | m_BannedViewers.Add(viewer.Trim().ToLower()); |
896 | { | ||
897 | m_BannedViewers.Add(viewer.Trim().ToLower()); | ||
898 | } | ||
899 | } | 983 | } |
900 | |||
901 | MinFrameTime = startupConfig.GetFloat( "MinFrameTime", MinFrameTime); | ||
902 | m_update_backup = startupConfig.GetInt( "UpdateStorageEveryNFrames", m_update_backup); | ||
903 | m_update_coarse_locations = startupConfig.GetInt( "UpdateCoarseLocationsEveryNFrames", m_update_coarse_locations); | ||
904 | m_update_entitymovement = startupConfig.GetInt( "UpdateEntityMovementEveryNFrames", m_update_entitymovement); | ||
905 | m_update_events = startupConfig.GetInt( "UpdateEventsEveryNFrames", m_update_events); | ||
906 | m_update_objects = startupConfig.GetInt( "UpdateObjectsEveryNFrames", m_update_objects); | ||
907 | m_update_physics = startupConfig.GetInt( "UpdatePhysicsEveryNFrames", m_update_physics); | ||
908 | m_update_presences = startupConfig.GetInt( "UpdateAgentsEveryNFrames", m_update_presences); | ||
909 | m_update_terrain = startupConfig.GetInt( "UpdateTerrainEveryNFrames", m_update_terrain); | ||
910 | m_update_temp_cleaning = startupConfig.GetInt( "UpdateTempCleaningEveryNFrames", m_update_temp_cleaning); | ||
911 | } | 984 | } |
912 | } | 985 | |
913 | catch (Exception e) | 986 | MinFrameTime = startupConfig.GetFloat( "MinFrameTime", MinFrameTime); |
914 | { | 987 | m_update_backup = startupConfig.GetInt( "UpdateStorageEveryNFrames", m_update_backup); |
915 | m_log.Error("[SCENE]: Failed to load StartupConfig: " + e.ToString()); | 988 | m_update_coarse_locations = startupConfig.GetInt( "UpdateCoarseLocationsEveryNFrames", m_update_coarse_locations); |
989 | m_update_entitymovement = startupConfig.GetInt( "UpdateEntityMovementEveryNFrames", m_update_entitymovement); | ||
990 | m_update_events = startupConfig.GetInt( "UpdateEventsEveryNFrames", m_update_events); | ||
991 | m_update_objects = startupConfig.GetInt( "UpdateObjectsEveryNFrames", m_update_objects); | ||
992 | m_update_physics = startupConfig.GetInt( "UpdatePhysicsEveryNFrames", m_update_physics); | ||
993 | m_update_presences = startupConfig.GetInt( "UpdateAgentsEveryNFrames", m_update_presences); | ||
994 | m_update_terrain = startupConfig.GetInt( "UpdateTerrainEveryNFrames", m_update_terrain); | ||
995 | m_update_temp_cleaning = startupConfig.GetInt( "UpdateTempCleaningEveryNFrames", m_update_temp_cleaning); | ||
916 | } | 996 | } |
917 | 997 | ||
918 | // FIXME: Ultimately this should be in a module. | 998 | // FIXME: Ultimately this should be in a module. |
@@ -965,6 +1045,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
965 | { | 1045 | { |
966 | PhysicalPrims = true; | 1046 | PhysicalPrims = true; |
967 | CollidablePrims = true; | 1047 | CollidablePrims = true; |
1048 | PhysicsEnabled = true; | ||
1049 | |||
1050 | PeriodicBackup = true; | ||
1051 | UseBackup = true; | ||
968 | 1052 | ||
969 | BordersLocked = true; | 1053 | BordersLocked = true; |
970 | Border northBorder = new Border(); | 1054 | Border northBorder = new Border(); |
@@ -1207,83 +1291,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
1207 | } | 1291 | } |
1208 | } | 1292 | } |
1209 | 1293 | ||
1210 | public void SetSceneCoreDebug(Dictionary<string, string> options) | ||
1211 | { | ||
1212 | if (options.ContainsKey("active")) | ||
1213 | { | ||
1214 | bool active; | ||
1215 | |||
1216 | if (bool.TryParse(options["active"], out active)) | ||
1217 | Active = active; | ||
1218 | } | ||
1219 | |||
1220 | if (options.ContainsKey("scripting")) | ||
1221 | { | ||
1222 | bool enableScripts = true; | ||
1223 | if (bool.TryParse(options["scripting"], out enableScripts) && m_scripts_enabled != enableScripts) | ||
1224 | { | ||
1225 | if (!enableScripts) | ||
1226 | { | ||
1227 | m_log.Info("Stopping all Scripts in Scene"); | ||
1228 | |||
1229 | EntityBase[] entities = Entities.GetEntities(); | ||
1230 | foreach (EntityBase ent in entities) | ||
1231 | { | ||
1232 | if (ent is SceneObjectGroup) | ||
1233 | ((SceneObjectGroup)ent).RemoveScriptInstances(false); | ||
1234 | } | ||
1235 | } | ||
1236 | else | ||
1237 | { | ||
1238 | m_log.Info("Starting all Scripts in Scene"); | ||
1239 | |||
1240 | EntityBase[] entities = Entities.GetEntities(); | ||
1241 | foreach (EntityBase ent in entities) | ||
1242 | { | ||
1243 | if (ent is SceneObjectGroup) | ||
1244 | { | ||
1245 | SceneObjectGroup sog = (SceneObjectGroup)ent; | ||
1246 | sog.CreateScriptInstances(0, false, DefaultScriptEngine, 0); | ||
1247 | sog.ResumeScripts(); | ||
1248 | } | ||
1249 | } | ||
1250 | } | ||
1251 | |||
1252 | m_scripts_enabled = enableScripts; | ||
1253 | } | ||
1254 | } | ||
1255 | |||
1256 | if (options.ContainsKey("physics")) | ||
1257 | { | ||
1258 | bool enablePhysics; | ||
1259 | if (bool.TryParse(options["physics"], out enablePhysics)) | ||
1260 | m_physics_enabled = enablePhysics; | ||
1261 | } | ||
1262 | |||
1263 | // if (options.ContainsKey("collisions")) | ||
1264 | // { | ||
1265 | // // TODO: Implement. If false, should stop objects colliding, though possibly should still allow | ||
1266 | // // the avatar themselves to collide with the ground. | ||
1267 | // } | ||
1268 | |||
1269 | if (options.ContainsKey("teleport")) | ||
1270 | { | ||
1271 | bool enableTeleportDebugging; | ||
1272 | if (bool.TryParse(options["teleport"], out enableTeleportDebugging)) | ||
1273 | DebugTeleporting = enableTeleportDebugging; | ||
1274 | } | ||
1275 | |||
1276 | if (options.ContainsKey("updates")) | ||
1277 | { | ||
1278 | bool enableUpdateDebugging; | ||
1279 | if (bool.TryParse(options["updates"], out enableUpdateDebugging)) | ||
1280 | { | ||
1281 | DebugUpdates = enableUpdateDebugging; | ||
1282 | GcNotify.Enabled = DebugUpdates; | ||
1283 | } | ||
1284 | } | ||
1285 | } | ||
1286 | |||
1287 | public int GetInaccurateNeighborCount() | 1294 | public int GetInaccurateNeighborCount() |
1288 | { | 1295 | { |
1289 | return m_neighbours.Count; | 1296 | return m_neighbours.Count; |
@@ -1332,16 +1339,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1332 | 1339 | ||
1333 | m_log.Debug("[SCENE]: Persisting changed objects"); | 1340 | m_log.Debug("[SCENE]: Persisting changed objects"); |
1334 | 1341 | ||
1335 | EntityBase[] entities = GetEntities(); | 1342 | Backup(false); |
1336 | foreach (EntityBase entity in entities) | ||
1337 | { | ||
1338 | if (!entity.IsDeleted && entity is SceneObjectGroup && ((SceneObjectGroup)entity).HasGroupChanged) | ||
1339 | { | ||
1340 | ((SceneObjectGroup)entity).ProcessBackup(SimulationDataService, false); | ||
1341 | } | ||
1342 | } | ||
1343 | |||
1344 | m_log.Debug("[SCENE]: Graph close"); | ||
1345 | m_sceneGraph.Close(); | 1343 | m_sceneGraph.Close(); |
1346 | 1344 | ||
1347 | if (!GridService.DeregisterRegion(RegionInfo.RegionID)) | 1345 | if (!GridService.DeregisterRegion(RegionInfo.RegionID)) |
@@ -1568,7 +1566,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1568 | } | 1566 | } |
1569 | 1567 | ||
1570 | tmpMS = Util.EnvironmentTickCount(); | 1568 | tmpMS = Util.EnvironmentTickCount(); |
1571 | if ((Frame % m_update_physics == 0) && m_physics_enabled) | 1569 | if (PhysicsEnabled && Frame % m_update_physics == 0) |
1572 | m_sceneGraph.UpdatePreparePhysics(); | 1570 | m_sceneGraph.UpdatePreparePhysics(); |
1573 | physicsMS2 = Util.EnvironmentTickCountSubtract(tmpMS); | 1571 | physicsMS2 = Util.EnvironmentTickCountSubtract(tmpMS); |
1574 | 1572 | ||
@@ -1583,7 +1581,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1583 | tmpMS = Util.EnvironmentTickCount(); | 1581 | tmpMS = Util.EnvironmentTickCount(); |
1584 | if (Frame % m_update_physics == 0) | 1582 | if (Frame % m_update_physics == 0) |
1585 | { | 1583 | { |
1586 | if (m_physics_enabled) | 1584 | if (PhysicsEnabled) |
1587 | physicsFPS = m_sceneGraph.UpdatePhysics(MinFrameTime); | 1585 | physicsFPS = m_sceneGraph.UpdatePhysics(MinFrameTime); |
1588 | 1586 | ||
1589 | if (SynchronizeScene != null) | 1587 | if (SynchronizeScene != null) |
@@ -1625,7 +1623,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1625 | eventMS = Util.EnvironmentTickCountSubtract(tmpMS); | 1623 | eventMS = Util.EnvironmentTickCountSubtract(tmpMS); |
1626 | } | 1624 | } |
1627 | 1625 | ||
1628 | if (Frame % m_update_backup == 0) | 1626 | if (PeriodicBackup && Frame % m_update_backup == 0) |
1629 | { | 1627 | { |
1630 | tmpMS = Util.EnvironmentTickCount(); | 1628 | tmpMS = Util.EnvironmentTickCount(); |
1631 | UpdateStorageBackup(); | 1629 | UpdateStorageBackup(); |
@@ -2646,7 +2644,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
2646 | 2644 | ||
2647 | } | 2645 | } |
2648 | } | 2646 | } |
2649 | |||
2650 | 2647 | ||
2651 | return null; | 2648 | return null; |
2652 | } | 2649 | } |
@@ -2769,8 +2766,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
2769 | 2766 | ||
2770 | if (newPosition != Vector3.Zero) | 2767 | if (newPosition != Vector3.Zero) |
2771 | newObject.RootPart.GroupPosition = newPosition; | 2768 | newObject.RootPart.GroupPosition = newPosition; |
2772 | if (newObject.RootPart.KeyframeMotion != null) | ||
2773 | newObject.RootPart.KeyframeMotion.UpdateSceneObject(newObject); | ||
2774 | 2769 | ||
2775 | if (!AddSceneObject(newObject)) | 2770 | if (!AddSceneObject(newObject)) |
2776 | { | 2771 | { |
@@ -2798,6 +2793,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
2798 | // before we restart the scripts, or else some functions won't work. | 2793 | // before we restart the scripts, or else some functions won't work. |
2799 | newObject.RootPart.ParentGroup.CreateScriptInstances(0, false, DefaultScriptEngine, GetStateSource(newObject)); | 2794 | newObject.RootPart.ParentGroup.CreateScriptInstances(0, false, DefaultScriptEngine, GetStateSource(newObject)); |
2800 | newObject.ResumeScripts(); | 2795 | newObject.ResumeScripts(); |
2796 | |||
2797 | if (newObject.RootPart.KeyframeMotion != null) | ||
2798 | newObject.RootPart.KeyframeMotion.UpdateSceneObject(newObject); | ||
2801 | } | 2799 | } |
2802 | 2800 | ||
2803 | // Do this as late as possible so that listeners have full access to the incoming object | 2801 | // Do this as late as possible so that listeners have full access to the incoming object |
@@ -2863,9 +2861,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
2863 | // "[ATTACHMENT]: Attach to avatar {0} at position {1}", sp.UUID, grp.AbsolutePosition); | 2861 | // "[ATTACHMENT]: Attach to avatar {0} at position {1}", sp.UUID, grp.AbsolutePosition); |
2864 | 2862 | ||
2865 | RootPrim.RemFlag(PrimFlags.TemporaryOnRez); | 2863 | RootPrim.RemFlag(PrimFlags.TemporaryOnRez); |
2866 | 2864 | ||
2865 | // We must currently not resume scripts at this stage since AttachmentsModule does not have the | ||
2866 | // information that this is due to a teleport/border cross rather than an ordinary attachment. | ||
2867 | // We currently do this in Scene.MakeRootAgent() instead. | ||
2867 | if (AttachmentsModule != null) | 2868 | if (AttachmentsModule != null) |
2868 | AttachmentsModule.AttachObject(sp, grp, 0, false, false, false); | 2869 | AttachmentsModule.AttachObject(sp, grp, 0, false, false, false, true); |
2869 | } | 2870 | } |
2870 | else | 2871 | else |
2871 | { | 2872 | { |
@@ -2970,24 +2971,16 @@ namespace OpenSim.Region.Framework.Scenes | |||
2970 | SubscribeToClientEvents(client); | 2971 | SubscribeToClientEvents(client); |
2971 | 2972 | ||
2972 | sp = m_sceneGraph.CreateAndAddChildScenePresence(client, aCircuit.Appearance, type); | 2973 | sp = m_sceneGraph.CreateAndAddChildScenePresence(client, aCircuit.Appearance, type); |
2974 | InventoryFolderBase cof = InventoryService.GetFolderForType(client.AgentId, (AssetType)46); | ||
2975 | if (cof == null) | ||
2976 | sp.COF = UUID.Zero; | ||
2977 | else | ||
2978 | sp.COF = cof.ID; | ||
2979 | |||
2980 | m_log.DebugFormat("[SCENE]: COF for {0} is {1}", client.AgentId, sp.COF); | ||
2973 | m_eventManager.TriggerOnNewPresence(sp); | 2981 | m_eventManager.TriggerOnNewPresence(sp); |
2974 | 2982 | ||
2975 | sp.TeleportFlags = (TPFlags)aCircuit.teleportFlags; | 2983 | sp.TeleportFlags = (TPFlags)aCircuit.teleportFlags; |
2976 | |||
2977 | // The first agent upon login is a root agent by design. | ||
2978 | // For this agent we will have to rez the attachments. | ||
2979 | // All other AddNewClient calls find aCircuit.child to be true. | ||
2980 | if (aCircuit.child == false) | ||
2981 | { | ||
2982 | // We have to set SP to be a root agent here so that SP.MakeRootAgent() will later not try to | ||
2983 | // start the scripts again (since this is done in RezAttachments()). | ||
2984 | // XXX: This is convoluted. | ||
2985 | sp.IsChildAgent = false; | ||
2986 | sp.IsLoggingIn = true; | ||
2987 | |||
2988 | if (AttachmentsModule != null) | ||
2989 | Util.FireAndForget(delegate(object o) { AttachmentsModule.RezAttachments(sp); }); | ||
2990 | } | ||
2991 | } | 2984 | } |
2992 | else | 2985 | else |
2993 | { | 2986 | { |
@@ -3615,7 +3608,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3615 | // TODO: We shouldn't use closeChildAgents here - it's being used by the NPC module to stop | 3608 | // TODO: We shouldn't use closeChildAgents here - it's being used by the NPC module to stop |
3616 | // unnecessary operations. This should go away once NPCs have no accompanying IClientAPI | 3609 | // unnecessary operations. This should go away once NPCs have no accompanying IClientAPI |
3617 | if (closeChildAgents && CapsModule != null) | 3610 | if (closeChildAgents && CapsModule != null) |
3618 | CapsModule.RemoveCaps(agentID); | 3611 | CapsModule.RemoveCaps(agentID, avatar.ControllingClient.CircuitCode); |
3619 | 3612 | ||
3620 | // // REFACTORING PROBLEM -- well not really a problem, but just to point out that whatever | 3613 | // // REFACTORING PROBLEM -- well not really a problem, but just to point out that whatever |
3621 | // // this method is doing is HORRIBLE!!! | 3614 | // // this method is doing is HORRIBLE!!! |
@@ -3846,20 +3839,36 @@ namespace OpenSim.Region.Framework.Scenes | |||
3846 | return false; | 3839 | return false; |
3847 | } | 3840 | } |
3848 | 3841 | ||
3849 | |||
3850 | ScenePresence sp = GetScenePresence(agent.AgentID); | 3842 | ScenePresence sp = GetScenePresence(agent.AgentID); |
3851 | 3843 | ||
3852 | if (sp != null && !sp.IsChildAgent) | 3844 | // If we have noo presence here or if that presence is a zombie root |
3845 | // presence that will be kicled, we need a new CAPS object. | ||
3846 | if (sp == null || (sp != null && !sp.IsChildAgent)) | ||
3853 | { | 3847 | { |
3854 | // We have a zombie from a crashed session. | 3848 | if (CapsModule != null) |
3855 | // Or the same user is trying to be root twice here, won't work. | 3849 | { |
3856 | // Kill it. | 3850 | lock (agent) |
3857 | m_log.WarnFormat( | 3851 | { |
3858 | "[SCENE]: Existing root scene presence detected for {0} {1} in {2} when connecting. Removing existing presence.", | 3852 | CapsModule.SetAgentCapsSeeds(agent); |
3859 | sp.Name, sp.UUID, RegionInfo.RegionName); | 3853 | CapsModule.CreateCaps(agent.AgentID, agent.circuitcode); |
3854 | } | ||
3855 | } | ||
3856 | } | ||
3860 | 3857 | ||
3861 | sp.ControllingClient.Close(true, true); | 3858 | if (sp != null) |
3862 | sp = null; | 3859 | { |
3860 | if (!sp.IsChildAgent) | ||
3861 | { | ||
3862 | // We have a zombie from a crashed session. | ||
3863 | // Or the same user is trying to be root twice here, won't work. | ||
3864 | // Kill it. | ||
3865 | m_log.WarnFormat( | ||
3866 | "[SCENE]: Existing root scene presence detected for {0} {1} in {2} when connecting. Removing existing presence.", | ||
3867 | sp.Name, sp.UUID, RegionInfo.RegionName); | ||
3868 | |||
3869 | sp.ControllingClient.Close(true, true); | ||
3870 | sp = null; | ||
3871 | } | ||
3863 | } | 3872 | } |
3864 | 3873 | ||
3865 | lock (agent) | 3874 | lock (agent) |
@@ -3900,7 +3909,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
3900 | if (vialogin || (!m_seeIntoBannedRegion)) | 3909 | if (vialogin || (!m_seeIntoBannedRegion)) |
3901 | { | 3910 | { |
3902 | if (!AuthorizeUser(agent, out reason)) | 3911 | if (!AuthorizeUser(agent, out reason)) |
3912 | { | ||
3903 | return false; | 3913 | return false; |
3914 | } | ||
3904 | } | 3915 | } |
3905 | } | 3916 | } |
3906 | catch (Exception e) | 3917 | catch (Exception e) |
@@ -3915,11 +3926,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
3915 | RegionInfo.RegionName, (agent.child ? "child" : "root"), agent.firstname, agent.lastname, | 3926 | RegionInfo.RegionName, (agent.child ? "child" : "root"), agent.firstname, agent.lastname, |
3916 | agent.AgentID, agent.circuitcode); | 3927 | agent.AgentID, agent.circuitcode); |
3917 | 3928 | ||
3918 | if (CapsModule != null) | ||
3919 | { | ||
3920 | CapsModule.SetAgentCapsSeeds(agent); | ||
3921 | CapsModule.CreateCaps(agent.AgentID); | ||
3922 | } | ||
3923 | } | 3929 | } |
3924 | else | 3930 | else |
3925 | { | 3931 | { |
@@ -3945,6 +3951,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
3945 | agent.teleportFlags = teleportFlags; | 3951 | agent.teleportFlags = teleportFlags; |
3946 | m_authenticateHandler.AddNewCircuit(agent.circuitcode, agent); | 3952 | m_authenticateHandler.AddNewCircuit(agent.circuitcode, agent); |
3947 | 3953 | ||
3954 | if (CapsModule != null) | ||
3955 | { | ||
3956 | CapsModule.ActivateCaps(agent.circuitcode); | ||
3957 | } | ||
3958 | |||
3948 | if (vialogin) | 3959 | if (vialogin) |
3949 | { | 3960 | { |
3950 | // CleanDroppedAttachments(); | 3961 | // CleanDroppedAttachments(); |
@@ -4306,33 +4317,33 @@ namespace OpenSim.Region.Framework.Scenes | |||
4306 | // } | 4317 | // } |
4307 | // } | 4318 | // } |
4308 | 4319 | ||
4309 | /// <summary> | 4320 | // /// <summary> |
4310 | /// Triggered when an agent crosses into this sim. Also happens on initial login. | 4321 | // /// Triggered when an agent crosses into this sim. Also happens on initial login. |
4311 | /// </summary> | 4322 | // /// </summary> |
4312 | /// <param name="agentID"></param> | 4323 | // /// <param name="agentID"></param> |
4313 | /// <param name="position"></param> | 4324 | // /// <param name="position"></param> |
4314 | /// <param name="isFlying"></param> | 4325 | // /// <param name="isFlying"></param> |
4315 | public virtual void AgentCrossing(UUID agentID, Vector3 position, bool isFlying) | 4326 | // public virtual void AgentCrossing(UUID agentID, Vector3 position, bool isFlying) |
4316 | { | 4327 | // { |
4317 | ScenePresence presence = GetScenePresence(agentID); | 4328 | // ScenePresence presence = GetScenePresence(agentID); |
4318 | if (presence != null) | 4329 | // if (presence != null) |
4319 | { | 4330 | // { |
4320 | try | 4331 | // try |
4321 | { | 4332 | // { |
4322 | presence.MakeRootAgent(position, isFlying); | 4333 | // presence.MakeRootAgent(position, isFlying); |
4323 | } | 4334 | // } |
4324 | catch (Exception e) | 4335 | // catch (Exception e) |
4325 | { | 4336 | // { |
4326 | m_log.ErrorFormat("[SCENE]: Unable to do agent crossing, exception {0}{1}", e.Message, e.StackTrace); | 4337 | // m_log.ErrorFormat("[SCENE]: Unable to do agent crossing, exception {0}{1}", e.Message, e.StackTrace); |
4327 | } | 4338 | // } |
4328 | } | 4339 | // } |
4329 | else | 4340 | // else |
4330 | { | 4341 | // { |
4331 | m_log.ErrorFormat( | 4342 | // m_log.ErrorFormat( |
4332 | "[SCENE]: Could not find presence for agent {0} crossing into scene {1}", | 4343 | // "[SCENE]: Could not find presence for agent {0} crossing into scene {1}", |
4333 | agentID, RegionInfo.RegionName); | 4344 | // agentID, RegionInfo.RegionName); |
4334 | } | 4345 | // } |
4335 | } | 4346 | // } |
4336 | 4347 | ||
4337 | /// <summary> | 4348 | /// <summary> |
4338 | /// We've got an update about an agent that sees into this region, | 4349 | /// We've got an update about an agent that sees into this region, |
@@ -4702,19 +4713,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
4702 | 4713 | ||
4703 | #region Script Engine | 4714 | #region Script Engine |
4704 | 4715 | ||
4705 | private List<ScriptEngineInterface> ScriptEngines = new List<ScriptEngineInterface>(); | ||
4706 | public bool DumpAssetsToFile; | ||
4707 | |||
4708 | /// <summary> | ||
4709 | /// | ||
4710 | /// </summary> | ||
4711 | /// <param name="scriptEngine"></param> | ||
4712 | public void AddScriptEngine(ScriptEngineInterface scriptEngine) | ||
4713 | { | ||
4714 | ScriptEngines.Add(scriptEngine); | ||
4715 | scriptEngine.InitializeEngine(this); | ||
4716 | } | ||
4717 | |||
4718 | private bool ScriptDanger(SceneObjectPart part,Vector3 pos) | 4716 | private bool ScriptDanger(SceneObjectPart part,Vector3 pos) |
4719 | { | 4717 | { |
4720 | ILandObject parcel = LandChannel.GetLandObject(pos.X, pos.Y); | 4718 | ILandObject parcel = LandChannel.GetLandObject(pos.X, pos.Y); |
@@ -5122,7 +5120,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
5122 | { | 5120 | { |
5123 | if ((grp.RootPart.Flags & PrimFlags.TemporaryOnRez) != 0) | 5121 | if ((grp.RootPart.Flags & PrimFlags.TemporaryOnRez) != 0) |
5124 | { | 5122 | { |
5125 | if (grp.RootPart.Expires <= DateTime.Now) | 5123 | if (grp.GetSittingAvatarsCount() == 0 && grp.RootPart.Expires <= DateTime.Now) |
5126 | DeleteSceneObject(grp, false); | 5124 | DeleteSceneObject(grp, false); |
5127 | } | 5125 | } |
5128 | } | 5126 | } |
@@ -5621,33 +5619,7 @@ Environment.Exit(1); | |||
5621 | 5619 | ||
5622 | public void TriggerEstateSunUpdate() | 5620 | public void TriggerEstateSunUpdate() |
5623 | { | 5621 | { |
5624 | float sun; | 5622 | EventManager.TriggerEstateToolsSunUpdate(RegionInfo.RegionHandle); |
5625 | if (RegionInfo.RegionSettings.UseEstateSun) | ||
5626 | { | ||
5627 | sun = (float)RegionInfo.EstateSettings.SunPosition; | ||
5628 | if (RegionInfo.EstateSettings.UseGlobalTime) | ||
5629 | { | ||
5630 | sun = EventManager.GetCurrentTimeAsSunLindenHour() - 6.0f; | ||
5631 | } | ||
5632 | |||
5633 | // | ||
5634 | EventManager.TriggerEstateToolsSunUpdate( | ||
5635 | RegionInfo.RegionHandle, | ||
5636 | RegionInfo.EstateSettings.FixedSun, | ||
5637 | RegionInfo.RegionSettings.UseEstateSun, | ||
5638 | sun); | ||
5639 | } | ||
5640 | else | ||
5641 | { | ||
5642 | // Use the Sun Position from the Region Settings | ||
5643 | sun = (float)RegionInfo.RegionSettings.SunPosition - 6.0f; | ||
5644 | |||
5645 | EventManager.TriggerEstateToolsSunUpdate( | ||
5646 | RegionInfo.RegionHandle, | ||
5647 | RegionInfo.RegionSettings.FixedSun, | ||
5648 | RegionInfo.RegionSettings.UseEstateSun, | ||
5649 | sun); | ||
5650 | } | ||
5651 | } | 5623 | } |
5652 | 5624 | ||
5653 | private void HandleReloadEstate(string module, string[] cmd) | 5625 | private void HandleReloadEstate(string module, string[] cmd) |
@@ -5915,8 +5887,13 @@ Environment.Exit(1); | |||
5915 | 5887 | ||
5916 | if (banned) | 5888 | if (banned) |
5917 | { | 5889 | { |
5918 | reason = "No suitable landing point found"; | 5890 | if(Permissions.IsAdministrator(agentID) == false || Permissions.IsGridGod(agentID) == false) |
5919 | return false; | 5891 | { |
5892 | reason = "No suitable landing point found"; | ||
5893 | return false; | ||
5894 | } | ||
5895 | reason = "Administrative access only"; | ||
5896 | return true; | ||
5920 | } | 5897 | } |
5921 | } | 5898 | } |
5922 | } | 5899 | } |
@@ -6043,10 +6020,17 @@ Environment.Exit(1); | |||
6043 | GC.Collect(); | 6020 | GC.Collect(); |
6044 | } | 6021 | } |
6045 | 6022 | ||
6046 | // Wrappers to get physics modules retrieve assets. Has to be done this way | 6023 | /// <summary> |
6047 | // because we can't assign the asset service to physics directly - at the | 6024 | /// Wrappers to get physics modules retrieve assets. |
6048 | // time physics are instantiated it's not registered but it will be by | 6025 | /// </summary> |
6049 | // the time the first prim exists. | 6026 | /// <remarks> |
6027 | /// Has to be done this way | ||
6028 | /// because we can't assign the asset service to physics directly - at the | ||
6029 | /// time physics are instantiated it's not registered but it will be by | ||
6030 | /// the time the first prim exists. | ||
6031 | /// </remarks> | ||
6032 | /// <param name="assetID"></param> | ||
6033 | /// <param name="callback"></param> | ||
6050 | public void PhysicsRequestAsset(UUID assetID, AssetReceivedDelegate callback) | 6034 | public void PhysicsRequestAsset(UUID assetID, AssetReceivedDelegate callback) |
6051 | { | 6035 | { |
6052 | AssetService.Get(assetID.ToString(), callback, PhysicsAssetReceived); | 6036 | AssetService.Get(assetID.ToString(), callback, PhysicsAssetReceived); |
diff --git a/OpenSim/Region/Framework/Scenes/SceneManager.cs b/OpenSim/Region/Framework/Scenes/SceneManager.cs index 0e0b6c3..c70342f 100644 --- a/OpenSim/Region/Framework/Scenes/SceneManager.cs +++ b/OpenSim/Region/Framework/Scenes/SceneManager.cs | |||
@@ -100,7 +100,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
100 | } | 100 | } |
101 | 101 | ||
102 | private readonly DoubleDictionary<UUID, string, Scene> m_localScenes = new DoubleDictionary<UUID, string, Scene>(); | 102 | private readonly DoubleDictionary<UUID, string, Scene> m_localScenes = new DoubleDictionary<UUID, string, Scene>(); |
103 | private Scene m_currentScene = null; | ||
104 | 103 | ||
105 | public List<Scene> Scenes | 104 | public List<Scene> Scenes |
106 | { | 105 | { |
@@ -313,35 +312,30 @@ namespace OpenSim.Region.Framework.Scenes | |||
313 | 312 | ||
314 | public void SendCommandToPluginModules(string[] cmdparams) | 313 | public void SendCommandToPluginModules(string[] cmdparams) |
315 | { | 314 | { |
316 | ForEachCurrentScene(delegate(Scene scene) { scene.SendCommandToPlugins(cmdparams); }); | 315 | ForEachSelectedScene(delegate(Scene scene) { scene.SendCommandToPlugins(cmdparams); }); |
317 | } | 316 | } |
318 | 317 | ||
319 | public void SetBypassPermissionsOnCurrentScene(bool bypassPermissions) | 318 | public void SetBypassPermissionsOnCurrentScene(bool bypassPermissions) |
320 | { | 319 | { |
321 | ForEachCurrentScene(delegate(Scene scene) { scene.Permissions.SetBypassPermissions(bypassPermissions); }); | 320 | ForEachSelectedScene(delegate(Scene scene) { scene.Permissions.SetBypassPermissions(bypassPermissions); }); |
322 | } | 321 | } |
323 | 322 | ||
324 | private void ForEachCurrentScene(Action<Scene> func) | 323 | public void ForEachSelectedScene(Action<Scene> func) |
325 | { | 324 | { |
326 | if (CurrentScene == null) | 325 | if (CurrentScene == null) |
327 | { | 326 | ForEachScene(func); |
328 | List<Scene> sceneList = Scenes; | ||
329 | sceneList.ForEach(func); | ||
330 | } | ||
331 | else | 327 | else |
332 | { | ||
333 | func(CurrentScene); | 328 | func(CurrentScene); |
334 | } | ||
335 | } | 329 | } |
336 | 330 | ||
337 | public void RestartCurrentScene() | 331 | public void RestartCurrentScene() |
338 | { | 332 | { |
339 | ForEachCurrentScene(delegate(Scene scene) { scene.RestartNow(); }); | 333 | ForEachSelectedScene(delegate(Scene scene) { scene.RestartNow(); }); |
340 | } | 334 | } |
341 | 335 | ||
342 | public void BackupCurrentScene() | 336 | public void BackupCurrentScene() |
343 | { | 337 | { |
344 | ForEachCurrentScene(delegate(Scene scene) { scene.Backup(true); }); | 338 | ForEachSelectedScene(delegate(Scene scene) { scene.Backup(true); }); |
345 | } | 339 | } |
346 | 340 | ||
347 | public bool TrySetCurrentScene(string regionName) | 341 | public bool TrySetCurrentScene(string regionName) |
@@ -359,7 +353,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
359 | 353 | ||
360 | if (m_localScenes.TryGetValue(regionName, out s)) | 354 | if (m_localScenes.TryGetValue(regionName, out s)) |
361 | { | 355 | { |
362 | m_currentScene = s; | 356 | CurrentScene = s; |
363 | return true; | 357 | return true; |
364 | } | 358 | } |
365 | 359 | ||
@@ -375,7 +369,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
375 | 369 | ||
376 | if (m_localScenes.TryGetValue(regionID, out s)) | 370 | if (m_localScenes.TryGetValue(regionID, out s)) |
377 | { | 371 | { |
378 | m_currentScene = s; | 372 | CurrentScene = s; |
379 | return true; | 373 | return true; |
380 | } | 374 | } |
381 | 375 | ||
@@ -434,7 +428,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
434 | /// <param name="name">Name of avatar to debug</param> | 428 | /// <param name="name">Name of avatar to debug</param> |
435 | public void SetDebugPacketLevelOnCurrentScene(int newDebug, string name) | 429 | public void SetDebugPacketLevelOnCurrentScene(int newDebug, string name) |
436 | { | 430 | { |
437 | ForEachCurrentScene(scene => | 431 | ForEachSelectedScene(scene => |
438 | scene.ForEachScenePresence(sp => | 432 | scene.ForEachScenePresence(sp => |
439 | { | 433 | { |
440 | if (name == null || sp.Name == name) | 434 | if (name == null || sp.Name == name) |
@@ -453,7 +447,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
453 | { | 447 | { |
454 | List<ScenePresence> avatars = new List<ScenePresence>(); | 448 | List<ScenePresence> avatars = new List<ScenePresence>(); |
455 | 449 | ||
456 | ForEachCurrentScene( | 450 | ForEachSelectedScene( |
457 | delegate(Scene scene) | 451 | delegate(Scene scene) |
458 | { | 452 | { |
459 | scene.ForEachRootScenePresence(delegate(ScenePresence scenePresence) | 453 | scene.ForEachRootScenePresence(delegate(ScenePresence scenePresence) |
@@ -470,7 +464,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
470 | { | 464 | { |
471 | List<ScenePresence> presences = new List<ScenePresence>(); | 465 | List<ScenePresence> presences = new List<ScenePresence>(); |
472 | 466 | ||
473 | ForEachCurrentScene(delegate(Scene scene) | 467 | ForEachSelectedScene(delegate(Scene scene) |
474 | { | 468 | { |
475 | scene.ForEachScenePresence(delegate(ScenePresence sp) | 469 | scene.ForEachScenePresence(delegate(ScenePresence sp) |
476 | { | 470 | { |
@@ -494,12 +488,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
494 | 488 | ||
495 | public void ForceCurrentSceneClientUpdate() | 489 | public void ForceCurrentSceneClientUpdate() |
496 | { | 490 | { |
497 | ForEachCurrentScene(delegate(Scene scene) { scene.ForceClientUpdate(); }); | 491 | ForEachSelectedScene(delegate(Scene scene) { scene.ForceClientUpdate(); }); |
498 | } | 492 | } |
499 | 493 | ||
500 | public void HandleEditCommandOnCurrentScene(string[] cmdparams) | 494 | public void HandleEditCommandOnCurrentScene(string[] cmdparams) |
501 | { | 495 | { |
502 | ForEachCurrentScene(delegate(Scene scene) { scene.HandleEditCommand(cmdparams); }); | 496 | ForEachSelectedScene(delegate(Scene scene) { scene.HandleEditCommand(cmdparams); }); |
503 | } | 497 | } |
504 | 498 | ||
505 | public bool TryGetScenePresence(UUID avatarId, out ScenePresence avatar) | 499 | public bool TryGetScenePresence(UUID avatarId, out ScenePresence avatar) |
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs index 26524fb..f8624e7 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs | |||
@@ -34,6 +34,7 @@ using OpenSim.Framework; | |||
34 | using OpenSim.Region.Framework.Interfaces; | 34 | using OpenSim.Region.Framework.Interfaces; |
35 | using System.Collections.Generic; | 35 | using System.Collections.Generic; |
36 | using System.Xml; | 36 | using System.Xml; |
37 | using PermissionMask = OpenSim.Framework.PermissionMask; | ||
37 | 38 | ||
38 | namespace OpenSim.Region.Framework.Scenes | 39 | namespace OpenSim.Region.Framework.Scenes |
39 | { | 40 | { |
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index ed1bbd8..69fb6df 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | |||
@@ -41,6 +41,7 @@ using OpenSim.Framework; | |||
41 | using OpenSim.Region.Framework.Interfaces; | 41 | using OpenSim.Region.Framework.Interfaces; |
42 | using OpenSim.Region.Physics.Manager; | 42 | using OpenSim.Region.Physics.Manager; |
43 | using OpenSim.Region.Framework.Scenes.Serialization; | 43 | using OpenSim.Region.Framework.Scenes.Serialization; |
44 | using PermissionMask = OpenSim.Framework.PermissionMask; | ||
44 | 45 | ||
45 | namespace OpenSim.Region.Framework.Scenes | 46 | namespace OpenSim.Region.Framework.Scenes |
46 | { | 47 | { |
@@ -101,6 +102,15 @@ namespace OpenSim.Region.Framework.Scenes | |||
101 | /// </summary> | 102 | /// </summary> |
102 | public partial class SceneObjectGroup : EntityBase, ISceneObject | 103 | public partial class SceneObjectGroup : EntityBase, ISceneObject |
103 | { | 104 | { |
105 | // Axis selection bitmask used by SetAxisRotation() | ||
106 | // Just happen to be the same bits used by llSetStatus() and defined in ScriptBaseClass. | ||
107 | public enum axisSelect : int | ||
108 | { | ||
109 | STATUS_ROTATE_X = 0x002, | ||
110 | STATUS_ROTATE_Y = 0x004, | ||
111 | STATUS_ROTATE_Z = 0x008, | ||
112 | } | ||
113 | |||
104 | // private PrimCountTaintedDelegate handlerPrimCountTainted = null; | 114 | // private PrimCountTaintedDelegate handlerPrimCountTainted = null; |
105 | 115 | ||
106 | /// <summary> | 116 | /// <summary> |
@@ -512,11 +522,19 @@ namespace OpenSim.Region.Framework.Scenes | |||
512 | 522 | ||
513 | if (Scene != null) | 523 | if (Scene != null) |
514 | { | 524 | { |
515 | // if ((Scene.TestBorderCross(val - Vector3.UnitX, Cardinals.E) || Scene.TestBorderCross(val + Vector3.UnitX, Cardinals.W) | 525 | if ( |
516 | // || Scene.TestBorderCross(val - Vector3.UnitY, Cardinals.N) || Scene.TestBorderCross(val + Vector3.UnitY, Cardinals.S)) | 526 | // (Scene.TestBorderCross(val - Vector3.UnitX, Cardinals.E) |
517 | // && !IsAttachmentCheckFull() && (!Scene.LoadingPrims)) | 527 | // || Scene.TestBorderCross(val + Vector3.UnitX, Cardinals.W) |
518 | if ((Scene.TestBorderCross(val, Cardinals.E) || Scene.TestBorderCross(val, Cardinals.W) | 528 | // || Scene.TestBorderCross(val - Vector3.UnitY, Cardinals.N) |
519 | || Scene.TestBorderCross(val, Cardinals.N) || Scene.TestBorderCross(val, Cardinals.S)) | 529 | // || Scene.TestBorderCross(val + Vector3.UnitY, Cardinals.S)) |
530 | // Experimental change for better border crossings. | ||
531 | // The commented out original lines above would, it seems, trigger | ||
532 | // a border crossing a little early or late depending on which | ||
533 | // direction the object was moving. | ||
534 | (Scene.TestBorderCross(val, Cardinals.E) | ||
535 | || Scene.TestBorderCross(val, Cardinals.W) | ||
536 | || Scene.TestBorderCross(val, Cardinals.N) | ||
537 | || Scene.TestBorderCross(val, Cardinals.S)) | ||
520 | && !IsAttachmentCheckFull() && (!Scene.LoadingPrims)) | 538 | && !IsAttachmentCheckFull() && (!Scene.LoadingPrims)) |
521 | { | 539 | { |
522 | IEntityTransferModule entityTransfer = m_scene.RequestModuleInterface<IEntityTransferModule>(); | 540 | IEntityTransferModule entityTransfer = m_scene.RequestModuleInterface<IEntityTransferModule>(); |
@@ -935,6 +953,18 @@ namespace OpenSim.Region.Framework.Scenes | |||
935 | /// </remarks> | 953 | /// </remarks> |
936 | public UUID FromFolderID { get; set; } | 954 | public UUID FromFolderID { get; set; } |
937 | 955 | ||
956 | /// <summary> | ||
957 | /// IDs of all avatars sat on this scene object. | ||
958 | /// </summary> | ||
959 | /// <remarks> | ||
960 | /// We need this so that we can maintain a linkset wide ordering of avatars sat on different parts. | ||
961 | /// This must be locked before it is read or written. | ||
962 | /// SceneObjectPart sitting avatar add/remove code also locks on this object to avoid race conditions. | ||
963 | /// No avatar should appear more than once in this list. | ||
964 | /// Do not manipulate this list directly - use the Add/Remove sitting avatar methods on SceneObjectPart. | ||
965 | /// </remarks> | ||
966 | protected internal List<UUID> m_sittingAvatars = new List<UUID>(); | ||
967 | |||
938 | #endregion | 968 | #endregion |
939 | 969 | ||
940 | // ~SceneObjectGroup() | 970 | // ~SceneObjectGroup() |
@@ -3438,7 +3468,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3438 | 3468 | ||
3439 | public void AdjustChildPrimPermissions() | 3469 | public void AdjustChildPrimPermissions() |
3440 | { | 3470 | { |
3441 | uint newOwnerMask = (uint)PermissionMask.All & 0xfffffff8; // Mask folded bits | 3471 | uint newOwnerMask = (uint)(PermissionMask.All | PermissionMask.Export) & 0xfffffff8; // Mask folded bits |
3442 | uint foldedPerms = RootPart.OwnerMask & 3; | 3472 | uint foldedPerms = RootPart.OwnerMask & 3; |
3443 | 3473 | ||
3444 | ForEachPart(part => | 3474 | ForEachPart(part => |
@@ -4509,17 +4539,28 @@ namespace OpenSim.Region.Framework.Scenes | |||
4509 | } | 4539 | } |
4510 | 4540 | ||
4511 | /// <summary> | 4541 | /// <summary> |
4542 | /// Get a copy of the list of sitting avatars on all prims of this object. | ||
4543 | /// </summary> | ||
4544 | /// <remarks> | ||
4545 | /// This is sorted by the order in which avatars sat down. If an avatar stands up then all avatars that sat | ||
4546 | /// down after it move one place down the list. | ||
4547 | /// </remarks> | ||
4548 | /// <returns>A list of the sitting avatars. Returns an empty list if there are no sitting avatars.</returns> | ||
4549 | public List<UUID> GetSittingAvatars() | ||
4550 | { | ||
4551 | lock (m_sittingAvatars) | ||
4552 | return new List<UUID>(m_sittingAvatars); | ||
4553 | } | ||
4554 | |||
4555 | /// <summary> | ||
4512 | /// Gets the number of sitting avatars. | 4556 | /// Gets the number of sitting avatars. |
4513 | /// </summary> | 4557 | /// </summary> |
4514 | /// <remarks>This applies to all sitting avatars whether there is a sit target set or not.</remarks> | 4558 | /// <remarks>This applies to all sitting avatars whether there is a sit target set or not.</remarks> |
4515 | /// <returns></returns> | 4559 | /// <returns></returns> |
4516 | public int GetSittingAvatarsCount() | 4560 | public int GetSittingAvatarsCount() |
4517 | { | 4561 | { |
4518 | int count = 0; | 4562 | lock (m_sittingAvatars) |
4519 | 4563 | return m_sittingAvatars.Count; | |
4520 | Array.ForEach<SceneObjectPart>(m_parts.GetArray(), p => count += p.GetSittingAvatarsCount()); | ||
4521 | |||
4522 | return count; | ||
4523 | } | 4564 | } |
4524 | 4565 | ||
4525 | public override string ToString() | 4566 | public override string ToString() |
@@ -4528,7 +4569,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
4528 | } | 4569 | } |
4529 | 4570 | ||
4530 | #region ISceneObject | 4571 | #region ISceneObject |
4531 | 4572 | ||
4532 | public virtual ISceneObject CloneForNewScene() | 4573 | public virtual ISceneObject CloneForNewScene() |
4533 | { | 4574 | { |
4534 | SceneObjectGroup sog = Copy(false); | 4575 | SceneObjectGroup sog = Copy(false); |
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 8528edc..42644dc 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | |||
@@ -37,11 +37,13 @@ using System.Xml.Serialization; | |||
37 | using log4net; | 37 | using log4net; |
38 | using OpenMetaverse; | 38 | using OpenMetaverse; |
39 | using OpenMetaverse.Packets; | 39 | using OpenMetaverse.Packets; |
40 | using OpenMetaverse.StructuredData; | ||
40 | using OpenSim.Framework; | 41 | using OpenSim.Framework; |
41 | using OpenSim.Region.Framework.Interfaces; | 42 | using OpenSim.Region.Framework.Interfaces; |
42 | using OpenSim.Region.Framework.Scenes.Scripting; | 43 | using OpenSim.Region.Framework.Scenes.Scripting; |
43 | using OpenSim.Region.Framework.Scenes.Serialization; | 44 | using OpenSim.Region.Framework.Scenes.Serialization; |
44 | using OpenSim.Region.Physics.Manager; | 45 | using OpenSim.Region.Physics.Manager; |
46 | using PermissionMask = OpenSim.Framework.PermissionMask; | ||
45 | 47 | ||
46 | namespace OpenSim.Region.Framework.Scenes | 48 | namespace OpenSim.Region.Framework.Scenes |
47 | { | 49 | { |
@@ -116,7 +118,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
116 | 118 | ||
117 | #endregion Enumerations | 119 | #endregion Enumerations |
118 | 120 | ||
119 | public class SceneObjectPart : IScriptHost, ISceneEntity | 121 | public class SceneObjectPart : ISceneEntity |
120 | { | 122 | { |
121 | /// <value> | 123 | /// <value> |
122 | /// Denote all sides of the prim | 124 | /// Denote all sides of the prim |
@@ -136,6 +138,32 @@ namespace OpenSim.Region.Framework.Scenes | |||
136 | 138 | ||
137 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 139 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
138 | 140 | ||
141 | /// <summary> | ||
142 | /// Dynamic attributes can be created and deleted as required. | ||
143 | /// </summary> | ||
144 | public DAMap DynAttrs { get; set; } | ||
145 | |||
146 | private DOMap m_dynObjs; | ||
147 | |||
148 | /// <summary> | ||
149 | /// Dynamic objects that can be created and deleted as required. | ||
150 | /// </summary> | ||
151 | public DOMap DynObjs | ||
152 | { | ||
153 | get | ||
154 | { | ||
155 | if (m_dynObjs == null) | ||
156 | m_dynObjs = new DOMap(); | ||
157 | |||
158 | return m_dynObjs; | ||
159 | } | ||
160 | |||
161 | set | ||
162 | { | ||
163 | m_dynObjs = value; | ||
164 | } | ||
165 | } | ||
166 | |||
139 | /// <value> | 167 | /// <value> |
140 | /// Is this a root part? | 168 | /// Is this a root part? |
141 | /// </value> | 169 | /// </value> |
@@ -386,6 +414,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
386 | m_particleSystem = Utils.EmptyBytes; | 414 | m_particleSystem = Utils.EmptyBytes; |
387 | Rezzed = DateTime.UtcNow; | 415 | Rezzed = DateTime.UtcNow; |
388 | Description = String.Empty; | 416 | Description = String.Empty; |
417 | DynAttrs = new DAMap(); | ||
389 | 418 | ||
390 | // Prims currently only contain a single folder (Contents). From looking at the Second Life protocol, | 419 | // Prims currently only contain a single folder (Contents). From looking at the Second Life protocol, |
391 | // this appears to have the same UUID (!) as the prim. If this isn't the case, one can't drag items from | 420 | // this appears to have the same UUID (!) as the prim. If this isn't the case, one can't drag items from |
@@ -441,8 +470,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
441 | private uint _category; | 470 | private uint _category; |
442 | private Int32 _creationDate; | 471 | private Int32 _creationDate; |
443 | private uint _parentID = 0; | 472 | private uint _parentID = 0; |
444 | private uint _baseMask = (uint)PermissionMask.All; | 473 | private uint _baseMask = (uint)(PermissionMask.All | PermissionMask.Export); |
445 | private uint _ownerMask = (uint)PermissionMask.All; | 474 | private uint _ownerMask = (uint)(PermissionMask.All | PermissionMask.Export); |
446 | private uint _groupMask = (uint)PermissionMask.None; | 475 | private uint _groupMask = (uint)PermissionMask.None; |
447 | private uint _everyoneMask = (uint)PermissionMask.None; | 476 | private uint _everyoneMask = (uint)PermissionMask.None; |
448 | private uint _nextOwnerMask = (uint)(PermissionMask.Move | PermissionMask.Modify | PermissionMask.Transfer); | 477 | private uint _nextOwnerMask = (uint)(PermissionMask.Move | PermissionMask.Modify | PermissionMask.Transfer); |
@@ -1342,7 +1371,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1342 | public UUID SitTargetAvatar { get; set; } | 1371 | public UUID SitTargetAvatar { get; set; } |
1343 | 1372 | ||
1344 | /// <summary> | 1373 | /// <summary> |
1345 | /// IDs of all avatars start on this object part. | 1374 | /// IDs of all avatars sat on this part. |
1346 | /// </summary> | 1375 | /// </summary> |
1347 | /// <remarks> | 1376 | /// <remarks> |
1348 | /// We need to track this so that we can stop sat upon prims from being attached. | 1377 | /// We need to track this so that we can stop sat upon prims from being attached. |
@@ -1689,6 +1718,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
1689 | 1718 | ||
1690 | if (ParentGroup != null) | 1719 | if (ParentGroup != null) |
1691 | ParentGroup.HasGroupChanged = true; | 1720 | ParentGroup.HasGroupChanged = true; |
1721 | |||
1722 | PhysicsActor pa = PhysActor; | ||
1723 | if (pa != null) | ||
1724 | pa.Density = Density; | ||
1692 | } | 1725 | } |
1693 | } | 1726 | } |
1694 | 1727 | ||
@@ -1708,6 +1741,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
1708 | if (ParentGroup != null) | 1741 | if (ParentGroup != null) |
1709 | ParentGroup.HasGroupChanged = true; | 1742 | ParentGroup.HasGroupChanged = true; |
1710 | 1743 | ||
1744 | PhysicsActor pa = PhysActor; | ||
1745 | if (pa != null) | ||
1746 | pa.GravModifier = GravityModifier; | ||
1711 | } | 1747 | } |
1712 | } | 1748 | } |
1713 | 1749 | ||
@@ -1726,10 +1762,14 @@ namespace OpenSim.Region.Framework.Scenes | |||
1726 | 1762 | ||
1727 | if (ParentGroup != null) | 1763 | if (ParentGroup != null) |
1728 | ParentGroup.HasGroupChanged = true; | 1764 | ParentGroup.HasGroupChanged = true; |
1765 | |||
1766 | PhysicsActor pa = PhysActor; | ||
1767 | if (pa != null) | ||
1768 | pa.Friction = Friction; | ||
1729 | } | 1769 | } |
1730 | } | 1770 | } |
1731 | 1771 | ||
1732 | public float Bounciness | 1772 | public float Restitution |
1733 | { | 1773 | { |
1734 | get { return m_bounce; } | 1774 | get { return m_bounce; } |
1735 | set | 1775 | set |
@@ -1744,6 +1784,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
1744 | 1784 | ||
1745 | if (ParentGroup != null) | 1785 | if (ParentGroup != null) |
1746 | ParentGroup.HasGroupChanged = true; | 1786 | ParentGroup.HasGroupChanged = true; |
1787 | |||
1788 | PhysicsActor pa = PhysActor; | ||
1789 | if (pa != null) | ||
1790 | pa.Restitution = Restitution; | ||
1747 | } | 1791 | } |
1748 | } | 1792 | } |
1749 | 1793 | ||
@@ -2118,6 +2162,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
2118 | // safeguard actual copy is done in sog.copy | 2162 | // safeguard actual copy is done in sog.copy |
2119 | dupe.KeyframeMotion = null; | 2163 | dupe.KeyframeMotion = null; |
2120 | 2164 | ||
2165 | dupe.DynAttrs.CopyFrom(DynAttrs); | ||
2166 | |||
2121 | if (userExposed) | 2167 | if (userExposed) |
2122 | { | 2168 | { |
2123 | /* | 2169 | /* |
@@ -2431,11 +2477,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
2431 | public int GetAxisRotation(int axis) | 2477 | public int GetAxisRotation(int axis) |
2432 | { | 2478 | { |
2433 | //Cannot use ScriptBaseClass constants as no referance to it currently. | 2479 | //Cannot use ScriptBaseClass constants as no referance to it currently. |
2434 | if (axis == 2)//STATUS_ROTATE_X | 2480 | if (axis == (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_X) |
2435 | return STATUS_ROTATE_X; | 2481 | return STATUS_ROTATE_X; |
2436 | if (axis == 4)//STATUS_ROTATE_Y | 2482 | if (axis == (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Y) |
2437 | return STATUS_ROTATE_Y; | 2483 | return STATUS_ROTATE_Y; |
2438 | if (axis == 8)//STATUS_ROTATE_Z | 2484 | if (axis == (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Z) |
2439 | return STATUS_ROTATE_Z; | 2485 | return STATUS_ROTATE_Z; |
2440 | 2486 | ||
2441 | return 0; | 2487 | return 0; |
@@ -2470,18 +2516,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
2470 | return new Vector3(0, 0, 0); | 2516 | return new Vector3(0, 0, 0); |
2471 | 2517 | ||
2472 | return ParentGroup.GetGeometricCenter(); | 2518 | return ParentGroup.GetGeometricCenter(); |
2473 | |||
2474 | /* | ||
2475 | PhysicsActor pa = PhysActor; | ||
2476 | |||
2477 | if (pa != null) | ||
2478 | { | ||
2479 | Vector3 vtmp = pa.CenterOfMass; | ||
2480 | return vtmp; | ||
2481 | } | ||
2482 | else | ||
2483 | return new Vector3(0, 0, 0); | ||
2484 | */ | ||
2485 | } | 2519 | } |
2486 | 2520 | ||
2487 | public float GetMass() | 2521 | public float GetMass() |
@@ -2895,11 +2929,14 @@ namespace OpenSim.Region.Framework.Scenes | |||
2895 | 2929 | ||
2896 | public void PhysicsOutOfBounds(Vector3 pos) | 2930 | public void PhysicsOutOfBounds(Vector3 pos) |
2897 | { | 2931 | { |
2898 | m_log.Error("[PHYSICS]: Physical Object went out of bounds."); | 2932 | // Note: This is only being called on the root prim at this time. |
2933 | |||
2934 | m_log.ErrorFormat( | ||
2935 | "[SCENE OBJECT PART]: Physical object {0}, localID {1} went out of bounds at {2} in {3}. Stopping at {4} and making non-physical.", | ||
2936 | Name, LocalId, pos, ParentGroup.Scene.Name, AbsolutePosition); | ||
2899 | 2937 | ||
2900 | RemFlag(PrimFlags.Physics); | 2938 | RemFlag(PrimFlags.Physics); |
2901 | DoPhysicsPropertyUpdate(false, true); | 2939 | DoPhysicsPropertyUpdate(false, true); |
2902 | //ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(PhysActor); | ||
2903 | } | 2940 | } |
2904 | 2941 | ||
2905 | public void PhysicsRequestingTerseUpdate() | 2942 | public void PhysicsRequestingTerseUpdate() |
@@ -3322,13 +3359,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
3322 | ParentGroup.SetAxisRotation(axis, rotate); | 3359 | ParentGroup.SetAxisRotation(axis, rotate); |
3323 | 3360 | ||
3324 | //Cannot use ScriptBaseClass constants as no referance to it currently. | 3361 | //Cannot use ScriptBaseClass constants as no referance to it currently. |
3325 | if (axis == 2)//STATUS_ROTATE_X | 3362 | if ((axis & (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_X) != 0) |
3326 | STATUS_ROTATE_X = rotate; | 3363 | STATUS_ROTATE_X = rotate; |
3327 | 3364 | ||
3328 | if (axis == 4)//STATUS_ROTATE_Y | 3365 | if ((axis & (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Y) != 0) |
3329 | STATUS_ROTATE_Y = rotate; | 3366 | STATUS_ROTATE_Y = rotate; |
3330 | 3367 | ||
3331 | if (axis == 8)//STATUS_ROTATE_Z | 3368 | if ((axis & (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Z) != 0) |
3332 | STATUS_ROTATE_Z = rotate; | 3369 | STATUS_ROTATE_Z = rotate; |
3333 | } | 3370 | } |
3334 | 3371 | ||
@@ -3706,6 +3743,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
3706 | /// <param name="events"></param> | 3743 | /// <param name="events"></param> |
3707 | public void SetScriptEvents(UUID scriptid, int events) | 3744 | public void SetScriptEvents(UUID scriptid, int events) |
3708 | { | 3745 | { |
3746 | // m_log.DebugFormat( | ||
3747 | // "[SCENE OBJECT PART]: Set script events for script with id {0} on {1}/{2} to {3} in {4}", | ||
3748 | // scriptid, Name, ParentGroup.Name, events, ParentGroup.Scene.Name); | ||
3749 | |||
3709 | // scriptEvents oldparts; | 3750 | // scriptEvents oldparts; |
3710 | lock (m_scriptEvents) | 3751 | lock (m_scriptEvents) |
3711 | { | 3752 | { |
@@ -4235,6 +4276,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
4235 | result.distance = distance2; | 4276 | result.distance = distance2; |
4236 | result.HitTF = true; | 4277 | result.HitTF = true; |
4237 | result.ipoint = q; | 4278 | result.ipoint = q; |
4279 | result.face = i; | ||
4238 | //m_log.Info("[FACE]:" + i.ToString()); | 4280 | //m_log.Info("[FACE]:" + i.ToString()); |
4239 | //m_log.Info("[POINT]: " + q.ToString()); | 4281 | //m_log.Info("[POINT]: " + q.ToString()); |
4240 | //m_log.Info("[DIST]: " + distance2.ToString()); | 4282 | //m_log.Info("[DIST]: " + distance2.ToString()); |
@@ -4281,10 +4323,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
4281 | 4323 | ||
4282 | public void TrimPermissions() | 4324 | public void TrimPermissions() |
4283 | { | 4325 | { |
4284 | BaseMask &= (uint)PermissionMask.All; | 4326 | BaseMask &= (uint)(PermissionMask.All | PermissionMask.Export); |
4285 | OwnerMask &= (uint)PermissionMask.All; | 4327 | OwnerMask &= (uint)(PermissionMask.All | PermissionMask.Export); |
4286 | GroupMask &= (uint)PermissionMask.All; | 4328 | GroupMask &= (uint)PermissionMask.All; |
4287 | EveryoneMask &= (uint)PermissionMask.All; | 4329 | EveryoneMask &= (uint)(PermissionMask.All | PermissionMask.Export); |
4288 | NextOwnerMask &= (uint)PermissionMask.All; | 4330 | NextOwnerMask &= (uint)PermissionMask.All; |
4289 | } | 4331 | } |
4290 | 4332 | ||
@@ -4387,10 +4429,22 @@ namespace OpenSim.Region.Framework.Scenes | |||
4387 | baseMask; | 4429 | baseMask; |
4388 | break; | 4430 | break; |
4389 | case 8: | 4431 | case 8: |
4432 | // Trying to set export permissions - extra checks | ||
4433 | if (set && (mask & (uint)PermissionMask.Export) != 0) | ||
4434 | { | ||
4435 | if ((OwnerMask & (uint)PermissionMask.Export) == 0 || (BaseMask & (uint)PermissionMask.Export) == 0 || (NextOwnerMask & (uint)PermissionMask.All) != (uint)PermissionMask.All) | ||
4436 | mask &= ~(uint)PermissionMask.Export; | ||
4437 | } | ||
4390 | EveryoneMask = ApplyMask(EveryoneMask, set, mask) & | 4438 | EveryoneMask = ApplyMask(EveryoneMask, set, mask) & |
4391 | baseMask; | 4439 | baseMask; |
4392 | break; | 4440 | break; |
4393 | case 16: | 4441 | case 16: |
4442 | // Force full perm if export | ||
4443 | if ((EveryoneMask & (uint)PermissionMask.Export) != 0) | ||
4444 | { | ||
4445 | NextOwnerMask = (uint)PermissionMask.All; | ||
4446 | break; | ||
4447 | } | ||
4394 | NextOwnerMask = ApplyMask(NextOwnerMask, set, mask) & | 4448 | NextOwnerMask = ApplyMask(NextOwnerMask, set, mask) & |
4395 | baseMask; | 4449 | baseMask; |
4396 | // Prevent the client from creating no copy, no transfer | 4450 | // Prevent the client from creating no copy, no transfer |
@@ -4493,8 +4547,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
4493 | GravityModifier = physdata.GravitationModifier; | 4547 | GravityModifier = physdata.GravitationModifier; |
4494 | if(Friction != physdata.Friction) | 4548 | if(Friction != physdata.Friction) |
4495 | Friction = physdata.Friction; | 4549 | Friction = physdata.Friction; |
4496 | if(Bounciness != physdata.Bounce) | 4550 | if(Restitution != physdata.Bounce) |
4497 | Bounciness = physdata.Bounce; | 4551 | Restitution = physdata.Bounce; |
4498 | } | 4552 | } |
4499 | /// <summary> | 4553 | /// <summary> |
4500 | /// Update the flags on this prim. This covers properties such as phantom, physics and temporary. | 4554 | /// Update the flags on this prim. This covers properties such as phantom, physics and temporary. |
@@ -4558,7 +4612,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
4558 | if (ParentGroup.RootPart == this) | 4612 | if (ParentGroup.RootPart == this) |
4559 | AngularVelocity = new Vector3(0, 0, 0); | 4613 | AngularVelocity = new Vector3(0, 0, 0); |
4560 | } | 4614 | } |
4561 | else | 4615 | |
4616 | else | ||
4562 | { | 4617 | { |
4563 | if (ParentGroup.Scene.CollidablePrims) | 4618 | if (ParentGroup.Scene.CollidablePrims) |
4564 | { | 4619 | { |
@@ -4604,9 +4659,31 @@ namespace OpenSim.Region.Framework.Scenes | |||
4604 | UpdatePhysicsSubscribedEvents(); | 4659 | UpdatePhysicsSubscribedEvents(); |
4605 | } | 4660 | } |
4606 | } | 4661 | } |
4607 | 4662 | if (SetVD) | |
4663 | { | ||
4664 | // If the above logic worked (this is urgent candidate to unit tests!) | ||
4665 | // we now have a physicsactor. | ||
4666 | // Defensive programming calls for a check here. | ||
4667 | // Better would be throwing an exception that could be catched by a unit test as the internal | ||
4668 | // logic should make sure, this Physactor is always here. | ||
4669 | if (pa != null) | ||
4670 | { | ||
4671 | pa.SetVolumeDetect(1); | ||
4672 | AddFlag(PrimFlags.Phantom); // We set this flag also if VD is active | ||
4673 | VolumeDetectActive = true; | ||
4674 | } | ||
4608 | // m_log.Debug("Update: PHY:" + UsePhysics.ToString() + ", T:" + IsTemporary.ToString() + ", PHA:" + IsPhantom.ToString() + " S:" + CastsShadows.ToString()); | 4675 | // m_log.Debug("Update: PHY:" + UsePhysics.ToString() + ", T:" + IsTemporary.ToString() + ", PHA:" + IsPhantom.ToString() + " S:" + CastsShadows.ToString()); |
4676 | } | ||
4677 | else if (SetVD != wasVD) | ||
4678 | { | ||
4679 | // Remove VolumeDetect in any case. Note, it's safe to call SetVolumeDetect as often as you like | ||
4680 | // (mumbles, well, at least if you have infinte CPU powers :-)) | ||
4681 | if (pa != null) | ||
4682 | pa.SetVolumeDetect(0); | ||
4609 | 4683 | ||
4684 | RemFlag(PrimFlags.Phantom); | ||
4685 | VolumeDetectActive = false; | ||
4686 | } | ||
4610 | // and last in case we have a new actor and not building | 4687 | // and last in case we have a new actor and not building |
4611 | 4688 | ||
4612 | if (ParentGroup != null) | 4689 | if (ParentGroup != null) |
@@ -4646,9 +4723,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
4646 | PhysicsShapeType, | 4723 | PhysicsShapeType, |
4647 | m_localId); | 4724 | m_localId); |
4648 | } | 4725 | } |
4649 | catch (Exception ex) | 4726 | catch (Exception e) |
4650 | { | 4727 | { |
4651 | m_log.ErrorFormat("[SCENE]: AddToPhysics object {0} failed: {1}", m_uuid, ex.Message); | 4728 | m_log.ErrorFormat("[SCENE]: caught exception meshing object {0}. Object set to phantom. e={1}", m_uuid, e); |
4652 | pa = null; | 4729 | pa = null; |
4653 | } | 4730 | } |
4654 | 4731 | ||
@@ -4657,6 +4734,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
4657 | pa.SOPName = this.Name; // save object into the PhysActor so ODE internals know the joint/body info | 4734 | pa.SOPName = this.Name; // save object into the PhysActor so ODE internals know the joint/body info |
4658 | pa.SetMaterial(Material); | 4735 | pa.SetMaterial(Material); |
4659 | 4736 | ||
4737 | pa.Density = Density; | ||
4738 | pa.GravModifier = GravityModifier; | ||
4739 | pa.Friction = Friction; | ||
4740 | pa.Restitution = Restitution; | ||
4741 | |||
4660 | if (VolumeDetectActive) // change if not the default only | 4742 | if (VolumeDetectActive) // change if not the default only |
4661 | pa.SetVolumeDetect(1); | 4743 | pa.SetVolumeDetect(1); |
4662 | 4744 | ||
@@ -4717,7 +4799,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
4717 | } | 4799 | } |
4718 | 4800 | ||
4719 | PhysActor = pa; | 4801 | PhysActor = pa; |
4720 | } | 4802 | |
4803 | ParentGroup.Scene.EventManager.TriggerObjectAddedToPhysicalScene(this); | ||
4804 | } | ||
4721 | 4805 | ||
4722 | /// <summary> | 4806 | /// <summary> |
4723 | /// This removes the part from the physics scene. | 4807 | /// This removes the part from the physics scene. |
@@ -4736,6 +4820,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
4736 | pa.OnOutOfBounds -= PhysicsOutOfBounds; | 4820 | pa.OnOutOfBounds -= PhysicsOutOfBounds; |
4737 | 4821 | ||
4738 | ParentGroup.Scene.PhysicsScene.RemovePrim(pa); | 4822 | ParentGroup.Scene.PhysicsScene.RemovePrim(pa); |
4823 | |||
4824 | ParentGroup.Scene.EventManager.TriggerObjectRemovedFromPhysicalScene(this); | ||
4739 | } | 4825 | } |
4740 | PhysActor = null; | 4826 | PhysActor = null; |
4741 | } | 4827 | } |
@@ -4911,8 +4997,25 @@ namespace OpenSim.Region.Framework.Scenes | |||
4911 | 4997 | ||
4912 | Changed changeFlags = 0; | 4998 | Changed changeFlags = 0; |
4913 | 4999 | ||
5000 | Primitive.TextureEntryFace fallbackNewFace = newTex.DefaultTexture; | ||
5001 | Primitive.TextureEntryFace fallbackOldFace = oldTex.DefaultTexture; | ||
5002 | |||
5003 | // On Incoming packets, sometimes newText.DefaultTexture is null. The assumption is that all | ||
5004 | // other prim-sides are set, but apparently that's not always the case. Lets assume packet/data corruption at this point. | ||
5005 | if (fallbackNewFace == null) | ||
5006 | { | ||
5007 | fallbackNewFace = new Primitive.TextureEntry(Util.BLANK_TEXTURE_UUID).CreateFace(0); | ||
5008 | newTex.DefaultTexture = fallbackNewFace; | ||
5009 | } | ||
5010 | if (fallbackOldFace == null) | ||
5011 | { | ||
5012 | fallbackOldFace = new Primitive.TextureEntry(Util.BLANK_TEXTURE_UUID).CreateFace(0); | ||
5013 | oldTex.DefaultTexture = fallbackOldFace; | ||
5014 | } | ||
5015 | |||
4914 | for (int i = 0 ; i < GetNumberOfSides(); i++) | 5016 | for (int i = 0 ; i < GetNumberOfSides(); i++) |
4915 | { | 5017 | { |
5018 | |||
4916 | Primitive.TextureEntryFace newFace = newTex.DefaultTexture; | 5019 | Primitive.TextureEntryFace newFace = newTex.DefaultTexture; |
4917 | Primitive.TextureEntryFace oldFace = oldTex.DefaultTexture; | 5020 | Primitive.TextureEntryFace oldFace = oldTex.DefaultTexture; |
4918 | 5021 | ||
@@ -5138,9 +5241,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
5138 | 5241 | ||
5139 | public void ApplyNextOwnerPermissions() | 5242 | public void ApplyNextOwnerPermissions() |
5140 | { | 5243 | { |
5141 | BaseMask &= NextOwnerMask; | 5244 | // Export needs to be preserved in the base and everyone |
5245 | // mask, but removed in the owner mask as a next owner | ||
5246 | // can never change the export status | ||
5247 | BaseMask &= NextOwnerMask | (uint)PermissionMask.Export; | ||
5142 | OwnerMask &= NextOwnerMask; | 5248 | OwnerMask &= NextOwnerMask; |
5143 | EveryoneMask &= NextOwnerMask; | 5249 | EveryoneMask &= NextOwnerMask | (uint)PermissionMask.Export; |
5144 | 5250 | ||
5145 | Inventory.ApplyNextOwnerPermissions(); | 5251 | Inventory.ApplyNextOwnerPermissions(); |
5146 | } | 5252 | } |
@@ -5202,18 +5308,22 @@ namespace OpenSim.Region.Framework.Scenes | |||
5202 | /// <param name='avatarId'></param> | 5308 | /// <param name='avatarId'></param> |
5203 | protected internal bool AddSittingAvatar(UUID avatarId) | 5309 | protected internal bool AddSittingAvatar(UUID avatarId) |
5204 | { | 5310 | { |
5205 | if (IsSitTargetSet && SitTargetAvatar == UUID.Zero) | 5311 | lock (ParentGroup.m_sittingAvatars) |
5206 | SitTargetAvatar = avatarId; | 5312 | { |
5313 | if (IsSitTargetSet && SitTargetAvatar == UUID.Zero) | ||
5314 | SitTargetAvatar = avatarId; | ||
5207 | 5315 | ||
5208 | HashSet<UUID> sittingAvatars = m_sittingAvatars; | 5316 | if (m_sittingAvatars == null) |
5317 | m_sittingAvatars = new HashSet<UUID>(); | ||
5209 | 5318 | ||
5210 | if (sittingAvatars == null) | 5319 | if (m_sittingAvatars.Add(avatarId)) |
5211 | sittingAvatars = new HashSet<UUID>(); | 5320 | { |
5321 | ParentGroup.m_sittingAvatars.Add(avatarId); | ||
5212 | 5322 | ||
5213 | lock (sittingAvatars) | 5323 | return true; |
5214 | { | 5324 | } |
5215 | m_sittingAvatars = sittingAvatars; | 5325 | |
5216 | return m_sittingAvatars.Add(avatarId); | 5326 | return false; |
5217 | } | 5327 | } |
5218 | } | 5328 | } |
5219 | 5329 | ||
@@ -5227,27 +5337,26 @@ namespace OpenSim.Region.Framework.Scenes | |||
5227 | /// <param name='avatarId'></param> | 5337 | /// <param name='avatarId'></param> |
5228 | protected internal bool RemoveSittingAvatar(UUID avatarId) | 5338 | protected internal bool RemoveSittingAvatar(UUID avatarId) |
5229 | { | 5339 | { |
5230 | if (SitTargetAvatar == avatarId) | 5340 | lock (ParentGroup.m_sittingAvatars) |
5231 | SitTargetAvatar = UUID.Zero; | 5341 | { |
5232 | 5342 | if (SitTargetAvatar == avatarId) | |
5233 | HashSet<UUID> sittingAvatars = m_sittingAvatars; | 5343 | SitTargetAvatar = UUID.Zero; |
5234 | 5344 | ||
5235 | // This can occur under a race condition where another thread | 5345 | if (m_sittingAvatars == null) |
5236 | if (sittingAvatars == null) | 5346 | return false; |
5237 | return false; | ||
5238 | 5347 | ||
5239 | lock (sittingAvatars) | 5348 | if (m_sittingAvatars.Remove(avatarId)) |
5240 | { | ||
5241 | if (sittingAvatars.Remove(avatarId)) | ||
5242 | { | 5349 | { |
5243 | if (sittingAvatars.Count == 0) | 5350 | if (m_sittingAvatars.Count == 0) |
5244 | m_sittingAvatars = null; | 5351 | m_sittingAvatars = null; |
5245 | 5352 | ||
5353 | ParentGroup.m_sittingAvatars.Remove(avatarId); | ||
5354 | |||
5246 | return true; | 5355 | return true; |
5247 | } | 5356 | } |
5248 | } | ||
5249 | 5357 | ||
5250 | return false; | 5358 | return false; |
5359 | } | ||
5251 | } | 5360 | } |
5252 | 5361 | ||
5253 | /// <summary> | 5362 | /// <summary> |
@@ -5257,16 +5366,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
5257 | /// <returns>A hashset of the sitting avatars. Returns null if there are no sitting avatars.</returns> | 5366 | /// <returns>A hashset of the sitting avatars. Returns null if there are no sitting avatars.</returns> |
5258 | public HashSet<UUID> GetSittingAvatars() | 5367 | public HashSet<UUID> GetSittingAvatars() |
5259 | { | 5368 | { |
5260 | HashSet<UUID> sittingAvatars = m_sittingAvatars; | 5369 | lock (ParentGroup.m_sittingAvatars) |
5261 | |||
5262 | if (sittingAvatars == null) | ||
5263 | { | ||
5264 | return null; | ||
5265 | } | ||
5266 | else | ||
5267 | { | 5370 | { |
5268 | lock (sittingAvatars) | 5371 | if (m_sittingAvatars == null) |
5269 | return new HashSet<UUID>(sittingAvatars); | 5372 | return null; |
5373 | else | ||
5374 | return new HashSet<UUID>(m_sittingAvatars); | ||
5270 | } | 5375 | } |
5271 | } | 5376 | } |
5272 | 5377 | ||
@@ -5277,13 +5382,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
5277 | /// <returns></returns> | 5382 | /// <returns></returns> |
5278 | public int GetSittingAvatarsCount() | 5383 | public int GetSittingAvatarsCount() |
5279 | { | 5384 | { |
5280 | HashSet<UUID> sittingAvatars = m_sittingAvatars; | 5385 | lock (ParentGroup.m_sittingAvatars) |
5281 | 5386 | { | |
5282 | if (sittingAvatars == null) | 5387 | if (m_sittingAvatars == null) |
5283 | return 0; | 5388 | return 0; |
5284 | 5389 | else | |
5285 | lock (sittingAvatars) | 5390 | return m_sittingAvatars.Count; |
5286 | return sittingAvatars.Count; | 5391 | } |
5287 | } | 5392 | } |
5288 | } | 5393 | } |
5289 | } | 5394 | } |
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs index 3a9a146..d04d87b 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs | |||
@@ -38,6 +38,7 @@ using OpenSim.Framework; | |||
38 | using OpenSim.Region.Framework.Interfaces; | 38 | using OpenSim.Region.Framework.Interfaces; |
39 | using OpenSim.Region.Framework.Scenes.Scripting; | 39 | using OpenSim.Region.Framework.Scenes.Scripting; |
40 | using OpenSim.Region.Framework.Scenes.Serialization; | 40 | using OpenSim.Region.Framework.Scenes.Serialization; |
41 | using PermissionMask = OpenSim.Framework.PermissionMask; | ||
41 | 42 | ||
42 | namespace OpenSim.Region.Framework.Scenes | 43 | namespace OpenSim.Region.Framework.Scenes |
43 | { | 44 | { |
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index a9195f7..0ab267a 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs | |||
@@ -204,6 +204,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
204 | 204 | ||
205 | private const int LAND_VELOCITYMAG_MAX = 12; | 205 | private const int LAND_VELOCITYMAG_MAX = 12; |
206 | 206 | ||
207 | private const float FLY_ROLL_MAX_RADIANS = 1.1f; | ||
208 | |||
209 | private const float FLY_ROLL_RADIANS_PER_UPDATE = 0.06f; | ||
210 | private const float FLY_ROLL_RESET_RADIANS_PER_UPDATE = 0.02f; | ||
211 | |||
207 | private float m_health = 100f; | 212 | private float m_health = 100f; |
208 | 213 | ||
209 | protected ulong crossingFromRegion; | 214 | protected ulong crossingFromRegion; |
@@ -216,8 +221,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
216 | 221 | ||
217 | private Quaternion m_headrotation = Quaternion.Identity; | 222 | private Quaternion m_headrotation = Quaternion.Identity; |
218 | 223 | ||
219 | private string m_nextSitAnimation = String.Empty; | ||
220 | |||
221 | //PauPaw:Proper PID Controler for autopilot************ | 224 | //PauPaw:Proper PID Controler for autopilot************ |
222 | public bool MovingToTarget { get; private set; } | 225 | public bool MovingToTarget { get; private set; } |
223 | public Vector3 MoveToPositionTarget { get; private set; } | 226 | public Vector3 MoveToPositionTarget { get; private set; } |
@@ -438,6 +441,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
438 | get { return (IClientCore)ControllingClient; } | 441 | get { return (IClientCore)ControllingClient; } |
439 | } | 442 | } |
440 | 443 | ||
444 | public UUID COF { get; set; } | ||
445 | |||
441 | // public Vector3 ParentPosition { get; set; } | 446 | // public Vector3 ParentPosition { get; set; } |
442 | 447 | ||
443 | /// <summary> | 448 | /// <summary> |
@@ -451,9 +456,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
451 | { | 456 | { |
452 | m_pos = PhysicsActor.Position; | 457 | m_pos = PhysicsActor.Position; |
453 | 458 | ||
454 | //m_log.DebugFormat( | 459 | // m_log.DebugFormat( |
455 | // "[SCENE PRESENCE]: Set position {0} for {1} in {2} via getting AbsolutePosition!", | 460 | // "[SCENE PRESENCE]: Set position of {0} in {1} to {2} via getting AbsolutePosition!", |
456 | // m_pos, Name, Scene.RegionInfo.RegionName); | 461 | // Name, Scene.Name, m_pos); |
457 | } | 462 | } |
458 | else | 463 | else |
459 | { | 464 | { |
@@ -480,6 +485,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
480 | } | 485 | } |
481 | set | 486 | set |
482 | { | 487 | { |
488 | // m_log.DebugFormat("[SCENE PRESENCE]: Setting position of {0} in {1} to {2}", Name, Scene.Name, value); | ||
489 | // Util.PrintCallStack(); | ||
490 | |||
483 | if (PhysicsActor != null) | 491 | if (PhysicsActor != null) |
484 | { | 492 | { |
485 | try | 493 | try |
@@ -585,27 +593,48 @@ namespace OpenSim.Region.Framework.Scenes | |||
585 | */ | 593 | */ |
586 | private Quaternion m_bodyRot = Quaternion.Identity; | 594 | private Quaternion m_bodyRot = Quaternion.Identity; |
587 | 595 | ||
596 | /// <summary> | ||
597 | /// The rotation of the avatar. | ||
598 | /// </summary> | ||
599 | /// <remarks> | ||
600 | /// If the avatar is not sitting, this is with respect to the world | ||
601 | /// If the avatar is sitting, this is a with respect to the part that it's sitting upon (a local rotation). | ||
602 | /// If you always want the world rotation, use GetWorldRotation() | ||
603 | /// </remarks> | ||
588 | public Quaternion Rotation | 604 | public Quaternion Rotation |
589 | { | 605 | { |
590 | get { return m_bodyRot; } | 606 | get |
607 | { | ||
608 | return m_bodyRot; | ||
609 | } | ||
610 | |||
591 | set | 611 | set |
592 | { | 612 | { |
593 | m_bodyRot = value; | 613 | m_bodyRot = value; |
594 | // m_log.DebugFormat("[SCENE PRESENCE]: Body rot for {0} set to {1}", Name, m_bodyRot); | 614 | |
595 | if (PhysicsActor != null) | 615 | if (PhysicsActor != null) |
596 | { | 616 | { |
597 | try | 617 | try |
598 | { | 618 | { |
599 | PhysicsActor.Orientation = value; | 619 | PhysicsActor.Orientation = m_bodyRot; |
600 | } | 620 | } |
601 | catch (Exception e) | 621 | catch (Exception e) |
602 | { | 622 | { |
603 | m_log.Error("[SCENE PRESENCE]: Orientation " + e.Message); | 623 | m_log.Error("[SCENE PRESENCE]: Orientation " + e.Message); |
604 | } | 624 | } |
605 | } | 625 | } |
626 | // m_log.DebugFormat("[SCENE PRESENCE]: Body rot for {0} set to {1}", Name, m_bodyRot); | ||
606 | } | 627 | } |
607 | } | 628 | } |
608 | 629 | ||
630 | // Used for limited viewer 'fake' user rotations. | ||
631 | private Vector3 m_AngularVelocity = Vector3.Zero; | ||
632 | |||
633 | public Vector3 AngularVelocity | ||
634 | { | ||
635 | get { return m_AngularVelocity; } | ||
636 | } | ||
637 | |||
609 | public bool IsChildAgent { get; set; } | 638 | public bool IsChildAgent { get; set; } |
610 | public bool IsLoggingIn { get; set; } | 639 | public bool IsLoggingIn { get; set; } |
611 | 640 | ||
@@ -641,6 +670,26 @@ namespace OpenSim.Region.Framework.Scenes | |||
641 | set { m_health = value; } | 670 | set { m_health = value; } |
642 | } | 671 | } |
643 | 672 | ||
673 | /// <summary> | ||
674 | /// Gets the world rotation of this presence. | ||
675 | /// </summary> | ||
676 | /// <remarks> | ||
677 | /// Unlike Rotation, this returns the world rotation no matter whether the avatar is sitting on a prim or not. | ||
678 | /// </remarks> | ||
679 | /// <returns></returns> | ||
680 | public Quaternion GetWorldRotation() | ||
681 | { | ||
682 | if (IsSatOnObject) | ||
683 | { | ||
684 | SceneObjectPart sitPart = ParentPart; | ||
685 | |||
686 | if (sitPart != null) | ||
687 | return sitPart.GetWorldRotation() * Rotation; | ||
688 | } | ||
689 | |||
690 | return Rotation; | ||
691 | } | ||
692 | |||
644 | public void AdjustKnownSeeds() | 693 | public void AdjustKnownSeeds() |
645 | { | 694 | { |
646 | Dictionary<ulong, string> seeds; | 695 | Dictionary<ulong, string> seeds; |
@@ -690,6 +739,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
690 | 739 | ||
691 | private bool m_inTransit; | 740 | private bool m_inTransit; |
692 | 741 | ||
742 | /// <summary> | ||
743 | /// This signals whether the presence is in transit between neighbouring regions. | ||
744 | /// </summary> | ||
745 | /// <remarks> | ||
746 | /// It is not set when the presence is teleporting or logging in/out directly to a region. | ||
747 | /// </remarks> | ||
693 | public bool IsInTransit | 748 | public bool IsInTransit |
694 | { | 749 | { |
695 | get { return m_inTransit; } | 750 | get { return m_inTransit; } |
@@ -886,8 +941,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
886 | "[SCENE]: Upgrading child to root agent for {0} in {1}", | 941 | "[SCENE]: Upgrading child to root agent for {0} in {1}", |
887 | Name, m_scene.RegionInfo.RegionName); | 942 | Name, m_scene.RegionInfo.RegionName); |
888 | 943 | ||
889 | bool wasChild = IsChildAgent; | ||
890 | |||
891 | if (ParentUUID != UUID.Zero) | 944 | if (ParentUUID != UUID.Zero) |
892 | { | 945 | { |
893 | m_log.DebugFormat("[SCENE PRESENCE]: Sitting avatar back on prim {0}", ParentUUID); | 946 | m_log.DebugFormat("[SCENE PRESENCE]: Sitting avatar back on prim {0}", ParentUUID); |
@@ -920,6 +973,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
920 | IsLoggingIn = false; | 973 | IsLoggingIn = false; |
921 | } | 974 | } |
922 | 975 | ||
976 | //m_log.DebugFormat("[SCENE]: known regions in {0}: {1}", Scene.RegionInfo.RegionName, KnownChildRegionHandles.Count); | ||
977 | |||
978 | IsChildAgent = false; | ||
923 | 979 | ||
924 | IGroupsModule gm = m_scene.RequestModuleInterface<IGroupsModule>(); | 980 | IGroupsModule gm = m_scene.RequestModuleInterface<IGroupsModule>(); |
925 | if (gm != null) | 981 | if (gm != null) |
@@ -1013,6 +1069,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
1013 | else | 1069 | else |
1014 | AddToPhysicalScene(isFlying); | 1070 | AddToPhysicalScene(isFlying); |
1015 | 1071 | ||
1072 | // XXX: This is to trigger any secondary teleport needed for a megaregion when the user has teleported to a | ||
1073 | // location outside the 'root region' (the south-west 256x256 corner). This is the earlist we can do it | ||
1074 | // since it requires a physics actor to be present. If it is left any later, then physics appears to reset | ||
1075 | // the value to a negative position which does not trigger the border cross. | ||
1076 | // This may not be the best location for this. | ||
1077 | CheckForBorderCrossing(); | ||
1078 | |||
1016 | if (ForceFly) | 1079 | if (ForceFly) |
1017 | { | 1080 | { |
1018 | Flying = true; | 1081 | Flying = true; |
@@ -1033,22 +1096,43 @@ namespace OpenSim.Region.Framework.Scenes | |||
1033 | // and it has already rezzed the attachments and started their scripts. | 1096 | // and it has already rezzed the attachments and started their scripts. |
1034 | // We do the following only for non-login agents, because their scripts | 1097 | // We do the following only for non-login agents, because their scripts |
1035 | // haven't started yet. | 1098 | // haven't started yet. |
1036 | lock (m_attachments) | 1099 | if (PresenceType == PresenceType.Npc || (TeleportFlags & TeleportFlags.ViaLogin) != 0) |
1037 | { | 1100 | { |
1038 | if (wasChild && HasAttachments()) | 1101 | // Viewers which have a current outfit folder will actually rez their own attachments. However, |
1102 | // viewers without (e.g. v1 viewers) will not, so we still need to make this call. | ||
1103 | if (Scene.AttachmentsModule != null) | ||
1104 | Util.FireAndForget( | ||
1105 | o => | ||
1106 | { | ||
1107 | // if (PresenceType != PresenceType.Npc && Util.FireAndForgetMethod != FireAndForgetMethod.None) | ||
1108 | // System.Threading.Thread.Sleep(7000); | ||
1109 | |||
1110 | Scene.AttachmentsModule.RezAttachments(this); | ||
1111 | }); | ||
1112 | } | ||
1113 | else | ||
1114 | { | ||
1115 | // We need to restart scripts here so that they receive the correct changed events (CHANGED_TELEPORT | ||
1116 | // and CHANGED_REGION) when the attachments have been rezzed in the new region. This cannot currently | ||
1117 | // be done in AttachmentsModule.CopyAttachments(AgentData ad, IScenePresence sp) itself since we are | ||
1118 | // not transporting the required data. | ||
1119 | lock (m_attachments) | ||
1039 | { | 1120 | { |
1040 | m_log.DebugFormat( | 1121 | if (HasAttachments()) |
1041 | "[SCENE PRESENCE]: Restarting scripts in attachments for {0} in {1}", Name, Scene.Name); | 1122 | { |
1042 | 1123 | m_log.DebugFormat( | |
1043 | // Resume scripts | 1124 | "[SCENE PRESENCE]: Restarting scripts in attachments for {0} in {1}", Name, Scene.Name); |
1044 | Util.FireAndForget(delegate(object x) { | 1125 | |
1045 | foreach (SceneObjectGroup sog in m_attachments) | 1126 | // Resume scripts |
1046 | { | 1127 | Util.FireAndForget(delegate(object x) { |
1047 | sog.ScheduleGroupForFullUpdate(); | 1128 | foreach (SceneObjectGroup sog in m_attachments) |
1048 | sog.RootPart.ParentGroup.CreateScriptInstances(0, false, m_scene.DefaultScriptEngine, GetStateSource()); | 1129 | { |
1049 | sog.ResumeScripts(); | 1130 | sog.ScheduleGroupForFullUpdate(); |
1050 | } | 1131 | sog.RootPart.ParentGroup.CreateScriptInstances(0, false, m_scene.DefaultScriptEngine, GetStateSource()); |
1051 | }); | 1132 | sog.ResumeScripts(); |
1133 | } | ||
1134 | }); | ||
1135 | } | ||
1052 | } | 1136 | } |
1053 | } | 1137 | } |
1054 | 1138 | ||
@@ -1225,6 +1309,85 @@ namespace OpenSim.Region.Framework.Scenes | |||
1225 | ControllingClient.StopFlying(this); | 1309 | ControllingClient.StopFlying(this); |
1226 | } | 1310 | } |
1227 | 1311 | ||
1312 | /// <summary> | ||
1313 | /// Applies a roll accumulator to the avatar's angular velocity for the avatar fly roll effect. | ||
1314 | /// </summary> | ||
1315 | /// <param name="amount">Postive or negative roll amount in radians</param> | ||
1316 | private void ApplyFlyingRoll(float amount, bool PressingUp, bool PressingDown) | ||
1317 | { | ||
1318 | |||
1319 | float rollAmount = Util.Clamp(m_AngularVelocity.Z + amount, -FLY_ROLL_MAX_RADIANS, FLY_ROLL_MAX_RADIANS); | ||
1320 | m_AngularVelocity.Z = rollAmount; | ||
1321 | |||
1322 | // APPLY EXTRA consideration for flying up and flying down during this time. | ||
1323 | // if we're turning left | ||
1324 | if (amount > 0) | ||
1325 | { | ||
1326 | |||
1327 | // If we're at the max roll and pressing up, we want to swing BACK a bit | ||
1328 | // Automatically adds noise | ||
1329 | if (PressingUp) | ||
1330 | { | ||
1331 | if (m_AngularVelocity.Z >= FLY_ROLL_MAX_RADIANS - 0.04f) | ||
1332 | m_AngularVelocity.Z -= 0.9f; | ||
1333 | } | ||
1334 | // If we're at the max roll and pressing down, we want to swing MORE a bit | ||
1335 | if (PressingDown) | ||
1336 | { | ||
1337 | if (m_AngularVelocity.Z >= FLY_ROLL_MAX_RADIANS && m_AngularVelocity.Z < FLY_ROLL_MAX_RADIANS + 0.6f) | ||
1338 | m_AngularVelocity.Z += 0.6f; | ||
1339 | } | ||
1340 | } | ||
1341 | else // we're turning right. | ||
1342 | { | ||
1343 | // If we're at the max roll and pressing up, we want to swing BACK a bit | ||
1344 | // Automatically adds noise | ||
1345 | if (PressingUp) | ||
1346 | { | ||
1347 | if (m_AngularVelocity.Z <= (-FLY_ROLL_MAX_RADIANS)) | ||
1348 | m_AngularVelocity.Z += 0.6f; | ||
1349 | } | ||
1350 | // If we're at the max roll and pressing down, we want to swing MORE a bit | ||
1351 | if (PressingDown) | ||
1352 | { | ||
1353 | if (m_AngularVelocity.Z >= -FLY_ROLL_MAX_RADIANS - 0.6f) | ||
1354 | m_AngularVelocity.Z -= 0.6f; | ||
1355 | } | ||
1356 | } | ||
1357 | } | ||
1358 | |||
1359 | /// <summary> | ||
1360 | /// incrementally sets roll amount to zero | ||
1361 | /// </summary> | ||
1362 | /// <param name="amount">Positive roll amount in radians</param> | ||
1363 | /// <returns></returns> | ||
1364 | private float CalculateFlyingRollResetToZero(float amount) | ||
1365 | { | ||
1366 | const float rollMinRadians = 0f; | ||
1367 | |||
1368 | if (m_AngularVelocity.Z > 0) | ||
1369 | { | ||
1370 | |||
1371 | float leftOverToMin = m_AngularVelocity.Z - rollMinRadians; | ||
1372 | if (amount > leftOverToMin) | ||
1373 | return -leftOverToMin; | ||
1374 | else | ||
1375 | return -amount; | ||
1376 | |||
1377 | } | ||
1378 | else | ||
1379 | { | ||
1380 | |||
1381 | float leftOverToMin = -m_AngularVelocity.Z - rollMinRadians; | ||
1382 | if (amount > leftOverToMin) | ||
1383 | return leftOverToMin; | ||
1384 | else | ||
1385 | return amount; | ||
1386 | } | ||
1387 | } | ||
1388 | |||
1389 | |||
1390 | |||
1228 | // neighbouring regions we have enabled a child agent in | 1391 | // neighbouring regions we have enabled a child agent in |
1229 | // holds the seed cap for the child agent in that region | 1392 | // holds the seed cap for the child agent in that region |
1230 | private Dictionary<ulong, string> m_knownChildRegions = new Dictionary<ulong, string>(); | 1393 | private Dictionary<ulong, string> m_knownChildRegions = new Dictionary<ulong, string>(); |
@@ -1398,6 +1561,15 @@ namespace OpenSim.Region.Framework.Scenes | |||
1398 | 1561 | ||
1399 | } | 1562 | } |
1400 | 1563 | ||
1564 | // XXX: If we force an update here, then multiple attachments do appear correctly on a destination region | ||
1565 | // If we do it a little bit earlier (e.g. when converting the child to a root agent) then this does not work. | ||
1566 | // This may be due to viewer code or it may be something we're not doing properly simulator side. | ||
1567 | lock (m_attachments) | ||
1568 | { | ||
1569 | foreach (SceneObjectGroup sog in m_attachments) | ||
1570 | sog.ScheduleGroupForFullUpdate(); | ||
1571 | } | ||
1572 | |||
1401 | // m_log.DebugFormat( | 1573 | // m_log.DebugFormat( |
1402 | // "[SCENE PRESENCE]: Completing movement of {0} into region {1} took {2}ms", | 1574 | // "[SCENE PRESENCE]: Completing movement of {0} into region {1} took {2}ms", |
1403 | // client.Name, Scene.RegionInfo.RegionName, (DateTime.Now - startTime).Milliseconds); | 1575 | // client.Name, Scene.RegionInfo.RegionName, (DateTime.Now - startTime).Milliseconds); |
@@ -1430,17 +1602,42 @@ namespace OpenSim.Region.Framework.Scenes | |||
1430 | m_doingCamRayCast = false; | 1602 | m_doingCamRayCast = false; |
1431 | if (hitYN && localid != LocalId) | 1603 | if (hitYN && localid != LocalId) |
1432 | { | 1604 | { |
1433 | CameraConstraintActive = true; | 1605 | SceneObjectGroup group = m_scene.GetGroupByPrim(localid); |
1434 | pNormal.X = (float)Math.Round(pNormal.X, 2); | 1606 | bool IsPrim = group != null; |
1435 | pNormal.Y = (float)Math.Round(pNormal.Y, 2); | 1607 | if (IsPrim) |
1436 | pNormal.Z = (float)Math.Round(pNormal.Z, 2); | 1608 | { |
1437 | pNormal.Normalize(); | 1609 | SceneObjectPart part = group.GetPart(localid); |
1438 | collisionPoint.X = (float)Math.Round(collisionPoint.X, 1); | 1610 | if (part != null && !part.VolumeDetectActive) |
1439 | collisionPoint.Y = (float)Math.Round(collisionPoint.Y, 1); | 1611 | { |
1440 | collisionPoint.Z = (float)Math.Round(collisionPoint.Z, 1); | 1612 | CameraConstraintActive = true; |
1441 | 1613 | pNormal.X = (float) Math.Round(pNormal.X, 2); | |
1442 | Vector4 plane = new Vector4(pNormal.X, pNormal.Y, pNormal.Z, Vector3.Dot(collisionPoint, pNormal)); | 1614 | pNormal.Y = (float) Math.Round(pNormal.Y, 2); |
1443 | UpdateCameraCollisionPlane(plane); | 1615 | pNormal.Z = (float) Math.Round(pNormal.Z, 2); |
1616 | pNormal.Normalize(); | ||
1617 | collisionPoint.X = (float) Math.Round(collisionPoint.X, 1); | ||
1618 | collisionPoint.Y = (float) Math.Round(collisionPoint.Y, 1); | ||
1619 | collisionPoint.Z = (float) Math.Round(collisionPoint.Z, 1); | ||
1620 | |||
1621 | Vector4 plane = new Vector4(pNormal.X, pNormal.Y, pNormal.Z, | ||
1622 | Vector3.Dot(collisionPoint, pNormal)); | ||
1623 | UpdateCameraCollisionPlane(plane); | ||
1624 | } | ||
1625 | } | ||
1626 | else | ||
1627 | { | ||
1628 | CameraConstraintActive = true; | ||
1629 | pNormal.X = (float) Math.Round(pNormal.X, 2); | ||
1630 | pNormal.Y = (float) Math.Round(pNormal.Y, 2); | ||
1631 | pNormal.Z = (float) Math.Round(pNormal.Z, 2); | ||
1632 | pNormal.Normalize(); | ||
1633 | collisionPoint.X = (float) Math.Round(collisionPoint.X, 1); | ||
1634 | collisionPoint.Y = (float) Math.Round(collisionPoint.Y, 1); | ||
1635 | collisionPoint.Z = (float) Math.Round(collisionPoint.Z, 1); | ||
1636 | |||
1637 | Vector4 plane = new Vector4(pNormal.X, pNormal.Y, pNormal.Z, | ||
1638 | Vector3.Dot(collisionPoint, pNormal)); | ||
1639 | UpdateCameraCollisionPlane(plane); | ||
1640 | } | ||
1444 | } | 1641 | } |
1445 | else if (!m_pos.ApproxEquals(m_lastPosition, POSITION_TOLERANCE) || | 1642 | else if (!m_pos.ApproxEquals(m_lastPosition, POSITION_TOLERANCE) || |
1446 | !Rotation.ApproxEquals(m_lastRotation, ROTATION_TOLERANCE)) | 1643 | !Rotation.ApproxEquals(m_lastRotation, ROTATION_TOLERANCE)) |
@@ -1741,6 +1938,29 @@ namespace OpenSim.Region.Framework.Scenes | |||
1741 | bool controlland = (((flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0) || | 1938 | bool controlland = (((flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0) || |
1742 | ((flags & AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG) != 0)); | 1939 | ((flags & AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG) != 0)); |
1743 | 1940 | ||
1941 | //m_log.Debug("[CONTROL]: " +flags); | ||
1942 | // Applies a satisfying roll effect to the avatar when flying. | ||
1943 | if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_LEFT) != 0 && (flags & AgentManager.ControlFlags.AGENT_CONTROL_YAW_POS) != 0) | ||
1944 | { | ||
1945 | ApplyFlyingRoll( | ||
1946 | FLY_ROLL_RADIANS_PER_UPDATE, | ||
1947 | (flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) != 0, | ||
1948 | (flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0); | ||
1949 | } | ||
1950 | else if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_RIGHT) != 0 && | ||
1951 | (flags & AgentManager.ControlFlags.AGENT_CONTROL_YAW_NEG) != 0) | ||
1952 | { | ||
1953 | ApplyFlyingRoll( | ||
1954 | -FLY_ROLL_RADIANS_PER_UPDATE, | ||
1955 | (flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) != 0, | ||
1956 | (flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0); | ||
1957 | } | ||
1958 | else | ||
1959 | { | ||
1960 | if (m_AngularVelocity.Z != 0) | ||
1961 | m_AngularVelocity.Z += CalculateFlyingRollResetToZero(FLY_ROLL_RESET_RADIANS_PER_UPDATE); | ||
1962 | } | ||
1963 | |||
1744 | if (Flying && IsColliding && controlland) | 1964 | if (Flying && IsColliding && controlland) |
1745 | { | 1965 | { |
1746 | // nesting this check because LengthSquared() is expensive and we don't | 1966 | // nesting this check because LengthSquared() is expensive and we don't |
@@ -1954,7 +2174,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
1954 | // Get terrain height for sub-region in a megaregion if necessary | 2174 | // Get terrain height for sub-region in a megaregion if necessary |
1955 | int X = (int)((m_scene.RegionInfo.RegionLocX * Constants.RegionSize) + pos.X); | 2175 | int X = (int)((m_scene.RegionInfo.RegionLocX * Constants.RegionSize) + pos.X); |
1956 | int Y = (int)((m_scene.RegionInfo.RegionLocY * Constants.RegionSize) + pos.Y); | 2176 | int Y = (int)((m_scene.RegionInfo.RegionLocY * Constants.RegionSize) + pos.Y); |
1957 | UUID target_regionID = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, X, Y).RegionID; | 2177 | GridRegion target_region = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, X, Y); |
2178 | // If X and Y is NaN, target_region will be null | ||
2179 | if (target_region == null) | ||
2180 | return; | ||
2181 | UUID target_regionID = target_region.RegionID; | ||
1958 | Scene targetScene = m_scene; | 2182 | Scene targetScene = m_scene; |
1959 | 2183 | ||
1960 | if (!SceneManager.Instance.TryGetScene(target_regionID, out targetScene)) | 2184 | if (!SceneManager.Instance.TryGetScene(target_regionID, out targetScene)) |
@@ -2199,28 +2423,16 @@ namespace OpenSim.Region.Framework.Scenes | |||
2199 | 2423 | ||
2200 | if (ParentID != 0) | 2424 | if (ParentID != 0) |
2201 | { | 2425 | { |
2426 | if (ParentPart.UUID == targetID) | ||
2427 | return; // already sitting here, ignore | ||
2428 | |||
2202 | StandUp(); | 2429 | StandUp(); |
2203 | } | 2430 | } |
2204 | 2431 | ||
2205 | // if (!String.IsNullOrEmpty(sitAnimation)) | ||
2206 | // { | ||
2207 | // m_nextSitAnimation = sitAnimation; | ||
2208 | // } | ||
2209 | // else | ||
2210 | // { | ||
2211 | m_nextSitAnimation = "SIT"; | ||
2212 | // } | ||
2213 | |||
2214 | //SceneObjectPart part = m_scene.GetSceneObjectPart(targetID); | ||
2215 | SceneObjectPart part = FindNextAvailableSitTarget(targetID); | 2432 | SceneObjectPart part = FindNextAvailableSitTarget(targetID); |
2216 | 2433 | ||
2217 | if (part != null) | 2434 | if (part != null) |
2218 | { | 2435 | { |
2219 | if (!String.IsNullOrEmpty(part.SitAnimation)) | ||
2220 | { | ||
2221 | m_nextSitAnimation = part.SitAnimation; | ||
2222 | } | ||
2223 | |||
2224 | m_requestedSitTargetID = part.LocalId; | 2436 | m_requestedSitTargetID = part.LocalId; |
2225 | m_requestedSitTargetUUID = targetID; | 2437 | m_requestedSitTargetUUID = targetID; |
2226 | 2438 | ||
@@ -2341,18 +2553,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
2341 | 2553 | ||
2342 | public void HandleAgentSit(IClientAPI remoteClient, UUID agentID) | 2554 | public void HandleAgentSit(IClientAPI remoteClient, UUID agentID) |
2343 | { | 2555 | { |
2344 | if (!String.IsNullOrEmpty(m_nextSitAnimation)) | ||
2345 | { | ||
2346 | HandleAgentSit(remoteClient, agentID, m_nextSitAnimation); | ||
2347 | } | ||
2348 | else | ||
2349 | { | ||
2350 | HandleAgentSit(remoteClient, agentID, "SIT"); | ||
2351 | } | ||
2352 | } | ||
2353 | |||
2354 | public void HandleAgentSit(IClientAPI remoteClient, UUID agentID, string sitAnimation) | ||
2355 | { | ||
2356 | SceneObjectPart part = m_scene.GetSceneObjectPart(m_requestedSitTargetID); | 2556 | SceneObjectPart part = m_scene.GetSceneObjectPart(m_requestedSitTargetID); |
2357 | 2557 | ||
2358 | if (part != null) | 2558 | if (part != null) |
@@ -2422,10 +2622,15 @@ namespace OpenSim.Region.Framework.Scenes | |||
2422 | 2622 | ||
2423 | ParentPart = m_scene.GetSceneObjectPart(m_requestedSitTargetID); | 2623 | ParentPart = m_scene.GetSceneObjectPart(m_requestedSitTargetID); |
2424 | ParentID = m_requestedSitTargetID; | 2624 | ParentID = m_requestedSitTargetID; |
2425 | 2625 | m_AngularVelocity = Vector3.Zero; | |
2426 | Velocity = Vector3.Zero; | 2626 | Velocity = Vector3.Zero; |
2427 | RemoveFromPhysicalScene(); | 2627 | RemoveFromPhysicalScene(); |
2428 | 2628 | ||
2629 | String sitAnimation = "SIT"; | ||
2630 | if (!String.IsNullOrEmpty(part.SitAnimation)) | ||
2631 | { | ||
2632 | sitAnimation = part.SitAnimation; | ||
2633 | } | ||
2429 | Animator.TrySetMovementAnimation(sitAnimation); | 2634 | Animator.TrySetMovementAnimation(sitAnimation); |
2430 | SendAvatarDataToAllAgents(); | 2635 | SendAvatarDataToAllAgents(); |
2431 | } | 2636 | } |
@@ -2433,7 +2638,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
2433 | 2638 | ||
2434 | public void HandleAgentSitOnGround() | 2639 | public void HandleAgentSitOnGround() |
2435 | { | 2640 | { |
2436 | // m_updateCount = 0; // Kill animation update burst so that the SIT_G.. will stick. | 2641 | // m_updateCount = 0; // Kill animation update burst so that the SIT_G.. will stick.. |
2642 | m_AngularVelocity = Vector3.Zero; | ||
2437 | Animator.TrySetMovementAnimation("SIT_GROUND_CONSTRAINED"); | 2643 | Animator.TrySetMovementAnimation("SIT_GROUND_CONSTRAINED"); |
2438 | SitGround = true; | 2644 | SitGround = true; |
2439 | RemoveFromPhysicalScene(); | 2645 | RemoveFromPhysicalScene(); |
@@ -2455,7 +2661,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2455 | 2661 | ||
2456 | public void HandleStopAnim(IClientAPI remoteClient, UUID animID) | 2662 | public void HandleStopAnim(IClientAPI remoteClient, UUID animID) |
2457 | { | 2663 | { |
2458 | Animator.RemoveAnimation(animID); | 2664 | Animator.RemoveAnimation(animID, false); |
2459 | } | 2665 | } |
2460 | 2666 | ||
2461 | public void avnHandleChangeAnim(UUID animID, bool addRemove,bool sendPack) | 2667 | public void avnHandleChangeAnim(UUID animID, bool addRemove,bool sendPack) |
@@ -2471,7 +2677,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
2471 | /// <param name="vec">The vector in which to move. This is relative to the rotation argument</param> | 2677 | /// <param name="vec">The vector in which to move. This is relative to the rotation argument</param> |
2472 | public void AddNewMovement(Vector3 vec) | 2678 | public void AddNewMovement(Vector3 vec) |
2473 | { | 2679 | { |
2474 | // m_log.DebugFormat("[SCENE PRESENCE]: Adding new movement {0} for {1}", vec, Name); | 2680 | // m_log.DebugFormat( |
2681 | // "[SCENE PRESENCE]: Adding new movement {0} with rotation {1} for {2}", vec, Rotation, Name); | ||
2475 | 2682 | ||
2476 | Vector3 direc = vec * Rotation; | 2683 | Vector3 direc = vec * Rotation; |
2477 | direc.Normalize(); | 2684 | direc.Normalize(); |
@@ -2491,6 +2698,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
2491 | 2698 | ||
2492 | direc *= 0.03f * 128f * SpeedModifier; | 2699 | direc *= 0.03f * 128f * SpeedModifier; |
2493 | 2700 | ||
2701 | // m_log.DebugFormat("[SCENE PRESENCE]: Force to apply before modification was {0} for {1}", direc, Name); | ||
2702 | |||
2494 | if (PhysicsActor != null) | 2703 | if (PhysicsActor != null) |
2495 | { | 2704 | { |
2496 | if (Flying) | 2705 | if (Flying) |
@@ -2524,6 +2733,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
2524 | } | 2733 | } |
2525 | } | 2734 | } |
2526 | 2735 | ||
2736 | // m_log.DebugFormat("[SCENE PRESENCE]: Setting force to apply to {0} for {1}", direc, Name); | ||
2737 | |||
2527 | // TODO: Add the force instead of only setting it to support multiple forces per frame? | 2738 | // TODO: Add the force instead of only setting it to support multiple forces per frame? |
2528 | m_forceToApply = direc; | 2739 | m_forceToApply = direc; |
2529 | Animator.UpdateMovementAnimations(); | 2740 | Animator.UpdateMovementAnimations(); |
@@ -2942,6 +3153,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
2942 | 3153 | ||
2943 | if (!IsInTransit) | 3154 | if (!IsInTransit) |
2944 | { | 3155 | { |
3156 | // m_log.DebugFormat( | ||
3157 | // "[SCENE PRESENCE]: Testing border check for projected position {0} of {1} in {2}", | ||
3158 | // pos2, Name, Scene.Name); | ||
3159 | |||
2945 | // Checks if where it's headed exists a region | 3160 | // Checks if where it's headed exists a region |
2946 | bool needsTransit = false; | 3161 | bool needsTransit = false; |
2947 | if (m_scene.TestBorderCross(pos2, Cardinals.W)) | 3162 | if (m_scene.TestBorderCross(pos2, Cardinals.W)) |
@@ -4166,6 +4381,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
4166 | (m_teleportFlags & TeleportFlags.ViaLocation) != 0 || | 4381 | (m_teleportFlags & TeleportFlags.ViaLocation) != 0 || |
4167 | (m_teleportFlags & Constants.TeleportFlags.ViaHGLogin) != 0) | 4382 | (m_teleportFlags & Constants.TeleportFlags.ViaHGLogin) != 0) |
4168 | { | 4383 | { |
4384 | |||
4169 | if (GodLevel < 200 && | 4385 | if (GodLevel < 200 && |
4170 | ((!m_scene.Permissions.IsGod(m_uuid) && | 4386 | ((!m_scene.Permissions.IsGod(m_uuid) && |
4171 | !m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_uuid)) || | 4387 | !m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_uuid)) || |
@@ -4174,7 +4390,14 @@ namespace OpenSim.Region.Framework.Scenes | |||
4174 | { | 4390 | { |
4175 | SpawnPoint[] spawnPoints = m_scene.RegionInfo.RegionSettings.SpawnPoints().ToArray(); | 4391 | SpawnPoint[] spawnPoints = m_scene.RegionInfo.RegionSettings.SpawnPoints().ToArray(); |
4176 | if (spawnPoints.Length == 0) | 4392 | if (spawnPoints.Length == 0) |
4393 | { | ||
4394 | if(m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_uuid)) | ||
4395 | { | ||
4396 | pos.X = 128.0f; | ||
4397 | pos.Y = 128.0f; | ||
4398 | } | ||
4177 | return; | 4399 | return; |
4400 | } | ||
4178 | 4401 | ||
4179 | int index; | 4402 | int index; |
4180 | bool selected = false; | 4403 | bool selected = false; |
@@ -4183,6 +4406,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
4183 | { | 4406 | { |
4184 | case "random": | 4407 | case "random": |
4185 | 4408 | ||
4409 | if (spawnPoints.Length == 0) | ||
4410 | return; | ||
4186 | do | 4411 | do |
4187 | { | 4412 | { |
4188 | index = Util.RandomClass.Next(spawnPoints.Length - 1); | 4413 | index = Util.RandomClass.Next(spawnPoints.Length - 1); |
@@ -4194,6 +4419,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
4194 | // SpawnPoint sp = spawnPoints[index]; | 4419 | // SpawnPoint sp = spawnPoints[index]; |
4195 | 4420 | ||
4196 | ILandObject land = m_scene.LandChannel.GetLandObject(spawnPosition.X, spawnPosition.Y); | 4421 | ILandObject land = m_scene.LandChannel.GetLandObject(spawnPosition.X, spawnPosition.Y); |
4422 | |||
4197 | if (land == null || land.IsEitherBannedOrRestricted(UUID)) | 4423 | if (land == null || land.IsEitherBannedOrRestricted(UUID)) |
4198 | selected = false; | 4424 | selected = false; |
4199 | else | 4425 | else |
diff --git a/OpenSim/Region/Framework/Scenes/Scripting/ScriptEngineLoader.cs b/OpenSim/Region/Framework/Scenes/Scripting/ScriptEngineLoader.cs deleted file mode 100644 index c58ccc5..0000000 --- a/OpenSim/Region/Framework/Scenes/Scripting/ScriptEngineLoader.cs +++ /dev/null | |||
@@ -1,119 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | /* Original code: Tedd Hansen */ | ||
29 | using System; | ||
30 | using System.IO; | ||
31 | using System.Reflection; | ||
32 | using log4net; | ||
33 | |||
34 | namespace OpenSim.Region.Framework.Scenes.Scripting | ||
35 | { | ||
36 | public class ScriptEngineLoader | ||
37 | { | ||
38 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
39 | |||
40 | public ScriptEngineInterface LoadScriptEngine(string EngineName) | ||
41 | { | ||
42 | ScriptEngineInterface ret = null; | ||
43 | try | ||
44 | { | ||
45 | ret = | ||
46 | LoadAndInitAssembly( | ||
47 | Path.Combine("ScriptEngines", "OpenSim.Region.ScriptEngine." + EngineName + ".dll"), | ||
48 | "OpenSim.Region.ScriptEngine." + EngineName + ".ScriptEngine"); | ||
49 | } | ||
50 | catch (Exception e) | ||
51 | { | ||
52 | m_log.Error("[ScriptEngine]: " + | ||
53 | "Error loading assembly \"" + EngineName + "\": " + e.Message + ", " + | ||
54 | e.StackTrace.ToString()); | ||
55 | } | ||
56 | return ret; | ||
57 | } | ||
58 | |||
59 | /// <summary> | ||
60 | /// Does actual loading and initialization of script Assembly | ||
61 | /// </summary> | ||
62 | /// <param name="FreeAppDomain">AppDomain to load script into</param> | ||
63 | /// <param name="FileName">FileName of script assembly (.dll)</param> | ||
64 | /// <returns></returns> | ||
65 | private ScriptEngineInterface LoadAndInitAssembly(string FileName, string NameSpace) | ||
66 | { | ||
67 | //Common.SendToDebug("Loading ScriptEngine Assembly " + FileName); | ||
68 | // Load .Net Assembly (.dll) | ||
69 | // Initialize and return it | ||
70 | |||
71 | // TODO: Add error handling | ||
72 | |||
73 | Assembly a; | ||
74 | //try | ||
75 | //{ | ||
76 | |||
77 | |||
78 | // Load to default appdomain (temporary) | ||
79 | a = Assembly.LoadFrom(FileName); | ||
80 | // Load to specified appdomain | ||
81 | // TODO: Insert security | ||
82 | //a = FreeAppDomain.Load(FileName); | ||
83 | //} | ||
84 | //catch (Exception e) | ||
85 | //{ | ||
86 | // m_log.Error("[ScriptEngine]: Error loading assembly \String.Empty + FileName + "\": " + e.ToString()); | ||
87 | //} | ||
88 | |||
89 | |||
90 | //m_log.Debug("Loading: " + FileName); | ||
91 | //foreach (Type _t in a.GetTypes()) | ||
92 | //{ | ||
93 | // m_log.Debug("Type: " + _t.ToString()); | ||
94 | //} | ||
95 | |||
96 | Type t; | ||
97 | //try | ||
98 | //{ | ||
99 | t = a.GetType(NameSpace, true); | ||
100 | //} | ||
101 | //catch (Exception e) | ||
102 | //{ | ||
103 | // m_log.Error("[ScriptEngine]: Error initializing type \String.Empty + NameSpace + "\" from \String.Empty + FileName + "\": " + e.ToString()); | ||
104 | //} | ||
105 | |||
106 | ScriptEngineInterface ret; | ||
107 | //try | ||
108 | //{ | ||
109 | ret = (ScriptEngineInterface) Activator.CreateInstance(t); | ||
110 | //} | ||
111 | //catch (Exception e) | ||
112 | //{ | ||
113 | // m_log.Error("[ScriptEngine]: Error initializing type \String.Empty + NameSpace + "\" from \String.Empty + FileName + "\": " + e.ToString()); | ||
114 | //} | ||
115 | |||
116 | return ret; | ||
117 | } | ||
118 | } | ||
119 | } | ||
diff --git a/OpenSim/Region/Framework/Scenes/Scripting/ScriptUtils.cs b/OpenSim/Region/Framework/Scenes/Scripting/ScriptUtils.cs new file mode 100644 index 0000000..f08ba59 --- /dev/null +++ b/OpenSim/Region/Framework/Scenes/Scripting/ScriptUtils.cs | |||
@@ -0,0 +1,107 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using OpenMetaverse; | ||
31 | using OpenSim.Framework; | ||
32 | |||
33 | namespace OpenSim.Region.Framework.Scenes.Scripting | ||
34 | { | ||
35 | /// <summary> | ||
36 | /// Utility functions for use by scripts manipulating the scene. | ||
37 | /// </summary> | ||
38 | public static class ScriptUtils | ||
39 | { | ||
40 | /// <summary> | ||
41 | /// Get an asset id given an item name and an item type. | ||
42 | /// </summary> | ||
43 | /// <returns>UUID.Zero if the name and type did not match any item.</returns> | ||
44 | /// <param name='part'></param> | ||
45 | /// <param name='name'></param> | ||
46 | /// <param name='type'></param> | ||
47 | public static UUID GetAssetIdFromItemName(SceneObjectPart part, string name, int type) | ||
48 | { | ||
49 | TaskInventoryItem item = part.Inventory.GetInventoryItem(name); | ||
50 | |||
51 | if (item != null && item.Type == type) | ||
52 | return item.AssetID; | ||
53 | else | ||
54 | return UUID.Zero; | ||
55 | } | ||
56 | |||
57 | /// <summary> | ||
58 | /// accepts a valid UUID, -or- a name of an inventory item. | ||
59 | /// Returns a valid UUID or UUID.Zero if key invalid and item not found | ||
60 | /// in prim inventory. | ||
61 | /// </summary> | ||
62 | /// <param name="part">Scene object part to search for inventory item</param> | ||
63 | /// <param name="key"></param> | ||
64 | /// <returns></returns> | ||
65 | public static UUID GetAssetIdFromKeyOrItemName(SceneObjectPart part, string identifier) | ||
66 | { | ||
67 | UUID key; | ||
68 | |||
69 | // if we can parse the string as a key, use it. | ||
70 | // else try to locate the name in inventory of object. found returns key, | ||
71 | // not found returns UUID.Zero | ||
72 | if (!UUID.TryParse(identifier, out key)) | ||
73 | { | ||
74 | TaskInventoryItem item = part.Inventory.GetInventoryItem(identifier); | ||
75 | |||
76 | if (item != null) | ||
77 | key = item.AssetID; | ||
78 | else | ||
79 | key = UUID.Zero; | ||
80 | } | ||
81 | |||
82 | return key; | ||
83 | } | ||
84 | |||
85 | /// <summary> | ||
86 | /// Return the UUID of the asset matching the specified key or name | ||
87 | /// and asset type. | ||
88 | /// </summary> | ||
89 | /// <param name="part">Scene object part to search for inventory item</param> | ||
90 | /// <param name="identifier"></param> | ||
91 | /// <param name="type"></param> | ||
92 | /// <returns></returns> | ||
93 | public static UUID GetAssetIdFromKeyOrItemName(SceneObjectPart part, string identifier, AssetType type) | ||
94 | { | ||
95 | UUID key; | ||
96 | |||
97 | if (!UUID.TryParse(identifier, out key)) | ||
98 | { | ||
99 | TaskInventoryItem item = part.Inventory.GetInventoryItem(identifier); | ||
100 | if (item != null && item.Type == (int)type) | ||
101 | key = item.AssetID; | ||
102 | } | ||
103 | |||
104 | return key; | ||
105 | } | ||
106 | } | ||
107 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs index a4f730d..5cb271d 100644 --- a/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs +++ b/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs | |||
@@ -42,9 +42,6 @@ namespace OpenSim.Region.Framework.Scenes.Serialization | |||
42 | /// <summary> | 42 | /// <summary> |
43 | /// Serialize and deserialize coalesced scene objects. | 43 | /// Serialize and deserialize coalesced scene objects. |
44 | /// </summary> | 44 | /// </summary> |
45 | /// <remarks> | ||
46 | /// Deserialization not yet here. | ||
47 | /// </remarks> | ||
48 | public class CoalescedSceneObjectsSerializer | 45 | public class CoalescedSceneObjectsSerializer |
49 | { | 46 | { |
50 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 47 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
@@ -128,6 +125,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization | |||
128 | // m_log.DebugFormat("[COALESCED SCENE OBJECTS SERIALIZER]: TryFromXml() deserializing {0}", xml); | 125 | // m_log.DebugFormat("[COALESCED SCENE OBJECTS SERIALIZER]: TryFromXml() deserializing {0}", xml); |
129 | 126 | ||
130 | coa = null; | 127 | coa = null; |
128 | int i = 0; | ||
131 | 129 | ||
132 | using (StringReader sr = new StringReader(xml)) | 130 | using (StringReader sr = new StringReader(xml)) |
133 | { | 131 | { |
@@ -153,7 +151,23 @@ namespace OpenSim.Region.Framework.Scenes.Serialization | |||
153 | if (reader.Name == "SceneObjectGroup") | 151 | if (reader.Name == "SceneObjectGroup") |
154 | { | 152 | { |
155 | string soXml = reader.ReadOuterXml(); | 153 | string soXml = reader.ReadOuterXml(); |
156 | coa.Add(SceneObjectSerializer.FromOriginalXmlFormat(soXml)); | 154 | |
155 | SceneObjectGroup so = SceneObjectSerializer.FromOriginalXmlFormat(soXml); | ||
156 | |||
157 | if (so != null) | ||
158 | { | ||
159 | coa.Add(so); | ||
160 | } | ||
161 | else | ||
162 | { | ||
163 | // XXX: Possibly we should fail outright here rather than continuing if a particular component of the | ||
164 | // coalesced object fails to load. | ||
165 | m_log.WarnFormat( | ||
166 | "[COALESCED SCENE OBJECTS SERIALIZER]: Deserialization of xml for component {0} failed. Continuing.", | ||
167 | i); | ||
168 | } | ||
169 | |||
170 | i++; | ||
157 | } | 171 | } |
158 | } | 172 | } |
159 | 173 | ||
diff --git a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs index 123c158..ce4fb40 100644 --- a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs +++ b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs | |||
@@ -365,6 +365,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization | |||
365 | m_SOPXmlProcessors.Add("CollisionSound", ProcessCollisionSound); | 365 | m_SOPXmlProcessors.Add("CollisionSound", ProcessCollisionSound); |
366 | m_SOPXmlProcessors.Add("CollisionSoundVolume", ProcessCollisionSoundVolume); | 366 | m_SOPXmlProcessors.Add("CollisionSoundVolume", ProcessCollisionSoundVolume); |
367 | m_SOPXmlProcessors.Add("MediaUrl", ProcessMediaUrl); | 367 | m_SOPXmlProcessors.Add("MediaUrl", ProcessMediaUrl); |
368 | m_SOPXmlProcessors.Add("DynAttrs", ProcessDynAttrs); | ||
368 | m_SOPXmlProcessors.Add("TextureAnimation", ProcessTextureAnimation); | 369 | m_SOPXmlProcessors.Add("TextureAnimation", ProcessTextureAnimation); |
369 | m_SOPXmlProcessors.Add("ParticleSystem", ProcessParticleSystem); | 370 | m_SOPXmlProcessors.Add("ParticleSystem", ProcessParticleSystem); |
370 | m_SOPXmlProcessors.Add("PayPrice0", ProcessPayPrice0); | 371 | m_SOPXmlProcessors.Add("PayPrice0", ProcessPayPrice0); |
@@ -633,7 +634,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization | |||
633 | 634 | ||
634 | private static void ProcessBounce(SceneObjectPart obj, XmlTextReader reader) | 635 | private static void ProcessBounce(SceneObjectPart obj, XmlTextReader reader) |
635 | { | 636 | { |
636 | obj.Bounciness = reader.ReadElementContentAsFloat("Bounce", String.Empty); | 637 | obj.Restitution = reader.ReadElementContentAsFloat("Bounce", String.Empty); |
637 | } | 638 | } |
638 | 639 | ||
639 | private static void ProcessGravityModifier(SceneObjectPart obj, XmlTextReader reader) | 640 | private static void ProcessGravityModifier(SceneObjectPart obj, XmlTextReader reader) |
@@ -797,6 +798,11 @@ namespace OpenSim.Region.Framework.Scenes.Serialization | |||
797 | obj.MediaUrl = reader.ReadElementContentAsString("MediaUrl", String.Empty); | 798 | obj.MediaUrl = reader.ReadElementContentAsString("MediaUrl", String.Empty); |
798 | } | 799 | } |
799 | 800 | ||
801 | private static void ProcessDynAttrs(SceneObjectPart obj, XmlTextReader reader) | ||
802 | { | ||
803 | obj.DynAttrs.ReadXml(reader); | ||
804 | } | ||
805 | |||
800 | private static void ProcessTextureAnimation(SceneObjectPart obj, XmlTextReader reader) | 806 | private static void ProcessTextureAnimation(SceneObjectPart obj, XmlTextReader reader) |
801 | { | 807 | { |
802 | obj.TextureAnimation = Convert.FromBase64String(reader.ReadElementContentAsString("TextureAnimation", String.Empty)); | 808 | obj.TextureAnimation = Convert.FromBase64String(reader.ReadElementContentAsString("TextureAnimation", String.Empty)); |
@@ -1339,6 +1345,14 @@ namespace OpenSim.Region.Framework.Scenes.Serialization | |||
1339 | writer.WriteElementString("CollisionSoundVolume", sop.CollisionSoundVolume.ToString()); | 1345 | writer.WriteElementString("CollisionSoundVolume", sop.CollisionSoundVolume.ToString()); |
1340 | if (sop.MediaUrl != null) | 1346 | if (sop.MediaUrl != null) |
1341 | writer.WriteElementString("MediaUrl", sop.MediaUrl.ToString()); | 1347 | writer.WriteElementString("MediaUrl", sop.MediaUrl.ToString()); |
1348 | |||
1349 | if (sop.DynAttrs.Count > 0) | ||
1350 | { | ||
1351 | writer.WriteStartElement("DynAttrs"); | ||
1352 | sop.DynAttrs.WriteXml(writer); | ||
1353 | writer.WriteEndElement(); | ||
1354 | } | ||
1355 | |||
1342 | WriteBytes(writer, "TextureAnimation", sop.TextureAnimation); | 1356 | WriteBytes(writer, "TextureAnimation", sop.TextureAnimation); |
1343 | WriteBytes(writer, "ParticleSystem", sop.ParticleSystem); | 1357 | WriteBytes(writer, "ParticleSystem", sop.ParticleSystem); |
1344 | writer.WriteElementString("PayPrice0", sop.PayPrice[0].ToString()); | 1358 | writer.WriteElementString("PayPrice0", sop.PayPrice[0].ToString()); |
@@ -1363,8 +1377,8 @@ namespace OpenSim.Region.Framework.Scenes.Serialization | |||
1363 | writer.WriteElementString("Density", sop.Density.ToString().ToLower()); | 1377 | writer.WriteElementString("Density", sop.Density.ToString().ToLower()); |
1364 | if (sop.Friction != 0.6f) | 1378 | if (sop.Friction != 0.6f) |
1365 | writer.WriteElementString("Friction", sop.Friction.ToString().ToLower()); | 1379 | writer.WriteElementString("Friction", sop.Friction.ToString().ToLower()); |
1366 | if (sop.Bounciness != 0.5f) | 1380 | if (sop.Restitution != 0.5f) |
1367 | writer.WriteElementString("Bounce", sop.Bounciness.ToString().ToLower()); | 1381 | writer.WriteElementString("Bounce", sop.Restitution.ToString().ToLower()); |
1368 | if (sop.GravityModifier != 1.0f) | 1382 | if (sop.GravityModifier != 1.0f) |
1369 | writer.WriteElementString("GravityModifier", sop.GravityModifier.ToString().ToLower()); | 1383 | writer.WriteElementString("GravityModifier", sop.GravityModifier.ToString().ToLower()); |
1370 | WriteVector(writer, "CameraEyeOffset", sop.GetCameraEyeOffset()); | 1384 | WriteVector(writer, "CameraEyeOffset", sop.GetCameraEyeOffset()); |
diff --git a/OpenSim/Region/Framework/Scenes/Tests/BorderTests.cs b/OpenSim/Region/Framework/Scenes/Tests/BorderTests.cs index 4a21dc9..e209221 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/BorderTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/BorderTests.cs | |||
@@ -37,7 +37,7 @@ using OpenSim.Tests.Common; | |||
37 | namespace OpenSim.Region.Framework.Scenes.Tests | 37 | namespace OpenSim.Region.Framework.Scenes.Tests |
38 | { | 38 | { |
39 | [TestFixture] | 39 | [TestFixture] |
40 | public class BorderTests | 40 | public class BorderTests : OpenSimTestCase |
41 | { | 41 | { |
42 | [Test] | 42 | [Test] |
43 | public void TestCross() | 43 | public void TestCross() |
diff --git a/OpenSim/Region/Framework/Scenes/Tests/EntityManagerTests.cs b/OpenSim/Region/Framework/Scenes/Tests/EntityManagerTests.cs index ea9fc93..766ce83 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/EntityManagerTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/EntityManagerTests.cs | |||
@@ -41,7 +41,7 @@ using OpenSim.Tests.Common; | |||
41 | namespace OpenSim.Region.Framework.Scenes.Tests | 41 | namespace OpenSim.Region.Framework.Scenes.Tests |
42 | { | 42 | { |
43 | [TestFixture, LongRunning] | 43 | [TestFixture, LongRunning] |
44 | public class EntityManagerTests | 44 | public class EntityManagerTests : OpenSimTestCase |
45 | { | 45 | { |
46 | static public Random random; | 46 | static public Random random; |
47 | SceneObjectGroup found; | 47 | SceneObjectGroup found; |
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneGraphTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneGraphTests.cs index d23c965..575a081 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneGraphTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneGraphTests.cs | |||
@@ -40,7 +40,7 @@ using OpenSim.Tests.Common.Mock; | |||
40 | namespace OpenSim.Region.Framework.Scenes.Tests | 40 | namespace OpenSim.Region.Framework.Scenes.Tests |
41 | { | 41 | { |
42 | [TestFixture] | 42 | [TestFixture] |
43 | public class SceneGraphTests | 43 | public class SceneGraphTests : OpenSimTestCase |
44 | { | 44 | { |
45 | [Test] | 45 | [Test] |
46 | public void TestDuplicateObject() | 46 | public void TestDuplicateObject() |
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneManagerTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneManagerTests.cs index ab56f4e..2d831fa 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneManagerTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneManagerTests.cs | |||
@@ -41,7 +41,7 @@ using OpenSim.Tests.Common.Mock; | |||
41 | namespace OpenSim.Region.Framework.Scenes.Tests | 41 | namespace OpenSim.Region.Framework.Scenes.Tests |
42 | { | 42 | { |
43 | [TestFixture] | 43 | [TestFixture] |
44 | public class SceneManagerTests | 44 | public class SceneManagerTests : OpenSimTestCase |
45 | { | 45 | { |
46 | [Test] | 46 | [Test] |
47 | public void TestClose() | 47 | public void TestClose() |
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs index 5b334c6..a07d64c 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs | |||
@@ -29,6 +29,7 @@ using System; | |||
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.Reflection; | 30 | using System.Reflection; |
31 | using System.Threading; | 31 | using System.Threading; |
32 | using Nini.Config; | ||
32 | using NUnit.Framework; | 33 | using NUnit.Framework; |
33 | using OpenMetaverse; | 34 | using OpenMetaverse; |
34 | using OpenSim.Framework; | 35 | using OpenSim.Framework; |
@@ -182,6 +183,10 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
182 | /// <summary> | 183 | /// <summary> |
183 | /// Test deleting an object from a scene. | 184 | /// Test deleting an object from a scene. |
184 | /// </summary> | 185 | /// </summary> |
186 | /// <remarks> | ||
187 | /// This is the most basic form of delete. For all more sophisticated forms of derez (done asynchrnously | ||
188 | /// and where object can be taken to user inventory, etc.), see SceneObjectDeRezTests. | ||
189 | /// </remarks> | ||
185 | [Test] | 190 | [Test] |
186 | public void TestDeleteSceneObject() | 191 | public void TestDeleteSceneObject() |
187 | { | 192 | { |
@@ -201,100 +206,6 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
201 | } | 206 | } |
202 | 207 | ||
203 | /// <summary> | 208 | /// <summary> |
204 | /// Test deleting an object asynchronously | ||
205 | /// </summary> | ||
206 | [Test] | ||
207 | public void TestDeleteSceneObjectAsync() | ||
208 | { | ||
209 | TestHelpers.InMethod(); | ||
210 | //log4net.Config.XmlConfigurator.Configure(); | ||
211 | |||
212 | UUID agentId = UUID.Parse("00000000-0000-0000-0000-000000000001"); | ||
213 | |||
214 | TestScene scene = new SceneHelpers().SetupScene(); | ||
215 | |||
216 | // Turn off the timer on the async sog deleter - we'll crank it by hand for this test. | ||
217 | AsyncSceneObjectGroupDeleter sogd = scene.SceneObjectGroupDeleter; | ||
218 | sogd.Enabled = false; | ||
219 | |||
220 | SceneObjectGroup so = SceneHelpers.AddSceneObject(scene); | ||
221 | |||
222 | IClientAPI client = SceneHelpers.AddScenePresence(scene, agentId).ControllingClient; | ||
223 | scene.DeRezObjects(client, new System.Collections.Generic.List<uint>() { so.LocalId }, UUID.Zero, DeRezAction.Delete, UUID.Zero); | ||
224 | |||
225 | SceneObjectPart retrievedPart = scene.GetSceneObjectPart(so.LocalId); | ||
226 | |||
227 | Assert.That(retrievedPart, Is.Not.Null); | ||
228 | |||
229 | Assert.That(so.IsDeleted, Is.False); | ||
230 | |||
231 | sogd.InventoryDeQueueAndDelete(); | ||
232 | |||
233 | Assert.That(so.IsDeleted, Is.True); | ||
234 | |||
235 | SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(so.LocalId); | ||
236 | Assert.That(retrievedPart2, Is.Null); | ||
237 | } | ||
238 | |||
239 | /// <summary> | ||
240 | /// Test deleting an object asynchronously to user inventory. | ||
241 | /// </summary> | ||
242 | // [Test] | ||
243 | public void TestDeleteSceneObjectAsyncToUserInventory() | ||
244 | { | ||
245 | TestHelpers.InMethod(); | ||
246 | TestHelpers.EnableLogging(); | ||
247 | |||
248 | UUID agentId = UUID.Parse("00000000-0000-0000-0000-000000000001"); | ||
249 | string myObjectName = "Fred"; | ||
250 | |||
251 | TestScene scene = new SceneHelpers().SetupScene(); | ||
252 | |||
253 | // Turn off the timer on the async sog deleter - we'll crank it by hand for this test. | ||
254 | AsyncSceneObjectGroupDeleter sogd = scene.SceneObjectGroupDeleter; | ||
255 | sogd.Enabled = false; | ||
256 | |||
257 | SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, myObjectName, agentId); | ||
258 | |||
259 | // Assert.That( | ||
260 | // scene.CommsManager.UserAdminService.AddUser( | ||
261 | // "Bob", "Hoskins", "test", "test@test.com", 1000, 1000, agentId), | ||
262 | // Is.EqualTo(agentId)); | ||
263 | |||
264 | UserAccount ua = UserAccountHelpers.CreateUserWithInventory(scene, agentId); | ||
265 | InventoryFolderBase folder1 | ||
266 | = UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, ua.PrincipalID, "folder1"); | ||
267 | |||
268 | IClientAPI client = SceneHelpers.AddScenePresence(scene, agentId).ControllingClient; | ||
269 | scene.DeRezObjects(client, new List<uint>() { so.LocalId }, UUID.Zero, DeRezAction.Take, folder1.ID); | ||
270 | |||
271 | SceneObjectPart retrievedPart = scene.GetSceneObjectPart(so.LocalId); | ||
272 | |||
273 | Assert.That(retrievedPart, Is.Not.Null); | ||
274 | Assert.That(so.IsDeleted, Is.False); | ||
275 | |||
276 | sogd.InventoryDeQueueAndDelete(); | ||
277 | |||
278 | Assert.That(so.IsDeleted, Is.True); | ||
279 | |||
280 | SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(so.LocalId); | ||
281 | Assert.That(retrievedPart2, Is.Null); | ||
282 | |||
283 | // SceneSetupHelpers.DeleteSceneObjectAsync(scene, part, DeRezAction.Take, userInfo.RootFolder.ID, client); | ||
284 | |||
285 | InventoryItemBase retrievedItem | ||
286 | = UserInventoryHelpers.GetInventoryItem( | ||
287 | scene.InventoryService, ua.PrincipalID, "folder1/" + myObjectName); | ||
288 | |||
289 | // Check that we now have the taken part in our inventory | ||
290 | Assert.That(retrievedItem, Is.Not.Null); | ||
291 | |||
292 | // Check that the taken part has actually disappeared | ||
293 | // SceneObjectPart retrievedPart = scene.GetSceneObjectPart(part.LocalId); | ||
294 | // Assert.That(retrievedPart, Is.Null); | ||
295 | } | ||
296 | |||
297 | /// <summary> | ||
298 | /// Changing a scene object uuid changes the root part uuid. This is a valid operation if the object is not | 209 | /// Changing a scene object uuid changes the root part uuid. This is a valid operation if the object is not |
299 | /// in a scene and is useful if one wants to supply a UUID directly rather than use the one generated by | 210 | /// in a scene and is useful if one wants to supply a UUID directly rather than use the one generated by |
300 | /// OpenSim. | 211 | /// OpenSim. |
@@ -329,4 +240,4 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
329 | Assert.That(sog.Parts.Length, Is.EqualTo(2)); | 240 | Assert.That(sog.Parts.Length, Is.EqualTo(2)); |
330 | } | 241 | } |
331 | } | 242 | } |
332 | } | 243 | } \ No newline at end of file |
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs index 0076f41..52ad538 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs | |||
@@ -33,22 +33,24 @@ using NUnit.Framework; | |||
33 | using OpenMetaverse; | 33 | using OpenMetaverse; |
34 | using OpenSim.Framework; | 34 | using OpenSim.Framework; |
35 | using OpenSim.Framework.Communications; | 35 | using OpenSim.Framework.Communications; |
36 | using OpenSim.Region.CoreModules.Framework.InventoryAccess; | ||
36 | using OpenSim.Region.CoreModules.World.Permissions; | 37 | using OpenSim.Region.CoreModules.World.Permissions; |
37 | using OpenSim.Region.Framework.Scenes; | 38 | using OpenSim.Region.Framework.Scenes; |
39 | using OpenSim.Services.Interfaces; | ||
38 | using OpenSim.Tests.Common; | 40 | using OpenSim.Tests.Common; |
39 | using OpenSim.Tests.Common.Mock; | 41 | using OpenSim.Tests.Common.Mock; |
40 | 42 | ||
41 | namespace OpenSim.Region.Framework.Scenes.Tests | 43 | namespace OpenSim.Region.Framework.Scenes.Tests |
42 | { | 44 | { |
43 | /// <summary> | 45 | /// <summary> |
44 | /// Tests derez of scene objects by users. | 46 | /// Tests derez of scene objects. |
45 | /// </summary> | 47 | /// </summary> |
46 | /// <remarks> | 48 | /// <remarks> |
47 | /// This is at a level above the SceneObjectBasicTests, which act on the scene directly. | 49 | /// This is at a level above the SceneObjectBasicTests, which act on the scene directly. |
48 | /// TODO: These tests are very incomplete - they only test for a few conditions. | 50 | /// TODO: These tests are incomplete - need to test more kinds of derez (e.g. return object). |
49 | /// </remarks> | 51 | /// </remarks> |
50 | [TestFixture] | 52 | [TestFixture] |
51 | public class SceneObjectDeRezTests | 53 | public class SceneObjectDeRezTests : OpenSimTestCase |
52 | { | 54 | { |
53 | /// <summary> | 55 | /// <summary> |
54 | /// Test deleting an object from a scene. | 56 | /// Test deleting an object from a scene. |
@@ -76,14 +78,20 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
76 | = new SceneObjectPart(userId, PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero); | 78 | = new SceneObjectPart(userId, PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero); |
77 | part.Name = "obj1"; | 79 | part.Name = "obj1"; |
78 | scene.AddNewSceneObject(new SceneObjectGroup(part), false); | 80 | scene.AddNewSceneObject(new SceneObjectGroup(part), false); |
81 | |||
79 | List<uint> localIds = new List<uint>(); | 82 | List<uint> localIds = new List<uint>(); |
80 | localIds.Add(part.LocalId); | 83 | localIds.Add(part.LocalId); |
81 | |||
82 | scene.DeRezObjects(client, localIds, UUID.Zero, DeRezAction.Delete, UUID.Zero); | 84 | scene.DeRezObjects(client, localIds, UUID.Zero, DeRezAction.Delete, UUID.Zero); |
85 | |||
86 | // Check that object isn't deleted until we crank the sogd handle. | ||
87 | SceneObjectPart retrievedPart = scene.GetSceneObjectPart(part.LocalId); | ||
88 | Assert.That(retrievedPart, Is.Not.Null); | ||
89 | Assert.That(retrievedPart.ParentGroup.IsDeleted, Is.False); | ||
90 | |||
83 | sogd.InventoryDeQueueAndDelete(); | 91 | sogd.InventoryDeQueueAndDelete(); |
84 | 92 | ||
85 | SceneObjectPart retrievedPart = scene.GetSceneObjectPart(part.LocalId); | 93 | SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(part.LocalId); |
86 | Assert.That(retrievedPart, Is.Null); | 94 | Assert.That(retrievedPart2, Is.Null); |
87 | } | 95 | } |
88 | 96 | ||
89 | /// <summary> | 97 | /// <summary> |
@@ -124,6 +132,67 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
124 | // Object should still be in the scene. | 132 | // Object should still be in the scene. |
125 | SceneObjectPart retrievedPart = scene.GetSceneObjectPart(part.LocalId); | 133 | SceneObjectPart retrievedPart = scene.GetSceneObjectPart(part.LocalId); |
126 | Assert.That(retrievedPart.UUID, Is.EqualTo(part.UUID)); | 134 | Assert.That(retrievedPart.UUID, Is.EqualTo(part.UUID)); |
127 | } | 135 | } |
136 | |||
137 | /// <summary> | ||
138 | /// Test deleting an object asynchronously to user inventory. | ||
139 | /// </summary> | ||
140 | [Test] | ||
141 | public void TestDeleteSceneObjectAsyncToUserInventory() | ||
142 | { | ||
143 | TestHelpers.InMethod(); | ||
144 | // TestHelpers.EnableLogging(); | ||
145 | |||
146 | UUID agentId = UUID.Parse("00000000-0000-0000-0000-000000000001"); | ||
147 | string myObjectName = "Fred"; | ||
148 | |||
149 | TestScene scene = new SceneHelpers().SetupScene(); | ||
150 | |||
151 | IConfigSource configSource = new IniConfigSource(); | ||
152 | IConfig config = configSource.AddConfig("Modules"); | ||
153 | config.Set("InventoryAccessModule", "BasicInventoryAccessModule"); | ||
154 | SceneHelpers.SetupSceneModules( | ||
155 | scene, configSource, new object[] { new BasicInventoryAccessModule() }); | ||
156 | |||
157 | SceneHelpers.SetupSceneModules(scene, new object[] { }); | ||
158 | |||
159 | // Turn off the timer on the async sog deleter - we'll crank it by hand for this test. | ||
160 | AsyncSceneObjectGroupDeleter sogd = scene.SceneObjectGroupDeleter; | ||
161 | sogd.Enabled = false; | ||
162 | |||
163 | SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, myObjectName, agentId); | ||
164 | |||
165 | UserAccount ua = UserAccountHelpers.CreateUserWithInventory(scene, agentId); | ||
166 | InventoryFolderBase folder1 | ||
167 | = UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, ua.PrincipalID, "folder1", false); | ||
168 | |||
169 | IClientAPI client = SceneHelpers.AddScenePresence(scene, agentId).ControllingClient; | ||
170 | scene.DeRezObjects(client, new List<uint>() { so.LocalId }, UUID.Zero, DeRezAction.Take, folder1.ID); | ||
171 | |||
172 | SceneObjectPart retrievedPart = scene.GetSceneObjectPart(so.LocalId); | ||
173 | |||
174 | Assert.That(retrievedPart, Is.Not.Null); | ||
175 | Assert.That(so.IsDeleted, Is.False); | ||
176 | |||
177 | sogd.InventoryDeQueueAndDelete(); | ||
178 | |||
179 | Assert.That(so.IsDeleted, Is.True); | ||
180 | |||
181 | SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(so.LocalId); | ||
182 | Assert.That(retrievedPart2, Is.Null); | ||
183 | |||
184 | // SceneSetupHelpers.DeleteSceneObjectAsync(scene, part, DeRezAction.Take, userInfo.RootFolder.ID, client); | ||
185 | |||
186 | InventoryItemBase retrievedItem | ||
187 | = UserInventoryHelpers.GetInventoryItem( | ||
188 | scene.InventoryService, ua.PrincipalID, "folder1/" + myObjectName); | ||
189 | |||
190 | // Check that we now have the taken part in our inventory | ||
191 | Assert.That(retrievedItem, Is.Not.Null); | ||
192 | |||
193 | // Check that the taken part has actually disappeared | ||
194 | // SceneObjectPart retrievedPart = scene.GetSceneObjectPart(part.LocalId); | ||
195 | // Assert.That(retrievedPart, Is.Null); | ||
196 | } | ||
128 | } | 197 | } |
129 | } \ No newline at end of file | 198 | } \ No newline at end of file |
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectLinkingTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectLinkingTests.cs index 0e525c9..9378e20 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectLinkingTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectLinkingTests.cs | |||
@@ -40,7 +40,7 @@ using log4net; | |||
40 | namespace OpenSim.Region.Framework.Scenes.Tests | 40 | namespace OpenSim.Region.Framework.Scenes.Tests |
41 | { | 41 | { |
42 | [TestFixture] | 42 | [TestFixture] |
43 | public class SceneObjectLinkingTests | 43 | public class SceneObjectLinkingTests : OpenSimTestCase |
44 | { | 44 | { |
45 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 45 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
46 | 46 | ||
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectResizeTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectResizeTests.cs index e931859..1182c96 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectResizeTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectResizeTests.cs | |||
@@ -41,7 +41,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
41 | /// Basic scene object resize tests | 41 | /// Basic scene object resize tests |
42 | /// </summary> | 42 | /// </summary> |
43 | [TestFixture] | 43 | [TestFixture] |
44 | public class SceneObjectResizeTests | 44 | public class SceneObjectResizeTests : OpenSimTestCase |
45 | { | 45 | { |
46 | /// <summary> | 46 | /// <summary> |
47 | /// Test resizing an object | 47 | /// Test resizing an object |
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectScriptTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectScriptTests.cs index d2361f8..a58e735 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectScriptTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectScriptTests.cs | |||
@@ -40,7 +40,7 @@ using OpenSim.Tests.Common.Mock; | |||
40 | namespace OpenSim.Region.Framework.Scenes.Tests | 40 | namespace OpenSim.Region.Framework.Scenes.Tests |
41 | { | 41 | { |
42 | [TestFixture] | 42 | [TestFixture] |
43 | public class SceneObjectScriptTests | 43 | public class SceneObjectScriptTests : OpenSimTestCase |
44 | { | 44 | { |
45 | [Test] | 45 | [Test] |
46 | public void TestAddScript() | 46 | public void TestAddScript() |
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectSpatialTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectSpatialTests.cs index 6d255aa..abaa1d1 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectSpatialTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectSpatialTests.cs | |||
@@ -42,14 +42,16 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
42 | /// Spatial scene object tests (will eventually cover root and child part position, rotation properties, etc.) | 42 | /// Spatial scene object tests (will eventually cover root and child part position, rotation properties, etc.) |
43 | /// </summary> | 43 | /// </summary> |
44 | [TestFixture] | 44 | [TestFixture] |
45 | public class SceneObjectSpatialTests | 45 | public class SceneObjectSpatialTests : OpenSimTestCase |
46 | { | 46 | { |
47 | TestScene m_scene; | 47 | TestScene m_scene; |
48 | UUID m_ownerId = TestHelpers.ParseTail(0x1); | 48 | UUID m_ownerId = TestHelpers.ParseTail(0x1); |
49 | 49 | ||
50 | [SetUp] | 50 | [SetUp] |
51 | public void SetUp() | 51 | public override void SetUp() |
52 | { | 52 | { |
53 | base.SetUp(); | ||
54 | |||
53 | m_scene = new SceneHelpers().SetupScene(); | 55 | m_scene = new SceneHelpers().SetupScene(); |
54 | } | 56 | } |
55 | 57 | ||
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs index 742c769..8eb3191 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs | |||
@@ -42,7 +42,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
42 | /// Basic scene object status tests | 42 | /// Basic scene object status tests |
43 | /// </summary> | 43 | /// </summary> |
44 | [TestFixture] | 44 | [TestFixture] |
45 | public class SceneObjectStatusTests | 45 | public class SceneObjectStatusTests : OpenSimTestCase |
46 | { | 46 | { |
47 | private TestScene m_scene; | 47 | private TestScene m_scene; |
48 | private UUID m_ownerId = TestHelpers.ParseTail(0x1); | 48 | private UUID m_ownerId = TestHelpers.ParseTail(0x1); |
@@ -78,6 +78,26 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
78 | } | 78 | } |
79 | 79 | ||
80 | [Test] | 80 | [Test] |
81 | public void TestSetNonPhysicsVolumeDetectSinglePrim() | ||
82 | { | ||
83 | TestHelpers.InMethod(); | ||
84 | |||
85 | m_scene.AddSceneObject(m_so1); | ||
86 | |||
87 | SceneObjectPart rootPart = m_so1.RootPart; | ||
88 | Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.None)); | ||
89 | |||
90 | m_so1.ScriptSetVolumeDetect(true); | ||
91 | |||
92 | // Console.WriteLine("so.RootPart.Flags [{0}]", so.RootPart.Flags); | ||
93 | Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.Phantom)); | ||
94 | |||
95 | m_so1.ScriptSetVolumeDetect(false); | ||
96 | |||
97 | Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.None)); | ||
98 | } | ||
99 | |||
100 | [Test] | ||
81 | public void TestSetPhysicsSinglePrim() | 101 | public void TestSetPhysicsSinglePrim() |
82 | { | 102 | { |
83 | TestHelpers.InMethod(); | 103 | TestHelpers.InMethod(); |
@@ -89,13 +109,32 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
89 | 109 | ||
90 | m_so1.ScriptSetPhysicsStatus(true); | 110 | m_so1.ScriptSetPhysicsStatus(true); |
91 | 111 | ||
92 | // Console.WriteLine("so.RootPart.Flags [{0}]", so.RootPart.Flags); | ||
93 | Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.Physics)); | 112 | Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.Physics)); |
94 | 113 | ||
95 | m_so1.ScriptSetPhysicsStatus(false); | 114 | m_so1.ScriptSetPhysicsStatus(false); |
96 | 115 | ||
97 | Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.None)); | 116 | Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.None)); |
98 | } | 117 | } |
118 | |||
119 | [Test] | ||
120 | public void TestSetPhysicsVolumeDetectSinglePrim() | ||
121 | { | ||
122 | TestHelpers.InMethod(); | ||
123 | |||
124 | m_scene.AddSceneObject(m_so1); | ||
125 | |||
126 | SceneObjectPart rootPart = m_so1.RootPart; | ||
127 | Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.None)); | ||
128 | |||
129 | m_so1.ScriptSetPhysicsStatus(true); | ||
130 | m_so1.ScriptSetVolumeDetect(true); | ||
131 | |||
132 | Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.Phantom | PrimFlags.Physics)); | ||
133 | |||
134 | m_so1.ScriptSetVolumeDetect(false); | ||
135 | |||
136 | Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.Physics)); | ||
137 | } | ||
99 | 138 | ||
100 | [Test] | 139 | [Test] |
101 | public void TestSetPhysicsLinkset() | 140 | public void TestSetPhysicsLinkset() |
diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs index 5faf131..bbfbbfc 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs | |||
@@ -289,108 +289,5 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
289 | // | 289 | // |
290 | // Assert.That(presence, Is.Null, "presence is not null"); | 290 | // Assert.That(presence, Is.Null, "presence is not null"); |
291 | // } | 291 | // } |
292 | |||
293 | // I'm commenting this test because it does not represent | ||
294 | // crossings. The Thread.Sleep's in here are not meaningful mocks, | ||
295 | // and they sometimes fail in panda. | ||
296 | // We need to talk in order to develop a test | ||
297 | // that really tests region crossings. There are 3 async components, | ||
298 | // but things are synchronous among them. So there should be | ||
299 | // 3 threads in here. | ||
300 | //[Test] | ||
301 | // public void T021_TestCrossToNewRegion() | ||
302 | // { | ||
303 | // TestHelpers.InMethod(); | ||
304 | // | ||
305 | // scene.RegisterRegionWithGrid(); | ||
306 | // scene2.RegisterRegionWithGrid(); | ||
307 | // | ||
308 | // // Adding child agent to region 1001 | ||
309 | // string reason; | ||
310 | // scene2.NewUserConnection(acd1,0, out reason); | ||
311 | // scene2.AddNewClient(testclient, PresenceType.User); | ||
312 | // | ||
313 | // ScenePresence presence = scene.GetScenePresence(agent1); | ||
314 | // presence.MakeRootAgent(new Vector3(0,unchecked(Constants.RegionSize-1),0), true); | ||
315 | // | ||
316 | // ScenePresence presence2 = scene2.GetScenePresence(agent1); | ||
317 | // | ||
318 | // // Adding neighbour region caps info to presence2 | ||
319 | // | ||
320 | // string cap = presence.ControllingClient.RequestClientInfo().CapsPath; | ||
321 | // presence2.AddNeighbourRegion(region1, cap); | ||
322 | // | ||
323 | // Assert.That(presence.IsChildAgent, Is.False, "Did not start root in origin region."); | ||
324 | // Assert.That(presence2.IsChildAgent, Is.True, "Is not a child on destination region."); | ||
325 | // | ||
326 | // // Cross to x+1 | ||
327 | // presence.AbsolutePosition = new Vector3(Constants.RegionSize+1,3,100); | ||
328 | // presence.Update(); | ||
329 | // | ||
330 | // EventWaitHandle wh = new EventWaitHandle (false, EventResetMode.AutoReset, "Crossing"); | ||
331 | // | ||
332 | // // Mimicking communication between client and server, by waiting OK from client | ||
333 | // // sent by TestClient.CrossRegion call. Originally, this is network comm. | ||
334 | // if (!wh.WaitOne(5000,false)) | ||
335 | // { | ||
336 | // presence.Update(); | ||
337 | // if (!wh.WaitOne(8000,false)) | ||
338 | // throw new ArgumentException("1 - Timeout waiting for signal/variable."); | ||
339 | // } | ||
340 | // | ||
341 | // // This is a TestClient specific method that fires OnCompleteMovementToRegion event, which | ||
342 | // // would normally be fired after receiving the reply packet from comm. done on the last line. | ||
343 | // testclient.CompleteMovement(); | ||
344 | // | ||
345 | // // Crossings are asynchronous | ||
346 | // int timer = 10; | ||
347 | // | ||
348 | // // Make sure cross hasn't already finished | ||
349 | // if (!presence.IsInTransit && !presence.IsChildAgent) | ||
350 | // { | ||
351 | // // If not and not in transit yet, give it some more time | ||
352 | // Thread.Sleep(5000); | ||
353 | // } | ||
354 | // | ||
355 | // // Enough time, should at least be in transit by now. | ||
356 | // while (presence.IsInTransit && timer > 0) | ||
357 | // { | ||
358 | // Thread.Sleep(1000); | ||
359 | // timer-=1; | ||
360 | // } | ||
361 | // | ||
362 | // Assert.That(timer,Is.GreaterThan(0),"Timed out waiting to cross 2->1."); | ||
363 | // Assert.That(presence.IsChildAgent, Is.True, "Did not complete region cross as expected."); | ||
364 | // Assert.That(presence2.IsChildAgent, Is.False, "Did not receive root status after receiving agent."); | ||
365 | // | ||
366 | // // Cross Back | ||
367 | // presence2.AbsolutePosition = new Vector3(-10, 3, 100); | ||
368 | // presence2.Update(); | ||
369 | // | ||
370 | // if (!wh.WaitOne(5000,false)) | ||
371 | // { | ||
372 | // presence2.Update(); | ||
373 | // if (!wh.WaitOne(8000,false)) | ||
374 | // throw new ArgumentException("2 - Timeout waiting for signal/variable."); | ||
375 | // } | ||
376 | // testclient.CompleteMovement(); | ||
377 | // | ||
378 | // if (!presence2.IsInTransit && !presence2.IsChildAgent) | ||
379 | // { | ||
380 | // // If not and not in transit yet, give it some more time | ||
381 | // Thread.Sleep(5000); | ||
382 | // } | ||
383 | // | ||
384 | // // Enough time, should at least be in transit by now. | ||
385 | // while (presence2.IsInTransit && timer > 0) | ||
386 | // { | ||
387 | // Thread.Sleep(1000); | ||
388 | // timer-=1; | ||
389 | // } | ||
390 | // | ||
391 | // Assert.That(timer,Is.GreaterThan(0),"Timed out waiting to cross 1->2."); | ||
392 | // Assert.That(presence2.IsChildAgent, Is.True, "Did not return from region as expected."); | ||
393 | // Assert.That(presence.IsChildAgent, Is.False, "Presence was not made root in old region again."); | ||
394 | // } | ||
395 | } | 292 | } |
396 | } \ No newline at end of file | 293 | } \ No newline at end of file |
diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAnimationTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAnimationTests.cs index 646e5fa..1cd8ae9 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAnimationTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAnimationTests.cs | |||
@@ -51,7 +51,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
51 | /// Scene presence animation tests | 51 | /// Scene presence animation tests |
52 | /// </summary> | 52 | /// </summary> |
53 | [TestFixture] | 53 | [TestFixture] |
54 | public class ScenePresenceAnimationTests | 54 | public class ScenePresenceAnimationTests : OpenSimTestCase |
55 | { | 55 | { |
56 | [Test] | 56 | [Test] |
57 | public void TestFlyingAnimation() | 57 | public void TestFlyingAnimation() |
diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAutopilotTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAutopilotTests.cs index 1d1ff88..d80afd3 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAutopilotTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAutopilotTests.cs | |||
@@ -42,7 +42,7 @@ using OpenSim.Tests.Common.Mock; | |||
42 | namespace OpenSim.Region.Framework.Scenes.Tests | 42 | namespace OpenSim.Region.Framework.Scenes.Tests |
43 | { | 43 | { |
44 | [TestFixture] | 44 | [TestFixture] |
45 | public class ScenePresenceAutopilotTests | 45 | public class ScenePresenceAutopilotTests : OpenSimTestCase |
46 | { | 46 | { |
47 | private TestScene m_scene; | 47 | private TestScene m_scene; |
48 | 48 | ||
diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs new file mode 100644 index 0000000..8775949 --- /dev/null +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs | |||
@@ -0,0 +1,162 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Reflection; | ||
31 | using Nini.Config; | ||
32 | using NUnit.Framework; | ||
33 | using OpenMetaverse; | ||
34 | using OpenSim.Framework; | ||
35 | using OpenSim.Framework.Communications; | ||
36 | using OpenSim.Framework.Servers; | ||
37 | using OpenSim.Region.Framework.Interfaces; | ||
38 | using OpenSim.Region.CoreModules.Framework; | ||
39 | using OpenSim.Region.CoreModules.Framework.EntityTransfer; | ||
40 | using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; | ||
41 | using OpenSim.Tests.Common; | ||
42 | using OpenSim.Tests.Common.Mock; | ||
43 | |||
44 | namespace OpenSim.Region.Framework.Scenes.Tests | ||
45 | { | ||
46 | [TestFixture] | ||
47 | public class ScenePresenceCrossingTests : OpenSimTestCase | ||
48 | { | ||
49 | [TestFixtureSetUp] | ||
50 | public void FixtureInit() | ||
51 | { | ||
52 | // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread. | ||
53 | Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest; | ||
54 | } | ||
55 | |||
56 | [TestFixtureTearDown] | ||
57 | public void TearDown() | ||
58 | { | ||
59 | // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple | ||
60 | // threads. Possibly, later tests should be rewritten so none of them require async stuff (which regression | ||
61 | // tests really shouldn't). | ||
62 | Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod; | ||
63 | } | ||
64 | |||
65 | [Test] | ||
66 | public void TestCrossOnSameSimulator() | ||
67 | { | ||
68 | TestHelpers.InMethod(); | ||
69 | // TestHelpers.EnableLogging(); | ||
70 | |||
71 | UUID userId = TestHelpers.ParseTail(0x1); | ||
72 | |||
73 | // TestEventQueueGetModule eqmA = new TestEventQueueGetModule(); | ||
74 | EntityTransferModule etmA = new EntityTransferModule(); | ||
75 | EntityTransferModule etmB = new EntityTransferModule(); | ||
76 | LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule(); | ||
77 | |||
78 | IConfigSource config = new IniConfigSource(); | ||
79 | IConfig modulesConfig = config.AddConfig("Modules"); | ||
80 | modulesConfig.Set("EntityTransferModule", etmA.Name); | ||
81 | modulesConfig.Set("SimulationServices", lscm.Name); | ||
82 | // IConfig entityTransferConfig = config.AddConfig("EntityTransfer"); | ||
83 | |||
84 | // In order to run a single threaded regression test we do not want the entity transfer module waiting | ||
85 | // for a callback from the destination scene before removing its avatar data. | ||
86 | // entityTransferConfig.Set("wait_for_callback", false); | ||
87 | |||
88 | SceneHelpers sh = new SceneHelpers(); | ||
89 | TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000); | ||
90 | TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1000, 999); | ||
91 | |||
92 | SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm); | ||
93 | SceneHelpers.SetupSceneModules(sceneA, config, new CapabilitiesModule(), etmA); | ||
94 | // SceneHelpers.SetupSceneModules(sceneA, config, new CapabilitiesModule(), etmA, eqmA); | ||
95 | SceneHelpers.SetupSceneModules(sceneB, config, new CapabilitiesModule(), etmB); | ||
96 | |||
97 | AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId); | ||
98 | TestClient tc = new TestClient(acd, sceneA, sh.SceneManager); | ||
99 | List<TestClient> destinationTestClients = new List<TestClient>(); | ||
100 | EntityTransferHelpers.SetUpInformClientOfNeighbour(tc, destinationTestClients); | ||
101 | |||
102 | ScenePresence originalSp = SceneHelpers.AddScenePresence(sceneA, tc, acd, sh.SceneManager); | ||
103 | originalSp.AbsolutePosition = new Vector3(128, 32, 10); | ||
104 | |||
105 | // originalSp.Flying = true; | ||
106 | |||
107 | // Console.WriteLine("First pos {0}", originalSp.AbsolutePosition); | ||
108 | |||
109 | // eqmA.ClearEvents(); | ||
110 | |||
111 | AgentUpdateArgs moveArgs = new AgentUpdateArgs(); | ||
112 | //moveArgs.BodyRotation = Quaternion.CreateFromEulers(Vector3.Zero); | ||
113 | moveArgs.BodyRotation = Quaternion.CreateFromEulers(new Vector3(0, 0, (float)-(Math.PI / 2))); | ||
114 | moveArgs.ControlFlags = (uint)AgentManager.ControlFlags.AGENT_CONTROL_AT_POS; | ||
115 | |||
116 | originalSp.HandleAgentUpdate(originalSp.ControllingClient, moveArgs); | ||
117 | |||
118 | sceneA.Update(1); | ||
119 | |||
120 | // Console.WriteLine("Second pos {0}", originalSp.AbsolutePosition); | ||
121 | |||
122 | // FIXME: This is a sufficient number of updates to for the presence to reach the northern border. | ||
123 | // But really we want to do this in a more robust way. | ||
124 | for (int i = 0; i < 100; i++) | ||
125 | { | ||
126 | sceneA.Update(1); | ||
127 | // Console.WriteLine("Pos {0}", originalSp.AbsolutePosition); | ||
128 | } | ||
129 | |||
130 | // Need to sort processing of EnableSimulator message on adding scene presences before we can test eqm | ||
131 | // messages | ||
132 | // Dictionary<UUID, List<TestEventQueueGetModule.Event>> eqmEvents = eqmA.Events; | ||
133 | // | ||
134 | // Assert.That(eqmEvents.Count, Is.EqualTo(1)); | ||
135 | // Assert.That(eqmEvents.ContainsKey(originalSp.UUID), Is.True); | ||
136 | // | ||
137 | // List<TestEventQueueGetModule.Event> spEqmEvents = eqmEvents[originalSp.UUID]; | ||
138 | // | ||
139 | // Assert.That(spEqmEvents.Count, Is.EqualTo(1)); | ||
140 | // Assert.That(spEqmEvents[0].Name, Is.EqualTo("CrossRegion")); | ||
141 | |||
142 | // sceneA should now only have a child agent | ||
143 | ScenePresence spAfterCrossSceneA = sceneA.GetScenePresence(originalSp.UUID); | ||
144 | Assert.That(spAfterCrossSceneA.IsChildAgent, Is.True); | ||
145 | |||
146 | ScenePresence spAfterCrossSceneB = sceneB.GetScenePresence(originalSp.UUID); | ||
147 | |||
148 | // Agent remains a child until the client triggers complete movement | ||
149 | Assert.That(spAfterCrossSceneB.IsChildAgent, Is.True); | ||
150 | |||
151 | TestClient sceneBTc = ((TestClient)spAfterCrossSceneB.ControllingClient); | ||
152 | |||
153 | int agentMovementCompleteReceived = 0; | ||
154 | sceneBTc.OnReceivedMoveAgentIntoRegion += (ri, pos, look) => agentMovementCompleteReceived++; | ||
155 | |||
156 | sceneBTc.CompleteMovement(); | ||
157 | |||
158 | Assert.That(agentMovementCompleteReceived, Is.EqualTo(1)); | ||
159 | Assert.That(spAfterCrossSceneB.IsChildAgent, Is.False); | ||
160 | } | ||
161 | } | ||
162 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceSitTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceSitTests.cs index 493ab70..acaeb90 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceSitTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceSitTests.cs | |||
@@ -43,7 +43,7 @@ using System.Threading; | |||
43 | namespace OpenSim.Region.Framework.Scenes.Tests | 43 | namespace OpenSim.Region.Framework.Scenes.Tests |
44 | { | 44 | { |
45 | [TestFixture] | 45 | [TestFixture] |
46 | public class ScenePresenceSitTests | 46 | public class ScenePresenceSitTests : OpenSimTestCase |
47 | { | 47 | { |
48 | private TestScene m_scene; | 48 | private TestScene m_scene; |
49 | private ScenePresence m_sp; | 49 | private ScenePresence m_sp; |
diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs index 37b5184..de4458d 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs | |||
@@ -26,7 +26,10 @@ | |||
26 | */ | 26 | */ |
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Reflection; | 29 | using System.Collections.Generic; |
30 | using System.IO; | ||
31 | using System.Net; | ||
32 | using System.Text; | ||
30 | using Nini.Config; | 33 | using Nini.Config; |
31 | using NUnit.Framework; | 34 | using NUnit.Framework; |
32 | using OpenMetaverse; | 35 | using OpenMetaverse; |
@@ -40,8 +43,6 @@ using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; | |||
40 | using OpenSim.Region.CoreModules.World.Permissions; | 43 | using OpenSim.Region.CoreModules.World.Permissions; |
41 | using OpenSim.Tests.Common; | 44 | using OpenSim.Tests.Common; |
42 | using OpenSim.Tests.Common.Mock; | 45 | using OpenSim.Tests.Common.Mock; |
43 | using System.IO; | ||
44 | using System.Text; | ||
45 | 46 | ||
46 | namespace OpenSim.Region.Framework.Scenes.Tests | 47 | namespace OpenSim.Region.Framework.Scenes.Tests |
47 | { | 48 | { |
@@ -49,7 +50,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
49 | /// Teleport tests in a standalone OpenSim | 50 | /// Teleport tests in a standalone OpenSim |
50 | /// </summary> | 51 | /// </summary> |
51 | [TestFixture] | 52 | [TestFixture] |
52 | public class ScenePresenceTeleportTests | 53 | public class ScenePresenceTeleportTests : OpenSimTestCase |
53 | { | 54 | { |
54 | [TestFixtureSetUp] | 55 | [TestFixtureSetUp] |
55 | public void FixtureInit() | 56 | public void FixtureInit() |
@@ -68,7 +69,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
68 | } | 69 | } |
69 | 70 | ||
70 | [Test] | 71 | [Test] |
71 | public void TestSameRegionTeleport() | 72 | public void TestSameRegion() |
72 | { | 73 | { |
73 | TestHelpers.InMethod(); | 74 | TestHelpers.InMethod(); |
74 | // log4net.Config.XmlConfigurator.Configure(); | 75 | // log4net.Config.XmlConfigurator.Configure(); |
@@ -106,10 +107,10 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
106 | } | 107 | } |
107 | 108 | ||
108 | [Test] | 109 | [Test] |
109 | public void TestSameSimulatorSeparatedRegionsTeleport() | 110 | public void TestSameSimulatorIsolatedRegions() |
110 | { | 111 | { |
111 | TestHelpers.InMethod(); | 112 | TestHelpers.InMethod(); |
112 | // log4net.Config.XmlConfigurator.Configure(); | 113 | // TestHelpers.EnableLogging(); |
113 | 114 | ||
114 | UUID userId = TestHelpers.ParseTail(0x1); | 115 | UUID userId = TestHelpers.ParseTail(0x1); |
115 | 116 | ||
@@ -141,9 +142,8 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
141 | ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId, sh.SceneManager); | 142 | ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId, sh.SceneManager); |
142 | sp.AbsolutePosition = new Vector3(30, 31, 32); | 143 | sp.AbsolutePosition = new Vector3(30, 31, 32); |
143 | 144 | ||
144 | // XXX: A very nasty hack to tell the client about the destination scene without having to crank the whole | 145 | List<TestClient> destinationTestClients = new List<TestClient>(); |
145 | // UDP stack (?) | 146 | EntityTransferHelpers.SetUpInformClientOfNeighbour((TestClient)sp.ControllingClient, destinationTestClients); |
146 | // ((TestClient)sp.ControllingClient).TeleportTargetScene = sceneB; | ||
147 | 147 | ||
148 | sceneA.RequestTeleportLocation( | 148 | sceneA.RequestTeleportLocation( |
149 | sp.ControllingClient, | 149 | sp.ControllingClient, |
@@ -152,7 +152,10 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
152 | teleportLookAt, | 152 | teleportLookAt, |
153 | (uint)TeleportFlags.ViaLocation); | 153 | (uint)TeleportFlags.ViaLocation); |
154 | 154 | ||
155 | ((TestClient)sp.ControllingClient).CompleteTeleportClientSide(); | 155 | // SetupInformClientOfNeighbour() will have handled the callback into the target scene to setup the child |
156 | // agent. This call will now complete the movement of the user into the destination and upgrade the agent | ||
157 | // from child to root. | ||
158 | destinationTestClients[0].CompleteMovement(); | ||
156 | 159 | ||
157 | Assert.That(sceneA.GetScenePresence(userId), Is.Null); | 160 | Assert.That(sceneA.GetScenePresence(userId), Is.Null); |
158 | 161 | ||
@@ -177,7 +180,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
177 | /// Test teleport procedures when the target simulator returns false when queried about access. | 180 | /// Test teleport procedures when the target simulator returns false when queried about access. |
178 | /// </summary> | 181 | /// </summary> |
179 | [Test] | 182 | [Test] |
180 | public void TestSameSimulatorSeparatedRegionsQueryAccessFails() | 183 | public void TestSameSimulatorIsolatedRegions_DeniedOnQueryAccess() |
181 | { | 184 | { |
182 | TestHelpers.InMethod(); | 185 | TestHelpers.InMethod(); |
183 | // TestHelpers.EnableLogging(); | 186 | // TestHelpers.EnableLogging(); |
@@ -261,7 +264,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
261 | /// Test teleport procedures when the target simulator create agent step is refused. | 264 | /// Test teleport procedures when the target simulator create agent step is refused. |
262 | /// </summary> | 265 | /// </summary> |
263 | [Test] | 266 | [Test] |
264 | public void TestSameSimulatorSeparatedRegionsCreateAgentFails() | 267 | public void TestSameSimulatorIsolatedRegions_DeniedOnCreateAgent() |
265 | { | 268 | { |
266 | TestHelpers.InMethod(); | 269 | TestHelpers.InMethod(); |
267 | // TestHelpers.EnableLogging(); | 270 | // TestHelpers.EnableLogging(); |
@@ -333,13 +336,101 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
333 | // TestHelpers.DisableLogging(); | 336 | // TestHelpers.DisableLogging(); |
334 | } | 337 | } |
335 | 338 | ||
339 | /// <summary> | ||
340 | /// Test teleport when the destination region does not process (or does not receive) the connection attempt | ||
341 | /// from the viewer. | ||
342 | /// </summary> | ||
343 | /// <remarks> | ||
344 | /// This could be quite a common case where the source region can connect to a remove destination region | ||
345 | /// (for CreateAgent) but the viewer cannot reach the destination region due to network issues. | ||
346 | /// </remarks> | ||
336 | [Test] | 347 | [Test] |
337 | public void TestSameSimulatorNeighbouringRegionsTeleport() | 348 | public void TestSameSimulatorIsolatedRegions_DestinationDidNotProcessViewerConnection() |
338 | { | 349 | { |
339 | TestHelpers.InMethod(); | 350 | TestHelpers.InMethod(); |
340 | // TestHelpers.EnableLogging(); | 351 | // TestHelpers.EnableLogging(); |
341 | 352 | ||
342 | UUID userId = TestHelpers.ParseTail(0x1); | 353 | UUID userId = TestHelpers.ParseTail(0x1); |
354 | Vector3 preTeleportPosition = new Vector3(30, 31, 32); | ||
355 | |||
356 | EntityTransferModule etmA = new EntityTransferModule(); | ||
357 | EntityTransferModule etmB = new EntityTransferModule(); | ||
358 | |||
359 | LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule(); | ||
360 | |||
361 | IConfigSource config = new IniConfigSource(); | ||
362 | config.AddConfig("Modules"); | ||
363 | config.Configs["Modules"].Set("EntityTransferModule", etmA.Name); | ||
364 | config.Configs["Modules"].Set("SimulationServices", lscm.Name); | ||
365 | |||
366 | config.AddConfig("EntityTransfer"); | ||
367 | |||
368 | // In order to run a single threaded regression test we do not want the entity transfer module waiting | ||
369 | // for a callback from the destination scene before removing its avatar data. | ||
370 | config.Configs["EntityTransfer"].Set("wait_for_callback", false); | ||
371 | |||
372 | // config.AddConfig("Startup"); | ||
373 | // config.Configs["Startup"].Set("serverside_object_permissions", true); | ||
374 | |||
375 | SceneHelpers sh = new SceneHelpers(); | ||
376 | TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000); | ||
377 | TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1002, 1000); | ||
378 | |||
379 | SceneHelpers.SetupSceneModules(sceneA, config, etmA ); | ||
380 | |||
381 | // We need to set up the permisions module on scene B so that our later use of agent limit to deny | ||
382 | // QueryAccess won't succeed anyway because administrators are always allowed in and the default | ||
383 | // IsAdministrator if no permissions module is present is true. | ||
384 | SceneHelpers.SetupSceneModules(sceneB, config, new object[] { new PermissionsModule(), etmB }); | ||
385 | |||
386 | // Shared scene modules | ||
387 | SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm); | ||
388 | |||
389 | Vector3 teleportPosition = new Vector3(10, 11, 12); | ||
390 | Vector3 teleportLookAt = new Vector3(20, 21, 22); | ||
391 | |||
392 | ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId, sh.SceneManager); | ||
393 | sp.AbsolutePosition = preTeleportPosition; | ||
394 | |||
395 | sceneA.RequestTeleportLocation( | ||
396 | sp.ControllingClient, | ||
397 | sceneB.RegionInfo.RegionHandle, | ||
398 | teleportPosition, | ||
399 | teleportLookAt, | ||
400 | (uint)TeleportFlags.ViaLocation); | ||
401 | |||
402 | // FIXME: Not setting up InformClientOfNeighbour on the TestClient means that it does not initiate | ||
403 | // communication with the destination region. But this is a very non-obvious way of doing it - really we | ||
404 | // should be forced to expicitly set this up. | ||
405 | |||
406 | Assert.That(sceneB.GetScenePresence(userId), Is.Null); | ||
407 | |||
408 | ScenePresence sceneASp = sceneA.GetScenePresence(userId); | ||
409 | Assert.That(sceneASp, Is.Not.Null); | ||
410 | Assert.That(sceneASp.Scene.RegionInfo.RegionName, Is.EqualTo(sceneA.RegionInfo.RegionName)); | ||
411 | Assert.That(sceneASp.AbsolutePosition, Is.EqualTo(preTeleportPosition)); | ||
412 | |||
413 | Assert.That(sceneA.GetRootAgentCount(), Is.EqualTo(1)); | ||
414 | Assert.That(sceneA.GetChildAgentCount(), Is.EqualTo(0)); | ||
415 | Assert.That(sceneB.GetRootAgentCount(), Is.EqualTo(0)); | ||
416 | Assert.That(sceneB.GetChildAgentCount(), Is.EqualTo(0)); | ||
417 | |||
418 | // TODO: Add assertions to check correct circuit details in both scenes. | ||
419 | |||
420 | // Lookat is sent to the client only - sp.Lookat does not yield the same thing (calculation from camera | ||
421 | // position instead). | ||
422 | // Assert.That(sp.Lookat, Is.EqualTo(teleportLookAt)); | ||
423 | |||
424 | // TestHelpers.DisableLogging(); | ||
425 | } | ||
426 | |||
427 | [Test] | ||
428 | public void TestSameSimulatorNeighbouringRegions() | ||
429 | { | ||
430 | TestHelpers.InMethod(); | ||
431 | TestHelpers.EnableLogging(); | ||
432 | |||
433 | UUID userId = TestHelpers.ParseTail(0x1); | ||
343 | 434 | ||
344 | EntityTransferModule etmA = new EntityTransferModule(); | 435 | EntityTransferModule etmA = new EntityTransferModule(); |
345 | EntityTransferModule etmB = new EntityTransferModule(); | 436 | EntityTransferModule etmB = new EntityTransferModule(); |
@@ -366,10 +457,14 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
366 | Vector3 teleportPosition = new Vector3(10, 11, 12); | 457 | Vector3 teleportPosition = new Vector3(10, 11, 12); |
367 | Vector3 teleportLookAt = new Vector3(20, 21, 22); | 458 | Vector3 teleportLookAt = new Vector3(20, 21, 22); |
368 | 459 | ||
369 | ScenePresence originalSp = SceneHelpers.AddScenePresence(sceneA, userId, sh.SceneManager); | 460 | AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId); |
370 | originalSp.AbsolutePosition = new Vector3(30, 31, 32); | 461 | TestClient tc = new TestClient(acd, sceneA, sh.SceneManager); |
462 | List<TestClient> destinationTestClients = new List<TestClient>(); | ||
463 | EntityTransferHelpers.SetUpInformClientOfNeighbour(tc, destinationTestClients); | ||
464 | |||
465 | ScenePresence beforeSceneASp = SceneHelpers.AddScenePresence(sceneA, tc, acd, sh.SceneManager); | ||
466 | beforeSceneASp.AbsolutePosition = new Vector3(30, 31, 32); | ||
371 | 467 | ||
372 | ScenePresence beforeSceneASp = sceneA.GetScenePresence(userId); | ||
373 | Assert.That(beforeSceneASp, Is.Not.Null); | 468 | Assert.That(beforeSceneASp, Is.Not.Null); |
374 | Assert.That(beforeSceneASp.IsChildAgent, Is.False); | 469 | Assert.That(beforeSceneASp.IsChildAgent, Is.False); |
375 | 470 | ||
@@ -377,10 +472,8 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
377 | Assert.That(beforeSceneBSp, Is.Not.Null); | 472 | Assert.That(beforeSceneBSp, Is.Not.Null); |
378 | Assert.That(beforeSceneBSp.IsChildAgent, Is.True); | 473 | Assert.That(beforeSceneBSp.IsChildAgent, Is.True); |
379 | 474 | ||
380 | // XXX: A very nasty hack to tell the client about the destination scene without having to crank the whole | 475 | // In this case, we will not receieve a second InformClientOfNeighbour since the viewer already knows |
381 | // UDP stack (?) | 476 | // about the neighbour region it is teleporting to. |
382 | // ((TestClient)beforeSceneASp.ControllingClient).TeleportTargetScene = sceneB; | ||
383 | |||
384 | sceneA.RequestTeleportLocation( | 477 | sceneA.RequestTeleportLocation( |
385 | beforeSceneASp.ControllingClient, | 478 | beforeSceneASp.ControllingClient, |
386 | sceneB.RegionInfo.RegionHandle, | 479 | sceneB.RegionInfo.RegionHandle, |
@@ -388,7 +481,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
388 | teleportLookAt, | 481 | teleportLookAt, |
389 | (uint)TeleportFlags.ViaLocation); | 482 | (uint)TeleportFlags.ViaLocation); |
390 | 483 | ||
391 | ((TestClient)beforeSceneASp.ControllingClient).CompleteTeleportClientSide(); | 484 | destinationTestClients[0].CompleteMovement(); |
392 | 485 | ||
393 | ScenePresence afterSceneASp = sceneA.GetScenePresence(userId); | 486 | ScenePresence afterSceneASp = sceneA.GetScenePresence(userId); |
394 | Assert.That(afterSceneASp, Is.Not.Null); | 487 | Assert.That(afterSceneASp, Is.Not.Null); |
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneTests.cs index ac3da1e..9d8eb0b 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneTests.cs | |||
@@ -50,7 +50,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
50 | /// Scene presence tests | 50 | /// Scene presence tests |
51 | /// </summary> | 51 | /// </summary> |
52 | [TestFixture] | 52 | [TestFixture] |
53 | public class SceneTests | 53 | public class SceneTests : OpenSimTestCase |
54 | { | 54 | { |
55 | /// <summary> | 55 | /// <summary> |
56 | /// Very basic scene update test. Should become more elaborate with time. | 56 | /// Very basic scene update test. Should become more elaborate with time. |
diff --git a/OpenSim/Region/Framework/Scenes/Tests/TaskInventoryTests.cs b/OpenSim/Region/Framework/Scenes/Tests/TaskInventoryTests.cs index a51e4e3..6e0ea7d 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/TaskInventoryTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/TaskInventoryTests.cs | |||
@@ -50,7 +50,7 @@ using OpenSim.Tests.Common.Mock; | |||
50 | namespace OpenSim.Region.Framework.Tests | 50 | namespace OpenSim.Region.Framework.Tests |
51 | { | 51 | { |
52 | [TestFixture] | 52 | [TestFixture] |
53 | public class TaskInventoryTests | 53 | public class TaskInventoryTests : OpenSimTestCase |
54 | { | 54 | { |
55 | [Test] | 55 | [Test] |
56 | public void TestAddTaskInventoryItem() | 56 | public void TestAddTaskInventoryItem() |
@@ -130,10 +130,10 @@ namespace OpenSim.Region.Framework.Tests | |||
130 | SceneObjectPart sop1 = sog1.RootPart; | 130 | SceneObjectPart sop1 = sog1.RootPart; |
131 | TaskInventoryItem sopItem1 | 131 | TaskInventoryItem sopItem1 |
132 | = TaskInventoryHelpers.AddNotecard( | 132 | = TaskInventoryHelpers.AddNotecard( |
133 | scene, sop1, "ncItem", TestHelpers.ParseTail(0x800), TestHelpers.ParseTail(0x900)); | 133 | scene, sop1, "ncItem", TestHelpers.ParseTail(0x800), TestHelpers.ParseTail(0x900), "Hello World!"); |
134 | 134 | ||
135 | InventoryFolderBase folder | 135 | InventoryFolderBase folder |
136 | = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, user1.PrincipalID, "Objects")[0]; | 136 | = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, user1.PrincipalID, "Objects")[0]; |
137 | 137 | ||
138 | // Perform test | 138 | // Perform test |
139 | scene.MoveTaskInventoryItem(user1.PrincipalID, folder.ID, sop1, sopItem1.ItemID); | 139 | scene.MoveTaskInventoryItem(user1.PrincipalID, folder.ID, sop1, sopItem1.ItemID); |
@@ -162,7 +162,7 @@ namespace OpenSim.Region.Framework.Tests | |||
162 | SceneObjectPart sop1 = sog1.RootPart; | 162 | SceneObjectPart sop1 = sog1.RootPart; |
163 | TaskInventoryItem sopItem1 | 163 | TaskInventoryItem sopItem1 |
164 | = TaskInventoryHelpers.AddNotecard( | 164 | = TaskInventoryHelpers.AddNotecard( |
165 | scene, sop1, "ncItem", TestHelpers.ParseTail(0x800), TestHelpers.ParseTail(0x900)); | 165 | scene, sop1, "ncItem", TestHelpers.ParseTail(0x800), TestHelpers.ParseTail(0x900), "Hello World!"); |
166 | 166 | ||
167 | // Perform test | 167 | // Perform test |
168 | scene.MoveTaskInventoryItem(user1.PrincipalID, UUID.Zero, sop1, sopItem1.ItemID); | 168 | scene.MoveTaskInventoryItem(user1.PrincipalID, UUID.Zero, sop1, sopItem1.ItemID); |
diff --git a/OpenSim/Region/Framework/Scenes/Tests/UserInventoryTests.cs b/OpenSim/Region/Framework/Scenes/Tests/UserInventoryTests.cs index 9457ebb..e50b4da 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/UserInventoryTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/UserInventoryTests.cs | |||
@@ -64,7 +64,7 @@ namespace OpenSim.Region.Framework.Tests | |||
64 | Scene scene = new SceneHelpers().SetupScene(); | 64 | Scene scene = new SceneHelpers().SetupScene(); |
65 | UserAccount user1 = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(1001)); | 65 | UserAccount user1 = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(1001)); |
66 | 66 | ||
67 | UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, user1.PrincipalID, foldersName); | 67 | UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, user1.PrincipalID, foldersName, false); |
68 | 68 | ||
69 | List<InventoryFolderBase> oneFolder | 69 | List<InventoryFolderBase> oneFolder |
70 | = UserInventoryHelpers.GetInventoryFolders(scene.InventoryService, user1.PrincipalID, foldersName); | 70 | = UserInventoryHelpers.GetInventoryFolders(scene.InventoryService, user1.PrincipalID, foldersName); |
@@ -73,7 +73,7 @@ namespace OpenSim.Region.Framework.Tests | |||
73 | InventoryFolderBase firstRetrievedFolder = oneFolder[0]; | 73 | InventoryFolderBase firstRetrievedFolder = oneFolder[0]; |
74 | Assert.That(firstRetrievedFolder.Name, Is.EqualTo(foldersName)); | 74 | Assert.That(firstRetrievedFolder.Name, Is.EqualTo(foldersName)); |
75 | 75 | ||
76 | UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, user1.PrincipalID, foldersName); | 76 | UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, user1.PrincipalID, foldersName, false); |
77 | 77 | ||
78 | List<InventoryFolderBase> twoFolders | 78 | List<InventoryFolderBase> twoFolders |
79 | = UserInventoryHelpers.GetInventoryFolders(scene.InventoryService, user1.PrincipalID, foldersName); | 79 | = UserInventoryHelpers.GetInventoryFolders(scene.InventoryService, user1.PrincipalID, foldersName); |
@@ -121,7 +121,7 @@ namespace OpenSim.Region.Framework.Tests | |||
121 | UserAccount user1 = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(1001)); | 121 | UserAccount user1 = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(1001)); |
122 | UserAccount user2 = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(1002)); | 122 | UserAccount user2 = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(1002)); |
123 | InventoryFolderBase folder1 | 123 | InventoryFolderBase folder1 |
124 | = UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, user1.PrincipalID, "folder1"); | 124 | = UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, user1.PrincipalID, "folder1", false); |
125 | 125 | ||
126 | scene.GiveInventoryFolder(user2.PrincipalID, user1.PrincipalID, folder1.ID, UUID.Zero); | 126 | scene.GiveInventoryFolder(user2.PrincipalID, user1.PrincipalID, folder1.ID, UUID.Zero); |
127 | 127 | ||
diff --git a/OpenSim/Region/Framework/Scenes/Tests/UuidGathererTests.cs b/OpenSim/Region/Framework/Scenes/Tests/UuidGathererTests.cs index 198e487..dd27294 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/UuidGathererTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/UuidGathererTests.cs | |||
@@ -38,7 +38,7 @@ using OpenSim.Tests.Common.Mock; | |||
38 | namespace OpenSim.Region.Framework.Scenes.Tests | 38 | namespace OpenSim.Region.Framework.Scenes.Tests |
39 | { | 39 | { |
40 | [TestFixture] | 40 | [TestFixture] |
41 | public class UuidGathererTests | 41 | public class UuidGathererTests : OpenSimTestCase |
42 | { | 42 | { |
43 | protected IAssetService m_assetService; | 43 | protected IAssetService m_assetService; |
44 | protected UuidGatherer m_uuidGatherer; | 44 | protected UuidGatherer m_uuidGatherer; |
diff --git a/OpenSim/Region/Framework/Scenes/UuidGatherer.cs b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs index 2279e62..b09ae39 100644 --- a/OpenSim/Region/Framework/Scenes/UuidGatherer.cs +++ b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs | |||
@@ -127,7 +127,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
127 | /// within this object). | 127 | /// within this object). |
128 | /// </remarks> | 128 | /// </remarks> |
129 | /// <param name="sceneObject">The scene object for which to gather assets</param> | 129 | /// <param name="sceneObject">The scene object for which to gather assets</param> |
130 | /// <param name="assetUuids">The assets gathered</param> | 130 | /// <param name="assetUuids"> |
131 | /// A dictionary which is populated with the asset UUIDs gathered and the type of that asset. | ||
132 | /// For assets where the type is not clear (e.g. UUIDs extracted from LSL and notecards), the type is Unknown. | ||
133 | /// </param> | ||
131 | public void GatherAssetUuids(SceneObjectGroup sceneObject, IDictionary<UUID, AssetType> assetUuids) | 134 | public void GatherAssetUuids(SceneObjectGroup sceneObject, IDictionary<UUID, AssetType> assetUuids) |
132 | { | 135 | { |
133 | // m_log.DebugFormat( | 136 | // m_log.DebugFormat( |
@@ -257,8 +260,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
257 | UUID uuid = new UUID(uuidMatch.Value); | 260 | UUID uuid = new UUID(uuidMatch.Value); |
258 | // m_log.DebugFormat("[ARCHIVER]: Recording {0} in text", uuid); | 261 | // m_log.DebugFormat("[ARCHIVER]: Recording {0} in text", uuid); |
259 | 262 | ||
260 | // Assume AssetIDs embedded are textures. | 263 | // Embedded asset references (if not false positives) could be for many types of asset, so we will |
261 | assetUuids[uuid] = AssetType.Texture; | 264 | // label these as unknown. |
265 | assetUuids[uuid] = AssetType.Unknown; | ||
262 | } | 266 | } |
263 | } | 267 | } |
264 | } | 268 | } |
diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs index 5ac4e27..686c605 100644 --- a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs +++ b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs | |||
@@ -976,12 +976,12 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server | |||
976 | // TODO | 976 | // TODO |
977 | } | 977 | } |
978 | 978 | ||
979 | public void SendGenericMessage(string method, List<string> message) | 979 | public void SendGenericMessage(string method, UUID invoice, List<string> message) |
980 | { | 980 | { |
981 | 981 | ||
982 | } | 982 | } |
983 | 983 | ||
984 | public void SendGenericMessage(string method, List<byte[]> message) | 984 | public void SendGenericMessage(string method, UUID invoice, List<byte[]> message) |
985 | { | 985 | { |
986 | 986 | ||
987 | } | 987 | } |
diff --git a/OpenSim/Region/OptionalModules/Avatar/Animations/AnimationsCommandModule.cs b/OpenSim/Region/OptionalModules/Avatar/Animations/AnimationsCommandModule.cs new file mode 100644 index 0000000..84211a9 --- /dev/null +++ b/OpenSim/Region/OptionalModules/Avatar/Animations/AnimationsCommandModule.cs | |||
@@ -0,0 +1,200 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Linq; | ||
31 | using System.Reflection; | ||
32 | using System.Text; | ||
33 | using log4net; | ||
34 | using Mono.Addins; | ||
35 | using Nini.Config; | ||
36 | using OpenMetaverse; | ||
37 | using OpenSim.Framework; | ||
38 | using OpenSim.Framework.Console; | ||
39 | using OpenSim.Framework.Monitoring; | ||
40 | using OpenSim.Region.ClientStack.LindenUDP; | ||
41 | using OpenSim.Region.Framework.Interfaces; | ||
42 | using OpenSim.Region.Framework.Scenes; | ||
43 | using OpenSim.Region.Framework.Scenes.Animation; | ||
44 | using OpenSim.Services.Interfaces; | ||
45 | |||
46 | namespace OpenSim.Region.OptionalModules.Avatar.Animations | ||
47 | { | ||
48 | /// <summary> | ||
49 | /// A module that just holds commands for inspecting avatar animations. | ||
50 | /// </summary> | ||
51 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "AnimationsCommandModule")] | ||
52 | public class AnimationsCommandModule : ISharedRegionModule | ||
53 | { | ||
54 | // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
55 | |||
56 | private List<Scene> m_scenes = new List<Scene>(); | ||
57 | |||
58 | public string Name { get { return "Animations Command Module"; } } | ||
59 | |||
60 | public Type ReplaceableInterface { get { return null; } } | ||
61 | |||
62 | public void Initialise(IConfigSource source) | ||
63 | { | ||
64 | // m_log.DebugFormat("[ANIMATIONS COMMAND MODULE]: INITIALIZED MODULE"); | ||
65 | } | ||
66 | |||
67 | public void PostInitialise() | ||
68 | { | ||
69 | // m_log.DebugFormat("[ANIMATIONS COMMAND MODULE]: POST INITIALIZED MODULE"); | ||
70 | } | ||
71 | |||
72 | public void Close() | ||
73 | { | ||
74 | // m_log.DebugFormat("[ANIMATIONS COMMAND MODULE]: CLOSED MODULE"); | ||
75 | } | ||
76 | |||
77 | public void AddRegion(Scene scene) | ||
78 | { | ||
79 | // m_log.DebugFormat("[ANIMATIONS COMMAND MODULE]: REGION {0} ADDED", scene.RegionInfo.RegionName); | ||
80 | } | ||
81 | |||
82 | public void RemoveRegion(Scene scene) | ||
83 | { | ||
84 | // m_log.DebugFormat("[ATTACHMENTS COMMAND MODULE]: REGION {0} REMOVED", scene.RegionInfo.RegionName); | ||
85 | |||
86 | lock (m_scenes) | ||
87 | m_scenes.Remove(scene); | ||
88 | } | ||
89 | |||
90 | public void RegionLoaded(Scene scene) | ||
91 | { | ||
92 | // m_log.DebugFormat("[ANIMATIONS COMMAND MODULE]: REGION {0} LOADED", scene.RegionInfo.RegionName); | ||
93 | |||
94 | lock (m_scenes) | ||
95 | m_scenes.Add(scene); | ||
96 | |||
97 | scene.AddCommand( | ||
98 | "Users", this, "show animations", | ||
99 | "show animations [<first-name> <last-name>]", | ||
100 | "Show animation information for avatars in this simulator.", | ||
101 | "If no name is supplied then information for all avatars is shown.\n" | ||
102 | + "Please note that for inventory animations, the animation name is the name under which the animation was originally uploaded\n" | ||
103 | + ", which is not necessarily the current inventory name.", | ||
104 | HandleShowAnimationsCommand); | ||
105 | } | ||
106 | |||
107 | protected void HandleShowAnimationsCommand(string module, string[] cmd) | ||
108 | { | ||
109 | if (cmd.Length != 2 && cmd.Length < 4) | ||
110 | { | ||
111 | MainConsole.Instance.OutputFormat("Usage: show animations [<first-name> <last-name>]"); | ||
112 | return; | ||
113 | } | ||
114 | |||
115 | bool targetNameSupplied = false; | ||
116 | string optionalTargetFirstName = null; | ||
117 | string optionalTargetLastName = null; | ||
118 | |||
119 | if (cmd.Length >= 4) | ||
120 | { | ||
121 | targetNameSupplied = true; | ||
122 | optionalTargetFirstName = cmd[2]; | ||
123 | optionalTargetLastName = cmd[3]; | ||
124 | } | ||
125 | |||
126 | StringBuilder sb = new StringBuilder(); | ||
127 | |||
128 | lock (m_scenes) | ||
129 | { | ||
130 | foreach (Scene scene in m_scenes) | ||
131 | { | ||
132 | if (targetNameSupplied) | ||
133 | { | ||
134 | ScenePresence sp = scene.GetScenePresence(optionalTargetFirstName, optionalTargetLastName); | ||
135 | if (sp != null && !sp.IsChildAgent) | ||
136 | GetAttachmentsReport(sp, sb); | ||
137 | } | ||
138 | else | ||
139 | { | ||
140 | scene.ForEachRootScenePresence(sp => GetAttachmentsReport(sp, sb)); | ||
141 | } | ||
142 | } | ||
143 | } | ||
144 | |||
145 | MainConsole.Instance.Output(sb.ToString()); | ||
146 | } | ||
147 | |||
148 | private void GetAttachmentsReport(ScenePresence sp, StringBuilder sb) | ||
149 | { | ||
150 | sb.AppendFormat("Animations for {0}\n", sp.Name); | ||
151 | |||
152 | ConsoleDisplayList cdl = new ConsoleDisplayList() { Indent = 2 }; | ||
153 | ScenePresenceAnimator spa = sp.Animator; | ||
154 | AnimationSet anims = sp.Animator.Animations; | ||
155 | |||
156 | string cma = spa.CurrentMovementAnimation; | ||
157 | cdl.AddRow( | ||
158 | "Current movement anim", | ||
159 | string.Format("{0}, {1}", DefaultAvatarAnimations.GetDefaultAnimation(cma), cma)); | ||
160 | |||
161 | UUID defaultAnimId = anims.DefaultAnimation.AnimID; | ||
162 | cdl.AddRow( | ||
163 | "Default anim", | ||
164 | string.Format("{0}, {1}", defaultAnimId, sp.Animator.GetAnimName(defaultAnimId))); | ||
165 | |||
166 | UUID implicitDefaultAnimId = anims.ImplicitDefaultAnimation.AnimID; | ||
167 | cdl.AddRow( | ||
168 | "Implicit default anim", | ||
169 | string.Format("{0}, {1}", | ||
170 | implicitDefaultAnimId, sp.Animator.GetAnimName(implicitDefaultAnimId))); | ||
171 | |||
172 | cdl.AddToStringBuilder(sb); | ||
173 | |||
174 | ConsoleDisplayTable cdt = new ConsoleDisplayTable() { Indent = 2 }; | ||
175 | cdt.AddColumn("Animation ID", 36); | ||
176 | cdt.AddColumn("Name", 20); | ||
177 | cdt.AddColumn("Seq", 3); | ||
178 | cdt.AddColumn("Object ID", 36); | ||
179 | |||
180 | UUID[] animIds; | ||
181 | int[] sequenceNumbers; | ||
182 | UUID[] objectIds; | ||
183 | |||
184 | sp.Animator.Animations.GetArrays(out animIds, out sequenceNumbers, out objectIds); | ||
185 | |||
186 | for (int i = 0; i < animIds.Length; i++) | ||
187 | { | ||
188 | UUID animId = animIds[i]; | ||
189 | string animName = sp.Animator.GetAnimName(animId); | ||
190 | int seq = sequenceNumbers[i]; | ||
191 | UUID objectId = objectIds[i]; | ||
192 | |||
193 | cdt.AddRow(animId, animName, seq, objectId); | ||
194 | } | ||
195 | |||
196 | cdt.AddToStringBuilder(sb); | ||
197 | sb.Append("\n"); | ||
198 | } | ||
199 | } | ||
200 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/OptionalModules/Avatar/Appearance/AppearanceInfoModule.cs b/OpenSim/Region/OptionalModules/Avatar/Appearance/AppearanceInfoModule.cs index d718a2f..fa35f0f 100644 --- a/OpenSim/Region/OptionalModules/Avatar/Appearance/AppearanceInfoModule.cs +++ b/OpenSim/Region/OptionalModules/Avatar/Appearance/AppearanceInfoModule.cs | |||
@@ -222,7 +222,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance | |||
222 | { | 222 | { |
223 | bool bakedTextureValid = scene.AvatarFactory.ValidateBakedTextureCache(sp); | 223 | bool bakedTextureValid = scene.AvatarFactory.ValidateBakedTextureCache(sp); |
224 | MainConsole.Instance.OutputFormat( | 224 | MainConsole.Instance.OutputFormat( |
225 | "{0} baked appearance texture is {1}", sp.Name, bakedTextureValid ? "OK" : "corrupt"); | 225 | "{0} baked appearance texture is {1}", sp.Name, bakedTextureValid ? "OK" : "incomplete"); |
226 | } | 226 | } |
227 | ); | 227 | ); |
228 | } | 228 | } |
diff --git a/OpenSim/Region/OptionalModules/Avatar/Attachments/AttachmentsCommandModule.cs b/OpenSim/Region/OptionalModules/Avatar/Attachments/AttachmentsCommandModule.cs index 68bcb4a..0333747 100644 --- a/OpenSim/Region/OptionalModules/Avatar/Attachments/AttachmentsCommandModule.cs +++ b/OpenSim/Region/OptionalModules/Avatar/Attachments/AttachmentsCommandModule.cs | |||
@@ -97,6 +97,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments | |||
97 | "Users", this, "attachments show", | 97 | "Users", this, "attachments show", |
98 | "attachments show [<first-name> <last-name>]", | 98 | "attachments show [<first-name> <last-name>]", |
99 | "Show attachment information for avatars in this simulator.", | 99 | "Show attachment information for avatars in this simulator.", |
100 | "If no name is supplied then information for all avatars is shown.", | ||
100 | HandleShowAttachmentsCommand); | 101 | HandleShowAttachmentsCommand); |
101 | } | 102 | } |
102 | 103 | ||
@@ -175,16 +176,13 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments | |||
175 | // " {0,-36} {1,-10} {2,-36} {3,-14} {4,-15}\n", | 176 | // " {0,-36} {1,-10} {2,-36} {3,-14} {4,-15}\n", |
176 | // attachmentObject.Name, attachmentObject.LocalId, attachmentObject.FromItemID, | 177 | // attachmentObject.Name, attachmentObject.LocalId, attachmentObject.FromItemID, |
177 | // (AttachmentPoint)attachmentObject.AttachmentPoint, attachmentObject.RootPart.AttachedPos); | 178 | // (AttachmentPoint)attachmentObject.AttachmentPoint, attachmentObject.RootPart.AttachedPos); |
178 | ct.Rows.Add( | 179 | |
179 | new ConsoleDisplayTableRow( | 180 | ct.AddRow( |
180 | new List<string>() | 181 | attachmentObject.Name, |
181 | { | 182 | attachmentObject.LocalId, |
182 | attachmentObject.Name, | 183 | attachmentObject.FromItemID, |
183 | attachmentObject.LocalId.ToString(), | 184 | ((AttachmentPoint)attachmentObject.AttachmentPoint), |
184 | attachmentObject.FromItemID.ToString(), | 185 | attachmentObject.RootPart.AttachedPos); |
185 | ((AttachmentPoint)attachmentObject.AttachmentPoint).ToString(), | ||
186 | attachmentObject.RootPart.AttachedPos.ToString() | ||
187 | })); | ||
188 | // } | 186 | // } |
189 | } | 187 | } |
190 | 188 | ||
diff --git a/OpenSim/Region/OptionalModules/Avatar/Attachments/TempAttachmentsModule.cs b/OpenSim/Region/OptionalModules/Avatar/Attachments/TempAttachmentsModule.cs index 17971e3..d56e39d 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; | |||
40 | using OpenSim.Region.ClientStack.LindenUDP; | 40 | using OpenSim.Region.ClientStack.LindenUDP; |
41 | using OpenSim.Region.Framework.Interfaces; | 41 | using OpenSim.Region.Framework.Interfaces; |
42 | using OpenSim.Region.Framework.Scenes; | 42 | using OpenSim.Region.Framework.Scenes; |
43 | using PermissionMask = OpenSim.Framework.PermissionMask; | ||
43 | 44 | ||
44 | namespace OpenSim.Region.OptionalModules.Avatar.Attachments | 45 | namespace 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, true) ? 1 : 0; | 187 | return attachmentsModule.AttachObject(target, hostPart.ParentGroup, (uint)attachmentPoint, false, false, true, 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..5a37fad 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 && |
@@ -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..c5cba8e 100644 --- a/OpenSim/Region/OptionalModules/Avatar/Chat/IRCConnector.cs +++ b/OpenSim/Region/OptionalModules/Avatar/Chat/IRCConnector.cs | |||
@@ -53,16 +53,16 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat | |||
53 | // Local constants | 53 | // Local constants |
54 | 54 | ||
55 | private static readonly Vector3 CenterOfRegion = new Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 20); | 55 | 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 = { ' ' }; | 56 | private static readonly char[] CS_SPACE = { ' ' }; |
57 | 57 | ||
58 | private const int WD_INTERVAL = 1000; // base watchdog interval | 58 | private const int WD_INTERVAL = 1000; // base watchdog interval |
59 | private static int PING_PERIOD = 15; // WD intervals per PING | 59 | private static int PING_PERIOD = 15; // WD intervals per PING |
60 | private static int ICCD_PERIOD = 10; // WD intervals between Connects | 60 | private static int ICCD_PERIOD = 10; // WD intervals between Connects |
61 | private static int L_TIMEOUT = 25; // Login time out interval | 61 | private static int L_TIMEOUT = 25; // Login time out interval |
62 | 62 | ||
63 | private static int _idk_ = 0; // core connector identifier | 63 | private static int _idk_ = 0; // core connector identifier |
64 | private static int _pdk_ = 0; // ping interval counter | 64 | private static int _pdk_ = 0; // ping interval counter |
65 | private static int _icc_ = ICCD_PERIOD; // IRC connect counter | 65 | private static int _icc_ = ICCD_PERIOD; // IRC connect counter |
66 | 66 | ||
67 | // List of configured connectors | 67 | // List of configured connectors |
68 | 68 | ||
@@ -113,7 +113,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat | |||
113 | 113 | ||
114 | private Object msyncConnect = new Object(); | 114 | private Object msyncConnect = new Object(); |
115 | 115 | ||
116 | internal bool m_randomizeNick = true; // add random suffix | 116 | internal bool m_randomizeNick = true; // add random suffix |
117 | internal string m_baseNick = null; // base name for randomizing | 117 | internal string m_baseNick = null; // base name for randomizing |
118 | internal string m_nick = null; // effective nickname | 118 | internal string m_nick = null; // effective nickname |
119 | 119 | ||
@@ -122,7 +122,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat | |||
122 | get { return m_nick; } | 122 | get { return m_nick; } |
123 | set { m_nick = value; } | 123 | set { m_nick = value; } |
124 | } | 124 | } |
125 | 125 | ||
126 | private bool m_enabled = false; // connector enablement | 126 | private bool m_enabled = false; // connector enablement |
127 | public bool Enabled | 127 | public bool Enabled |
128 | { | 128 | { |
@@ -130,8 +130,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat | |||
130 | } | 130 | } |
131 | 131 | ||
132 | private bool m_connected = false; // connection status | 132 | private bool m_connected = false; // connection status |
133 | private bool m_pending = false; // login disposition | 133 | private bool m_pending = false; // login disposition |
134 | private int m_timeout = L_TIMEOUT; // login timeout counter | 134 | private int m_timeout = L_TIMEOUT; // login timeout counter |
135 | public bool Connected | 135 | public bool Connected |
136 | { | 136 | { |
137 | get { return m_connected; } | 137 | get { return m_connected; } |
@@ -143,9 +143,9 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat | |||
143 | get { return m_ircChannel; } | 143 | get { return m_ircChannel; } |
144 | set { m_ircChannel = value; } | 144 | set { m_ircChannel = value; } |
145 | } | 145 | } |
146 | 146 | ||
147 | private uint m_port = 6667; // session port | 147 | private uint m_port = 6667; // session port |
148 | public uint Port | 148 | public uint Port |
149 | { | 149 | { |
150 | get { return m_port; } | 150 | get { return m_port; } |
151 | set { m_port = value; } | 151 | set { m_port = value; } |
@@ -172,10 +172,10 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat | |||
172 | 172 | ||
173 | // Network interface | 173 | // Network interface |
174 | 174 | ||
175 | private TcpClient m_tcp; | 175 | private TcpClient m_tcp; |
176 | private NetworkStream m_stream = null; | 176 | private NetworkStream m_stream = null; |
177 | private StreamReader m_reader; | 177 | private StreamReader m_reader; |
178 | private StreamWriter m_writer; | 178 | private StreamWriter m_writer; |
179 | 179 | ||
180 | // Channel characteristic info (if available) | 180 | // Channel characteristic info (if available) |
181 | 181 | ||
@@ -193,26 +193,26 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat | |||
193 | 193 | ||
194 | // Prepare network interface | 194 | // Prepare network interface |
195 | 195 | ||
196 | m_tcp = null; | 196 | m_tcp = null; |
197 | m_writer = null; | 197 | m_writer = null; |
198 | m_reader = null; | 198 | m_reader = null; |
199 | 199 | ||
200 | // Setup IRC session parameters | 200 | // Setup IRC session parameters |
201 | 201 | ||
202 | m_server = cs.Server; | 202 | m_server = cs.Server; |
203 | m_password = cs.Password; | 203 | m_password = cs.Password; |
204 | m_baseNick = cs.BaseNickname; | 204 | m_baseNick = cs.BaseNickname; |
205 | m_randomizeNick = cs.RandomizeNickname; | 205 | m_randomizeNick = cs.RandomizeNickname; |
206 | m_ircChannel = cs.IrcChannel; | 206 | m_ircChannel = cs.IrcChannel; |
207 | m_port = cs.Port; | 207 | m_port = cs.Port; |
208 | m_user = cs.User; | 208 | m_user = cs.User; |
209 | 209 | ||
210 | if (m_watchdog == null) | 210 | if (m_watchdog == null) |
211 | { | 211 | { |
212 | // Non-differentiating | 212 | // Non-differentiating |
213 | 213 | ||
214 | ICCD_PERIOD = cs.ConnectDelay; | 214 | ICCD_PERIOD = cs.ConnectDelay; |
215 | PING_PERIOD = cs.PingDelay; | 215 | PING_PERIOD = cs.PingDelay; |
216 | 216 | ||
217 | // Smaller values are not reasonable | 217 | // Smaller values are not reasonable |
218 | 218 | ||
@@ -235,7 +235,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat | |||
235 | 235 | ||
236 | if (m_randomizeNick) | 236 | if (m_randomizeNick) |
237 | m_nick = m_baseNick + Util.RandomClass.Next(1, 99); | 237 | m_nick = m_baseNick + Util.RandomClass.Next(1, 99); |
238 | else | 238 | else |
239 | m_nick = m_baseNick; | 239 | m_nick = m_baseNick; |
240 | 240 | ||
241 | m_log.InfoFormat("[IRC-Connector-{0}]: Initialization complete", idn); | 241 | m_log.InfoFormat("[IRC-Connector-{0}]: Initialization complete", idn); |
@@ -295,18 +295,22 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat | |||
295 | m_nick, m_ircChannel, m_server)); | 295 | m_nick, m_ircChannel, m_server)); |
296 | m_writer.Flush(); | 296 | m_writer.Flush(); |
297 | } | 297 | } |
298 | catch (Exception) {} | 298 | catch (Exception) { } |
299 | 299 | ||
300 | 300 | ||
301 | m_connected = false; | 301 | m_connected = false; |
302 | 302 | ||
303 | try { m_writer.Close(); } catch (Exception) {} | 303 | try { m_writer.Close(); } |
304 | try { m_reader.Close(); } catch (Exception) {} | 304 | catch (Exception) { } |
305 | try { m_stream.Close(); } catch (Exception) {} | 305 | try { m_reader.Close(); } |
306 | try { m_tcp.Close(); } catch (Exception) {} | 306 | catch (Exception) { } |
307 | try { m_stream.Close(); } | ||
308 | catch (Exception) { } | ||
309 | try { m_tcp.Close(); } | ||
310 | catch (Exception) { } | ||
307 | 311 | ||
308 | } | 312 | } |
309 | 313 | ||
310 | lock (m_connectors) | 314 | lock (m_connectors) |
311 | m_connectors.Remove(this); | 315 | m_connectors.Remove(this); |
312 | 316 | ||
@@ -347,15 +351,15 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat | |||
347 | if (m_connected) return; | 351 | if (m_connected) return; |
348 | 352 | ||
349 | m_connected = true; | 353 | m_connected = true; |
350 | m_pending = true; | 354 | m_pending = true; |
351 | m_timeout = L_TIMEOUT; | 355 | m_timeout = L_TIMEOUT; |
352 | 356 | ||
353 | m_tcp = new TcpClient(m_server, (int)m_port); | 357 | m_tcp = new TcpClient(m_server, (int)m_port); |
354 | m_stream = m_tcp.GetStream(); | 358 | m_stream = m_tcp.GetStream(); |
355 | m_reader = new StreamReader(m_stream); | 359 | m_reader = new StreamReader(m_stream); |
356 | m_writer = new StreamWriter(m_stream); | 360 | m_writer = new StreamWriter(m_stream); |
357 | 361 | ||
358 | m_log.InfoFormat("[IRC-Connector-{0}]: Connected to {1}:{2}", idn, m_server, m_port); | 362 | m_log.InfoFormat("[IRC-Connector-{0}]: Connected to {1}:{2}", idn, m_server, m_port); |
359 | 363 | ||
360 | m_listener = new Thread(new ThreadStart(ListenerRun)); | 364 | m_listener = new Thread(new ThreadStart(ListenerRun)); |
361 | m_listener.Name = "IRCConnectorListenerThread"; | 365 | m_listener.Name = "IRCConnectorListenerThread"; |
@@ -418,12 +422,15 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat | |||
418 | // the socket and it will disappear of its own accord, once this | 422 | // the socket and it will disappear of its own accord, once this |
419 | // processing is completed. | 423 | // processing is completed. |
420 | 424 | ||
421 | try { m_writer.Close(); } catch (Exception) {} | 425 | try { m_writer.Close(); } |
422 | try { m_reader.Close(); } catch (Exception) {} | 426 | catch (Exception) { } |
423 | try { m_tcp.Close(); } catch (Exception) {} | 427 | try { m_reader.Close(); } |
428 | catch (Exception) { } | ||
429 | try { m_tcp.Close(); } | ||
430 | catch (Exception) { } | ||
424 | 431 | ||
425 | m_connected = false; | 432 | m_connected = false; |
426 | m_pending = false; | 433 | m_pending = false; |
427 | m_resetk++; | 434 | m_resetk++; |
428 | 435 | ||
429 | } | 436 | } |
@@ -495,7 +502,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat | |||
495 | { | 502 | { |
496 | 503 | ||
497 | string inputLine; | 504 | string inputLine; |
498 | int resetk = m_resetk; | 505 | int resetk = m_resetk; |
499 | 506 | ||
500 | try | 507 | try |
501 | { | 508 | { |
@@ -555,7 +562,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat | |||
555 | Reconnect(); | 562 | Reconnect(); |
556 | } | 563 | } |
557 | 564 | ||
558 | private Regex RE = new Regex(@":(?<nick>[\w-]*)!(?<user>\S*) PRIVMSG (?<channel>\S+) :(?<msg>.*)", | 565 | private Regex RE = new Regex(@":(?<nick>[\w-]*)!(?<user>\S*) PRIVMSG (?<channel>\S+) :(?<msg>.*)", |
559 | RegexOptions.Multiline); | 566 | RegexOptions.Multiline); |
560 | 567 | ||
561 | private Dictionary<string, string> ExtractMsg(string input) | 568 | private Dictionary<string, string> ExtractMsg(string input) |
@@ -617,8 +624,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat | |||
617 | string[] commArgs; | 624 | string[] commArgs; |
618 | string c_server = m_server; | 625 | string c_server = m_server; |
619 | 626 | ||
620 | string pfx = String.Empty; | 627 | string pfx = String.Empty; |
621 | string cmd = String.Empty; | 628 | string cmd = String.Empty; |
622 | string parms = String.Empty; | 629 | string parms = String.Empty; |
623 | 630 | ||
624 | // ":" indicates that a prefix is present | 631 | // ":" indicates that a prefix is present |
@@ -627,15 +634,15 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat | |||
627 | // ":" indicates that the remainder of the | 634 | // ":" indicates that the remainder of the |
628 | // line is a single parameter value. | 635 | // line is a single parameter value. |
629 | 636 | ||
630 | commArgs = command.Split(CS_SPACE,2); | 637 | commArgs = command.Split(CS_SPACE, 2); |
631 | 638 | ||
632 | if (commArgs[0].StartsWith(":")) | 639 | if (commArgs[0].StartsWith(":")) |
633 | { | 640 | { |
634 | pfx = commArgs[0].Substring(1); | 641 | pfx = commArgs[0].Substring(1); |
635 | commArgs = commArgs[1].Split(CS_SPACE,2); | 642 | commArgs = commArgs[1].Split(CS_SPACE, 2); |
636 | } | 643 | } |
637 | 644 | ||
638 | cmd = commArgs[0]; | 645 | cmd = commArgs[0]; |
639 | parms = commArgs[1]; | 646 | parms = commArgs[1]; |
640 | 647 | ||
641 | // m_log.DebugFormat("[IRC-Connector-{0}] prefix = <{1}> cmd = <{2}>", idn, pfx, cmd); | 648 | // m_log.DebugFormat("[IRC-Connector-{0}] prefix = <{1}> cmd = <{2}>", idn, pfx, cmd); |
@@ -646,44 +653,44 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat | |||
646 | // Messages 001-004 are always sent | 653 | // Messages 001-004 are always sent |
647 | // following signon. | 654 | // following signon. |
648 | 655 | ||
649 | case "001" : // Welcome ... | 656 | case "001": // Welcome ... |
650 | case "002" : // Server information | 657 | case "002": // Server information |
651 | case "003" : // Welcome ... | 658 | case "003": // Welcome ... |
652 | break; | 659 | break; |
653 | case "004" : // Server information | 660 | case "004": // Server information |
654 | m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms); | 661 | m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms); |
655 | commArgs = parms.Split(CS_SPACE); | 662 | commArgs = parms.Split(CS_SPACE); |
656 | c_server = commArgs[1]; | 663 | c_server = commArgs[1]; |
657 | m_server = c_server; | 664 | m_server = c_server; |
658 | version = commArgs[2]; | 665 | version = commArgs[2]; |
659 | usermod = commArgs[3]; | 666 | usermod = commArgs[3]; |
660 | chanmod = commArgs[4]; | 667 | chanmod = commArgs[4]; |
661 | break; | 668 | break; |
662 | case "005" : // Server information | 669 | case "005": // Server information |
663 | break; | 670 | break; |
664 | case "042" : | 671 | case "042": |
665 | case "250" : | 672 | case "250": |
666 | case "251" : | 673 | case "251": |
667 | case "252" : | 674 | case "252": |
668 | case "254" : | 675 | case "254": |
669 | case "255" : | 676 | case "255": |
670 | case "265" : | 677 | case "265": |
671 | case "266" : | 678 | case "266": |
672 | case "332" : // Subject | 679 | case "332": // Subject |
673 | case "333" : // Subject owner (?) | 680 | case "333": // Subject owner (?) |
674 | case "353" : // Name list | 681 | case "353": // Name list |
675 | case "366" : // End-of-Name list marker | 682 | case "366": // End-of-Name list marker |
676 | case "372" : // MOTD body | 683 | case "372": // MOTD body |
677 | case "375" : // MOTD start | 684 | case "375": // MOTD start |
678 | // m_log.InfoFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]); | 685 | // m_log.InfoFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]); |
679 | break; | 686 | break; |
680 | case "376" : // MOTD end | 687 | case "376": // MOTD end |
681 | // m_log.InfoFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]); | 688 | // m_log.InfoFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]); |
682 | motd = true; | 689 | motd = true; |
683 | break; | 690 | break; |
684 | case "451" : // Not registered | 691 | case "451": // Not registered |
685 | break; | 692 | break; |
686 | case "433" : // Nickname in use | 693 | case "433": // Nickname in use |
687 | // Gen a new name | 694 | // Gen a new name |
688 | m_nick = m_baseNick + Util.RandomClass.Next(1, 99); | 695 | 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); | 696 | m_log.ErrorFormat("[IRC-Connector-{0}]: [{1}] IRC SERVER reports NicknameInUse, trying {2}", idn, cmd, m_nick); |
@@ -695,29 +702,29 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat | |||
695 | m_writer.WriteLine(String.Format("JOIN {0}", m_ircChannel)); | 702 | m_writer.WriteLine(String.Format("JOIN {0}", m_ircChannel)); |
696 | m_writer.Flush(); | 703 | m_writer.Flush(); |
697 | break; | 704 | break; |
698 | case "479" : // Bad channel name, etc. This will never work, so disable the connection | 705 | 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]); | 706 | 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); | 707 | m_log.ErrorFormat("[IRC-Connector-{0}] [{1}] Connector disabled", idn, cmd); |
701 | m_enabled = false; | 708 | m_enabled = false; |
702 | m_connected = false; | 709 | m_connected = false; |
703 | m_pending = false; | 710 | m_pending = false; |
704 | break; | 711 | break; |
705 | case "NOTICE" : | 712 | case "NOTICE": |
706 | // m_log.WarnFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]); | 713 | // m_log.WarnFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]); |
707 | break; | 714 | break; |
708 | case "ERROR" : | 715 | case "ERROR": |
709 | m_log.ErrorFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]); | 716 | m_log.ErrorFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE, 2)[1]); |
710 | if (parms.Contains("reconnect too fast")) | 717 | if (parms.Contains("reconnect too fast")) |
711 | ICCD_PERIOD++; | 718 | ICCD_PERIOD++; |
712 | m_pending = false; | 719 | m_pending = false; |
713 | Reconnect(); | 720 | Reconnect(); |
714 | break; | 721 | break; |
715 | case "PING" : | 722 | case "PING": |
716 | m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms); | 723 | m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms); |
717 | m_writer.WriteLine(String.Format("PONG {0}", parms)); | 724 | m_writer.WriteLine(String.Format("PONG {0}", parms)); |
718 | m_writer.Flush(); | 725 | m_writer.Flush(); |
719 | break; | 726 | break; |
720 | case "PONG" : | 727 | case "PONG": |
721 | break; | 728 | break; |
722 | case "JOIN": | 729 | case "JOIN": |
723 | if (m_pending) | 730 | if (m_pending) |
@@ -748,19 +755,19 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat | |||
748 | m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms); | 755 | m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms); |
749 | eventIrcQuit(pfx, cmd, parms); | 756 | eventIrcQuit(pfx, cmd, parms); |
750 | break; | 757 | break; |
751 | default : | 758 | default: |
752 | m_log.DebugFormat("[IRC-Connector-{0}] Command '{1}' ignored, parms = {2}", idn, cmd, parms); | 759 | m_log.DebugFormat("[IRC-Connector-{0}] Command '{1}' ignored, parms = {2}", idn, cmd, parms); |
753 | break; | 760 | break; |
754 | } | 761 | } |
755 | 762 | ||
756 | // m_log.DebugFormat("[IRC-Connector-{0}] prefix = <{1}> cmd = <{2}> complete", idn, pfx, cmd); | 763 | // m_log.DebugFormat("[IRC-Connector-{0}] prefix = <{1}> cmd = <{2}> complete", idn, pfx, cmd); |
757 | 764 | ||
758 | } | 765 | } |
759 | 766 | ||
760 | public void eventIrcJoin(string prefix, string command, string parms) | 767 | public void eventIrcJoin(string prefix, string command, string parms) |
761 | { | 768 | { |
762 | string[] args = parms.Split(CS_SPACE,2); | 769 | string[] args = parms.Split(CS_SPACE, 2); |
763 | string IrcUser = prefix.Split('!')[0]; | 770 | string IrcUser = prefix.Split('!')[0]; |
764 | string IrcChannel = args[0]; | 771 | string IrcChannel = args[0]; |
765 | 772 | ||
766 | if (IrcChannel.StartsWith(":")) | 773 | if (IrcChannel.StartsWith(":")) |
@@ -772,8 +779,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat | |||
772 | 779 | ||
773 | public void eventIrcPart(string prefix, string command, string parms) | 780 | public void eventIrcPart(string prefix, string command, string parms) |
774 | { | 781 | { |
775 | string[] args = parms.Split(CS_SPACE,2); | 782 | string[] args = parms.Split(CS_SPACE, 2); |
776 | string IrcUser = prefix.Split('!')[0]; | 783 | string IrcUser = prefix.Split('!')[0]; |
777 | string IrcChannel = args[0]; | 784 | string IrcChannel = args[0]; |
778 | 785 | ||
779 | m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCPart {1}:{2}", idn, m_server, m_ircChannel); | 786 | m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCPart {1}:{2}", idn, m_server, m_ircChannel); |
@@ -782,7 +789,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat | |||
782 | 789 | ||
783 | public void eventIrcMode(string prefix, string command, string parms) | 790 | public void eventIrcMode(string prefix, string command, string parms) |
784 | { | 791 | { |
785 | string[] args = parms.Split(CS_SPACE,2); | 792 | string[] args = parms.Split(CS_SPACE, 2); |
786 | string UserMode = args[1]; | 793 | string UserMode = args[1]; |
787 | 794 | ||
788 | m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCMode {1}:{2}", idn, m_server, m_ircChannel); | 795 | m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCMode {1}:{2}", idn, m_server, m_ircChannel); |
@@ -794,7 +801,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat | |||
794 | 801 | ||
795 | public void eventIrcNickChange(string prefix, string command, string parms) | 802 | public void eventIrcNickChange(string prefix, string command, string parms) |
796 | { | 803 | { |
797 | string[] args = parms.Split(CS_SPACE,2); | 804 | string[] args = parms.Split(CS_SPACE, 2); |
798 | string UserOldNick = prefix.Split('!')[0]; | 805 | string UserOldNick = prefix.Split('!')[0]; |
799 | string UserNewNick = args[0].Remove(0, 1); | 806 | string UserNewNick = args[0].Remove(0, 1); |
800 | 807 | ||
@@ -804,11 +811,11 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat | |||
804 | 811 | ||
805 | public void eventIrcKick(string prefix, string command, string parms) | 812 | public void eventIrcKick(string prefix, string command, string parms) |
806 | { | 813 | { |
807 | string[] args = parms.Split(CS_SPACE,3); | 814 | string[] args = parms.Split(CS_SPACE, 3); |
808 | string UserKicker = prefix.Split('!')[0]; | 815 | string UserKicker = prefix.Split('!')[0]; |
809 | string IrcChannel = args[0]; | 816 | string IrcChannel = args[0]; |
810 | string UserKicked = args[1]; | 817 | string UserKicked = args[1]; |
811 | string KickMessage = args[2]; | 818 | string KickMessage = args[2]; |
812 | 819 | ||
813 | m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCKick {1}:{2}", idn, m_server, m_ircChannel); | 820 | 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); | 821 | BroadcastSim(UserKicker, "/me kicks kicks {0} off {1} saying \"{2}\"", UserKicked, IrcChannel, KickMessage); |
@@ -822,7 +829,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat | |||
822 | 829 | ||
823 | public void eventIrcQuit(string prefix, string command, string parms) | 830 | public void eventIrcQuit(string prefix, string command, string parms) |
824 | { | 831 | { |
825 | string IrcUser = prefix.Split('!')[0]; | 832 | string IrcUser = prefix.Split('!')[0]; |
826 | string QuitMessage = parms; | 833 | string QuitMessage = parms; |
827 | 834 | ||
828 | m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCQuit {1}:{2}", idn, m_server, m_ircChannel); | 835 | m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCQuit {1}:{2}", idn, m_server, m_ircChannel); |
@@ -842,65 +849,65 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat | |||
842 | 849 | ||
843 | // m_log.InfoFormat("[IRC-Watchdog] Status scan, pdk = {0}, icc = {1}", _pdk_, _icc_); | 850 | // m_log.InfoFormat("[IRC-Watchdog] Status scan, pdk = {0}, icc = {1}", _pdk_, _icc_); |
844 | 851 | ||
845 | _pdk_ = (_pdk_+1)%PING_PERIOD; // cycle the ping trigger | 852 | _pdk_ = (_pdk_ + 1) % PING_PERIOD; // cycle the ping trigger |
846 | _icc_++; // increment the inter-consecutive-connect-delay counter | 853 | _icc_++; // increment the inter-consecutive-connect-delay counter |
847 | 854 | ||
848 | lock (m_connectors) | 855 | lock (m_connectors) |
849 | foreach (IRCConnector connector in m_connectors) | 856 | foreach (IRCConnector connector in m_connectors) |
850 | { | 857 | { |
851 | 858 | ||
852 | // m_log.InfoFormat("[IRC-Watchdog] Scanning {0}", connector); | 859 | // m_log.InfoFormat("[IRC-Watchdog] Scanning {0}", connector); |
853 | 860 | ||
854 | if (connector.Enabled) | 861 | if (connector.Enabled) |
855 | { | ||
856 | if (!connector.Connected) | ||
857 | { | 862 | { |
858 | try | 863 | if (!connector.Connected) |
859 | { | 864 | { |
860 | // m_log.DebugFormat("[IRC-Watchdog] Connecting {1}:{2}", connector.idn, connector.m_server, connector.m_ircChannel); | 865 | try |
861 | connector.Connect(); | 866 | { |
867 | // m_log.DebugFormat("[IRC-Watchdog] Connecting {1}:{2}", connector.idn, connector.m_server, connector.m_ircChannel); | ||
868 | connector.Connect(); | ||
869 | } | ||
870 | catch (Exception e) | ||
871 | { | ||
872 | m_log.ErrorFormat("[IRC-Watchdog] Exception on connector {0}: {1} ", connector.idn, e.Message); | ||
873 | } | ||
862 | } | 874 | } |
863 | catch (Exception e) | 875 | else |
864 | { | 876 | { |
865 | m_log.ErrorFormat("[IRC-Watchdog] Exception on connector {0}: {1} ", connector.idn, e.Message); | ||
866 | } | ||
867 | } | ||
868 | else | ||
869 | { | ||
870 | 877 | ||
871 | if (connector.m_pending) | 878 | if (connector.m_pending) |
872 | { | ||
873 | if (connector.m_timeout == 0) | ||
874 | { | 879 | { |
875 | m_log.ErrorFormat("[IRC-Watchdog] Login timed-out for connector {0}, reconnecting", connector.idn); | 880 | if (connector.m_timeout == 0) |
876 | connector.Reconnect(); | 881 | { |
882 | m_log.ErrorFormat("[IRC-Watchdog] Login timed-out for connector {0}, reconnecting", connector.idn); | ||
883 | connector.Reconnect(); | ||
884 | } | ||
885 | else | ||
886 | connector.m_timeout--; | ||
877 | } | 887 | } |
878 | else | ||
879 | connector.m_timeout--; | ||
880 | } | ||
881 | 888 | ||
882 | // Being marked connected is not enough to ping. Socket establishment can sometimes take a long | 889 | // 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 | 890 | // 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. | 891 | // set up, with nasty side-effects. |
885 | 892 | ||
886 | else if (_pdk_ == 0) | 893 | 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 | { | 894 | { |
895 | m_log.ErrorFormat("[IRC-PingRun] Exception on connector {0}: {1} ", connector.idn, e.Message); | 895 | try |
896 | m_log.Debug(e); | 896 | { |
897 | connector.Reconnect(); | 897 | connector.m_writer.WriteLine(String.Format("PING :{0}", connector.m_server)); |
898 | connector.m_writer.Flush(); | ||
899 | } | ||
900 | catch (Exception e) | ||
901 | { | ||
902 | m_log.ErrorFormat("[IRC-PingRun] Exception on connector {0}: {1} ", connector.idn, e.Message); | ||
903 | m_log.Debug(e); | ||
904 | connector.Reconnect(); | ||
905 | } | ||
898 | } | 906 | } |
899 | } | ||
900 | 907 | ||
908 | } | ||
901 | } | 909 | } |
902 | } | 910 | } |
903 | } | ||
904 | 911 | ||
905 | // m_log.InfoFormat("[IRC-Watchdog] Status scan completed"); | 912 | // m_log.InfoFormat("[IRC-Watchdog] Status scan completed"); |
906 | 913 | ||
diff --git a/OpenSim/Region/OptionalModules/Avatar/Chat/RegionState.cs b/OpenSim/Region/OptionalModules/Avatar/Chat/RegionState.cs index 53b103e..d4fe5e0 100644 --- a/OpenSim/Region/OptionalModules/Avatar/Chat/RegionState.cs +++ b/OpenSim/Region/OptionalModules/Avatar/Chat/RegionState.cs | |||
@@ -41,49 +41,71 @@ 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 | ||
48 | private static readonly OpenMetaverse.Vector3 CenterOfRegion = new OpenMetaverse.Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 20); | 47 | 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; | 48 | private const int DEBUG_CHANNEL = 2147483647; |
50 | 49 | ||
51 | private static int _idk_ = 0; | 50 | private static int _idk_ = 0; |
52 | 51 | ||
53 | // Runtime variables; these values are assigned when the | 52 | // Runtime variables; these values are assigned when the |
54 | // IrcState is created and remain constant thereafter. | 53 | // IrcState is created and remain constant thereafter. |
55 | 54 | ||
56 | internal string Region = String.Empty; | 55 | internal string Region = String.Empty; |
57 | internal string Host = String.Empty; | 56 | internal string Host = String.Empty; |
58 | internal string LocX = String.Empty; | 57 | internal string LocX = String.Empty; |
59 | internal string LocY = String.Empty; | 58 | internal string LocY = String.Empty; |
60 | internal string IDK = String.Empty; | 59 | internal string IDK = String.Empty; |
61 | 60 | ||
62 | // System values - used only be the IRC classes themselves | 61 | // System values - used only be the IRC classes themselves |
63 | 62 | ||
64 | internal ChannelState cs = null; // associated IRC configuration | 63 | internal ChannelState cs = null; // associated IRC configuration |
65 | internal Scene scene = null; // associated scene | 64 | internal Scene scene = null; // associated scene |
66 | internal IConfig config = null; // configuration file reference | 65 | internal IConfig config = null; // configuration file reference |
67 | internal bool enabled = true; | 66 | internal bool enabled = true; |
68 | 67 | ||
68 | //AgentAlert | ||
69 | internal bool showAlert = false; | ||
70 | internal string alertMessage = String.Empty; | ||
71 | internal IDialogModule dialogModule = null; | ||
72 | |||
69 | // This list is used to keep track of who is here, and by | 73 | // This list is used to keep track of who is here, and by |
70 | // implication, who is not. | 74 | // implication, who is not. |
71 | 75 | ||
72 | internal List<IClientAPI> clients = new List<IClientAPI>(); | 76 | internal List<IClientAPI> clients = new List<IClientAPI>(); |
73 | 77 | ||
74 | // Setup runtime variable values | 78 | // Setup runtime variable values |
75 | 79 | ||
76 | public RegionState(Scene p_scene, IConfig p_config) | 80 | public RegionState(Scene p_scene, IConfig p_config) |
77 | { | 81 | { |
78 | 82 | scene = p_scene; | |
79 | scene = p_scene; | ||
80 | config = p_config; | 83 | config = p_config; |
81 | 84 | ||
82 | Region = scene.RegionInfo.RegionName; | 85 | Region = scene.RegionInfo.RegionName; |
83 | Host = scene.RegionInfo.ExternalHostName; | 86 | Host = scene.RegionInfo.ExternalHostName; |
84 | LocX = Convert.ToString(scene.RegionInfo.RegionLocX); | 87 | LocX = Convert.ToString(scene.RegionInfo.RegionLocX); |
85 | LocY = Convert.ToString(scene.RegionInfo.RegionLocY); | 88 | LocY = Convert.ToString(scene.RegionInfo.RegionLocY); |
86 | IDK = Convert.ToString(_idk_++); | 89 | IDK = Convert.ToString(_idk_++); |
90 | |||
91 | showAlert = config.GetBoolean("alert_show", false); | ||
92 | string alertServerInfo = String.Empty; | ||
93 | |||
94 | if (showAlert) | ||
95 | { | ||
96 | bool showAlertServerInfo = config.GetBoolean("alert_show_serverinfo", true); | ||
97 | |||
98 | if (showAlertServerInfo) | ||
99 | alertServerInfo = String.Format("\nServer: {0}\nPort: {1}\nChannel: {2}\n\n", | ||
100 | config.GetString("server", ""), config.GetString("port", ""), config.GetString("channel", "")); | ||
101 | |||
102 | string alertPreMessage = config.GetString("alert_msg_pre", "This region is linked to Irc."); | ||
103 | string alertPostMessage = config.GetString("alert_msg_post", "Everything you say in public chat can be listened."); | ||
104 | |||
105 | alertMessage = String.Format("{0}\n{1}{2}", alertPreMessage, alertServerInfo, alertPostMessage); | ||
106 | |||
107 | dialogModule = scene.RequestModuleInterface<IDialogModule>(); | ||
108 | } | ||
87 | 109 | ||
88 | // OpenChannel conditionally establishes a connection to the | 110 | // OpenChannel conditionally establishes a connection to the |
89 | // IRC server. The request will either succeed, or it will | 111 | // IRC server. The request will either succeed, or it will |
@@ -93,9 +115,9 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat | |||
93 | 115 | ||
94 | // Connect channel to world events | 116 | // Connect channel to world events |
95 | 117 | ||
96 | scene.EventManager.OnChatFromWorld += OnSimChat; | 118 | scene.EventManager.OnChatFromWorld += OnSimChat; |
97 | scene.EventManager.OnChatFromClient += OnSimChat; | 119 | scene.EventManager.OnChatFromClient += OnSimChat; |
98 | scene.EventManager.OnMakeRootAgent += OnMakeRootAgent; | 120 | scene.EventManager.OnMakeRootAgent += OnMakeRootAgent; |
99 | scene.EventManager.OnMakeChildAgent += OnMakeChildAgent; | 121 | scene.EventManager.OnMakeChildAgent += OnMakeChildAgent; |
100 | 122 | ||
101 | m_log.InfoFormat("[IRC-Region {0}] Initialization complete", Region); | 123 | m_log.InfoFormat("[IRC-Region {0}] Initialization complete", Region); |
@@ -106,8 +128,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat | |||
106 | 128 | ||
107 | ~RegionState() | 129 | ~RegionState() |
108 | { | 130 | { |
109 | if (cs != null) | 131 | if (cs != null) |
110 | cs.RemoveRegion(this); | 132 | cs.RemoveRegion(this); |
111 | } | 133 | } |
112 | 134 | ||
113 | // Called by PostInitialize after all regions have been created | 135 | // Called by PostInitialize after all regions have been created |
@@ -138,7 +160,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat | |||
138 | { | 160 | { |
139 | if (clients.Contains(client)) | 161 | if (clients.Contains(client)) |
140 | { | 162 | { |
141 | if (enabled && (cs.irc.Enabled) && (cs.irc.Connected) && (cs.ClientReporting)) | 163 | if (enabled && (cs.irc.Enabled) && (cs.irc.Connected) && (cs.ClientReporting)) |
142 | { | 164 | { |
143 | m_log.InfoFormat("[IRC-Region {0}]: {1} has left", Region, client.Name); | 165 | m_log.InfoFormat("[IRC-Region {0}]: {1} has left", Region, client.Name); |
144 | //Check if this person is excluded from IRC | 166 | //Check if this person is excluded from IRC |
@@ -147,7 +169,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat | |||
147 | cs.irc.PrivMsg(cs.NoticeMessageFormat, cs.irc.Nick, Region, String.Format("{0} has left", client.Name)); | 169 | cs.irc.PrivMsg(cs.NoticeMessageFormat, cs.irc.Nick, Region, String.Format("{0} has left", client.Name)); |
148 | } | 170 | } |
149 | } | 171 | } |
150 | client.OnLogout -= OnClientLoggedOut; | 172 | client.OnLogout -= OnClientLoggedOut; |
151 | client.OnConnectionClosed -= OnClientLoggedOut; | 173 | client.OnConnectionClosed -= OnClientLoggedOut; |
152 | clients.Remove(client); | 174 | clients.Remove(client); |
153 | } | 175 | } |
@@ -171,13 +193,13 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat | |||
171 | { | 193 | { |
172 | if (clients.Contains(client)) | 194 | if (clients.Contains(client)) |
173 | { | 195 | { |
174 | if (enabled && (cs.irc.Enabled) && (cs.irc.Connected) && (cs.ClientReporting)) | 196 | if (enabled && (cs.irc.Enabled) && (cs.irc.Connected) && (cs.ClientReporting)) |
175 | { | 197 | { |
176 | string clientName = String.Format("{0} {1}", presence.Firstname, presence.Lastname); | 198 | string clientName = String.Format("{0} {1}", presence.Firstname, presence.Lastname); |
177 | m_log.DebugFormat("[IRC-Region {0}] {1} has left", Region, clientName); | 199 | 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)); | 200 | cs.irc.PrivMsg(cs.NoticeMessageFormat, cs.irc.Nick, Region, String.Format("{0} has left", clientName)); |
179 | } | 201 | } |
180 | client.OnLogout -= OnClientLoggedOut; | 202 | client.OnLogout -= OnClientLoggedOut; |
181 | client.OnConnectionClosed -= OnClientLoggedOut; | 203 | client.OnConnectionClosed -= OnClientLoggedOut; |
182 | clients.Remove(client); | 204 | clients.Remove(client); |
183 | } | 205 | } |
@@ -195,14 +217,13 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat | |||
195 | 217 | ||
196 | private void OnMakeRootAgent(ScenePresence presence) | 218 | private void OnMakeRootAgent(ScenePresence presence) |
197 | { | 219 | { |
198 | |||
199 | IClientAPI client = presence.ControllingClient; | 220 | IClientAPI client = presence.ControllingClient; |
200 | 221 | ||
201 | try | 222 | try |
202 | { | 223 | { |
203 | if (!clients.Contains(client)) | 224 | if (!clients.Contains(client)) |
204 | { | 225 | { |
205 | client.OnLogout += OnClientLoggedOut; | 226 | client.OnLogout += OnClientLoggedOut; |
206 | client.OnConnectionClosed += OnClientLoggedOut; | 227 | client.OnConnectionClosed += OnClientLoggedOut; |
207 | clients.Add(client); | 228 | clients.Add(client); |
208 | if (enabled && (cs.irc.Enabled) && (cs.irc.Connected) && (cs.ClientReporting)) | 229 | if (enabled && (cs.irc.Enabled) && (cs.irc.Connected) && (cs.ClientReporting)) |
@@ -216,17 +237,18 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat | |||
216 | } | 237 | } |
217 | } | 238 | } |
218 | } | 239 | } |
240 | |||
241 | if (dialogModule != null && showAlert) | ||
242 | dialogModule.SendAlertToUser(client, alertMessage, true); | ||
219 | } | 243 | } |
220 | catch (Exception ex) | 244 | catch (Exception ex) |
221 | { | 245 | { |
222 | m_log.ErrorFormat("[IRC-Region {0}]: MakeRootAgent exception: {1}", Region, ex.Message); | 246 | m_log.ErrorFormat("[IRC-Region {0}]: MakeRootAgent exception: {1}", Region, ex.Message); |
223 | m_log.Debug(ex); | 247 | m_log.Debug(ex); |
224 | } | 248 | } |
225 | |||
226 | } | 249 | } |
227 | 250 | ||
228 | // This handler detects chat events int he virtual world. | 251 | // This handler detects chat events int he virtual world. |
229 | |||
230 | public void OnSimChat(Object sender, OSChatMessage msg) | 252 | public void OnSimChat(Object sender, OSChatMessage msg) |
231 | { | 253 | { |
232 | 254 | ||
@@ -317,14 +339,14 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat | |||
317 | // that evident. | 339 | // that evident. |
318 | 340 | ||
319 | default: | 341 | default: |
320 | m_log.DebugFormat("[IRC-Region {0}] Forwarding unrecognized command to IRC : {1}", | 342 | m_log.DebugFormat("[IRC-Region {0}] Forwarding unrecognized command to IRC : {1}", |
321 | Region, msg.Message); | 343 | Region, msg.Message); |
322 | cs.irc.Send(msg.Message); | 344 | cs.irc.Send(msg.Message); |
323 | break; | 345 | break; |
324 | } | 346 | } |
325 | } | 347 | } |
326 | catch (Exception ex) | 348 | catch (Exception ex) |
327 | { | 349 | { |
328 | m_log.WarnFormat("[IRC-Region {0}] error processing in-world command channel input: {1}", | 350 | m_log.WarnFormat("[IRC-Region {0}] error processing in-world command channel input: {1}", |
329 | Region, ex.Message); | 351 | Region, ex.Message); |
330 | m_log.Debug(ex); | 352 | m_log.Debug(ex); |
@@ -366,7 +388,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat | |||
366 | 388 | ||
367 | m_log.DebugFormat("[IRC-Region {0}] heard on channel {1} : {2}", Region, msg.Channel, msg.Message); | 389 | m_log.DebugFormat("[IRC-Region {0}] heard on channel {1} : {2}", Region, msg.Channel, msg.Message); |
368 | 390 | ||
369 | if (null != avatar && cs.RelayChat && (msg.Channel == 0 || msg.Channel == DEBUG_CHANNEL)) | 391 | if (null != avatar && cs.RelayChat && (msg.Channel == 0 || msg.Channel == DEBUG_CHANNEL)) |
370 | { | 392 | { |
371 | string txt = msg.Message; | 393 | string txt = msg.Message; |
372 | if (txt.StartsWith("/me ")) | 394 | if (txt.StartsWith("/me ")) |
@@ -376,13 +398,13 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat | |||
376 | return; | 398 | return; |
377 | } | 399 | } |
378 | 400 | ||
379 | if (null == avatar && cs.RelayPrivateChannels && null != cs.AccessPassword && | 401 | if (null == avatar && cs.RelayPrivateChannels && null != cs.AccessPassword && |
380 | msg.Channel == cs.RelayChannelOut) | 402 | msg.Channel == cs.RelayChannelOut) |
381 | { | 403 | { |
382 | Match m = cs.AccessPasswordRegex.Match(msg.Message); | 404 | Match m = cs.AccessPasswordRegex.Match(msg.Message); |
383 | if (null != m) | 405 | if (null != m) |
384 | { | 406 | { |
385 | m_log.DebugFormat("[IRC] relaying message from {0}: {1}", m.Groups["avatar"].ToString(), | 407 | m_log.DebugFormat("[IRC] relaying message from {0}: {1}", m.Groups["avatar"].ToString(), |
386 | m.Groups["message"].ToString()); | 408 | m.Groups["message"].ToString()); |
387 | cs.irc.PrivMsg(cs.PrivateMessageFormat, m.Groups["avatar"].ToString(), | 409 | cs.irc.PrivMsg(cs.PrivateMessageFormat, m.Groups["avatar"].ToString(), |
388 | scene.RegionInfo.RegionName, m.Groups["message"].ToString()); | 410 | scene.RegionInfo.RegionName, m.Groups["message"].ToString()); |
diff --git a/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs b/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs index f292a75..0cec959 100644 --- a/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs +++ b/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs | |||
@@ -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 7da1de6..e756c70 100644 --- a/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs +++ b/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs | |||
@@ -1123,18 +1123,16 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice | |||
1123 | // Otherwise prepare the request | 1123 | // Otherwise prepare the request |
1124 | // m_log.DebugFormat("[VivoxVoice] Sending request <{0}>", requrl); | 1124 | // m_log.DebugFormat("[VivoxVoice] Sending request <{0}>", requrl); |
1125 | 1125 | ||
1126 | HttpWebRequest req = (HttpWebRequest)WebRequest.Create(requrl); | 1126 | HttpWebRequest req = (HttpWebRequest)WebRequest.Create(requrl); |
1127 | HttpWebResponse rsp = null; | ||
1128 | 1127 | ||
1129 | // We are sending just parameters, no content | 1128 | // We are sending just parameters, no content |
1130 | req.ContentLength = 0; | 1129 | req.ContentLength = 0; |
1131 | 1130 | ||
1132 | // Send request and retrieve the response | 1131 | // Send request and retrieve the response |
1133 | rsp = (HttpWebResponse)req.GetResponse(); | 1132 | using (HttpWebResponse rsp = (HttpWebResponse)req.GetResponse()) |
1134 | 1133 | using (Stream s = rsp.GetResponseStream()) | |
1135 | XmlTextReader rdr = new XmlTextReader(rsp.GetResponseStream()); | 1134 | using (XmlTextReader rdr = new XmlTextReader(s)) |
1136 | doc.Load(rdr); | 1135 | doc.Load(rdr); |
1137 | rdr.Close(); | ||
1138 | } | 1136 | } |
1139 | catch (Exception e) | 1137 | catch (Exception e) |
1140 | { | 1138 | { |
diff --git a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs index ae0ad02..d764936 100644 --- a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs +++ b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs | |||
@@ -126,7 +126,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups | |||
126 | { | 126 | { |
127 | scene.RegisterModuleInterface<IGroupsModule>(this); | 127 | scene.RegisterModuleInterface<IGroupsModule>(this); |
128 | scene.AddCommand( | 128 | scene.AddCommand( |
129 | "debug", | 129 | "Debug", |
130 | this, | 130 | this, |
131 | "debug groups verbose", | 131 | "debug groups verbose", |
132 | "debug groups verbose <true|false>", | 132 | "debug groups verbose <true|false>", |
diff --git a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/IGroupsServicesConnector.cs b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/IGroupsServicesConnector.cs index 6d26075..6b5b40a 100644 --- a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/IGroupsServicesConnector.cs +++ b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/IGroupsServicesConnector.cs | |||
@@ -36,7 +36,22 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups | |||
36 | { | 36 | { |
37 | UUID CreateGroup(UUID RequestingAgentID, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, bool allowPublish, bool maturePublish, UUID founderID); | 37 | UUID CreateGroup(UUID RequestingAgentID, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, bool allowPublish, bool maturePublish, UUID founderID); |
38 | void UpdateGroup(UUID RequestingAgentID, UUID groupID, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, bool allowPublish, bool maturePublish); | 38 | void UpdateGroup(UUID RequestingAgentID, UUID groupID, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, bool allowPublish, bool maturePublish); |
39 | |||
40 | /// <summary> | ||
41 | /// Get the group record. | ||
42 | /// </summary> | ||
43 | /// <returns></returns> | ||
44 | /// <param name='RequestingAgentID'>The UUID of the user making the request.</param> | ||
45 | /// <param name='GroupID'> | ||
46 | /// The ID of the record to retrieve. | ||
47 | /// GroupName may be specified instead, in which case this parameter will be UUID.Zero | ||
48 | /// </param> | ||
49 | /// <param name='GroupName'> | ||
50 | /// The name of the group to retrieve. | ||
51 | /// GroupID may be specified instead, in which case this parmeter will be null. | ||
52 | /// </param> | ||
39 | GroupRecord GetGroupRecord(UUID RequestingAgentID, UUID GroupID, string GroupName); | 53 | GroupRecord GetGroupRecord(UUID RequestingAgentID, UUID GroupID, string GroupName); |
54 | |||
40 | List<DirGroupsReplyData> FindGroups(UUID RequestingAgentID, string search); | 55 | List<DirGroupsReplyData> FindGroups(UUID RequestingAgentID, string search); |
41 | List<GroupMembersData> GetGroupMembers(UUID RequestingAgentID, UUID GroupID); | 56 | List<GroupMembersData> GetGroupMembers(UUID RequestingAgentID, UUID GroupID); |
42 | 57 | ||
diff --git a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/Tests/GroupsModuleTests.cs b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/Tests/GroupsModuleTests.cs index ac638f1..c1bdacb 100644 --- a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/Tests/GroupsModuleTests.cs +++ b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/Tests/GroupsModuleTests.cs | |||
@@ -42,7 +42,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups.Tests | |||
42 | /// Basic groups module tests | 42 | /// Basic groups module tests |
43 | /// </summary> | 43 | /// </summary> |
44 | [TestFixture] | 44 | [TestFixture] |
45 | public class GroupsModuleTests | 45 | public class GroupsModuleTests : OpenSimTestCase |
46 | { | 46 | { |
47 | [Test] | 47 | [Test] |
48 | public void TestBasic() | 48 | public void TestBasic() |
diff --git a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/XmlRpcGroupsServicesConnectorModule.cs b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/XmlRpcGroupsServicesConnectorModule.cs index d0c3ea5..71b24ac 100644 --- a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/XmlRpcGroupsServicesConnectorModule.cs +++ b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/XmlRpcGroupsServicesConnectorModule.cs | |||
@@ -54,13 +54,62 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups | |||
54 | 54 | ||
55 | private bool m_debugEnabled = false; | 55 | private bool m_debugEnabled = false; |
56 | 56 | ||
57 | public const GroupPowers m_DefaultEveryonePowers = GroupPowers.AllowSetHome | | 57 | public const GroupPowers DefaultEveryonePowers |
58 | GroupPowers.Accountable | | 58 | = GroupPowers.AllowSetHome |
59 | GroupPowers.JoinChat | | 59 | | GroupPowers.Accountable |
60 | GroupPowers.AllowVoiceChat | | 60 | | GroupPowers.JoinChat |
61 | GroupPowers.ReceiveNotices | | 61 | | GroupPowers.AllowVoiceChat |
62 | GroupPowers.StartProposal | | 62 | | GroupPowers.ReceiveNotices |
63 | GroupPowers.VoteOnProposal; | 63 | | GroupPowers.StartProposal |
64 | | GroupPowers.VoteOnProposal; | ||
65 | |||
66 | // Would this be cleaner as (GroupPowers)ulong.MaxValue? | ||
67 | public const GroupPowers DefaultOwnerPowers | ||
68 | = GroupPowers.Accountable | ||
69 | | GroupPowers.AllowEditLand | ||
70 | | GroupPowers.AllowFly | ||
71 | | GroupPowers.AllowLandmark | ||
72 | | GroupPowers.AllowRez | ||
73 | | GroupPowers.AllowSetHome | ||
74 | | GroupPowers.AllowVoiceChat | ||
75 | | GroupPowers.AssignMember | ||
76 | | GroupPowers.AssignMemberLimited | ||
77 | | GroupPowers.ChangeActions | ||
78 | | GroupPowers.ChangeIdentity | ||
79 | | GroupPowers.ChangeMedia | ||
80 | | GroupPowers.ChangeOptions | ||
81 | | GroupPowers.CreateRole | ||
82 | | GroupPowers.DeedObject | ||
83 | | GroupPowers.DeleteRole | ||
84 | | GroupPowers.Eject | ||
85 | | GroupPowers.FindPlaces | ||
86 | | GroupPowers.Invite | ||
87 | | GroupPowers.JoinChat | ||
88 | | GroupPowers.LandChangeIdentity | ||
89 | | GroupPowers.LandDeed | ||
90 | | GroupPowers.LandDivideJoin | ||
91 | | GroupPowers.LandEdit | ||
92 | | GroupPowers.LandEjectAndFreeze | ||
93 | | GroupPowers.LandGardening | ||
94 | | GroupPowers.LandManageAllowed | ||
95 | | GroupPowers.LandManageBanned | ||
96 | | GroupPowers.LandManagePasses | ||
97 | | GroupPowers.LandOptions | ||
98 | | GroupPowers.LandRelease | ||
99 | | GroupPowers.LandSetSale | ||
100 | | GroupPowers.ModerateChat | ||
101 | | GroupPowers.ObjectManipulate | ||
102 | | GroupPowers.ObjectSetForSale | ||
103 | | GroupPowers.ReceiveNotices | ||
104 | | GroupPowers.RemoveMember | ||
105 | | GroupPowers.ReturnGroupOwned | ||
106 | | GroupPowers.ReturnGroupSet | ||
107 | | GroupPowers.ReturnNonGroup | ||
108 | | GroupPowers.RoleProperties | ||
109 | | GroupPowers.SendNotices | ||
110 | | GroupPowers.SetLandingPoint | ||
111 | | GroupPowers.StartProposal | ||
112 | | GroupPowers.VoteOnProposal; | ||
64 | 113 | ||
65 | private bool m_connectorEnabled = false; | 114 | private bool m_connectorEnabled = false; |
66 | 115 | ||
@@ -219,59 +268,9 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups | |||
219 | param["AllowPublish"] = allowPublish == true ? 1 : 0; | 268 | param["AllowPublish"] = allowPublish == true ? 1 : 0; |
220 | param["MaturePublish"] = maturePublish == true ? 1 : 0; | 269 | param["MaturePublish"] = maturePublish == true ? 1 : 0; |
221 | param["FounderID"] = founderID.ToString(); | 270 | param["FounderID"] = founderID.ToString(); |
222 | param["EveryonePowers"] = ((ulong)m_DefaultEveryonePowers).ToString(); | 271 | param["EveryonePowers"] = ((ulong)DefaultEveryonePowers).ToString(); |
223 | param["OwnerRoleID"] = OwnerRoleID.ToString(); | 272 | param["OwnerRoleID"] = OwnerRoleID.ToString(); |
224 | 273 | param["OwnersPowers"] = ((ulong)DefaultOwnerPowers).ToString(); | |
225 | // Would this be cleaner as (GroupPowers)ulong.MaxValue; | ||
226 | GroupPowers OwnerPowers = GroupPowers.Accountable | ||
227 | | GroupPowers.AllowEditLand | ||
228 | | GroupPowers.AllowFly | ||
229 | | GroupPowers.AllowLandmark | ||
230 | | GroupPowers.AllowRez | ||
231 | | GroupPowers.AllowSetHome | ||
232 | | GroupPowers.AllowVoiceChat | ||
233 | | GroupPowers.AssignMember | ||
234 | | GroupPowers.AssignMemberLimited | ||
235 | | GroupPowers.ChangeActions | ||
236 | | GroupPowers.ChangeIdentity | ||
237 | | GroupPowers.ChangeMedia | ||
238 | | GroupPowers.ChangeOptions | ||
239 | | GroupPowers.CreateRole | ||
240 | | GroupPowers.DeedObject | ||
241 | | GroupPowers.DeleteRole | ||
242 | | GroupPowers.Eject | ||
243 | | GroupPowers.FindPlaces | ||
244 | | GroupPowers.Invite | ||
245 | | GroupPowers.JoinChat | ||
246 | | GroupPowers.LandChangeIdentity | ||
247 | | GroupPowers.LandDeed | ||
248 | | GroupPowers.LandDivideJoin | ||
249 | | GroupPowers.LandEdit | ||
250 | | GroupPowers.LandEjectAndFreeze | ||
251 | | GroupPowers.LandGardening | ||
252 | | GroupPowers.LandManageAllowed | ||
253 | | GroupPowers.LandManageBanned | ||
254 | | GroupPowers.LandManagePasses | ||
255 | | GroupPowers.LandOptions | ||
256 | | GroupPowers.LandRelease | ||
257 | | GroupPowers.LandSetSale | ||
258 | | GroupPowers.ModerateChat | ||
259 | | GroupPowers.ObjectManipulate | ||
260 | | GroupPowers.ObjectSetForSale | ||
261 | | GroupPowers.ReceiveNotices | ||
262 | | GroupPowers.RemoveMember | ||
263 | | GroupPowers.ReturnGroupOwned | ||
264 | | GroupPowers.ReturnGroupSet | ||
265 | | GroupPowers.ReturnNonGroup | ||
266 | | GroupPowers.RoleProperties | ||
267 | | GroupPowers.SendNotices | ||
268 | | GroupPowers.SetLandingPoint | ||
269 | | GroupPowers.StartProposal | ||
270 | | GroupPowers.VoteOnProposal; | ||
271 | param["OwnersPowers"] = ((ulong)OwnerPowers).ToString(); | ||
272 | |||
273 | |||
274 | |||
275 | 274 | ||
276 | Hashtable respData = XmlRpcCall(requestingAgentID, "groups.createGroup", param); | 275 | Hashtable respData = XmlRpcCall(requestingAgentID, "groups.createGroup", param); |
277 | 276 | ||
@@ -612,8 +611,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups | |||
612 | } | 611 | } |
613 | 612 | ||
614 | return Roles; | 613 | return Roles; |
615 | |||
616 | |||
617 | } | 614 | } |
618 | 615 | ||
619 | public List<GroupRolesData> GetGroupRoles(UUID requestingAgentID, UUID GroupID) | 616 | public List<GroupRolesData> GetGroupRoles(UUID requestingAgentID, UUID GroupID) |
@@ -676,7 +673,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups | |||
676 | } | 673 | } |
677 | 674 | ||
678 | return members; | 675 | return members; |
679 | |||
680 | } | 676 | } |
681 | 677 | ||
682 | public List<GroupRoleMembersData> GetGroupRoleMembers(UUID requestingAgentID, UUID GroupID) | 678 | public List<GroupRoleMembersData> GetGroupRoleMembers(UUID requestingAgentID, UUID GroupID) |
@@ -727,9 +723,10 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups | |||
727 | values.Add(data); | 723 | values.Add(data); |
728 | } | 724 | } |
729 | } | 725 | } |
730 | return values; | ||
731 | 726 | ||
727 | return values; | ||
732 | } | 728 | } |
729 | |||
733 | public GroupNoticeInfo GetGroupNotice(UUID requestingAgentID, UUID noticeID) | 730 | public GroupNoticeInfo GetGroupNotice(UUID requestingAgentID, UUID noticeID) |
734 | { | 731 | { |
735 | Hashtable param = new Hashtable(); | 732 | Hashtable param = new Hashtable(); |
@@ -737,7 +734,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups | |||
737 | 734 | ||
738 | Hashtable respData = XmlRpcCall(requestingAgentID, "groups.getGroupNotice", param); | 735 | Hashtable respData = XmlRpcCall(requestingAgentID, "groups.getGroupNotice", param); |
739 | 736 | ||
740 | |||
741 | if (respData.Contains("error")) | 737 | if (respData.Contains("error")) |
742 | { | 738 | { |
743 | return null; | 739 | return null; |
@@ -761,6 +757,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups | |||
761 | 757 | ||
762 | return data; | 758 | return data; |
763 | } | 759 | } |
760 | |||
764 | public void AddGroupNotice(UUID requestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message, byte[] binaryBucket) | 761 | public void AddGroupNotice(UUID requestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message, byte[] binaryBucket) |
765 | { | 762 | { |
766 | string binBucket = OpenMetaverse.Utils.BytesToHexString(binaryBucket, ""); | 763 | string binBucket = OpenMetaverse.Utils.BytesToHexString(binaryBucket, ""); |
@@ -777,8 +774,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups | |||
777 | XmlRpcCall(requestingAgentID, "groups.addGroupNotice", param); | 774 | XmlRpcCall(requestingAgentID, "groups.addGroupNotice", param); |
778 | } | 775 | } |
779 | 776 | ||
780 | |||
781 | |||
782 | #endregion | 777 | #endregion |
783 | 778 | ||
784 | #region GroupSessionTracking | 779 | #region GroupSessionTracking |
@@ -1151,28 +1146,38 @@ namespace Nwc.XmlRpc | |||
1151 | request.AllowWriteStreamBuffering = true; | 1146 | request.AllowWriteStreamBuffering = true; |
1152 | request.KeepAlive = !_disableKeepAlive; | 1147 | request.KeepAlive = !_disableKeepAlive; |
1153 | 1148 | ||
1154 | Stream stream = request.GetRequestStream(); | 1149 | using (Stream stream = request.GetRequestStream()) |
1155 | XmlTextWriter xml = new XmlTextWriter(stream, Encoding.ASCII); | ||
1156 | _serializer.Serialize(xml, this); | ||
1157 | xml.Flush(); | ||
1158 | xml.Close(); | ||
1159 | |||
1160 | HttpWebResponse response = (HttpWebResponse)request.GetResponse(); | ||
1161 | StreamReader input = new StreamReader(response.GetResponseStream()); | ||
1162 | |||
1163 | string inputXml = input.ReadToEnd(); | ||
1164 | XmlRpcResponse resp; | ||
1165 | try | ||
1166 | { | 1150 | { |
1167 | resp = (XmlRpcResponse)_deserializer.Deserialize(inputXml); | 1151 | using (XmlTextWriter xml = new XmlTextWriter(stream, Encoding.ASCII)) |
1152 | { | ||
1153 | _serializer.Serialize(xml, this); | ||
1154 | xml.Flush(); | ||
1155 | } | ||
1168 | } | 1156 | } |
1169 | catch (Exception e) | 1157 | |
1158 | XmlRpcResponse resp; | ||
1159 | |||
1160 | using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) | ||
1170 | { | 1161 | { |
1171 | RequestResponse = inputXml; | 1162 | using (Stream s = response.GetResponseStream()) |
1172 | throw e; | 1163 | { |
1164 | using (StreamReader input = new StreamReader(s)) | ||
1165 | { | ||
1166 | string inputXml = input.ReadToEnd(); | ||
1167 | |||
1168 | try | ||
1169 | { | ||
1170 | resp = (XmlRpcResponse)_deserializer.Deserialize(inputXml); | ||
1171 | } | ||
1172 | catch (Exception e) | ||
1173 | { | ||
1174 | RequestResponse = inputXml; | ||
1175 | throw e; | ||
1176 | } | ||
1177 | } | ||
1178 | } | ||
1173 | } | 1179 | } |
1174 | input.Close(); | 1180 | |
1175 | response.Close(); | ||
1176 | return resp; | 1181 | return resp; |
1177 | } | 1182 | } |
1178 | } | 1183 | } |
diff --git a/OpenSim/Region/OptionalModules/Example/BareBonesNonShared/BareBonesNonSharedModule.cs b/OpenSim/Region/OptionalModules/Example/BareBonesNonShared/BareBonesNonSharedModule.cs index 7d37135..0615036 100644 --- a/OpenSim/Region/OptionalModules/Example/BareBonesNonShared/BareBonesNonSharedModule.cs +++ b/OpenSim/Region/OptionalModules/Example/BareBonesNonShared/BareBonesNonSharedModule.cs | |||
@@ -33,6 +33,12 @@ using Nini.Config; | |||
33 | using OpenSim.Region.Framework.Interfaces; | 33 | using OpenSim.Region.Framework.Interfaces; |
34 | using OpenSim.Region.Framework.Scenes; | 34 | using 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.5")] | ||
41 | |||
36 | namespace OpenSim.Region.OptionalModules.Example.BareBonesNonShared | 42 | namespace 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..811a263 100644 --- a/OpenSim/Region/OptionalModules/Example/BareBonesShared/BareBonesSharedModule.cs +++ b/OpenSim/Region/OptionalModules/Example/BareBonesShared/BareBonesSharedModule.cs | |||
@@ -33,6 +33,12 @@ using Nini.Config; | |||
33 | using OpenSim.Region.Framework.Interfaces; | 33 | using OpenSim.Region.Framework.Interfaces; |
34 | using OpenSim.Region.Framework.Scenes; | 34 | using 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.5")] | ||
41 | |||
36 | namespace OpenSim.Region.OptionalModules.Example.BareBonesShared | 42 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Reflection; | ||
31 | using OpenSim.Framework.Servers; | ||
32 | using Mono.Addins; | ||
33 | using log4net; | ||
34 | using Nini.Config; | ||
35 | using OpenSim.Region.Framework.Interfaces; | ||
36 | using OpenSim.Region.Framework.Scenes; | ||
37 | |||
38 | using OpenSim.Framework.Servers.HttpServer; | ||
39 | |||
40 | |||
41 | namespace 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/Framework/Monitoring/ServerStats.cs b/OpenSim/Region/OptionalModules/Framework/Monitoring/ServerStats.cs new file mode 100644 index 0000000..6e74ce0 --- /dev/null +++ b/OpenSim/Region/OptionalModules/Framework/Monitoring/ServerStats.cs | |||
@@ -0,0 +1,339 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Diagnostics; | ||
31 | using System.Linq; | ||
32 | using System.Net.NetworkInformation; | ||
33 | using System.Text; | ||
34 | using System.Threading; | ||
35 | |||
36 | using log4net; | ||
37 | using Mono.Addins; | ||
38 | using Nini.Config; | ||
39 | |||
40 | using OpenSim.Framework; | ||
41 | using OpenSim.Framework.Console; | ||
42 | using OpenSim.Framework.Monitoring; | ||
43 | using OpenSim.Region.Framework.Interfaces; | ||
44 | using OpenSim.Region.Framework.Scenes; | ||
45 | |||
46 | using OpenMetaverse.StructuredData; | ||
47 | |||
48 | namespace OpenSim.Region.OptionalModules.Framework.Monitoring | ||
49 | { | ||
50 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "ServerStatistics")] | ||
51 | public class ServerStats : ISharedRegionModule | ||
52 | { | ||
53 | private readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); | ||
54 | private readonly string LogHeader = "[SERVER STATS]"; | ||
55 | |||
56 | public bool Enabled = false; | ||
57 | private static Dictionary<string, Stat> RegisteredStats = new Dictionary<string, Stat>(); | ||
58 | |||
59 | public readonly string CategoryServer = "server"; | ||
60 | |||
61 | public readonly string ContainerProcessor = "processor"; | ||
62 | public readonly string ContainerMemory = "memory"; | ||
63 | public readonly string ContainerNetwork = "network"; | ||
64 | public readonly string ContainerProcess = "process"; | ||
65 | |||
66 | public string NetworkInterfaceTypes = "Ethernet"; | ||
67 | |||
68 | readonly int performanceCounterSampleInterval = 500; | ||
69 | int lastperformanceCounterSampleTime = 0; | ||
70 | |||
71 | private class PerfCounterControl | ||
72 | { | ||
73 | public PerformanceCounter perfCounter; | ||
74 | public int lastFetch; | ||
75 | public string name; | ||
76 | public PerfCounterControl(PerformanceCounter pPc) | ||
77 | : this(pPc, String.Empty) | ||
78 | { | ||
79 | } | ||
80 | public PerfCounterControl(PerformanceCounter pPc, string pName) | ||
81 | { | ||
82 | perfCounter = pPc; | ||
83 | lastFetch = 0; | ||
84 | name = pName; | ||
85 | } | ||
86 | } | ||
87 | |||
88 | PerfCounterControl processorPercentPerfCounter = null; | ||
89 | |||
90 | #region ISharedRegionModule | ||
91 | // IRegionModuleBase.Name | ||
92 | public string Name { get { return "Server Stats"; } } | ||
93 | // IRegionModuleBase.ReplaceableInterface | ||
94 | public Type ReplaceableInterface { get { return null; } } | ||
95 | // IRegionModuleBase.Initialize | ||
96 | public void Initialise(IConfigSource source) | ||
97 | { | ||
98 | IConfig cfg = source.Configs["Monitoring"]; | ||
99 | |||
100 | if (cfg != null) | ||
101 | Enabled = cfg.GetBoolean("ServerStatsEnabled", true); | ||
102 | |||
103 | if (Enabled) | ||
104 | { | ||
105 | NetworkInterfaceTypes = cfg.GetString("NetworkInterfaceTypes", "Ethernet"); | ||
106 | } | ||
107 | } | ||
108 | // IRegionModuleBase.Close | ||
109 | public void Close() | ||
110 | { | ||
111 | if (RegisteredStats.Count > 0) | ||
112 | { | ||
113 | foreach (Stat stat in RegisteredStats.Values) | ||
114 | { | ||
115 | StatsManager.DeregisterStat(stat); | ||
116 | stat.Dispose(); | ||
117 | } | ||
118 | RegisteredStats.Clear(); | ||
119 | } | ||
120 | } | ||
121 | // IRegionModuleBase.AddRegion | ||
122 | public void AddRegion(Scene scene) | ||
123 | { | ||
124 | } | ||
125 | // IRegionModuleBase.RemoveRegion | ||
126 | public void RemoveRegion(Scene scene) | ||
127 | { | ||
128 | } | ||
129 | // IRegionModuleBase.RegionLoaded | ||
130 | public void RegionLoaded(Scene scene) | ||
131 | { | ||
132 | } | ||
133 | // ISharedRegionModule.PostInitialize | ||
134 | public void PostInitialise() | ||
135 | { | ||
136 | if (RegisteredStats.Count == 0) | ||
137 | { | ||
138 | RegisterServerStats(); | ||
139 | } | ||
140 | } | ||
141 | #endregion ISharedRegionModule | ||
142 | |||
143 | private void MakeStat(string pName, string pDesc, string pUnit, string pContainer, Action<Stat> act) | ||
144 | { | ||
145 | string desc = pDesc; | ||
146 | if (desc == null) | ||
147 | desc = pName; | ||
148 | Stat stat = new Stat(pName, pName, desc, pUnit, CategoryServer, pContainer, StatType.Pull, act, StatVerbosity.Info); | ||
149 | StatsManager.RegisterStat(stat); | ||
150 | RegisteredStats.Add(pName, stat); | ||
151 | } | ||
152 | |||
153 | public void RegisterServerStats() | ||
154 | { | ||
155 | lastperformanceCounterSampleTime = Util.EnvironmentTickCount(); | ||
156 | PerformanceCounter tempPC; | ||
157 | Stat tempStat; | ||
158 | string tempName; | ||
159 | |||
160 | try | ||
161 | { | ||
162 | tempName = "CPUPercent"; | ||
163 | tempPC = new PerformanceCounter("Processor", "% Processor Time", "_Total"); | ||
164 | processorPercentPerfCounter = new PerfCounterControl(tempPC); | ||
165 | // A long time bug in mono is that CPU percent is reported as CPU percent idle. Windows reports CPU percent busy. | ||
166 | tempStat = new Stat(tempName, tempName, "", "percent", CategoryServer, ContainerProcessor, | ||
167 | StatType.Pull, (s) => { GetNextValue(s, processorPercentPerfCounter, Util.IsWindows() ? 1 : -1); }, | ||
168 | StatVerbosity.Info); | ||
169 | StatsManager.RegisterStat(tempStat); | ||
170 | RegisteredStats.Add(tempName, tempStat); | ||
171 | |||
172 | MakeStat("TotalProcessorTime", null, "sec", ContainerProcessor, | ||
173 | (s) => { s.Value = Process.GetCurrentProcess().TotalProcessorTime.TotalSeconds; }); | ||
174 | |||
175 | MakeStat("UserProcessorTime", null, "sec", ContainerProcessor, | ||
176 | (s) => { s.Value = Process.GetCurrentProcess().UserProcessorTime.TotalSeconds; }); | ||
177 | |||
178 | MakeStat("PrivilegedProcessorTime", null, "sec", ContainerProcessor, | ||
179 | (s) => { s.Value = Process.GetCurrentProcess().PrivilegedProcessorTime.TotalSeconds; }); | ||
180 | |||
181 | MakeStat("Threads", null, "threads", ContainerProcessor, | ||
182 | (s) => { s.Value = Process.GetCurrentProcess().Threads.Count; }); | ||
183 | } | ||
184 | catch (Exception e) | ||
185 | { | ||
186 | m_log.ErrorFormat("{0} Exception creating 'Process': {1}", LogHeader, e); | ||
187 | } | ||
188 | |||
189 | try | ||
190 | { | ||
191 | List<string> okInterfaceTypes = new List<string>(NetworkInterfaceTypes.Split(',')); | ||
192 | |||
193 | IEnumerable<NetworkInterface> nics = NetworkInterface.GetAllNetworkInterfaces(); | ||
194 | foreach (NetworkInterface nic in nics) | ||
195 | { | ||
196 | if (nic.OperationalStatus != OperationalStatus.Up) | ||
197 | continue; | ||
198 | |||
199 | string nicInterfaceType = nic.NetworkInterfaceType.ToString(); | ||
200 | if (!okInterfaceTypes.Contains(nicInterfaceType)) | ||
201 | { | ||
202 | m_log.DebugFormat("{0} Not including stats for network interface '{1}' of type '{2}'.", | ||
203 | LogHeader, nic.Name, nicInterfaceType); | ||
204 | m_log.DebugFormat("{0} To include, add to comma separated list in [Monitoring]NetworkInterfaceTypes={1}", | ||
205 | LogHeader, NetworkInterfaceTypes); | ||
206 | continue; | ||
207 | } | ||
208 | |||
209 | if (nic.Supports(NetworkInterfaceComponent.IPv4)) | ||
210 | { | ||
211 | IPv4InterfaceStatistics nicStats = nic.GetIPv4Statistics(); | ||
212 | if (nicStats != null) | ||
213 | { | ||
214 | MakeStat("BytesRcvd/" + nic.Name, nic.Name, "KB", ContainerNetwork, | ||
215 | (s) => { LookupNic(s, (ns) => { return ns.BytesReceived; }, 1024.0); }); | ||
216 | MakeStat("BytesSent/" + nic.Name, nic.Name, "KB", ContainerNetwork, | ||
217 | (s) => { LookupNic(s, (ns) => { return ns.BytesSent; }, 1024.0); }); | ||
218 | MakeStat("TotalBytes/" + nic.Name, nic.Name, "KB", ContainerNetwork, | ||
219 | (s) => { LookupNic(s, (ns) => { return ns.BytesSent + ns.BytesReceived; }, 1024.0); }); | ||
220 | } | ||
221 | } | ||
222 | // TODO: add IPv6 (it may actually happen someday) | ||
223 | } | ||
224 | } | ||
225 | catch (Exception e) | ||
226 | { | ||
227 | m_log.ErrorFormat("{0} Exception creating 'Network Interface': {1}", LogHeader, e); | ||
228 | } | ||
229 | |||
230 | MakeStat("ProcessMemory", null, "MB", ContainerMemory, | ||
231 | (s) => { s.Value = Process.GetCurrentProcess().WorkingSet64 / 1024d / 1024d; }); | ||
232 | MakeStat("ObjectMemory", null, "MB", ContainerMemory, | ||
233 | (s) => { s.Value = GC.GetTotalMemory(false) / 1024d / 1024d; }); | ||
234 | MakeStat("LastMemoryChurn", null, "MB/sec", ContainerMemory, | ||
235 | (s) => { s.Value = Math.Round(MemoryWatchdog.LastMemoryChurn * 1000d / 1024d / 1024d, 3); }); | ||
236 | MakeStat("AverageMemoryChurn", null, "MB/sec", ContainerMemory, | ||
237 | (s) => { s.Value = Math.Round(MemoryWatchdog.AverageMemoryChurn * 1000d / 1024d / 1024d, 3); }); | ||
238 | } | ||
239 | |||
240 | // Notes on performance counters: | ||
241 | // "How To Read Performance Counters": http://blogs.msdn.com/b/bclteam/archive/2006/06/02/618156.aspx | ||
242 | // "How to get the CPU Usage in C#": http://stackoverflow.com/questions/278071/how-to-get-the-cpu-usage-in-c | ||
243 | // "Mono Performance Counters": http://www.mono-project.com/Mono_Performance_Counters | ||
244 | private delegate double PerfCounterNextValue(); | ||
245 | private void GetNextValue(Stat stat, PerfCounterControl perfControl) | ||
246 | { | ||
247 | GetNextValue(stat, perfControl, 1.0); | ||
248 | } | ||
249 | private void GetNextValue(Stat stat, PerfCounterControl perfControl, double factor) | ||
250 | { | ||
251 | if (Util.EnvironmentTickCountSubtract(perfControl.lastFetch) > performanceCounterSampleInterval) | ||
252 | { | ||
253 | if (perfControl != null && perfControl.perfCounter != null) | ||
254 | { | ||
255 | try | ||
256 | { | ||
257 | // Kludge for factor to run double duty. If -1, subtract the value from one | ||
258 | if (factor == -1) | ||
259 | stat.Value = 1 - perfControl.perfCounter.NextValue(); | ||
260 | else | ||
261 | stat.Value = perfControl.perfCounter.NextValue() / factor; | ||
262 | } | ||
263 | catch (Exception e) | ||
264 | { | ||
265 | m_log.ErrorFormat("{0} Exception on NextValue fetching {1}: {2}", LogHeader, stat.Name, e); | ||
266 | } | ||
267 | perfControl.lastFetch = Util.EnvironmentTickCount(); | ||
268 | } | ||
269 | } | ||
270 | } | ||
271 | |||
272 | // Lookup the nic that goes with this stat and set the value by using a fetch action. | ||
273 | // Not sure about closure with delegates inside delegates. | ||
274 | private delegate double GetIPv4StatValue(IPv4InterfaceStatistics interfaceStat); | ||
275 | private void LookupNic(Stat stat, GetIPv4StatValue getter, double factor) | ||
276 | { | ||
277 | // Get the one nic that has the name of this stat | ||
278 | IEnumerable<NetworkInterface> nics = NetworkInterface.GetAllNetworkInterfaces().Where( | ||
279 | (network) => network.Name == stat.Description); | ||
280 | try | ||
281 | { | ||
282 | foreach (NetworkInterface nic in nics) | ||
283 | { | ||
284 | IPv4InterfaceStatistics intrStats = nic.GetIPv4Statistics(); | ||
285 | if (intrStats != null) | ||
286 | { | ||
287 | double newVal = Math.Round(getter(intrStats) / factor, 3); | ||
288 | stat.Value = newVal; | ||
289 | } | ||
290 | break; | ||
291 | } | ||
292 | } | ||
293 | catch | ||
294 | { | ||
295 | // There are times interfaces go away so we just won't update the stat for this | ||
296 | m_log.ErrorFormat("{0} Exception fetching stat on interface '{1}'", LogHeader, stat.Description); | ||
297 | } | ||
298 | } | ||
299 | } | ||
300 | |||
301 | public class ServerStatsAggregator : Stat | ||
302 | { | ||
303 | public ServerStatsAggregator( | ||
304 | string shortName, | ||
305 | string name, | ||
306 | string description, | ||
307 | string unitName, | ||
308 | string category, | ||
309 | string container | ||
310 | ) | ||
311 | : base( | ||
312 | shortName, | ||
313 | name, | ||
314 | description, | ||
315 | unitName, | ||
316 | category, | ||
317 | container, | ||
318 | StatType.Push, | ||
319 | MeasuresOfInterest.None, | ||
320 | null, | ||
321 | StatVerbosity.Info) | ||
322 | { | ||
323 | } | ||
324 | public override string ToConsoleString() | ||
325 | { | ||
326 | StringBuilder sb = new StringBuilder(); | ||
327 | |||
328 | return sb.ToString(); | ||
329 | } | ||
330 | |||
331 | public override OSDMap ToOSDMap() | ||
332 | { | ||
333 | OSDMap ret = new OSDMap(); | ||
334 | |||
335 | return ret; | ||
336 | } | ||
337 | } | ||
338 | |||
339 | } | ||
diff --git a/OpenSim/Region/OptionalModules/PhysicsParameters/PhysicsParameters.cs b/OpenSim/Region/OptionalModules/PhysicsParameters/PhysicsParameters.cs index 40f7fbc..3083a33 100755 --- a/OpenSim/Region/OptionalModules/PhysicsParameters/PhysicsParameters.cs +++ b/OpenSim/Region/OptionalModules/PhysicsParameters/PhysicsParameters.cs | |||
@@ -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 39cabb5..a375da9 100644 --- a/OpenSim/Region/OptionalModules/PrimLimitsModule/PrimLimitsModule.cs +++ b/OpenSim/Region/OptionalModules/PrimLimitsModule/PrimLimitsModule.cs | |||
@@ -57,9 +57,10 @@ namespace OpenSim.Region.OptionalModules | |||
57 | 57 | ||
58 | public void Initialise(IConfigSource config) | 58 | public void Initialise(IConfigSource config) |
59 | { | 59 | { |
60 | IConfig myConfig = config.Configs["Startup"]; | 60 | //IConfig myConfig = config.Configs["Startup"]; |
61 | 61 | ||
62 | string permissionModules = myConfig.GetString("permissionmodules", "DefaultPermissionsModule"); | 62 | string permissionModules = Util.GetConfigVarFromSections<string>(config, "permissionmodules", |
63 | new string[] { "Startup", "Permissions" }, "DefaultPermissionsModule"); | ||
63 | 64 | ||
64 | List<string> modules=new List<string>(permissionModules.Split(',')); | 65 | List<string> modules=new List<string>(permissionModules.Split(',')); |
65 | 66 | ||
diff --git a/OpenSim/Region/OptionalModules/Properties/AssemblyInfo.cs b/OpenSim/Region/OptionalModules/Properties/AssemblyInfo.cs index 217b2d5..70bda72 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.7.6.*")] |
34 | [assembly: AssemblyFileVersion("1.0.0.0")] | 34 | |
35 | 35 | ||
36 | [assembly: Addin("OpenSim.Region.OptionalModules", "0.1")] | 36 | [assembly: Addin("OpenSim.Region.OptionalModules", "0.1")] |
37 | [assembly: AddinDependency("OpenSim", "0.5")] | 37 | [assembly: AddinDependency("OpenSim", "0.5")] |
diff --git a/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs b/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs new file mode 100755 index 0000000..6009dc5 --- /dev/null +++ b/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.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 copyrightD | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Linq; | ||
30 | using System.Reflection; | ||
31 | using System.Text; | ||
32 | |||
33 | using OpenSim.Framework; | ||
34 | using OpenSim.Region.Framework; | ||
35 | using OpenSim.Region.Framework.Interfaces; | ||
36 | using OpenSim.Region.Framework.Scenes; | ||
37 | using OpenSim.Region.CoreModules; | ||
38 | |||
39 | using Mono.Addins; | ||
40 | using Nini.Config; | ||
41 | using log4net; | ||
42 | using OpenMetaverse; | ||
43 | |||
44 | namespace OpenSim.Region.OptionalModules.Scripting | ||
45 | { | ||
46 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] | ||
47 | public class ExtendedPhysics : INonSharedRegionModule | ||
48 | { | ||
49 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
50 | private static string LogHeader = "[EXTENDED PHYSICS]"; | ||
51 | |||
52 | private IConfig Configuration { get; set; } | ||
53 | private bool Enabled { get; set; } | ||
54 | private Scene BaseScene { get; set; } | ||
55 | private IScriptModuleComms Comms { get; set; } | ||
56 | |||
57 | #region INonSharedRegionModule | ||
58 | |||
59 | public string Name { get { return this.GetType().Name; } } | ||
60 | |||
61 | public void Initialise(IConfigSource config) | ||
62 | { | ||
63 | BaseScene = null; | ||
64 | Enabled = false; | ||
65 | Configuration = null; | ||
66 | Comms = null; | ||
67 | |||
68 | try | ||
69 | { | ||
70 | if ((Configuration = config.Configs["ExtendedPhysics"]) != null) | ||
71 | { | ||
72 | Enabled = Configuration.GetBoolean("Enabled", Enabled); | ||
73 | } | ||
74 | } | ||
75 | catch (Exception e) | ||
76 | { | ||
77 | m_log.ErrorFormat("{0} Initialization error: {0}", LogHeader, e); | ||
78 | } | ||
79 | |||
80 | m_log.InfoFormat("{0} module {1} enabled", LogHeader, (Enabled ? "is" : "is not")); | ||
81 | } | ||
82 | |||
83 | public void Close() | ||
84 | { | ||
85 | if (BaseScene != null) | ||
86 | { | ||
87 | BaseScene.EventManager.OnObjectAddedToScene -= EventManager_OnObjectAddedToScene; | ||
88 | BaseScene.EventManager.OnSceneObjectPartUpdated -= EventManager_OnSceneObjectPartUpdated; | ||
89 | BaseScene = null; | ||
90 | } | ||
91 | } | ||
92 | |||
93 | public void AddRegion(Scene scene) | ||
94 | { | ||
95 | } | ||
96 | |||
97 | public void RemoveRegion(Scene scene) | ||
98 | { | ||
99 | if (BaseScene != null && BaseScene == scene) | ||
100 | { | ||
101 | Close(); | ||
102 | } | ||
103 | } | ||
104 | |||
105 | public void RegionLoaded(Scene scene) | ||
106 | { | ||
107 | if (!Enabled) return; | ||
108 | |||
109 | BaseScene = scene; | ||
110 | |||
111 | Comms = BaseScene.RequestModuleInterface<IScriptModuleComms>(); | ||
112 | if (Comms == null) | ||
113 | { | ||
114 | m_log.WarnFormat("{0} ScriptModuleComms interface not defined", LogHeader); | ||
115 | Enabled = false; | ||
116 | |||
117 | return; | ||
118 | } | ||
119 | |||
120 | // Register as LSL functions all the [ScriptInvocation] marked methods. | ||
121 | Comms.RegisterScriptInvocations(this); | ||
122 | |||
123 | // When an object is modified, we might need to update its extended physics parameters | ||
124 | BaseScene.EventManager.OnObjectAddedToScene += EventManager_OnObjectAddedToScene; | ||
125 | BaseScene.EventManager.OnSceneObjectPartUpdated += EventManager_OnSceneObjectPartUpdated; | ||
126 | |||
127 | } | ||
128 | |||
129 | public Type ReplaceableInterface { get { return null; } } | ||
130 | |||
131 | #endregion // INonSharedRegionModule | ||
132 | |||
133 | private void EventManager_OnObjectAddedToScene(SceneObjectGroup obj) | ||
134 | { | ||
135 | throw new NotImplementedException(); | ||
136 | } | ||
137 | |||
138 | // Event generated when some property of a prim changes. | ||
139 | private void EventManager_OnSceneObjectPartUpdated(SceneObjectPart sop, bool isFullUpdate) | ||
140 | { | ||
141 | } | ||
142 | |||
143 | [ScriptConstant] | ||
144 | public static int PHYS_CENTER_OF_MASS = 1 << 0; | ||
145 | |||
146 | [ScriptConstant] | ||
147 | public static int PHYS_LINKSET_TYPE_CONSTRAINT = 1; | ||
148 | [ScriptConstant] | ||
149 | public static int PHYS_LINKSET_TYPE_COMPOUND = 2; | ||
150 | [ScriptConstant] | ||
151 | public static int PHYS_LINKSET_TYPE_MANUAL = 3; | ||
152 | |||
153 | [ScriptInvocation] | ||
154 | public string physGetEngineType(UUID hostID, UUID scriptID) | ||
155 | { | ||
156 | string ret = string.Empty; | ||
157 | |||
158 | if (BaseScene.PhysicsScene != null) | ||
159 | { | ||
160 | ret = BaseScene.PhysicsScene.EngineType; | ||
161 | } | ||
162 | |||
163 | return ret; | ||
164 | } | ||
165 | |||
166 | [ScriptInvocation] | ||
167 | public void physSetLinksetType(UUID hostID, UUID scriptID, int linksetType) | ||
168 | { | ||
169 | } | ||
170 | } | ||
171 | } | ||
diff --git a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStore.cs b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStore.cs index 34894ba..e498c6a 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 e) | ||
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/JsonStoreModule.cs b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs index e68764a..5fbfcc5 100644 --- a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs +++ b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs | |||
@@ -54,6 +54,9 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore | |||
54 | 54 | ||
55 | private IConfig m_config = null; | 55 | private IConfig m_config = null; |
56 | private bool m_enabled = false; | 56 | private bool m_enabled = false; |
57 | private bool m_enableObjectStore = false; | ||
58 | private int m_maxStringSpace = Int32.MaxValue; | ||
59 | |||
57 | private Scene m_scene = null; | 60 | private Scene m_scene = null; |
58 | 61 | ||
59 | private Dictionary<UUID,JsonStore> m_JsonValueStore; | 62 | private Dictionary<UUID,JsonStore> m_JsonValueStore; |
@@ -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 | // ----------------------------------------------------------------- |
@@ -175,6 +182,35 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore | |||
175 | /// | 182 | /// |
176 | /// </summary> | 183 | /// </summary> |
177 | // ----------------------------------------------------------------- | 184 | // ----------------------------------------------------------------- |
185 | public bool AttachObjectStore(UUID objectID) | ||
186 | { | ||
187 | if (! m_enabled) return false; | ||
188 | if (! m_enableObjectStore) return false; | ||
189 | |||
190 | SceneObjectPart sop = m_scene.GetSceneObjectPart(objectID); | ||
191 | if (sop == null) | ||
192 | { | ||
193 | m_log.ErrorFormat("[JsonStore] unable to attach to unknown object; {0}", objectID); | ||
194 | return false; | ||
195 | } | ||
196 | |||
197 | lock (m_JsonValueStore) | ||
198 | { | ||
199 | if (m_JsonValueStore.ContainsKey(objectID)) | ||
200 | return true; | ||
201 | |||
202 | JsonStore map = new JsonObjectStore(m_scene,objectID); | ||
203 | m_JsonValueStore.Add(objectID,map); | ||
204 | } | ||
205 | |||
206 | return true; | ||
207 | } | ||
208 | |||
209 | // ----------------------------------------------------------------- | ||
210 | /// <summary> | ||
211 | /// | ||
212 | /// </summary> | ||
213 | // ----------------------------------------------------------------- | ||
178 | public bool CreateStore(string value, ref UUID result) | 214 | public bool CreateStore(string value, ref UUID result) |
179 | { | 215 | { |
180 | if (result == UUID.Zero) | 216 | if (result == UUID.Zero) |
@@ -191,7 +227,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore | |||
191 | } | 227 | } |
192 | catch (Exception e) | 228 | catch (Exception e) |
193 | { | 229 | { |
194 | m_log.InfoFormat("[JsonStore] Unable to initialize store from {0}; {1}",value,e.Message); | 230 | m_log.ErrorFormat("[JsonStore]: Unable to initialize store from {0}", value); |
195 | return false; | 231 | return false; |
196 | } | 232 | } |
197 | 233 | ||
@@ -211,7 +247,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore | |||
211 | if (! m_enabled) return false; | 247 | if (! m_enabled) return false; |
212 | 248 | ||
213 | lock (m_JsonValueStore) | 249 | lock (m_JsonValueStore) |
214 | m_JsonValueStore.Remove(storeID); | 250 | return m_JsonValueStore.Remove(storeID); |
215 | 251 | ||
216 | return true; | 252 | return true; |
217 | } | 253 | } |
@@ -221,31 +257,76 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore | |||
221 | /// | 257 | /// |
222 | /// </summary> | 258 | /// </summary> |
223 | // ----------------------------------------------------------------- | 259 | // ----------------------------------------------------------------- |
224 | public bool TestPath(UUID storeID, string path, bool useJson) | 260 | public bool TestStore(UUID storeID) |
225 | { | 261 | { |
226 | if (! m_enabled) return false; | 262 | if (! m_enabled) return false; |
227 | 263 | ||
264 | lock (m_JsonValueStore) | ||
265 | return m_JsonValueStore.ContainsKey(storeID); | ||
266 | } | ||
267 | |||
268 | // ----------------------------------------------------------------- | ||
269 | /// <summary> | ||
270 | /// | ||
271 | /// </summary> | ||
272 | // ----------------------------------------------------------------- | ||
273 | public JsonStoreNodeType GetNodeType(UUID storeID, string path) | ||
274 | { | ||
275 | if (! m_enabled) return JsonStoreNodeType.Undefined; | ||
276 | |||
228 | JsonStore map = null; | 277 | JsonStore map = null; |
229 | lock (m_JsonValueStore) | 278 | lock (m_JsonValueStore) |
230 | { | 279 | { |
231 | if (! m_JsonValueStore.TryGetValue(storeID,out map)) | 280 | if (! m_JsonValueStore.TryGetValue(storeID,out map)) |
232 | { | 281 | { |
233 | m_log.InfoFormat("[JsonStore] Missing store {0}",storeID); | 282 | m_log.InfoFormat("[JsonStore] Missing store {0}",storeID); |
234 | return false; | 283 | return JsonStoreNodeType.Undefined; |
235 | } | 284 | } |
236 | } | 285 | } |
237 | 286 | ||
238 | try | 287 | try |
239 | { | 288 | { |
240 | lock (map) | 289 | lock (map) |
241 | return map.TestPath(path,useJson); | 290 | return map.GetNodeType(path); |
242 | } | 291 | } |
243 | catch (Exception e) | 292 | catch (Exception e) |
244 | { | 293 | { |
245 | m_log.InfoFormat("[JsonStore] Path test failed for {0} in {1}; {2}",path,storeID,e.Message); | 294 | m_log.Error(string.Format("[JsonStore]: Path test failed for {0} in {1}", path, storeID), e); |
246 | } | 295 | } |
247 | 296 | ||
248 | return false; | 297 | return JsonStoreNodeType.Undefined; |
298 | } | ||
299 | |||
300 | // ----------------------------------------------------------------- | ||
301 | /// <summary> | ||
302 | /// | ||
303 | /// </summary> | ||
304 | // ----------------------------------------------------------------- | ||
305 | public JsonStoreValueType GetValueType(UUID storeID, string path) | ||
306 | { | ||
307 | if (! m_enabled) return JsonStoreValueType.Undefined; | ||
308 | |||
309 | JsonStore map = null; | ||
310 | lock (m_JsonValueStore) | ||
311 | { | ||
312 | if (! m_JsonValueStore.TryGetValue(storeID,out map)) | ||
313 | { | ||
314 | m_log.InfoFormat("[JsonStore] Missing store {0}",storeID); | ||
315 | return JsonStoreValueType.Undefined; | ||
316 | } | ||
317 | } | ||
318 | |||
319 | try | ||
320 | { | ||
321 | lock (map) | ||
322 | return map.GetValueType(path); | ||
323 | } | ||
324 | catch (Exception e) | ||
325 | { | ||
326 | m_log.Error(string.Format("[JsonStore]: Path test failed for {0} in {1}", path, storeID), e); | ||
327 | } | ||
328 | |||
329 | return JsonStoreValueType.Undefined; | ||
249 | } | 330 | } |
250 | 331 | ||
251 | // ----------------------------------------------------------------- | 332 | // ----------------------------------------------------------------- |
@@ -270,12 +351,20 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore | |||
270 | try | 351 | try |
271 | { | 352 | { |
272 | lock (map) | 353 | lock (map) |
273 | if (map.SetValue(path,value,useJson)) | 354 | { |
274 | return true; | 355 | if (map.StringSpace > m_maxStringSpace) |
356 | { | ||
357 | m_log.WarnFormat("[JsonStore] {0} exceeded string size; {1} bytes used of {2} limit", | ||
358 | storeID,map.StringSpace,m_maxStringSpace); | ||
359 | return false; | ||
360 | } | ||
361 | |||
362 | return map.SetValue(path,value,useJson); | ||
363 | } | ||
275 | } | 364 | } |
276 | catch (Exception e) | 365 | catch (Exception e) |
277 | { | 366 | { |
278 | m_log.InfoFormat("[JsonStore] Unable to assign {0} to {1} in {2}; {3}",value,path,storeID,e.Message); | 367 | m_log.Error(string.Format("[JsonStore]: Unable to assign {0} to {1} in {2}", value, path, storeID), e); |
279 | } | 368 | } |
280 | 369 | ||
281 | return false; | 370 | return false; |
@@ -303,12 +392,11 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore | |||
303 | try | 392 | try |
304 | { | 393 | { |
305 | lock (map) | 394 | lock (map) |
306 | if (map.RemoveValue(path)) | 395 | return map.RemoveValue(path); |
307 | return true; | ||
308 | } | 396 | } |
309 | catch (Exception e) | 397 | catch (Exception e) |
310 | { | 398 | { |
311 | m_log.InfoFormat("[JsonStore] Unable to remove {0} in {1}; {2}",path,storeID,e.Message); | 399 | m_log.Error(string.Format("[JsonStore]: Unable to remove {0} in {1}", path, storeID), e); |
312 | } | 400 | } |
313 | 401 | ||
314 | return false; | 402 | return false; |
@@ -319,6 +407,37 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore | |||
319 | /// | 407 | /// |
320 | /// </summary> | 408 | /// </summary> |
321 | // ----------------------------------------------------------------- | 409 | // ----------------------------------------------------------------- |
410 | public int GetArrayLength(UUID storeID, string path) | ||
411 | { | ||
412 | if (! m_enabled) return -1; | ||
413 | |||
414 | JsonStore map = null; | ||
415 | lock (m_JsonValueStore) | ||
416 | { | ||
417 | if (! m_JsonValueStore.TryGetValue(storeID,out map)) | ||
418 | return -1; | ||
419 | } | ||
420 | |||
421 | try | ||
422 | { | ||
423 | lock (map) | ||
424 | { | ||
425 | return map.ArrayLength(path); | ||
426 | } | ||
427 | } | ||
428 | catch (Exception e) | ||
429 | { | ||
430 | m_log.Error("[JsonStore]: unable to retrieve value", e); | ||
431 | } | ||
432 | |||
433 | return -1; | ||
434 | } | ||
435 | |||
436 | // ----------------------------------------------------------------- | ||
437 | /// <summary> | ||
438 | /// | ||
439 | /// </summary> | ||
440 | // ----------------------------------------------------------------- | ||
322 | public bool GetValue(UUID storeID, string path, bool useJson, out string value) | 441 | public bool GetValue(UUID storeID, string path, bool useJson, out string value) |
323 | { | 442 | { |
324 | value = String.Empty; | 443 | value = String.Empty; |
@@ -341,7 +460,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore | |||
341 | } | 460 | } |
342 | catch (Exception e) | 461 | catch (Exception e) |
343 | { | 462 | { |
344 | m_log.InfoFormat("[JsonStore] unable to retrieve value; {0}",e.Message); | 463 | m_log.Error("[JsonStore]: unable to retrieve value", e); |
345 | } | 464 | } |
346 | 465 | ||
347 | return false; | 466 | return false; |
@@ -380,7 +499,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore | |||
380 | } | 499 | } |
381 | catch (Exception e) | 500 | catch (Exception e) |
382 | { | 501 | { |
383 | m_log.InfoFormat("[JsonStore] unable to retrieve value; {0}",e.ToString()); | 502 | m_log.Error("[JsonStore] unable to retrieve value", e); |
384 | } | 503 | } |
385 | 504 | ||
386 | cback(String.Empty); | 505 | cback(String.Empty); |
@@ -419,7 +538,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore | |||
419 | } | 538 | } |
420 | catch (Exception e) | 539 | catch (Exception e) |
421 | { | 540 | { |
422 | m_log.InfoFormat("[JsonStore] unable to retrieve value; {0}",e.ToString()); | 541 | m_log.Error("[JsonStore]: unable to retrieve value", e); |
423 | } | 542 | } |
424 | 543 | ||
425 | cback(String.Empty); | 544 | cback(String.Empty); |
diff --git a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs index 0c175ca..1bb5aee 100644 --- a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs +++ b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs | |||
@@ -39,8 +39,10 @@ using OpenMetaverse.StructuredData; | |||
39 | using OpenSim.Framework; | 39 | using OpenSim.Framework; |
40 | using OpenSim.Region.Framework.Interfaces; | 40 | using OpenSim.Region.Framework.Interfaces; |
41 | using OpenSim.Region.Framework.Scenes; | 41 | using OpenSim.Region.Framework.Scenes; |
42 | using OpenSim.Region.Framework.Scenes.Scripting; | ||
42 | using System.Collections.Generic; | 43 | using System.Collections.Generic; |
43 | using System.Text.RegularExpressions; | 44 | using System.Text.RegularExpressions; |
45 | using PermissionMask = OpenSim.Framework.PermissionMask; | ||
44 | 46 | ||
45 | namespace OpenSim.Region.OptionalModules.Scripting.JsonStore | 47 | namespace OpenSim.Region.OptionalModules.Scripting.JsonStore |
46 | { | 48 | { |
@@ -92,12 +94,12 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore | |||
92 | } | 94 | } |
93 | catch (Exception e) | 95 | catch (Exception e) |
94 | { | 96 | { |
95 | m_log.ErrorFormat("[JsonStoreScripts] initialization error: {0}",e.Message); | 97 | m_log.ErrorFormat("[JsonStoreScripts]: initialization error: {0}", e.Message); |
96 | return; | 98 | return; |
97 | } | 99 | } |
98 | 100 | ||
99 | if (m_enabled) | 101 | if (m_enabled) |
100 | m_log.DebugFormat("[JsonStoreScripts] module is enabled"); | 102 | m_log.DebugFormat("[JsonStoreScripts]: module is enabled"); |
101 | } | 103 | } |
102 | 104 | ||
103 | // ----------------------------------------------------------------- | 105 | // ----------------------------------------------------------------- |
@@ -150,7 +152,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore | |||
150 | m_comms = m_scene.RequestModuleInterface<IScriptModuleComms>(); | 152 | m_comms = m_scene.RequestModuleInterface<IScriptModuleComms>(); |
151 | if (m_comms == null) | 153 | if (m_comms == null) |
152 | { | 154 | { |
153 | m_log.ErrorFormat("[JsonStoreScripts] ScriptModuleComms interface not defined"); | 155 | m_log.ErrorFormat("[JsonStoreScripts]: ScriptModuleComms interface not defined"); |
154 | m_enabled = false; | 156 | m_enabled = false; |
155 | return; | 157 | return; |
156 | } | 158 | } |
@@ -158,40 +160,20 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore | |||
158 | m_store = m_scene.RequestModuleInterface<IJsonStoreModule>(); | 160 | m_store = m_scene.RequestModuleInterface<IJsonStoreModule>(); |
159 | if (m_store == null) | 161 | if (m_store == null) |
160 | { | 162 | { |
161 | m_log.ErrorFormat("[JsonStoreScripts] JsonModule interface not defined"); | 163 | m_log.ErrorFormat("[JsonStoreScripts]: JsonModule interface not defined"); |
162 | m_enabled = false; | 164 | m_enabled = false; |
163 | return; | 165 | return; |
164 | } | 166 | } |
165 | 167 | ||
166 | try | 168 | try |
167 | { | 169 | { |
168 | m_comms.RegisterScriptInvocation(this,"JsonCreateStore"); | 170 | m_comms.RegisterScriptInvocations(this); |
169 | m_comms.RegisterScriptInvocation(this,"JsonDestroyStore"); | 171 | 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 | } | 172 | } |
191 | catch (Exception e) | 173 | catch (Exception e) |
192 | { | 174 | { |
193 | // See http://opensimulator.org/mantis/view.php?id=5971 for more information | 175 | // See http://opensimulator.org/mantis/view.php?id=5971 for more information |
194 | m_log.WarnFormat("[JsonStroreScripts] script method registration failed; {0}",e.Message); | 176 | m_log.WarnFormat("[JsonStoreScripts]: script method registration failed; {0}", e.Message); |
195 | m_enabled = false; | 177 | m_enabled = false; |
196 | } | 178 | } |
197 | } | 179 | } |
@@ -208,23 +190,61 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore | |||
208 | 190 | ||
209 | #endregion | 191 | #endregion |
210 | 192 | ||
193 | #region ScriptConstantsInterface | ||
194 | |||
195 | [ScriptConstant] | ||
196 | public static readonly int JSON_NODETYPE_UNDEF = (int)JsonStoreNodeType.Undefined; | ||
197 | |||
198 | [ScriptConstant] | ||
199 | public static readonly int JSON_NODETYPE_OBJECT = (int)JsonStoreNodeType.Object; | ||
200 | |||
201 | [ScriptConstant] | ||
202 | public static readonly int JSON_NODETYPE_ARRAY = (int)JsonStoreNodeType.Array; | ||
203 | |||
204 | [ScriptConstant] | ||
205 | public static readonly int JSON_NODETYPE_VALUE = (int)JsonStoreNodeType.Value; | ||
206 | |||
207 | [ScriptConstant] | ||
208 | public static readonly int JSON_VALUETYPE_UNDEF = (int)JsonStoreValueType.Undefined; | ||
209 | |||
210 | [ScriptConstant] | ||
211 | public static readonly int JSON_VALUETYPE_BOOLEAN = (int)JsonStoreValueType.Boolean; | ||
212 | |||
213 | [ScriptConstant] | ||
214 | public static readonly int JSON_VALUETYPE_INTEGER = (int)JsonStoreValueType.Integer; | ||
215 | |||
216 | [ScriptConstant] | ||
217 | public static readonly int JSON_VALUETYPE_FLOAT = (int)JsonStoreValueType.Float; | ||
218 | |||
219 | [ScriptConstant] | ||
220 | public static readonly int JSON_VALUETYPE_STRING = (int)JsonStoreValueType.String; | ||
221 | |||
222 | |||
223 | #endregion | ||
224 | |||
211 | #region ScriptInvocationInteface | 225 | #region ScriptInvocationInteface |
212 | // ----------------------------------------------------------------- | 226 | // ----------------------------------------------------------------- |
213 | /// <summary> | 227 | /// <summary> |
214 | /// | 228 | /// |
215 | /// </summary> | 229 | /// </summary> |
216 | // ----------------------------------------------------------------- | 230 | // ----------------------------------------------------------------- |
217 | protected void GenerateRuntimeError(string msg) | 231 | [ScriptInvocation] |
232 | public UUID JsonAttachObjectStore(UUID hostID, UUID scriptID) | ||
218 | { | 233 | { |
219 | throw new Exception("JsonStore Runtime Error: " + msg); | 234 | UUID uuid = UUID.Zero; |
235 | if (! m_store.AttachObjectStore(hostID)) | ||
236 | GenerateRuntimeError("Failed to create Json store"); | ||
237 | |||
238 | return hostID; | ||
220 | } | 239 | } |
221 | 240 | ||
222 | // ----------------------------------------------------------------- | 241 | // ----------------------------------------------------------------- |
223 | /// <summary> | 242 | /// <summary> |
224 | /// | 243 | /// |
225 | /// </summary> | 244 | /// </summary> |
226 | // ----------------------------------------------------------------- | 245 | // ----------------------------------------------------------------- |
227 | protected UUID JsonCreateStore(UUID hostID, UUID scriptID, string value) | 246 | [ScriptInvocation] |
247 | public UUID JsonCreateStore(UUID hostID, UUID scriptID, string value) | ||
228 | { | 248 | { |
229 | UUID uuid = UUID.Zero; | 249 | UUID uuid = UUID.Zero; |
230 | if (! m_store.CreateStore(value, ref uuid)) | 250 | if (! m_store.CreateStore(value, ref uuid)) |
@@ -238,7 +258,8 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore | |||
238 | /// | 258 | /// |
239 | /// </summary> | 259 | /// </summary> |
240 | // ----------------------------------------------------------------- | 260 | // ----------------------------------------------------------------- |
241 | protected int JsonDestroyStore(UUID hostID, UUID scriptID, UUID storeID) | 261 | [ScriptInvocation] |
262 | public int JsonDestroyStore(UUID hostID, UUID scriptID, UUID storeID) | ||
242 | { | 263 | { |
243 | return m_store.DestroyStore(storeID) ? 1 : 0; | 264 | return m_store.DestroyStore(storeID) ? 1 : 0; |
244 | } | 265 | } |
@@ -248,10 +269,22 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore | |||
248 | /// | 269 | /// |
249 | /// </summary> | 270 | /// </summary> |
250 | // ----------------------------------------------------------------- | 271 | // ----------------------------------------------------------------- |
251 | protected UUID JsonReadNotecard(UUID hostID, UUID scriptID, UUID storeID, string path, UUID assetID) | 272 | [ScriptInvocation] |
273 | public int JsonTestStore(UUID hostID, UUID scriptID, UUID storeID) | ||
274 | { | ||
275 | return m_store.TestStore(storeID) ? 1 : 0; | ||
276 | } | ||
277 | |||
278 | // ----------------------------------------------------------------- | ||
279 | /// <summary> | ||
280 | /// | ||
281 | /// </summary> | ||
282 | // ----------------------------------------------------------------- | ||
283 | [ScriptInvocation] | ||
284 | public UUID JsonReadNotecard(UUID hostID, UUID scriptID, UUID storeID, string path, string notecardIdentifier) | ||
252 | { | 285 | { |
253 | UUID reqID = UUID.Random(); | 286 | UUID reqID = UUID.Random(); |
254 | Util.FireAndForget(delegate(object o) { DoJsonReadNotecard(reqID,hostID,scriptID,storeID,path,assetID); }); | 287 | Util.FireAndForget(o => DoJsonReadNotecard(reqID, hostID, scriptID, storeID, path, notecardIdentifier)); |
255 | return reqID; | 288 | return reqID; |
256 | } | 289 | } |
257 | 290 | ||
@@ -260,7 +293,8 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore | |||
260 | /// | 293 | /// |
261 | /// </summary> | 294 | /// </summary> |
262 | // ----------------------------------------------------------------- | 295 | // ----------------------------------------------------------------- |
263 | protected UUID JsonWriteNotecard(UUID hostID, UUID scriptID, UUID storeID, string path, string name) | 296 | [ScriptInvocation] |
297 | public UUID JsonWriteNotecard(UUID hostID, UUID scriptID, UUID storeID, string path, string name) | ||
264 | { | 298 | { |
265 | UUID reqID = UUID.Random(); | 299 | UUID reqID = UUID.Random(); |
266 | Util.FireAndForget(delegate(object o) { DoJsonWriteNotecard(reqID,hostID,scriptID,storeID,path,name); }); | 300 | Util.FireAndForget(delegate(object o) { DoJsonWriteNotecard(reqID,hostID,scriptID,storeID,path,name); }); |
@@ -272,14 +306,41 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore | |||
272 | /// | 306 | /// |
273 | /// </summary> | 307 | /// </summary> |
274 | // ----------------------------------------------------------------- | 308 | // ----------------------------------------------------------------- |
275 | protected int JsonTestPath(UUID hostID, UUID scriptID, UUID storeID, string path) | 309 | [ScriptInvocation] |
310 | public string JsonList2Path(UUID hostID, UUID scriptID, object[] pathlist) | ||
276 | { | 311 | { |
277 | return m_store.TestPath(storeID,path,false) ? 1 : 0; | 312 | string ipath = ConvertList2Path(pathlist); |
313 | string opath; | ||
314 | |||
315 | if (JsonStore.CanonicalPathExpression(ipath,out opath)) | ||
316 | return opath; | ||
317 | |||
318 | // This won't parse if passed to the other routines as opposed to | ||
319 | // returning an empty string which is a valid path and would overwrite | ||
320 | // the entire store | ||
321 | return "**INVALID**"; | ||
322 | } | ||
323 | |||
324 | // ----------------------------------------------------------------- | ||
325 | /// <summary> | ||
326 | /// | ||
327 | /// </summary> | ||
328 | // ----------------------------------------------------------------- | ||
329 | [ScriptInvocation] | ||
330 | public int JsonGetNodeType(UUID hostID, UUID scriptID, UUID storeID, string path) | ||
331 | { | ||
332 | return (int)m_store.GetNodeType(storeID,path); | ||
278 | } | 333 | } |
279 | 334 | ||
280 | protected int JsonTestPathJson(UUID hostID, UUID scriptID, UUID storeID, string path) | 335 | // ----------------------------------------------------------------- |
336 | /// <summary> | ||
337 | /// | ||
338 | /// </summary> | ||
339 | // ----------------------------------------------------------------- | ||
340 | [ScriptInvocation] | ||
341 | public int JsonGetValueType(UUID hostID, UUID scriptID, UUID storeID, string path) | ||
281 | { | 342 | { |
282 | return m_store.TestPath(storeID,path,true) ? 1 : 0; | 343 | return (int)m_store.GetValueType(storeID,path); |
283 | } | 344 | } |
284 | 345 | ||
285 | // ----------------------------------------------------------------- | 346 | // ----------------------------------------------------------------- |
@@ -287,12 +348,14 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore | |||
287 | /// | 348 | /// |
288 | /// </summary> | 349 | /// </summary> |
289 | // ----------------------------------------------------------------- | 350 | // ----------------------------------------------------------------- |
290 | protected int JsonSetValue(UUID hostID, UUID scriptID, UUID storeID, string path, string value) | 351 | [ScriptInvocation] |
352 | public int JsonSetValue(UUID hostID, UUID scriptID, UUID storeID, string path, string value) | ||
291 | { | 353 | { |
292 | return m_store.SetValue(storeID,path,value,false) ? 1 : 0; | 354 | return m_store.SetValue(storeID,path,value,false) ? 1 : 0; |
293 | } | 355 | } |
294 | 356 | ||
295 | protected int JsonSetValueJson(UUID hostID, UUID scriptID, UUID storeID, string path, string value) | 357 | [ScriptInvocation] |
358 | public int JsonSetJson(UUID hostID, UUID scriptID, UUID storeID, string path, string value) | ||
296 | { | 359 | { |
297 | return m_store.SetValue(storeID,path,value,true) ? 1 : 0; | 360 | return m_store.SetValue(storeID,path,value,true) ? 1 : 0; |
298 | } | 361 | } |
@@ -302,7 +365,8 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore | |||
302 | /// | 365 | /// |
303 | /// </summary> | 366 | /// </summary> |
304 | // ----------------------------------------------------------------- | 367 | // ----------------------------------------------------------------- |
305 | protected int JsonRemoveValue(UUID hostID, UUID scriptID, UUID storeID, string path) | 368 | [ScriptInvocation] |
369 | public int JsonRemoveValue(UUID hostID, UUID scriptID, UUID storeID, string path) | ||
306 | { | 370 | { |
307 | return m_store.RemoveValue(storeID,path) ? 1 : 0; | 371 | return m_store.RemoveValue(storeID,path) ? 1 : 0; |
308 | } | 372 | } |
@@ -312,14 +376,27 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore | |||
312 | /// | 376 | /// |
313 | /// </summary> | 377 | /// </summary> |
314 | // ----------------------------------------------------------------- | 378 | // ----------------------------------------------------------------- |
315 | protected string JsonGetValue(UUID hostID, UUID scriptID, UUID storeID, string path) | 379 | [ScriptInvocation] |
380 | public int JsonGetArrayLength(UUID hostID, UUID scriptID, UUID storeID, string path) | ||
381 | { | ||
382 | return m_store.GetArrayLength(storeID,path); | ||
383 | } | ||
384 | |||
385 | // ----------------------------------------------------------------- | ||
386 | /// <summary> | ||
387 | /// | ||
388 | /// </summary> | ||
389 | // ----------------------------------------------------------------- | ||
390 | [ScriptInvocation] | ||
391 | public string JsonGetValue(UUID hostID, UUID scriptID, UUID storeID, string path) | ||
316 | { | 392 | { |
317 | string value = String.Empty; | 393 | string value = String.Empty; |
318 | m_store.GetValue(storeID,path,false,out value); | 394 | m_store.GetValue(storeID,path,false,out value); |
319 | return value; | 395 | return value; |
320 | } | 396 | } |
321 | 397 | ||
322 | protected string JsonGetValueJson(UUID hostID, UUID scriptID, UUID storeID, string path) | 398 | [ScriptInvocation] |
399 | public string JsonGetJson(UUID hostID, UUID scriptID, UUID storeID, string path) | ||
323 | { | 400 | { |
324 | string value = String.Empty; | 401 | string value = String.Empty; |
325 | m_store.GetValue(storeID,path,true, out value); | 402 | m_store.GetValue(storeID,path,true, out value); |
@@ -331,80 +408,105 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore | |||
331 | /// | 408 | /// |
332 | /// </summary> | 409 | /// </summary> |
333 | // ----------------------------------------------------------------- | 410 | // ----------------------------------------------------------------- |
334 | protected UUID JsonTakeValue(UUID hostID, UUID scriptID, UUID storeID, string path) | 411 | [ScriptInvocation] |
412 | public UUID JsonTakeValue(UUID hostID, UUID scriptID, UUID storeID, string path) | ||
335 | { | 413 | { |
336 | UUID reqID = UUID.Random(); | 414 | UUID reqID = UUID.Random(); |
337 | Util.FireAndForget(delegate(object o) { DoJsonTakeValue(scriptID,reqID,storeID,path,false); }); | 415 | Util.FireAndForget(delegate(object o) { DoJsonTakeValue(scriptID,reqID,storeID,path,false); }); |
338 | return reqID; | 416 | return reqID; |
339 | } | 417 | } |
340 | 418 | ||
341 | protected UUID JsonTakeValueJson(UUID hostID, UUID scriptID, UUID storeID, string path) | 419 | [ScriptInvocation] |
420 | public UUID JsonTakeValueJson(UUID hostID, UUID scriptID, UUID storeID, string path) | ||
342 | { | 421 | { |
343 | UUID reqID = UUID.Random(); | 422 | UUID reqID = UUID.Random(); |
344 | Util.FireAndForget(delegate(object o) { DoJsonTakeValue(scriptID,reqID,storeID,path,true); }); | 423 | Util.FireAndForget(delegate(object o) { DoJsonTakeValue(scriptID,reqID,storeID,path,true); }); |
345 | return reqID; | 424 | return reqID; |
346 | } | 425 | } |
347 | 426 | ||
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 | // ----------------------------------------------------------------- | 427 | // ----------------------------------------------------------------- |
365 | /// <summary> | 428 | /// <summary> |
366 | /// | 429 | /// |
367 | /// </summary> | 430 | /// </summary> |
368 | // ----------------------------------------------------------------- | 431 | // ----------------------------------------------------------------- |
369 | protected UUID JsonReadValue(UUID hostID, UUID scriptID, UUID storeID, string path) | 432 | [ScriptInvocation] |
433 | public UUID JsonReadValue(UUID hostID, UUID scriptID, UUID storeID, string path) | ||
370 | { | 434 | { |
371 | UUID reqID = UUID.Random(); | 435 | UUID reqID = UUID.Random(); |
372 | Util.FireAndForget(delegate(object o) { DoJsonReadValue(scriptID,reqID,storeID,path,false); }); | 436 | Util.FireAndForget(delegate(object o) { DoJsonReadValue(scriptID,reqID,storeID,path,false); }); |
373 | return reqID; | 437 | return reqID; |
374 | } | 438 | } |
375 | 439 | ||
376 | protected UUID JsonReadValueJson(UUID hostID, UUID scriptID, UUID storeID, string path) | 440 | [ScriptInvocation] |
441 | public UUID JsonReadValueJson(UUID hostID, UUID scriptID, UUID storeID, string path) | ||
377 | { | 442 | { |
378 | UUID reqID = UUID.Random(); | 443 | UUID reqID = UUID.Random(); |
379 | Util.FireAndForget(delegate(object o) { DoJsonReadValue(scriptID,reqID,storeID,path,true); }); | 444 | Util.FireAndForget(delegate(object o) { DoJsonReadValue(scriptID,reqID,storeID,path,true); }); |
380 | return reqID; | 445 | return reqID; |
381 | } | 446 | } |
382 | 447 | ||
383 | private void DoJsonReadValue(UUID scriptID, UUID reqID, UUID storeID, string path, bool useJson) | 448 | #endregion |
449 | |||
450 | // ----------------------------------------------------------------- | ||
451 | /// <summary> | ||
452 | /// | ||
453 | /// </summary> | ||
454 | // ----------------------------------------------------------------- | ||
455 | protected void GenerateRuntimeError(string msg) | ||
456 | { | ||
457 | m_log.InfoFormat("[JsonStore] runtime error: {0}",msg); | ||
458 | throw new Exception("JsonStore Runtime Error: " + msg); | ||
459 | } | ||
460 | |||
461 | // ----------------------------------------------------------------- | ||
462 | /// <summary> | ||
463 | /// | ||
464 | /// </summary> | ||
465 | // ----------------------------------------------------------------- | ||
466 | protected void DispatchValue(UUID scriptID, UUID reqID, string value) | ||
467 | { | ||
468 | m_comms.DispatchReply(scriptID,1,value,reqID.ToString()); | ||
469 | } | ||
470 | |||
471 | // ----------------------------------------------------------------- | ||
472 | /// <summary> | ||
473 | /// | ||
474 | /// </summary> | ||
475 | // ----------------------------------------------------------------- | ||
476 | private void DoJsonTakeValue(UUID scriptID, UUID reqID, UUID storeID, string path, bool useJson) | ||
384 | { | 477 | { |
385 | try | 478 | try |
386 | { | 479 | { |
387 | m_store.ReadValue(storeID,path,useJson,delegate(string value) { DispatchValue(scriptID,reqID,value); }); | 480 | m_store.TakeValue(storeID,path,useJson,delegate(string value) { DispatchValue(scriptID,reqID,value); }); |
388 | return; | 481 | return; |
389 | } | 482 | } |
390 | catch (Exception e) | 483 | catch (Exception e) |
391 | { | 484 | { |
392 | m_log.InfoFormat("[JsonStoreScripts] unable to retrieve value; {0}",e.ToString()); | 485 | m_log.InfoFormat("[JsonStoreScripts]: unable to retrieve value; {0}",e.ToString()); |
393 | } | 486 | } |
394 | 487 | ||
395 | DispatchValue(scriptID,reqID,String.Empty); | 488 | DispatchValue(scriptID,reqID,String.Empty); |
396 | } | 489 | } |
397 | 490 | ||
398 | #endregion | ||
399 | 491 | ||
400 | // ----------------------------------------------------------------- | 492 | // ----------------------------------------------------------------- |
401 | /// <summary> | 493 | /// <summary> |
402 | /// | 494 | /// |
403 | /// </summary> | 495 | /// </summary> |
404 | // ----------------------------------------------------------------- | 496 | // ----------------------------------------------------------------- |
405 | protected void DispatchValue(UUID scriptID, UUID reqID, string value) | 497 | private void DoJsonReadValue(UUID scriptID, UUID reqID, UUID storeID, string path, bool useJson) |
406 | { | 498 | { |
407 | m_comms.DispatchReply(scriptID,1,value,reqID.ToString()); | 499 | try |
500 | { | ||
501 | m_store.ReadValue(storeID,path,useJson,delegate(string value) { DispatchValue(scriptID,reqID,value); }); | ||
502 | return; | ||
503 | } | ||
504 | catch (Exception e) | ||
505 | { | ||
506 | m_log.InfoFormat("[JsonStoreScripts]: unable to retrieve value; {0}",e.ToString()); | ||
507 | } | ||
508 | |||
509 | DispatchValue(scriptID,reqID,String.Empty); | ||
408 | } | 510 | } |
409 | 511 | ||
410 | // ----------------------------------------------------------------- | 512 | // ----------------------------------------------------------------- |
@@ -412,31 +514,40 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore | |||
412 | /// | 514 | /// |
413 | /// </summary> | 515 | /// </summary> |
414 | // ----------------------------------------------------------------- | 516 | // ----------------------------------------------------------------- |
415 | private void DoJsonReadNotecard(UUID reqID, UUID hostID, UUID scriptID, UUID storeID, string path, UUID assetID) | 517 | private void DoJsonReadNotecard( |
518 | UUID reqID, UUID hostID, UUID scriptID, UUID storeID, string path, string notecardIdentifier) | ||
416 | { | 519 | { |
520 | UUID assetID; | ||
521 | |||
522 | if (!UUID.TryParse(notecardIdentifier, out assetID)) | ||
523 | { | ||
524 | SceneObjectPart part = m_scene.GetSceneObjectPart(hostID); | ||
525 | assetID = ScriptUtils.GetAssetIdFromItemName(part, notecardIdentifier, (int)AssetType.Notecard); | ||
526 | } | ||
527 | |||
417 | AssetBase a = m_scene.AssetService.Get(assetID.ToString()); | 528 | AssetBase a = m_scene.AssetService.Get(assetID.ToString()); |
418 | if (a == null) | 529 | if (a == null) |
419 | GenerateRuntimeError(String.Format("Unable to find notecard asset {0}",assetID)); | 530 | GenerateRuntimeError(String.Format("Unable to find notecard asset {0}", assetID)); |
420 | 531 | ||
421 | if (a.Type != (sbyte)AssetType.Notecard) | 532 | if (a.Type != (sbyte)AssetType.Notecard) |
422 | GenerateRuntimeError(String.Format("Invalid notecard asset {0}",assetID)); | 533 | GenerateRuntimeError(String.Format("Invalid notecard asset {0}", assetID)); |
423 | 534 | ||
424 | m_log.DebugFormat("[JsonStoreScripts] read notecard in context {0}",storeID); | 535 | m_log.DebugFormat("[JsonStoreScripts]: read notecard in context {0}",storeID); |
425 | 536 | ||
426 | try | 537 | try |
427 | { | 538 | { |
428 | string jsondata = SLUtil.ParseNotecardToString(Encoding.UTF8.GetString(a.Data)); | 539 | string jsondata = SLUtil.ParseNotecardToString(Encoding.UTF8.GetString(a.Data)); |
429 | int result = m_store.SetValue(storeID, path, jsondata,true) ? 1 : 0; | 540 | int result = m_store.SetValue(storeID, path, jsondata,true) ? 1 : 0; |
430 | m_comms.DispatchReply(scriptID,result, "", reqID.ToString()); | 541 | m_comms.DispatchReply(scriptID, result, "", reqID.ToString()); |
431 | return; | 542 | return; |
432 | } | 543 | } |
433 | catch (Exception e) | 544 | catch (Exception e) |
434 | { | 545 | { |
435 | m_log.WarnFormat("[JsonStoreScripts] Json parsing failed; {0}",e.Message); | 546 | m_log.WarnFormat("[JsonStoreScripts]: Json parsing failed; {0}", e.Message); |
436 | } | 547 | } |
437 | 548 | ||
438 | GenerateRuntimeError(String.Format("Json parsing failed for {0}",assetID.ToString())); | 549 | GenerateRuntimeError(String.Format("Json parsing failed for {0}", assetID)); |
439 | m_comms.DispatchReply(scriptID,0,"",reqID.ToString()); | 550 | m_comms.DispatchReply(scriptID, 0, "", reqID.ToString()); |
440 | } | 551 | } |
441 | 552 | ||
442 | // ----------------------------------------------------------------- | 553 | // ----------------------------------------------------------------- |
@@ -494,5 +605,43 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore | |||
494 | 605 | ||
495 | m_comms.DispatchReply(scriptID,1,assetID.ToString(),reqID.ToString()); | 606 | m_comms.DispatchReply(scriptID,1,assetID.ToString(),reqID.ToString()); |
496 | } | 607 | } |
608 | |||
609 | // ----------------------------------------------------------------- | ||
610 | /// <summary> | ||
611 | /// Convert a list of values that are path components to a single string path | ||
612 | /// </summary> | ||
613 | // ----------------------------------------------------------------- | ||
614 | protected static Regex m_ArrayPattern = new Regex("^([0-9]+|\\+)$"); | ||
615 | private string ConvertList2Path(object[] pathlist) | ||
616 | { | ||
617 | string path = ""; | ||
618 | for (int i = 0; i < pathlist.Length; i++) | ||
619 | { | ||
620 | string token = ""; | ||
621 | |||
622 | if (pathlist[i] is string) | ||
623 | { | ||
624 | token = pathlist[i].ToString(); | ||
625 | |||
626 | // Check to see if this is a bare number which would not be a valid | ||
627 | // identifier otherwise | ||
628 | if (m_ArrayPattern.IsMatch(token)) | ||
629 | token = '[' + token + ']'; | ||
630 | } | ||
631 | else if (pathlist[i] is int) | ||
632 | { | ||
633 | token = "[" + pathlist[i].ToString() + "]"; | ||
634 | } | ||
635 | else | ||
636 | { | ||
637 | token = "." + pathlist[i].ToString() + "."; | ||
638 | } | ||
639 | |||
640 | path += token + "."; | ||
641 | } | ||
642 | |||
643 | return path; | ||
644 | } | ||
645 | |||
497 | } | 646 | } |
498 | } | 647 | } |
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..bfa9937 --- /dev/null +++ b/OpenSim/Region/OptionalModules/Scripting/JsonStore/Tests/JsonStoreScriptModuleTests.cs | |||
@@ -0,0 +1,901 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Reflection; | ||
31 | using System.Text; | ||
32 | using log4net; | ||
33 | using Nini.Config; | ||
34 | using NUnit.Framework; | ||
35 | using OpenMetaverse; | ||
36 | using OpenSim.Framework; | ||
37 | using OpenSim.Region.CoreModules.Scripting.ScriptModuleComms; | ||
38 | using OpenSim.Region.Framework.Scenes; | ||
39 | using OpenSim.Region.ScriptEngine.Shared; | ||
40 | using OpenSim.Region.ScriptEngine.Shared.Api; | ||
41 | using OpenSim.Services.Interfaces; | ||
42 | using OpenSim.Tests.Common; | ||
43 | using OpenSim.Tests.Common.Mock; | ||
44 | |||
45 | namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests | ||
46 | { | ||
47 | /// <summary> | ||
48 | /// Tests for inventory functions in LSL | ||
49 | /// </summary> | ||
50 | [TestFixture] | ||
51 | public class JsonStoreScriptModuleTests : OpenSimTestCase | ||
52 | { | ||
53 | private Scene m_scene; | ||
54 | private MockScriptEngine m_engine; | ||
55 | private ScriptModuleCommsModule m_smcm; | ||
56 | private JsonStoreScriptModule m_jssm; | ||
57 | |||
58 | [TestFixtureSetUp] | ||
59 | public void FixtureInit() | ||
60 | { | ||
61 | // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread. | ||
62 | Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest; | ||
63 | } | ||
64 | |||
65 | [TestFixtureTearDown] | ||
66 | public void TearDown() | ||
67 | { | ||
68 | // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple | ||
69 | // threads. Possibly, later tests should be rewritten so none of them require async stuff (which regression | ||
70 | // tests really shouldn't). | ||
71 | Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod; | ||
72 | } | ||
73 | |||
74 | [SetUp] | ||
75 | public override void SetUp() | ||
76 | { | ||
77 | base.SetUp(); | ||
78 | |||
79 | IConfigSource configSource = new IniConfigSource(); | ||
80 | IConfig jsonStoreConfig = configSource.AddConfig("JsonStore"); | ||
81 | jsonStoreConfig.Set("Enabled", "true"); | ||
82 | |||
83 | m_engine = new MockScriptEngine(); | ||
84 | m_smcm = new ScriptModuleCommsModule(); | ||
85 | JsonStoreModule jsm = new JsonStoreModule(); | ||
86 | m_jssm = new JsonStoreScriptModule(); | ||
87 | |||
88 | m_scene = new SceneHelpers().SetupScene(); | ||
89 | SceneHelpers.SetupSceneModules(m_scene, configSource, m_engine, m_smcm, jsm, m_jssm); | ||
90 | |||
91 | try | ||
92 | { | ||
93 | m_smcm.RegisterScriptInvocation(this, "DummyTestMethod"); | ||
94 | } | ||
95 | catch (ArgumentException) | ||
96 | { | ||
97 | Assert.Ignore("Ignoring test since running on .NET 3.5 or earlier."); | ||
98 | } | ||
99 | |||
100 | // XXX: Unfortunately, ICommsModule currently has no way of deregistering methods. | ||
101 | } | ||
102 | |||
103 | private object InvokeOp(string name, params object[] args) | ||
104 | { | ||
105 | return InvokeOpOnHost(name, UUID.Zero, args); | ||
106 | } | ||
107 | |||
108 | private object InvokeOpOnHost(string name, UUID hostId, params object[] args) | ||
109 | { | ||
110 | return m_smcm.InvokeOperation(hostId, UUID.Zero, name, args); | ||
111 | } | ||
112 | |||
113 | [Test] | ||
114 | public void TestJsonCreateStore() | ||
115 | { | ||
116 | TestHelpers.InMethod(); | ||
117 | // TestHelpers.EnableLogging(); | ||
118 | |||
119 | // Test blank store | ||
120 | { | ||
121 | UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}"); | ||
122 | Assert.That(storeId, Is.Not.EqualTo(UUID.Zero)); | ||
123 | } | ||
124 | |||
125 | // Test single element store | ||
126 | { | ||
127 | UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : 'World' }"); | ||
128 | Assert.That(storeId, Is.Not.EqualTo(UUID.Zero)); | ||
129 | } | ||
130 | |||
131 | // Test with an integer value | ||
132 | { | ||
133 | UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : 42.15 }"); | ||
134 | Assert.That(storeId, Is.Not.EqualTo(UUID.Zero)); | ||
135 | |||
136 | string value = (string)InvokeOp("JsonGetValue", storeId, "Hello"); | ||
137 | Assert.That(value, Is.EqualTo("42.15")); | ||
138 | } | ||
139 | |||
140 | // Test with an array as the root node | ||
141 | { | ||
142 | UUID storeId = (UUID)InvokeOp("JsonCreateStore", "[ 'one', 'two', 'three' ]"); | ||
143 | Assert.That(storeId, Is.Not.EqualTo(UUID.Zero)); | ||
144 | |||
145 | string value = (string)InvokeOp("JsonGetValue", storeId, "[1]"); | ||
146 | Assert.That(value, Is.EqualTo("two")); | ||
147 | } | ||
148 | } | ||
149 | |||
150 | [Test] | ||
151 | public void TestJsonDestroyStore() | ||
152 | { | ||
153 | TestHelpers.InMethod(); | ||
154 | // TestHelpers.EnableLogging(); | ||
155 | |||
156 | UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : 'World' }"); | ||
157 | int dsrv = (int)InvokeOp("JsonDestroyStore", storeId); | ||
158 | |||
159 | Assert.That(dsrv, Is.EqualTo(1)); | ||
160 | |||
161 | int tprv = (int)InvokeOp("JsonGetNodeType", storeId, "Hello"); | ||
162 | Assert.That(tprv, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_UNDEF)); | ||
163 | } | ||
164 | |||
165 | [Test] | ||
166 | public void TestJsonDestroyStoreNotExists() | ||
167 | { | ||
168 | TestHelpers.InMethod(); | ||
169 | // TestHelpers.EnableLogging(); | ||
170 | |||
171 | UUID fakeStoreId = TestHelpers.ParseTail(0x500); | ||
172 | |||
173 | int dsrv = (int)InvokeOp("JsonDestroyStore", fakeStoreId); | ||
174 | |||
175 | Assert.That(dsrv, Is.EqualTo(0)); | ||
176 | } | ||
177 | |||
178 | [Test] | ||
179 | public void TestJsonGetValue() | ||
180 | { | ||
181 | TestHelpers.InMethod(); | ||
182 | // TestHelpers.EnableLogging(); | ||
183 | |||
184 | UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : 'Two' } }"); | ||
185 | |||
186 | { | ||
187 | string value = (string)InvokeOp("JsonGetValue", storeId, "Hello.World"); | ||
188 | Assert.That(value, Is.EqualTo("Two")); | ||
189 | } | ||
190 | |||
191 | // Test get of path section instead of leaf | ||
192 | { | ||
193 | string value = (string)InvokeOp("JsonGetValue", storeId, "Hello"); | ||
194 | Assert.That(value, Is.EqualTo("")); | ||
195 | } | ||
196 | |||
197 | // Test get of non-existing value | ||
198 | { | ||
199 | string fakeValueGet = (string)InvokeOp("JsonGetValue", storeId, "foo"); | ||
200 | Assert.That(fakeValueGet, Is.EqualTo("")); | ||
201 | } | ||
202 | |||
203 | // Test get from non-existing store | ||
204 | { | ||
205 | UUID fakeStoreId = TestHelpers.ParseTail(0x500); | ||
206 | string fakeStoreValueGet = (string)InvokeOp("JsonGetValue", fakeStoreId, "Hello"); | ||
207 | Assert.That(fakeStoreValueGet, Is.EqualTo("")); | ||
208 | } | ||
209 | } | ||
210 | |||
211 | [Test] | ||
212 | public void TestJsonGetJson() | ||
213 | { | ||
214 | TestHelpers.InMethod(); | ||
215 | // TestHelpers.EnableLogging(); | ||
216 | |||
217 | UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : 'Two' } }"); | ||
218 | |||
219 | { | ||
220 | string value = (string)InvokeOp("JsonGetJson", storeId, "Hello.World"); | ||
221 | Assert.That(value, Is.EqualTo("'Two'")); | ||
222 | } | ||
223 | |||
224 | // Test get of path section instead of leaf | ||
225 | { | ||
226 | string value = (string)InvokeOp("JsonGetJson", storeId, "Hello"); | ||
227 | Assert.That(value, Is.EqualTo("{\"World\":\"Two\"}")); | ||
228 | } | ||
229 | |||
230 | // Test get of non-existing value | ||
231 | { | ||
232 | string fakeValueGet = (string)InvokeOp("JsonGetJson", storeId, "foo"); | ||
233 | Assert.That(fakeValueGet, Is.EqualTo("")); | ||
234 | } | ||
235 | |||
236 | // Test get from non-existing store | ||
237 | { | ||
238 | UUID fakeStoreId = TestHelpers.ParseTail(0x500); | ||
239 | string fakeStoreValueGet = (string)InvokeOp("JsonGetJson", fakeStoreId, "Hello"); | ||
240 | Assert.That(fakeStoreValueGet, Is.EqualTo("")); | ||
241 | } | ||
242 | } | ||
243 | |||
244 | // [Test] | ||
245 | // public void TestJsonTakeValue() | ||
246 | // { | ||
247 | // TestHelpers.InMethod(); | ||
248 | //// TestHelpers.EnableLogging(); | ||
249 | // | ||
250 | // UUID storeId | ||
251 | // = (UUID)m_smcm.InvokeOperation( | ||
252 | // UUID.Zero, UUID.Zero, "JsonCreateStore", new object[] { "{ 'Hello' : 'World' }" }); | ||
253 | // | ||
254 | // string value | ||
255 | // = (string)m_smcm.InvokeOperation( | ||
256 | // UUID.Zero, UUID.Zero, "JsonTakeValue", new object[] { storeId, "Hello" }); | ||
257 | // | ||
258 | // Assert.That(value, Is.EqualTo("World")); | ||
259 | // | ||
260 | // string value2 | ||
261 | // = (string)m_smcm.InvokeOperation( | ||
262 | // UUID.Zero, UUID.Zero, "JsonGetValue", new object[] { storeId, "Hello" }); | ||
263 | // | ||
264 | // Assert.That(value, Is.Null); | ||
265 | // } | ||
266 | |||
267 | [Test] | ||
268 | public void TestJsonRemoveValue() | ||
269 | { | ||
270 | TestHelpers.InMethod(); | ||
271 | // TestHelpers.EnableLogging(); | ||
272 | |||
273 | // Test remove of node in object pointing to a string | ||
274 | { | ||
275 | UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : 'World' }"); | ||
276 | |||
277 | int returnValue = (int)InvokeOp( "JsonRemoveValue", storeId, "Hello"); | ||
278 | Assert.That(returnValue, Is.EqualTo(1)); | ||
279 | |||
280 | int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello"); | ||
281 | Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_UNDEF)); | ||
282 | |||
283 | string returnValue2 = (string)InvokeOp("JsonGetValue", storeId, "Hello"); | ||
284 | Assert.That(returnValue2, Is.EqualTo("")); | ||
285 | } | ||
286 | |||
287 | // Test remove of node in object pointing to another object | ||
288 | { | ||
289 | UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : 'Wally' } }"); | ||
290 | |||
291 | int returnValue = (int)InvokeOp( "JsonRemoveValue", storeId, "Hello"); | ||
292 | Assert.That(returnValue, Is.EqualTo(1)); | ||
293 | |||
294 | int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello"); | ||
295 | Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_UNDEF)); | ||
296 | |||
297 | string returnValue2 = (string)InvokeOp("JsonGetJson", storeId, "Hello"); | ||
298 | Assert.That(returnValue2, Is.EqualTo("")); | ||
299 | } | ||
300 | |||
301 | // Test remove of node in an array | ||
302 | { | ||
303 | UUID storeId | ||
304 | = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : [ 'value1', 'value2' ] }"); | ||
305 | |||
306 | int returnValue = (int)InvokeOp( "JsonRemoveValue", storeId, "Hello[0]"); | ||
307 | Assert.That(returnValue, Is.EqualTo(1)); | ||
308 | |||
309 | int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello[0]"); | ||
310 | Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_VALUE)); | ||
311 | |||
312 | result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello[1]"); | ||
313 | Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_UNDEF)); | ||
314 | |||
315 | string stringReturnValue = (string)InvokeOp("JsonGetValue", storeId, "Hello[0]"); | ||
316 | Assert.That(stringReturnValue, Is.EqualTo("value2")); | ||
317 | |||
318 | stringReturnValue = (string)InvokeOp("JsonGetJson", storeId, "Hello[1]"); | ||
319 | Assert.That(stringReturnValue, Is.EqualTo("")); | ||
320 | } | ||
321 | |||
322 | // Test remove of non-existing value | ||
323 | { | ||
324 | UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : 'World' }"); | ||
325 | |||
326 | int fakeValueRemove = (int)InvokeOp("JsonRemoveValue", storeId, "Cheese"); | ||
327 | Assert.That(fakeValueRemove, Is.EqualTo(0)); | ||
328 | } | ||
329 | |||
330 | { | ||
331 | // Test get from non-existing store | ||
332 | UUID fakeStoreId = TestHelpers.ParseTail(0x500); | ||
333 | int fakeStoreValueRemove = (int)InvokeOp("JsonRemoveValue", fakeStoreId, "Hello"); | ||
334 | Assert.That(fakeStoreValueRemove, Is.EqualTo(0)); | ||
335 | } | ||
336 | } | ||
337 | |||
338 | // [Test] | ||
339 | // public void TestJsonTestPath() | ||
340 | // { | ||
341 | // TestHelpers.InMethod(); | ||
342 | //// TestHelpers.EnableLogging(); | ||
343 | // | ||
344 | // UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : 'One' } }"); | ||
345 | // | ||
346 | // { | ||
347 | // int result = (int)InvokeOp("JsonTestPath", storeId, "Hello.World"); | ||
348 | // Assert.That(result, Is.EqualTo(1)); | ||
349 | // } | ||
350 | // | ||
351 | // // Test for path which does not resolve to a value. | ||
352 | // { | ||
353 | // int result = (int)InvokeOp("JsonTestPath", storeId, "Hello"); | ||
354 | // Assert.That(result, Is.EqualTo(0)); | ||
355 | // } | ||
356 | // | ||
357 | // { | ||
358 | // int result2 = (int)InvokeOp("JsonTestPath", storeId, "foo"); | ||
359 | // Assert.That(result2, Is.EqualTo(0)); | ||
360 | // } | ||
361 | // | ||
362 | // // Test with fake store | ||
363 | // { | ||
364 | // UUID fakeStoreId = TestHelpers.ParseTail(0x500); | ||
365 | // int fakeStoreValueRemove = (int)InvokeOp("JsonTestPath", fakeStoreId, "Hello"); | ||
366 | // Assert.That(fakeStoreValueRemove, Is.EqualTo(0)); | ||
367 | // } | ||
368 | // } | ||
369 | |||
370 | // [Test] | ||
371 | // public void TestJsonTestPathJson() | ||
372 | // { | ||
373 | // TestHelpers.InMethod(); | ||
374 | //// TestHelpers.EnableLogging(); | ||
375 | // | ||
376 | // UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : 'One' } }"); | ||
377 | // | ||
378 | // { | ||
379 | // int result = (int)InvokeOp("JsonTestPathJson", storeId, "Hello.World"); | ||
380 | // Assert.That(result, Is.EqualTo(1)); | ||
381 | // } | ||
382 | // | ||
383 | // // Test for path which does not resolve to a value. | ||
384 | // { | ||
385 | // int result = (int)InvokeOp("JsonTestPathJson", storeId, "Hello"); | ||
386 | // Assert.That(result, Is.EqualTo(1)); | ||
387 | // } | ||
388 | // | ||
389 | // { | ||
390 | // int result2 = (int)InvokeOp("JsonTestPathJson", storeId, "foo"); | ||
391 | // Assert.That(result2, Is.EqualTo(0)); | ||
392 | // } | ||
393 | // | ||
394 | // // Test with fake store | ||
395 | // { | ||
396 | // UUID fakeStoreId = TestHelpers.ParseTail(0x500); | ||
397 | // int fakeStoreValueRemove = (int)InvokeOp("JsonTestPathJson", fakeStoreId, "Hello"); | ||
398 | // Assert.That(fakeStoreValueRemove, Is.EqualTo(0)); | ||
399 | // } | ||
400 | // } | ||
401 | |||
402 | [Test] | ||
403 | public void TestJsonGetArrayLength() | ||
404 | { | ||
405 | TestHelpers.InMethod(); | ||
406 | // TestHelpers.EnableLogging(); | ||
407 | |||
408 | UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : [ 'one', 2 ] } }"); | ||
409 | |||
410 | { | ||
411 | int result = (int)InvokeOp("JsonGetArrayLength", storeId, "Hello.World"); | ||
412 | Assert.That(result, Is.EqualTo(2)); | ||
413 | } | ||
414 | |||
415 | // Test path which is not an array | ||
416 | { | ||
417 | int result = (int)InvokeOp("JsonGetArrayLength", storeId, "Hello"); | ||
418 | Assert.That(result, Is.EqualTo(-1)); | ||
419 | } | ||
420 | |||
421 | // Test fake path | ||
422 | { | ||
423 | int result = (int)InvokeOp("JsonGetArrayLength", storeId, "foo"); | ||
424 | Assert.That(result, Is.EqualTo(-1)); | ||
425 | } | ||
426 | |||
427 | // Test fake store | ||
428 | { | ||
429 | UUID fakeStoreId = TestHelpers.ParseTail(0x500); | ||
430 | int result = (int)InvokeOp("JsonGetArrayLength", fakeStoreId, "Hello.World"); | ||
431 | Assert.That(result, Is.EqualTo(-1)); | ||
432 | } | ||
433 | } | ||
434 | |||
435 | [Test] | ||
436 | public void TestJsonGetNodeType() | ||
437 | { | ||
438 | TestHelpers.InMethod(); | ||
439 | // TestHelpers.EnableLogging(); | ||
440 | |||
441 | UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : [ 'one', 2 ] } }"); | ||
442 | |||
443 | { | ||
444 | int result = (int)InvokeOp("JsonGetNodeType", storeId, "."); | ||
445 | Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_OBJECT)); | ||
446 | } | ||
447 | |||
448 | { | ||
449 | int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello"); | ||
450 | Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_OBJECT)); | ||
451 | } | ||
452 | |||
453 | { | ||
454 | int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello.World"); | ||
455 | Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_ARRAY)); | ||
456 | } | ||
457 | |||
458 | { | ||
459 | int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello.World[0]"); | ||
460 | Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_VALUE)); | ||
461 | } | ||
462 | |||
463 | { | ||
464 | int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello.World[1]"); | ||
465 | Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_VALUE)); | ||
466 | } | ||
467 | |||
468 | // Test for non-existant path | ||
469 | { | ||
470 | int result = (int)InvokeOp("JsonGetNodeType", storeId, "foo"); | ||
471 | Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_UNDEF)); | ||
472 | } | ||
473 | |||
474 | // Test for non-existant store | ||
475 | { | ||
476 | UUID fakeStoreId = TestHelpers.ParseTail(0x500); | ||
477 | int result = (int)InvokeOp("JsonGetNodeType", fakeStoreId, "."); | ||
478 | Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_UNDEF)); | ||
479 | } | ||
480 | } | ||
481 | |||
482 | [Test] | ||
483 | public void TestJsonList2Path() | ||
484 | { | ||
485 | TestHelpers.InMethod(); | ||
486 | // TestHelpers.EnableLogging(); | ||
487 | |||
488 | // Invoking these methods directly since I just couldn't get comms module invocation to work for some reason | ||
489 | // - some confusion with the methods that take a params object[] invocation. | ||
490 | { | ||
491 | string result = m_jssm.JsonList2Path(UUID.Zero, UUID.Zero, new object[] { "foo" }); | ||
492 | Assert.That(result, Is.EqualTo("{foo}")); | ||
493 | } | ||
494 | |||
495 | { | ||
496 | string result = m_jssm.JsonList2Path(UUID.Zero, UUID.Zero, new object[] { "foo", "bar" }); | ||
497 | Assert.That(result, Is.EqualTo("{foo}.{bar}")); | ||
498 | } | ||
499 | |||
500 | { | ||
501 | string result = m_jssm.JsonList2Path(UUID.Zero, UUID.Zero, new object[] { "foo", 1, "bar" }); | ||
502 | Assert.That(result, Is.EqualTo("{foo}.[1].{bar}")); | ||
503 | } | ||
504 | } | ||
505 | |||
506 | [Test] | ||
507 | public void TestJsonSetValue() | ||
508 | { | ||
509 | TestHelpers.InMethod(); | ||
510 | // TestHelpers.EnableLogging(); | ||
511 | |||
512 | { | ||
513 | UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}"); | ||
514 | |||
515 | int result = (int)InvokeOp("JsonSetValue", storeId, "Fun", "Times"); | ||
516 | Assert.That(result, Is.EqualTo(1)); | ||
517 | |||
518 | string value = (string)InvokeOp("JsonGetValue", storeId, "Fun"); | ||
519 | Assert.That(value, Is.EqualTo("Times")); | ||
520 | } | ||
521 | |||
522 | // Test setting a key containing periods with delineation | ||
523 | { | ||
524 | UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}"); | ||
525 | |||
526 | int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun.Circus}", "Times"); | ||
527 | Assert.That(result, Is.EqualTo(1)); | ||
528 | |||
529 | string value = (string)InvokeOp("JsonGetValue", storeId, "{Fun.Circus}"); | ||
530 | Assert.That(value, Is.EqualTo("Times")); | ||
531 | } | ||
532 | |||
533 | // *** Test [] *** | ||
534 | |||
535 | // Test setting a key containing unbalanced ] without delineation. Expecting failure | ||
536 | { | ||
537 | UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}"); | ||
538 | |||
539 | int result = (int)InvokeOp("JsonSetValue", storeId, "Fun]Circus", "Times"); | ||
540 | Assert.That(result, Is.EqualTo(0)); | ||
541 | |||
542 | string value = (string)InvokeOp("JsonGetValue", storeId, "Fun]Circus"); | ||
543 | Assert.That(value, Is.EqualTo("")); | ||
544 | } | ||
545 | |||
546 | // Test setting a key containing unbalanced [ without delineation. Expecting failure | ||
547 | { | ||
548 | UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}"); | ||
549 | |||
550 | int result = (int)InvokeOp("JsonSetValue", storeId, "Fun[Circus", "Times"); | ||
551 | Assert.That(result, Is.EqualTo(0)); | ||
552 | |||
553 | string value = (string)InvokeOp("JsonGetValue", storeId, "Fun[Circus"); | ||
554 | Assert.That(value, Is.EqualTo("")); | ||
555 | } | ||
556 | |||
557 | // Test setting a key containing unbalanced [] without delineation. Expecting failure | ||
558 | { | ||
559 | UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}"); | ||
560 | |||
561 | int result = (int)InvokeOp("JsonSetValue", storeId, "Fun[]Circus", "Times"); | ||
562 | Assert.That(result, Is.EqualTo(0)); | ||
563 | |||
564 | string value = (string)InvokeOp("JsonGetValue", storeId, "Fun[]Circus"); | ||
565 | Assert.That(value, Is.EqualTo("")); | ||
566 | } | ||
567 | |||
568 | // Test setting a key containing unbalanced ] with delineation | ||
569 | { | ||
570 | UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}"); | ||
571 | |||
572 | int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun]Circus}", "Times"); | ||
573 | Assert.That(result, Is.EqualTo(1)); | ||
574 | |||
575 | string value = (string)InvokeOp("JsonGetValue", storeId, "{Fun]Circus}"); | ||
576 | Assert.That(value, Is.EqualTo("Times")); | ||
577 | } | ||
578 | |||
579 | // Test setting a key containing unbalanced [ with delineation | ||
580 | { | ||
581 | UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}"); | ||
582 | |||
583 | int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun[Circus}", "Times"); | ||
584 | Assert.That(result, Is.EqualTo(1)); | ||
585 | |||
586 | string value = (string)InvokeOp("JsonGetValue", storeId, "{Fun[Circus}"); | ||
587 | Assert.That(value, Is.EqualTo("Times")); | ||
588 | } | ||
589 | |||
590 | // Test setting a key containing empty balanced [] with delineation | ||
591 | { | ||
592 | UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}"); | ||
593 | |||
594 | int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun[]Circus}", "Times"); | ||
595 | Assert.That(result, Is.EqualTo(1)); | ||
596 | |||
597 | string value = (string)InvokeOp("JsonGetValue", storeId, "{Fun[]Circus}"); | ||
598 | Assert.That(value, Is.EqualTo("Times")); | ||
599 | } | ||
600 | |||
601 | // // Commented out as this currently unexpectedly fails. | ||
602 | // // Test setting a key containing brackets around an integer with delineation | ||
603 | // { | ||
604 | // UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}"); | ||
605 | // | ||
606 | // int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun[0]Circus}", "Times"); | ||
607 | // Assert.That(result, Is.EqualTo(1)); | ||
608 | // | ||
609 | // string value = (string)InvokeOp("JsonGetValue", storeId, "{Fun[0]Circus}"); | ||
610 | // Assert.That(value, Is.EqualTo("Times")); | ||
611 | // } | ||
612 | |||
613 | // *** Test {} *** | ||
614 | |||
615 | // Test setting a key containing unbalanced } without delineation. Expecting failure (?) | ||
616 | { | ||
617 | UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}"); | ||
618 | |||
619 | int result = (int)InvokeOp("JsonSetValue", storeId, "Fun}Circus", "Times"); | ||
620 | Assert.That(result, Is.EqualTo(0)); | ||
621 | |||
622 | string value = (string)InvokeOp("JsonGetValue", storeId, "Fun}Circus"); | ||
623 | Assert.That(value, Is.EqualTo("")); | ||
624 | } | ||
625 | |||
626 | // Test setting a key containing unbalanced { without delineation. Expecting failure (?) | ||
627 | { | ||
628 | UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}"); | ||
629 | |||
630 | int result = (int)InvokeOp("JsonSetValue", storeId, "Fun{Circus", "Times"); | ||
631 | Assert.That(result, Is.EqualTo(0)); | ||
632 | |||
633 | string value = (string)InvokeOp("JsonGetValue", storeId, "Fun}Circus"); | ||
634 | Assert.That(value, Is.EqualTo("")); | ||
635 | } | ||
636 | |||
637 | // // Commented out as this currently unexpectedly fails. | ||
638 | // // Test setting a key containing unbalanced } | ||
639 | // { | ||
640 | // UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}"); | ||
641 | // | ||
642 | // int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun}Circus}", "Times"); | ||
643 | // Assert.That(result, Is.EqualTo(0)); | ||
644 | // } | ||
645 | |||
646 | // Test setting a key containing unbalanced { with delineation | ||
647 | { | ||
648 | UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}"); | ||
649 | |||
650 | int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun{Circus}", "Times"); | ||
651 | Assert.That(result, Is.EqualTo(1)); | ||
652 | |||
653 | string value = (string)InvokeOp("JsonGetValue", storeId, "{Fun{Circus}"); | ||
654 | Assert.That(value, Is.EqualTo("Times")); | ||
655 | } | ||
656 | |||
657 | // Test setting a key containing balanced {} with delineation. This should fail. | ||
658 | { | ||
659 | UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}"); | ||
660 | |||
661 | int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun{Filled}Circus}", "Times"); | ||
662 | Assert.That(result, Is.EqualTo(0)); | ||
663 | |||
664 | string value = (string)InvokeOp("JsonGetValue", storeId, "{Fun{Filled}Circus}"); | ||
665 | Assert.That(value, Is.EqualTo("")); | ||
666 | } | ||
667 | |||
668 | // Test setting to location that does not exist. This should fail. | ||
669 | { | ||
670 | UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}"); | ||
671 | |||
672 | int result = (int)InvokeOp("JsonSetValue", storeId, "Fun.Circus", "Times"); | ||
673 | Assert.That(result, Is.EqualTo(0)); | ||
674 | |||
675 | string value = (string)InvokeOp("JsonGetValue", storeId, "Fun.Circus"); | ||
676 | Assert.That(value, Is.EqualTo("")); | ||
677 | } | ||
678 | |||
679 | // Test with fake store | ||
680 | { | ||
681 | UUID fakeStoreId = TestHelpers.ParseTail(0x500); | ||
682 | int fakeStoreValueSet = (int)InvokeOp("JsonSetValue", fakeStoreId, "Hello", "World"); | ||
683 | Assert.That(fakeStoreValueSet, Is.EqualTo(0)); | ||
684 | } | ||
685 | } | ||
686 | |||
687 | [Test] | ||
688 | public void TestJsonSetJson() | ||
689 | { | ||
690 | TestHelpers.InMethod(); | ||
691 | // TestHelpers.EnableLogging(); | ||
692 | |||
693 | // Single quoted token case | ||
694 | { | ||
695 | UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ }"); | ||
696 | |||
697 | int result = (int)InvokeOp("JsonSetJson", storeId, "Fun", "'Times'"); | ||
698 | Assert.That(result, Is.EqualTo(1)); | ||
699 | |||
700 | string value = (string)InvokeOp("JsonGetValue", storeId, "Fun"); | ||
701 | Assert.That(value, Is.EqualTo("Times")); | ||
702 | } | ||
703 | |||
704 | // Sub-tree case | ||
705 | { | ||
706 | UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ }"); | ||
707 | |||
708 | int result = (int)InvokeOp("JsonSetJson", storeId, "Fun", "{ 'Filled' : 'Times' }"); | ||
709 | Assert.That(result, Is.EqualTo(1)); | ||
710 | |||
711 | string value = (string)InvokeOp("JsonGetValue", storeId, "Fun.Filled"); | ||
712 | Assert.That(value, Is.EqualTo("Times")); | ||
713 | } | ||
714 | |||
715 | // If setting single strings in JsonSetValueJson, these must be single quoted tokens, not bare strings. | ||
716 | { | ||
717 | UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ }"); | ||
718 | |||
719 | int result = (int)InvokeOp("JsonSetJson", storeId, "Fun", "Times"); | ||
720 | Assert.That(result, Is.EqualTo(0)); | ||
721 | |||
722 | string value = (string)InvokeOp("JsonGetValue", storeId, "Fun"); | ||
723 | Assert.That(value, Is.EqualTo("")); | ||
724 | } | ||
725 | |||
726 | // Test setting to location that does not exist. This should fail. | ||
727 | { | ||
728 | UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ }"); | ||
729 | |||
730 | int result = (int)InvokeOp("JsonSetJson", storeId, "Fun.Circus", "'Times'"); | ||
731 | Assert.That(result, Is.EqualTo(0)); | ||
732 | |||
733 | string value = (string)InvokeOp("JsonGetValue", storeId, "Fun.Circus"); | ||
734 | Assert.That(value, Is.EqualTo("")); | ||
735 | } | ||
736 | |||
737 | // Test with fake store | ||
738 | { | ||
739 | UUID fakeStoreId = TestHelpers.ParseTail(0x500); | ||
740 | int fakeStoreValueSet = (int)InvokeOp("JsonSetJson", fakeStoreId, "Hello", "'World'"); | ||
741 | Assert.That(fakeStoreValueSet, Is.EqualTo(0)); | ||
742 | } | ||
743 | } | ||
744 | |||
745 | /// <summary> | ||
746 | /// Test for writing json to a notecard | ||
747 | /// </summary> | ||
748 | /// <remarks> | ||
749 | /// TODO: Really needs to test correct receipt of the link_message event. Could do this by directly fetching | ||
750 | /// it via the MockScriptEngine or perhaps by a dummy script instance. | ||
751 | /// </remarks> | ||
752 | [Test] | ||
753 | public void TestJsonWriteNotecard() | ||
754 | { | ||
755 | TestHelpers.InMethod(); | ||
756 | // TestHelpers.EnableLogging(); | ||
757 | |||
758 | SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, TestHelpers.ParseTail(0x1)); | ||
759 | m_scene.AddSceneObject(so); | ||
760 | |||
761 | UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello':'World' }"); | ||
762 | |||
763 | { | ||
764 | string notecardName = "nc1"; | ||
765 | |||
766 | // Write notecard | ||
767 | UUID writeNotecardRequestId = (UUID)InvokeOpOnHost("JsonWriteNotecard", so.UUID, storeId, "", notecardName); | ||
768 | Assert.That(writeNotecardRequestId, Is.Not.EqualTo(UUID.Zero)); | ||
769 | |||
770 | TaskInventoryItem nc1Item = so.RootPart.Inventory.GetInventoryItem(notecardName); | ||
771 | Assert.That(nc1Item, Is.Not.Null); | ||
772 | |||
773 | // TODO: Should independently check the contents. | ||
774 | } | ||
775 | |||
776 | // TODO: Write partial test | ||
777 | |||
778 | { | ||
779 | // Try to write notecard for a bad path | ||
780 | // In this case we do get a request id but no notecard is written. | ||
781 | string badPathNotecardName = "badPathNotecardName"; | ||
782 | |||
783 | UUID writeNotecardBadPathRequestId | ||
784 | = (UUID)InvokeOpOnHost("JsonWriteNotecard", so.UUID, storeId, "flibble", badPathNotecardName); | ||
785 | Assert.That(writeNotecardBadPathRequestId, Is.Not.EqualTo(UUID.Zero)); | ||
786 | |||
787 | TaskInventoryItem badPathItem = so.RootPart.Inventory.GetInventoryItem(badPathNotecardName); | ||
788 | Assert.That(badPathItem, Is.Null); | ||
789 | } | ||
790 | |||
791 | { | ||
792 | // Test with fake store | ||
793 | // In this case we do get a request id but no notecard is written. | ||
794 | string fakeStoreNotecardName = "fakeStoreNotecardName"; | ||
795 | |||
796 | UUID fakeStoreId = TestHelpers.ParseTail(0x500); | ||
797 | UUID fakeStoreWriteNotecardValue | ||
798 | = (UUID)InvokeOpOnHost("JsonWriteNotecard", so.UUID, fakeStoreId, "", fakeStoreNotecardName); | ||
799 | Assert.That(fakeStoreWriteNotecardValue, Is.Not.EqualTo(UUID.Zero)); | ||
800 | |||
801 | TaskInventoryItem fakeStoreItem = so.RootPart.Inventory.GetInventoryItem(fakeStoreNotecardName); | ||
802 | Assert.That(fakeStoreItem, Is.Null); | ||
803 | } | ||
804 | } | ||
805 | |||
806 | /// <summary> | ||
807 | /// Test for reading json from a notecard | ||
808 | /// </summary> | ||
809 | /// <remarks> | ||
810 | /// TODO: Really needs to test correct receipt of the link_message event. Could do this by directly fetching | ||
811 | /// it via the MockScriptEngine or perhaps by a dummy script instance. | ||
812 | /// </remarks> | ||
813 | [Test] | ||
814 | public void TestJsonReadNotecard() | ||
815 | { | ||
816 | TestHelpers.InMethod(); | ||
817 | // TestHelpers.EnableLogging(); | ||
818 | |||
819 | string notecardName = "nc1"; | ||
820 | |||
821 | SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, TestHelpers.ParseTail(0x1)); | ||
822 | m_scene.AddSceneObject(so); | ||
823 | |||
824 | UUID creatingStoreId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello':'World' }"); | ||
825 | |||
826 | // Write notecard | ||
827 | InvokeOpOnHost("JsonWriteNotecard", so.UUID, creatingStoreId, "", notecardName); | ||
828 | |||
829 | { | ||
830 | // Read notecard | ||
831 | UUID receivingStoreId = (UUID)InvokeOp("JsonCreateStore", "{}"); | ||
832 | UUID readNotecardRequestId = (UUID)InvokeOpOnHost("JsonReadNotecard", so.UUID, receivingStoreId, "", notecardName); | ||
833 | Assert.That(readNotecardRequestId, Is.Not.EqualTo(UUID.Zero)); | ||
834 | |||
835 | string value = (string)InvokeOp("JsonGetValue", receivingStoreId, "Hello"); | ||
836 | Assert.That(value, Is.EqualTo("World")); | ||
837 | } | ||
838 | |||
839 | { | ||
840 | // Read notecard to new single component path | ||
841 | UUID receivingStoreId = (UUID)InvokeOp("JsonCreateStore", "{}"); | ||
842 | UUID readNotecardRequestId = (UUID)InvokeOpOnHost("JsonReadNotecard", so.UUID, receivingStoreId, "make", notecardName); | ||
843 | Assert.That(readNotecardRequestId, Is.Not.EqualTo(UUID.Zero)); | ||
844 | |||
845 | string value = (string)InvokeOp("JsonGetValue", receivingStoreId, "Hello"); | ||
846 | Assert.That(value, Is.EqualTo("")); | ||
847 | |||
848 | value = (string)InvokeOp("JsonGetValue", receivingStoreId, "make.Hello"); | ||
849 | Assert.That(value, Is.EqualTo("World")); | ||
850 | } | ||
851 | |||
852 | { | ||
853 | // Read notecard to new multi-component path. This should not work. | ||
854 | UUID receivingStoreId = (UUID)InvokeOp("JsonCreateStore", "{}"); | ||
855 | UUID readNotecardRequestId = (UUID)InvokeOpOnHost("JsonReadNotecard", so.UUID, receivingStoreId, "make.it", notecardName); | ||
856 | Assert.That(readNotecardRequestId, Is.Not.EqualTo(UUID.Zero)); | ||
857 | |||
858 | string value = (string)InvokeOp("JsonGetValue", receivingStoreId, "Hello"); | ||
859 | Assert.That(value, Is.EqualTo("")); | ||
860 | |||
861 | value = (string)InvokeOp("JsonGetValue", receivingStoreId, "make.it.Hello"); | ||
862 | Assert.That(value, Is.EqualTo("")); | ||
863 | } | ||
864 | |||
865 | { | ||
866 | // Read notecard to existing multi-component path. This should work | ||
867 | UUID receivingStoreId = (UUID)InvokeOp("JsonCreateStore", "{ 'make' : { 'it' : 'so' } }"); | ||
868 | UUID readNotecardRequestId = (UUID)InvokeOpOnHost("JsonReadNotecard", so.UUID, receivingStoreId, "make.it", notecardName); | ||
869 | Assert.That(readNotecardRequestId, Is.Not.EqualTo(UUID.Zero)); | ||
870 | |||
871 | string value = (string)InvokeOp("JsonGetValue", receivingStoreId, "Hello"); | ||
872 | Assert.That(value, Is.EqualTo("")); | ||
873 | |||
874 | value = (string)InvokeOp("JsonGetValue", receivingStoreId, "make.it.Hello"); | ||
875 | Assert.That(value, Is.EqualTo("World")); | ||
876 | } | ||
877 | |||
878 | { | ||
879 | // Read notecard to invalid path. This should not work. | ||
880 | UUID receivingStoreId = (UUID)InvokeOp("JsonCreateStore", "{ 'make' : { 'it' : 'so' } }"); | ||
881 | UUID readNotecardRequestId = (UUID)InvokeOpOnHost("JsonReadNotecard", so.UUID, receivingStoreId, "/", notecardName); | ||
882 | Assert.That(readNotecardRequestId, Is.Not.EqualTo(UUID.Zero)); | ||
883 | |||
884 | string value = (string)InvokeOp("JsonGetValue", receivingStoreId, "Hello"); | ||
885 | Assert.That(value, Is.EqualTo("")); | ||
886 | } | ||
887 | |||
888 | { | ||
889 | // Try read notecard to fake store. | ||
890 | UUID fakeStoreId = TestHelpers.ParseTail(0x500); | ||
891 | UUID readNotecardRequestId = (UUID)InvokeOpOnHost("JsonReadNotecard", so.UUID, fakeStoreId, "", notecardName); | ||
892 | Assert.That(readNotecardRequestId, Is.Not.EqualTo(UUID.Zero)); | ||
893 | |||
894 | string value = (string)InvokeOp("JsonGetValue", fakeStoreId, "Hello"); | ||
895 | Assert.That(value, Is.EqualTo("")); | ||
896 | } | ||
897 | } | ||
898 | |||
899 | public object DummyTestMethod(object o1, object o2, object o3, object o4, object o5) { return null; } | ||
900 | } | ||
901 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcGridRouterModule.cs b/OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcGridRouterModule.cs index 6120a81..709d389 100644 --- a/OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcGridRouterModule.cs +++ b/OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcGridRouterModule.cs | |||
@@ -46,6 +46,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.XmlRpcGridRouterModule | |||
46 | { | 46 | { |
47 | public class XmlRpcInfo | 47 | public class XmlRpcInfo |
48 | { | 48 | { |
49 | public UUID item; | ||
49 | public UUID channel; | 50 | public UUID channel; |
50 | public string uri; | 51 | public string uri; |
51 | } | 52 | } |
@@ -88,6 +89,14 @@ namespace OpenSim.Region.OptionalModules.Scripting.XmlRpcGridRouterModule | |||
88 | return; | 89 | return; |
89 | 90 | ||
90 | scene.RegisterModuleInterface<IXmlRpcRouter>(this); | 91 | scene.RegisterModuleInterface<IXmlRpcRouter>(this); |
92 | |||
93 | IScriptModule scriptEngine = scene.RequestModuleInterface<IScriptModule>(); | ||
94 | if ( scriptEngine != null ) | ||
95 | { | ||
96 | scriptEngine.OnScriptRemoved += this.ScriptRemoved; | ||
97 | scriptEngine.OnObjectRemoved += this.ObjectRemoved; | ||
98 | |||
99 | } | ||
91 | } | 100 | } |
92 | 101 | ||
93 | public void RegionLoaded(Scene scene) | 102 | public void RegionLoaded(Scene scene) |
@@ -120,22 +129,36 @@ namespace OpenSim.Region.OptionalModules.Scripting.XmlRpcGridRouterModule | |||
120 | 129 | ||
121 | public void RegisterNewReceiver(IScriptModule scriptEngine, UUID channel, UUID objectID, UUID itemID, string uri) | 130 | public void RegisterNewReceiver(IScriptModule scriptEngine, UUID channel, UUID objectID, UUID itemID, string uri) |
122 | { | 131 | { |
123 | if (!m_Channels.ContainsKey(itemID)) | 132 | if (!m_Enabled) |
124 | { | 133 | return; |
125 | XmlRpcInfo info = new XmlRpcInfo(); | ||
126 | info.channel = channel; | ||
127 | info.uri = uri; | ||
128 | 134 | ||
129 | bool success = SynchronousRestObjectRequester.MakeRequest<XmlRpcInfo, bool>( | 135 | m_log.InfoFormat("[XMLRPC GRID ROUTER]: New receiver Obj: {0} Ch: {1} ID: {2} URI: {3}", |
130 | "POST", m_ServerURI+"/RegisterChannel/", info); | 136 | objectID.ToString(), channel.ToString(), itemID.ToString(), uri); |
131 | 137 | ||
132 | if (!success) | 138 | XmlRpcInfo info = new XmlRpcInfo(); |
133 | { | 139 | info.channel = channel; |
134 | m_log.Error("[XMLRPC GRID ROUTER] Error contacting server"); | 140 | info.uri = uri; |
135 | } | 141 | info.item = itemID; |
142 | |||
143 | bool success = SynchronousRestObjectRequester.MakeRequest<XmlRpcInfo, bool>( | ||
144 | "POST", m_ServerURI+"/RegisterChannel/", info); | ||
136 | 145 | ||
137 | m_Channels[itemID] = channel; | 146 | if (!success) |
147 | { | ||
148 | m_log.Error("[XMLRPC GRID ROUTER] Error contacting server"); | ||
138 | } | 149 | } |
150 | |||
151 | m_Channels[itemID] = channel; | ||
152 | |||
153 | } | ||
154 | |||
155 | public void UnRegisterReceiver(string channelID, UUID itemID) | ||
156 | { | ||
157 | if (!m_Enabled) | ||
158 | return; | ||
159 | |||
160 | RemoveChannel(itemID); | ||
161 | |||
139 | } | 162 | } |
140 | 163 | ||
141 | public void ScriptRemoved(UUID itemID) | 164 | public void ScriptRemoved(UUID itemID) |
@@ -143,10 +166,33 @@ namespace OpenSim.Region.OptionalModules.Scripting.XmlRpcGridRouterModule | |||
143 | if (!m_Enabled) | 166 | if (!m_Enabled) |
144 | return; | 167 | return; |
145 | 168 | ||
146 | if (m_Channels.ContainsKey(itemID)) | 169 | RemoveChannel(itemID); |
170 | |||
171 | } | ||
172 | |||
173 | public void ObjectRemoved(UUID objectID) | ||
174 | { | ||
175 | // m_log.InfoFormat("[XMLRPC GRID ROUTER]: Object Removed {0}",objectID.ToString()); | ||
176 | } | ||
177 | |||
178 | private bool RemoveChannel(UUID itemID) | ||
179 | { | ||
180 | if(!m_Channels.ContainsKey(itemID)) | ||
181 | { | ||
182 | m_log.InfoFormat("[XMLRPC GRID ROUTER]: Attempted to unregister non-existing Item: {0}", itemID.ToString()); | ||
183 | return false; | ||
184 | } | ||
185 | |||
186 | XmlRpcInfo info = new XmlRpcInfo(); | ||
187 | |||
188 | info.channel = m_Channels[itemID]; | ||
189 | info.item = itemID; | ||
190 | info.uri = "http://0.0.0.0:00"; | ||
191 | |||
192 | if (info != null) | ||
147 | { | 193 | { |
148 | bool success = SynchronousRestObjectRequester.MakeRequest<UUID, bool>( | 194 | bool success = SynchronousRestObjectRequester.MakeRequest<XmlRpcInfo, bool>( |
149 | "POST", m_ServerURI+"/RemoveChannel/", m_Channels[itemID]); | 195 | "POST", m_ServerURI+"/RemoveChannel/", info); |
150 | 196 | ||
151 | if (!success) | 197 | if (!success) |
152 | { | 198 | { |
@@ -154,11 +200,9 @@ namespace OpenSim.Region.OptionalModules.Scripting.XmlRpcGridRouterModule | |||
154 | } | 200 | } |
155 | 201 | ||
156 | m_Channels.Remove(itemID); | 202 | m_Channels.Remove(itemID); |
203 | return true; | ||
157 | } | 204 | } |
158 | } | 205 | return false; |
159 | |||
160 | public void ObjectRemoved(UUID objectID) | ||
161 | { | ||
162 | } | 206 | } |
163 | } | 207 | } |
164 | } | 208 | } |
diff --git a/OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcRouterModule.cs b/OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcRouterModule.cs index 4bde52a..32549d6 100644 --- a/OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcRouterModule.cs +++ b/OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcRouterModule.cs | |||
@@ -104,12 +104,18 @@ namespace OpenSim.Region.OptionalModules.Scripting.XmlRpcRouterModule | |||
104 | } | 104 | } |
105 | } | 105 | } |
106 | 106 | ||
107 | public void UnRegisterReceiver(string channelID, UUID itemID) | ||
108 | { | ||
109 | } | ||
110 | |||
107 | public void ScriptRemoved(UUID itemID) | 111 | public void ScriptRemoved(UUID itemID) |
108 | { | 112 | { |
113 | // System.Console.WriteLine("TEST Script Removed!"); | ||
109 | } | 114 | } |
110 | 115 | ||
111 | public void ObjectRemoved(UUID objectID) | 116 | public void ObjectRemoved(UUID objectID) |
112 | { | 117 | { |
118 | // System.Console.WriteLine("TEST Obj Removed!"); | ||
113 | } | 119 | } |
114 | } | 120 | } |
115 | } | 121 | } |
diff --git a/OpenSim/Region/OptionalModules/ViewerSupport/DynamicFloaterModule.cs b/OpenSim/Region/OptionalModules/ViewerSupport/DynamicFloaterModule.cs new file mode 100644 index 0000000..7919fef --- /dev/null +++ b/OpenSim/Region/OptionalModules/ViewerSupport/DynamicFloaterModule.cs | |||
@@ -0,0 +1,228 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.IO; | ||
30 | using System.Reflection; | ||
31 | using System.Text; | ||
32 | using System.Collections.Generic; | ||
33 | using OpenMetaverse; | ||
34 | using OpenMetaverse.StructuredData; | ||
35 | using OpenSim; | ||
36 | using OpenSim.Region; | ||
37 | using OpenSim.Region.Framework; | ||
38 | using OpenSim.Region.Framework.Scenes; | ||
39 | using OpenSim.Region.Framework.Interfaces; | ||
40 | using OpenSim.Framework; | ||
41 | using OpenSim.Framework.Servers; | ||
42 | using OpenSim.Framework.Servers.HttpServer; | ||
43 | using Nini.Config; | ||
44 | using log4net; | ||
45 | using Mono.Addins; | ||
46 | using Caps = OpenSim.Framework.Capabilities.Caps; | ||
47 | using OSDMap = OpenMetaverse.StructuredData.OSDMap; | ||
48 | |||
49 | namespace 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 | m_floaters[agentID].Add(dialogData.Channel, dialogData); | ||
126 | |||
127 | string xml; | ||
128 | using (FileStream fs = File.Open(dialogData.XmlName + ".xml", FileMode.Open)) | ||
129 | { | ||
130 | using (StreamReader sr = new StreamReader(fs)) | ||
131 | xml = sr.ReadToEnd().Replace("\n", ""); | ||
132 | } | ||
133 | |||
134 | List<string> xparts = new List<string>(); | ||
135 | |||
136 | while (xml.Length > 0) | ||
137 | { | ||
138 | string x = xml; | ||
139 | if (x.Length > 600) | ||
140 | { | ||
141 | x = x.Substring(0, 600); | ||
142 | xml = xml.Substring(600); | ||
143 | } | ||
144 | else | ||
145 | { | ||
146 | xml = String.Empty; | ||
147 | } | ||
148 | |||
149 | xparts.Add(x); | ||
150 | } | ||
151 | |||
152 | for (int i = 0 ; i < xparts.Count ; i++) | ||
153 | SendToClient(sp, String.Format("># floater {2} create {0}/{1} " + xparts[i], i + 1, xparts.Count, dialogData.FloaterName)); | ||
154 | |||
155 | 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)); | ||
156 | } | ||
157 | |||
158 | private void OnChatFromClient(object sender, OSChatMessage msg) | ||
159 | { | ||
160 | if (msg.Sender == null) | ||
161 | return; | ||
162 | |||
163 | //m_log.DebugFormat("chan {0} msg {1}", msg.Channel, msg.Message); | ||
164 | |||
165 | IClientAPI client = msg.Sender; | ||
166 | |||
167 | if (!m_floaters.ContainsKey(client.AgentId)) | ||
168 | return; | ||
169 | |||
170 | string[] parts = msg.Message.Split(new char[] {':'}); | ||
171 | if (parts.Length == 0) | ||
172 | return; | ||
173 | |||
174 | ScenePresence sp = m_scene.GetScenePresence(client.AgentId); | ||
175 | if (sp == null || sp.IsChildAgent) | ||
176 | return; | ||
177 | |||
178 | Dictionary<int, FloaterData> d = m_floaters[client.AgentId]; | ||
179 | |||
180 | // Work around a viewer bug - VALUE from any | ||
181 | // dialog can appear on this channel and needs to | ||
182 | // be dispatched to ALL open dialogs for the user | ||
183 | if (msg.Channel == 427169570) | ||
184 | { | ||
185 | if (parts[0] == "VALUE") | ||
186 | { | ||
187 | foreach (FloaterData dd in d.Values) | ||
188 | { | ||
189 | if(dd.Handler(client, dd, parts)) | ||
190 | { | ||
191 | m_floaters[client.AgentId].Remove(dd.Channel); | ||
192 | SendToClient(sp, String.Format("># floater {0} destroy", dd.FloaterName)); | ||
193 | break; | ||
194 | } | ||
195 | } | ||
196 | } | ||
197 | return; | ||
198 | } | ||
199 | |||
200 | if (!d.ContainsKey(msg.Channel)) | ||
201 | return; | ||
202 | |||
203 | FloaterData data = d[msg.Channel]; | ||
204 | |||
205 | if (parts[0] == "NOTIFY") | ||
206 | { | ||
207 | if (parts[1] == "cancel" || parts[1] == data.FloaterName) | ||
208 | { | ||
209 | m_floaters[client.AgentId].Remove(data.Channel); | ||
210 | SendToClient(sp, String.Format("># floater {0} destroy", data.FloaterName)); | ||
211 | } | ||
212 | } | ||
213 | |||
214 | if (data.Handler(client, data, parts)) | ||
215 | { | ||
216 | m_floaters[client.AgentId].Remove(data.Channel); | ||
217 | SendToClient(sp, String.Format("># floater {0} destroy", data.FloaterName)); | ||
218 | } | ||
219 | } | ||
220 | |||
221 | public void FloaterControl(ScenePresence sp, FloaterData d, string msg) | ||
222 | { | ||
223 | string sendData = String.Format("># floater {0} {1}", d.FloaterName, msg); | ||
224 | SendToClient(sp, sendData); | ||
225 | |||
226 | } | ||
227 | } | ||
228 | } | ||
diff --git a/OpenSim/Region/OptionalModules/ViewerSupport/DynamicMenuModule.cs b/OpenSim/Region/OptionalModules/ViewerSupport/DynamicMenuModule.cs new file mode 100644 index 0000000..917911f --- /dev/null +++ b/OpenSim/Region/OptionalModules/ViewerSupport/DynamicMenuModule.cs | |||
@@ -0,0 +1,282 @@ | |||
1 | // ****************************************************************** | ||
2 | // Copyright (c) 2008, 2009 Melanie Thielker | ||
3 | // | ||
4 | // All rights reserved | ||
5 | // | ||
6 | |||
7 | using System; | ||
8 | using System.IO; | ||
9 | using System.Reflection; | ||
10 | using System.Text; | ||
11 | using System.Collections.Generic; | ||
12 | using OpenMetaverse; | ||
13 | using OpenMetaverse.StructuredData; | ||
14 | using OpenSim; | ||
15 | using OpenSim.Region; | ||
16 | using OpenSim.Region.Framework; | ||
17 | using OpenSim.Region.Framework.Scenes; | ||
18 | using OpenSim.Region.Framework.Interfaces; | ||
19 | using OpenSim.Framework; | ||
20 | //using OpenSim.Framework.Capabilities; | ||
21 | using OpenSim.Framework.Servers; | ||
22 | using OpenSim.Framework.Servers.HttpServer; | ||
23 | using Nini.Config; | ||
24 | using log4net; | ||
25 | using Mono.Addins; | ||
26 | using Caps = OpenSim.Framework.Capabilities.Caps; | ||
27 | using OSDMap = OpenMetaverse.StructuredData.OSDMap; | ||
28 | |||
29 | namespace OpenSim.Region.OptionalModules.ViewerSupport | ||
30 | { | ||
31 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DynamicMenu")] | ||
32 | public class DynamicMenuModule : INonSharedRegionModule, IDynamicMenuModule | ||
33 | { | ||
34 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
35 | |||
36 | private class MenuItemData | ||
37 | { | ||
38 | public string Title; | ||
39 | public UUID AgentID; | ||
40 | public InsertLocation Location; | ||
41 | public UserMode Mode; | ||
42 | public CustomMenuHandler Handler; | ||
43 | } | ||
44 | |||
45 | private Dictionary<UUID, List<MenuItemData>> m_menuItems = | ||
46 | new Dictionary<UUID, List<MenuItemData>>(); | ||
47 | |||
48 | private Scene m_scene; | ||
49 | |||
50 | public string Name | ||
51 | { | ||
52 | get { return "DynamicMenuModule"; } | ||
53 | } | ||
54 | |||
55 | public Type ReplaceableInterface | ||
56 | { | ||
57 | get { return null; } | ||
58 | } | ||
59 | |||
60 | public void Initialise(IConfigSource config) | ||
61 | { | ||
62 | } | ||
63 | |||
64 | public void Close() | ||
65 | { | ||
66 | } | ||
67 | |||
68 | public void AddRegion(Scene scene) | ||
69 | { | ||
70 | m_scene = scene; | ||
71 | scene.EventManager.OnRegisterCaps += OnRegisterCaps; | ||
72 | m_scene.RegisterModuleInterface<IDynamicMenuModule>(this); | ||
73 | } | ||
74 | |||
75 | public void RegionLoaded(Scene scene) | ||
76 | { | ||
77 | ISimulatorFeaturesModule featuresModule = m_scene.RequestModuleInterface<ISimulatorFeaturesModule>(); | ||
78 | |||
79 | if (featuresModule != null) | ||
80 | featuresModule.OnSimulatorFeaturesRequest += OnSimulatorFeaturesRequest; | ||
81 | } | ||
82 | |||
83 | public void RemoveRegion(Scene scene) | ||
84 | { | ||
85 | } | ||
86 | |||
87 | private void OnSimulatorFeaturesRequest(UUID agentID, ref OSDMap features) | ||
88 | { | ||
89 | OSD menus = new OSDMap(); | ||
90 | if (features.ContainsKey("menus")) | ||
91 | menus = features["menus"]; | ||
92 | |||
93 | OSDMap agent = new OSDMap(); | ||
94 | OSDMap world = new OSDMap(); | ||
95 | OSDMap tools = new OSDMap(); | ||
96 | OSDMap advanced = new OSDMap(); | ||
97 | OSDMap admin = new OSDMap(); | ||
98 | if (((OSDMap)menus).ContainsKey("agent")) | ||
99 | agent = (OSDMap)((OSDMap)menus)["agent"]; | ||
100 | if (((OSDMap)menus).ContainsKey("world")) | ||
101 | world = (OSDMap)((OSDMap)menus)["world"]; | ||
102 | if (((OSDMap)menus).ContainsKey("tools")) | ||
103 | tools = (OSDMap)((OSDMap)menus)["tools"]; | ||
104 | if (((OSDMap)menus).ContainsKey("advanced")) | ||
105 | advanced = (OSDMap)((OSDMap)menus)["advanced"]; | ||
106 | if (((OSDMap)menus).ContainsKey("admin")) | ||
107 | admin = (OSDMap)((OSDMap)menus)["admin"]; | ||
108 | |||
109 | if (m_menuItems.ContainsKey(UUID.Zero)) | ||
110 | { | ||
111 | foreach (MenuItemData d in m_menuItems[UUID.Zero]) | ||
112 | { | ||
113 | if (d.Mode == UserMode.God && (!m_scene.Permissions.IsGod(agentID))) | ||
114 | continue; | ||
115 | |||
116 | OSDMap loc = null; | ||
117 | switch (d.Location) | ||
118 | { | ||
119 | case InsertLocation.Agent: | ||
120 | loc = agent; | ||
121 | break; | ||
122 | case InsertLocation.World: | ||
123 | loc = world; | ||
124 | break; | ||
125 | case InsertLocation.Tools: | ||
126 | loc = tools; | ||
127 | break; | ||
128 | case InsertLocation.Advanced: | ||
129 | loc = advanced; | ||
130 | break; | ||
131 | case InsertLocation.Admin: | ||
132 | loc = admin; | ||
133 | break; | ||
134 | } | ||
135 | |||
136 | if (loc == null) | ||
137 | continue; | ||
138 | |||
139 | loc[d.Title] = OSD.FromString(d.Title); | ||
140 | } | ||
141 | } | ||
142 | |||
143 | if (m_menuItems.ContainsKey(agentID)) | ||
144 | { | ||
145 | foreach (MenuItemData d in m_menuItems[agentID]) | ||
146 | { | ||
147 | if (d.Mode == UserMode.God && (!m_scene.Permissions.IsGod(agentID))) | ||
148 | continue; | ||
149 | |||
150 | OSDMap loc = null; | ||
151 | switch (d.Location) | ||
152 | { | ||
153 | case InsertLocation.Agent: | ||
154 | loc = agent; | ||
155 | break; | ||
156 | case InsertLocation.World: | ||
157 | loc = world; | ||
158 | break; | ||
159 | case InsertLocation.Tools: | ||
160 | loc = tools; | ||
161 | break; | ||
162 | case InsertLocation.Advanced: | ||
163 | loc = advanced; | ||
164 | break; | ||
165 | case InsertLocation.Admin: | ||
166 | loc = admin; | ||
167 | break; | ||
168 | } | ||
169 | |||
170 | if (loc == null) | ||
171 | continue; | ||
172 | |||
173 | loc[d.Title] = OSD.FromString(d.Title); | ||
174 | } | ||
175 | } | ||
176 | |||
177 | |||
178 | ((OSDMap)menus)["agent"] = agent; | ||
179 | ((OSDMap)menus)["world"] = world; | ||
180 | ((OSDMap)menus)["tools"] = tools; | ||
181 | ((OSDMap)menus)["advanced"] = advanced; | ||
182 | ((OSDMap)menus)["admin"] = admin; | ||
183 | |||
184 | features["menus"] = menus; | ||
185 | } | ||
186 | |||
187 | private void OnRegisterCaps(UUID agentID, Caps caps) | ||
188 | { | ||
189 | string capUrl = "/CAPS/" + UUID.Random() + "/"; | ||
190 | |||
191 | capUrl = "/CAPS/" + UUID.Random() + "/"; | ||
192 | caps.RegisterHandler("CustomMenuAction", new MenuActionHandler(capUrl, "CustomMenuAction", agentID, this, m_scene)); | ||
193 | } | ||
194 | |||
195 | internal void HandleMenuSelection(string action, UUID agentID, List<uint> selection) | ||
196 | { | ||
197 | if (m_menuItems.ContainsKey(agentID)) | ||
198 | { | ||
199 | foreach (MenuItemData d in m_menuItems[agentID]) | ||
200 | { | ||
201 | if (d.Title == action) | ||
202 | d.Handler(action, agentID, selection); | ||
203 | } | ||
204 | } | ||
205 | |||
206 | if (m_menuItems.ContainsKey(UUID.Zero)) | ||
207 | { | ||
208 | foreach (MenuItemData d in m_menuItems[UUID.Zero]) | ||
209 | { | ||
210 | if (d.Title == action) | ||
211 | d.Handler(action, agentID, selection); | ||
212 | } | ||
213 | } | ||
214 | } | ||
215 | |||
216 | public void AddMenuItem(string title, InsertLocation location, UserMode mode, CustomMenuHandler handler) | ||
217 | { | ||
218 | AddMenuItem(UUID.Zero, title, location, mode, handler); | ||
219 | } | ||
220 | |||
221 | public void AddMenuItem(UUID agentID, string title, InsertLocation location, UserMode mode, CustomMenuHandler handler) | ||
222 | { | ||
223 | if (!m_menuItems.ContainsKey(agentID)) | ||
224 | m_menuItems[agentID] = new List<MenuItemData>(); | ||
225 | |||
226 | m_menuItems[agentID].Add(new MenuItemData() { Title = title, AgentID = agentID, Location = location, Mode = mode, Handler = handler }); | ||
227 | } | ||
228 | |||
229 | public void RemoveMenuItem(string action) | ||
230 | { | ||
231 | foreach (KeyValuePair<UUID,List< MenuItemData>> kvp in m_menuItems) | ||
232 | { | ||
233 | List<MenuItemData> pendingDeletes = new List<MenuItemData>(); | ||
234 | foreach (MenuItemData d in kvp.Value) | ||
235 | { | ||
236 | if (d.Title == action) | ||
237 | pendingDeletes.Add(d); | ||
238 | } | ||
239 | |||
240 | foreach (MenuItemData d in pendingDeletes) | ||
241 | kvp.Value.Remove(d); | ||
242 | } | ||
243 | } | ||
244 | } | ||
245 | |||
246 | public class MenuActionHandler : BaseStreamHandler | ||
247 | { | ||
248 | private static readonly ILog m_log = | ||
249 | LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
250 | |||
251 | private UUID m_agentID; | ||
252 | private Scene m_scene; | ||
253 | private DynamicMenuModule m_module; | ||
254 | |||
255 | public MenuActionHandler(string path, string name, UUID agentID, DynamicMenuModule module, Scene scene) | ||
256 | :base("POST", path, name, agentID.ToString()) | ||
257 | { | ||
258 | m_agentID = agentID; | ||
259 | m_scene = scene; | ||
260 | m_module = module; | ||
261 | } | ||
262 | |||
263 | public override byte[] Handle(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | ||
264 | { | ||
265 | StreamReader reader = new StreamReader(request); | ||
266 | string requestBody = reader.ReadToEnd(); | ||
267 | |||
268 | OSD osd = OSDParser.DeserializeLLSDXml(requestBody); | ||
269 | |||
270 | string action = ((OSDMap)osd)["action"].AsString(); | ||
271 | OSDArray selection = (OSDArray)((OSDMap)osd)["selection"]; | ||
272 | List<uint> sel = new List<uint>(); | ||
273 | for (int i = 0 ; i < selection.Count ; i++) | ||
274 | sel.Add(selection[i].AsUInteger()); | ||
275 | |||
276 | Util.FireAndForget(x => { m_module.HandleMenuSelection(action, m_agentID, sel); }); | ||
277 | |||
278 | Encoding encoding = Encoding.UTF8; | ||
279 | return encoding.GetBytes(OSDParser.SerializeLLSDXmlString(new OSD())); | ||
280 | } | ||
281 | } | ||
282 | } | ||
diff --git a/OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs b/OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs index c7e3a7a..be020e4 100644 --- a/OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs +++ b/OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs | |||
@@ -49,7 +49,7 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule | |||
49 | /// (such as land transfers). There is no money code here! Use FORGE as an example for money code. | 49 | /// (such as land transfers). There is no money code here! Use FORGE as an example for money code. |
50 | /// Demo Economy/Money Module. This is a purposely crippled module! | 50 | /// Demo Economy/Money Module. This is a purposely crippled module! |
51 | /// // To land transfer you need to add: | 51 | /// // To land transfer you need to add: |
52 | /// -helperuri <ADDRESS TO THIS SERVER> | 52 | /// -helperuri http://serveraddress:port/ |
53 | /// to the command line parameters you use to start up your client | 53 | /// to the command line parameters you use to start up your client |
54 | /// This commonly looks like -helperuri http://127.0.0.1:9000/ | 54 | /// This commonly looks like -helperuri http://127.0.0.1:9000/ |
55 | /// | 55 | /// |
@@ -116,10 +116,9 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule | |||
116 | } | 116 | } |
117 | 117 | ||
118 | /// <summary> | 118 | /// <summary> |
119 | /// Startup | 119 | /// Called on startup so the module can be configured. |
120 | /// </summary> | 120 | /// </summary> |
121 | /// <param name="scene"></param> | 121 | /// <param name="config">Configuration source.</param> |
122 | /// <param name="config"></param> | ||
123 | public void Initialise(IConfigSource config) | 122 | public void Initialise(IConfigSource config) |
124 | { | 123 | { |
125 | m_gConfig = config; | 124 | m_gConfig = config; |
@@ -674,9 +673,12 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule | |||
674 | } | 673 | } |
675 | 674 | ||
676 | /// <summary> | 675 | /// <summary> |
677 | /// When the client closes the connection we remove their accounting info from memory to free up resources. | 676 | /// When the client closes the connection we remove their accounting |
677 | /// info from memory to free up resources. | ||
678 | /// </summary> | 678 | /// </summary> |
679 | /// <param name="AgentID"></param> | 679 | /// <param name="AgentID">UUID of agent</param> |
680 | /// <param name="scene">Scene the agent was connected to.</param> | ||
681 | /// <see cref="OpenSim.Region.Framework.Scenes.EventManager.ClientClosed"/> | ||
680 | public void ClientClosed(UUID AgentID, Scene scene) | 682 | public void ClientClosed(UUID AgentID, Scene scene) |
681 | { | 683 | { |
682 | 684 | ||
@@ -686,19 +688,14 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule | |||
686 | /// Event called Economy Data Request handler. | 688 | /// Event called Economy Data Request handler. |
687 | /// </summary> | 689 | /// </summary> |
688 | /// <param name="agentId"></param> | 690 | /// <param name="agentId"></param> |
689 | public void EconomyDataRequestHandler(UUID agentId) | 691 | public void EconomyDataRequestHandler(IClientAPI user) |
690 | { | 692 | { |
691 | IClientAPI user = LocateClientObject(agentId); | 693 | Scene s = LocateSceneClientIn(user.AgentId); |
692 | 694 | ||
693 | if (user != null) | 695 | user.SendEconomyData(EnergyEfficiency, s.RegionInfo.ObjectCapacity, ObjectCount, PriceEnergyUnit, PriceGroupCreate, |
694 | { | 696 | PriceObjectClaim, PriceObjectRent, PriceObjectScaleFactor, PriceParcelClaim, PriceParcelClaimFactor, |
695 | Scene s = LocateSceneClientIn(user.AgentId); | 697 | PriceParcelRent, PricePublicObjectDecay, PricePublicObjectDelete, PriceRentLight, PriceUpload, |
696 | 698 | TeleportMinPrice, TeleportPriceExponent); | |
697 | user.SendEconomyData(EnergyEfficiency, s.RegionInfo.ObjectCapacity, ObjectCount, PriceEnergyUnit, PriceGroupCreate, | ||
698 | PriceObjectClaim, PriceObjectRent, PriceObjectScaleFactor, PriceParcelClaim, PriceParcelClaimFactor, | ||
699 | PriceParcelRent, PricePublicObjectDecay, PricePublicObjectDelete, PriceRentLight, PriceUpload, | ||
700 | TeleportMinPrice, TeleportPriceExponent); | ||
701 | } | ||
702 | } | 699 | } |
703 | 700 | ||
704 | private void ValidateLandBuy(Object osender, EventManager.LandBuyArgs e) | 701 | 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 d665126..7918c22 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs | |||
@@ -630,12 +630,12 @@ namespace OpenSim.Region.OptionalModules.World.NPC | |||
630 | 630 | ||
631 | } | 631 | } |
632 | 632 | ||
633 | public void SendGenericMessage(string method, List<string> message) | 633 | public void SendGenericMessage(string method, UUID invoice, List<string> message) |
634 | { | 634 | { |
635 | 635 | ||
636 | } | 636 | } |
637 | 637 | ||
638 | public void SendGenericMessage(string method, List<byte[]> message) | 638 | public void SendGenericMessage(string method, UUID invoice, List<byte[]> message) |
639 | { | 639 | { |
640 | 640 | ||
641 | } | 641 | } |
diff --git a/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs b/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs index ef4005b..34362af 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs | |||
@@ -48,7 +48,7 @@ using OpenSim.Tests.Common.Mock; | |||
48 | namespace OpenSim.Region.OptionalModules.World.NPC.Tests | 48 | namespace OpenSim.Region.OptionalModules.World.NPC.Tests |
49 | { | 49 | { |
50 | [TestFixture] | 50 | [TestFixture] |
51 | public class NPCModuleTests | 51 | public class NPCModuleTests : OpenSimTestCase |
52 | { | 52 | { |
53 | private TestScene m_scene; | 53 | private TestScene m_scene; |
54 | private AvatarFactoryModule m_afMod; | 54 | private AvatarFactoryModule m_afMod; |
@@ -74,6 +74,8 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests | |||
74 | [SetUp] | 74 | [SetUp] |
75 | public void Init() | 75 | public void Init() |
76 | { | 76 | { |
77 | base.SetUp(); | ||
78 | |||
77 | IConfigSource config = new IniConfigSource(); | 79 | IConfigSource config = new IniConfigSource(); |
78 | config.AddConfig("NPC"); | 80 | config.AddConfig("NPC"); |
79 | config.Configs["NPC"].Set("Enabled", "true"); | 81 | config.Configs["NPC"].Set("Enabled", "true"); |
diff --git a/OpenSim/Region/OptionalModules/World/SceneCommands/SceneCommandsModule.cs b/OpenSim/Region/OptionalModules/World/SceneCommands/SceneCommandsModule.cs new file mode 100644 index 0000000..29b39e0 --- /dev/null +++ b/OpenSim/Region/OptionalModules/World/SceneCommands/SceneCommandsModule.cs | |||
@@ -0,0 +1,266 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Linq; | ||
31 | using System.Reflection; | ||
32 | using System.Text; | ||
33 | using log4net; | ||
34 | using Mono.Addins; | ||
35 | using Nini.Config; | ||
36 | using OpenMetaverse; | ||
37 | using OpenSim.Framework; | ||
38 | using OpenSim.Framework.Console; | ||
39 | using OpenSim.Framework.Monitoring; | ||
40 | using OpenSim.Region.Framework.Interfaces; | ||
41 | using OpenSim.Region.Framework.Scenes; | ||
42 | |||
43 | namespace OpenSim.Region.OptionalModules.Avatar.Attachments | ||
44 | { | ||
45 | /// <summary> | ||
46 | /// A module that just holds commands for inspecting avatar appearance. | ||
47 | /// </summary> | ||
48 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "SceneCommandsModule")] | ||
49 | public class SceneCommandsModule : ISceneCommandsModule, INonSharedRegionModule | ||
50 | { | ||
51 | // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
52 | |||
53 | private Scene m_scene; | ||
54 | |||
55 | public string Name { get { return "Scene Commands Module"; } } | ||
56 | |||
57 | public Type ReplaceableInterface { get { return null; } } | ||
58 | |||
59 | public void Initialise(IConfigSource source) | ||
60 | { | ||
61 | // m_log.DebugFormat("[SCENE COMMANDS MODULE]: INITIALIZED MODULE"); | ||
62 | } | ||
63 | |||
64 | public void PostInitialise() | ||
65 | { | ||
66 | // m_log.DebugFormat("[SCENE COMMANDS MODULE]: POST INITIALIZED MODULE"); | ||
67 | } | ||
68 | |||
69 | public void Close() | ||
70 | { | ||
71 | // m_log.DebugFormat("[SCENE COMMANDS MODULE]: CLOSED MODULE"); | ||
72 | } | ||
73 | |||
74 | public void AddRegion(Scene scene) | ||
75 | { | ||
76 | // m_log.DebugFormat("[SCENE COMMANDS MODULE]: REGION {0} ADDED", scene.RegionInfo.RegionName); | ||
77 | |||
78 | m_scene = scene; | ||
79 | |||
80 | m_scene.RegisterModuleInterface<ISceneCommandsModule>(this); | ||
81 | } | ||
82 | |||
83 | public void RemoveRegion(Scene scene) | ||
84 | { | ||
85 | // m_log.DebugFormat("[SCENE COMMANDS MODULE]: REGION {0} REMOVED", scene.RegionInfo.RegionName); | ||
86 | } | ||
87 | |||
88 | public void RegionLoaded(Scene scene) | ||
89 | { | ||
90 | // m_log.DebugFormat("[ATTACHMENTS COMMAND MODULE]: REGION {0} LOADED", scene.RegionInfo.RegionName); | ||
91 | |||
92 | scene.AddCommand( | ||
93 | "Debug", this, "debug scene get", | ||
94 | "debug scene get", | ||
95 | "List current scene options.", | ||
96 | "If active is 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 | + "If collisions is false then collisions with other objects are turned off.\n" | ||
99 | + "If pbackup is false then periodic scene backup is turned off.\n" | ||
100 | + "If physics is false then all physics objects are non-physical.\n" | ||
101 | + "If scripting is false then no scripting operations happen.\n" | ||
102 | + "If teleport is true then some extra teleport debug information is logged.\n" | ||
103 | + "If updates is true then any frame which exceeds double the maximum desired frame time is logged.", | ||
104 | HandleDebugSceneGetCommand); | ||
105 | |||
106 | scene.AddCommand( | ||
107 | "Debug", this, "debug scene set", | ||
108 | "debug scene set active|collisions|pbackup|physics|scripting|teleport|updates true|false", | ||
109 | "Turn on scene debugging options.", | ||
110 | "If active is false then main scene update and maintenance loops are suspended.\n" | ||
111 | + "If animations is true then extra animations debug information is logged.\n" | ||
112 | + "If collisions is false then collisions with other objects are turned off.\n" | ||
113 | + "If pbackup is false then periodic scene backup is turned off.\n" | ||
114 | + "If physics is false then all physics objects are non-physical.\n" | ||
115 | + "If scripting is false then no scripting operations happen.\n" | ||
116 | + "If teleport is true then some extra teleport debug information is logged.\n" | ||
117 | + "If updates is true then any frame which exceeds double the maximum desired frame time is logged.", | ||
118 | HandleDebugSceneSetCommand); | ||
119 | |||
120 | scene.AddCommand( | ||
121 | "Regions", | ||
122 | this, "show borders", "show borders", "Show border information for regions", HandleShowBordersCommand); | ||
123 | } | ||
124 | |||
125 | private void HandleShowBordersCommand(string module, string[] args) | ||
126 | { | ||
127 | StringBuilder sb = new StringBuilder(); | ||
128 | sb.AppendFormat("Borders for {0}:\n", m_scene.Name); | ||
129 | |||
130 | ConsoleDisplayTable cdt = new ConsoleDisplayTable(); | ||
131 | cdt.AddColumn("Cross Direction", 15); | ||
132 | cdt.AddColumn("Line", 34); | ||
133 | cdt.AddColumn("Trigger Region", 14); | ||
134 | |||
135 | foreach (Border b in m_scene.NorthBorders) | ||
136 | cdt.AddRow(b.CrossDirection, b.BorderLine, string.Format("{0}, {1}", b.TriggerRegionX, b.TriggerRegionY)); | ||
137 | |||
138 | foreach (Border b in m_scene.EastBorders) | ||
139 | cdt.AddRow(b.CrossDirection, b.BorderLine, string.Format("{0}, {1}", b.TriggerRegionX, b.TriggerRegionY)); | ||
140 | |||
141 | foreach (Border b in m_scene.SouthBorders) | ||
142 | cdt.AddRow(b.CrossDirection, b.BorderLine, string.Format("{0}, {1}", b.TriggerRegionX, b.TriggerRegionY)); | ||
143 | |||
144 | foreach (Border b in m_scene.WestBorders) | ||
145 | cdt.AddRow(b.CrossDirection, b.BorderLine, string.Format("{0}, {1}", b.TriggerRegionX, b.TriggerRegionY)); | ||
146 | |||
147 | cdt.AddToStringBuilder(sb); | ||
148 | |||
149 | MainConsole.Instance.Output(sb.ToString()); | ||
150 | } | ||
151 | |||
152 | private void HandleDebugSceneGetCommand(string module, string[] args) | ||
153 | { | ||
154 | if (args.Length == 3) | ||
155 | { | ||
156 | if (MainConsole.Instance.ConsoleScene != m_scene && MainConsole.Instance.ConsoleScene != null) | ||
157 | return; | ||
158 | |||
159 | OutputSceneDebugOptions(); | ||
160 | } | ||
161 | else | ||
162 | { | ||
163 | MainConsole.Instance.Output("Usage: debug scene get"); | ||
164 | } | ||
165 | } | ||
166 | |||
167 | private void OutputSceneDebugOptions() | ||
168 | { | ||
169 | ConsoleDisplayList cdl = new ConsoleDisplayList(); | ||
170 | cdl.AddRow("active", m_scene.Active); | ||
171 | cdl.AddRow("animations", m_scene.DebugAnimations); | ||
172 | cdl.AddRow("pbackup", m_scene.PeriodicBackup); | ||
173 | cdl.AddRow("physics", m_scene.PhysicsEnabled); | ||
174 | cdl.AddRow("scripting", m_scene.ScriptsEnabled); | ||
175 | cdl.AddRow("teleport", m_scene.DebugTeleporting); | ||
176 | cdl.AddRow("updates", m_scene.DebugUpdates); | ||
177 | |||
178 | MainConsole.Instance.OutputFormat("Scene {0} options:", m_scene.Name); | ||
179 | MainConsole.Instance.Output(cdl.ToString()); | ||
180 | } | ||
181 | |||
182 | private void HandleDebugSceneSetCommand(string module, string[] args) | ||
183 | { | ||
184 | if (args.Length == 5) | ||
185 | { | ||
186 | if (MainConsole.Instance.ConsoleScene != m_scene && MainConsole.Instance.ConsoleScene != null) | ||
187 | return; | ||
188 | |||
189 | string key = args[3]; | ||
190 | string value = args[4]; | ||
191 | SetSceneDebugOptions(new Dictionary<string, string>() { { key, value } }); | ||
192 | |||
193 | MainConsole.Instance.OutputFormat("Set {0} debug scene {1} = {2}", m_scene.Name, key, value); | ||
194 | } | ||
195 | else | ||
196 | { | ||
197 | MainConsole.Instance.Output( | ||
198 | "Usage: debug scene set active|collisions|pbackup|physics|scripting|teleport|updates true|false"); | ||
199 | } | ||
200 | } | ||
201 | |||
202 | public void SetSceneDebugOptions(Dictionary<string, string> options) | ||
203 | { | ||
204 | if (options.ContainsKey("active")) | ||
205 | { | ||
206 | bool active; | ||
207 | |||
208 | if (bool.TryParse(options["active"], out active)) | ||
209 | m_scene.Active = active; | ||
210 | } | ||
211 | |||
212 | if (options.ContainsKey("animations")) | ||
213 | { | ||
214 | bool active; | ||
215 | |||
216 | if (bool.TryParse(options["animations"], out active)) | ||
217 | m_scene.DebugAnimations = active; | ||
218 | } | ||
219 | |||
220 | if (options.ContainsKey("pbackup")) | ||
221 | { | ||
222 | bool active; | ||
223 | |||
224 | if (bool.TryParse(options["pbackup"], out active)) | ||
225 | m_scene.PeriodicBackup = active; | ||
226 | } | ||
227 | |||
228 | if (options.ContainsKey("scripting")) | ||
229 | { | ||
230 | bool enableScripts = true; | ||
231 | if (bool.TryParse(options["scripting"], out enableScripts)) | ||
232 | m_scene.ScriptsEnabled = enableScripts; | ||
233 | } | ||
234 | |||
235 | if (options.ContainsKey("physics")) | ||
236 | { | ||
237 | bool enablePhysics; | ||
238 | if (bool.TryParse(options["physics"], out enablePhysics)) | ||
239 | m_scene.PhysicsEnabled = enablePhysics; | ||
240 | } | ||
241 | |||
242 | // if (options.ContainsKey("collisions")) | ||
243 | // { | ||
244 | // // TODO: Implement. If false, should stop objects colliding, though possibly should still allow | ||
245 | // // the avatar themselves to collide with the ground. | ||
246 | // } | ||
247 | |||
248 | if (options.ContainsKey("teleport")) | ||
249 | { | ||
250 | bool enableTeleportDebugging; | ||
251 | if (bool.TryParse(options["teleport"], out enableTeleportDebugging)) | ||
252 | m_scene.DebugTeleporting = enableTeleportDebugging; | ||
253 | } | ||
254 | |||
255 | if (options.ContainsKey("updates")) | ||
256 | { | ||
257 | bool enableUpdateDebugging; | ||
258 | if (bool.TryParse(options["updates"], out enableUpdateDebugging)) | ||
259 | { | ||
260 | m_scene.DebugUpdates = enableUpdateDebugging; | ||
261 | GcNotify.Enabled = enableUpdateDebugging; | ||
262 | } | ||
263 | } | ||
264 | } | ||
265 | } | ||
266 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/Physics/BasicPhysicsPlugin/AssemblyInfo.cs b/OpenSim/Region/Physics/BasicPhysicsPlugin/AssemblyInfo.cs index fb9cb66..6fd6f7e 100644 --- a/OpenSim/Region/Physics/BasicPhysicsPlugin/AssemblyInfo.cs +++ b/OpenSim/Region/Physics/BasicPhysicsPlugin/AssemblyInfo.cs | |||
@@ -55,4 +55,4 @@ using System.Runtime.InteropServices; | |||
55 | // You can specify all values by your own or you can build default build and revision | 55 | // You can specify all values by your own or you can build default build and revision |
56 | // numbers with the '*' character (the default): | 56 | // numbers with the '*' character (the default): |
57 | 57 | ||
58 | [assembly : AssemblyVersion("0.7.5.*")] | 58 | [assembly : AssemblyVersion("0.7.6.*")] |
diff --git a/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsPlugin.cs b/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsPlugin.cs index 7ab2a03..373c7e0 100644 --- a/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsPlugin.cs +++ b/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsPlugin.cs | |||
@@ -49,7 +49,7 @@ namespace OpenSim.Region.Physics.BasicPhysicsPlugin | |||
49 | 49 | ||
50 | public PhysicsScene GetScene(string sceneIdentifier) | 50 | public PhysicsScene GetScene(string sceneIdentifier) |
51 | { | 51 | { |
52 | return new BasicScene(sceneIdentifier); | 52 | return new BasicScene(GetName(), sceneIdentifier); |
53 | } | 53 | } |
54 | 54 | ||
55 | public string GetName() | 55 | public string GetName() |
diff --git a/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsScene.cs b/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsScene.cs index f5826ed..0816b7b 100644 --- a/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsScene.cs +++ b/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsScene.cs | |||
@@ -49,8 +49,10 @@ namespace OpenSim.Region.Physics.BasicPhysicsPlugin | |||
49 | 49 | ||
50 | //protected internal string sceneIdentifier; | 50 | //protected internal string sceneIdentifier; |
51 | 51 | ||
52 | public BasicScene(string _sceneIdentifier) | 52 | public BasicScene(string engineType, string _sceneIdentifier) |
53 | { | 53 | { |
54 | EngineType = engineType; | ||
55 | Name = EngineType + "/" + _sceneIdentifier; | ||
54 | //sceneIdentifier = _sceneIdentifier; | 56 | //sceneIdentifier = _sceneIdentifier; |
55 | } | 57 | } |
56 | 58 | ||
@@ -100,6 +102,8 @@ namespace OpenSim.Region.Physics.BasicPhysicsPlugin | |||
100 | 102 | ||
101 | public override float Simulate(float timeStep) | 103 | public override float Simulate(float timeStep) |
102 | { | 104 | { |
105 | // Console.WriteLine("Simulating"); | ||
106 | |||
103 | float fps = 0; | 107 | float fps = 0; |
104 | for (int i = 0; i < _actors.Count; ++i) | 108 | for (int i = 0; i < _actors.Count; ++i) |
105 | { | 109 | { |
@@ -107,8 +111,11 @@ namespace OpenSim.Region.Physics.BasicPhysicsPlugin | |||
107 | Vector3 actorPosition = actor.Position; | 111 | Vector3 actorPosition = actor.Position; |
108 | Vector3 actorVelocity = actor.Velocity; | 112 | Vector3 actorVelocity = actor.Velocity; |
109 | 113 | ||
110 | actorPosition.X += actor.Velocity.X*timeStep; | 114 | // Console.WriteLine( |
111 | actorPosition.Y += actor.Velocity.Y*timeStep; | 115 | // "Processing actor {0}, starting pos {1}, starting vel {2}", i, actorPosition, actorVelocity); |
116 | |||
117 | actorPosition.X += actor.Velocity.X * timeStep; | ||
118 | actorPosition.Y += actor.Velocity.Y * timeStep; | ||
112 | 119 | ||
113 | if (actor.Position.Y < 0) | 120 | if (actor.Position.Y < 0) |
114 | { | 121 | { |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs b/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs new file mode 100755 index 0000000..77ea3ed --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs | |||
@@ -0,0 +1,1987 @@ | |||
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 copyrightD | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Reflection; | ||
30 | using System.Runtime.InteropServices; | ||
31 | using System.Security; | ||
32 | using System.Text; | ||
33 | |||
34 | using OpenSim.Framework; | ||
35 | |||
36 | using OpenMetaverse; | ||
37 | |||
38 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
39 | { | ||
40 | public sealed class BSAPIUnman : BSAPITemplate | ||
41 | { | ||
42 | |||
43 | private sealed class BulletWorldUnman : BulletWorld | ||
44 | { | ||
45 | public IntPtr ptr; | ||
46 | public BulletWorldUnman(uint id, BSScene physScene, IntPtr xx) | ||
47 | : base(id, physScene) | ||
48 | { | ||
49 | ptr = xx; | ||
50 | } | ||
51 | } | ||
52 | |||
53 | private sealed class BulletBodyUnman : BulletBody | ||
54 | { | ||
55 | public IntPtr ptr; | ||
56 | public BulletBodyUnman(uint id, IntPtr xx) | ||
57 | : base(id) | ||
58 | { | ||
59 | ptr = xx; | ||
60 | } | ||
61 | public override bool HasPhysicalBody | ||
62 | { | ||
63 | get { return ptr != IntPtr.Zero; } | ||
64 | } | ||
65 | public override void Clear() | ||
66 | { | ||
67 | ptr = IntPtr.Zero; | ||
68 | } | ||
69 | public override string AddrString | ||
70 | { | ||
71 | get { return ptr.ToString("X"); } | ||
72 | } | ||
73 | } | ||
74 | |||
75 | private sealed class BulletShapeUnman : BulletShape | ||
76 | { | ||
77 | public IntPtr ptr; | ||
78 | public BulletShapeUnman(IntPtr xx, BSPhysicsShapeType typ) | ||
79 | : base() | ||
80 | { | ||
81 | ptr = xx; | ||
82 | type = typ; | ||
83 | } | ||
84 | public override bool HasPhysicalShape | ||
85 | { | ||
86 | get { return ptr != IntPtr.Zero; } | ||
87 | } | ||
88 | public override void Clear() | ||
89 | { | ||
90 | ptr = IntPtr.Zero; | ||
91 | } | ||
92 | public override BulletShape Clone() | ||
93 | { | ||
94 | return new BulletShapeUnman(ptr, type); | ||
95 | } | ||
96 | public override bool ReferenceSame(BulletShape other) | ||
97 | { | ||
98 | BulletShapeUnman otheru = other as BulletShapeUnman; | ||
99 | return (otheru != null) && (this.ptr == otheru.ptr); | ||
100 | |||
101 | } | ||
102 | public override string AddrString | ||
103 | { | ||
104 | get { return ptr.ToString("X"); } | ||
105 | } | ||
106 | } | ||
107 | private sealed class BulletConstraintUnman : BulletConstraint | ||
108 | { | ||
109 | public BulletConstraintUnman(IntPtr xx) : base() | ||
110 | { | ||
111 | ptr = xx; | ||
112 | } | ||
113 | public IntPtr ptr; | ||
114 | |||
115 | public override void Clear() | ||
116 | { | ||
117 | ptr = IntPtr.Zero; | ||
118 | } | ||
119 | public override bool HasPhysicalConstraint { get { return ptr != IntPtr.Zero; } } | ||
120 | |||
121 | // Used for log messages for a unique display of the memory/object allocated to this instance | ||
122 | public override string AddrString | ||
123 | { | ||
124 | get { return ptr.ToString("X"); } | ||
125 | } | ||
126 | } | ||
127 | |||
128 | // We pin the memory passed between the managed and unmanaged code. | ||
129 | GCHandle m_paramsHandle; | ||
130 | private GCHandle m_collisionArrayPinnedHandle; | ||
131 | private GCHandle m_updateArrayPinnedHandle; | ||
132 | |||
133 | // Handle to the callback used by the unmanaged code to call into the managed code. | ||
134 | // Used for debug logging. | ||
135 | // Need to store the handle in a persistant variable so it won't be freed. | ||
136 | private BSAPICPP.DebugLogCallback m_DebugLogCallbackHandle; | ||
137 | |||
138 | private BSScene PhysicsScene { get; set; } | ||
139 | |||
140 | public override string BulletEngineName { get { return "BulletUnmanaged"; } } | ||
141 | public override string BulletEngineVersion { get; protected set; } | ||
142 | |||
143 | public BSAPIUnman(string paramName, BSScene physScene) | ||
144 | { | ||
145 | PhysicsScene = physScene; | ||
146 | |||
147 | // Do something fancy with the paramName to get the right DLL implementation | ||
148 | // like "Bullet-2.80-OpenCL-Intel" loading the version for Intel based OpenCL implementation, etc. | ||
149 | if (Util.IsWindows()) | ||
150 | Util.LoadArchSpecificWindowsDll("BulletSim.dll"); | ||
151 | // If not Windows, loading is performed by the | ||
152 | // Mono loader as specified in | ||
153 | // "bin/Physics/OpenSim.Region.Physics.BulletSPlugin.dll.config". | ||
154 | } | ||
155 | |||
156 | // Initialization and simulation | ||
157 | public override BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms, | ||
158 | int maxCollisions, ref CollisionDesc[] collisionArray, | ||
159 | int maxUpdates, ref EntityProperties[] updateArray | ||
160 | ) | ||
161 | { | ||
162 | // Pin down the memory that will be used to pass object collisions and updates back from unmanaged code | ||
163 | m_paramsHandle = GCHandle.Alloc(parms, GCHandleType.Pinned); | ||
164 | m_collisionArrayPinnedHandle = GCHandle.Alloc(collisionArray, GCHandleType.Pinned); | ||
165 | m_updateArrayPinnedHandle = GCHandle.Alloc(updateArray, GCHandleType.Pinned); | ||
166 | |||
167 | // If Debug logging level, enable logging from the unmanaged code | ||
168 | m_DebugLogCallbackHandle = null; | ||
169 | if (BSScene.m_log.IsDebugEnabled && PhysicsScene.PhysicsLogging.Enabled) | ||
170 | { | ||
171 | BSScene.m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", BSScene.LogHeader); | ||
172 | if (PhysicsScene.PhysicsLogging.Enabled) | ||
173 | // The handle is saved in a variable to make sure it doesn't get freed after this call | ||
174 | m_DebugLogCallbackHandle = new BSAPICPP.DebugLogCallback(BulletLoggerPhysLog); | ||
175 | else | ||
176 | m_DebugLogCallbackHandle = new BSAPICPP.DebugLogCallback(BulletLogger); | ||
177 | } | ||
178 | |||
179 | // Get the version of the DLL | ||
180 | // TODO: this doesn't work yet. Something wrong with marshaling the returned string. | ||
181 | // BulletEngineVersion = BulletSimAPI.GetVersion2(); | ||
182 | BulletEngineVersion = ""; | ||
183 | |||
184 | // Call the unmanaged code with the buffers and other information | ||
185 | return new BulletWorldUnman(0, PhysicsScene, BSAPICPP.Initialize2(maxPosition, m_paramsHandle.AddrOfPinnedObject(), | ||
186 | maxCollisions, m_collisionArrayPinnedHandle.AddrOfPinnedObject(), | ||
187 | maxUpdates, m_updateArrayPinnedHandle.AddrOfPinnedObject(), | ||
188 | m_DebugLogCallbackHandle)); | ||
189 | |||
190 | } | ||
191 | |||
192 | // Called directly from unmanaged code so don't do much | ||
193 | private void BulletLogger(string msg) | ||
194 | { | ||
195 | BSScene.m_log.Debug("[BULLETS UNMANAGED]:" + msg); | ||
196 | } | ||
197 | |||
198 | // Called directly from unmanaged code so don't do much | ||
199 | private void BulletLoggerPhysLog(string msg) | ||
200 | { | ||
201 | PhysicsScene.DetailLog("[BULLETS UNMANAGED]:" + msg); | ||
202 | } | ||
203 | |||
204 | public override int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep, | ||
205 | out int updatedEntityCount, out int collidersCount) | ||
206 | { | ||
207 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
208 | return BSAPICPP.PhysicsStep2(worldu.ptr, timeStep, maxSubSteps, fixedTimeStep, out updatedEntityCount, out collidersCount); | ||
209 | } | ||
210 | |||
211 | public override void Shutdown(BulletWorld world) | ||
212 | { | ||
213 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
214 | BSAPICPP.Shutdown2(worldu.ptr); | ||
215 | |||
216 | if (m_paramsHandle.IsAllocated) | ||
217 | { | ||
218 | m_paramsHandle.Free(); | ||
219 | } | ||
220 | if (m_collisionArrayPinnedHandle.IsAllocated) | ||
221 | { | ||
222 | m_collisionArrayPinnedHandle.Free(); | ||
223 | } | ||
224 | if (m_updateArrayPinnedHandle.IsAllocated) | ||
225 | { | ||
226 | m_updateArrayPinnedHandle.Free(); | ||
227 | } | ||
228 | } | ||
229 | |||
230 | public override bool PushUpdate(BulletBody obj) | ||
231 | { | ||
232 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
233 | return BSAPICPP.PushUpdate2(bodyu.ptr); | ||
234 | } | ||
235 | |||
236 | public override bool UpdateParameter(BulletWorld world, uint localID, String parm, float value) | ||
237 | { | ||
238 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
239 | return BSAPICPP.UpdateParameter2(worldu.ptr, localID, parm, value); | ||
240 | } | ||
241 | |||
242 | // ===================================================================================== | ||
243 | // Mesh, hull, shape and body creation helper routines | ||
244 | public override BulletShape CreateMeshShape(BulletWorld world, | ||
245 | int indicesCount, int[] indices, | ||
246 | int verticesCount, float[] vertices) | ||
247 | { | ||
248 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
249 | return new BulletShapeUnman( | ||
250 | BSAPICPP.CreateMeshShape2(worldu.ptr, indicesCount, indices, verticesCount, vertices), | ||
251 | BSPhysicsShapeType.SHAPE_MESH); | ||
252 | } | ||
253 | |||
254 | public override BulletShape CreateHullShape(BulletWorld world, int hullCount, float[] hulls) | ||
255 | { | ||
256 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
257 | return new BulletShapeUnman( | ||
258 | BSAPICPP.CreateHullShape2(worldu.ptr, hullCount, hulls), | ||
259 | BSPhysicsShapeType.SHAPE_HULL); | ||
260 | } | ||
261 | |||
262 | public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape) | ||
263 | { | ||
264 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
265 | BulletShapeUnman shapeu = meshShape as BulletShapeUnman; | ||
266 | return new BulletShapeUnman( | ||
267 | BSAPICPP.BuildHullShapeFromMesh2(worldu.ptr, shapeu.ptr), | ||
268 | BSPhysicsShapeType.SHAPE_HULL); | ||
269 | } | ||
270 | |||
271 | public override BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData) | ||
272 | { | ||
273 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
274 | return new BulletShapeUnman(BSAPICPP.BuildNativeShape2(worldu.ptr, shapeData), shapeData.Type); | ||
275 | } | ||
276 | |||
277 | public override bool IsNativeShape(BulletShape shape) | ||
278 | { | ||
279 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
280 | if (shapeu != null && shapeu.HasPhysicalShape) | ||
281 | return BSAPICPP.IsNativeShape2(shapeu.ptr); | ||
282 | return false; | ||
283 | } | ||
284 | |||
285 | public override void SetShapeCollisionMargin(BulletShape shape, float margin) | ||
286 | { | ||
287 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
288 | if (shapeu != null && shapeu.HasPhysicalShape) | ||
289 | BSAPICPP.SetShapeCollisionMargin(shapeu.ptr, margin); | ||
290 | } | ||
291 | |||
292 | public override BulletShape BuildCapsuleShape(BulletWorld world, float radius, float height, Vector3 scale) | ||
293 | { | ||
294 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
295 | return new BulletShapeUnman( | ||
296 | BSAPICPP.BuildCapsuleShape2(worldu.ptr, radius, height, scale), | ||
297 | BSPhysicsShapeType.SHAPE_CAPSULE); | ||
298 | } | ||
299 | |||
300 | public override BulletShape CreateCompoundShape(BulletWorld world, bool enableDynamicAabbTree) | ||
301 | { | ||
302 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
303 | return new BulletShapeUnman( | ||
304 | BSAPICPP.CreateCompoundShape2(worldu.ptr, enableDynamicAabbTree), | ||
305 | BSPhysicsShapeType.SHAPE_COMPOUND); | ||
306 | |||
307 | } | ||
308 | |||
309 | public override int GetNumberOfCompoundChildren(BulletShape shape) | ||
310 | { | ||
311 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
312 | if (shapeu != null && shapeu.HasPhysicalShape) | ||
313 | return BSAPICPP.GetNumberOfCompoundChildren2(shapeu.ptr); | ||
314 | return 0; | ||
315 | } | ||
316 | |||
317 | public override void AddChildShapeToCompoundShape(BulletShape shape, BulletShape addShape, Vector3 pos, Quaternion rot) | ||
318 | { | ||
319 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
320 | BulletShapeUnman addShapeu = addShape as BulletShapeUnman; | ||
321 | BSAPICPP.AddChildShapeToCompoundShape2(shapeu.ptr, addShapeu.ptr, pos, rot); | ||
322 | } | ||
323 | |||
324 | public override BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape shape, int indx) | ||
325 | { | ||
326 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
327 | return new BulletShapeUnman(BSAPICPP.GetChildShapeFromCompoundShapeIndex2(shapeu.ptr, indx), BSPhysicsShapeType.SHAPE_UNKNOWN); | ||
328 | } | ||
329 | |||
330 | public override BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape shape, int indx) | ||
331 | { | ||
332 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
333 | return new BulletShapeUnman(BSAPICPP.RemoveChildShapeFromCompoundShapeIndex2(shapeu.ptr, indx), BSPhysicsShapeType.SHAPE_UNKNOWN); | ||
334 | } | ||
335 | |||
336 | public override void RemoveChildShapeFromCompoundShape(BulletShape shape, BulletShape removeShape) | ||
337 | { | ||
338 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
339 | BulletShapeUnman removeShapeu = removeShape as BulletShapeUnman; | ||
340 | BSAPICPP.RemoveChildShapeFromCompoundShape2(shapeu.ptr, removeShapeu.ptr); | ||
341 | } | ||
342 | |||
343 | public override void UpdateChildTransform(BulletShape pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb) | ||
344 | { | ||
345 | BulletShapeUnman shapeu = pShape as BulletShapeUnman; | ||
346 | BSAPICPP.UpdateChildTransform2(shapeu.ptr, childIndex, pos, rot, shouldRecalculateLocalAabb); | ||
347 | } | ||
348 | |||
349 | public override void RecalculateCompoundShapeLocalAabb(BulletShape shape) | ||
350 | { | ||
351 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
352 | BSAPICPP.RecalculateCompoundShapeLocalAabb2(shapeu.ptr); | ||
353 | } | ||
354 | |||
355 | public override BulletShape DuplicateCollisionShape(BulletWorld world, BulletShape srcShape, uint id) | ||
356 | { | ||
357 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
358 | BulletShapeUnman srcShapeu = srcShape as BulletShapeUnman; | ||
359 | return new BulletShapeUnman(BSAPICPP.DuplicateCollisionShape2(worldu.ptr, srcShapeu.ptr, id), srcShape.type); | ||
360 | } | ||
361 | |||
362 | public override bool DeleteCollisionShape(BulletWorld world, BulletShape shape) | ||
363 | { | ||
364 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
365 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
366 | return BSAPICPP.DeleteCollisionShape2(worldu.ptr, shapeu.ptr); | ||
367 | } | ||
368 | |||
369 | public override CollisionObjectTypes GetBodyType(BulletBody obj) | ||
370 | { | ||
371 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
372 | return (CollisionObjectTypes)BSAPICPP.GetBodyType2(bodyu.ptr); | ||
373 | } | ||
374 | |||
375 | public override BulletBody CreateBodyFromShape(BulletWorld world, BulletShape shape, uint id, Vector3 pos, Quaternion rot) | ||
376 | { | ||
377 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
378 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
379 | return new BulletBodyUnman(id, BSAPICPP.CreateBodyFromShape2(worldu.ptr, shapeu.ptr, id, pos, rot)); | ||
380 | } | ||
381 | |||
382 | public override BulletBody CreateBodyWithDefaultMotionState(BulletShape shape, uint id, Vector3 pos, Quaternion rot) | ||
383 | { | ||
384 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
385 | return new BulletBodyUnman(id, BSAPICPP.CreateBodyWithDefaultMotionState2(shapeu.ptr, id, pos, rot)); | ||
386 | } | ||
387 | |||
388 | public override BulletBody CreateGhostFromShape(BulletWorld world, BulletShape shape, uint id, Vector3 pos, Quaternion rot) | ||
389 | { | ||
390 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
391 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
392 | return new BulletBodyUnman(id, BSAPICPP.CreateGhostFromShape2(worldu.ptr, shapeu.ptr, id, pos, rot)); | ||
393 | } | ||
394 | |||
395 | public override void DestroyObject(BulletWorld world, BulletBody obj) | ||
396 | { | ||
397 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
398 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
399 | BSAPICPP.DestroyObject2(worldu.ptr, bodyu.ptr); | ||
400 | } | ||
401 | |||
402 | // ===================================================================================== | ||
403 | // Terrain creation and helper routines | ||
404 | public override BulletShape CreateGroundPlaneShape(uint id, float height, float collisionMargin) | ||
405 | { | ||
406 | return new BulletShapeUnman(BSAPICPP.CreateGroundPlaneShape2(id, height, collisionMargin), BSPhysicsShapeType.SHAPE_GROUNDPLANE); | ||
407 | } | ||
408 | |||
409 | public override BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap, | ||
410 | float scaleFactor, float collisionMargin) | ||
411 | { | ||
412 | return new BulletShapeUnman(BSAPICPP.CreateTerrainShape2(id, size, minHeight, maxHeight, heightMap, scaleFactor, collisionMargin), | ||
413 | BSPhysicsShapeType.SHAPE_TERRAIN); | ||
414 | } | ||
415 | |||
416 | // ===================================================================================== | ||
417 | // Constraint creation and helper routines | ||
418 | public override BulletConstraint Create6DofConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
419 | Vector3 frame1loc, Quaternion frame1rot, | ||
420 | Vector3 frame2loc, Quaternion frame2rot, | ||
421 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) | ||
422 | { | ||
423 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
424 | BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; | ||
425 | BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman; | ||
426 | return new BulletConstraintUnman(BSAPICPP.Create6DofConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot, | ||
427 | frame2loc, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); | ||
428 | } | ||
429 | |||
430 | public override BulletConstraint Create6DofConstraintToPoint(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
431 | Vector3 joinPoint, | ||
432 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) | ||
433 | { | ||
434 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
435 | BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; | ||
436 | BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman; | ||
437 | return new BulletConstraintUnman(BSAPICPP.Create6DofConstraintToPoint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, | ||
438 | joinPoint, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); | ||
439 | } | ||
440 | |||
441 | public override BulletConstraint Create6DofConstraintFixed(BulletWorld world, BulletBody obj1, | ||
442 | Vector3 frameInBloc, Quaternion frameInBrot, | ||
443 | bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies) | ||
444 | { | ||
445 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
446 | BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; | ||
447 | return new BulletConstraintUnman(BSAPICPP.Create6DofConstraintFixed2(worldu.ptr, bodyu1.ptr, | ||
448 | frameInBloc, frameInBrot, useLinearReferenceFrameB, disableCollisionsBetweenLinkedBodies)); | ||
449 | } | ||
450 | |||
451 | public override BulletConstraint Create6DofSpringConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
452 | Vector3 frame1loc, Quaternion frame1rot, | ||
453 | Vector3 frame2loc, Quaternion frame2rot, | ||
454 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) | ||
455 | { | ||
456 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
457 | BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; | ||
458 | BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman; | ||
459 | return new BulletConstraintUnman(BSAPICPP.Create6DofSpringConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot, | ||
460 | frame2loc, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); | ||
461 | } | ||
462 | |||
463 | public override BulletConstraint CreateHingeConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
464 | Vector3 pivotinA, Vector3 pivotinB, | ||
465 | Vector3 axisInA, Vector3 axisInB, | ||
466 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) | ||
467 | { | ||
468 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
469 | BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; | ||
470 | BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman; | ||
471 | return new BulletConstraintUnman(BSAPICPP.CreateHingeConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, | ||
472 | pivotinA, pivotinB, axisInA, axisInB, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); | ||
473 | } | ||
474 | |||
475 | public override BulletConstraint CreateSliderConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
476 | Vector3 frame1loc, Quaternion frame1rot, | ||
477 | Vector3 frame2loc, Quaternion frame2rot, | ||
478 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) | ||
479 | { | ||
480 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
481 | BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; | ||
482 | BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman; | ||
483 | return new BulletConstraintUnman(BSAPICPP.CreateSliderConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot, | ||
484 | frame2loc, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); | ||
485 | } | ||
486 | |||
487 | public override BulletConstraint CreateConeTwistConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
488 | Vector3 frame1loc, Quaternion frame1rot, | ||
489 | Vector3 frame2loc, Quaternion frame2rot, | ||
490 | bool disableCollisionsBetweenLinkedBodies) | ||
491 | { | ||
492 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
493 | BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; | ||
494 | BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman; | ||
495 | return new BulletConstraintUnman(BSAPICPP.CreateConeTwistConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot, | ||
496 | frame2loc, frame2rot, disableCollisionsBetweenLinkedBodies)); | ||
497 | } | ||
498 | |||
499 | public override BulletConstraint CreateGearConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
500 | Vector3 axisInA, Vector3 axisInB, | ||
501 | float ratio, bool disableCollisionsBetweenLinkedBodies) | ||
502 | { | ||
503 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
504 | BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; | ||
505 | BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman; | ||
506 | return new BulletConstraintUnman(BSAPICPP.CreateGearConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, axisInA, axisInB, | ||
507 | ratio, disableCollisionsBetweenLinkedBodies)); | ||
508 | } | ||
509 | |||
510 | public override BulletConstraint CreatePoint2PointConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
511 | Vector3 pivotInA, Vector3 pivotInB, | ||
512 | bool disableCollisionsBetweenLinkedBodies) | ||
513 | { | ||
514 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
515 | BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; | ||
516 | BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman; | ||
517 | return new BulletConstraintUnman(BSAPICPP.CreatePoint2PointConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, pivotInA, pivotInB, | ||
518 | disableCollisionsBetweenLinkedBodies)); | ||
519 | } | ||
520 | |||
521 | public override void SetConstraintEnable(BulletConstraint constrain, float numericTrueFalse) | ||
522 | { | ||
523 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
524 | BSAPICPP.SetConstraintEnable2(constrainu.ptr, numericTrueFalse); | ||
525 | } | ||
526 | |||
527 | public override void SetConstraintNumSolverIterations(BulletConstraint constrain, float iterations) | ||
528 | { | ||
529 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
530 | BSAPICPP.SetConstraintNumSolverIterations2(constrainu.ptr, iterations); | ||
531 | } | ||
532 | |||
533 | public override bool SetFrames(BulletConstraint constrain, | ||
534 | Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot) | ||
535 | { | ||
536 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
537 | return BSAPICPP.SetFrames2(constrainu.ptr, frameA, frameArot, frameB, frameBrot); | ||
538 | } | ||
539 | |||
540 | public override bool SetLinearLimits(BulletConstraint constrain, Vector3 low, Vector3 hi) | ||
541 | { | ||
542 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
543 | return BSAPICPP.SetLinearLimits2(constrainu.ptr, low, hi); | ||
544 | } | ||
545 | |||
546 | public override bool SetAngularLimits(BulletConstraint constrain, Vector3 low, Vector3 hi) | ||
547 | { | ||
548 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
549 | return BSAPICPP.SetAngularLimits2(constrainu.ptr, low, hi); | ||
550 | } | ||
551 | |||
552 | public override bool UseFrameOffset(BulletConstraint constrain, float enable) | ||
553 | { | ||
554 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
555 | return BSAPICPP.UseFrameOffset2(constrainu.ptr, enable); | ||
556 | } | ||
557 | |||
558 | public override bool TranslationalLimitMotor(BulletConstraint constrain, float enable, float targetVel, float maxMotorForce) | ||
559 | { | ||
560 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
561 | return BSAPICPP.TranslationalLimitMotor2(constrainu.ptr, enable, targetVel, maxMotorForce); | ||
562 | } | ||
563 | |||
564 | public override bool SetBreakingImpulseThreshold(BulletConstraint constrain, float threshold) | ||
565 | { | ||
566 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
567 | return BSAPICPP.SetBreakingImpulseThreshold2(constrainu.ptr, threshold); | ||
568 | } | ||
569 | |||
570 | public override bool CalculateTransforms(BulletConstraint constrain) | ||
571 | { | ||
572 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
573 | return BSAPICPP.CalculateTransforms2(constrainu.ptr); | ||
574 | } | ||
575 | |||
576 | public override bool SetConstraintParam(BulletConstraint constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis) | ||
577 | { | ||
578 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
579 | return BSAPICPP.SetConstraintParam2(constrainu.ptr, paramIndex, value, axis); | ||
580 | } | ||
581 | |||
582 | public override bool DestroyConstraint(BulletWorld world, BulletConstraint constrain) | ||
583 | { | ||
584 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
585 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
586 | return BSAPICPP.DestroyConstraint2(worldu.ptr, constrainu.ptr); | ||
587 | } | ||
588 | |||
589 | // ===================================================================================== | ||
590 | // btCollisionWorld entries | ||
591 | public override void UpdateSingleAabb(BulletWorld world, BulletBody obj) | ||
592 | { | ||
593 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
594 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
595 | BSAPICPP.UpdateSingleAabb2(worldu.ptr, bodyu.ptr); | ||
596 | } | ||
597 | |||
598 | public override void UpdateAabbs(BulletWorld world) | ||
599 | { | ||
600 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
601 | BSAPICPP.UpdateAabbs2(worldu.ptr); | ||
602 | } | ||
603 | |||
604 | public override bool GetForceUpdateAllAabbs(BulletWorld world) | ||
605 | { | ||
606 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
607 | return BSAPICPP.GetForceUpdateAllAabbs2(worldu.ptr); | ||
608 | } | ||
609 | |||
610 | public override void SetForceUpdateAllAabbs(BulletWorld world, bool force) | ||
611 | { | ||
612 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
613 | BSAPICPP.SetForceUpdateAllAabbs2(worldu.ptr, force); | ||
614 | } | ||
615 | |||
616 | // ===================================================================================== | ||
617 | // btDynamicsWorld entries | ||
618 | public override bool AddObjectToWorld(BulletWorld world, BulletBody obj) | ||
619 | { | ||
620 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
621 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
622 | |||
623 | // Bullet resets several variables when an object is added to the world. | ||
624 | // Gravity is reset to world default depending on the static/dynamic | ||
625 | // type. Of course, the collision flags in the broadphase proxy are initialized to default. | ||
626 | Vector3 origGrav = BSAPICPP.GetGravity2(bodyu.ptr); | ||
627 | |||
628 | bool ret = BSAPICPP.AddObjectToWorld2(worldu.ptr, bodyu.ptr); | ||
629 | |||
630 | if (ret) | ||
631 | { | ||
632 | BSAPICPP.SetGravity2(bodyu.ptr, origGrav); | ||
633 | obj.ApplyCollisionMask(world.physicsScene); | ||
634 | } | ||
635 | return ret; | ||
636 | } | ||
637 | |||
638 | public override bool RemoveObjectFromWorld(BulletWorld world, BulletBody obj) | ||
639 | { | ||
640 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
641 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
642 | return BSAPICPP.RemoveObjectFromWorld2(worldu.ptr, bodyu.ptr); | ||
643 | } | ||
644 | |||
645 | public override bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects) | ||
646 | { | ||
647 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
648 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
649 | return BSAPICPP.AddConstraintToWorld2(worldu.ptr, constrainu.ptr, disableCollisionsBetweenLinkedObjects); | ||
650 | } | ||
651 | |||
652 | public override bool RemoveConstraintFromWorld(BulletWorld world, BulletConstraint constrain) | ||
653 | { | ||
654 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
655 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
656 | return BSAPICPP.RemoveConstraintFromWorld2(worldu.ptr, constrainu.ptr); | ||
657 | } | ||
658 | // ===================================================================================== | ||
659 | // btCollisionObject entries | ||
660 | public override Vector3 GetAnisotripicFriction(BulletConstraint constrain) | ||
661 | { | ||
662 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
663 | return BSAPICPP.GetAnisotripicFriction2(constrainu.ptr); | ||
664 | } | ||
665 | |||
666 | public override Vector3 SetAnisotripicFriction(BulletConstraint constrain, Vector3 frict) | ||
667 | { | ||
668 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
669 | return BSAPICPP.SetAnisotripicFriction2(constrainu.ptr, frict); | ||
670 | } | ||
671 | |||
672 | public override bool HasAnisotripicFriction(BulletConstraint constrain) | ||
673 | { | ||
674 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
675 | return BSAPICPP.HasAnisotripicFriction2(constrainu.ptr); | ||
676 | } | ||
677 | |||
678 | public override void SetContactProcessingThreshold(BulletBody obj, float val) | ||
679 | { | ||
680 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
681 | BSAPICPP.SetContactProcessingThreshold2(bodyu.ptr, val); | ||
682 | } | ||
683 | |||
684 | public override float GetContactProcessingThreshold(BulletBody obj) | ||
685 | { | ||
686 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
687 | return BSAPICPP.GetContactProcessingThreshold2(bodyu.ptr); | ||
688 | } | ||
689 | |||
690 | public override bool IsStaticObject(BulletBody obj) | ||
691 | { | ||
692 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
693 | return BSAPICPP.IsStaticObject2(bodyu.ptr); | ||
694 | } | ||
695 | |||
696 | public override bool IsKinematicObject(BulletBody obj) | ||
697 | { | ||
698 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
699 | return BSAPICPP.IsKinematicObject2(bodyu.ptr); | ||
700 | } | ||
701 | |||
702 | public override bool IsStaticOrKinematicObject(BulletBody obj) | ||
703 | { | ||
704 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
705 | return BSAPICPP.IsStaticOrKinematicObject2(bodyu.ptr); | ||
706 | } | ||
707 | |||
708 | public override bool HasContactResponse(BulletBody obj) | ||
709 | { | ||
710 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
711 | return BSAPICPP.HasContactResponse2(bodyu.ptr); | ||
712 | } | ||
713 | |||
714 | public override void SetCollisionShape(BulletWorld world, BulletBody obj, BulletShape shape) | ||
715 | { | ||
716 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
717 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
718 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
719 | if (worldu != null && bodyu != null) | ||
720 | { | ||
721 | // Special case to allow the caller to zero out the reference to any physical shape | ||
722 | if (shapeu != null) | ||
723 | BSAPICPP.SetCollisionShape2(worldu.ptr, bodyu.ptr, shapeu.ptr); | ||
724 | else | ||
725 | BSAPICPP.SetCollisionShape2(worldu.ptr, bodyu.ptr, IntPtr.Zero); | ||
726 | } | ||
727 | } | ||
728 | |||
729 | public override BulletShape GetCollisionShape(BulletBody obj) | ||
730 | { | ||
731 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
732 | return new BulletShapeUnman(BSAPICPP.GetCollisionShape2(bodyu.ptr), BSPhysicsShapeType.SHAPE_UNKNOWN); | ||
733 | } | ||
734 | |||
735 | public override int GetActivationState(BulletBody obj) | ||
736 | { | ||
737 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
738 | return BSAPICPP.GetActivationState2(bodyu.ptr); | ||
739 | } | ||
740 | |||
741 | public override void SetActivationState(BulletBody obj, int state) | ||
742 | { | ||
743 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
744 | BSAPICPP.SetActivationState2(bodyu.ptr, state); | ||
745 | } | ||
746 | |||
747 | public override void SetDeactivationTime(BulletBody obj, float dtime) | ||
748 | { | ||
749 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
750 | BSAPICPP.SetDeactivationTime2(bodyu.ptr, dtime); | ||
751 | } | ||
752 | |||
753 | public override float GetDeactivationTime(BulletBody obj) | ||
754 | { | ||
755 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
756 | return BSAPICPP.GetDeactivationTime2(bodyu.ptr); | ||
757 | } | ||
758 | |||
759 | public override void ForceActivationState(BulletBody obj, ActivationState state) | ||
760 | { | ||
761 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
762 | BSAPICPP.ForceActivationState2(bodyu.ptr, state); | ||
763 | } | ||
764 | |||
765 | public override void Activate(BulletBody obj, bool forceActivation) | ||
766 | { | ||
767 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
768 | BSAPICPP.Activate2(bodyu.ptr, forceActivation); | ||
769 | } | ||
770 | |||
771 | public override bool IsActive(BulletBody obj) | ||
772 | { | ||
773 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
774 | return BSAPICPP.IsActive2(bodyu.ptr); | ||
775 | } | ||
776 | |||
777 | public override void SetRestitution(BulletBody obj, float val) | ||
778 | { | ||
779 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
780 | BSAPICPP.SetRestitution2(bodyu.ptr, val); | ||
781 | } | ||
782 | |||
783 | public override float GetRestitution(BulletBody obj) | ||
784 | { | ||
785 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
786 | return BSAPICPP.GetRestitution2(bodyu.ptr); | ||
787 | } | ||
788 | |||
789 | public override void SetFriction(BulletBody obj, float val) | ||
790 | { | ||
791 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
792 | BSAPICPP.SetFriction2(bodyu.ptr, val); | ||
793 | } | ||
794 | |||
795 | public override float GetFriction(BulletBody obj) | ||
796 | { | ||
797 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
798 | return BSAPICPP.GetFriction2(bodyu.ptr); | ||
799 | } | ||
800 | |||
801 | public override Vector3 GetPosition(BulletBody obj) | ||
802 | { | ||
803 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
804 | return BSAPICPP.GetPosition2(bodyu.ptr); | ||
805 | } | ||
806 | |||
807 | public override Quaternion GetOrientation(BulletBody obj) | ||
808 | { | ||
809 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
810 | return BSAPICPP.GetOrientation2(bodyu.ptr); | ||
811 | } | ||
812 | |||
813 | public override void SetTranslation(BulletBody obj, Vector3 position, Quaternion rotation) | ||
814 | { | ||
815 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
816 | BSAPICPP.SetTranslation2(bodyu.ptr, position, rotation); | ||
817 | } | ||
818 | |||
819 | /* | ||
820 | public override IntPtr GetBroadphaseHandle(BulletBody obj) | ||
821 | { | ||
822 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
823 | return BSAPICPP.GetBroadphaseHandle2(bodyu.ptr); | ||
824 | } | ||
825 | |||
826 | public override void SetBroadphaseHandle(BulletBody obj, IntPtr handle) | ||
827 | { | ||
828 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
829 | BSAPICPP.SetUserPointer2(bodyu.ptr, handle); | ||
830 | } | ||
831 | */ | ||
832 | |||
833 | public override void SetInterpolationLinearVelocity(BulletBody obj, Vector3 vel) | ||
834 | { | ||
835 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
836 | BSAPICPP.SetInterpolationLinearVelocity2(bodyu.ptr, vel); | ||
837 | } | ||
838 | |||
839 | public override void SetInterpolationAngularVelocity(BulletBody obj, Vector3 vel) | ||
840 | { | ||
841 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
842 | BSAPICPP.SetInterpolationAngularVelocity2(bodyu.ptr, vel); | ||
843 | } | ||
844 | |||
845 | public override void SetInterpolationVelocity(BulletBody obj, Vector3 linearVel, Vector3 angularVel) | ||
846 | { | ||
847 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
848 | BSAPICPP.SetInterpolationVelocity2(bodyu.ptr, linearVel, angularVel); | ||
849 | } | ||
850 | |||
851 | public override float GetHitFraction(BulletBody obj) | ||
852 | { | ||
853 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
854 | return BSAPICPP.GetHitFraction2(bodyu.ptr); | ||
855 | } | ||
856 | |||
857 | public override void SetHitFraction(BulletBody obj, float val) | ||
858 | { | ||
859 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
860 | BSAPICPP.SetHitFraction2(bodyu.ptr, val); | ||
861 | } | ||
862 | |||
863 | public override CollisionFlags GetCollisionFlags(BulletBody obj) | ||
864 | { | ||
865 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
866 | return BSAPICPP.GetCollisionFlags2(bodyu.ptr); | ||
867 | } | ||
868 | |||
869 | public override CollisionFlags SetCollisionFlags(BulletBody obj, CollisionFlags flags) | ||
870 | { | ||
871 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
872 | return BSAPICPP.SetCollisionFlags2(bodyu.ptr, flags); | ||
873 | } | ||
874 | |||
875 | public override CollisionFlags AddToCollisionFlags(BulletBody obj, CollisionFlags flags) | ||
876 | { | ||
877 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
878 | return BSAPICPP.AddToCollisionFlags2(bodyu.ptr, flags); | ||
879 | } | ||
880 | |||
881 | public override CollisionFlags RemoveFromCollisionFlags(BulletBody obj, CollisionFlags flags) | ||
882 | { | ||
883 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
884 | return BSAPICPP.RemoveFromCollisionFlags2(bodyu.ptr, flags); | ||
885 | } | ||
886 | |||
887 | public override float GetCcdMotionThreshold(BulletBody obj) | ||
888 | { | ||
889 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
890 | return BSAPICPP.GetCcdMotionThreshold2(bodyu.ptr); | ||
891 | } | ||
892 | |||
893 | |||
894 | public override void SetCcdMotionThreshold(BulletBody obj, float val) | ||
895 | { | ||
896 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
897 | BSAPICPP.SetCcdMotionThreshold2(bodyu.ptr, val); | ||
898 | } | ||
899 | |||
900 | public override float GetCcdSweptSphereRadius(BulletBody obj) | ||
901 | { | ||
902 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
903 | return BSAPICPP.GetCcdSweptSphereRadius2(bodyu.ptr); | ||
904 | } | ||
905 | |||
906 | public override void SetCcdSweptSphereRadius(BulletBody obj, float val) | ||
907 | { | ||
908 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
909 | BSAPICPP.SetCcdSweptSphereRadius2(bodyu.ptr, val); | ||
910 | } | ||
911 | |||
912 | public override IntPtr GetUserPointer(BulletBody obj) | ||
913 | { | ||
914 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
915 | return BSAPICPP.GetUserPointer2(bodyu.ptr); | ||
916 | } | ||
917 | |||
918 | public override void SetUserPointer(BulletBody obj, IntPtr val) | ||
919 | { | ||
920 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
921 | BSAPICPP.SetUserPointer2(bodyu.ptr, val); | ||
922 | } | ||
923 | |||
924 | // ===================================================================================== | ||
925 | // btRigidBody entries | ||
926 | public override void ApplyGravity(BulletBody obj) | ||
927 | { | ||
928 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
929 | BSAPICPP.ApplyGravity2(bodyu.ptr); | ||
930 | } | ||
931 | |||
932 | public override void SetGravity(BulletBody obj, Vector3 val) | ||
933 | { | ||
934 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
935 | BSAPICPP.SetGravity2(bodyu.ptr, val); | ||
936 | } | ||
937 | |||
938 | public override Vector3 GetGravity(BulletBody obj) | ||
939 | { | ||
940 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
941 | return BSAPICPP.GetGravity2(bodyu.ptr); | ||
942 | } | ||
943 | |||
944 | public override void SetDamping(BulletBody obj, float lin_damping, float ang_damping) | ||
945 | { | ||
946 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
947 | BSAPICPP.SetDamping2(bodyu.ptr, lin_damping, ang_damping); | ||
948 | } | ||
949 | |||
950 | public override void SetLinearDamping(BulletBody obj, float lin_damping) | ||
951 | { | ||
952 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
953 | BSAPICPP.SetLinearDamping2(bodyu.ptr, lin_damping); | ||
954 | } | ||
955 | |||
956 | public override void SetAngularDamping(BulletBody obj, float ang_damping) | ||
957 | { | ||
958 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
959 | BSAPICPP.SetAngularDamping2(bodyu.ptr, ang_damping); | ||
960 | } | ||
961 | |||
962 | public override float GetLinearDamping(BulletBody obj) | ||
963 | { | ||
964 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
965 | return BSAPICPP.GetLinearDamping2(bodyu.ptr); | ||
966 | } | ||
967 | |||
968 | public override float GetAngularDamping(BulletBody obj) | ||
969 | { | ||
970 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
971 | return BSAPICPP.GetAngularDamping2(bodyu.ptr); | ||
972 | } | ||
973 | |||
974 | public override float GetLinearSleepingThreshold(BulletBody obj) | ||
975 | { | ||
976 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
977 | return BSAPICPP.GetLinearSleepingThreshold2(bodyu.ptr); | ||
978 | } | ||
979 | |||
980 | public override void ApplyDamping(BulletBody obj, float timeStep) | ||
981 | { | ||
982 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
983 | BSAPICPP.ApplyDamping2(bodyu.ptr, timeStep); | ||
984 | } | ||
985 | |||
986 | public override void SetMassProps(BulletBody obj, float mass, Vector3 inertia) | ||
987 | { | ||
988 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
989 | BSAPICPP.SetMassProps2(bodyu.ptr, mass, inertia); | ||
990 | } | ||
991 | |||
992 | public override Vector3 GetLinearFactor(BulletBody obj) | ||
993 | { | ||
994 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
995 | return BSAPICPP.GetLinearFactor2(bodyu.ptr); | ||
996 | } | ||
997 | |||
998 | public override void SetLinearFactor(BulletBody obj, Vector3 factor) | ||
999 | { | ||
1000 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1001 | BSAPICPP.SetLinearFactor2(bodyu.ptr, factor); | ||
1002 | } | ||
1003 | |||
1004 | public override void SetCenterOfMassByPosRot(BulletBody obj, Vector3 pos, Quaternion rot) | ||
1005 | { | ||
1006 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1007 | BSAPICPP.SetCenterOfMassByPosRot2(bodyu.ptr, pos, rot); | ||
1008 | } | ||
1009 | |||
1010 | // Add a force to the object as if its mass is one. | ||
1011 | // Deep down in Bullet: m_totalForce += force*m_linearFactor; | ||
1012 | public override void ApplyCentralForce(BulletBody obj, Vector3 force) | ||
1013 | { | ||
1014 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1015 | BSAPICPP.ApplyCentralForce2(bodyu.ptr, force); | ||
1016 | } | ||
1017 | |||
1018 | // Set the force being applied to the object as if its mass is one. | ||
1019 | public override void SetObjectForce(BulletBody obj, Vector3 force) | ||
1020 | { | ||
1021 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1022 | BSAPICPP.SetObjectForce2(bodyu.ptr, force); | ||
1023 | } | ||
1024 | |||
1025 | public override Vector3 GetTotalForce(BulletBody obj) | ||
1026 | { | ||
1027 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1028 | return BSAPICPP.GetTotalForce2(bodyu.ptr); | ||
1029 | } | ||
1030 | |||
1031 | public override Vector3 GetTotalTorque(BulletBody obj) | ||
1032 | { | ||
1033 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1034 | return BSAPICPP.GetTotalTorque2(bodyu.ptr); | ||
1035 | } | ||
1036 | |||
1037 | public override Vector3 GetInvInertiaDiagLocal(BulletBody obj) | ||
1038 | { | ||
1039 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1040 | return BSAPICPP.GetInvInertiaDiagLocal2(bodyu.ptr); | ||
1041 | } | ||
1042 | |||
1043 | public override void SetInvInertiaDiagLocal(BulletBody obj, Vector3 inert) | ||
1044 | { | ||
1045 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1046 | BSAPICPP.SetInvInertiaDiagLocal2(bodyu.ptr, inert); | ||
1047 | } | ||
1048 | |||
1049 | public override void SetSleepingThresholds(BulletBody obj, float lin_threshold, float ang_threshold) | ||
1050 | { | ||
1051 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1052 | BSAPICPP.SetSleepingThresholds2(bodyu.ptr, lin_threshold, ang_threshold); | ||
1053 | } | ||
1054 | |||
1055 | // Deep down in Bullet: m_totalTorque += torque*m_angularFactor; | ||
1056 | public override void ApplyTorque(BulletBody obj, Vector3 torque) | ||
1057 | { | ||
1058 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1059 | BSAPICPP.ApplyTorque2(bodyu.ptr, torque); | ||
1060 | } | ||
1061 | |||
1062 | // Apply force at the given point. Will add torque to the object. | ||
1063 | // Deep down in Bullet: applyCentralForce(force); | ||
1064 | // applyTorque(rel_pos.cross(force*m_linearFactor)); | ||
1065 | public override void ApplyForce(BulletBody obj, Vector3 force, Vector3 pos) | ||
1066 | { | ||
1067 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1068 | BSAPICPP.ApplyForce2(bodyu.ptr, force, pos); | ||
1069 | } | ||
1070 | |||
1071 | // Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass. | ||
1072 | // Deep down in Bullet: m_linearVelocity += impulse *m_linearFactor * m_inverseMass; | ||
1073 | public override void ApplyCentralImpulse(BulletBody obj, Vector3 imp) | ||
1074 | { | ||
1075 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1076 | BSAPICPP.ApplyCentralImpulse2(bodyu.ptr, imp); | ||
1077 | } | ||
1078 | |||
1079 | // Apply impulse to the object's torque. Force is scaled by object's mass. | ||
1080 | // Deep down in Bullet: m_angularVelocity += m_invInertiaTensorWorld * torque * m_angularFactor; | ||
1081 | public override void ApplyTorqueImpulse(BulletBody obj, Vector3 imp) | ||
1082 | { | ||
1083 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1084 | BSAPICPP.ApplyTorqueImpulse2(bodyu.ptr, imp); | ||
1085 | } | ||
1086 | |||
1087 | // Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces. | ||
1088 | // Deep down in Bullet: applyCentralImpulse(impulse); | ||
1089 | // applyTorqueImpulse(rel_pos.cross(impulse*m_linearFactor)); | ||
1090 | public override void ApplyImpulse(BulletBody obj, Vector3 imp, Vector3 pos) | ||
1091 | { | ||
1092 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1093 | BSAPICPP.ApplyImpulse2(bodyu.ptr, imp, pos); | ||
1094 | } | ||
1095 | |||
1096 | public override void ClearForces(BulletBody obj) | ||
1097 | { | ||
1098 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1099 | BSAPICPP.ClearForces2(bodyu.ptr); | ||
1100 | } | ||
1101 | |||
1102 | public override void ClearAllForces(BulletBody obj) | ||
1103 | { | ||
1104 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1105 | BSAPICPP.ClearAllForces2(bodyu.ptr); | ||
1106 | } | ||
1107 | |||
1108 | public override void UpdateInertiaTensor(BulletBody obj) | ||
1109 | { | ||
1110 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1111 | BSAPICPP.UpdateInertiaTensor2(bodyu.ptr); | ||
1112 | } | ||
1113 | |||
1114 | public override Vector3 GetLinearVelocity(BulletBody obj) | ||
1115 | { | ||
1116 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1117 | return BSAPICPP.GetLinearVelocity2(bodyu.ptr); | ||
1118 | } | ||
1119 | |||
1120 | public override Vector3 GetAngularVelocity(BulletBody obj) | ||
1121 | { | ||
1122 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1123 | return BSAPICPP.GetAngularVelocity2(bodyu.ptr); | ||
1124 | } | ||
1125 | |||
1126 | public override void SetLinearVelocity(BulletBody obj, Vector3 vel) | ||
1127 | { | ||
1128 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1129 | BSAPICPP.SetLinearVelocity2(bodyu.ptr, vel); | ||
1130 | } | ||
1131 | |||
1132 | public override void SetAngularVelocity(BulletBody obj, Vector3 angularVelocity) | ||
1133 | { | ||
1134 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1135 | BSAPICPP.SetAngularVelocity2(bodyu.ptr, angularVelocity); | ||
1136 | } | ||
1137 | |||
1138 | public override Vector3 GetVelocityInLocalPoint(BulletBody obj, Vector3 pos) | ||
1139 | { | ||
1140 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1141 | return BSAPICPP.GetVelocityInLocalPoint2(bodyu.ptr, pos); | ||
1142 | } | ||
1143 | |||
1144 | public override void Translate(BulletBody obj, Vector3 trans) | ||
1145 | { | ||
1146 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1147 | BSAPICPP.Translate2(bodyu.ptr, trans); | ||
1148 | } | ||
1149 | |||
1150 | public override void UpdateDeactivation(BulletBody obj, float timeStep) | ||
1151 | { | ||
1152 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1153 | BSAPICPP.UpdateDeactivation2(bodyu.ptr, timeStep); | ||
1154 | } | ||
1155 | |||
1156 | public override bool WantsSleeping(BulletBody obj) | ||
1157 | { | ||
1158 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1159 | return BSAPICPP.WantsSleeping2(bodyu.ptr); | ||
1160 | } | ||
1161 | |||
1162 | public override void SetAngularFactor(BulletBody obj, float factor) | ||
1163 | { | ||
1164 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1165 | BSAPICPP.SetAngularFactor2(bodyu.ptr, factor); | ||
1166 | } | ||
1167 | |||
1168 | public override void SetAngularFactorV(BulletBody obj, Vector3 factor) | ||
1169 | { | ||
1170 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1171 | BSAPICPP.SetAngularFactorV2(bodyu.ptr, factor); | ||
1172 | } | ||
1173 | |||
1174 | public override Vector3 GetAngularFactor(BulletBody obj) | ||
1175 | { | ||
1176 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1177 | return BSAPICPP.GetAngularFactor2(bodyu.ptr); | ||
1178 | } | ||
1179 | |||
1180 | public override bool IsInWorld(BulletWorld world, BulletBody obj) | ||
1181 | { | ||
1182 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1183 | return BSAPICPP.IsInWorld2(bodyu.ptr); | ||
1184 | } | ||
1185 | |||
1186 | public override void AddConstraintRef(BulletBody obj, BulletConstraint constrain) | ||
1187 | { | ||
1188 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1189 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
1190 | BSAPICPP.AddConstraintRef2(bodyu.ptr, constrainu.ptr); | ||
1191 | } | ||
1192 | |||
1193 | public override void RemoveConstraintRef(BulletBody obj, BulletConstraint constrain) | ||
1194 | { | ||
1195 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1196 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
1197 | BSAPICPP.RemoveConstraintRef2(bodyu.ptr, constrainu.ptr); | ||
1198 | } | ||
1199 | |||
1200 | public override BulletConstraint GetConstraintRef(BulletBody obj, int index) | ||
1201 | { | ||
1202 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1203 | return new BulletConstraintUnman(BSAPICPP.GetConstraintRef2(bodyu.ptr, index)); | ||
1204 | } | ||
1205 | |||
1206 | public override int GetNumConstraintRefs(BulletBody obj) | ||
1207 | { | ||
1208 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1209 | return BSAPICPP.GetNumConstraintRefs2(bodyu.ptr); | ||
1210 | } | ||
1211 | |||
1212 | public override bool SetCollisionGroupMask(BulletBody body, uint filter, uint mask) | ||
1213 | { | ||
1214 | BulletBodyUnman bodyu = body as BulletBodyUnman; | ||
1215 | return BSAPICPP.SetCollisionGroupMask2(bodyu.ptr, filter, mask); | ||
1216 | } | ||
1217 | |||
1218 | // ===================================================================================== | ||
1219 | // btCollisionShape entries | ||
1220 | |||
1221 | public override float GetAngularMotionDisc(BulletShape shape) | ||
1222 | { | ||
1223 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
1224 | return BSAPICPP.GetAngularMotionDisc2(shapeu.ptr); | ||
1225 | } | ||
1226 | |||
1227 | public override float GetContactBreakingThreshold(BulletShape shape, float defaultFactor) | ||
1228 | { | ||
1229 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
1230 | return BSAPICPP.GetContactBreakingThreshold2(shapeu.ptr, defaultFactor); | ||
1231 | } | ||
1232 | |||
1233 | public override bool IsPolyhedral(BulletShape shape) | ||
1234 | { | ||
1235 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
1236 | return BSAPICPP.IsPolyhedral2(shapeu.ptr); | ||
1237 | } | ||
1238 | |||
1239 | public override bool IsConvex2d(BulletShape shape) | ||
1240 | { | ||
1241 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
1242 | return BSAPICPP.IsConvex2d2(shapeu.ptr); | ||
1243 | } | ||
1244 | |||
1245 | public override bool IsConvex(BulletShape shape) | ||
1246 | { | ||
1247 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
1248 | return BSAPICPP.IsConvex2(shapeu.ptr); | ||
1249 | } | ||
1250 | |||
1251 | public override bool IsNonMoving(BulletShape shape) | ||
1252 | { | ||
1253 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
1254 | return BSAPICPP.IsNonMoving2(shapeu.ptr); | ||
1255 | } | ||
1256 | |||
1257 | public override bool IsConcave(BulletShape shape) | ||
1258 | { | ||
1259 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
1260 | return BSAPICPP.IsConcave2(shapeu.ptr); | ||
1261 | } | ||
1262 | |||
1263 | public override bool IsCompound(BulletShape shape) | ||
1264 | { | ||
1265 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
1266 | return BSAPICPP.IsCompound2(shapeu.ptr); | ||
1267 | } | ||
1268 | |||
1269 | public override bool IsSoftBody(BulletShape shape) | ||
1270 | { | ||
1271 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
1272 | return BSAPICPP.IsSoftBody2(shapeu.ptr); | ||
1273 | } | ||
1274 | |||
1275 | public override bool IsInfinite(BulletShape shape) | ||
1276 | { | ||
1277 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
1278 | return BSAPICPP.IsInfinite2(shapeu.ptr); | ||
1279 | } | ||
1280 | |||
1281 | public override void SetLocalScaling(BulletShape shape, Vector3 scale) | ||
1282 | { | ||
1283 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
1284 | BSAPICPP.SetLocalScaling2(shapeu.ptr, scale); | ||
1285 | } | ||
1286 | |||
1287 | public override Vector3 GetLocalScaling(BulletShape shape) | ||
1288 | { | ||
1289 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
1290 | return BSAPICPP.GetLocalScaling2(shapeu.ptr); | ||
1291 | } | ||
1292 | |||
1293 | public override Vector3 CalculateLocalInertia(BulletShape shape, float mass) | ||
1294 | { | ||
1295 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
1296 | return BSAPICPP.CalculateLocalInertia2(shapeu.ptr, mass); | ||
1297 | } | ||
1298 | |||
1299 | public override int GetShapeType(BulletShape shape) | ||
1300 | { | ||
1301 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
1302 | return BSAPICPP.GetShapeType2(shapeu.ptr); | ||
1303 | } | ||
1304 | |||
1305 | public override void SetMargin(BulletShape shape, float val) | ||
1306 | { | ||
1307 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
1308 | BSAPICPP.SetMargin2(shapeu.ptr, val); | ||
1309 | } | ||
1310 | |||
1311 | public override float GetMargin(BulletShape shape) | ||
1312 | { | ||
1313 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
1314 | return BSAPICPP.GetMargin2(shapeu.ptr); | ||
1315 | } | ||
1316 | |||
1317 | // ===================================================================================== | ||
1318 | // Debugging | ||
1319 | public override void DumpRigidBody(BulletWorld world, BulletBody collisionObject) | ||
1320 | { | ||
1321 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
1322 | BulletBodyUnman bodyu = collisionObject as BulletBodyUnman; | ||
1323 | BSAPICPP.DumpRigidBody2(worldu.ptr, bodyu.ptr); | ||
1324 | } | ||
1325 | |||
1326 | public override void DumpCollisionShape(BulletWorld world, BulletShape collisionShape) | ||
1327 | { | ||
1328 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
1329 | BulletShapeUnman shapeu = collisionShape as BulletShapeUnman; | ||
1330 | BSAPICPP.DumpCollisionShape2(worldu.ptr, shapeu.ptr); | ||
1331 | } | ||
1332 | |||
1333 | public override void DumpConstraint(BulletWorld world, BulletConstraint constrain) | ||
1334 | { | ||
1335 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
1336 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
1337 | BSAPICPP.DumpConstraint2(worldu.ptr, constrainu.ptr); | ||
1338 | } | ||
1339 | |||
1340 | public override void DumpActivationInfo(BulletWorld world) | ||
1341 | { | ||
1342 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
1343 | BSAPICPP.DumpActivationInfo2(worldu.ptr); | ||
1344 | } | ||
1345 | |||
1346 | public override void DumpAllInfo(BulletWorld world) | ||
1347 | { | ||
1348 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
1349 | BSAPICPP.DumpAllInfo2(worldu.ptr); | ||
1350 | } | ||
1351 | |||
1352 | public override void DumpPhysicsStatistics(BulletWorld world) | ||
1353 | { | ||
1354 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
1355 | BSAPICPP.DumpPhysicsStatistics2(worldu.ptr); | ||
1356 | } | ||
1357 | public override void ResetBroadphasePool(BulletWorld world) | ||
1358 | { | ||
1359 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
1360 | BSAPICPP.ResetBroadphasePool(worldu.ptr); | ||
1361 | } | ||
1362 | public override void ResetConstraintSolver(BulletWorld world) | ||
1363 | { | ||
1364 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
1365 | BSAPICPP.ResetConstraintSolver(worldu.ptr); | ||
1366 | } | ||
1367 | |||
1368 | // ===================================================================================== | ||
1369 | // ===================================================================================== | ||
1370 | // ===================================================================================== | ||
1371 | // ===================================================================================== | ||
1372 | // ===================================================================================== | ||
1373 | // The actual interface to the unmanaged code | ||
1374 | static class BSAPICPP | ||
1375 | { | ||
1376 | // =============================================================================== | ||
1377 | // Link back to the managed code for outputting log messages | ||
1378 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] | ||
1379 | public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg); | ||
1380 | |||
1381 | // =============================================================================== | ||
1382 | // Initialization and simulation | ||
1383 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1384 | public static extern IntPtr Initialize2(Vector3 maxPosition, IntPtr parms, | ||
1385 | int maxCollisions, IntPtr collisionArray, | ||
1386 | int maxUpdates, IntPtr updateArray, | ||
1387 | DebugLogCallback logRoutine); | ||
1388 | |||
1389 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1390 | public static extern int PhysicsStep2(IntPtr world, float timeStep, int maxSubSteps, float fixedTimeStep, | ||
1391 | out int updatedEntityCount, out int collidersCount); | ||
1392 | |||
1393 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1394 | public static extern void Shutdown2(IntPtr sim); | ||
1395 | |||
1396 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1397 | public static extern bool PushUpdate2(IntPtr obj); | ||
1398 | |||
1399 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1400 | public static extern bool UpdateParameter2(IntPtr world, uint localID, String parm, float value); | ||
1401 | |||
1402 | // ===================================================================================== | ||
1403 | // Mesh, hull, shape and body creation helper routines | ||
1404 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1405 | public static extern IntPtr CreateMeshShape2(IntPtr world, | ||
1406 | int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices, | ||
1407 | int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices ); | ||
1408 | |||
1409 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1410 | public static extern IntPtr CreateHullShape2(IntPtr world, | ||
1411 | int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls); | ||
1412 | |||
1413 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1414 | public static extern IntPtr BuildHullShapeFromMesh2(IntPtr world, IntPtr meshShape); | ||
1415 | |||
1416 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1417 | public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData); | ||
1418 | |||
1419 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1420 | public static extern bool IsNativeShape2(IntPtr shape); | ||
1421 | |||
1422 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1423 | public static extern void SetShapeCollisionMargin(IntPtr shape, float margin); | ||
1424 | |||
1425 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1426 | public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale); | ||
1427 | |||
1428 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1429 | public static extern IntPtr CreateCompoundShape2(IntPtr sim, bool enableDynamicAabbTree); | ||
1430 | |||
1431 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1432 | public static extern int GetNumberOfCompoundChildren2(IntPtr cShape); | ||
1433 | |||
1434 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1435 | public static extern void AddChildShapeToCompoundShape2(IntPtr cShape, IntPtr addShape, Vector3 pos, Quaternion rot); | ||
1436 | |||
1437 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1438 | public static extern IntPtr GetChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx); | ||
1439 | |||
1440 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1441 | public static extern IntPtr RemoveChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx); | ||
1442 | |||
1443 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1444 | public static extern void RemoveChildShapeFromCompoundShape2(IntPtr cShape, IntPtr removeShape); | ||
1445 | |||
1446 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1447 | public static extern void UpdateChildTransform2(IntPtr pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb); | ||
1448 | |||
1449 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1450 | public static extern void RecalculateCompoundShapeLocalAabb2(IntPtr cShape); | ||
1451 | |||
1452 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1453 | public static extern IntPtr DuplicateCollisionShape2(IntPtr sim, IntPtr srcShape, uint id); | ||
1454 | |||
1455 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1456 | public static extern bool DeleteCollisionShape2(IntPtr world, IntPtr shape); | ||
1457 | |||
1458 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1459 | public static extern int GetBodyType2(IntPtr obj); | ||
1460 | |||
1461 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1462 | public static extern IntPtr CreateBodyFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot); | ||
1463 | |||
1464 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1465 | public static extern IntPtr CreateBodyWithDefaultMotionState2(IntPtr shape, uint id, Vector3 pos, Quaternion rot); | ||
1466 | |||
1467 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1468 | public static extern IntPtr CreateGhostFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot); | ||
1469 | |||
1470 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1471 | public static extern void DestroyObject2(IntPtr sim, IntPtr obj); | ||
1472 | |||
1473 | // ===================================================================================== | ||
1474 | // Terrain creation and helper routines | ||
1475 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1476 | public static extern IntPtr CreateGroundPlaneShape2(uint id, float height, float collisionMargin); | ||
1477 | |||
1478 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1479 | public static extern IntPtr CreateTerrainShape2(uint id, Vector3 size, float minHeight, float maxHeight, | ||
1480 | [MarshalAs(UnmanagedType.LPArray)] float[] heightMap, | ||
1481 | float scaleFactor, float collisionMargin); | ||
1482 | |||
1483 | // ===================================================================================== | ||
1484 | // Constraint creation and helper routines | ||
1485 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1486 | public static extern IntPtr Create6DofConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, | ||
1487 | Vector3 frame1loc, Quaternion frame1rot, | ||
1488 | Vector3 frame2loc, Quaternion frame2rot, | ||
1489 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); | ||
1490 | |||
1491 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1492 | public static extern IntPtr Create6DofConstraintToPoint2(IntPtr world, IntPtr obj1, IntPtr obj2, | ||
1493 | Vector3 joinPoint, | ||
1494 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); | ||
1495 | |||
1496 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1497 | public static extern IntPtr Create6DofConstraintFixed2(IntPtr world, IntPtr obj1, | ||
1498 | Vector3 frameInBloc, Quaternion frameInBrot, | ||
1499 | bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies); | ||
1500 | |||
1501 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1502 | public static extern IntPtr Create6DofSpringConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, | ||
1503 | Vector3 frame1loc, Quaternion frame1rot, | ||
1504 | Vector3 frame2loc, Quaternion frame2rot, | ||
1505 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); | ||
1506 | |||
1507 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1508 | public static extern IntPtr CreateHingeConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, | ||
1509 | Vector3 pivotinA, Vector3 pivotinB, | ||
1510 | Vector3 axisInA, Vector3 axisInB, | ||
1511 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); | ||
1512 | |||
1513 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1514 | public static extern IntPtr CreateSliderConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, | ||
1515 | Vector3 frameInAloc, Quaternion frameInArot, | ||
1516 | Vector3 frameInBloc, Quaternion frameInBrot, | ||
1517 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); | ||
1518 | |||
1519 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1520 | public static extern IntPtr CreateConeTwistConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, | ||
1521 | Vector3 frameInAloc, Quaternion frameInArot, | ||
1522 | Vector3 frameInBloc, Quaternion frameInBrot, | ||
1523 | bool disableCollisionsBetweenLinkedBodies); | ||
1524 | |||
1525 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1526 | public static extern IntPtr CreateGearConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, | ||
1527 | Vector3 axisInA, Vector3 axisInB, | ||
1528 | float ratio, bool disableCollisionsBetweenLinkedBodies); | ||
1529 | |||
1530 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1531 | public static extern IntPtr CreatePoint2PointConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, | ||
1532 | Vector3 pivotInA, Vector3 pivotInB, | ||
1533 | bool disableCollisionsBetweenLinkedBodies); | ||
1534 | |||
1535 | |||
1536 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1537 | public static extern void SetConstraintEnable2(IntPtr constrain, float numericTrueFalse); | ||
1538 | |||
1539 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1540 | public static extern void SetConstraintNumSolverIterations2(IntPtr constrain, float iterations); | ||
1541 | |||
1542 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1543 | public static extern bool SetFrames2(IntPtr constrain, | ||
1544 | Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot); | ||
1545 | |||
1546 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1547 | public static extern bool SetLinearLimits2(IntPtr constrain, Vector3 low, Vector3 hi); | ||
1548 | |||
1549 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1550 | public static extern bool SetAngularLimits2(IntPtr constrain, Vector3 low, Vector3 hi); | ||
1551 | |||
1552 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1553 | public static extern bool UseFrameOffset2(IntPtr constrain, float enable); | ||
1554 | |||
1555 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1556 | public static extern bool TranslationalLimitMotor2(IntPtr constrain, float enable, float targetVel, float maxMotorForce); | ||
1557 | |||
1558 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1559 | public static extern bool SetBreakingImpulseThreshold2(IntPtr constrain, float threshold); | ||
1560 | |||
1561 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1562 | public static extern bool CalculateTransforms2(IntPtr constrain); | ||
1563 | |||
1564 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1565 | public static extern bool SetConstraintParam2(IntPtr constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis); | ||
1566 | |||
1567 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1568 | public static extern bool DestroyConstraint2(IntPtr world, IntPtr constrain); | ||
1569 | |||
1570 | // ===================================================================================== | ||
1571 | // btCollisionWorld entries | ||
1572 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1573 | public static extern void UpdateSingleAabb2(IntPtr world, IntPtr obj); | ||
1574 | |||
1575 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1576 | public static extern void UpdateAabbs2(IntPtr world); | ||
1577 | |||
1578 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1579 | public static extern bool GetForceUpdateAllAabbs2(IntPtr world); | ||
1580 | |||
1581 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1582 | public static extern void SetForceUpdateAllAabbs2(IntPtr world, bool force); | ||
1583 | |||
1584 | // ===================================================================================== | ||
1585 | // btDynamicsWorld entries | ||
1586 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1587 | public static extern bool AddObjectToWorld2(IntPtr world, IntPtr obj); | ||
1588 | |||
1589 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1590 | public static extern bool RemoveObjectFromWorld2(IntPtr world, IntPtr obj); | ||
1591 | |||
1592 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1593 | public static extern bool AddConstraintToWorld2(IntPtr world, IntPtr constrain, bool disableCollisionsBetweenLinkedObjects); | ||
1594 | |||
1595 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1596 | public static extern bool RemoveConstraintFromWorld2(IntPtr world, IntPtr constrain); | ||
1597 | // ===================================================================================== | ||
1598 | // btCollisionObject entries | ||
1599 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1600 | public static extern Vector3 GetAnisotripicFriction2(IntPtr constrain); | ||
1601 | |||
1602 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1603 | public static extern Vector3 SetAnisotripicFriction2(IntPtr constrain, Vector3 frict); | ||
1604 | |||
1605 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1606 | public static extern bool HasAnisotripicFriction2(IntPtr constrain); | ||
1607 | |||
1608 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1609 | public static extern void SetContactProcessingThreshold2(IntPtr obj, float val); | ||
1610 | |||
1611 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1612 | public static extern float GetContactProcessingThreshold2(IntPtr obj); | ||
1613 | |||
1614 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1615 | public static extern bool IsStaticObject2(IntPtr obj); | ||
1616 | |||
1617 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1618 | public static extern bool IsKinematicObject2(IntPtr obj); | ||
1619 | |||
1620 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1621 | public static extern bool IsStaticOrKinematicObject2(IntPtr obj); | ||
1622 | |||
1623 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1624 | public static extern bool HasContactResponse2(IntPtr obj); | ||
1625 | |||
1626 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1627 | public static extern void SetCollisionShape2(IntPtr sim, IntPtr obj, IntPtr shape); | ||
1628 | |||
1629 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1630 | public static extern IntPtr GetCollisionShape2(IntPtr obj); | ||
1631 | |||
1632 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1633 | public static extern int GetActivationState2(IntPtr obj); | ||
1634 | |||
1635 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1636 | public static extern void SetActivationState2(IntPtr obj, int state); | ||
1637 | |||
1638 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1639 | public static extern void SetDeactivationTime2(IntPtr obj, float dtime); | ||
1640 | |||
1641 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1642 | public static extern float GetDeactivationTime2(IntPtr obj); | ||
1643 | |||
1644 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1645 | public static extern void ForceActivationState2(IntPtr obj, ActivationState state); | ||
1646 | |||
1647 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1648 | public static extern void Activate2(IntPtr obj, bool forceActivation); | ||
1649 | |||
1650 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1651 | public static extern bool IsActive2(IntPtr obj); | ||
1652 | |||
1653 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1654 | public static extern void SetRestitution2(IntPtr obj, float val); | ||
1655 | |||
1656 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1657 | public static extern float GetRestitution2(IntPtr obj); | ||
1658 | |||
1659 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1660 | public static extern void SetFriction2(IntPtr obj, float val); | ||
1661 | |||
1662 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1663 | public static extern float GetFriction2(IntPtr obj); | ||
1664 | |||
1665 | /* Haven't defined the type 'Transform' | ||
1666 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1667 | public static extern Transform GetWorldTransform2(IntPtr obj); | ||
1668 | |||
1669 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1670 | public static extern void setWorldTransform2(IntPtr obj, Transform trans); | ||
1671 | */ | ||
1672 | |||
1673 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1674 | public static extern Vector3 GetPosition2(IntPtr obj); | ||
1675 | |||
1676 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1677 | public static extern Quaternion GetOrientation2(IntPtr obj); | ||
1678 | |||
1679 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1680 | public static extern void SetTranslation2(IntPtr obj, Vector3 position, Quaternion rotation); | ||
1681 | |||
1682 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1683 | public static extern IntPtr GetBroadphaseHandle2(IntPtr obj); | ||
1684 | |||
1685 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1686 | public static extern void SetBroadphaseHandle2(IntPtr obj, IntPtr handle); | ||
1687 | |||
1688 | /* | ||
1689 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1690 | public static extern Transform GetInterpolationWorldTransform2(IntPtr obj); | ||
1691 | |||
1692 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1693 | public static extern void SetInterpolationWorldTransform2(IntPtr obj, Transform trans); | ||
1694 | */ | ||
1695 | |||
1696 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1697 | public static extern void SetInterpolationLinearVelocity2(IntPtr obj, Vector3 vel); | ||
1698 | |||
1699 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1700 | public static extern void SetInterpolationAngularVelocity2(IntPtr obj, Vector3 vel); | ||
1701 | |||
1702 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1703 | public static extern void SetInterpolationVelocity2(IntPtr obj, Vector3 linearVel, Vector3 angularVel); | ||
1704 | |||
1705 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1706 | public static extern float GetHitFraction2(IntPtr obj); | ||
1707 | |||
1708 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1709 | public static extern void SetHitFraction2(IntPtr obj, float val); | ||
1710 | |||
1711 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1712 | public static extern CollisionFlags GetCollisionFlags2(IntPtr obj); | ||
1713 | |||
1714 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1715 | public static extern CollisionFlags SetCollisionFlags2(IntPtr obj, CollisionFlags flags); | ||
1716 | |||
1717 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1718 | public static extern CollisionFlags AddToCollisionFlags2(IntPtr obj, CollisionFlags flags); | ||
1719 | |||
1720 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1721 | public static extern CollisionFlags RemoveFromCollisionFlags2(IntPtr obj, CollisionFlags flags); | ||
1722 | |||
1723 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1724 | public static extern float GetCcdMotionThreshold2(IntPtr obj); | ||
1725 | |||
1726 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1727 | public static extern void SetCcdMotionThreshold2(IntPtr obj, float val); | ||
1728 | |||
1729 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1730 | public static extern float GetCcdSweptSphereRadius2(IntPtr obj); | ||
1731 | |||
1732 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1733 | public static extern void SetCcdSweptSphereRadius2(IntPtr obj, float val); | ||
1734 | |||
1735 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1736 | public static extern IntPtr GetUserPointer2(IntPtr obj); | ||
1737 | |||
1738 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1739 | public static extern void SetUserPointer2(IntPtr obj, IntPtr val); | ||
1740 | |||
1741 | // ===================================================================================== | ||
1742 | // btRigidBody entries | ||
1743 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1744 | public static extern void ApplyGravity2(IntPtr obj); | ||
1745 | |||
1746 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1747 | public static extern void SetGravity2(IntPtr obj, Vector3 val); | ||
1748 | |||
1749 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1750 | public static extern Vector3 GetGravity2(IntPtr obj); | ||
1751 | |||
1752 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1753 | public static extern void SetDamping2(IntPtr obj, float lin_damping, float ang_damping); | ||
1754 | |||
1755 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1756 | public static extern void SetLinearDamping2(IntPtr obj, float lin_damping); | ||
1757 | |||
1758 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1759 | public static extern void SetAngularDamping2(IntPtr obj, float ang_damping); | ||
1760 | |||
1761 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1762 | public static extern float GetLinearDamping2(IntPtr obj); | ||
1763 | |||
1764 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1765 | public static extern float GetAngularDamping2(IntPtr obj); | ||
1766 | |||
1767 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1768 | public static extern float GetLinearSleepingThreshold2(IntPtr obj); | ||
1769 | |||
1770 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1771 | public static extern float GetAngularSleepingThreshold2(IntPtr obj); | ||
1772 | |||
1773 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1774 | public static extern void ApplyDamping2(IntPtr obj, float timeStep); | ||
1775 | |||
1776 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1777 | public static extern void SetMassProps2(IntPtr obj, float mass, Vector3 inertia); | ||
1778 | |||
1779 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1780 | public static extern Vector3 GetLinearFactor2(IntPtr obj); | ||
1781 | |||
1782 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1783 | public static extern void SetLinearFactor2(IntPtr obj, Vector3 factor); | ||
1784 | |||
1785 | /* | ||
1786 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1787 | public static extern void SetCenterOfMassTransform2(IntPtr obj, Transform trans); | ||
1788 | */ | ||
1789 | |||
1790 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1791 | public static extern void SetCenterOfMassByPosRot2(IntPtr obj, Vector3 pos, Quaternion rot); | ||
1792 | |||
1793 | // Add a force to the object as if its mass is one. | ||
1794 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1795 | public static extern void ApplyCentralForce2(IntPtr obj, Vector3 force); | ||
1796 | |||
1797 | // Set the force being applied to the object as if its mass is one. | ||
1798 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1799 | public static extern void SetObjectForce2(IntPtr obj, Vector3 force); | ||
1800 | |||
1801 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1802 | public static extern Vector3 GetTotalForce2(IntPtr obj); | ||
1803 | |||
1804 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1805 | public static extern Vector3 GetTotalTorque2(IntPtr obj); | ||
1806 | |||
1807 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1808 | public static extern Vector3 GetInvInertiaDiagLocal2(IntPtr obj); | ||
1809 | |||
1810 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1811 | public static extern void SetInvInertiaDiagLocal2(IntPtr obj, Vector3 inert); | ||
1812 | |||
1813 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1814 | public static extern void SetSleepingThresholds2(IntPtr obj, float lin_threshold, float ang_threshold); | ||
1815 | |||
1816 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1817 | public static extern void ApplyTorque2(IntPtr obj, Vector3 torque); | ||
1818 | |||
1819 | // Apply force at the given point. Will add torque to the object. | ||
1820 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1821 | public static extern void ApplyForce2(IntPtr obj, Vector3 force, Vector3 pos); | ||
1822 | |||
1823 | // Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass. | ||
1824 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1825 | public static extern void ApplyCentralImpulse2(IntPtr obj, Vector3 imp); | ||
1826 | |||
1827 | // Apply impulse to the object's torque. Force is scaled by object's mass. | ||
1828 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1829 | public static extern void ApplyTorqueImpulse2(IntPtr obj, Vector3 imp); | ||
1830 | |||
1831 | // Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces. | ||
1832 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1833 | public static extern void ApplyImpulse2(IntPtr obj, Vector3 imp, Vector3 pos); | ||
1834 | |||
1835 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1836 | public static extern void ClearForces2(IntPtr obj); | ||
1837 | |||
1838 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1839 | public static extern void ClearAllForces2(IntPtr obj); | ||
1840 | |||
1841 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1842 | public static extern void UpdateInertiaTensor2(IntPtr obj); | ||
1843 | |||
1844 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1845 | public static extern Vector3 GetCenterOfMassPosition2(IntPtr obj); | ||
1846 | |||
1847 | /* | ||
1848 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1849 | public static extern Transform GetCenterOfMassTransform2(IntPtr obj); | ||
1850 | */ | ||
1851 | |||
1852 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1853 | public static extern Vector3 GetLinearVelocity2(IntPtr obj); | ||
1854 | |||
1855 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1856 | public static extern Vector3 GetAngularVelocity2(IntPtr obj); | ||
1857 | |||
1858 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1859 | public static extern void SetLinearVelocity2(IntPtr obj, Vector3 val); | ||
1860 | |||
1861 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1862 | public static extern void SetAngularVelocity2(IntPtr obj, Vector3 angularVelocity); | ||
1863 | |||
1864 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1865 | public static extern Vector3 GetVelocityInLocalPoint2(IntPtr obj, Vector3 pos); | ||
1866 | |||
1867 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1868 | public static extern void Translate2(IntPtr obj, Vector3 trans); | ||
1869 | |||
1870 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1871 | public static extern void UpdateDeactivation2(IntPtr obj, float timeStep); | ||
1872 | |||
1873 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1874 | public static extern bool WantsSleeping2(IntPtr obj); | ||
1875 | |||
1876 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1877 | public static extern void SetAngularFactor2(IntPtr obj, float factor); | ||
1878 | |||
1879 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1880 | public static extern void SetAngularFactorV2(IntPtr obj, Vector3 factor); | ||
1881 | |||
1882 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1883 | public static extern Vector3 GetAngularFactor2(IntPtr obj); | ||
1884 | |||
1885 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1886 | public static extern bool IsInWorld2(IntPtr obj); | ||
1887 | |||
1888 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1889 | public static extern void AddConstraintRef2(IntPtr obj, IntPtr constrain); | ||
1890 | |||
1891 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1892 | public static extern void RemoveConstraintRef2(IntPtr obj, IntPtr constrain); | ||
1893 | |||
1894 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1895 | public static extern IntPtr GetConstraintRef2(IntPtr obj, int index); | ||
1896 | |||
1897 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1898 | public static extern int GetNumConstraintRefs2(IntPtr obj); | ||
1899 | |||
1900 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1901 | public static extern bool SetCollisionGroupMask2(IntPtr body, uint filter, uint mask); | ||
1902 | |||
1903 | // ===================================================================================== | ||
1904 | // btCollisionShape entries | ||
1905 | |||
1906 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1907 | public static extern float GetAngularMotionDisc2(IntPtr shape); | ||
1908 | |||
1909 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1910 | public static extern float GetContactBreakingThreshold2(IntPtr shape, float defaultFactor); | ||
1911 | |||
1912 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1913 | public static extern bool IsPolyhedral2(IntPtr shape); | ||
1914 | |||
1915 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1916 | public static extern bool IsConvex2d2(IntPtr shape); | ||
1917 | |||
1918 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1919 | public static extern bool IsConvex2(IntPtr shape); | ||
1920 | |||
1921 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1922 | public static extern bool IsNonMoving2(IntPtr shape); | ||
1923 | |||
1924 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1925 | public static extern bool IsConcave2(IntPtr shape); | ||
1926 | |||
1927 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1928 | public static extern bool IsCompound2(IntPtr shape); | ||
1929 | |||
1930 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1931 | public static extern bool IsSoftBody2(IntPtr shape); | ||
1932 | |||
1933 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1934 | public static extern bool IsInfinite2(IntPtr shape); | ||
1935 | |||
1936 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1937 | public static extern void SetLocalScaling2(IntPtr shape, Vector3 scale); | ||
1938 | |||
1939 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1940 | public static extern Vector3 GetLocalScaling2(IntPtr shape); | ||
1941 | |||
1942 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1943 | public static extern Vector3 CalculateLocalInertia2(IntPtr shape, float mass); | ||
1944 | |||
1945 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1946 | public static extern int GetShapeType2(IntPtr shape); | ||
1947 | |||
1948 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1949 | public static extern void SetMargin2(IntPtr shape, float val); | ||
1950 | |||
1951 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1952 | public static extern float GetMargin2(IntPtr shape); | ||
1953 | |||
1954 | // ===================================================================================== | ||
1955 | // Debugging | ||
1956 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1957 | public static extern void DumpRigidBody2(IntPtr sim, IntPtr collisionObject); | ||
1958 | |||
1959 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1960 | public static extern void DumpCollisionShape2(IntPtr sim, IntPtr collisionShape); | ||
1961 | |||
1962 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1963 | public static extern void DumpMapInfo2(IntPtr sim, IntPtr manInfo); | ||
1964 | |||
1965 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1966 | public static extern void DumpConstraint2(IntPtr sim, IntPtr constrain); | ||
1967 | |||
1968 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1969 | public static extern void DumpActivationInfo2(IntPtr sim); | ||
1970 | |||
1971 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1972 | public static extern void DumpAllInfo2(IntPtr sim); | ||
1973 | |||
1974 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1975 | public static extern void DumpPhysicsStatistics2(IntPtr sim); | ||
1976 | |||
1977 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1978 | public static extern void ResetBroadphasePool(IntPtr sim); | ||
1979 | |||
1980 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1981 | public static extern void ResetConstraintSolver(IntPtr sim); | ||
1982 | |||
1983 | } | ||
1984 | |||
1985 | } | ||
1986 | |||
1987 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs b/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs new file mode 100755 index 0000000..6fc10e9 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs | |||
@@ -0,0 +1,2311 @@ | |||
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 copyrightD | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.IO; | ||
30 | using System.Runtime.InteropServices; | ||
31 | using System.Text; | ||
32 | |||
33 | using OpenSim.Framework; | ||
34 | |||
35 | using OpenMetaverse; | ||
36 | |||
37 | using BulletXNA; | ||
38 | using BulletXNA.LinearMath; | ||
39 | using BulletXNA.BulletCollision; | ||
40 | using BulletXNA.BulletDynamics; | ||
41 | using BulletXNA.BulletCollision.CollisionDispatch; | ||
42 | |||
43 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
44 | { | ||
45 | public sealed class BSAPIXNA : BSAPITemplate | ||
46 | { | ||
47 | private sealed class BulletWorldXNA : BulletWorld | ||
48 | { | ||
49 | public DiscreteDynamicsWorld world; | ||
50 | public BulletWorldXNA(uint id, BSScene physScene, DiscreteDynamicsWorld xx) | ||
51 | : base(id, physScene) | ||
52 | { | ||
53 | world = xx; | ||
54 | } | ||
55 | } | ||
56 | |||
57 | private sealed class BulletBodyXNA : BulletBody | ||
58 | { | ||
59 | public CollisionObject body; | ||
60 | public RigidBody rigidBody { get { return RigidBody.Upcast(body); } } | ||
61 | |||
62 | public BulletBodyXNA(uint id, CollisionObject xx) | ||
63 | : base(id) | ||
64 | { | ||
65 | body = xx; | ||
66 | } | ||
67 | public override bool HasPhysicalBody | ||
68 | { | ||
69 | get { return body != null; } | ||
70 | } | ||
71 | public override void Clear() | ||
72 | { | ||
73 | body = null; | ||
74 | } | ||
75 | public override string AddrString | ||
76 | { | ||
77 | get { return "XNARigidBody"; } | ||
78 | } | ||
79 | } | ||
80 | |||
81 | private sealed class BulletShapeXNA : BulletShape | ||
82 | { | ||
83 | public CollisionShape shape; | ||
84 | public BulletShapeXNA(CollisionShape xx, BSPhysicsShapeType typ) | ||
85 | : base() | ||
86 | { | ||
87 | shape = xx; | ||
88 | type = typ; | ||
89 | } | ||
90 | public override bool HasPhysicalShape | ||
91 | { | ||
92 | get { return shape != null; } | ||
93 | } | ||
94 | public override void Clear() | ||
95 | { | ||
96 | shape = null; | ||
97 | } | ||
98 | public override BulletShape Clone() | ||
99 | { | ||
100 | return new BulletShapeXNA(shape, type); | ||
101 | } | ||
102 | public override bool ReferenceSame(BulletShape other) | ||
103 | { | ||
104 | BulletShapeXNA otheru = other as BulletShapeXNA; | ||
105 | return (otheru != null) && (this.shape == otheru.shape); | ||
106 | |||
107 | } | ||
108 | public override string AddrString | ||
109 | { | ||
110 | get { return "XNACollisionShape"; } | ||
111 | } | ||
112 | } | ||
113 | private sealed class BulletConstraintXNA : BulletConstraint | ||
114 | { | ||
115 | public TypedConstraint constrain; | ||
116 | public BulletConstraintXNA(TypedConstraint xx) : base() | ||
117 | { | ||
118 | constrain = xx; | ||
119 | } | ||
120 | |||
121 | public override void Clear() | ||
122 | { | ||
123 | constrain = null; | ||
124 | } | ||
125 | public override bool HasPhysicalConstraint { get { return constrain != null; } } | ||
126 | |||
127 | // Used for log messages for a unique display of the memory/object allocated to this instance | ||
128 | public override string AddrString | ||
129 | { | ||
130 | get { return "XNAConstraint"; } | ||
131 | } | ||
132 | } | ||
133 | internal int m_maxCollisions; | ||
134 | internal CollisionDesc[] UpdatedCollisions; | ||
135 | internal int LastCollisionDesc = 0; | ||
136 | internal int m_maxUpdatesPerFrame; | ||
137 | internal int LastEntityProperty = 0; | ||
138 | |||
139 | internal EntityProperties[] UpdatedObjects; | ||
140 | internal Dictionary<uint, GhostObject> specialCollisionObjects; | ||
141 | |||
142 | private static int m_collisionsThisFrame; | ||
143 | private BSScene PhysicsScene { get; set; } | ||
144 | |||
145 | public override string BulletEngineName { get { return "BulletXNA"; } } | ||
146 | public override string BulletEngineVersion { get; protected set; } | ||
147 | |||
148 | public BSAPIXNA(string paramName, BSScene physScene) | ||
149 | { | ||
150 | PhysicsScene = physScene; | ||
151 | } | ||
152 | |||
153 | /// <summary> | ||
154 | /// | ||
155 | /// </summary> | ||
156 | /// <param name="p"></param> | ||
157 | /// <param name="p_2"></param> | ||
158 | public override bool RemoveObjectFromWorld(BulletWorld pWorld, BulletBody pBody) | ||
159 | { | ||
160 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
161 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
162 | CollisionObject collisionObject = ((BulletBodyXNA)pBody).body; | ||
163 | if (body != null) | ||
164 | world.RemoveRigidBody(body); | ||
165 | else if (collisionObject != null) | ||
166 | world.RemoveCollisionObject(collisionObject); | ||
167 | else | ||
168 | return false; | ||
169 | return true; | ||
170 | } | ||
171 | |||
172 | public override bool AddConstraintToWorld(BulletWorld pWorld, BulletConstraint pConstraint, bool pDisableCollisionsBetweenLinkedObjects) | ||
173 | { | ||
174 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
175 | TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain; | ||
176 | world.AddConstraint(constraint, pDisableCollisionsBetweenLinkedObjects); | ||
177 | |||
178 | return true; | ||
179 | |||
180 | } | ||
181 | |||
182 | public override bool RemoveConstraintFromWorld(BulletWorld pWorld, BulletConstraint pConstraint) | ||
183 | { | ||
184 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
185 | TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain; | ||
186 | world.RemoveConstraint(constraint); | ||
187 | return true; | ||
188 | } | ||
189 | |||
190 | public override void SetRestitution(BulletBody pCollisionObject, float pRestitution) | ||
191 | { | ||
192 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; | ||
193 | collisionObject.SetRestitution(pRestitution); | ||
194 | } | ||
195 | |||
196 | public override int GetShapeType(BulletShape pShape) | ||
197 | { | ||
198 | CollisionShape shape = (pShape as BulletShapeXNA).shape; | ||
199 | return (int)shape.GetShapeType(); | ||
200 | } | ||
201 | public override void SetMargin(BulletShape pShape, float pMargin) | ||
202 | { | ||
203 | CollisionShape shape = (pShape as BulletShapeXNA).shape; | ||
204 | shape.SetMargin(pMargin); | ||
205 | } | ||
206 | |||
207 | public override float GetMargin(BulletShape pShape) | ||
208 | { | ||
209 | CollisionShape shape = (pShape as BulletShapeXNA).shape; | ||
210 | return shape.GetMargin(); | ||
211 | } | ||
212 | |||
213 | public override void SetLocalScaling(BulletShape pShape, Vector3 pScale) | ||
214 | { | ||
215 | CollisionShape shape = (pShape as BulletShapeXNA).shape; | ||
216 | IndexedVector3 vec = new IndexedVector3(pScale.X, pScale.Y, pScale.Z); | ||
217 | shape.SetLocalScaling(ref vec); | ||
218 | |||
219 | } | ||
220 | |||
221 | public override void SetContactProcessingThreshold(BulletBody pCollisionObject, float contactprocessingthreshold) | ||
222 | { | ||
223 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; | ||
224 | collisionObject.SetContactProcessingThreshold(contactprocessingthreshold); | ||
225 | } | ||
226 | |||
227 | public override void SetCcdMotionThreshold(BulletBody pCollisionObject, float pccdMotionThreashold) | ||
228 | { | ||
229 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; | ||
230 | collisionObject.SetCcdMotionThreshold(pccdMotionThreashold); | ||
231 | } | ||
232 | |||
233 | public override void SetCcdSweptSphereRadius(BulletBody pCollisionObject, float pCcdSweptSphereRadius) | ||
234 | { | ||
235 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; | ||
236 | collisionObject.SetCcdSweptSphereRadius(pCcdSweptSphereRadius); | ||
237 | } | ||
238 | |||
239 | public override void SetAngularFactorV(BulletBody pBody, Vector3 pAngularFactor) | ||
240 | { | ||
241 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
242 | body.SetAngularFactor(new IndexedVector3(pAngularFactor.X, pAngularFactor.Y, pAngularFactor.Z)); | ||
243 | } | ||
244 | |||
245 | public override CollisionFlags AddToCollisionFlags(BulletBody pCollisionObject, CollisionFlags pcollisionFlags) | ||
246 | { | ||
247 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; | ||
248 | CollisionFlags existingcollisionFlags = (CollisionFlags)(uint)collisionObject.GetCollisionFlags(); | ||
249 | existingcollisionFlags |= pcollisionFlags; | ||
250 | collisionObject.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags)(uint)existingcollisionFlags); | ||
251 | return (CollisionFlags) (uint) existingcollisionFlags; | ||
252 | } | ||
253 | |||
254 | public override bool AddObjectToWorld(BulletWorld pWorld, BulletBody pBody) | ||
255 | { | ||
256 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
257 | CollisionObject cbody = (pBody as BulletBodyXNA).body; | ||
258 | RigidBody rbody = cbody as RigidBody; | ||
259 | |||
260 | // Bullet resets several variables when an object is added to the world. In particular, | ||
261 | // BulletXNA resets position and rotation. Gravity is also reset depending on the static/dynamic | ||
262 | // type. Of course, the collision flags in the broadphase proxy are initialized to default. | ||
263 | IndexedMatrix origPos = cbody.GetWorldTransform(); | ||
264 | if (rbody != null) | ||
265 | { | ||
266 | IndexedVector3 origGrav = rbody.GetGravity(); | ||
267 | world.AddRigidBody(rbody); | ||
268 | rbody.SetGravity(origGrav); | ||
269 | } | ||
270 | else | ||
271 | { | ||
272 | world.AddCollisionObject(cbody); | ||
273 | } | ||
274 | cbody.SetWorldTransform(origPos); | ||
275 | |||
276 | pBody.ApplyCollisionMask(pWorld.physicsScene); | ||
277 | |||
278 | //if (body.GetBroadphaseHandle() != null) | ||
279 | // world.UpdateSingleAabb(body); | ||
280 | return true; | ||
281 | } | ||
282 | |||
283 | public override void ForceActivationState(BulletBody pCollisionObject, ActivationState pActivationState) | ||
284 | { | ||
285 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; | ||
286 | collisionObject.ForceActivationState((BulletXNA.BulletCollision.ActivationState)(uint)pActivationState); | ||
287 | } | ||
288 | |||
289 | public override void UpdateSingleAabb(BulletWorld pWorld, BulletBody pCollisionObject) | ||
290 | { | ||
291 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
292 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; | ||
293 | world.UpdateSingleAabb(collisionObject); | ||
294 | } | ||
295 | |||
296 | public override void UpdateAabbs(BulletWorld pWorld) { | ||
297 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
298 | world.UpdateAabbs(); | ||
299 | } | ||
300 | public override bool GetForceUpdateAllAabbs(BulletWorld pWorld) { | ||
301 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
302 | return world.GetForceUpdateAllAabbs(); | ||
303 | |||
304 | } | ||
305 | public override void SetForceUpdateAllAabbs(BulletWorld pWorld, bool pForce) | ||
306 | { | ||
307 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
308 | world.SetForceUpdateAllAabbs(pForce); | ||
309 | } | ||
310 | |||
311 | public override bool SetCollisionGroupMask(BulletBody pCollisionObject, uint pGroup, uint pMask) | ||
312 | { | ||
313 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; | ||
314 | collisionObject.GetBroadphaseHandle().m_collisionFilterGroup = (BulletXNA.BulletCollision.CollisionFilterGroups) pGroup; | ||
315 | collisionObject.GetBroadphaseHandle().m_collisionFilterGroup = (BulletXNA.BulletCollision.CollisionFilterGroups) pGroup; | ||
316 | if ((uint) collisionObject.GetBroadphaseHandle().m_collisionFilterGroup == 0) | ||
317 | return false; | ||
318 | return true; | ||
319 | } | ||
320 | |||
321 | public override void ClearAllForces(BulletBody pCollisionObject) | ||
322 | { | ||
323 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; | ||
324 | IndexedVector3 zeroVector = new IndexedVector3(0, 0, 0); | ||
325 | collisionObject.SetInterpolationLinearVelocity(ref zeroVector); | ||
326 | collisionObject.SetInterpolationAngularVelocity(ref zeroVector); | ||
327 | IndexedMatrix bodytransform = collisionObject.GetWorldTransform(); | ||
328 | |||
329 | collisionObject.SetInterpolationWorldTransform(ref bodytransform); | ||
330 | |||
331 | if (collisionObject is RigidBody) | ||
332 | { | ||
333 | RigidBody rigidbody = collisionObject as RigidBody; | ||
334 | rigidbody.SetLinearVelocity(zeroVector); | ||
335 | rigidbody.SetAngularVelocity(zeroVector); | ||
336 | rigidbody.ClearForces(); | ||
337 | } | ||
338 | } | ||
339 | |||
340 | public override void SetInterpolationAngularVelocity(BulletBody pCollisionObject, Vector3 pVector3) | ||
341 | { | ||
342 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; | ||
343 | IndexedVector3 vec = new IndexedVector3(pVector3.X, pVector3.Y, pVector3.Z); | ||
344 | collisionObject.SetInterpolationAngularVelocity(ref vec); | ||
345 | } | ||
346 | |||
347 | public override void SetAngularVelocity(BulletBody pBody, Vector3 pVector3) | ||
348 | { | ||
349 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
350 | IndexedVector3 vec = new IndexedVector3(pVector3.X, pVector3.Y, pVector3.Z); | ||
351 | body.SetAngularVelocity(ref vec); | ||
352 | } | ||
353 | public override Vector3 GetTotalForce(BulletBody pBody) | ||
354 | { | ||
355 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
356 | IndexedVector3 iv3 = body.GetTotalForce(); | ||
357 | return new Vector3(iv3.X, iv3.Y, iv3.Z); | ||
358 | } | ||
359 | public override Vector3 GetTotalTorque(BulletBody pBody) | ||
360 | { | ||
361 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
362 | IndexedVector3 iv3 = body.GetTotalTorque(); | ||
363 | return new Vector3(iv3.X, iv3.Y, iv3.Z); | ||
364 | } | ||
365 | public override Vector3 GetInvInertiaDiagLocal(BulletBody pBody) | ||
366 | { | ||
367 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
368 | IndexedVector3 iv3 = body.GetInvInertiaDiagLocal(); | ||
369 | return new Vector3(iv3.X, iv3.Y, iv3.Z); | ||
370 | } | ||
371 | public override void SetInvInertiaDiagLocal(BulletBody pBody, Vector3 inert) | ||
372 | { | ||
373 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
374 | IndexedVector3 iv3 = new IndexedVector3(inert.X, inert.Y, inert.Z); | ||
375 | body.SetInvInertiaDiagLocal(ref iv3); | ||
376 | } | ||
377 | public override void ApplyForce(BulletBody pBody, Vector3 force, Vector3 pos) | ||
378 | { | ||
379 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
380 | IndexedVector3 forceiv3 = new IndexedVector3(force.X, force.Y, force.Z); | ||
381 | IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z); | ||
382 | body.ApplyForce(ref forceiv3, ref posiv3); | ||
383 | } | ||
384 | public override void ApplyImpulse(BulletBody pBody, Vector3 imp, Vector3 pos) | ||
385 | { | ||
386 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
387 | IndexedVector3 impiv3 = new IndexedVector3(imp.X, imp.Y, imp.Z); | ||
388 | IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z); | ||
389 | body.ApplyImpulse(ref impiv3, ref posiv3); | ||
390 | } | ||
391 | |||
392 | public override void ClearForces(BulletBody pBody) | ||
393 | { | ||
394 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
395 | body.ClearForces(); | ||
396 | } | ||
397 | |||
398 | public override void SetTranslation(BulletBody pCollisionObject, Vector3 _position, Quaternion _orientation) | ||
399 | { | ||
400 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; | ||
401 | IndexedVector3 vposition = new IndexedVector3(_position.X, _position.Y, _position.Z); | ||
402 | IndexedQuaternion vquaternion = new IndexedQuaternion(_orientation.X, _orientation.Y, _orientation.Z, | ||
403 | _orientation.W); | ||
404 | IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(vquaternion); | ||
405 | mat._origin = vposition; | ||
406 | collisionObject.SetWorldTransform(mat); | ||
407 | |||
408 | } | ||
409 | |||
410 | public override Vector3 GetPosition(BulletBody pCollisionObject) | ||
411 | { | ||
412 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; | ||
413 | IndexedVector3 pos = collisionObject.GetInterpolationWorldTransform()._origin; | ||
414 | return new Vector3(pos.X, pos.Y, pos.Z); | ||
415 | } | ||
416 | |||
417 | public override Vector3 CalculateLocalInertia(BulletShape pShape, float pphysMass) | ||
418 | { | ||
419 | CollisionShape shape = (pShape as BulletShapeXNA).shape; | ||
420 | IndexedVector3 inertia = IndexedVector3.Zero; | ||
421 | shape.CalculateLocalInertia(pphysMass, out inertia); | ||
422 | return new Vector3(inertia.X, inertia.Y, inertia.Z); | ||
423 | } | ||
424 | |||
425 | public override void SetMassProps(BulletBody pBody, float pphysMass, Vector3 plocalInertia) | ||
426 | { | ||
427 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
428 | if (body != null) // Can't set mass props on collision object. | ||
429 | { | ||
430 | IndexedVector3 inertia = new IndexedVector3(plocalInertia.X, plocalInertia.Y, plocalInertia.Z); | ||
431 | body.SetMassProps(pphysMass, inertia); | ||
432 | } | ||
433 | } | ||
434 | |||
435 | |||
436 | public override void SetObjectForce(BulletBody pBody, Vector3 _force) | ||
437 | { | ||
438 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
439 | IndexedVector3 force = new IndexedVector3(_force.X, _force.Y, _force.Z); | ||
440 | body.SetTotalForce(ref force); | ||
441 | } | ||
442 | |||
443 | public override void SetFriction(BulletBody pCollisionObject, float _currentFriction) | ||
444 | { | ||
445 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; | ||
446 | collisionObject.SetFriction(_currentFriction); | ||
447 | } | ||
448 | |||
449 | public override void SetLinearVelocity(BulletBody pBody, Vector3 _velocity) | ||
450 | { | ||
451 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
452 | IndexedVector3 velocity = new IndexedVector3(_velocity.X, _velocity.Y, _velocity.Z); | ||
453 | body.SetLinearVelocity(velocity); | ||
454 | } | ||
455 | |||
456 | public override void Activate(BulletBody pCollisionObject, bool pforceactivation) | ||
457 | { | ||
458 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; | ||
459 | collisionObject.Activate(pforceactivation); | ||
460 | |||
461 | } | ||
462 | |||
463 | public override Quaternion GetOrientation(BulletBody pCollisionObject) | ||
464 | { | ||
465 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; | ||
466 | IndexedQuaternion mat = collisionObject.GetInterpolationWorldTransform().GetRotation(); | ||
467 | return new Quaternion(mat.X, mat.Y, mat.Z, mat.W); | ||
468 | } | ||
469 | |||
470 | public override CollisionFlags RemoveFromCollisionFlags(BulletBody pCollisionObject, CollisionFlags pcollisionFlags) | ||
471 | { | ||
472 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; | ||
473 | CollisionFlags existingcollisionFlags = (CollisionFlags)(uint)collisionObject.GetCollisionFlags(); | ||
474 | existingcollisionFlags &= ~pcollisionFlags; | ||
475 | collisionObject.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags)(uint)existingcollisionFlags); | ||
476 | return (CollisionFlags)(uint)existingcollisionFlags; | ||
477 | } | ||
478 | |||
479 | public override float GetCcdMotionThreshold(BulletBody pCollisionObject) | ||
480 | { | ||
481 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; | ||
482 | return collisionObject.GetCcdSquareMotionThreshold(); | ||
483 | } | ||
484 | |||
485 | public override float GetCcdSweptSphereRadius(BulletBody pCollisionObject) | ||
486 | { | ||
487 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; | ||
488 | return collisionObject.GetCcdSweptSphereRadius(); | ||
489 | |||
490 | } | ||
491 | |||
492 | public override IntPtr GetUserPointer(BulletBody pCollisionObject) | ||
493 | { | ||
494 | CollisionObject shape = (pCollisionObject as BulletBodyXNA).body; | ||
495 | return (IntPtr)shape.GetUserPointer(); | ||
496 | } | ||
497 | |||
498 | public override void SetUserPointer(BulletBody pCollisionObject, IntPtr val) | ||
499 | { | ||
500 | CollisionObject shape = (pCollisionObject as BulletBodyXNA).body; | ||
501 | shape.SetUserPointer(val); | ||
502 | } | ||
503 | |||
504 | public override void SetGravity(BulletBody pBody, Vector3 pGravity) | ||
505 | { | ||
506 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
507 | if (body != null) // Can't set collisionobject.set gravity | ||
508 | { | ||
509 | IndexedVector3 gravity = new IndexedVector3(pGravity.X, pGravity.Y, pGravity.Z); | ||
510 | body.SetGravity(gravity); | ||
511 | } | ||
512 | } | ||
513 | |||
514 | public override bool DestroyConstraint(BulletWorld pWorld, BulletConstraint pConstraint) | ||
515 | { | ||
516 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
517 | TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain; | ||
518 | world.RemoveConstraint(constraint); | ||
519 | return true; | ||
520 | } | ||
521 | |||
522 | public override bool SetLinearLimits(BulletConstraint pConstraint, Vector3 low, Vector3 high) | ||
523 | { | ||
524 | Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; | ||
525 | IndexedVector3 lowlimit = new IndexedVector3(low.X, low.Y, low.Z); | ||
526 | IndexedVector3 highlimit = new IndexedVector3(high.X, high.Y, high.Z); | ||
527 | constraint.SetLinearLowerLimit(lowlimit); | ||
528 | constraint.SetLinearUpperLimit(highlimit); | ||
529 | return true; | ||
530 | } | ||
531 | |||
532 | public override bool SetAngularLimits(BulletConstraint pConstraint, Vector3 low, Vector3 high) | ||
533 | { | ||
534 | Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; | ||
535 | IndexedVector3 lowlimit = new IndexedVector3(low.X, low.Y, low.Z); | ||
536 | IndexedVector3 highlimit = new IndexedVector3(high.X, high.Y, high.Z); | ||
537 | constraint.SetAngularLowerLimit(lowlimit); | ||
538 | constraint.SetAngularUpperLimit(highlimit); | ||
539 | return true; | ||
540 | } | ||
541 | |||
542 | public override void SetConstraintNumSolverIterations(BulletConstraint pConstraint, float cnt) | ||
543 | { | ||
544 | Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; | ||
545 | constraint.SetOverrideNumSolverIterations((int)cnt); | ||
546 | } | ||
547 | |||
548 | public override bool CalculateTransforms(BulletConstraint pConstraint) | ||
549 | { | ||
550 | Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; | ||
551 | constraint.CalculateTransforms(); | ||
552 | return true; | ||
553 | } | ||
554 | |||
555 | public override void SetConstraintEnable(BulletConstraint pConstraint, float p_2) | ||
556 | { | ||
557 | Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; | ||
558 | constraint.SetEnabled((p_2 == 0) ? false : true); | ||
559 | } | ||
560 | |||
561 | |||
562 | public override BulletConstraint Create6DofConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, | ||
563 | Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot, | ||
564 | bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) | ||
565 | |||
566 | { | ||
567 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
568 | RigidBody body1 = (pBody1 as BulletBodyXNA).rigidBody; | ||
569 | RigidBody body2 = (pBody2 as BulletBodyXNA).rigidBody; | ||
570 | IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z); | ||
571 | IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W); | ||
572 | IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot); | ||
573 | frame1._origin = frame1v; | ||
574 | |||
575 | IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z); | ||
576 | IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W); | ||
577 | IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot); | ||
578 | frame2._origin = frame1v; | ||
579 | |||
580 | Generic6DofConstraint consttr = new Generic6DofConstraint(body1, body2, ref frame1, ref frame2, | ||
581 | puseLinearReferenceFrameA); | ||
582 | consttr.CalculateTransforms(); | ||
583 | world.AddConstraint(consttr,pdisableCollisionsBetweenLinkedBodies); | ||
584 | |||
585 | return new BulletConstraintXNA(consttr); | ||
586 | } | ||
587 | |||
588 | public override BulletConstraint Create6DofConstraintFixed(BulletWorld pWorld, BulletBody pBody1, | ||
589 | Vector3 pframe1, Quaternion pframe1rot, | ||
590 | bool pUseLinearReferenceFrameB, bool pdisableCollisionsBetweenLinkedBodies) | ||
591 | { | ||
592 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
593 | RigidBody body1 = (pBody1 as BulletBodyXNA).rigidBody; | ||
594 | IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z); | ||
595 | IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W); | ||
596 | IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot); | ||
597 | frame1._origin = frame1v; | ||
598 | |||
599 | Generic6DofConstraint consttr = new Generic6DofConstraint(body1, ref frame1, pUseLinearReferenceFrameB); | ||
600 | consttr.CalculateTransforms(); | ||
601 | world.AddConstraint(consttr,pdisableCollisionsBetweenLinkedBodies); | ||
602 | |||
603 | return new BulletConstraintXNA(consttr); | ||
604 | } | ||
605 | |||
606 | /// <summary> | ||
607 | /// | ||
608 | /// </summary> | ||
609 | /// <param name="pWorld"></param> | ||
610 | /// <param name="pBody1"></param> | ||
611 | /// <param name="pBody2"></param> | ||
612 | /// <param name="pjoinPoint"></param> | ||
613 | /// <param name="puseLinearReferenceFrameA"></param> | ||
614 | /// <param name="pdisableCollisionsBetweenLinkedBodies"></param> | ||
615 | /// <returns></returns> | ||
616 | public override BulletConstraint Create6DofConstraintToPoint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, Vector3 pjoinPoint, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) | ||
617 | { | ||
618 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
619 | RigidBody body1 = (pBody1 as BulletBodyXNA).rigidBody; | ||
620 | RigidBody body2 = (pBody2 as BulletBodyXNA).rigidBody; | ||
621 | IndexedMatrix frame1 = new IndexedMatrix(IndexedBasisMatrix.Identity, new IndexedVector3(0, 0, 0)); | ||
622 | IndexedMatrix frame2 = new IndexedMatrix(IndexedBasisMatrix.Identity, new IndexedVector3(0, 0, 0)); | ||
623 | |||
624 | IndexedVector3 joinPoint = new IndexedVector3(pjoinPoint.X, pjoinPoint.Y, pjoinPoint.Z); | ||
625 | IndexedMatrix mat = IndexedMatrix.Identity; | ||
626 | mat._origin = new IndexedVector3(pjoinPoint.X, pjoinPoint.Y, pjoinPoint.Z); | ||
627 | frame1._origin = body1.GetWorldTransform().Inverse()*joinPoint; | ||
628 | frame2._origin = body2.GetWorldTransform().Inverse()*joinPoint; | ||
629 | |||
630 | Generic6DofConstraint consttr = new Generic6DofConstraint(body1, body2, ref frame1, ref frame2, puseLinearReferenceFrameA); | ||
631 | consttr.CalculateTransforms(); | ||
632 | world.AddConstraint(consttr, pdisableCollisionsBetweenLinkedBodies); | ||
633 | |||
634 | return new BulletConstraintXNA(consttr); | ||
635 | } | ||
636 | //SetFrames(m_constraint.ptr, frameA, frameArot, frameB, frameBrot); | ||
637 | public override bool SetFrames(BulletConstraint pConstraint, Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot) | ||
638 | { | ||
639 | Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; | ||
640 | IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z); | ||
641 | IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W); | ||
642 | IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot); | ||
643 | frame1._origin = frame1v; | ||
644 | |||
645 | IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z); | ||
646 | IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W); | ||
647 | IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot); | ||
648 | frame2._origin = frame1v; | ||
649 | constraint.SetFrames(ref frame1, ref frame2); | ||
650 | return true; | ||
651 | } | ||
652 | |||
653 | public override Vector3 GetLinearVelocity(BulletBody pBody) | ||
654 | { | ||
655 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
656 | IndexedVector3 iv3 = body.GetLinearVelocity(); | ||
657 | return new Vector3(iv3.X, iv3.Y, iv3.Z); | ||
658 | } | ||
659 | public override Vector3 GetAngularVelocity(BulletBody pBody) | ||
660 | { | ||
661 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
662 | IndexedVector3 iv3 = body.GetAngularVelocity(); | ||
663 | return new Vector3(iv3.X, iv3.Y, iv3.Z); | ||
664 | } | ||
665 | public override Vector3 GetVelocityInLocalPoint(BulletBody pBody, Vector3 pos) | ||
666 | { | ||
667 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
668 | IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z); | ||
669 | IndexedVector3 iv3 = body.GetVelocityInLocalPoint(ref posiv3); | ||
670 | return new Vector3(iv3.X, iv3.Y, iv3.Z); | ||
671 | } | ||
672 | public override void Translate(BulletBody pCollisionObject, Vector3 trans) | ||
673 | { | ||
674 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; | ||
675 | collisionObject.Translate(new IndexedVector3(trans.X,trans.Y,trans.Z)); | ||
676 | } | ||
677 | public override void UpdateDeactivation(BulletBody pBody, float timeStep) | ||
678 | { | ||
679 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
680 | body.UpdateDeactivation(timeStep); | ||
681 | } | ||
682 | |||
683 | public override bool WantsSleeping(BulletBody pBody) | ||
684 | { | ||
685 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
686 | return body.WantsSleeping(); | ||
687 | } | ||
688 | |||
689 | public override void SetAngularFactor(BulletBody pBody, float factor) | ||
690 | { | ||
691 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
692 | body.SetAngularFactor(factor); | ||
693 | } | ||
694 | |||
695 | public override Vector3 GetAngularFactor(BulletBody pBody) | ||
696 | { | ||
697 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
698 | IndexedVector3 iv3 = body.GetAngularFactor(); | ||
699 | return new Vector3(iv3.X, iv3.Y, iv3.Z); | ||
700 | } | ||
701 | |||
702 | public override bool IsInWorld(BulletWorld pWorld, BulletBody pCollisionObject) | ||
703 | { | ||
704 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
705 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; | ||
706 | return world.IsInWorld(collisionObject); | ||
707 | } | ||
708 | |||
709 | public override void AddConstraintRef(BulletBody pBody, BulletConstraint pConstraint) | ||
710 | { | ||
711 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
712 | TypedConstraint constrain = (pConstraint as BulletConstraintXNA).constrain; | ||
713 | body.AddConstraintRef(constrain); | ||
714 | } | ||
715 | |||
716 | public override void RemoveConstraintRef(BulletBody pBody, BulletConstraint pConstraint) | ||
717 | { | ||
718 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
719 | TypedConstraint constrain = (pConstraint as BulletConstraintXNA).constrain; | ||
720 | body.RemoveConstraintRef(constrain); | ||
721 | } | ||
722 | |||
723 | public override BulletConstraint GetConstraintRef(BulletBody pBody, int index) | ||
724 | { | ||
725 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
726 | return new BulletConstraintXNA(body.GetConstraintRef(index)); | ||
727 | } | ||
728 | |||
729 | public override int GetNumConstraintRefs(BulletBody pBody) | ||
730 | { | ||
731 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
732 | return body.GetNumConstraintRefs(); | ||
733 | } | ||
734 | |||
735 | public override void SetInterpolationLinearVelocity(BulletBody pCollisionObject, Vector3 VehicleVelocity) | ||
736 | { | ||
737 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; | ||
738 | IndexedVector3 velocity = new IndexedVector3(VehicleVelocity.X, VehicleVelocity.Y, VehicleVelocity.Z); | ||
739 | collisionObject.SetInterpolationLinearVelocity(ref velocity); | ||
740 | } | ||
741 | |||
742 | public override bool UseFrameOffset(BulletConstraint pConstraint, float onOff) | ||
743 | { | ||
744 | Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; | ||
745 | constraint.SetUseFrameOffset((onOff == 0) ? false : true); | ||
746 | return true; | ||
747 | } | ||
748 | //SetBreakingImpulseThreshold(m_constraint.ptr, threshold); | ||
749 | public override bool SetBreakingImpulseThreshold(BulletConstraint pConstraint, float threshold) | ||
750 | { | ||
751 | Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; | ||
752 | constraint.SetBreakingImpulseThreshold(threshold); | ||
753 | return true; | ||
754 | } | ||
755 | //BulletSimAPI.SetAngularDamping(Prim.PhysBody.ptr, angularDamping); | ||
756 | public override void SetAngularDamping(BulletBody pBody, float angularDamping) | ||
757 | { | ||
758 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
759 | float lineardamping = body.GetLinearDamping(); | ||
760 | body.SetDamping(lineardamping, angularDamping); | ||
761 | |||
762 | } | ||
763 | |||
764 | public override void UpdateInertiaTensor(BulletBody pBody) | ||
765 | { | ||
766 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
767 | if (body != null) // can't update inertia tensor on CollisionObject | ||
768 | body.UpdateInertiaTensor(); | ||
769 | } | ||
770 | |||
771 | public override void RecalculateCompoundShapeLocalAabb(BulletShape pCompoundShape) | ||
772 | { | ||
773 | CompoundShape shape = (pCompoundShape as BulletShapeXNA).shape as CompoundShape; | ||
774 | shape.RecalculateLocalAabb(); | ||
775 | } | ||
776 | |||
777 | //BulletSimAPI.GetCollisionFlags(PhysBody.ptr) | ||
778 | public override CollisionFlags GetCollisionFlags(BulletBody pCollisionObject) | ||
779 | { | ||
780 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; | ||
781 | uint flags = (uint)collisionObject.GetCollisionFlags(); | ||
782 | return (CollisionFlags) flags; | ||
783 | } | ||
784 | |||
785 | public override void SetDamping(BulletBody pBody, float pLinear, float pAngular) | ||
786 | { | ||
787 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
788 | body.SetDamping(pLinear, pAngular); | ||
789 | } | ||
790 | //PhysBody.ptr, PhysicsScene.Params.deactivationTime); | ||
791 | public override void SetDeactivationTime(BulletBody pCollisionObject, float pDeactivationTime) | ||
792 | { | ||
793 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; | ||
794 | collisionObject.SetDeactivationTime(pDeactivationTime); | ||
795 | } | ||
796 | //SetSleepingThresholds(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold); | ||
797 | public override void SetSleepingThresholds(BulletBody pBody, float plinearSleepingThreshold, float pangularSleepingThreshold) | ||
798 | { | ||
799 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
800 | body.SetSleepingThresholds(plinearSleepingThreshold, pangularSleepingThreshold); | ||
801 | } | ||
802 | |||
803 | public override CollisionObjectTypes GetBodyType(BulletBody pCollisionObject) | ||
804 | { | ||
805 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; | ||
806 | return (CollisionObjectTypes)(int) collisionObject.GetInternalType(); | ||
807 | } | ||
808 | |||
809 | public override void ApplyGravity(BulletBody pBody) | ||
810 | { | ||
811 | |||
812 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
813 | body.ApplyGravity(); | ||
814 | } | ||
815 | |||
816 | public override Vector3 GetGravity(BulletBody pBody) | ||
817 | { | ||
818 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
819 | IndexedVector3 gravity = body.GetGravity(); | ||
820 | return new Vector3(gravity.X, gravity.Y, gravity.Z); | ||
821 | } | ||
822 | |||
823 | public override void SetLinearDamping(BulletBody pBody, float lin_damping) | ||
824 | { | ||
825 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
826 | float angularDamping = body.GetAngularDamping(); | ||
827 | body.SetDamping(lin_damping, angularDamping); | ||
828 | } | ||
829 | |||
830 | public override float GetLinearDamping(BulletBody pBody) | ||
831 | { | ||
832 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
833 | return body.GetLinearDamping(); | ||
834 | } | ||
835 | |||
836 | public override float GetAngularDamping(BulletBody pBody) | ||
837 | { | ||
838 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
839 | return body.GetAngularDamping(); | ||
840 | } | ||
841 | |||
842 | public override float GetLinearSleepingThreshold(BulletBody pBody) | ||
843 | { | ||
844 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
845 | return body.GetLinearSleepingThreshold(); | ||
846 | } | ||
847 | |||
848 | public override void ApplyDamping(BulletBody pBody, float timeStep) | ||
849 | { | ||
850 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
851 | body.ApplyDamping(timeStep); | ||
852 | } | ||
853 | |||
854 | public override Vector3 GetLinearFactor(BulletBody pBody) | ||
855 | { | ||
856 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
857 | IndexedVector3 linearFactor = body.GetLinearFactor(); | ||
858 | return new Vector3(linearFactor.X, linearFactor.Y, linearFactor.Z); | ||
859 | } | ||
860 | |||
861 | public override void SetLinearFactor(BulletBody pBody, Vector3 factor) | ||
862 | { | ||
863 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
864 | body.SetLinearFactor(new IndexedVector3(factor.X, factor.Y, factor.Z)); | ||
865 | } | ||
866 | |||
867 | public override void SetCenterOfMassByPosRot(BulletBody pBody, Vector3 pos, Quaternion rot) | ||
868 | { | ||
869 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
870 | IndexedQuaternion quat = new IndexedQuaternion(rot.X, rot.Y, rot.Z,rot.W); | ||
871 | IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(quat); | ||
872 | mat._origin = new IndexedVector3(pos.X, pos.Y, pos.Z); | ||
873 | body.SetCenterOfMassTransform( ref mat); | ||
874 | /* TODO: double check this */ | ||
875 | } | ||
876 | |||
877 | //BulletSimAPI.ApplyCentralForce(PhysBody.ptr, fSum); | ||
878 | public override void ApplyCentralForce(BulletBody pBody, Vector3 pfSum) | ||
879 | { | ||
880 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
881 | IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z); | ||
882 | body.ApplyCentralForce(ref fSum); | ||
883 | } | ||
884 | public override void ApplyCentralImpulse(BulletBody pBody, Vector3 pfSum) | ||
885 | { | ||
886 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
887 | IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z); | ||
888 | body.ApplyCentralImpulse(ref fSum); | ||
889 | } | ||
890 | public override void ApplyTorque(BulletBody pBody, Vector3 pfSum) | ||
891 | { | ||
892 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
893 | IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z); | ||
894 | body.ApplyTorque(ref fSum); | ||
895 | } | ||
896 | public override void ApplyTorqueImpulse(BulletBody pBody, Vector3 pfSum) | ||
897 | { | ||
898 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
899 | IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z); | ||
900 | body.ApplyTorqueImpulse(ref fSum); | ||
901 | } | ||
902 | |||
903 | public override void DestroyObject(BulletWorld pWorld, BulletBody pBody) | ||
904 | { | ||
905 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
906 | CollisionObject co = (pBody as BulletBodyXNA).rigidBody; | ||
907 | RigidBody bo = co as RigidBody; | ||
908 | if (bo == null) | ||
909 | { | ||
910 | |||
911 | if (world.IsInWorld(co)) | ||
912 | { | ||
913 | world.RemoveCollisionObject(co); | ||
914 | } | ||
915 | } | ||
916 | else | ||
917 | { | ||
918 | |||
919 | if (world.IsInWorld(bo)) | ||
920 | { | ||
921 | world.RemoveRigidBody(bo); | ||
922 | } | ||
923 | } | ||
924 | if (co != null) | ||
925 | { | ||
926 | if (co.GetUserPointer() != null) | ||
927 | { | ||
928 | uint localId = (uint) co.GetUserPointer(); | ||
929 | if (specialCollisionObjects.ContainsKey(localId)) | ||
930 | { | ||
931 | specialCollisionObjects.Remove(localId); | ||
932 | } | ||
933 | } | ||
934 | } | ||
935 | |||
936 | } | ||
937 | |||
938 | public override void Shutdown(BulletWorld pWorld) | ||
939 | { | ||
940 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
941 | world.Cleanup(); | ||
942 | } | ||
943 | |||
944 | public override BulletShape DuplicateCollisionShape(BulletWorld pWorld, BulletShape pShape, uint id) | ||
945 | { | ||
946 | CollisionShape shape1 = (pShape as BulletShapeXNA).shape; | ||
947 | |||
948 | // TODO: Turn this from a reference copy to a Value Copy. | ||
949 | BulletShapeXNA shape2 = new BulletShapeXNA(shape1, BSShapeTypeFromBroadPhaseNativeType(shape1.GetShapeType())); | ||
950 | |||
951 | return shape2; | ||
952 | } | ||
953 | |||
954 | public override bool DeleteCollisionShape(BulletWorld pWorld, BulletShape pShape) | ||
955 | { | ||
956 | //TODO: | ||
957 | return false; | ||
958 | } | ||
959 | //(sim.ptr, shape.ptr, prim.LocalID, prim.RawPosition, prim.RawOrientation); | ||
960 | |||
961 | public override BulletBody CreateBodyFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation) | ||
962 | { | ||
963 | CollisionWorld world = (pWorld as BulletWorldXNA).world; | ||
964 | IndexedMatrix mat = | ||
965 | IndexedMatrix.CreateFromQuaternion(new IndexedQuaternion(pRawOrientation.X, pRawOrientation.Y, | ||
966 | pRawOrientation.Z, pRawOrientation.W)); | ||
967 | mat._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z); | ||
968 | CollisionShape shape = (pShape as BulletShapeXNA).shape; | ||
969 | //UpdateSingleAabb(world, shape); | ||
970 | // TODO: Feed Update array into null | ||
971 | SimMotionState motionState = new SimMotionState(this, pLocalID, mat, null); | ||
972 | RigidBody body = new RigidBody(0,motionState,shape,IndexedVector3.Zero); | ||
973 | RigidBodyConstructionInfo constructionInfo = new RigidBodyConstructionInfo(0, motionState, shape, IndexedVector3.Zero) | ||
974 | { | ||
975 | m_mass = 0 | ||
976 | }; | ||
977 | /* | ||
978 | m_mass = mass; | ||
979 | m_motionState =motionState; | ||
980 | m_collisionShape = collisionShape; | ||
981 | m_localInertia = localInertia; | ||
982 | m_linearDamping = 0f; | ||
983 | m_angularDamping = 0f; | ||
984 | m_friction = 0.5f; | ||
985 | m_restitution = 0f; | ||
986 | m_linearSleepingThreshold = 0.8f; | ||
987 | m_angularSleepingThreshold = 1f; | ||
988 | m_additionalDamping = false; | ||
989 | m_additionalDampingFactor = 0.005f; | ||
990 | m_additionalLinearDampingThresholdSqr = 0.01f; | ||
991 | m_additionalAngularDampingThresholdSqr = 0.01f; | ||
992 | m_additionalAngularDampingFactor = 0.01f; | ||
993 | m_startWorldTransform = IndexedMatrix.Identity; | ||
994 | */ | ||
995 | body.SetUserPointer(pLocalID); | ||
996 | |||
997 | return new BulletBodyXNA(pLocalID, body); | ||
998 | } | ||
999 | |||
1000 | |||
1001 | public override BulletBody CreateBodyWithDefaultMotionState( BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation) | ||
1002 | { | ||
1003 | |||
1004 | IndexedMatrix mat = | ||
1005 | IndexedMatrix.CreateFromQuaternion(new IndexedQuaternion(pRawOrientation.X, pRawOrientation.Y, | ||
1006 | pRawOrientation.Z, pRawOrientation.W)); | ||
1007 | mat._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z); | ||
1008 | |||
1009 | CollisionShape shape = (pShape as BulletShapeXNA).shape; | ||
1010 | |||
1011 | // TODO: Feed Update array into null | ||
1012 | RigidBody body = new RigidBody(0, new DefaultMotionState( mat, IndexedMatrix.Identity), shape, IndexedVector3.Zero); | ||
1013 | body.SetWorldTransform(mat); | ||
1014 | body.SetUserPointer(pLocalID); | ||
1015 | return new BulletBodyXNA(pLocalID, body); | ||
1016 | } | ||
1017 | //(m_mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT); | ||
1018 | public override CollisionFlags SetCollisionFlags(BulletBody pCollisionObject, CollisionFlags collisionFlags) | ||
1019 | { | ||
1020 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; | ||
1021 | collisionObject.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags) (uint) collisionFlags); | ||
1022 | return (CollisionFlags)collisionObject.GetCollisionFlags(); | ||
1023 | } | ||
1024 | |||
1025 | public override Vector3 GetAnisotripicFriction(BulletConstraint pconstrain) | ||
1026 | { | ||
1027 | |||
1028 | /* TODO */ | ||
1029 | return Vector3.Zero; | ||
1030 | } | ||
1031 | public override Vector3 SetAnisotripicFriction(BulletConstraint pconstrain, Vector3 frict) { /* TODO */ return Vector3.Zero; } | ||
1032 | public override bool HasAnisotripicFriction(BulletConstraint pconstrain) { /* TODO */ return false; } | ||
1033 | public override float GetContactProcessingThreshold(BulletBody pBody) { /* TODO */ return 0f; } | ||
1034 | public override bool IsStaticObject(BulletBody pCollisionObject) | ||
1035 | { | ||
1036 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; | ||
1037 | return collisionObject.IsStaticObject(); | ||
1038 | |||
1039 | } | ||
1040 | public override bool IsKinematicObject(BulletBody pCollisionObject) | ||
1041 | { | ||
1042 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; | ||
1043 | return collisionObject.IsKinematicObject(); | ||
1044 | } | ||
1045 | public override bool IsStaticOrKinematicObject(BulletBody pCollisionObject) | ||
1046 | { | ||
1047 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; | ||
1048 | return collisionObject.IsStaticOrKinematicObject(); | ||
1049 | } | ||
1050 | public override bool HasContactResponse(BulletBody pCollisionObject) | ||
1051 | { | ||
1052 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; | ||
1053 | return collisionObject.HasContactResponse(); | ||
1054 | } | ||
1055 | public override int GetActivationState(BulletBody pBody) { /* TODO */ return 0; } | ||
1056 | public override void SetActivationState(BulletBody pBody, int state) { /* TODO */ } | ||
1057 | public override float GetDeactivationTime(BulletBody pBody) { /* TODO */ return 0f; } | ||
1058 | public override bool IsActive(BulletBody pBody) { /* TODO */ return false; } | ||
1059 | public override float GetRestitution(BulletBody pBody) { /* TODO */ return 0f; } | ||
1060 | public override float GetFriction(BulletBody pBody) { /* TODO */ return 0f; } | ||
1061 | public override void SetInterpolationVelocity(BulletBody pBody, Vector3 linearVel, Vector3 angularVel) { /* TODO */ } | ||
1062 | public override float GetHitFraction(BulletBody pBody) { /* TODO */ return 0f; } | ||
1063 | |||
1064 | //(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction); | ||
1065 | public override void SetHitFraction(BulletBody pCollisionObject, float pHitFraction) | ||
1066 | { | ||
1067 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; | ||
1068 | collisionObject.SetHitFraction(pHitFraction); | ||
1069 | } | ||
1070 | //BuildCapsuleShape(physicsScene.World.ptr, 1f, 1f, prim.Scale); | ||
1071 | public override BulletShape BuildCapsuleShape(BulletWorld pWorld, float pRadius, float pHeight, Vector3 pScale) | ||
1072 | { | ||
1073 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
1074 | IndexedVector3 scale = new IndexedVector3(pScale.X, pScale.Y, pScale.Z); | ||
1075 | CapsuleShapeZ capsuleShapeZ = new CapsuleShapeZ(pRadius, pHeight); | ||
1076 | capsuleShapeZ.SetMargin(world.WorldSettings.Params.collisionMargin); | ||
1077 | capsuleShapeZ.SetLocalScaling(ref scale); | ||
1078 | |||
1079 | return new BulletShapeXNA(capsuleShapeZ, BSPhysicsShapeType.SHAPE_CAPSULE); ; | ||
1080 | } | ||
1081 | |||
1082 | public override BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms, | ||
1083 | int maxCollisions, ref CollisionDesc[] collisionArray, | ||
1084 | int maxUpdates, ref EntityProperties[] updateArray | ||
1085 | ) | ||
1086 | { | ||
1087 | |||
1088 | UpdatedObjects = updateArray; | ||
1089 | UpdatedCollisions = collisionArray; | ||
1090 | /* TODO */ | ||
1091 | ConfigurationParameters[] configparms = new ConfigurationParameters[1]; | ||
1092 | configparms[0] = parms; | ||
1093 | Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); | ||
1094 | m_maxCollisions = maxCollisions; | ||
1095 | m_maxUpdatesPerFrame = maxUpdates; | ||
1096 | specialCollisionObjects = new Dictionary<uint, GhostObject>(); | ||
1097 | |||
1098 | return new BulletWorldXNA(1, PhysicsScene, BSAPIXNA.Initialize2(worldExtent, configparms, maxCollisions, ref collisionArray, maxUpdates, ref updateArray, null)); | ||
1099 | } | ||
1100 | |||
1101 | private static DiscreteDynamicsWorld Initialize2(Vector3 worldExtent, | ||
1102 | ConfigurationParameters[] o, | ||
1103 | int mMaxCollisionsPerFrame, ref CollisionDesc[] collisionArray, | ||
1104 | int mMaxUpdatesPerFrame, ref EntityProperties[] updateArray, | ||
1105 | object mDebugLogCallbackHandle) | ||
1106 | { | ||
1107 | CollisionWorld.WorldData.ParamData p = new CollisionWorld.WorldData.ParamData(); | ||
1108 | |||
1109 | p.angularDamping = BSParam.AngularDamping; | ||
1110 | p.defaultFriction = o[0].defaultFriction; | ||
1111 | p.defaultFriction = o[0].defaultFriction; | ||
1112 | p.defaultDensity = o[0].defaultDensity; | ||
1113 | p.defaultRestitution = o[0].defaultRestitution; | ||
1114 | p.collisionMargin = o[0].collisionMargin; | ||
1115 | p.gravity = o[0].gravity; | ||
1116 | |||
1117 | p.linearDamping = BSParam.LinearDamping; | ||
1118 | p.angularDamping = BSParam.AngularDamping; | ||
1119 | p.deactivationTime = BSParam.DeactivationTime; | ||
1120 | p.linearSleepingThreshold = BSParam.LinearSleepingThreshold; | ||
1121 | p.angularSleepingThreshold = BSParam.AngularSleepingThreshold; | ||
1122 | p.ccdMotionThreshold = BSParam.CcdMotionThreshold; | ||
1123 | p.ccdSweptSphereRadius = BSParam.CcdSweptSphereRadius; | ||
1124 | p.contactProcessingThreshold = BSParam.ContactProcessingThreshold; | ||
1125 | |||
1126 | p.terrainImplementation = BSParam.TerrainImplementation; | ||
1127 | p.terrainFriction = BSParam.TerrainFriction; | ||
1128 | |||
1129 | p.terrainHitFraction = BSParam.TerrainHitFraction; | ||
1130 | p.terrainRestitution = BSParam.TerrainRestitution; | ||
1131 | p.terrainCollisionMargin = BSParam.TerrainCollisionMargin; | ||
1132 | |||
1133 | p.avatarFriction = BSParam.AvatarFriction; | ||
1134 | p.avatarStandingFriction = BSParam.AvatarStandingFriction; | ||
1135 | p.avatarDensity = BSParam.AvatarDensity; | ||
1136 | p.avatarRestitution = BSParam.AvatarRestitution; | ||
1137 | p.avatarCapsuleWidth = BSParam.AvatarCapsuleWidth; | ||
1138 | p.avatarCapsuleDepth = BSParam.AvatarCapsuleDepth; | ||
1139 | p.avatarCapsuleHeight = BSParam.AvatarCapsuleHeight; | ||
1140 | p.avatarContactProcessingThreshold = BSParam.AvatarContactProcessingThreshold; | ||
1141 | |||
1142 | p.vehicleAngularDamping = BSParam.VehicleAngularDamping; | ||
1143 | |||
1144 | p.maxPersistantManifoldPoolSize = o[0].maxPersistantManifoldPoolSize; | ||
1145 | p.maxCollisionAlgorithmPoolSize = o[0].maxCollisionAlgorithmPoolSize; | ||
1146 | p.shouldDisableContactPoolDynamicAllocation = o[0].shouldDisableContactPoolDynamicAllocation; | ||
1147 | p.shouldForceUpdateAllAabbs = o[0].shouldForceUpdateAllAabbs; | ||
1148 | p.shouldRandomizeSolverOrder = o[0].shouldRandomizeSolverOrder; | ||
1149 | p.shouldSplitSimulationIslands = o[0].shouldSplitSimulationIslands; | ||
1150 | p.shouldEnableFrictionCaching = o[0].shouldEnableFrictionCaching; | ||
1151 | p.numberOfSolverIterations = o[0].numberOfSolverIterations; | ||
1152 | |||
1153 | p.linksetImplementation = BSParam.LinksetImplementation; | ||
1154 | p.linkConstraintUseFrameOffset = BSParam.NumericBool(BSParam.LinkConstraintUseFrameOffset); | ||
1155 | p.linkConstraintEnableTransMotor = BSParam.NumericBool(BSParam.LinkConstraintEnableTransMotor); | ||
1156 | p.linkConstraintTransMotorMaxVel = BSParam.LinkConstraintTransMotorMaxVel; | ||
1157 | p.linkConstraintTransMotorMaxForce = BSParam.LinkConstraintTransMotorMaxForce; | ||
1158 | p.linkConstraintERP = BSParam.LinkConstraintERP; | ||
1159 | p.linkConstraintCFM = BSParam.LinkConstraintCFM; | ||
1160 | p.linkConstraintSolverIterations = BSParam.LinkConstraintSolverIterations; | ||
1161 | p.physicsLoggingFrames = o[0].physicsLoggingFrames; | ||
1162 | DefaultCollisionConstructionInfo ccci = new DefaultCollisionConstructionInfo(); | ||
1163 | |||
1164 | DefaultCollisionConfiguration cci = new DefaultCollisionConfiguration(); | ||
1165 | CollisionDispatcher m_dispatcher = new CollisionDispatcher(cci); | ||
1166 | |||
1167 | |||
1168 | if (p.maxPersistantManifoldPoolSize > 0) | ||
1169 | cci.m_persistentManifoldPoolSize = (int)p.maxPersistantManifoldPoolSize; | ||
1170 | if (p.shouldDisableContactPoolDynamicAllocation !=0) | ||
1171 | m_dispatcher.SetDispatcherFlags(DispatcherFlags.CD_DISABLE_CONTACTPOOL_DYNAMIC_ALLOCATION); | ||
1172 | //if (p.maxCollisionAlgorithmPoolSize >0 ) | ||
1173 | |||
1174 | DbvtBroadphase m_broadphase = new DbvtBroadphase(); | ||
1175 | //IndexedVector3 aabbMin = new IndexedVector3(0, 0, 0); | ||
1176 | //IndexedVector3 aabbMax = new IndexedVector3(256, 256, 256); | ||
1177 | |||
1178 | //AxisSweep3Internal m_broadphase2 = new AxisSweep3Internal(ref aabbMin, ref aabbMax, Convert.ToInt32(0xfffe), 0xffff, ushort.MaxValue/2, null, true); | ||
1179 | m_broadphase.GetOverlappingPairCache().SetInternalGhostPairCallback(new GhostPairCallback()); | ||
1180 | |||
1181 | SequentialImpulseConstraintSolver m_solver = new SequentialImpulseConstraintSolver(); | ||
1182 | |||
1183 | DiscreteDynamicsWorld world = new DiscreteDynamicsWorld(m_dispatcher, m_broadphase, m_solver, cci); | ||
1184 | |||
1185 | world.LastCollisionDesc = 0; | ||
1186 | world.LastEntityProperty = 0; | ||
1187 | |||
1188 | world.WorldSettings.Params = p; | ||
1189 | world.SetForceUpdateAllAabbs(p.shouldForceUpdateAllAabbs != 0); | ||
1190 | world.GetSolverInfo().m_solverMode = SolverMode.SOLVER_USE_WARMSTARTING | SolverMode.SOLVER_SIMD; | ||
1191 | if (p.shouldRandomizeSolverOrder != 0) | ||
1192 | world.GetSolverInfo().m_solverMode |= SolverMode.SOLVER_RANDMIZE_ORDER; | ||
1193 | |||
1194 | world.GetSimulationIslandManager().SetSplitIslands(p.shouldSplitSimulationIslands != 0); | ||
1195 | //world.GetDispatchInfo().m_enableSatConvex Not implemented in C# port | ||
1196 | |||
1197 | if (p.shouldEnableFrictionCaching != 0) | ||
1198 | world.GetSolverInfo().m_solverMode |= SolverMode.SOLVER_ENABLE_FRICTION_DIRECTION_CACHING; | ||
1199 | |||
1200 | if (p.numberOfSolverIterations > 0) | ||
1201 | world.GetSolverInfo().m_numIterations = (int) p.numberOfSolverIterations; | ||
1202 | |||
1203 | |||
1204 | world.GetSolverInfo().m_damping = world.WorldSettings.Params.linearDamping; | ||
1205 | world.GetSolverInfo().m_restitution = world.WorldSettings.Params.defaultRestitution; | ||
1206 | world.GetSolverInfo().m_globalCfm = 0.0f; | ||
1207 | world.GetSolverInfo().m_tau = 0.6f; | ||
1208 | world.GetSolverInfo().m_friction = 0.3f; | ||
1209 | world.GetSolverInfo().m_maxErrorReduction = 20f; | ||
1210 | world.GetSolverInfo().m_numIterations = 10; | ||
1211 | world.GetSolverInfo().m_erp = 0.2f; | ||
1212 | world.GetSolverInfo().m_erp2 = 0.1f; | ||
1213 | world.GetSolverInfo().m_sor = 1.0f; | ||
1214 | world.GetSolverInfo().m_splitImpulse = false; | ||
1215 | world.GetSolverInfo().m_splitImpulsePenetrationThreshold = -0.02f; | ||
1216 | world.GetSolverInfo().m_linearSlop = 0.0f; | ||
1217 | world.GetSolverInfo().m_warmstartingFactor = 0.85f; | ||
1218 | world.GetSolverInfo().m_restingContactRestitutionThreshold = 2; | ||
1219 | world.SetForceUpdateAllAabbs(true); | ||
1220 | |||
1221 | //BSParam.TerrainImplementation = 0; | ||
1222 | world.SetGravity(new IndexedVector3(0,0,p.gravity)); | ||
1223 | |||
1224 | return world; | ||
1225 | } | ||
1226 | //m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL | ||
1227 | public override bool SetConstraintParam(BulletConstraint pConstraint, ConstraintParams paramIndex, float paramvalue, ConstraintParamAxis axis) | ||
1228 | { | ||
1229 | Generic6DofConstraint constrain = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; | ||
1230 | if (axis == ConstraintParamAxis.AXIS_LINEAR_ALL || axis == ConstraintParamAxis.AXIS_ALL) | ||
1231 | { | ||
1232 | constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 0); | ||
1233 | constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 1); | ||
1234 | constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 2); | ||
1235 | } | ||
1236 | if (axis == ConstraintParamAxis.AXIS_ANGULAR_ALL || axis == ConstraintParamAxis.AXIS_ALL) | ||
1237 | { | ||
1238 | constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 3); | ||
1239 | constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 4); | ||
1240 | constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 5); | ||
1241 | } | ||
1242 | if (axis == ConstraintParamAxis.AXIS_LINEAR_ALL) | ||
1243 | { | ||
1244 | constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, (int)axis); | ||
1245 | } | ||
1246 | return true; | ||
1247 | } | ||
1248 | |||
1249 | public override bool PushUpdate(BulletBody pCollisionObject) | ||
1250 | { | ||
1251 | bool ret = false; | ||
1252 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; | ||
1253 | RigidBody rb = collisionObject as RigidBody; | ||
1254 | if (rb != null) | ||
1255 | { | ||
1256 | SimMotionState sms = rb.GetMotionState() as SimMotionState; | ||
1257 | if (sms != null) | ||
1258 | { | ||
1259 | IndexedMatrix wt = IndexedMatrix.Identity; | ||
1260 | sms.GetWorldTransform(out wt); | ||
1261 | sms.SetWorldTransform(ref wt, true); | ||
1262 | ret = true; | ||
1263 | } | ||
1264 | } | ||
1265 | return ret; | ||
1266 | |||
1267 | } | ||
1268 | |||
1269 | public override float GetAngularMotionDisc(BulletShape pShape) | ||
1270 | { | ||
1271 | CollisionShape shape = (pShape as BulletShapeXNA).shape; | ||
1272 | return shape.GetAngularMotionDisc(); | ||
1273 | } | ||
1274 | public override float GetContactBreakingThreshold(BulletShape pShape, float defaultFactor) | ||
1275 | { | ||
1276 | CollisionShape shape = (pShape as BulletShapeXNA).shape; | ||
1277 | return shape.GetContactBreakingThreshold(defaultFactor); | ||
1278 | } | ||
1279 | public override bool IsCompound(BulletShape pShape) | ||
1280 | { | ||
1281 | CollisionShape shape = (pShape as BulletShapeXNA).shape; | ||
1282 | return shape.IsCompound(); | ||
1283 | } | ||
1284 | public override bool IsSoftBody(BulletShape pShape) | ||
1285 | { | ||
1286 | CollisionShape shape = (pShape as BulletShapeXNA).shape; | ||
1287 | return shape.IsSoftBody(); | ||
1288 | } | ||
1289 | public override bool IsPolyhedral(BulletShape pShape) | ||
1290 | { | ||
1291 | CollisionShape shape = (pShape as BulletShapeXNA).shape; | ||
1292 | return shape.IsPolyhedral(); | ||
1293 | } | ||
1294 | public override bool IsConvex2d(BulletShape pShape) | ||
1295 | { | ||
1296 | CollisionShape shape = (pShape as BulletShapeXNA).shape; | ||
1297 | return shape.IsConvex2d(); | ||
1298 | } | ||
1299 | public override bool IsConvex(BulletShape pShape) | ||
1300 | { | ||
1301 | CollisionShape shape = (pShape as BulletShapeXNA).shape; | ||
1302 | return shape.IsConvex(); | ||
1303 | } | ||
1304 | public override bool IsNonMoving(BulletShape pShape) | ||
1305 | { | ||
1306 | CollisionShape shape = (pShape as BulletShapeXNA).shape; | ||
1307 | return shape.IsNonMoving(); | ||
1308 | } | ||
1309 | public override bool IsConcave(BulletShape pShape) | ||
1310 | { | ||
1311 | CollisionShape shape = (pShape as BulletShapeXNA).shape; | ||
1312 | return shape.IsConcave(); | ||
1313 | } | ||
1314 | public override bool IsInfinite(BulletShape pShape) | ||
1315 | { | ||
1316 | CollisionShape shape = (pShape as BulletShapeXNA).shape; | ||
1317 | return shape.IsInfinite(); | ||
1318 | } | ||
1319 | public override bool IsNativeShape(BulletShape pShape) | ||
1320 | { | ||
1321 | CollisionShape shape = (pShape as BulletShapeXNA).shape; | ||
1322 | bool ret; | ||
1323 | switch (shape.GetShapeType()) | ||
1324 | { | ||
1325 | case BroadphaseNativeTypes.BOX_SHAPE_PROXYTYPE: | ||
1326 | case BroadphaseNativeTypes.CONE_SHAPE_PROXYTYPE: | ||
1327 | case BroadphaseNativeTypes.SPHERE_SHAPE_PROXYTYPE: | ||
1328 | case BroadphaseNativeTypes.CYLINDER_SHAPE_PROXYTYPE: | ||
1329 | ret = true; | ||
1330 | break; | ||
1331 | default: | ||
1332 | ret = false; | ||
1333 | break; | ||
1334 | } | ||
1335 | return ret; | ||
1336 | } | ||
1337 | |||
1338 | public override void SetShapeCollisionMargin(BulletShape pShape, float pMargin) | ||
1339 | { | ||
1340 | CollisionShape shape = (pShape as BulletShapeXNA).shape; | ||
1341 | shape.SetMargin(pMargin); | ||
1342 | } | ||
1343 | |||
1344 | //sim.ptr, shape.ptr,prim.LocalID, prim.RawPosition, prim.RawOrientation | ||
1345 | public override BulletBody CreateGhostFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation) | ||
1346 | { | ||
1347 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
1348 | IndexedMatrix bodyTransform = new IndexedMatrix(); | ||
1349 | bodyTransform._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z); | ||
1350 | bodyTransform.SetRotation(new IndexedQuaternion(pRawOrientation.X,pRawOrientation.Y,pRawOrientation.Z,pRawOrientation.W)); | ||
1351 | GhostObject gObj = new PairCachingGhostObject(); | ||
1352 | gObj.SetWorldTransform(bodyTransform); | ||
1353 | CollisionShape shape = (pShape as BulletShapeXNA).shape; | ||
1354 | gObj.SetCollisionShape(shape); | ||
1355 | gObj.SetUserPointer(pLocalID); | ||
1356 | |||
1357 | if (specialCollisionObjects.ContainsKey(pLocalID)) | ||
1358 | specialCollisionObjects[pLocalID] = gObj; | ||
1359 | else | ||
1360 | specialCollisionObjects.Add(pLocalID, gObj); | ||
1361 | |||
1362 | // TODO: Add to Special CollisionObjects! | ||
1363 | return new BulletBodyXNA(pLocalID, gObj); | ||
1364 | } | ||
1365 | |||
1366 | public override void SetCollisionShape(BulletWorld pWorld, BulletBody pCollisionObject, BulletShape pShape) | ||
1367 | { | ||
1368 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
1369 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; | ||
1370 | if (pShape == null) | ||
1371 | { | ||
1372 | collisionObject.SetCollisionShape(new EmptyShape()); | ||
1373 | } | ||
1374 | else | ||
1375 | { | ||
1376 | CollisionShape shape = (pShape as BulletShapeXNA).shape; | ||
1377 | collisionObject.SetCollisionShape(shape); | ||
1378 | } | ||
1379 | } | ||
1380 | public override BulletShape GetCollisionShape(BulletBody pCollisionObject) | ||
1381 | { | ||
1382 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; | ||
1383 | CollisionShape shape = collisionObject.GetCollisionShape(); | ||
1384 | return new BulletShapeXNA(shape, BSShapeTypeFromBroadPhaseNativeType(shape.GetShapeType())); | ||
1385 | } | ||
1386 | |||
1387 | //(PhysicsScene.World.ptr, nativeShapeData) | ||
1388 | public override BulletShape BuildNativeShape(BulletWorld pWorld, ShapeData pShapeData) | ||
1389 | { | ||
1390 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
1391 | CollisionShape shape = null; | ||
1392 | switch (pShapeData.Type) | ||
1393 | { | ||
1394 | case BSPhysicsShapeType.SHAPE_BOX: | ||
1395 | shape = new BoxShape(new IndexedVector3(0.5f,0.5f,0.5f)); | ||
1396 | break; | ||
1397 | case BSPhysicsShapeType.SHAPE_CONE: | ||
1398 | shape = new ConeShapeZ(0.5f, 1.0f); | ||
1399 | break; | ||
1400 | case BSPhysicsShapeType.SHAPE_CYLINDER: | ||
1401 | shape = new CylinderShapeZ(new IndexedVector3(0.5f, 0.5f, 0.5f)); | ||
1402 | break; | ||
1403 | case BSPhysicsShapeType.SHAPE_SPHERE: | ||
1404 | shape = new SphereShape(0.5f); | ||
1405 | break; | ||
1406 | |||
1407 | } | ||
1408 | if (shape != null) | ||
1409 | { | ||
1410 | IndexedVector3 scaling = new IndexedVector3(pShapeData.Scale.X, pShapeData.Scale.Y, pShapeData.Scale.Z); | ||
1411 | shape.SetMargin(world.WorldSettings.Params.collisionMargin); | ||
1412 | shape.SetLocalScaling(ref scaling); | ||
1413 | |||
1414 | } | ||
1415 | return new BulletShapeXNA(shape, pShapeData.Type); | ||
1416 | } | ||
1417 | //PhysicsScene.World.ptr, false | ||
1418 | public override BulletShape CreateCompoundShape(BulletWorld pWorld, bool enableDynamicAabbTree) | ||
1419 | { | ||
1420 | return new BulletShapeXNA(new CompoundShape(enableDynamicAabbTree), BSPhysicsShapeType.SHAPE_COMPOUND); | ||
1421 | } | ||
1422 | |||
1423 | public override int GetNumberOfCompoundChildren(BulletShape pCompoundShape) | ||
1424 | { | ||
1425 | CompoundShape compoundshape = (pCompoundShape as BulletShapeXNA).shape as CompoundShape; | ||
1426 | return compoundshape.GetNumChildShapes(); | ||
1427 | } | ||
1428 | //LinksetRoot.PhysShape.ptr, newShape.ptr, displacementPos, displacementRot | ||
1429 | public override void AddChildShapeToCompoundShape(BulletShape pCShape, BulletShape paddShape, Vector3 displacementPos, Quaternion displacementRot) | ||
1430 | { | ||
1431 | IndexedMatrix relativeTransform = new IndexedMatrix(); | ||
1432 | CompoundShape compoundshape = (pCShape as BulletShapeXNA).shape as CompoundShape; | ||
1433 | CollisionShape addshape = (paddShape as BulletShapeXNA).shape; | ||
1434 | |||
1435 | relativeTransform._origin = new IndexedVector3(displacementPos.X, displacementPos.Y, displacementPos.Z); | ||
1436 | relativeTransform.SetRotation(new IndexedQuaternion(displacementRot.X,displacementRot.Y,displacementRot.Z,displacementRot.W)); | ||
1437 | compoundshape.AddChildShape(ref relativeTransform, addshape); | ||
1438 | |||
1439 | } | ||
1440 | |||
1441 | public override BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape pCShape, int pii) | ||
1442 | { | ||
1443 | CompoundShape compoundshape = (pCShape as BulletShapeXNA).shape as CompoundShape; | ||
1444 | CollisionShape ret = null; | ||
1445 | ret = compoundshape.GetChildShape(pii); | ||
1446 | compoundshape.RemoveChildShapeByIndex(pii); | ||
1447 | return new BulletShapeXNA(ret, BSShapeTypeFromBroadPhaseNativeType(ret.GetShapeType())); | ||
1448 | } | ||
1449 | |||
1450 | public override BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx) { | ||
1451 | |||
1452 | if (cShape == null) | ||
1453 | return null; | ||
1454 | CompoundShape compoundShape = (cShape as BulletShapeXNA).shape as CompoundShape; | ||
1455 | CollisionShape shape = compoundShape.GetChildShape(indx); | ||
1456 | BulletShape retShape = new BulletShapeXNA(shape, BSShapeTypeFromBroadPhaseNativeType(shape.GetShapeType())); | ||
1457 | |||
1458 | |||
1459 | return retShape; | ||
1460 | } | ||
1461 | |||
1462 | public BSPhysicsShapeType BSShapeTypeFromBroadPhaseNativeType(BroadphaseNativeTypes pin) | ||
1463 | { | ||
1464 | BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1465 | switch (pin) | ||
1466 | { | ||
1467 | case BroadphaseNativeTypes.BOX_SHAPE_PROXYTYPE: | ||
1468 | ret = BSPhysicsShapeType.SHAPE_BOX; | ||
1469 | break; | ||
1470 | case BroadphaseNativeTypes.TRIANGLE_SHAPE_PROXYTYPE: | ||
1471 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1472 | break; | ||
1473 | |||
1474 | case BroadphaseNativeTypes.TETRAHEDRAL_SHAPE_PROXYTYPE: | ||
1475 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1476 | break; | ||
1477 | case BroadphaseNativeTypes.CONVEX_TRIANGLEMESH_SHAPE_PROXYTYPE: | ||
1478 | ret = BSPhysicsShapeType.SHAPE_MESH; | ||
1479 | break; | ||
1480 | case BroadphaseNativeTypes.CONVEX_HULL_SHAPE_PROXYTYPE: | ||
1481 | ret = BSPhysicsShapeType.SHAPE_HULL; | ||
1482 | break; | ||
1483 | case BroadphaseNativeTypes.CONVEX_POINT_CLOUD_SHAPE_PROXYTYPE: | ||
1484 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1485 | break; | ||
1486 | case BroadphaseNativeTypes.CUSTOM_POLYHEDRAL_SHAPE_TYPE: | ||
1487 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1488 | break; | ||
1489 | //implicit convex shapes | ||
1490 | case BroadphaseNativeTypes.IMPLICIT_CONVEX_SHAPES_START_HERE: | ||
1491 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1492 | break; | ||
1493 | case BroadphaseNativeTypes.SPHERE_SHAPE_PROXYTYPE: | ||
1494 | ret = BSPhysicsShapeType.SHAPE_SPHERE; | ||
1495 | break; | ||
1496 | case BroadphaseNativeTypes.MULTI_SPHERE_SHAPE_PROXYTYPE: | ||
1497 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1498 | break; | ||
1499 | case BroadphaseNativeTypes.CAPSULE_SHAPE_PROXYTYPE: | ||
1500 | ret = BSPhysicsShapeType.SHAPE_CAPSULE; | ||
1501 | break; | ||
1502 | case BroadphaseNativeTypes.CONE_SHAPE_PROXYTYPE: | ||
1503 | ret = BSPhysicsShapeType.SHAPE_CONE; | ||
1504 | break; | ||
1505 | case BroadphaseNativeTypes.CONVEX_SHAPE_PROXYTYPE: | ||
1506 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1507 | break; | ||
1508 | case BroadphaseNativeTypes.CYLINDER_SHAPE_PROXYTYPE: | ||
1509 | ret = BSPhysicsShapeType.SHAPE_CYLINDER; | ||
1510 | break; | ||
1511 | case BroadphaseNativeTypes.UNIFORM_SCALING_SHAPE_PROXYTYPE: | ||
1512 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1513 | break; | ||
1514 | case BroadphaseNativeTypes.MINKOWSKI_SUM_SHAPE_PROXYTYPE: | ||
1515 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1516 | break; | ||
1517 | case BroadphaseNativeTypes.MINKOWSKI_DIFFERENCE_SHAPE_PROXYTYPE: | ||
1518 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1519 | break; | ||
1520 | case BroadphaseNativeTypes.BOX_2D_SHAPE_PROXYTYPE: | ||
1521 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1522 | break; | ||
1523 | case BroadphaseNativeTypes.CONVEX_2D_SHAPE_PROXYTYPE: | ||
1524 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1525 | break; | ||
1526 | case BroadphaseNativeTypes.CUSTOM_CONVEX_SHAPE_TYPE: | ||
1527 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1528 | break; | ||
1529 | //concave shape | ||
1530 | case BroadphaseNativeTypes.CONCAVE_SHAPES_START_HERE: | ||
1531 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1532 | break; | ||
1533 | //keep all the convex shapetype below here, for the check IsConvexShape in broadphase proxy! | ||
1534 | case BroadphaseNativeTypes.TRIANGLE_MESH_SHAPE_PROXYTYPE: | ||
1535 | ret = BSPhysicsShapeType.SHAPE_MESH; | ||
1536 | break; | ||
1537 | case BroadphaseNativeTypes.SCALED_TRIANGLE_MESH_SHAPE_PROXYTYPE: | ||
1538 | ret = BSPhysicsShapeType.SHAPE_MESH; | ||
1539 | break; | ||
1540 | ///used for demo integration FAST/Swift collision library and Bullet | ||
1541 | case BroadphaseNativeTypes.FAST_CONCAVE_MESH_PROXYTYPE: | ||
1542 | ret = BSPhysicsShapeType.SHAPE_MESH; | ||
1543 | break; | ||
1544 | //terrain | ||
1545 | case BroadphaseNativeTypes.TERRAIN_SHAPE_PROXYTYPE: | ||
1546 | ret = BSPhysicsShapeType.SHAPE_HEIGHTMAP; | ||
1547 | break; | ||
1548 | ///Used for GIMPACT Trimesh integration | ||
1549 | case BroadphaseNativeTypes.GIMPACT_SHAPE_PROXYTYPE: | ||
1550 | ret = BSPhysicsShapeType.SHAPE_MESH; | ||
1551 | break; | ||
1552 | ///Multimaterial mesh | ||
1553 | case BroadphaseNativeTypes.MULTIMATERIAL_TRIANGLE_MESH_PROXYTYPE: | ||
1554 | ret = BSPhysicsShapeType.SHAPE_MESH; | ||
1555 | break; | ||
1556 | |||
1557 | case BroadphaseNativeTypes.EMPTY_SHAPE_PROXYTYPE: | ||
1558 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1559 | break; | ||
1560 | case BroadphaseNativeTypes.STATIC_PLANE_PROXYTYPE: | ||
1561 | ret = BSPhysicsShapeType.SHAPE_GROUNDPLANE; | ||
1562 | break; | ||
1563 | case BroadphaseNativeTypes.CUSTOM_CONCAVE_SHAPE_TYPE: | ||
1564 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1565 | break; | ||
1566 | case BroadphaseNativeTypes.CONCAVE_SHAPES_END_HERE: | ||
1567 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1568 | break; | ||
1569 | |||
1570 | case BroadphaseNativeTypes.COMPOUND_SHAPE_PROXYTYPE: | ||
1571 | ret = BSPhysicsShapeType.SHAPE_COMPOUND; | ||
1572 | break; | ||
1573 | |||
1574 | case BroadphaseNativeTypes.SOFTBODY_SHAPE_PROXYTYPE: | ||
1575 | ret = BSPhysicsShapeType.SHAPE_MESH; | ||
1576 | break; | ||
1577 | case BroadphaseNativeTypes.HFFLUID_SHAPE_PROXYTYPE: | ||
1578 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1579 | break; | ||
1580 | case BroadphaseNativeTypes.HFFLUID_BUOYANT_CONVEX_SHAPE_PROXYTYPE: | ||
1581 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1582 | break; | ||
1583 | case BroadphaseNativeTypes.INVALID_SHAPE_PROXYTYPE: | ||
1584 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1585 | break; | ||
1586 | } | ||
1587 | return ret; | ||
1588 | } | ||
1589 | |||
1590 | public override void RemoveChildShapeFromCompoundShape(BulletShape cShape, BulletShape removeShape) { /* TODO */ } | ||
1591 | public override void UpdateChildTransform(BulletShape pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb) { /* TODO */ } | ||
1592 | |||
1593 | public override BulletShape CreateGroundPlaneShape(uint pLocalId, float pheight, float pcollisionMargin) | ||
1594 | { | ||
1595 | StaticPlaneShape m_planeshape = new StaticPlaneShape(new IndexedVector3(0,0,1),(int)pheight ); | ||
1596 | m_planeshape.SetMargin(pcollisionMargin); | ||
1597 | m_planeshape.SetUserPointer(pLocalId); | ||
1598 | return new BulletShapeXNA(m_planeshape, BSPhysicsShapeType.SHAPE_GROUNDPLANE); | ||
1599 | } | ||
1600 | |||
1601 | public override BulletConstraint Create6DofSpringConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, | ||
1602 | Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot, | ||
1603 | bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) | ||
1604 | |||
1605 | { | ||
1606 | Generic6DofSpringConstraint constrain = null; | ||
1607 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
1608 | RigidBody body1 = (pBody1 as BulletBodyXNA).rigidBody; | ||
1609 | RigidBody body2 = (pBody2 as BulletBodyXNA).rigidBody; | ||
1610 | if (body1 != null && body2 != null) | ||
1611 | { | ||
1612 | IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z); | ||
1613 | IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W); | ||
1614 | IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot); | ||
1615 | frame1._origin = frame1v; | ||
1616 | |||
1617 | IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z); | ||
1618 | IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W); | ||
1619 | IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot); | ||
1620 | frame2._origin = frame1v; | ||
1621 | |||
1622 | constrain = new Generic6DofSpringConstraint(body1, body2, ref frame1, ref frame2, puseLinearReferenceFrameA); | ||
1623 | world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies); | ||
1624 | |||
1625 | constrain.CalculateTransforms(); | ||
1626 | } | ||
1627 | |||
1628 | return new BulletConstraintXNA(constrain); | ||
1629 | } | ||
1630 | |||
1631 | public override BulletConstraint CreateHingeConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, | ||
1632 | Vector3 ppivotInA, Vector3 ppivotInB, Vector3 paxisInA, Vector3 paxisInB, | ||
1633 | bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) | ||
1634 | { | ||
1635 | HingeConstraint constrain = null; | ||
1636 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
1637 | RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody; | ||
1638 | RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody; | ||
1639 | if (rb1 != null && rb2 != null) | ||
1640 | { | ||
1641 | IndexedVector3 pivotInA = new IndexedVector3(ppivotInA.X, ppivotInA.Y, ppivotInA.Z); | ||
1642 | IndexedVector3 pivotInB = new IndexedVector3(ppivotInB.X, ppivotInB.Y, ppivotInB.Z); | ||
1643 | IndexedVector3 axisInA = new IndexedVector3(paxisInA.X, paxisInA.Y, paxisInA.Z); | ||
1644 | IndexedVector3 axisInB = new IndexedVector3(paxisInB.X, paxisInB.Y, paxisInB.Z); | ||
1645 | constrain = new HingeConstraint(rb1, rb2, ref pivotInA, ref pivotInB, ref axisInA, ref axisInB, puseLinearReferenceFrameA); | ||
1646 | world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies); | ||
1647 | } | ||
1648 | return new BulletConstraintXNA(constrain); | ||
1649 | } | ||
1650 | |||
1651 | public override BulletConstraint CreateSliderConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, | ||
1652 | Vector3 pframe1, Quaternion pframe1rot, | ||
1653 | Vector3 pframe2, Quaternion pframe2rot, | ||
1654 | bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) | ||
1655 | { | ||
1656 | SliderConstraint constrain = null; | ||
1657 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
1658 | RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody; | ||
1659 | RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody; | ||
1660 | if (rb1 != null && rb2 != null) | ||
1661 | { | ||
1662 | IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z); | ||
1663 | IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W); | ||
1664 | IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot); | ||
1665 | frame1._origin = frame1v; | ||
1666 | |||
1667 | IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z); | ||
1668 | IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W); | ||
1669 | IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot); | ||
1670 | frame2._origin = frame1v; | ||
1671 | |||
1672 | constrain = new SliderConstraint(rb1, rb2, ref frame1, ref frame2, puseLinearReferenceFrameA); | ||
1673 | world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies); | ||
1674 | } | ||
1675 | return new BulletConstraintXNA(constrain); | ||
1676 | } | ||
1677 | |||
1678 | public override BulletConstraint CreateConeTwistConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, | ||
1679 | Vector3 pframe1, Quaternion pframe1rot, | ||
1680 | Vector3 pframe2, Quaternion pframe2rot, | ||
1681 | bool pdisableCollisionsBetweenLinkedBodies) | ||
1682 | { | ||
1683 | ConeTwistConstraint constrain = null; | ||
1684 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
1685 | RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody; | ||
1686 | RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody; | ||
1687 | if (rb1 != null && rb2 != null) | ||
1688 | { | ||
1689 | IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z); | ||
1690 | IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W); | ||
1691 | IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot); | ||
1692 | frame1._origin = frame1v; | ||
1693 | |||
1694 | IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z); | ||
1695 | IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W); | ||
1696 | IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot); | ||
1697 | frame2._origin = frame1v; | ||
1698 | |||
1699 | constrain = new ConeTwistConstraint(rb1, rb2, ref frame1, ref frame2); | ||
1700 | world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies); | ||
1701 | } | ||
1702 | return new BulletConstraintXNA(constrain); | ||
1703 | } | ||
1704 | |||
1705 | public override BulletConstraint CreateGearConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, | ||
1706 | Vector3 paxisInA, Vector3 paxisInB, | ||
1707 | float pratio, bool pdisableCollisionsBetweenLinkedBodies) | ||
1708 | { | ||
1709 | Generic6DofConstraint constrain = null; | ||
1710 | /* BulletXNA does not have a gear constraint | ||
1711 | GearConstraint constrain = null; | ||
1712 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
1713 | RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody; | ||
1714 | RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody; | ||
1715 | if (rb1 != null && rb2 != null) | ||
1716 | { | ||
1717 | IndexedVector3 axis1 = new IndexedVector3(paxisInA.X, paxisInA.Y, paxisInA.Z); | ||
1718 | IndexedVector3 axis2 = new IndexedVector3(paxisInB.X, paxisInB.Y, paxisInB.Z); | ||
1719 | constrain = new GearConstraint(rb1, rb2, ref axis1, ref axis2, pratio); | ||
1720 | world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies); | ||
1721 | } | ||
1722 | */ | ||
1723 | return new BulletConstraintXNA(constrain); | ||
1724 | } | ||
1725 | |||
1726 | public override BulletConstraint CreatePoint2PointConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, | ||
1727 | Vector3 ppivotInA, Vector3 ppivotInB, | ||
1728 | bool pdisableCollisionsBetweenLinkedBodies) | ||
1729 | { | ||
1730 | Point2PointConstraint constrain = null; | ||
1731 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
1732 | RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody; | ||
1733 | RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody; | ||
1734 | if (rb1 != null && rb2 != null) | ||
1735 | { | ||
1736 | IndexedVector3 pivotInA = new IndexedVector3(ppivotInA.X, ppivotInA.Y, ppivotInA.Z); | ||
1737 | IndexedVector3 pivotInB = new IndexedVector3(ppivotInB.X, ppivotInB.Y, ppivotInB.Z); | ||
1738 | constrain = new Point2PointConstraint(rb1, rb2, ref pivotInA, ref pivotInB); | ||
1739 | world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies); | ||
1740 | } | ||
1741 | return new BulletConstraintXNA(constrain); | ||
1742 | } | ||
1743 | |||
1744 | public override BulletShape CreateHullShape(BulletWorld pWorld, int pHullCount, float[] pConvHulls) | ||
1745 | { | ||
1746 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
1747 | CompoundShape compoundshape = new CompoundShape(false); | ||
1748 | |||
1749 | compoundshape.SetMargin(world.WorldSettings.Params.collisionMargin); | ||
1750 | int ii = 1; | ||
1751 | |||
1752 | for (int i = 0; i < pHullCount; i++) | ||
1753 | { | ||
1754 | int vertexCount = (int) pConvHulls[ii]; | ||
1755 | |||
1756 | IndexedVector3 centroid = new IndexedVector3(pConvHulls[ii + 1], pConvHulls[ii + 2], pConvHulls[ii + 3]); | ||
1757 | IndexedMatrix childTrans = IndexedMatrix.Identity; | ||
1758 | childTrans._origin = centroid; | ||
1759 | |||
1760 | List<IndexedVector3> virts = new List<IndexedVector3>(); | ||
1761 | int ender = ((ii + 4) + (vertexCount*3)); | ||
1762 | for (int iii = ii + 4; iii < ender; iii+=3) | ||
1763 | { | ||
1764 | |||
1765 | virts.Add(new IndexedVector3(pConvHulls[iii], pConvHulls[iii + 1], pConvHulls[iii +2])); | ||
1766 | } | ||
1767 | ConvexHullShape convexShape = new ConvexHullShape(virts, vertexCount); | ||
1768 | convexShape.SetMargin(world.WorldSettings.Params.collisionMargin); | ||
1769 | compoundshape.AddChildShape(ref childTrans, convexShape); | ||
1770 | ii += (vertexCount*3 + 4); | ||
1771 | } | ||
1772 | |||
1773 | return new BulletShapeXNA(compoundshape, BSPhysicsShapeType.SHAPE_HULL); | ||
1774 | } | ||
1775 | |||
1776 | public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape) | ||
1777 | { | ||
1778 | /* TODO */ return null; | ||
1779 | |||
1780 | } | ||
1781 | |||
1782 | public override BulletShape CreateMeshShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats) | ||
1783 | { | ||
1784 | //DumpRaw(indices,verticesAsFloats,pIndicesCount,pVerticesCount); | ||
1785 | |||
1786 | for (int iter = 0; iter < pVerticesCount; iter++) | ||
1787 | { | ||
1788 | if (verticesAsFloats[iter] > 0 && verticesAsFloats[iter] < 0.0001) verticesAsFloats[iter] = 0; | ||
1789 | if (verticesAsFloats[iter] < 0 && verticesAsFloats[iter] > -0.0001) verticesAsFloats[iter] = 0; | ||
1790 | } | ||
1791 | |||
1792 | ObjectArray<int> indicesarr = new ObjectArray<int>(indices); | ||
1793 | ObjectArray<float> vertices = new ObjectArray<float>(verticesAsFloats); | ||
1794 | DumpRaw(indicesarr,vertices,pIndicesCount,pVerticesCount); | ||
1795 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
1796 | IndexedMesh mesh = new IndexedMesh(); | ||
1797 | mesh.m_indexType = PHY_ScalarType.PHY_INTEGER; | ||
1798 | mesh.m_numTriangles = pIndicesCount/3; | ||
1799 | mesh.m_numVertices = pVerticesCount; | ||
1800 | mesh.m_triangleIndexBase = indicesarr; | ||
1801 | mesh.m_vertexBase = vertices; | ||
1802 | mesh.m_vertexStride = 3; | ||
1803 | mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT; | ||
1804 | mesh.m_triangleIndexStride = 3; | ||
1805 | |||
1806 | TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray(); | ||
1807 | tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER); | ||
1808 | BvhTriangleMeshShape meshShape = new BvhTriangleMeshShape(tribuilder, true,true); | ||
1809 | meshShape.SetMargin(world.WorldSettings.Params.collisionMargin); | ||
1810 | // world.UpdateSingleAabb(meshShape); | ||
1811 | return new BulletShapeXNA(meshShape, BSPhysicsShapeType.SHAPE_MESH); | ||
1812 | |||
1813 | } | ||
1814 | public static void DumpRaw(ObjectArray<int>indices, ObjectArray<float> vertices, int pIndicesCount,int pVerticesCount ) | ||
1815 | { | ||
1816 | |||
1817 | String fileName = "objTest3.raw"; | ||
1818 | String completePath = System.IO.Path.Combine(Util.configDir(), fileName); | ||
1819 | StreamWriter sw = new StreamWriter(completePath); | ||
1820 | IndexedMesh mesh = new IndexedMesh(); | ||
1821 | |||
1822 | mesh.m_indexType = PHY_ScalarType.PHY_INTEGER; | ||
1823 | mesh.m_numTriangles = pIndicesCount / 3; | ||
1824 | mesh.m_numVertices = pVerticesCount; | ||
1825 | mesh.m_triangleIndexBase = indices; | ||
1826 | mesh.m_vertexBase = vertices; | ||
1827 | mesh.m_vertexStride = 3; | ||
1828 | mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT; | ||
1829 | mesh.m_triangleIndexStride = 3; | ||
1830 | |||
1831 | TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray(); | ||
1832 | tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER); | ||
1833 | |||
1834 | |||
1835 | |||
1836 | for (int i = 0; i < pVerticesCount; i++) | ||
1837 | { | ||
1838 | |||
1839 | string s = vertices[indices[i * 3]].ToString("0.0000"); | ||
1840 | s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000"); | ||
1841 | s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000"); | ||
1842 | |||
1843 | sw.Write(s + "\n"); | ||
1844 | } | ||
1845 | |||
1846 | sw.Close(); | ||
1847 | } | ||
1848 | public static void DumpRaw(int[] indices, float[] vertices, int pIndicesCount, int pVerticesCount) | ||
1849 | { | ||
1850 | |||
1851 | String fileName = "objTest6.raw"; | ||
1852 | String completePath = System.IO.Path.Combine(Util.configDir(), fileName); | ||
1853 | StreamWriter sw = new StreamWriter(completePath); | ||
1854 | IndexedMesh mesh = new IndexedMesh(); | ||
1855 | |||
1856 | mesh.m_indexType = PHY_ScalarType.PHY_INTEGER; | ||
1857 | mesh.m_numTriangles = pIndicesCount / 3; | ||
1858 | mesh.m_numVertices = pVerticesCount; | ||
1859 | mesh.m_triangleIndexBase = indices; | ||
1860 | mesh.m_vertexBase = vertices; | ||
1861 | mesh.m_vertexStride = 3; | ||
1862 | mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT; | ||
1863 | mesh.m_triangleIndexStride = 3; | ||
1864 | |||
1865 | TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray(); | ||
1866 | tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER); | ||
1867 | |||
1868 | |||
1869 | sw.WriteLine("Indices"); | ||
1870 | sw.WriteLine(string.Format("int[] indices = new int[{0}];",pIndicesCount)); | ||
1871 | for (int iter = 0; iter < indices.Length; iter++) | ||
1872 | { | ||
1873 | sw.WriteLine(string.Format("indices[{0}]={1};",iter,indices[iter])); | ||
1874 | } | ||
1875 | sw.WriteLine("VerticesFloats"); | ||
1876 | sw.WriteLine(string.Format("float[] vertices = new float[{0}];", pVerticesCount)); | ||
1877 | for (int iter = 0; iter < vertices.Length; iter++) | ||
1878 | { | ||
1879 | sw.WriteLine(string.Format("Vertices[{0}]={1};", iter, vertices[iter].ToString("0.0000"))); | ||
1880 | } | ||
1881 | |||
1882 | // for (int i = 0; i < pVerticesCount; i++) | ||
1883 | // { | ||
1884 | // | ||
1885 | // string s = vertices[indices[i * 3]].ToString("0.0000"); | ||
1886 | // s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000"); | ||
1887 | // s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000"); | ||
1888 | // | ||
1889 | // sw.Write(s + "\n"); | ||
1890 | //} | ||
1891 | |||
1892 | sw.Close(); | ||
1893 | } | ||
1894 | |||
1895 | public override BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap, | ||
1896 | float scaleFactor, float collisionMargin) | ||
1897 | { | ||
1898 | const int upAxis = 2; | ||
1899 | HeightfieldTerrainShape terrainShape = new HeightfieldTerrainShape((int)size.X, (int)size.Y, | ||
1900 | heightMap, scaleFactor, | ||
1901 | minHeight, maxHeight, upAxis, | ||
1902 | false); | ||
1903 | terrainShape.SetMargin(collisionMargin + 0.5f); | ||
1904 | terrainShape.SetUseDiamondSubdivision(true); | ||
1905 | terrainShape.SetUserPointer(id); | ||
1906 | return new BulletShapeXNA(terrainShape, BSPhysicsShapeType.SHAPE_TERRAIN); | ||
1907 | } | ||
1908 | |||
1909 | public override bool TranslationalLimitMotor(BulletConstraint pConstraint, float ponOff, float targetVelocity, float maxMotorForce) | ||
1910 | { | ||
1911 | TypedConstraint tconstrain = (pConstraint as BulletConstraintXNA).constrain; | ||
1912 | bool onOff = ponOff != 0; | ||
1913 | bool ret = false; | ||
1914 | |||
1915 | switch (tconstrain.GetConstraintType()) | ||
1916 | { | ||
1917 | case TypedConstraintType.D6_CONSTRAINT_TYPE: | ||
1918 | Generic6DofConstraint constrain = tconstrain as Generic6DofConstraint; | ||
1919 | constrain.GetTranslationalLimitMotor().m_enableMotor[0] = onOff; | ||
1920 | constrain.GetTranslationalLimitMotor().m_targetVelocity[0] = targetVelocity; | ||
1921 | constrain.GetTranslationalLimitMotor().m_maxMotorForce[0] = maxMotorForce; | ||
1922 | ret = true; | ||
1923 | break; | ||
1924 | } | ||
1925 | |||
1926 | |||
1927 | return ret; | ||
1928 | |||
1929 | } | ||
1930 | |||
1931 | public override int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep, | ||
1932 | out int updatedEntityCount, out int collidersCount) | ||
1933 | { | ||
1934 | /* TODO */ | ||
1935 | updatedEntityCount = 0; | ||
1936 | collidersCount = 0; | ||
1937 | |||
1938 | |||
1939 | int ret = PhysicsStep2(world,timeStep,maxSubSteps,fixedTimeStep,out updatedEntityCount,out world.physicsScene.m_updateArray, out collidersCount, out world.physicsScene.m_collisionArray); | ||
1940 | |||
1941 | return ret; | ||
1942 | } | ||
1943 | |||
1944 | private int PhysicsStep2(BulletWorld pWorld, float timeStep, int m_maxSubSteps, float m_fixedTimeStep, | ||
1945 | out int updatedEntityCount, out EntityProperties[] updatedEntities, | ||
1946 | out int collidersCount, out CollisionDesc[] colliders) | ||
1947 | { | ||
1948 | int epic = PhysicsStepint(pWorld, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out updatedEntities, | ||
1949 | out collidersCount, out colliders, m_maxCollisions, m_maxUpdatesPerFrame); | ||
1950 | return epic; | ||
1951 | } | ||
1952 | |||
1953 | private int PhysicsStepint(BulletWorld pWorld,float timeStep, int m_maxSubSteps, float m_fixedTimeStep, out int updatedEntityCount, | ||
1954 | out EntityProperties[] updatedEntities, out int collidersCount, out CollisionDesc[] colliders, int maxCollisions, int maxUpdates) | ||
1955 | { | ||
1956 | int numSimSteps = 0; | ||
1957 | Array.Clear(UpdatedObjects, 0, UpdatedObjects.Length); | ||
1958 | Array.Clear(UpdatedCollisions, 0, UpdatedCollisions.Length); | ||
1959 | LastEntityProperty=0; | ||
1960 | |||
1961 | |||
1962 | |||
1963 | |||
1964 | |||
1965 | |||
1966 | LastCollisionDesc=0; | ||
1967 | |||
1968 | updatedEntityCount = 0; | ||
1969 | collidersCount = 0; | ||
1970 | |||
1971 | |||
1972 | if (pWorld is BulletWorldXNA) | ||
1973 | { | ||
1974 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
1975 | |||
1976 | world.LastCollisionDesc = 0; | ||
1977 | world.LastEntityProperty = 0; | ||
1978 | numSimSteps = world.StepSimulation(timeStep, m_maxSubSteps, m_fixedTimeStep); | ||
1979 | int updates = 0; | ||
1980 | |||
1981 | PersistentManifold contactManifold; | ||
1982 | CollisionObject objA; | ||
1983 | CollisionObject objB; | ||
1984 | ManifoldPoint manifoldPoint; | ||
1985 | PairCachingGhostObject pairCachingGhostObject; | ||
1986 | |||
1987 | m_collisionsThisFrame = 0; | ||
1988 | int numManifolds = world.GetDispatcher().GetNumManifolds(); | ||
1989 | for (int j = 0; j < numManifolds; j++) | ||
1990 | { | ||
1991 | contactManifold = world.GetDispatcher().GetManifoldByIndexInternal(j); | ||
1992 | int numContacts = contactManifold.GetNumContacts(); | ||
1993 | if (numContacts == 0) | ||
1994 | continue; | ||
1995 | |||
1996 | objA = contactManifold.GetBody0() as CollisionObject; | ||
1997 | objB = contactManifold.GetBody1() as CollisionObject; | ||
1998 | |||
1999 | manifoldPoint = contactManifold.GetContactPoint(0); | ||
2000 | //IndexedVector3 contactPoint = manifoldPoint.GetPositionWorldOnB(); | ||
2001 | // IndexedVector3 contactNormal = -manifoldPoint.m_normalWorldOnB; // make relative to A | ||
2002 | |||
2003 | RecordCollision(this, objA, objB, manifoldPoint.GetPositionWorldOnB(), -manifoldPoint.m_normalWorldOnB, manifoldPoint.GetDistance()); | ||
2004 | m_collisionsThisFrame ++; | ||
2005 | if (m_collisionsThisFrame >= 9999999) | ||
2006 | break; | ||
2007 | |||
2008 | |||
2009 | } | ||
2010 | |||
2011 | foreach (GhostObject ghostObject in specialCollisionObjects.Values) | ||
2012 | { | ||
2013 | pairCachingGhostObject = ghostObject as PairCachingGhostObject; | ||
2014 | if (pairCachingGhostObject != null) | ||
2015 | { | ||
2016 | RecordGhostCollisions(pairCachingGhostObject); | ||
2017 | } | ||
2018 | |||
2019 | } | ||
2020 | |||
2021 | |||
2022 | updatedEntityCount = LastEntityProperty; | ||
2023 | updatedEntities = UpdatedObjects; | ||
2024 | |||
2025 | collidersCount = LastCollisionDesc; | ||
2026 | colliders = UpdatedCollisions; | ||
2027 | |||
2028 | |||
2029 | } | ||
2030 | else | ||
2031 | { | ||
2032 | //if (updatedEntities is null) | ||
2033 | //updatedEntities = new List<BulletXNA.EntityProperties>(); | ||
2034 | //updatedEntityCount = 0; | ||
2035 | |||
2036 | |||
2037 | //collidersCount = 0; | ||
2038 | |||
2039 | updatedEntities = new EntityProperties[0]; | ||
2040 | |||
2041 | |||
2042 | colliders = new CollisionDesc[0]; | ||
2043 | |||
2044 | } | ||
2045 | return numSimSteps; | ||
2046 | } | ||
2047 | public void RecordGhostCollisions(PairCachingGhostObject obj) | ||
2048 | { | ||
2049 | IOverlappingPairCache cache = obj.GetOverlappingPairCache(); | ||
2050 | ObjectArray<BroadphasePair> pairs = cache.GetOverlappingPairArray(); | ||
2051 | |||
2052 | DiscreteDynamicsWorld world = (PhysicsScene.World as BulletWorldXNA).world; | ||
2053 | PersistentManifoldArray manifoldArray = new PersistentManifoldArray(); | ||
2054 | BroadphasePair collisionPair; | ||
2055 | PersistentManifold contactManifold; | ||
2056 | |||
2057 | CollisionObject objA; | ||
2058 | CollisionObject objB; | ||
2059 | |||
2060 | ManifoldPoint pt; | ||
2061 | |||
2062 | int numPairs = pairs.Count; | ||
2063 | |||
2064 | for (int i = 0; i < numPairs; i++) | ||
2065 | { | ||
2066 | manifoldArray.Clear(); | ||
2067 | if (LastCollisionDesc < UpdatedCollisions.Length) | ||
2068 | break; | ||
2069 | collisionPair = world.GetPairCache().FindPair(pairs[i].m_pProxy0, pairs[i].m_pProxy1); | ||
2070 | if (collisionPair == null) | ||
2071 | continue; | ||
2072 | |||
2073 | collisionPair.m_algorithm.GetAllContactManifolds(manifoldArray); | ||
2074 | for (int j = 0; j < manifoldArray.Count; j++) | ||
2075 | { | ||
2076 | contactManifold = manifoldArray[j]; | ||
2077 | int numContacts = contactManifold.GetNumContacts(); | ||
2078 | objA = contactManifold.GetBody0() as CollisionObject; | ||
2079 | objB = contactManifold.GetBody1() as CollisionObject; | ||
2080 | for (int p = 0; p < numContacts; p++) | ||
2081 | { | ||
2082 | pt = contactManifold.GetContactPoint(p); | ||
2083 | if (pt.GetDistance() < 0.0f) | ||
2084 | { | ||
2085 | RecordCollision(this, objA, objB, pt.GetPositionWorldOnA(), -pt.m_normalWorldOnB,pt.GetDistance()); | ||
2086 | break; | ||
2087 | } | ||
2088 | } | ||
2089 | } | ||
2090 | } | ||
2091 | |||
2092 | } | ||
2093 | private static void RecordCollision(BSAPIXNA world, CollisionObject objA, CollisionObject objB, IndexedVector3 contact, IndexedVector3 norm, float penetration) | ||
2094 | { | ||
2095 | |||
2096 | IndexedVector3 contactNormal = norm; | ||
2097 | if ((objA.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0 && | ||
2098 | (objB.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0) | ||
2099 | { | ||
2100 | return; | ||
2101 | } | ||
2102 | uint idA = (uint)objA.GetUserPointer(); | ||
2103 | uint idB = (uint)objB.GetUserPointer(); | ||
2104 | if (idA > idB) | ||
2105 | { | ||
2106 | uint temp = idA; | ||
2107 | idA = idB; | ||
2108 | idB = temp; | ||
2109 | contactNormal = -contactNormal; | ||
2110 | } | ||
2111 | |||
2112 | //ulong collisionID = ((ulong) idA << 32) | idB; | ||
2113 | |||
2114 | CollisionDesc cDesc = new CollisionDesc() | ||
2115 | { | ||
2116 | aID = idA, | ||
2117 | bID = idB, | ||
2118 | point = new Vector3(contact.X,contact.Y,contact.Z), | ||
2119 | normal = new Vector3(contactNormal.X,contactNormal.Y,contactNormal.Z), | ||
2120 | penetration = penetration | ||
2121 | |||
2122 | }; | ||
2123 | if (world.LastCollisionDesc < world.UpdatedCollisions.Length) | ||
2124 | world.UpdatedCollisions[world.LastCollisionDesc++] = (cDesc); | ||
2125 | m_collisionsThisFrame++; | ||
2126 | |||
2127 | |||
2128 | } | ||
2129 | private static EntityProperties GetDebugProperties(BulletWorld pWorld, BulletBody pCollisionObject) | ||
2130 | { | ||
2131 | EntityProperties ent = new EntityProperties(); | ||
2132 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
2133 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; | ||
2134 | IndexedMatrix transform = collisionObject.GetWorldTransform(); | ||
2135 | IndexedVector3 LinearVelocity = collisionObject.GetInterpolationLinearVelocity(); | ||
2136 | IndexedVector3 AngularVelocity = collisionObject.GetInterpolationAngularVelocity(); | ||
2137 | IndexedQuaternion rotation = transform.GetRotation(); | ||
2138 | ent.Acceleration = Vector3.Zero; | ||
2139 | ent.ID = (uint)collisionObject.GetUserPointer(); | ||
2140 | ent.Position = new Vector3(transform._origin.X,transform._origin.Y,transform._origin.Z); | ||
2141 | ent.Rotation = new Quaternion(rotation.X,rotation.Y,rotation.Z,rotation.W); | ||
2142 | ent.Velocity = new Vector3(LinearVelocity.X, LinearVelocity.Y, LinearVelocity.Z); | ||
2143 | ent.RotationalVelocity = new Vector3(AngularVelocity.X, AngularVelocity.Y, AngularVelocity.Z); | ||
2144 | return ent; | ||
2145 | } | ||
2146 | |||
2147 | public override bool UpdateParameter(BulletWorld world, uint localID, String parm, float value) { /* TODO */ | ||
2148 | return false; } | ||
2149 | |||
2150 | public override Vector3 GetLocalScaling(BulletShape pShape) | ||
2151 | { | ||
2152 | CollisionShape shape = (pShape as BulletShapeXNA).shape; | ||
2153 | IndexedVector3 scale = shape.GetLocalScaling(); | ||
2154 | return new Vector3(scale.X,scale.Y,scale.Z); | ||
2155 | } | ||
2156 | |||
2157 | public bool RayCastGround(BulletWorld pWorld, Vector3 _RayOrigin, float pRayHeight, BulletBody NotMe) | ||
2158 | { | ||
2159 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
2160 | if (world != null) | ||
2161 | { | ||
2162 | if (NotMe is BulletBodyXNA && NotMe.HasPhysicalBody) | ||
2163 | { | ||
2164 | CollisionObject AvoidBody = (NotMe as BulletBodyXNA).body; | ||
2165 | |||
2166 | IndexedVector3 rOrigin = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z); | ||
2167 | IndexedVector3 rEnd = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z - pRayHeight); | ||
2168 | using ( | ||
2169 | ClosestNotMeRayResultCallback rayCallback = | ||
2170 | new ClosestNotMeRayResultCallback(rOrigin, rEnd, AvoidBody) | ||
2171 | ) | ||
2172 | { | ||
2173 | world.RayTest(ref rOrigin, ref rEnd, rayCallback); | ||
2174 | if (rayCallback.HasHit()) | ||
2175 | { | ||
2176 | IndexedVector3 hitLocation = rayCallback.m_hitPointWorld; | ||
2177 | } | ||
2178 | return rayCallback.HasHit(); | ||
2179 | } | ||
2180 | } | ||
2181 | } | ||
2182 | return false; | ||
2183 | } | ||
2184 | } | ||
2185 | |||
2186 | |||
2187 | |||
2188 | |||
2189 | public class SimMotionState : DefaultMotionState | ||
2190 | { | ||
2191 | public RigidBody Rigidbody; | ||
2192 | public Vector3 ZeroVect; | ||
2193 | |||
2194 | private IndexedMatrix m_xform; | ||
2195 | |||
2196 | private EntityProperties m_properties; | ||
2197 | private EntityProperties m_lastProperties; | ||
2198 | private BSAPIXNA m_world; | ||
2199 | |||
2200 | const float POSITION_TOLERANCE = 0.05f; | ||
2201 | const float VELOCITY_TOLERANCE = 0.001f; | ||
2202 | const float ROTATION_TOLERANCE = 0.01f; | ||
2203 | const float ANGULARVELOCITY_TOLERANCE = 0.01f; | ||
2204 | |||
2205 | public SimMotionState(BSAPIXNA pWorld, uint id, IndexedMatrix starTransform, object frameUpdates) | ||
2206 | { | ||
2207 | IndexedQuaternion OrientationQuaterion = starTransform.GetRotation(); | ||
2208 | m_properties = new EntityProperties() | ||
2209 | { | ||
2210 | ID = id, | ||
2211 | Position = new Vector3(starTransform._origin.X, starTransform._origin.Y,starTransform._origin.Z), | ||
2212 | Rotation = new Quaternion(OrientationQuaterion.X,OrientationQuaterion.Y,OrientationQuaterion.Z,OrientationQuaterion.W) | ||
2213 | }; | ||
2214 | m_lastProperties = new EntityProperties() | ||
2215 | { | ||
2216 | ID = id, | ||
2217 | Position = new Vector3(starTransform._origin.X, starTransform._origin.Y, starTransform._origin.Z), | ||
2218 | Rotation = new Quaternion(OrientationQuaterion.X, OrientationQuaterion.Y, OrientationQuaterion.Z, OrientationQuaterion.W) | ||
2219 | }; | ||
2220 | m_world = pWorld; | ||
2221 | m_xform = starTransform; | ||
2222 | } | ||
2223 | |||
2224 | public override void GetWorldTransform(out IndexedMatrix worldTrans) | ||
2225 | { | ||
2226 | worldTrans = m_xform; | ||
2227 | } | ||
2228 | |||
2229 | public override void SetWorldTransform(IndexedMatrix worldTrans) | ||
2230 | { | ||
2231 | SetWorldTransform(ref worldTrans); | ||
2232 | } | ||
2233 | |||
2234 | public override void SetWorldTransform(ref IndexedMatrix worldTrans) | ||
2235 | { | ||
2236 | SetWorldTransform(ref worldTrans, false); | ||
2237 | } | ||
2238 | public void SetWorldTransform(ref IndexedMatrix worldTrans, bool force) | ||
2239 | { | ||
2240 | m_xform = worldTrans; | ||
2241 | // Put the new transform into m_properties | ||
2242 | IndexedQuaternion OrientationQuaternion = m_xform.GetRotation(); | ||
2243 | IndexedVector3 LinearVelocityVector = Rigidbody.GetLinearVelocity(); | ||
2244 | IndexedVector3 AngularVelocityVector = Rigidbody.GetAngularVelocity(); | ||
2245 | m_properties.Position = new Vector3(m_xform._origin.X, m_xform._origin.Y, m_xform._origin.Z); | ||
2246 | m_properties.Rotation = new Quaternion(OrientationQuaternion.X, OrientationQuaternion.Y, | ||
2247 | OrientationQuaternion.Z, OrientationQuaternion.W); | ||
2248 | // A problem with stock Bullet is that we don't get an event when an object is deactivated. | ||
2249 | // This means that the last non-zero values for linear and angular velocity | ||
2250 | // are left in the viewer who does dead reconning and the objects look like | ||
2251 | // they float off. | ||
2252 | // BulletSim ships with a patch to Bullet which creates such an event. | ||
2253 | m_properties.Velocity = new Vector3(LinearVelocityVector.X, LinearVelocityVector.Y, LinearVelocityVector.Z); | ||
2254 | m_properties.RotationalVelocity = new Vector3(AngularVelocityVector.X, AngularVelocityVector.Y, AngularVelocityVector.Z); | ||
2255 | |||
2256 | if (force | ||
2257 | |||
2258 | || !AlmostEqual(ref m_lastProperties.Position, ref m_properties.Position, POSITION_TOLERANCE) | ||
2259 | || !AlmostEqual(ref m_properties.Rotation, ref m_lastProperties.Rotation, ROTATION_TOLERANCE) | ||
2260 | // If the Velocity and AngularVelocity are zero, most likely the object has | ||
2261 | // been deactivated. If they both are zero and they have become zero recently, | ||
2262 | // make sure a property update is sent so the zeros make it to the viewer. | ||
2263 | || ((m_properties.Velocity == ZeroVect && m_properties.RotationalVelocity == ZeroVect) | ||
2264 | && | ||
2265 | (m_properties.Velocity != m_lastProperties.Velocity || | ||
2266 | m_properties.RotationalVelocity != m_lastProperties.RotationalVelocity)) | ||
2267 | // If Velocity and AngularVelocity are non-zero but have changed, send an update. | ||
2268 | || !AlmostEqual(ref m_properties.Velocity, ref m_lastProperties.Velocity, VELOCITY_TOLERANCE) | ||
2269 | || | ||
2270 | !AlmostEqual(ref m_properties.RotationalVelocity, ref m_lastProperties.RotationalVelocity, | ||
2271 | ANGULARVELOCITY_TOLERANCE) | ||
2272 | ) | ||
2273 | |||
2274 | |||
2275 | { | ||
2276 | // Add this update to the list of updates for this frame. | ||
2277 | m_lastProperties = m_properties; | ||
2278 | if (m_world.LastEntityProperty < m_world.UpdatedObjects.Length) | ||
2279 | m_world.UpdatedObjects[m_world.LastEntityProperty++]=(m_properties); | ||
2280 | |||
2281 | //(*m_updatesThisFrame)[m_properties.ID] = &m_properties; | ||
2282 | } | ||
2283 | |||
2284 | |||
2285 | |||
2286 | |||
2287 | } | ||
2288 | public override void SetRigidBody(RigidBody body) | ||
2289 | { | ||
2290 | Rigidbody = body; | ||
2291 | } | ||
2292 | internal static bool AlmostEqual(ref Vector3 v1, ref Vector3 v2, float nEpsilon) | ||
2293 | { | ||
2294 | return | ||
2295 | (((v1.X - nEpsilon) < v2.X) && (v2.X < (v1.X + nEpsilon))) && | ||
2296 | (((v1.Y - nEpsilon) < v2.Y) && (v2.Y < (v1.Y + nEpsilon))) && | ||
2297 | (((v1.Z - nEpsilon) < v2.Z) && (v2.Z < (v1.Z + nEpsilon))); | ||
2298 | } | ||
2299 | |||
2300 | internal static bool AlmostEqual(ref Quaternion v1, ref Quaternion v2, float nEpsilon) | ||
2301 | { | ||
2302 | return | ||
2303 | (((v1.X - nEpsilon) < v2.X) && (v2.X < (v1.X + nEpsilon))) && | ||
2304 | (((v1.Y - nEpsilon) < v2.Y) && (v2.Y < (v1.Y + nEpsilon))) && | ||
2305 | (((v1.Z - nEpsilon) < v2.Z) && (v2.Z < (v1.Z + nEpsilon))) && | ||
2306 | (((v1.W - nEpsilon) < v2.W) && (v2.W < (v1.W + nEpsilon))); | ||
2307 | } | ||
2308 | |||
2309 | } | ||
2310 | } | ||
2311 | |||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs b/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs new file mode 100644 index 0000000..5765b0d --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs | |||
@@ -0,0 +1,683 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Runtime.InteropServices; | ||
30 | using System.Security; | ||
31 | using System.Text; | ||
32 | using OpenMetaverse; | ||
33 | |||
34 | namespace OpenSim.Region.Physics.BulletSPlugin { | ||
35 | |||
36 | // Constraint type values as defined by Bullet | ||
37 | public enum ConstraintType : int | ||
38 | { | ||
39 | POINT2POINT_CONSTRAINT_TYPE = 3, | ||
40 | HINGE_CONSTRAINT_TYPE, | ||
41 | CONETWIST_CONSTRAINT_TYPE, | ||
42 | D6_CONSTRAINT_TYPE, | ||
43 | SLIDER_CONSTRAINT_TYPE, | ||
44 | CONTACT_CONSTRAINT_TYPE, | ||
45 | D6_SPRING_CONSTRAINT_TYPE, | ||
46 | MAX_CONSTRAINT_TYPE | ||
47 | } | ||
48 | |||
49 | // =============================================================================== | ||
50 | [StructLayout(LayoutKind.Sequential)] | ||
51 | public struct ConvexHull | ||
52 | { | ||
53 | Vector3 Offset; | ||
54 | int VertexCount; | ||
55 | Vector3[] Vertices; | ||
56 | } | ||
57 | public enum BSPhysicsShapeType | ||
58 | { | ||
59 | SHAPE_UNKNOWN = 0, | ||
60 | SHAPE_CAPSULE = 1, | ||
61 | SHAPE_BOX = 2, | ||
62 | SHAPE_CONE = 3, | ||
63 | SHAPE_CYLINDER = 4, | ||
64 | SHAPE_SPHERE = 5, | ||
65 | SHAPE_MESH = 6, | ||
66 | SHAPE_HULL = 7, | ||
67 | // following defined by BulletSim | ||
68 | SHAPE_GROUNDPLANE = 20, | ||
69 | SHAPE_TERRAIN = 21, | ||
70 | SHAPE_COMPOUND = 22, | ||
71 | SHAPE_HEIGHTMAP = 23, | ||
72 | SHAPE_AVATAR = 24, | ||
73 | }; | ||
74 | |||
75 | // The native shapes have predefined shape hash keys | ||
76 | public enum FixedShapeKey : ulong | ||
77 | { | ||
78 | KEY_NONE = 0, | ||
79 | KEY_BOX = 1, | ||
80 | KEY_SPHERE = 2, | ||
81 | KEY_CONE = 3, | ||
82 | KEY_CYLINDER = 4, | ||
83 | KEY_CAPSULE = 5, | ||
84 | KEY_AVATAR = 6, | ||
85 | } | ||
86 | |||
87 | [StructLayout(LayoutKind.Sequential)] | ||
88 | public struct ShapeData | ||
89 | { | ||
90 | public UInt32 ID; | ||
91 | public BSPhysicsShapeType Type; | ||
92 | public Vector3 Position; | ||
93 | public Quaternion Rotation; | ||
94 | public Vector3 Velocity; | ||
95 | public Vector3 Scale; | ||
96 | public float Mass; | ||
97 | public float Buoyancy; | ||
98 | public System.UInt64 HullKey; | ||
99 | public System.UInt64 MeshKey; | ||
100 | public float Friction; | ||
101 | public float Restitution; | ||
102 | public float Collidable; // true of things bump into this | ||
103 | public float Static; // true if a static object. Otherwise gravity, etc. | ||
104 | public float Solid; // true if object cannot be passed through | ||
105 | public Vector3 Size; | ||
106 | |||
107 | // note that bools are passed as floats since bool size changes by language and architecture | ||
108 | public const float numericTrue = 1f; | ||
109 | public const float numericFalse = 0f; | ||
110 | } | ||
111 | [StructLayout(LayoutKind.Sequential)] | ||
112 | public struct SweepHit | ||
113 | { | ||
114 | public UInt32 ID; | ||
115 | public float Fraction; | ||
116 | public Vector3 Normal; | ||
117 | public Vector3 Point; | ||
118 | } | ||
119 | [StructLayout(LayoutKind.Sequential)] | ||
120 | public struct RaycastHit | ||
121 | { | ||
122 | public UInt32 ID; | ||
123 | public float Fraction; | ||
124 | public Vector3 Normal; | ||
125 | } | ||
126 | [StructLayout(LayoutKind.Sequential)] | ||
127 | public struct CollisionDesc | ||
128 | { | ||
129 | public UInt32 aID; | ||
130 | public UInt32 bID; | ||
131 | public Vector3 point; | ||
132 | public Vector3 normal; | ||
133 | public float penetration; | ||
134 | } | ||
135 | [StructLayout(LayoutKind.Sequential)] | ||
136 | public struct EntityProperties | ||
137 | { | ||
138 | public UInt32 ID; | ||
139 | public Vector3 Position; | ||
140 | public Quaternion Rotation; | ||
141 | public Vector3 Velocity; | ||
142 | public Vector3 Acceleration; | ||
143 | public Vector3 RotationalVelocity; | ||
144 | |||
145 | public override string ToString() | ||
146 | { | ||
147 | StringBuilder buff = new StringBuilder(); | ||
148 | buff.Append("<i="); | ||
149 | buff.Append(ID.ToString()); | ||
150 | buff.Append(",p="); | ||
151 | buff.Append(Position.ToString()); | ||
152 | buff.Append(",r="); | ||
153 | buff.Append(Rotation.ToString()); | ||
154 | buff.Append(",v="); | ||
155 | buff.Append(Velocity.ToString()); | ||
156 | buff.Append(",a="); | ||
157 | buff.Append(Acceleration.ToString()); | ||
158 | buff.Append(",rv="); | ||
159 | buff.Append(RotationalVelocity.ToString()); | ||
160 | buff.Append(">"); | ||
161 | return buff.ToString(); | ||
162 | } | ||
163 | } | ||
164 | |||
165 | // Format of this structure must match the definition in the C++ code | ||
166 | // NOTE: adding the X causes compile breaks if used. These are unused symbols | ||
167 | // that can be removed from both here and the unmanaged definition of this structure. | ||
168 | [StructLayout(LayoutKind.Sequential)] | ||
169 | public struct ConfigurationParameters | ||
170 | { | ||
171 | public float defaultFriction; | ||
172 | public float defaultDensity; | ||
173 | public float defaultRestitution; | ||
174 | public float collisionMargin; | ||
175 | public float gravity; | ||
176 | |||
177 | public float maxPersistantManifoldPoolSize; | ||
178 | public float maxCollisionAlgorithmPoolSize; | ||
179 | public float shouldDisableContactPoolDynamicAllocation; | ||
180 | public float shouldForceUpdateAllAabbs; | ||
181 | public float shouldRandomizeSolverOrder; | ||
182 | public float shouldSplitSimulationIslands; | ||
183 | public float shouldEnableFrictionCaching; | ||
184 | public float numberOfSolverIterations; | ||
185 | public float useSingleSidedMeshes; | ||
186 | public float globalContactBreakingThreshold; | ||
187 | |||
188 | public float physicsLoggingFrames; | ||
189 | |||
190 | public const float numericTrue = 1f; | ||
191 | public const float numericFalse = 0f; | ||
192 | } | ||
193 | |||
194 | |||
195 | // The states a bullet collision object can have | ||
196 | public enum ActivationState : uint | ||
197 | { | ||
198 | ACTIVE_TAG = 1, | ||
199 | ISLAND_SLEEPING, | ||
200 | WANTS_DEACTIVATION, | ||
201 | DISABLE_DEACTIVATION, | ||
202 | DISABLE_SIMULATION, | ||
203 | } | ||
204 | |||
205 | public enum CollisionObjectTypes : int | ||
206 | { | ||
207 | CO_COLLISION_OBJECT = 1 << 0, | ||
208 | CO_RIGID_BODY = 1 << 1, | ||
209 | CO_GHOST_OBJECT = 1 << 2, | ||
210 | CO_SOFT_BODY = 1 << 3, | ||
211 | CO_HF_FLUID = 1 << 4, | ||
212 | CO_USER_TYPE = 1 << 5, | ||
213 | } | ||
214 | |||
215 | // Values used by Bullet and BulletSim to control object properties. | ||
216 | // Bullet's "CollisionFlags" has more to do with operations on the | ||
217 | // object (if collisions happen, if gravity effects it, ...). | ||
218 | public enum CollisionFlags : uint | ||
219 | { | ||
220 | CF_STATIC_OBJECT = 1 << 0, | ||
221 | CF_KINEMATIC_OBJECT = 1 << 1, | ||
222 | CF_NO_CONTACT_RESPONSE = 1 << 2, | ||
223 | CF_CUSTOM_MATERIAL_CALLBACK = 1 << 3, | ||
224 | CF_CHARACTER_OBJECT = 1 << 4, | ||
225 | CF_DISABLE_VISUALIZE_OBJECT = 1 << 5, | ||
226 | CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6, | ||
227 | // Following used by BulletSim to control collisions and updates | ||
228 | BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10, // return collision events from unmanaged to managed | ||
229 | BS_FLOATS_ON_WATER = 1 << 11, // the object should float at water level | ||
230 | BS_VEHICLE_COLLISIONS = 1 << 12, // return collisions for vehicle ground checking | ||
231 | BS_RETURN_ROOT_COMPOUND_SHAPE = 1 << 13, // return the pos/rot of the root shape in a compound shape | ||
232 | BS_NONE = 0, | ||
233 | BS_ALL = 0xFFFFFFFF | ||
234 | }; | ||
235 | |||
236 | // Values f collisions groups and masks | ||
237 | public enum CollisionFilterGroups : uint | ||
238 | { | ||
239 | // Don't use the bit definitions!! Define the use in a | ||
240 | // filter/mask definition below. This way collision interactions | ||
241 | // are more easily found and debugged. | ||
242 | BNoneGroup = 0, | ||
243 | BDefaultGroup = 1 << 0, // 0001 | ||
244 | BStaticGroup = 1 << 1, // 0002 | ||
245 | BKinematicGroup = 1 << 2, // 0004 | ||
246 | BDebrisGroup = 1 << 3, // 0008 | ||
247 | BSensorTrigger = 1 << 4, // 0010 | ||
248 | BCharacterGroup = 1 << 5, // 0020 | ||
249 | BAllGroup = 0x000FFFFF, | ||
250 | // Filter groups defined by BulletSim | ||
251 | BGroundPlaneGroup = 1 << 10, // 0400 | ||
252 | BTerrainGroup = 1 << 11, // 0800 | ||
253 | BRaycastGroup = 1 << 12, // 1000 | ||
254 | BSolidGroup = 1 << 13, // 2000 | ||
255 | // BLinksetGroup = xx // a linkset proper is either static or dynamic | ||
256 | BLinksetChildGroup = 1 << 14, // 4000 | ||
257 | }; | ||
258 | |||
259 | // CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0 | ||
260 | // ERP controls amount of correction per tick. Usable range=0.1..0.8. Default=0.2. | ||
261 | public enum ConstraintParams : int | ||
262 | { | ||
263 | BT_CONSTRAINT_ERP = 1, // this one is not used in Bullet as of 20120730 | ||
264 | BT_CONSTRAINT_STOP_ERP, | ||
265 | BT_CONSTRAINT_CFM, | ||
266 | BT_CONSTRAINT_STOP_CFM, | ||
267 | }; | ||
268 | public enum ConstraintParamAxis : int | ||
269 | { | ||
270 | AXIS_LINEAR_X = 0, | ||
271 | AXIS_LINEAR_Y, | ||
272 | AXIS_LINEAR_Z, | ||
273 | AXIS_ANGULAR_X, | ||
274 | AXIS_ANGULAR_Y, | ||
275 | AXIS_ANGULAR_Z, | ||
276 | AXIS_LINEAR_ALL = 20, // these last three added by BulletSim so we don't have to do zillions of calls | ||
277 | AXIS_ANGULAR_ALL, | ||
278 | AXIS_ALL | ||
279 | }; | ||
280 | |||
281 | public abstract class BSAPITemplate | ||
282 | { | ||
283 | // Returns the name of the underlying Bullet engine | ||
284 | public abstract string BulletEngineName { get; } | ||
285 | public abstract string BulletEngineVersion { get; protected set;} | ||
286 | |||
287 | // Initialization and simulation | ||
288 | public abstract BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms, | ||
289 | int maxCollisions, ref CollisionDesc[] collisionArray, | ||
290 | int maxUpdates, ref EntityProperties[] updateArray | ||
291 | ); | ||
292 | |||
293 | public abstract int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep, | ||
294 | out int updatedEntityCount, out int collidersCount); | ||
295 | |||
296 | public abstract bool UpdateParameter(BulletWorld world, UInt32 localID, String parm, float value); | ||
297 | |||
298 | public abstract void Shutdown(BulletWorld sim); | ||
299 | |||
300 | public abstract bool PushUpdate(BulletBody obj); | ||
301 | |||
302 | // ===================================================================================== | ||
303 | // Mesh, hull, shape and body creation helper routines | ||
304 | public abstract BulletShape CreateMeshShape(BulletWorld world, | ||
305 | int indicesCount, int[] indices, | ||
306 | int verticesCount, float[] vertices ); | ||
307 | |||
308 | public abstract BulletShape CreateHullShape(BulletWorld world, | ||
309 | int hullCount, float[] hulls); | ||
310 | |||
311 | public abstract BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape); | ||
312 | |||
313 | public abstract BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData); | ||
314 | |||
315 | public abstract bool IsNativeShape(BulletShape shape); | ||
316 | |||
317 | public abstract void SetShapeCollisionMargin(BulletShape shape, float margin); | ||
318 | |||
319 | public abstract BulletShape BuildCapsuleShape(BulletWorld world, float radius, float height, Vector3 scale); | ||
320 | |||
321 | public abstract BulletShape CreateCompoundShape(BulletWorld sim, bool enableDynamicAabbTree); | ||
322 | |||
323 | public abstract int GetNumberOfCompoundChildren(BulletShape cShape); | ||
324 | |||
325 | public abstract void AddChildShapeToCompoundShape(BulletShape cShape, BulletShape addShape, Vector3 pos, Quaternion rot); | ||
326 | |||
327 | public abstract BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx); | ||
328 | |||
329 | public abstract BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx); | ||
330 | |||
331 | public abstract void RemoveChildShapeFromCompoundShape(BulletShape cShape, BulletShape removeShape); | ||
332 | |||
333 | public abstract void UpdateChildTransform(BulletShape pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb); | ||
334 | |||
335 | public abstract void RecalculateCompoundShapeLocalAabb(BulletShape cShape); | ||
336 | |||
337 | public abstract BulletShape DuplicateCollisionShape(BulletWorld sim, BulletShape srcShape, UInt32 id); | ||
338 | |||
339 | public abstract bool DeleteCollisionShape(BulletWorld world, BulletShape shape); | ||
340 | |||
341 | public abstract CollisionObjectTypes GetBodyType(BulletBody obj); | ||
342 | |||
343 | public abstract BulletBody CreateBodyFromShape(BulletWorld sim, BulletShape shape, UInt32 id, Vector3 pos, Quaternion rot); | ||
344 | |||
345 | public abstract BulletBody CreateBodyWithDefaultMotionState(BulletShape shape, UInt32 id, Vector3 pos, Quaternion rot); | ||
346 | |||
347 | public abstract BulletBody CreateGhostFromShape(BulletWorld sim, BulletShape shape, UInt32 id, Vector3 pos, Quaternion rot); | ||
348 | |||
349 | public abstract void DestroyObject(BulletWorld sim, BulletBody obj); | ||
350 | |||
351 | // ===================================================================================== | ||
352 | public abstract BulletShape CreateGroundPlaneShape(UInt32 id, float height, float collisionMargin); | ||
353 | |||
354 | public abstract BulletShape CreateTerrainShape(UInt32 id, Vector3 size, float minHeight, float maxHeight, float[] heightMap, | ||
355 | float scaleFactor, float collisionMargin); | ||
356 | |||
357 | // ===================================================================================== | ||
358 | // Constraint creation and helper routines | ||
359 | public abstract BulletConstraint Create6DofConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
360 | Vector3 frame1loc, Quaternion frame1rot, | ||
361 | Vector3 frame2loc, Quaternion frame2rot, | ||
362 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); | ||
363 | |||
364 | public abstract BulletConstraint Create6DofConstraintToPoint(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
365 | Vector3 joinPoint, | ||
366 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); | ||
367 | |||
368 | public abstract BulletConstraint Create6DofConstraintFixed(BulletWorld world, BulletBody obj1, | ||
369 | Vector3 frameInBloc, Quaternion frameInBrot, | ||
370 | bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies); | ||
371 | |||
372 | public abstract BulletConstraint Create6DofSpringConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
373 | Vector3 frame1loc, Quaternion frame1rot, | ||
374 | Vector3 frame2loc, Quaternion frame2rot, | ||
375 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); | ||
376 | |||
377 | public abstract BulletConstraint CreateHingeConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
378 | Vector3 pivotinA, Vector3 pivotinB, | ||
379 | Vector3 axisInA, Vector3 axisInB, | ||
380 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); | ||
381 | |||
382 | public abstract BulletConstraint CreateSliderConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
383 | Vector3 frameInAloc, Quaternion frameInArot, | ||
384 | Vector3 frameInBloc, Quaternion frameInBrot, | ||
385 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); | ||
386 | |||
387 | public abstract BulletConstraint CreateConeTwistConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
388 | Vector3 frameInAloc, Quaternion frameInArot, | ||
389 | Vector3 frameInBloc, Quaternion frameInBrot, | ||
390 | bool disableCollisionsBetweenLinkedBodies); | ||
391 | |||
392 | public abstract BulletConstraint CreateGearConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
393 | Vector3 axisInA, Vector3 axisInB, | ||
394 | float ratio, bool disableCollisionsBetweenLinkedBodies); | ||
395 | |||
396 | public abstract BulletConstraint CreatePoint2PointConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
397 | Vector3 pivotInA, Vector3 pivotInB, | ||
398 | bool disableCollisionsBetweenLinkedBodies); | ||
399 | |||
400 | public abstract void SetConstraintEnable(BulletConstraint constrain, float numericTrueFalse); | ||
401 | |||
402 | public abstract void SetConstraintNumSolverIterations(BulletConstraint constrain, float iterations); | ||
403 | |||
404 | public abstract bool SetFrames(BulletConstraint constrain, | ||
405 | Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot); | ||
406 | |||
407 | public abstract bool SetLinearLimits(BulletConstraint constrain, Vector3 low, Vector3 hi); | ||
408 | |||
409 | public abstract bool SetAngularLimits(BulletConstraint constrain, Vector3 low, Vector3 hi); | ||
410 | |||
411 | public abstract bool UseFrameOffset(BulletConstraint constrain, float enable); | ||
412 | |||
413 | public abstract bool TranslationalLimitMotor(BulletConstraint constrain, float enable, float targetVel, float maxMotorForce); | ||
414 | |||
415 | public abstract bool SetBreakingImpulseThreshold(BulletConstraint constrain, float threshold); | ||
416 | |||
417 | public abstract bool CalculateTransforms(BulletConstraint constrain); | ||
418 | |||
419 | public abstract bool SetConstraintParam(BulletConstraint constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis); | ||
420 | |||
421 | public abstract bool DestroyConstraint(BulletWorld world, BulletConstraint constrain); | ||
422 | |||
423 | // ===================================================================================== | ||
424 | // btCollisionWorld entries | ||
425 | public abstract void UpdateSingleAabb(BulletWorld world, BulletBody obj); | ||
426 | |||
427 | public abstract void UpdateAabbs(BulletWorld world); | ||
428 | |||
429 | public abstract bool GetForceUpdateAllAabbs(BulletWorld world); | ||
430 | |||
431 | public abstract void SetForceUpdateAllAabbs(BulletWorld world, bool force); | ||
432 | |||
433 | // ===================================================================================== | ||
434 | // btDynamicsWorld entries | ||
435 | // public abstract bool AddObjectToWorld(BulletWorld world, BulletBody obj, Vector3 pos, Quaternion rot); | ||
436 | public abstract bool AddObjectToWorld(BulletWorld world, BulletBody obj); | ||
437 | |||
438 | public abstract bool RemoveObjectFromWorld(BulletWorld world, BulletBody obj); | ||
439 | |||
440 | public abstract bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects); | ||
441 | |||
442 | public abstract bool RemoveConstraintFromWorld(BulletWorld world, BulletConstraint constrain); | ||
443 | // ===================================================================================== | ||
444 | // btCollisionObject entries | ||
445 | public abstract Vector3 GetAnisotripicFriction(BulletConstraint constrain); | ||
446 | |||
447 | public abstract Vector3 SetAnisotripicFriction(BulletConstraint constrain, Vector3 frict); | ||
448 | |||
449 | public abstract bool HasAnisotripicFriction(BulletConstraint constrain); | ||
450 | |||
451 | public abstract void SetContactProcessingThreshold(BulletBody obj, float val); | ||
452 | |||
453 | public abstract float GetContactProcessingThreshold(BulletBody obj); | ||
454 | |||
455 | public abstract bool IsStaticObject(BulletBody obj); | ||
456 | |||
457 | public abstract bool IsKinematicObject(BulletBody obj); | ||
458 | |||
459 | public abstract bool IsStaticOrKinematicObject(BulletBody obj); | ||
460 | |||
461 | public abstract bool HasContactResponse(BulletBody obj); | ||
462 | |||
463 | public abstract void SetCollisionShape(BulletWorld sim, BulletBody obj, BulletShape shape); | ||
464 | |||
465 | public abstract BulletShape GetCollisionShape(BulletBody obj); | ||
466 | |||
467 | public abstract int GetActivationState(BulletBody obj); | ||
468 | |||
469 | public abstract void SetActivationState(BulletBody obj, int state); | ||
470 | |||
471 | public abstract void SetDeactivationTime(BulletBody obj, float dtime); | ||
472 | |||
473 | public abstract float GetDeactivationTime(BulletBody obj); | ||
474 | |||
475 | public abstract void ForceActivationState(BulletBody obj, ActivationState state); | ||
476 | |||
477 | public abstract void Activate(BulletBody obj, bool forceActivation); | ||
478 | |||
479 | public abstract bool IsActive(BulletBody obj); | ||
480 | |||
481 | public abstract void SetRestitution(BulletBody obj, float val); | ||
482 | |||
483 | public abstract float GetRestitution(BulletBody obj); | ||
484 | |||
485 | public abstract void SetFriction(BulletBody obj, float val); | ||
486 | |||
487 | public abstract float GetFriction(BulletBody obj); | ||
488 | |||
489 | public abstract Vector3 GetPosition(BulletBody obj); | ||
490 | |||
491 | public abstract Quaternion GetOrientation(BulletBody obj); | ||
492 | |||
493 | public abstract void SetTranslation(BulletBody obj, Vector3 position, Quaternion rotation); | ||
494 | |||
495 | // public abstract IntPtr GetBroadphaseHandle(BulletBody obj); | ||
496 | |||
497 | // public abstract void SetBroadphaseHandle(BulletBody obj, IntPtr handle); | ||
498 | |||
499 | public abstract void SetInterpolationLinearVelocity(BulletBody obj, Vector3 vel); | ||
500 | |||
501 | public abstract void SetInterpolationAngularVelocity(BulletBody obj, Vector3 vel); | ||
502 | |||
503 | public abstract void SetInterpolationVelocity(BulletBody obj, Vector3 linearVel, Vector3 angularVel); | ||
504 | |||
505 | public abstract float GetHitFraction(BulletBody obj); | ||
506 | |||
507 | public abstract void SetHitFraction(BulletBody obj, float val); | ||
508 | |||
509 | public abstract CollisionFlags GetCollisionFlags(BulletBody obj); | ||
510 | |||
511 | public abstract CollisionFlags SetCollisionFlags(BulletBody obj, CollisionFlags flags); | ||
512 | |||
513 | public abstract CollisionFlags AddToCollisionFlags(BulletBody obj, CollisionFlags flags); | ||
514 | |||
515 | public abstract CollisionFlags RemoveFromCollisionFlags(BulletBody obj, CollisionFlags flags); | ||
516 | |||
517 | public abstract float GetCcdMotionThreshold(BulletBody obj); | ||
518 | |||
519 | public abstract void SetCcdMotionThreshold(BulletBody obj, float val); | ||
520 | |||
521 | public abstract float GetCcdSweptSphereRadius(BulletBody obj); | ||
522 | |||
523 | public abstract void SetCcdSweptSphereRadius(BulletBody obj, float val); | ||
524 | |||
525 | public abstract IntPtr GetUserPointer(BulletBody obj); | ||
526 | |||
527 | public abstract void SetUserPointer(BulletBody obj, IntPtr val); | ||
528 | |||
529 | // ===================================================================================== | ||
530 | // btRigidBody entries | ||
531 | public abstract void ApplyGravity(BulletBody obj); | ||
532 | |||
533 | public abstract void SetGravity(BulletBody obj, Vector3 val); | ||
534 | |||
535 | public abstract Vector3 GetGravity(BulletBody obj); | ||
536 | |||
537 | public abstract void SetDamping(BulletBody obj, float lin_damping, float ang_damping); | ||
538 | |||
539 | public abstract void SetLinearDamping(BulletBody obj, float lin_damping); | ||
540 | |||
541 | public abstract void SetAngularDamping(BulletBody obj, float ang_damping); | ||
542 | |||
543 | public abstract float GetLinearDamping(BulletBody obj); | ||
544 | |||
545 | public abstract float GetAngularDamping(BulletBody obj); | ||
546 | |||
547 | public abstract float GetLinearSleepingThreshold(BulletBody obj); | ||
548 | |||
549 | public abstract void ApplyDamping(BulletBody obj, float timeStep); | ||
550 | |||
551 | public abstract void SetMassProps(BulletBody obj, float mass, Vector3 inertia); | ||
552 | |||
553 | public abstract Vector3 GetLinearFactor(BulletBody obj); | ||
554 | |||
555 | public abstract void SetLinearFactor(BulletBody obj, Vector3 factor); | ||
556 | |||
557 | public abstract void SetCenterOfMassByPosRot(BulletBody obj, Vector3 pos, Quaternion rot); | ||
558 | |||
559 | // Add a force to the object as if its mass is one. | ||
560 | public abstract void ApplyCentralForce(BulletBody obj, Vector3 force); | ||
561 | |||
562 | // Set the force being applied to the object as if its mass is one. | ||
563 | public abstract void SetObjectForce(BulletBody obj, Vector3 force); | ||
564 | |||
565 | public abstract Vector3 GetTotalForce(BulletBody obj); | ||
566 | |||
567 | public abstract Vector3 GetTotalTorque(BulletBody obj); | ||
568 | |||
569 | public abstract Vector3 GetInvInertiaDiagLocal(BulletBody obj); | ||
570 | |||
571 | public abstract void SetInvInertiaDiagLocal(BulletBody obj, Vector3 inert); | ||
572 | |||
573 | public abstract void SetSleepingThresholds(BulletBody obj, float lin_threshold, float ang_threshold); | ||
574 | |||
575 | public abstract void ApplyTorque(BulletBody obj, Vector3 torque); | ||
576 | |||
577 | // Apply force at the given point. Will add torque to the object. | ||
578 | public abstract void ApplyForce(BulletBody obj, Vector3 force, Vector3 pos); | ||
579 | |||
580 | // Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass. | ||
581 | public abstract void ApplyCentralImpulse(BulletBody obj, Vector3 imp); | ||
582 | |||
583 | // Apply impulse to the object's torque. Force is scaled by object's mass. | ||
584 | public abstract void ApplyTorqueImpulse(BulletBody obj, Vector3 imp); | ||
585 | |||
586 | // Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces. | ||
587 | public abstract void ApplyImpulse(BulletBody obj, Vector3 imp, Vector3 pos); | ||
588 | |||
589 | public abstract void ClearForces(BulletBody obj); | ||
590 | |||
591 | public abstract void ClearAllForces(BulletBody obj); | ||
592 | |||
593 | public abstract void UpdateInertiaTensor(BulletBody obj); | ||
594 | |||
595 | public abstract Vector3 GetLinearVelocity(BulletBody obj); | ||
596 | |||
597 | public abstract Vector3 GetAngularVelocity(BulletBody obj); | ||
598 | |||
599 | public abstract void SetLinearVelocity(BulletBody obj, Vector3 val); | ||
600 | |||
601 | public abstract void SetAngularVelocity(BulletBody obj, Vector3 angularVelocity); | ||
602 | |||
603 | public abstract Vector3 GetVelocityInLocalPoint(BulletBody obj, Vector3 pos); | ||
604 | |||
605 | public abstract void Translate(BulletBody obj, Vector3 trans); | ||
606 | |||
607 | public abstract void UpdateDeactivation(BulletBody obj, float timeStep); | ||
608 | |||
609 | public abstract bool WantsSleeping(BulletBody obj); | ||
610 | |||
611 | public abstract void SetAngularFactor(BulletBody obj, float factor); | ||
612 | |||
613 | public abstract void SetAngularFactorV(BulletBody obj, Vector3 factor); | ||
614 | |||
615 | public abstract Vector3 GetAngularFactor(BulletBody obj); | ||
616 | |||
617 | public abstract bool IsInWorld(BulletWorld world, BulletBody obj); | ||
618 | |||
619 | public abstract void AddConstraintRef(BulletBody obj, BulletConstraint constrain); | ||
620 | |||
621 | public abstract void RemoveConstraintRef(BulletBody obj, BulletConstraint constrain); | ||
622 | |||
623 | public abstract BulletConstraint GetConstraintRef(BulletBody obj, int index); | ||
624 | |||
625 | public abstract int GetNumConstraintRefs(BulletBody obj); | ||
626 | |||
627 | public abstract bool SetCollisionGroupMask(BulletBody body, UInt32 filter, UInt32 mask); | ||
628 | |||
629 | // ===================================================================================== | ||
630 | // btCollisionShape entries | ||
631 | |||
632 | public abstract float GetAngularMotionDisc(BulletShape shape); | ||
633 | |||
634 | public abstract float GetContactBreakingThreshold(BulletShape shape, float defaultFactor); | ||
635 | |||
636 | public abstract bool IsPolyhedral(BulletShape shape); | ||
637 | |||
638 | public abstract bool IsConvex2d(BulletShape shape); | ||
639 | |||
640 | public abstract bool IsConvex(BulletShape shape); | ||
641 | |||
642 | public abstract bool IsNonMoving(BulletShape shape); | ||
643 | |||
644 | public abstract bool IsConcave(BulletShape shape); | ||
645 | |||
646 | public abstract bool IsCompound(BulletShape shape); | ||
647 | |||
648 | public abstract bool IsSoftBody(BulletShape shape); | ||
649 | |||
650 | public abstract bool IsInfinite(BulletShape shape); | ||
651 | |||
652 | public abstract void SetLocalScaling(BulletShape shape, Vector3 scale); | ||
653 | |||
654 | public abstract Vector3 GetLocalScaling(BulletShape shape); | ||
655 | |||
656 | public abstract Vector3 CalculateLocalInertia(BulletShape shape, float mass); | ||
657 | |||
658 | public abstract int GetShapeType(BulletShape shape); | ||
659 | |||
660 | public abstract void SetMargin(BulletShape shape, float val); | ||
661 | |||
662 | public abstract float GetMargin(BulletShape shape); | ||
663 | |||
664 | // ===================================================================================== | ||
665 | // Debugging | ||
666 | public virtual void DumpRigidBody(BulletWorld sim, BulletBody collisionObject) { } | ||
667 | |||
668 | public virtual void DumpCollisionShape(BulletWorld sim, BulletShape collisionShape) { } | ||
669 | |||
670 | public virtual void DumpConstraint(BulletWorld sim, BulletConstraint constrain) { } | ||
671 | |||
672 | public virtual void DumpActivationInfo(BulletWorld sim) { } | ||
673 | |||
674 | public virtual void DumpAllInfo(BulletWorld sim) { } | ||
675 | |||
676 | public virtual void DumpPhysicsStatistics(BulletWorld sim) { } | ||
677 | |||
678 | public virtual void ResetBroadphasePool(BulletWorld sim) { } | ||
679 | |||
680 | public virtual void ResetConstraintSolver(BulletWorld sim) { } | ||
681 | |||
682 | }; | ||
683 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index 4c195e1..90c2d9c 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs | |||
@@ -45,7 +45,6 @@ public sealed class BSCharacter : BSPhysObject | |||
45 | private bool _selected; | 45 | private bool _selected; |
46 | private OMV.Vector3 _position; | 46 | private OMV.Vector3 _position; |
47 | private float _mass; | 47 | private float _mass; |
48 | private float _avatarDensity; | ||
49 | private float _avatarVolume; | 48 | private float _avatarVolume; |
50 | private OMV.Vector3 _force; | 49 | private OMV.Vector3 _force; |
51 | private OMV.Vector3 _velocity; | 50 | private OMV.Vector3 _velocity; |
@@ -58,16 +57,12 @@ public sealed class BSCharacter : BSPhysObject | |||
58 | private bool _flying; | 57 | private bool _flying; |
59 | private bool _setAlwaysRun; | 58 | private bool _setAlwaysRun; |
60 | private bool _throttleUpdates; | 59 | private bool _throttleUpdates; |
61 | private bool _isColliding; | ||
62 | private bool _collidingObj; | ||
63 | private bool _floatOnWater; | 60 | private bool _floatOnWater; |
64 | private OMV.Vector3 _rotationalVelocity; | 61 | private OMV.Vector3 _rotationalVelocity; |
65 | private bool _kinematic; | 62 | private bool _kinematic; |
66 | private float _buoyancy; | 63 | private float _buoyancy; |
67 | 64 | ||
68 | // The friction and velocity of the avatar is modified depending on whether walking or not. | 65 | private BSVMotor _velocityMotor; |
69 | private OMV.Vector3 _appliedVelocity; // the last velocity applied to the avatar | ||
70 | private float _currentFriction; // the friction currently being used (changed by setVelocity). | ||
71 | 66 | ||
72 | private OMV.Vector3 _PIDTarget; | 67 | private OMV.Vector3 _PIDTarget; |
73 | private bool _usePID; | 68 | private bool _usePID; |
@@ -83,34 +78,36 @@ public sealed class BSCharacter : BSPhysObject | |||
83 | _physicsActorType = (int)ActorTypes.Agent; | 78 | _physicsActorType = (int)ActorTypes.Agent; |
84 | _position = pos; | 79 | _position = pos; |
85 | 80 | ||
86 | // Old versions of ScenePresence passed only the height. If width and/or depth are zero, | ||
87 | // replace with the default values. | ||
88 | _size = size; | ||
89 | if (_size.X == 0f) _size.X = PhysicsScene.Params.avatarCapsuleDepth; | ||
90 | if (_size.Y == 0f) _size.Y = PhysicsScene.Params.avatarCapsuleWidth; | ||
91 | |||
92 | _flying = isFlying; | 81 | _flying = isFlying; |
93 | _orientation = OMV.Quaternion.Identity; | 82 | _orientation = OMV.Quaternion.Identity; |
94 | _velocity = OMV.Vector3.Zero; | 83 | _velocity = OMV.Vector3.Zero; |
95 | _appliedVelocity = OMV.Vector3.Zero; | ||
96 | _buoyancy = ComputeBuoyancyFromFlying(isFlying); | 84 | _buoyancy = ComputeBuoyancyFromFlying(isFlying); |
97 | _currentFriction = PhysicsScene.Params.avatarStandingFriction; | 85 | Friction = BSParam.AvatarStandingFriction; |
98 | _avatarDensity = PhysicsScene.Params.avatarDensity; | 86 | Density = BSParam.AvatarDensity / BSParam.DensityScaleFactor; |
87 | |||
88 | // Old versions of ScenePresence passed only the height. If width and/or depth are zero, | ||
89 | // replace with the default values. | ||
90 | _size = size; | ||
91 | if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth; | ||
92 | if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth; | ||
99 | 93 | ||
100 | // The dimensions of the avatar capsule are kept in the scale. | 94 | // The dimensions of the physical capsule are kept in the scale. |
101 | // Physics creates a unit capsule which is scaled by the physics engine. | 95 | // Physics creates a unit capsule which is scaled by the physics engine. |
102 | ComputeAvatarScale(_size); | 96 | Scale = ComputeAvatarScale(_size); |
103 | // set _avatarVolume and _mass based on capsule size, _density and Scale | 97 | // set _avatarVolume and _mass based on capsule size, _density and Scale |
104 | ComputeAvatarVolumeAndMass(); | 98 | ComputeAvatarVolumeAndMass(); |
99 | |||
100 | SetupMovementMotor(); | ||
101 | |||
105 | DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}", | 102 | DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}", |
106 | LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass); | 103 | LocalID, _size, Scale, Density, _avatarVolume, RawMass); |
107 | 104 | ||
108 | // do actual create at taint time | 105 | // do actual creation in taint time |
109 | PhysicsScene.TaintedObject("BSCharacter.create", delegate() | 106 | PhysicsScene.TaintedObject("BSCharacter.create", delegate() |
110 | { | 107 | { |
111 | DetailLog("{0},BSCharacter.create,taint", LocalID); | 108 | DetailLog("{0},BSCharacter.create,taint", LocalID); |
112 | // New body and shape into PhysBody and PhysShape | 109 | // New body and shape into PhysBody and PhysShape |
113 | PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this, null, null); | 110 | PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this); |
114 | 111 | ||
115 | SetPhysicalProperties(); | 112 | SetPhysicalProperties(); |
116 | }); | 113 | }); |
@@ -120,54 +117,216 @@ public sealed class BSCharacter : BSPhysObject | |||
120 | // called when this character is being destroyed and the resources should be released | 117 | // called when this character is being destroyed and the resources should be released |
121 | public override void Destroy() | 118 | public override void Destroy() |
122 | { | 119 | { |
120 | base.Destroy(); | ||
121 | |||
123 | DetailLog("{0},BSCharacter.Destroy", LocalID); | 122 | DetailLog("{0},BSCharacter.Destroy", LocalID); |
124 | PhysicsScene.TaintedObject("BSCharacter.destroy", delegate() | 123 | PhysicsScene.TaintedObject("BSCharacter.destroy", delegate() |
125 | { | 124 | { |
126 | PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null); | 125 | PhysicsScene.Shapes.DereferenceBody(PhysBody, null /* bodyCallback */); |
127 | PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null); | 126 | PhysBody.Clear(); |
127 | PhysicsScene.Shapes.DereferenceShape(PhysShape, null /* bodyCallback */); | ||
128 | PhysShape.Clear(); | ||
128 | }); | 129 | }); |
129 | } | 130 | } |
130 | 131 | ||
131 | private void SetPhysicalProperties() | 132 | private void SetPhysicalProperties() |
132 | { | 133 | { |
133 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, PhysBody.ptr); | 134 | PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody); |
134 | 135 | ||
135 | ZeroMotion(true); | 136 | ZeroMotion(true); |
136 | ForcePosition = _position; | 137 | ForcePosition = _position; |
137 | // Set the velocity and compute the proper friction | 138 | |
139 | // Set the velocity | ||
140 | _velocityMotor.Reset(); | ||
141 | _velocityMotor.SetTarget(_velocity); | ||
142 | _velocityMotor.SetCurrent(_velocity); | ||
138 | ForceVelocity = _velocity; | 143 | ForceVelocity = _velocity; |
139 | 144 | ||
140 | // This will enable or disable the flying buoyancy of the avatar. | 145 | // This will enable or disable the flying buoyancy of the avatar. |
141 | // Needs to be reset especially when an avatar is recreated after crossing a region boundry. | 146 | // Needs to be reset especially when an avatar is recreated after crossing a region boundry. |
142 | Flying = _flying; | 147 | Flying = _flying; |
143 | 148 | ||
144 | BulletSimAPI.SetRestitution2(PhysBody.ptr, PhysicsScene.Params.avatarRestitution); | 149 | PhysicsScene.PE.SetRestitution(PhysBody, BSParam.AvatarRestitution); |
145 | BulletSimAPI.SetMargin2(PhysShape.ptr, PhysicsScene.Params.collisionMargin); | 150 | PhysicsScene.PE.SetMargin(PhysShape, PhysicsScene.Params.collisionMargin); |
146 | BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale); | 151 | PhysicsScene.PE.SetLocalScaling(PhysShape, Scale); |
147 | BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, PhysicsScene.Params.contactProcessingThreshold); | 152 | PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); |
148 | if (PhysicsScene.Params.ccdMotionThreshold > 0f) | 153 | if (BSParam.CcdMotionThreshold > 0f) |
149 | { | 154 | { |
150 | BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold); | 155 | PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); |
151 | BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); | 156 | PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); |
152 | } | 157 | } |
153 | 158 | ||
154 | UpdatePhysicalMassProperties(RawMass); | 159 | UpdatePhysicalMassProperties(RawMass, false); |
155 | 160 | ||
156 | // Make so capsule does not fall over | 161 | // Make so capsule does not fall over |
157 | BulletSimAPI.SetAngularFactorV2(PhysBody.ptr, OMV.Vector3.Zero); | 162 | PhysicsScene.PE.SetAngularFactorV(PhysBody, OMV.Vector3.Zero); |
158 | 163 | ||
159 | BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_CHARACTER_OBJECT); | 164 | PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT); |
160 | 165 | ||
161 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, PhysBody.ptr); | 166 | PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody); |
162 | 167 | ||
163 | // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ACTIVE_TAG); | 168 | // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG); |
164 | BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_DEACTIVATION); | 169 | PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_DEACTIVATION); |
165 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr); | 170 | PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, PhysBody); |
166 | 171 | ||
167 | // Do this after the object has been added to the world | 172 | // Do this after the object has been added to the world |
168 | BulletSimAPI.SetCollisionFilterMask2(PhysBody.ptr, | 173 | PhysBody.collisionType = CollisionType.Avatar; |
169 | (uint)CollisionFilterGroups.AvatarFilter, | 174 | PhysBody.ApplyCollisionMask(PhysicsScene); |
170 | (uint)CollisionFilterGroups.AvatarMask); | 175 | } |
176 | |||
177 | // The avatar's movement is controlled by this motor that speeds up and slows down | ||
178 | // the avatar seeking to reach the motor's target speed. | ||
179 | // This motor runs as a prestep action for the avatar so it will keep the avatar | ||
180 | // standing as well as moving. Destruction of the avatar will destroy the pre-step action. | ||
181 | private void SetupMovementMotor() | ||
182 | { | ||
183 | // Infinite decay and timescale values so motor only changes current to target values. | ||
184 | _velocityMotor = new BSVMotor("BSCharacter.Velocity", | ||
185 | 0.2f, // time scale | ||
186 | BSMotor.Infinite, // decay time scale | ||
187 | BSMotor.InfiniteVector, // friction timescale | ||
188 | 1f // efficiency | ||
189 | ); | ||
190 | // _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages. | ||
191 | |||
192 | RegisterPreStepAction("BSCharactor.Movement", LocalID, delegate(float timeStep) | ||
193 | { | ||
194 | // TODO: Decide if the step parameters should be changed depending on the avatar's | ||
195 | // state (flying, colliding, ...). There is code in ODE to do this. | ||
196 | |||
197 | // COMMENTARY: when the user is making the avatar walk, except for falling, the velocity | ||
198 | // specified for the avatar is the one that should be used. For falling, if the avatar | ||
199 | // is not flying and is not colliding then it is presumed to be falling and the Z | ||
200 | // component is not fooled with (thus allowing gravity to do its thing). | ||
201 | // When the avatar is standing, though, the user has specified a velocity of zero and | ||
202 | // the avatar should be standing. But if the avatar is pushed by something in the world | ||
203 | // (raising elevator platform, moving vehicle, ...) the avatar should be allowed to | ||
204 | // move. Thus, the velocity cannot be forced to zero. The problem is that small velocity | ||
205 | // errors can creap in and the avatar will slowly float off in some direction. | ||
206 | // So, the problem is that, when an avatar is standing, we cannot tell creaping error | ||
207 | // from real pushing. | ||
208 | // The code below uses whether the collider is static or moving to decide whether to zero motion. | ||
209 | |||
210 | _velocityMotor.Step(timeStep); | ||
211 | |||
212 | // If we're not supposed to be moving, make sure things are zero. | ||
213 | if (_velocityMotor.ErrorIsZero() && _velocityMotor.TargetValue == OMV.Vector3.Zero) | ||
214 | { | ||
215 | // The avatar shouldn't be moving | ||
216 | _velocityMotor.Zero(); | ||
217 | |||
218 | if (IsColliding) | ||
219 | { | ||
220 | // If we are colliding with a stationary object, presume we're standing and don't move around | ||
221 | if (!ColliderIsMoving) | ||
222 | { | ||
223 | DetailLog("{0},BSCharacter.MoveMotor,collidingWithStationary,zeroingMotion", LocalID); | ||
224 | ZeroMotion(true /* inTaintTime */); | ||
225 | } | ||
226 | |||
227 | // Standing has more friction on the ground | ||
228 | if (Friction != BSParam.AvatarStandingFriction) | ||
229 | { | ||
230 | Friction = BSParam.AvatarStandingFriction; | ||
231 | PhysicsScene.PE.SetFriction(PhysBody, Friction); | ||
232 | } | ||
233 | } | ||
234 | else | ||
235 | { | ||
236 | if (Flying) | ||
237 | { | ||
238 | // Flying and not collising and velocity nearly zero. | ||
239 | ZeroMotion(true /* inTaintTime */); | ||
240 | } | ||
241 | } | ||
242 | |||
243 | DetailLog("{0},BSCharacter.MoveMotor,taint,stopping,target={1},colliding={2}", LocalID, _velocityMotor.TargetValue, IsColliding); | ||
244 | } | ||
245 | else | ||
246 | { | ||
247 | // Supposed to be moving. | ||
248 | OMV.Vector3 stepVelocity = _velocityMotor.CurrentValue; | ||
249 | |||
250 | if (Friction != BSParam.AvatarFriction) | ||
251 | { | ||
252 | // Probably starting up walking. Set friction to moving friction. | ||
253 | Friction = BSParam.AvatarFriction; | ||
254 | PhysicsScene.PE.SetFriction(PhysBody, Friction); | ||
255 | } | ||
256 | |||
257 | // If falling, we keep the world's downward vector no matter what the other axis specify. | ||
258 | // The check for _velocity.Z < 0 makes jumping work (temporary upward force). | ||
259 | if (!Flying && !IsColliding) | ||
260 | { | ||
261 | if (_velocity.Z < 0) | ||
262 | stepVelocity.Z = _velocity.Z; | ||
263 | // DetailLog("{0},BSCharacter.MoveMotor,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity); | ||
264 | } | ||
265 | |||
266 | // 'stepVelocity' is now the speed we'd like the avatar to move in. Turn that into an instantanous force. | ||
267 | OMV.Vector3 moveForce = (stepVelocity - _velocity) * Mass; | ||
268 | |||
269 | // Should we check for move force being small and forcing velocity to zero? | ||
270 | |||
271 | // Add special movement force to allow avatars to walk up stepped surfaces. | ||
272 | moveForce += WalkUpStairs(); | ||
273 | |||
274 | DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}", LocalID, stepVelocity, _velocity, Mass, moveForce); | ||
275 | PhysicsScene.PE.ApplyCentralImpulse(PhysBody, moveForce); | ||
276 | } | ||
277 | }); | ||
278 | } | ||
279 | |||
280 | // Decide if the character is colliding with a low object and compute a force to pop the | ||
281 | // avatar up so it can walk up and over the low objects. | ||
282 | private OMV.Vector3 WalkUpStairs() | ||
283 | { | ||
284 | OMV.Vector3 ret = OMV.Vector3.Zero; | ||
285 | |||
286 | // This test is done if moving forward, not flying and is colliding with something. | ||
287 | // DetailLog("{0},BSCharacter.WalkUpStairs,IsColliding={1},flying={2},targSpeed={3},collisions={4}", | ||
288 | // LocalID, IsColliding, Flying, TargetSpeed, CollisionsLastTick.Count); | ||
289 | if (IsColliding && !Flying && TargetVelocitySpeed > 0.1f /* && ForwardSpeed < 0.1f */) | ||
290 | { | ||
291 | // The range near the character's feet where we will consider stairs | ||
292 | float nearFeetHeightMin = RawPosition.Z - (Size.Z / 2f) + 0.05f; | ||
293 | float nearFeetHeightMax = nearFeetHeightMin + BSParam.AvatarStepHeight; | ||
294 | |||
295 | // Look for a collision point that is near the character's feet and is oriented the same as the charactor is | ||
296 | foreach (KeyValuePair<uint, ContactPoint> kvp in CollisionsLastTick.m_objCollisionList) | ||
297 | { | ||
298 | // Don't care about collisions with the terrain | ||
299 | if (kvp.Key > PhysicsScene.TerrainManager.HighestTerrainID) | ||
300 | { | ||
301 | OMV.Vector3 touchPosition = kvp.Value.Position; | ||
302 | // DetailLog("{0},BSCharacter.WalkUpStairs,min={1},max={2},touch={3}", | ||
303 | // LocalID, nearFeetHeightMin, nearFeetHeightMax, touchPosition); | ||
304 | if (touchPosition.Z >= nearFeetHeightMin && touchPosition.Z <= nearFeetHeightMax) | ||
305 | { | ||
306 | // This contact is within the 'near the feet' range. | ||
307 | // The normal should be our contact point to the object so it is pointing away | ||
308 | // thus the difference between our facing orientation and the normal should be small. | ||
309 | OMV.Vector3 directionFacing = OMV.Vector3.UnitX * RawOrientation; | ||
310 | OMV.Vector3 touchNormal = OMV.Vector3.Normalize(kvp.Value.SurfaceNormal); | ||
311 | float diff = Math.Abs(OMV.Vector3.Distance(directionFacing, touchNormal)); | ||
312 | if (diff < BSParam.AvatarStepApproachFactor) | ||
313 | { | ||
314 | // Found the stairs contact point. Push up a little to raise the character. | ||
315 | float upForce = (touchPosition.Z - nearFeetHeightMin) * Mass * BSParam.AvatarStepForceFactor; | ||
316 | ret = new OMV.Vector3(0f, 0f, upForce); | ||
317 | |||
318 | // Also move the avatar up for the new height | ||
319 | OMV.Vector3 displacement = new OMV.Vector3(0f, 0f, BSParam.AvatarStepHeight / 2f); | ||
320 | ForcePosition = RawPosition + displacement; | ||
321 | } | ||
322 | DetailLog("{0},BSCharacter.WalkUpStairs,touchPos={1},nearFeetMin={2},faceDir={3},norm={4},diff={5},ret={6}", | ||
323 | LocalID, touchPosition, nearFeetHeightMin, directionFacing, touchNormal, diff, ret); | ||
324 | } | ||
325 | } | ||
326 | } | ||
327 | } | ||
328 | |||
329 | return ret; | ||
171 | } | 330 | } |
172 | 331 | ||
173 | public override void RequestPhysicsterseUpdate() | 332 | public override void RequestPhysicsterseUpdate() |
@@ -185,24 +344,31 @@ public sealed class BSCharacter : BSPhysObject | |||
185 | } | 344 | } |
186 | 345 | ||
187 | set { | 346 | set { |
188 | // When an avatar's size is set, only the height is changed. | ||
189 | _size = value; | 347 | _size = value; |
190 | ComputeAvatarScale(_size); | 348 | // Old versions of ScenePresence passed only the height. If width and/or depth are zero, |
349 | // replace with the default values. | ||
350 | if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth; | ||
351 | if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth; | ||
352 | |||
353 | Scale = ComputeAvatarScale(_size); | ||
191 | ComputeAvatarVolumeAndMass(); | 354 | ComputeAvatarVolumeAndMass(); |
192 | DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}", | 355 | DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}", |
193 | LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass); | 356 | LocalID, _size, Scale, Density, _avatarVolume, RawMass); |
194 | 357 | ||
195 | PhysicsScene.TaintedObject("BSCharacter.setSize", delegate() | 358 | PhysicsScene.TaintedObject("BSCharacter.setSize", delegate() |
196 | { | 359 | { |
197 | BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale); | 360 | if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape) |
198 | UpdatePhysicalMassProperties(RawMass); | 361 | { |
362 | PhysicsScene.PE.SetLocalScaling(PhysShape, Scale); | ||
363 | UpdatePhysicalMassProperties(RawMass, true); | ||
364 | // Make sure this change appears as a property update event | ||
365 | PhysicsScene.PE.PushUpdate(PhysBody); | ||
366 | } | ||
199 | }); | 367 | }); |
200 | 368 | ||
201 | } | 369 | } |
202 | } | 370 | } |
203 | 371 | ||
204 | public override OMV.Vector3 Scale { get; set; } | ||
205 | |||
206 | public override PrimitiveBaseShape Shape | 372 | public override PrimitiveBaseShape Shape |
207 | { | 373 | { |
208 | set { BaseShape = value; } | 374 | set { BaseShape = value; } |
@@ -219,6 +385,10 @@ public sealed class BSCharacter : BSPhysObject | |||
219 | public override bool Selected { | 385 | public override bool Selected { |
220 | set { _selected = value; } | 386 | set { _selected = value; } |
221 | } | 387 | } |
388 | public override bool IsSelected | ||
389 | { | ||
390 | get { return _selected; } | ||
391 | } | ||
222 | public override void CrossingFailure() { return; } | 392 | public override void CrossingFailure() { return; } |
223 | public override void link(PhysicsActor obj) { return; } | 393 | public override void link(PhysicsActor obj) { return; } |
224 | public override void delink() { return; } | 394 | public override void delink() { return; } |
@@ -236,7 +406,8 @@ public sealed class BSCharacter : BSPhysObject | |||
236 | // Zero some other properties directly into the physics engine | 406 | // Zero some other properties directly into the physics engine |
237 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() | 407 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() |
238 | { | 408 | { |
239 | BulletSimAPI.ClearAllForces2(PhysBody.ptr); | 409 | if (PhysBody.HasPhysicalBody) |
410 | PhysicsScene.PE.ClearAllForces(PhysBody); | ||
240 | }); | 411 | }); |
241 | } | 412 | } |
242 | public override void ZeroAngularMotion(bool inTaintTime) | 413 | public override void ZeroAngularMotion(bool inTaintTime) |
@@ -245,10 +416,13 @@ public sealed class BSCharacter : BSPhysObject | |||
245 | 416 | ||
246 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() | 417 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() |
247 | { | 418 | { |
248 | BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); | 419 | if (PhysBody.HasPhysicalBody) |
249 | BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); | 420 | { |
250 | // The next also get rid of applied linear force but the linear velocity is untouched. | 421 | PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, OMV.Vector3.Zero); |
251 | BulletSimAPI.ClearForces2(PhysBody.ptr); | 422 | PhysicsScene.PE.SetAngularVelocity(PhysBody, OMV.Vector3.Zero); |
423 | // The next also get rid of applied linear force but the linear velocity is untouched. | ||
424 | PhysicsScene.PE.ClearForces(PhysBody); | ||
425 | } | ||
252 | }); | 426 | }); |
253 | } | 427 | } |
254 | 428 | ||
@@ -263,29 +437,31 @@ public sealed class BSCharacter : BSPhysObject | |||
263 | public override OMV.Vector3 Position { | 437 | public override OMV.Vector3 Position { |
264 | get { | 438 | get { |
265 | // Don't refetch the position because this function is called a zillion times | 439 | // Don't refetch the position because this function is called a zillion times |
266 | // _position = BulletSimAPI.GetObjectPosition2(Scene.World.ptr, LocalID); | 440 | // _position = PhysicsScene.PE.GetObjectPosition(Scene.World, LocalID); |
267 | return _position; | 441 | return _position; |
268 | } | 442 | } |
269 | set { | 443 | set { |
270 | _position = value; | 444 | _position = value; |
271 | PositionSanityCheck(); | ||
272 | 445 | ||
273 | PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate() | 446 | PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate() |
274 | { | 447 | { |
275 | DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); | 448 | DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); |
276 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | 449 | PositionSanityCheck(); |
450 | ForcePosition = _position; | ||
277 | }); | 451 | }); |
278 | } | 452 | } |
279 | } | 453 | } |
280 | public override OMV.Vector3 ForcePosition { | 454 | public override OMV.Vector3 ForcePosition { |
281 | get { | 455 | get { |
282 | _position = BulletSimAPI.GetPosition2(PhysBody.ptr); | 456 | _position = PhysicsScene.PE.GetPosition(PhysBody); |
283 | return _position; | 457 | return _position; |
284 | } | 458 | } |
285 | set { | 459 | set { |
286 | _position = value; | 460 | _position = value; |
287 | PositionSanityCheck(); | 461 | if (PhysBody.HasPhysicalBody) |
288 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | 462 | { |
463 | PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); | ||
464 | } | ||
289 | } | 465 | } |
290 | } | 466 | } |
291 | 467 | ||
@@ -297,17 +473,28 @@ public sealed class BSCharacter : BSPhysObject | |||
297 | { | 473 | { |
298 | bool ret = false; | 474 | bool ret = false; |
299 | 475 | ||
476 | // TODO: check for out of bounds | ||
477 | if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(RawPosition)) | ||
478 | { | ||
479 | // The character is out of the known/simulated area. | ||
480 | // Force the avatar position to be within known. ScenePresence will use the position | ||
481 | // plus the velocity to decide if the avatar is moving out of the region. | ||
482 | RawPosition = PhysicsScene.TerrainManager.ClampPositionIntoKnownTerrain(RawPosition); | ||
483 | DetailLog("{0},BSCharacter.PositionSanityCheck,notWithinKnownTerrain,clampedPos={1}", LocalID, RawPosition); | ||
484 | return true; | ||
485 | } | ||
486 | |||
300 | // If below the ground, move the avatar up | 487 | // If below the ground, move the avatar up |
301 | float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); | 488 | float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition); |
302 | if (Position.Z < terrainHeight) | 489 | if (Position.Z < terrainHeight) |
303 | { | 490 | { |
304 | DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight); | 491 | DetailLog("{0},BSCharacter.PositionSanityCheck,adjustForUnderGround,pos={1},terrain={2}", LocalID, _position, terrainHeight); |
305 | _position.Z = terrainHeight + 2.0f; | 492 | _position.Z = terrainHeight + BSParam.AvatarBelowGroundUpCorrectionMeters; |
306 | ret = true; | 493 | ret = true; |
307 | } | 494 | } |
308 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) | 495 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) |
309 | { | 496 | { |
310 | float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position); | 497 | float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position); |
311 | if (Position.Z < waterHeight) | 498 | if (Position.Z < waterHeight) |
312 | { | 499 | { |
313 | _position.Z = waterHeight; | 500 | _position.Z = waterHeight; |
@@ -315,7 +502,6 @@ public sealed class BSCharacter : BSPhysObject | |||
315 | } | 502 | } |
316 | } | 503 | } |
317 | 504 | ||
318 | // TODO: check for out of bounds | ||
319 | return ret; | 505 | return ret; |
320 | } | 506 | } |
321 | 507 | ||
@@ -332,7 +518,7 @@ public sealed class BSCharacter : BSPhysObject | |||
332 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate() | 518 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate() |
333 | { | 519 | { |
334 | DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); | 520 | DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); |
335 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | 521 | ForcePosition = _position; |
336 | }); | 522 | }); |
337 | ret = true; | 523 | ret = true; |
338 | } | 524 | } |
@@ -345,10 +531,10 @@ public sealed class BSCharacter : BSPhysObject | |||
345 | public override float RawMass { | 531 | public override float RawMass { |
346 | get {return _mass; } | 532 | get {return _mass; } |
347 | } | 533 | } |
348 | public override void UpdatePhysicalMassProperties(float physMass) | 534 | public override void UpdatePhysicalMassProperties(float physMass, bool inWorld) |
349 | { | 535 | { |
350 | OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(PhysShape.ptr, physMass); | 536 | OMV.Vector3 localInertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape, physMass); |
351 | BulletSimAPI.SetMassProps2(PhysBody.ptr, physMass, localInertia); | 537 | PhysicsScene.PE.SetMassProps(PhysBody, physMass, localInertia); |
352 | } | 538 | } |
353 | 539 | ||
354 | public override OMV.Vector3 Force { | 540 | public override OMV.Vector3 Force { |
@@ -359,7 +545,8 @@ public sealed class BSCharacter : BSPhysObject | |||
359 | PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate() | 545 | PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate() |
360 | { | 546 | { |
361 | DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force); | 547 | DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force); |
362 | BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); | 548 | if (PhysBody.HasPhysicalBody) |
549 | PhysicsScene.PE.SetObjectForce(PhysBody, _force); | ||
363 | }); | 550 | }); |
364 | } | 551 | } |
365 | } | 552 | } |
@@ -376,6 +563,37 @@ public sealed class BSCharacter : BSPhysObject | |||
376 | 563 | ||
377 | public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } } | 564 | public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } } |
378 | public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } } | 565 | public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } } |
566 | |||
567 | // Sets the target in the motor. This starts the changing of the avatar's velocity. | ||
568 | public override OMV.Vector3 TargetVelocity | ||
569 | { | ||
570 | get | ||
571 | { | ||
572 | return m_targetVelocity; | ||
573 | } | ||
574 | set | ||
575 | { | ||
576 | DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value); | ||
577 | m_targetVelocity = value; | ||
578 | OMV.Vector3 targetVel = value; | ||
579 | if (_setAlwaysRun) | ||
580 | targetVel *= new OMV.Vector3(BSParam.AvatarAlwaysRunFactor, BSParam.AvatarAlwaysRunFactor, 0f); | ||
581 | |||
582 | PhysicsScene.TaintedObject("BSCharacter.setTargetVelocity", delegate() | ||
583 | { | ||
584 | _velocityMotor.Reset(); | ||
585 | _velocityMotor.SetTarget(targetVel); | ||
586 | _velocityMotor.SetCurrent(_velocity); | ||
587 | _velocityMotor.Enabled = true; | ||
588 | }); | ||
589 | } | ||
590 | } | ||
591 | public override OMV.Vector3 RawVelocity | ||
592 | { | ||
593 | get { return _velocity; } | ||
594 | set { _velocity = value; } | ||
595 | } | ||
596 | // Directly setting velocity means this is what the user really wants now. | ||
379 | public override OMV.Vector3 Velocity { | 597 | public override OMV.Vector3 Velocity { |
380 | get { return _velocity; } | 598 | get { return _velocity; } |
381 | set { | 599 | set { |
@@ -383,6 +601,11 @@ public sealed class BSCharacter : BSPhysObject | |||
383 | // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity); | 601 | // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity); |
384 | PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate() | 602 | PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate() |
385 | { | 603 | { |
604 | _velocityMotor.Reset(); | ||
605 | _velocityMotor.SetCurrent(_velocity); | ||
606 | _velocityMotor.SetTarget(_velocity); | ||
607 | _velocityMotor.Enabled = false; | ||
608 | |||
386 | DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity); | 609 | DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity); |
387 | ForceVelocity = _velocity; | 610 | ForceVelocity = _velocity; |
388 | }); | 611 | }); |
@@ -391,30 +614,11 @@ public sealed class BSCharacter : BSPhysObject | |||
391 | public override OMV.Vector3 ForceVelocity { | 614 | public override OMV.Vector3 ForceVelocity { |
392 | get { return _velocity; } | 615 | get { return _velocity; } |
393 | set { | 616 | set { |
394 | // Depending on whether the avatar is moving or not, change the friction | 617 | PhysicsScene.AssertInTaintTime("BSCharacter.ForceVelocity"); |
395 | // to keep the avatar from slipping around | ||
396 | if (_velocity.Length() == 0) | ||
397 | { | ||
398 | if (_currentFriction != PhysicsScene.Params.avatarStandingFriction) | ||
399 | { | ||
400 | _currentFriction = PhysicsScene.Params.avatarStandingFriction; | ||
401 | BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction); | ||
402 | } | ||
403 | } | ||
404 | else | ||
405 | { | ||
406 | if (_currentFriction != PhysicsScene.Params.avatarFriction) | ||
407 | { | ||
408 | _currentFriction = PhysicsScene.Params.avatarFriction; | ||
409 | BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction); | ||
410 | } | ||
411 | } | ||
412 | _velocity = value; | ||
413 | // Remember the set velocity so we can suppress the reduction by friction, ... | ||
414 | _appliedVelocity = value; | ||
415 | 618 | ||
416 | BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); | 619 | _velocity = value; |
417 | BulletSimAPI.Activate2(PhysBody.ptr, true); | 620 | PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity); |
621 | PhysicsScene.PE.Activate(PhysBody, true); | ||
418 | } | 622 | } |
419 | } | 623 | } |
420 | public override OMV.Vector3 Torque { | 624 | public override OMV.Vector3 Torque { |
@@ -439,13 +643,16 @@ public sealed class BSCharacter : BSPhysObject | |||
439 | public override OMV.Quaternion Orientation { | 643 | public override OMV.Quaternion Orientation { |
440 | get { return _orientation; } | 644 | get { return _orientation; } |
441 | set { | 645 | set { |
442 | _orientation = value; | 646 | // Orientation is set zillions of times when an avatar is walking. It's like |
443 | // m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation); | 647 | // the viewer doesn't trust us. |
444 | PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate() | 648 | if (_orientation != value) |
445 | { | 649 | { |
446 | // _position = BulletSimAPI.GetPosition2(BSBody.ptr); | 650 | _orientation = value; |
447 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | 651 | PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate() |
448 | }); | 652 | { |
653 | ForceOrientation = _orientation; | ||
654 | }); | ||
655 | } | ||
449 | } | 656 | } |
450 | } | 657 | } |
451 | // Go directly to Bullet to get/set the value. | 658 | // Go directly to Bullet to get/set the value. |
@@ -453,13 +660,17 @@ public sealed class BSCharacter : BSPhysObject | |||
453 | { | 660 | { |
454 | get | 661 | get |
455 | { | 662 | { |
456 | _orientation = BulletSimAPI.GetOrientation2(PhysBody.ptr); | 663 | _orientation = PhysicsScene.PE.GetOrientation(PhysBody); |
457 | return _orientation; | 664 | return _orientation; |
458 | } | 665 | } |
459 | set | 666 | set |
460 | { | 667 | { |
461 | _orientation = value; | 668 | _orientation = value; |
462 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | 669 | if (PhysBody.HasPhysicalBody) |
670 | { | ||
671 | // _position = PhysicsScene.PE.GetPosition(BSBody); | ||
672 | PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); | ||
673 | } | ||
463 | } | 674 | } |
464 | } | 675 | } |
465 | public override int PhysicsActorType { | 676 | public override int PhysicsActorType { |
@@ -478,10 +689,14 @@ public sealed class BSCharacter : BSPhysObject | |||
478 | public override bool IsStatic { | 689 | public override bool IsStatic { |
479 | get { return false; } | 690 | get { return false; } |
480 | } | 691 | } |
692 | public override bool IsPhysicallyActive { | ||
693 | get { return true; } | ||
694 | } | ||
481 | public override bool Flying { | 695 | public override bool Flying { |
482 | get { return _flying; } | 696 | get { return _flying; } |
483 | set { | 697 | set { |
484 | _flying = value; | 698 | _flying = value; |
699 | |||
485 | // simulate flying by changing the effect of gravity | 700 | // simulate flying by changing the effect of gravity |
486 | Buoyancy = ComputeBuoyancyFromFlying(_flying); | 701 | Buoyancy = ComputeBuoyancyFromFlying(_flying); |
487 | } | 702 | } |
@@ -500,27 +715,18 @@ public sealed class BSCharacter : BSPhysObject | |||
500 | get { return _throttleUpdates; } | 715 | get { return _throttleUpdates; } |
501 | set { _throttleUpdates = value; } | 716 | set { _throttleUpdates = value; } |
502 | } | 717 | } |
503 | public override bool IsColliding { | ||
504 | get { return (CollidingStep == PhysicsScene.SimulationStep); } | ||
505 | set { _isColliding = value; } | ||
506 | } | ||
507 | public override bool CollidingGround { | ||
508 | get { return (CollidingGroundStep == PhysicsScene.SimulationStep); } | ||
509 | set { CollidingGround = value; } | ||
510 | } | ||
511 | public override bool CollidingObj { | ||
512 | get { return _collidingObj; } | ||
513 | set { _collidingObj = value; } | ||
514 | } | ||
515 | public override bool FloatOnWater { | 718 | public override bool FloatOnWater { |
516 | set { | 719 | set { |
517 | _floatOnWater = value; | 720 | _floatOnWater = value; |
518 | PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate() | 721 | PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate() |
519 | { | 722 | { |
520 | if (_floatOnWater) | 723 | if (PhysBody.HasPhysicalBody) |
521 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); | 724 | { |
522 | else | 725 | if (_floatOnWater) |
523 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); | 726 | CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); |
727 | else | ||
728 | CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); | ||
729 | } | ||
524 | }); | 730 | }); |
525 | } | 731 | } |
526 | } | 732 | } |
@@ -549,11 +755,16 @@ public sealed class BSCharacter : BSPhysObject | |||
549 | } | 755 | } |
550 | public override float ForceBuoyancy { | 756 | public override float ForceBuoyancy { |
551 | get { return _buoyancy; } | 757 | get { return _buoyancy; } |
552 | set { _buoyancy = value; | 758 | set { |
759 | PhysicsScene.AssertInTaintTime("BSCharacter.ForceBuoyancy"); | ||
760 | |||
761 | _buoyancy = value; | ||
553 | DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); | 762 | DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); |
554 | // Buoyancy is faked by changing the gravity applied to the object | 763 | // Buoyancy is faked by changing the gravity applied to the object |
555 | float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); | 764 | float grav = BSParam.Gravity * (1f - _buoyancy); |
556 | BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav)); | 765 | Gravity = new OMV.Vector3(0f, 0f, grav); |
766 | if (PhysBody.HasPhysicalBody) | ||
767 | PhysicsScene.PE.SetGravity(PhysBody, Gravity); | ||
557 | } | 768 | } |
558 | } | 769 | } |
559 | 770 | ||
@@ -589,24 +800,33 @@ public sealed class BSCharacter : BSPhysObject | |||
589 | public override float APIDStrength { set { return; } } | 800 | public override float APIDStrength { set { return; } } |
590 | public override float APIDDamping { set { return; } } | 801 | public override float APIDDamping { set { return; } } |
591 | 802 | ||
592 | public override void AddForce(OMV.Vector3 force, bool pushforce) { | 803 | public override void AddForce(OMV.Vector3 force, bool pushforce) |
804 | { | ||
805 | // Since this force is being applied in only one step, make this a force per second. | ||
806 | OMV.Vector3 addForce = force / PhysicsScene.LastTimeStep; | ||
807 | AddForce(addForce, pushforce, false); | ||
808 | } | ||
809 | private void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { | ||
593 | if (force.IsFinite()) | 810 | if (force.IsFinite()) |
594 | { | 811 | { |
595 | _force.X += force.X; | 812 | OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude); |
596 | _force.Y += force.Y; | 813 | // DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce); |
597 | _force.Z += force.Z; | 814 | |
598 | // m_log.DebugFormat("{0}: AddForce. adding={1}, newForce={2}", LogHeader, force, _force); | 815 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.AddForce", delegate() |
599 | PhysicsScene.TaintedObject("BSCharacter.AddForce", delegate() | ||
600 | { | 816 | { |
601 | DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force); | 817 | // Bullet adds this central force to the total force for this tick |
602 | BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); | 818 | // DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce); |
819 | if (PhysBody.HasPhysicalBody) | ||
820 | { | ||
821 | PhysicsScene.PE.ApplyCentralForce(PhysBody, addForce); | ||
822 | } | ||
603 | }); | 823 | }); |
604 | } | 824 | } |
605 | else | 825 | else |
606 | { | 826 | { |
607 | m_log.ErrorFormat("{0}: Got a NaN force applied to a Character", LogHeader); | 827 | m_log.WarnFormat("{0}: Got a NaN force applied to a character. LocalID={1}", LogHeader, LocalID); |
828 | return; | ||
608 | } | 829 | } |
609 | //m_lastUpdateSent = false; | ||
610 | } | 830 | } |
611 | 831 | ||
612 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { | 832 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { |
@@ -614,24 +834,31 @@ public sealed class BSCharacter : BSPhysObject | |||
614 | public override void SetMomentum(OMV.Vector3 momentum) { | 834 | public override void SetMomentum(OMV.Vector3 momentum) { |
615 | } | 835 | } |
616 | 836 | ||
617 | private void ComputeAvatarScale(OMV.Vector3 size) | 837 | private OMV.Vector3 ComputeAvatarScale(OMV.Vector3 size) |
618 | { | 838 | { |
619 | // The 'size' given by the simulator is the mid-point of the avatar | 839 | OMV.Vector3 newScale; |
620 | // and X and Y are unspecified. | 840 | |
621 | 841 | // Bullet's capsule total height is the "passed height + radius * 2"; | |
622 | OMV.Vector3 newScale = size; | 842 | // The base capsule is 1 diameter and 2 height (passed radius=0.5, passed height = 1) |
623 | // newScale.X = PhysicsScene.Params.avatarCapsuleWidth; | 843 | // The number we pass in for 'scaling' is the multiplier to get that base |
624 | // newScale.Y = PhysicsScene.Params.avatarCapsuleDepth; | 844 | // shape to be the size desired. |
625 | 845 | // So, when creating the scale for the avatar height, we take the passed height | |
626 | // From the total height, remove the capsule half spheres that are at each end | 846 | // (size.Z) and remove the caps. |
627 | // The 1.15f came from ODE. Not sure what this factors in. | 847 | // Another oddity of the Bullet capsule implementation is that it presumes the Y |
628 | // newScale.Z = (size.Z * 1.15f) - (newScale.X + newScale.Y); | 848 | // dimension is the radius of the capsule. Even though some of the code allows |
849 | // for a asymmetrical capsule, other parts of the code presume it is cylindrical. | ||
850 | |||
851 | // Scale is multiplier of radius with one of "0.5" | ||
852 | newScale.X = size.X / 2f; | ||
853 | newScale.Y = size.Y / 2f; | ||
629 | 854 | ||
630 | // The total scale height is the central cylindar plus the caps on the two ends. | 855 | // The total scale height is the central cylindar plus the caps on the two ends. |
631 | newScale.Z = size.Z + (Math.Min(size.X, size.Y) * 2f); | 856 | newScale.Z = (size.Z + (Math.Min(size.X, size.Y) * 2)) / 2f; |
857 | // If smaller than the endcaps, just fake like we're almost that small | ||
858 | if (newScale.Z < 0) | ||
859 | newScale.Z = 0.1f; | ||
632 | 860 | ||
633 | // Convert diameters to radii and height to half height -- the way Bullet expects it. | 861 | return newScale; |
634 | Scale = newScale / 2f; | ||
635 | } | 862 | } |
636 | 863 | ||
637 | // set _avatarVolume and _mass based on capsule size, _density and Scale | 864 | // set _avatarVolume and _mass based on capsule size, _density and Scale |
@@ -639,16 +866,16 @@ public sealed class BSCharacter : BSPhysObject | |||
639 | { | 866 | { |
640 | _avatarVolume = (float)( | 867 | _avatarVolume = (float)( |
641 | Math.PI | 868 | Math.PI |
642 | * Scale.X | 869 | * Size.X / 2f |
643 | * Scale.Y // the area of capsule cylinder | 870 | * Size.Y / 2f // the area of capsule cylinder |
644 | * Scale.Z // times height of capsule cylinder | 871 | * Size.Z // times height of capsule cylinder |
645 | + 1.33333333f | 872 | + 1.33333333f |
646 | * Math.PI | 873 | * Math.PI |
647 | * Scale.X | 874 | * Size.X / 2f |
648 | * Math.Min(Scale.X, Scale.Y) | 875 | * Math.Min(Size.X, Size.Y) / 2 |
649 | * Scale.Y // plus the volume of the capsule end caps | 876 | * Size.Y / 2f // plus the volume of the capsule end caps |
650 | ); | 877 | ); |
651 | _mass = _avatarDensity * _avatarVolume; | 878 | _mass = Density * BSParam.DensityScaleFactor * _avatarVolume; |
652 | } | 879 | } |
653 | 880 | ||
654 | // The physics engine says that properties have updated. Update same and inform | 881 | // The physics engine says that properties have updated. Update same and inform |
@@ -657,27 +884,30 @@ public sealed class BSCharacter : BSPhysObject | |||
657 | { | 884 | { |
658 | _position = entprop.Position; | 885 | _position = entprop.Position; |
659 | _orientation = entprop.Rotation; | 886 | _orientation = entprop.Rotation; |
660 | _velocity = entprop.Velocity; | 887 | |
888 | // Smooth velocity. OpenSimulator is VERY sensitive to changes in velocity of the avatar | ||
889 | // and will send agent updates to the clients if velocity changes by more than | ||
890 | // 0.001m/s. Bullet introduces a lot of jitter in the velocity which causes many | ||
891 | // extra updates. | ||
892 | if (!entprop.Velocity.ApproxEquals(_velocity, 0.1f)) | ||
893 | _velocity = entprop.Velocity; | ||
894 | |||
661 | _acceleration = entprop.Acceleration; | 895 | _acceleration = entprop.Acceleration; |
662 | _rotationalVelocity = entprop.RotationalVelocity; | 896 | _rotationalVelocity = entprop.RotationalVelocity; |
897 | |||
663 | // Do some sanity checking for the avatar. Make sure it's above ground and inbounds. | 898 | // Do some sanity checking for the avatar. Make sure it's above ground and inbounds. |
664 | PositionSanityCheck(true); | 899 | if (PositionSanityCheck(true)) |
900 | { | ||
901 | DetailLog("{0},BSCharacter.UpdateProperties,updatePosForSanity,pos={1}", LocalID, _position); | ||
902 | entprop.Position = _position; | ||
903 | } | ||
665 | 904 | ||
666 | // remember the current and last set values | 905 | // remember the current and last set values |
667 | LastEntityProperties = CurrentEntityProperties; | 906 | LastEntityProperties = CurrentEntityProperties; |
668 | CurrentEntityProperties = entprop; | 907 | CurrentEntityProperties = entprop; |
669 | 908 | ||
670 | if (entprop.Velocity != LastEntityProperties.Velocity) | ||
671 | { | ||
672 | // Changes in the velocity are suppressed in avatars. | ||
673 | // That's just the way they are defined. | ||
674 | OMV.Vector3 avVel = new OMV.Vector3(_appliedVelocity.X, _appliedVelocity.Y, entprop.Velocity.Z); | ||
675 | _velocity = avVel; | ||
676 | BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, avVel); | ||
677 | } | ||
678 | |||
679 | // Tell the linkset about value changes | 909 | // Tell the linkset about value changes |
680 | Linkset.UpdateProperties(this); | 910 | // Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this); |
681 | 911 | ||
682 | // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. | 912 | // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. |
683 | // base.RequestPhysicsterseUpdate(); | 913 | // base.RequestPhysicsterseUpdate(); |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs index 65fac00..b813974 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs | |||
@@ -36,7 +36,8 @@ public abstract class BSConstraint : IDisposable | |||
36 | { | 36 | { |
37 | private static string LogHeader = "[BULLETSIM CONSTRAINT]"; | 37 | private static string LogHeader = "[BULLETSIM CONSTRAINT]"; |
38 | 38 | ||
39 | protected BulletSim m_world; | 39 | protected BulletWorld m_world; |
40 | protected BSScene PhysicsScene; | ||
40 | protected BulletBody m_body1; | 41 | protected BulletBody m_body1; |
41 | protected BulletBody m_body2; | 42 | protected BulletBody m_body2; |
42 | protected BulletConstraint m_constraint; | 43 | protected BulletConstraint m_constraint; |
@@ -48,8 +49,10 @@ public abstract class BSConstraint : IDisposable | |||
48 | public abstract ConstraintType Type { get; } | 49 | public abstract ConstraintType Type { get; } |
49 | public bool IsEnabled { get { return m_enabled; } } | 50 | public bool IsEnabled { get { return m_enabled; } } |
50 | 51 | ||
51 | public BSConstraint() | 52 | public BSConstraint(BulletWorld world) |
52 | { | 53 | { |
54 | m_world = world; | ||
55 | PhysicsScene = m_world.physicsScene; | ||
53 | } | 56 | } |
54 | 57 | ||
55 | public virtual void Dispose() | 58 | public virtual void Dispose() |
@@ -57,15 +60,15 @@ public abstract class BSConstraint : IDisposable | |||
57 | if (m_enabled) | 60 | if (m_enabled) |
58 | { | 61 | { |
59 | m_enabled = false; | 62 | m_enabled = false; |
60 | if (m_constraint.ptr != IntPtr.Zero) | 63 | if (m_constraint.HasPhysicalConstraint) |
61 | { | 64 | { |
62 | bool success = BulletSimAPI.DestroyConstraint2(m_world.ptr, m_constraint.ptr); | 65 | bool success = PhysicsScene.PE.DestroyConstraint(m_world, m_constraint); |
63 | m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}", | 66 | m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}", |
64 | BSScene.DetailLogZero, | 67 | BSScene.DetailLogZero, |
65 | m_body1.ID, m_body1.ptr.ToString("X"), | 68 | m_body1.ID, m_body1.AddrString, |
66 | m_body2.ID, m_body2.ptr.ToString("X"), | 69 | m_body2.ID, m_body2.AddrString, |
67 | success); | 70 | success); |
68 | m_constraint.ptr = System.IntPtr.Zero; | 71 | m_constraint.Clear(); |
69 | } | 72 | } |
70 | } | 73 | } |
71 | } | 74 | } |
@@ -74,7 +77,7 @@ public abstract class BSConstraint : IDisposable | |||
74 | { | 77 | { |
75 | bool ret = false; | 78 | bool ret = false; |
76 | if (m_enabled) | 79 | if (m_enabled) |
77 | ret = BulletSimAPI.SetLinearLimits2(m_constraint.ptr, low, high); | 80 | ret = PhysicsScene.PE.SetLinearLimits(m_constraint, low, high); |
78 | return ret; | 81 | return ret; |
79 | } | 82 | } |
80 | 83 | ||
@@ -82,7 +85,7 @@ public abstract class BSConstraint : IDisposable | |||
82 | { | 85 | { |
83 | bool ret = false; | 86 | bool ret = false; |
84 | if (m_enabled) | 87 | if (m_enabled) |
85 | ret = BulletSimAPI.SetAngularLimits2(m_constraint.ptr, low, high); | 88 | ret = PhysicsScene.PE.SetAngularLimits(m_constraint, low, high); |
86 | return ret; | 89 | return ret; |
87 | } | 90 | } |
88 | 91 | ||
@@ -91,7 +94,7 @@ public abstract class BSConstraint : IDisposable | |||
91 | bool ret = false; | 94 | bool ret = false; |
92 | if (m_enabled) | 95 | if (m_enabled) |
93 | { | 96 | { |
94 | BulletSimAPI.SetConstraintNumSolverIterations2(m_constraint.ptr, cnt); | 97 | PhysicsScene.PE.SetConstraintNumSolverIterations(m_constraint, cnt); |
95 | ret = true; | 98 | ret = true; |
96 | } | 99 | } |
97 | return ret; | 100 | return ret; |
@@ -103,7 +106,7 @@ public abstract class BSConstraint : IDisposable | |||
103 | if (m_enabled) | 106 | if (m_enabled) |
104 | { | 107 | { |
105 | // Recompute the internal transforms | 108 | // Recompute the internal transforms |
106 | BulletSimAPI.CalculateTransforms2(m_constraint.ptr); | 109 | PhysicsScene.PE.CalculateTransforms(m_constraint); |
107 | ret = true; | 110 | ret = true; |
108 | } | 111 | } |
109 | return ret; | 112 | return ret; |
@@ -122,7 +125,7 @@ public abstract class BSConstraint : IDisposable | |||
122 | // Setting an object's mass to zero (making it static like when it's selected) | 125 | // Setting an object's mass to zero (making it static like when it's selected) |
123 | // automatically disables the constraints. | 126 | // automatically disables the constraints. |
124 | // If the link is enabled, be sure to set the constraint itself to enabled. | 127 | // If the link is enabled, be sure to set the constraint itself to enabled. |
125 | BulletSimAPI.SetConstraintEnable2(m_constraint.ptr, m_world.physicsScene.NumericBool(true)); | 128 | PhysicsScene.PE.SetConstraintEnable(m_constraint, BSParam.NumericBool(true)); |
126 | } | 129 | } |
127 | else | 130 | else |
128 | { | 131 | { |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs index 23ef052..476a0e5 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs | |||
@@ -39,51 +39,50 @@ public sealed class BSConstraint6Dof : BSConstraint | |||
39 | public override ConstraintType Type { get { return ConstraintType.D6_CONSTRAINT_TYPE; } } | 39 | public override ConstraintType Type { get { return ConstraintType.D6_CONSTRAINT_TYPE; } } |
40 | 40 | ||
41 | // Create a btGeneric6DofConstraint | 41 | // Create a btGeneric6DofConstraint |
42 | public BSConstraint6Dof(BulletSim world, BulletBody obj1, BulletBody obj2, | 42 | public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2, |
43 | Vector3 frame1, Quaternion frame1rot, | 43 | Vector3 frame1, Quaternion frame1rot, |
44 | Vector3 frame2, Quaternion frame2rot, | 44 | Vector3 frame2, Quaternion frame2rot, |
45 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) | 45 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) |
46 | : base(world) | ||
46 | { | 47 | { |
47 | m_world = world; | ||
48 | m_body1 = obj1; | 48 | m_body1 = obj1; |
49 | m_body2 = obj2; | 49 | m_body2 = obj2; |
50 | m_constraint = new BulletConstraint( | 50 | m_constraint = PhysicsScene.PE.Create6DofConstraint(m_world, m_body1, m_body2, |
51 | BulletSimAPI.Create6DofConstraint2(m_world.ptr, m_body1.ptr, m_body2.ptr, | ||
52 | frame1, frame1rot, | 51 | frame1, frame1rot, |
53 | frame2, frame2rot, | 52 | frame2, frame2rot, |
54 | useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); | 53 | useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); |
55 | m_enabled = true; | 54 | m_enabled = true; |
56 | world.physicsScene.DetailLog("{0},BS6DofConstraint,createFrame,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", | 55 | world.physicsScene.DetailLog("{0},BS6DofConstraint,createFrame,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", |
57 | BSScene.DetailLogZero, world.worldID, | 56 | BSScene.DetailLogZero, world.worldID, |
58 | obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X")); | 57 | obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString); |
59 | } | 58 | } |
60 | 59 | ||
61 | public BSConstraint6Dof(BulletSim world, BulletBody obj1, BulletBody obj2, | 60 | // 6 Dof constraint based on a midpoint between the two constrained bodies |
61 | public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
62 | Vector3 joinPoint, | 62 | Vector3 joinPoint, |
63 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) | 63 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) |
64 | : base(world) | ||
64 | { | 65 | { |
65 | m_world = world; | ||
66 | m_body1 = obj1; | 66 | m_body1 = obj1; |
67 | m_body2 = obj2; | 67 | m_body2 = obj2; |
68 | if (obj1.ptr == IntPtr.Zero || obj2.ptr == IntPtr.Zero) | 68 | if (!obj1.HasPhysicalBody || !obj2.HasPhysicalBody) |
69 | { | 69 | { |
70 | world.physicsScene.DetailLog("{0},BS6DOFConstraint,badBodyPtr,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", | 70 | world.physicsScene.DetailLog("{0},BS6DOFConstraint,badBodyPtr,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", |
71 | BSScene.DetailLogZero, world.worldID, | 71 | BSScene.DetailLogZero, world.worldID, |
72 | obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X")); | 72 | obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString); |
73 | world.physicsScene.Logger.ErrorFormat("{0} Attempt to build 6DOF constraint with missing bodies: wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", | 73 | world.physicsScene.Logger.ErrorFormat("{0} Attempt to build 6DOF constraint with missing bodies: wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", |
74 | LogHeader, world.worldID, obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X")); | 74 | LogHeader, world.worldID, obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString); |
75 | m_enabled = false; | 75 | m_enabled = false; |
76 | } | 76 | } |
77 | else | 77 | else |
78 | { | 78 | { |
79 | m_constraint = new BulletConstraint( | 79 | m_constraint = PhysicsScene.PE.Create6DofConstraintToPoint(m_world, m_body1, m_body2, |
80 | BulletSimAPI.Create6DofConstraintToPoint2(m_world.ptr, m_body1.ptr, m_body2.ptr, | ||
81 | joinPoint, | 80 | joinPoint, |
82 | useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); | 81 | useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); |
83 | world.physicsScene.DetailLog("{0},BS6DofConstraint,createMidPoint,wID={1}, csrt={2}, rID={3}, rBody={4}, cID={5}, cBody={6}", | 82 | PhysicsScene.DetailLog("{0},BS6DofConstraint,createMidPoint,wID={1}, csrt={2}, rID={3}, rBody={4}, cID={5}, cBody={6}", |
84 | BSScene.DetailLogZero, world.worldID, m_constraint.ptr.ToString("X"), | 83 | BSScene.DetailLogZero, world.worldID, m_constraint.AddrString, |
85 | obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X")); | 84 | obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString); |
86 | if (m_constraint.ptr == IntPtr.Zero) | 85 | if (!m_constraint.HasPhysicalConstraint) |
87 | { | 86 | { |
88 | world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}", | 87 | world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}", |
89 | LogHeader, obj1.ID, obj2.ID); | 88 | LogHeader, obj1.ID, obj2.ID); |
@@ -96,12 +95,27 @@ public sealed class BSConstraint6Dof : BSConstraint | |||
96 | } | 95 | } |
97 | } | 96 | } |
98 | 97 | ||
98 | // A 6 Dof constraint that is fixed in the world and constrained to a on-the-fly created static object | ||
99 | public BSConstraint6Dof(BulletWorld world, BulletBody obj1, Vector3 frameInBloc, Quaternion frameInBrot, | ||
100 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) | ||
101 | : base(world) | ||
102 | { | ||
103 | m_body1 = obj1; | ||
104 | m_body2 = obj1; // Look out for confusion down the road | ||
105 | m_constraint = PhysicsScene.PE.Create6DofConstraintFixed(m_world, m_body1, | ||
106 | frameInBloc, frameInBrot, | ||
107 | useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); | ||
108 | m_enabled = true; | ||
109 | world.physicsScene.DetailLog("{0},BS6DofConstraint,createFixed,wID={1},rID={2},rBody={3}", | ||
110 | BSScene.DetailLogZero, world.worldID, obj1.ID, obj1.AddrString); | ||
111 | } | ||
112 | |||
99 | public bool SetFrames(Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot) | 113 | public bool SetFrames(Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot) |
100 | { | 114 | { |
101 | bool ret = false; | 115 | bool ret = false; |
102 | if (m_enabled) | 116 | if (m_enabled) |
103 | { | 117 | { |
104 | BulletSimAPI.SetFrames2(m_constraint.ptr, frameA, frameArot, frameB, frameBrot); | 118 | PhysicsScene.PE.SetFrames(m_constraint, frameA, frameArot, frameB, frameBrot); |
105 | ret = true; | 119 | ret = true; |
106 | } | 120 | } |
107 | return ret; | 121 | return ret; |
@@ -112,9 +126,9 @@ public sealed class BSConstraint6Dof : BSConstraint | |||
112 | bool ret = false; | 126 | bool ret = false; |
113 | if (m_enabled) | 127 | if (m_enabled) |
114 | { | 128 | { |
115 | BulletSimAPI.SetConstraintParam2(m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL); | 129 | PhysicsScene.PE.SetConstraintParam(m_constraint, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL); |
116 | BulletSimAPI.SetConstraintParam2(m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_ERP, erp, ConstraintParamAxis.AXIS_ALL); | 130 | PhysicsScene.PE.SetConstraintParam(m_constraint, ConstraintParams.BT_CONSTRAINT_STOP_ERP, erp, ConstraintParamAxis.AXIS_ALL); |
117 | BulletSimAPI.SetConstraintParam2(m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_CFM, cfm, ConstraintParamAxis.AXIS_ALL); | 131 | PhysicsScene.PE.SetConstraintParam(m_constraint, ConstraintParams.BT_CONSTRAINT_CFM, cfm, ConstraintParamAxis.AXIS_ALL); |
118 | ret = true; | 132 | ret = true; |
119 | } | 133 | } |
120 | return ret; | 134 | return ret; |
@@ -125,7 +139,7 @@ public sealed class BSConstraint6Dof : BSConstraint | |||
125 | bool ret = false; | 139 | bool ret = false; |
126 | float onOff = useOffset ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse; | 140 | float onOff = useOffset ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse; |
127 | if (m_enabled) | 141 | if (m_enabled) |
128 | ret = BulletSimAPI.UseFrameOffset2(m_constraint.ptr, onOff); | 142 | ret = PhysicsScene.PE.UseFrameOffset(m_constraint, onOff); |
129 | return ret; | 143 | return ret; |
130 | } | 144 | } |
131 | 145 | ||
@@ -135,7 +149,7 @@ public sealed class BSConstraint6Dof : BSConstraint | |||
135 | float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse; | 149 | float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse; |
136 | if (m_enabled) | 150 | if (m_enabled) |
137 | { | 151 | { |
138 | ret = BulletSimAPI.TranslationalLimitMotor2(m_constraint.ptr, onOff, targetVelocity, maxMotorForce); | 152 | ret = PhysicsScene.PE.TranslationalLimitMotor(m_constraint, onOff, targetVelocity, maxMotorForce); |
139 | m_world.physicsScene.DetailLog("{0},BS6DOFConstraint,TransLimitMotor,enable={1},vel={2},maxForce={3}", | 153 | m_world.physicsScene.DetailLog("{0},BS6DOFConstraint,TransLimitMotor,enable={1},vel={2},maxForce={3}", |
140 | BSScene.DetailLogZero, enable, targetVelocity, maxMotorForce); | 154 | BSScene.DetailLogZero, enable, targetVelocity, maxMotorForce); |
141 | } | 155 | } |
@@ -146,7 +160,7 @@ public sealed class BSConstraint6Dof : BSConstraint | |||
146 | { | 160 | { |
147 | bool ret = false; | 161 | bool ret = false; |
148 | if (m_enabled) | 162 | if (m_enabled) |
149 | ret = BulletSimAPI.SetBreakingImpulseThreshold2(m_constraint.ptr, threshold); | 163 | ret = PhysicsScene.PE.SetBreakingImpulseThreshold(m_constraint, threshold); |
150 | return ret; | 164 | return ret; |
151 | } | 165 | } |
152 | } | 166 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs index a9fd826..5c8d94e 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs | |||
@@ -41,9 +41,9 @@ public sealed class BSConstraintCollection : IDisposable | |||
41 | delegate bool ConstraintAction(BSConstraint constrain); | 41 | delegate bool ConstraintAction(BSConstraint constrain); |
42 | 42 | ||
43 | private List<BSConstraint> m_constraints; | 43 | private List<BSConstraint> m_constraints; |
44 | private BulletSim m_world; | 44 | private BulletWorld m_world; |
45 | 45 | ||
46 | public BSConstraintCollection(BulletSim world) | 46 | public BSConstraintCollection(BulletWorld world) |
47 | { | 47 | { |
48 | m_world = world; | 48 | m_world = world; |
49 | m_constraints = new List<BSConstraint>(); | 49 | m_constraints = new List<BSConstraint>(); |
@@ -117,8 +117,7 @@ public sealed class BSConstraintCollection : IDisposable | |||
117 | if (this.TryGetConstraint(body1, body2, out constrain)) | 117 | if (this.TryGetConstraint(body1, body2, out constrain)) |
118 | { | 118 | { |
119 | // remove the constraint from our collection | 119 | // remove the constraint from our collection |
120 | RemoveAndDestroyConstraint(constrain); | 120 | ret = RemoveAndDestroyConstraint(constrain); |
121 | ret = true; | ||
122 | } | 121 | } |
123 | } | 122 | } |
124 | 123 | ||
@@ -126,17 +125,19 @@ public sealed class BSConstraintCollection : IDisposable | |||
126 | } | 125 | } |
127 | 126 | ||
128 | // The constraint MUST exist in the collection | 127 | // The constraint MUST exist in the collection |
128 | // Could be called if the constraint was previously removed. | ||
129 | // Return 'true' if the constraint was actually removed and disposed. | ||
129 | public bool RemoveAndDestroyConstraint(BSConstraint constrain) | 130 | public bool RemoveAndDestroyConstraint(BSConstraint constrain) |
130 | { | 131 | { |
132 | bool removed = false; | ||
131 | lock (m_constraints) | 133 | lock (m_constraints) |
132 | { | 134 | { |
133 | // remove the constraint from our collection | 135 | // remove the constraint from our collection |
134 | m_constraints.Remove(constrain); | 136 | removed = m_constraints.Remove(constrain); |
135 | } | 137 | } |
136 | // tell the engine that all its structures need to be freed | 138 | // Dispose() is safe to call multiple times |
137 | constrain.Dispose(); | 139 | constrain.Dispose(); |
138 | // we destroyed something | 140 | return removed; |
139 | return true; | ||
140 | } | 141 | } |
141 | 142 | ||
142 | // Remove all constraints that reference the passed body. | 143 | // Remove all constraints that reference the passed body. |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs index ed3ffa7..7714a03 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs | |||
@@ -36,19 +36,17 @@ public sealed class BSConstraintHinge : BSConstraint | |||
36 | { | 36 | { |
37 | public override ConstraintType Type { get { return ConstraintType.HINGE_CONSTRAINT_TYPE; } } | 37 | public override ConstraintType Type { get { return ConstraintType.HINGE_CONSTRAINT_TYPE; } } |
38 | 38 | ||
39 | public BSConstraintHinge(BulletSim world, BulletBody obj1, BulletBody obj2, | 39 | public BSConstraintHinge(BulletWorld world, BulletBody obj1, BulletBody obj2, |
40 | Vector3 pivotInA, Vector3 pivotInB, | 40 | Vector3 pivotInA, Vector3 pivotInB, |
41 | Vector3 axisInA, Vector3 axisInB, | 41 | Vector3 axisInA, Vector3 axisInB, |
42 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) | 42 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) |
43 | : base(world) | ||
43 | { | 44 | { |
44 | m_world = world; | ||
45 | m_body1 = obj1; | 45 | m_body1 = obj1; |
46 | m_body2 = obj2; | 46 | m_body2 = obj2; |
47 | m_constraint = new BulletConstraint( | 47 | m_constraint = PhysicsScene.PE.CreateHingeConstraint(world, obj1, obj2, |
48 | BulletSimAPI.CreateHingeConstraint2(m_world.ptr, m_body1.ptr, m_body2.ptr, | 48 | pivotInA, pivotInB, axisInA, axisInB, |
49 | pivotInA, pivotInB, | 49 | useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); |
50 | axisInA, axisInB, | ||
51 | useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); | ||
52 | m_enabled = true; | 50 | m_enabled = true; |
53 | } | 51 | } |
54 | 52 | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index dbc9039..65df741 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | |||
@@ -24,28 +24,16 @@ | |||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | 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. | 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | * | 26 | * |
27 | 27 | * The quotations from http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial | |
28 | /* RA: June 14, 2011. Copied from ODEDynamics.cs and converted to | 28 | * are Copyright (c) 2009 Linden Research, Inc and are used under their license |
29 | * call the BulletSim system. | 29 | * of Creative Commons Attribution-Share Alike 3.0 |
30 | */ | 30 | * (http://creativecommons.org/licenses/by-sa/3.0/). |
31 | /* Revised Aug, Sept 2009 by Kitto Flora. ODEDynamics.cs replaces | ||
32 | * ODEVehicleSettings.cs. It and ODEPrim.cs are re-organised: | ||
33 | * ODEPrim.cs contains methods dealing with Prim editing, Prim | ||
34 | * characteristics and Kinetic motion. | ||
35 | * ODEDynamics.cs contains methods dealing with Prim Physical motion | ||
36 | * (dynamics) and the associated settings. Old Linear and angular | ||
37 | * motors for dynamic motion have been replace with MoveLinear() | ||
38 | * and MoveAngular(); 'Physical' is used only to switch ODE dynamic | ||
39 | * simualtion on/off; VEHICAL_TYPE_NONE/VEHICAL_TYPE_<other> is to | ||
40 | * switch between 'VEHICLE' parameter use and general dynamics | ||
41 | * settings use. | ||
42 | */ | 31 | */ |
43 | 32 | ||
44 | using System; | 33 | using System; |
45 | using System.Collections.Generic; | 34 | using System.Collections.Generic; |
46 | using System.Reflection; | 35 | using System.Reflection; |
47 | using System.Runtime.InteropServices; | 36 | using System.Runtime.InteropServices; |
48 | using log4net; | ||
49 | using OpenMetaverse; | 37 | using OpenMetaverse; |
50 | using OpenSim.Framework; | 38 | using OpenSim.Framework; |
51 | using OpenSim.Region.Physics.Manager; | 39 | using OpenSim.Region.Physics.Manager; |
@@ -80,10 +68,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
80 | private Quaternion m_referenceFrame = Quaternion.Identity; | 68 | private Quaternion m_referenceFrame = Quaternion.Identity; |
81 | 69 | ||
82 | // Linear properties | 70 | // Linear properties |
71 | private BSVMotor m_linearMotor = new BSVMotor("LinearMotor"); | ||
83 | private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time | 72 | private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time |
84 | private Vector3 m_linearMotorOffset = Vector3.Zero; // the point of force can be offset from the center | 73 | private Vector3 m_linearMotorOffset = Vector3.Zero; // the point of force can be offset from the center |
85 | private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL | 74 | private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL |
86 | private Vector3 m_newVelocity = Vector3.Zero; // velocity computed to be applied to body | ||
87 | private Vector3 m_linearFrictionTimescale = Vector3.Zero; | 75 | private Vector3 m_linearFrictionTimescale = Vector3.Zero; |
88 | private float m_linearMotorDecayTimescale = 0; | 76 | private float m_linearMotorDecayTimescale = 0; |
89 | private float m_linearMotorTimescale = 0; | 77 | private float m_linearMotorTimescale = 0; |
@@ -93,16 +81,18 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
93 | // private Vector3 m_linearMotorOffset = Vector3.Zero; | 81 | // private Vector3 m_linearMotorOffset = Vector3.Zero; |
94 | 82 | ||
95 | //Angular properties | 83 | //Angular properties |
84 | private BSVMotor m_angularMotor = new BSVMotor("AngularMotor"); | ||
96 | private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor | 85 | private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor |
97 | // private int m_angularMotorApply = 0; // application frame counter | 86 | // private int m_angularMotorApply = 0; // application frame counter |
98 | private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity | 87 | private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity |
99 | private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate | 88 | private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate |
100 | private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate | 89 | private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate |
101 | private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate | 90 | private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate |
102 | private Vector3 m_lastAngularVelocity = Vector3.Zero; // what was last applied to body | 91 | private Vector3 m_lastAngularVelocity = Vector3.Zero; |
103 | private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body | 92 | private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body |
104 | 93 | ||
105 | //Deflection properties | 94 | //Deflection properties |
95 | private BSVMotor m_angularDeflectionMotor = new BSVMotor("AngularDeflection"); | ||
106 | private float m_angularDeflectionEfficiency = 0; | 96 | private float m_angularDeflectionEfficiency = 0; |
107 | private float m_angularDeflectionTimescale = 0; | 97 | private float m_angularDeflectionTimescale = 0; |
108 | private float m_linearDeflectionEfficiency = 0; | 98 | private float m_linearDeflectionEfficiency = 0; |
@@ -114,33 +104,68 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
114 | private float m_bankingTimescale = 0; | 104 | private float m_bankingTimescale = 0; |
115 | 105 | ||
116 | //Hover and Buoyancy properties | 106 | //Hover and Buoyancy properties |
107 | private BSVMotor m_hoverMotor = new BSVMotor("Hover"); | ||
117 | private float m_VhoverHeight = 0f; | 108 | private float m_VhoverHeight = 0f; |
118 | private float m_VhoverEfficiency = 0f; | 109 | private float m_VhoverEfficiency = 0f; |
119 | private float m_VhoverTimescale = 0f; | 110 | private float m_VhoverTimescale = 0f; |
120 | private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height | 111 | private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height |
121 | private float m_VehicleBuoyancy = 0f; //KF: m_VehicleBuoyancy is set by VEHICLE_BUOYANCY for a vehicle. | 112 | // Modifies gravity. Slider between -1 (double-gravity) and 1 (full anti-gravity) |
122 | // Modifies gravity. Slider between -1 (double-gravity) and 1 (full anti-gravity) | 113 | private float m_VehicleBuoyancy = 0f; |
123 | // KF: So far I have found no good method to combine a script-requested .Z velocity and gravity. | 114 | private Vector3 m_VehicleGravity = Vector3.Zero; // Gravity computed when buoyancy set |
124 | // Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity. | ||
125 | 115 | ||
126 | //Attractor properties | 116 | //Attractor properties |
127 | private float m_verticalAttractionEfficiency = 1.0f; // damped | 117 | private BSVMotor m_verticalAttractionMotor = new BSVMotor("VerticalAttraction"); |
128 | private float m_verticalAttractionTimescale = 500f; // Timescale > 300 means no vert attractor. | 118 | private float m_verticalAttractionEfficiency = 1.0f; // damped |
119 | private float m_verticalAttractionCutoff = 500f; // per the documentation | ||
120 | // Timescale > cutoff means no vert attractor. | ||
121 | private float m_verticalAttractionTimescale = 510f; | ||
122 | |||
123 | // Just some recomputed constants: | ||
124 | static readonly float PIOverFour = ((float)Math.PI) / 4f; | ||
125 | static readonly float PIOverTwo = ((float)Math.PI) / 2f; | ||
126 | |||
127 | // For debugging, flags to turn on and off individual corrections. | ||
128 | public bool enableAngularVerticalAttraction; | ||
129 | public bool enableAngularDeflection; | ||
130 | public bool enableAngularBanking; | ||
129 | 131 | ||
130 | public BSDynamics(BSScene myScene, BSPrim myPrim) | 132 | public BSDynamics(BSScene myScene, BSPrim myPrim) |
131 | { | 133 | { |
132 | PhysicsScene = myScene; | 134 | PhysicsScene = myScene; |
133 | Prim = myPrim; | 135 | Prim = myPrim; |
134 | Type = Vehicle.TYPE_NONE; | 136 | Type = Vehicle.TYPE_NONE; |
137 | SetupVehicleDebugging(); | ||
138 | } | ||
139 | |||
140 | // Stopgap debugging enablement. Allows source level debugging but still checking | ||
141 | // in changes by making enablement of debugging flags from INI file. | ||
142 | public void SetupVehicleDebugging() | ||
143 | { | ||
144 | enableAngularVerticalAttraction = true; | ||
145 | enableAngularDeflection = false; | ||
146 | enableAngularBanking = true; | ||
147 | if (BSParam.VehicleDebuggingEnabled) | ||
148 | { | ||
149 | enableAngularVerticalAttraction = true; | ||
150 | enableAngularDeflection = false; | ||
151 | enableAngularBanking = false; | ||
152 | } | ||
135 | } | 153 | } |
136 | 154 | ||
137 | // Return 'true' if this vehicle is doing vehicle things | 155 | // Return 'true' if this vehicle is doing vehicle things |
138 | public bool IsActive | 156 | public bool IsActive |
139 | { | 157 | { |
140 | get { return Type != Vehicle.TYPE_NONE; } | 158 | get { return (Type != Vehicle.TYPE_NONE && Prim.IsPhysicallyActive); } |
141 | } | 159 | } |
142 | 160 | ||
143 | internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue) | 161 | // Return 'true' if this a vehicle that should be sitting on the ground |
162 | public bool IsGroundVehicle | ||
163 | { | ||
164 | get { return (Type == Vehicle.TYPE_CAR || Type == Vehicle.TYPE_SLED); } | ||
165 | } | ||
166 | |||
167 | #region Vehicle parameter setting | ||
168 | public void ProcessFloatVehicleParam(Vehicle pParam, float pValue) | ||
144 | { | 169 | { |
145 | VDetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue); | 170 | VDetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue); |
146 | switch (pParam) | 171 | switch (pParam) |
@@ -152,13 +177,15 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
152 | m_angularDeflectionTimescale = Math.Max(pValue, 0.01f); | 177 | m_angularDeflectionTimescale = Math.Max(pValue, 0.01f); |
153 | break; | 178 | break; |
154 | case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: | 179 | case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: |
155 | m_angularMotorDecayTimescale = Math.Max(pValue, 0.01f); | 180 | m_angularMotorDecayTimescale = ClampInRange(0.01f, pValue, 120); |
181 | m_angularMotor.TargetValueDecayTimeScale = m_angularMotorDecayTimescale; | ||
156 | break; | 182 | break; |
157 | case Vehicle.ANGULAR_MOTOR_TIMESCALE: | 183 | case Vehicle.ANGULAR_MOTOR_TIMESCALE: |
158 | m_angularMotorTimescale = Math.Max(pValue, 0.01f); | 184 | m_angularMotorTimescale = Math.Max(pValue, 0.01f); |
185 | m_angularMotor.TimeScale = m_angularMotorTimescale; | ||
159 | break; | 186 | break; |
160 | case Vehicle.BANKING_EFFICIENCY: | 187 | case Vehicle.BANKING_EFFICIENCY: |
161 | m_bankingEfficiency = Math.Max(-1f, Math.Min(pValue, 1f)); | 188 | m_bankingEfficiency = ClampInRange(-1f, pValue, 1f); |
162 | break; | 189 | break; |
163 | case Vehicle.BANKING_MIX: | 190 | case Vehicle.BANKING_MIX: |
164 | m_bankingMix = Math.Max(pValue, 0.01f); | 191 | m_bankingMix = Math.Max(pValue, 0.01f); |
@@ -167,10 +194,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
167 | m_bankingTimescale = Math.Max(pValue, 0.01f); | 194 | m_bankingTimescale = Math.Max(pValue, 0.01f); |
168 | break; | 195 | break; |
169 | case Vehicle.BUOYANCY: | 196 | case Vehicle.BUOYANCY: |
170 | m_VehicleBuoyancy = Math.Max(-1f, Math.Min(pValue, 1f)); | 197 | m_VehicleBuoyancy = ClampInRange(-1f, pValue, 1f); |
198 | m_VehicleGravity = Prim.ComputeGravity(m_VehicleBuoyancy); | ||
171 | break; | 199 | break; |
172 | case Vehicle.HOVER_EFFICIENCY: | 200 | case Vehicle.HOVER_EFFICIENCY: |
173 | m_VhoverEfficiency = Math.Max(0f, Math.Min(pValue, 1f)); | 201 | m_VhoverEfficiency = ClampInRange(0f, pValue, 1f); |
174 | break; | 202 | break; |
175 | case Vehicle.HOVER_HEIGHT: | 203 | case Vehicle.HOVER_HEIGHT: |
176 | m_VhoverHeight = pValue; | 204 | m_VhoverHeight = pValue; |
@@ -185,33 +213,41 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
185 | m_linearDeflectionTimescale = Math.Max(pValue, 0.01f); | 213 | m_linearDeflectionTimescale = Math.Max(pValue, 0.01f); |
186 | break; | 214 | break; |
187 | case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: | 215 | case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: |
188 | m_linearMotorDecayTimescale = Math.Max(pValue, 0.01f); | 216 | m_linearMotorDecayTimescale = ClampInRange(0.01f, pValue, 120); |
217 | m_linearMotor.TargetValueDecayTimeScale = m_linearMotorDecayTimescale; | ||
189 | break; | 218 | break; |
190 | case Vehicle.LINEAR_MOTOR_TIMESCALE: | 219 | case Vehicle.LINEAR_MOTOR_TIMESCALE: |
191 | m_linearMotorTimescale = Math.Max(pValue, 0.01f); | 220 | m_linearMotorTimescale = Math.Max(pValue, 0.01f); |
221 | m_linearMotor.TimeScale = m_linearMotorTimescale; | ||
192 | break; | 222 | break; |
193 | case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY: | 223 | case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY: |
194 | m_verticalAttractionEfficiency = Math.Max(0.1f, Math.Min(pValue, 1f)); | 224 | m_verticalAttractionEfficiency = ClampInRange(0.1f, pValue, 1f); |
225 | m_verticalAttractionMotor.Efficiency = m_verticalAttractionEfficiency; | ||
195 | break; | 226 | break; |
196 | case Vehicle.VERTICAL_ATTRACTION_TIMESCALE: | 227 | case Vehicle.VERTICAL_ATTRACTION_TIMESCALE: |
197 | m_verticalAttractionTimescale = Math.Max(pValue, 0.01f); | 228 | m_verticalAttractionTimescale = Math.Max(pValue, 0.01f); |
229 | m_verticalAttractionMotor.TimeScale = m_verticalAttractionTimescale; | ||
198 | break; | 230 | break; |
199 | 231 | ||
200 | // These are vector properties but the engine lets you use a single float value to | 232 | // These are vector properties but the engine lets you use a single float value to |
201 | // set all of the components to the same value | 233 | // set all of the components to the same value |
202 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: | 234 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: |
203 | m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue); | 235 | m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue); |
236 | m_angularMotor.FrictionTimescale = m_angularFrictionTimescale; | ||
204 | break; | 237 | break; |
205 | case Vehicle.ANGULAR_MOTOR_DIRECTION: | 238 | case Vehicle.ANGULAR_MOTOR_DIRECTION: |
206 | m_angularMotorDirection = new Vector3(pValue, pValue, pValue); | 239 | m_angularMotorDirection = new Vector3(pValue, pValue, pValue); |
207 | // m_angularMotorApply = 100; | 240 | m_angularMotor.Zero(); |
241 | m_angularMotor.SetTarget(m_angularMotorDirection); | ||
208 | break; | 242 | break; |
209 | case Vehicle.LINEAR_FRICTION_TIMESCALE: | 243 | case Vehicle.LINEAR_FRICTION_TIMESCALE: |
210 | m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); | 244 | m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); |
245 | m_linearMotor.FrictionTimescale = m_linearFrictionTimescale; | ||
211 | break; | 246 | break; |
212 | case Vehicle.LINEAR_MOTOR_DIRECTION: | 247 | case Vehicle.LINEAR_MOTOR_DIRECTION: |
213 | m_linearMotorDirection = new Vector3(pValue, pValue, pValue); | 248 | m_linearMotorDirection = new Vector3(pValue, pValue, pValue); |
214 | m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue); | 249 | m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue); |
250 | m_linearMotor.SetTarget(m_linearMotorDirection); | ||
215 | break; | 251 | break; |
216 | case Vehicle.LINEAR_MOTOR_OFFSET: | 252 | case Vehicle.LINEAR_MOTOR_OFFSET: |
217 | m_linearMotorOffset = new Vector3(pValue, pValue, pValue); | 253 | m_linearMotorOffset = new Vector3(pValue, pValue, pValue); |
@@ -227,21 +263,25 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
227 | { | 263 | { |
228 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: | 264 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: |
229 | m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); | 265 | m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); |
266 | m_angularMotor.FrictionTimescale = m_angularFrictionTimescale; | ||
230 | break; | 267 | break; |
231 | case Vehicle.ANGULAR_MOTOR_DIRECTION: | 268 | case Vehicle.ANGULAR_MOTOR_DIRECTION: |
232 | // Limit requested angular speed to 2 rps= 4 pi rads/sec | 269 | // Limit requested angular speed to 2 rps= 4 pi rads/sec |
233 | pValue.X = Math.Max(-12.56f, Math.Min(pValue.X, 12.56f)); | 270 | pValue.X = ClampInRange(-12.56f, pValue.X, 12.56f); |
234 | pValue.Y = Math.Max(-12.56f, Math.Min(pValue.Y, 12.56f)); | 271 | pValue.Y = ClampInRange(-12.56f, pValue.Y, 12.56f); |
235 | pValue.Z = Math.Max(-12.56f, Math.Min(pValue.Z, 12.56f)); | 272 | pValue.Z = ClampInRange(-12.56f, pValue.Z, 12.56f); |
236 | m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); | 273 | m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); |
237 | // m_angularMotorApply = 100; | 274 | m_angularMotor.Zero(); |
275 | m_angularMotor.SetTarget(m_angularMotorDirection); | ||
238 | break; | 276 | break; |
239 | case Vehicle.LINEAR_FRICTION_TIMESCALE: | 277 | case Vehicle.LINEAR_FRICTION_TIMESCALE: |
240 | m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); | 278 | m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); |
279 | m_linearMotor.FrictionTimescale = m_linearFrictionTimescale; | ||
241 | break; | 280 | break; |
242 | case Vehicle.LINEAR_MOTOR_DIRECTION: | 281 | case Vehicle.LINEAR_MOTOR_DIRECTION: |
243 | m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); | 282 | m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); |
244 | m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z); | 283 | m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z); |
284 | m_linearMotor.SetTarget(m_linearMotorDirection); | ||
245 | break; | 285 | break; |
246 | case Vehicle.LINEAR_MOTOR_OFFSET: | 286 | case Vehicle.LINEAR_MOTOR_OFFSET: |
247 | m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z); | 287 | m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z); |
@@ -281,7 +321,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
281 | } | 321 | } |
282 | } | 322 | } |
283 | 323 | ||
284 | internal void ProcessTypeChange(Vehicle pType) | 324 | public void ProcessTypeChange(Vehicle pType) |
285 | { | 325 | { |
286 | VDetailLog("{0},ProcessTypeChange,type={1}", Prim.LocalID, pType); | 326 | VDetailLog("{0},ProcessTypeChange,type={1}", Prim.LocalID, pType); |
287 | // Set Defaults For Type | 327 | // Set Defaults For Type |
@@ -303,7 +343,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
303 | m_VhoverEfficiency = 0; | 343 | m_VhoverEfficiency = 0; |
304 | m_VhoverTimescale = 0; | 344 | m_VhoverTimescale = 0; |
305 | m_VehicleBuoyancy = 0; | 345 | m_VehicleBuoyancy = 0; |
306 | 346 | ||
307 | m_linearDeflectionEfficiency = 1; | 347 | m_linearDeflectionEfficiency = 1; |
308 | m_linearDeflectionTimescale = 1; | 348 | m_linearDeflectionTimescale = 1; |
309 | 349 | ||
@@ -319,6 +359,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
319 | 359 | ||
320 | m_referenceFrame = Quaternion.Identity; | 360 | m_referenceFrame = Quaternion.Identity; |
321 | m_flags = (VehicleFlag)0; | 361 | m_flags = (VehicleFlag)0; |
362 | |||
322 | break; | 363 | break; |
323 | 364 | ||
324 | case Vehicle.TYPE_SLED: | 365 | case Vehicle.TYPE_SLED: |
@@ -351,10 +392,14 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
351 | m_bankingMix = 1; | 392 | m_bankingMix = 1; |
352 | 393 | ||
353 | m_referenceFrame = Quaternion.Identity; | 394 | m_referenceFrame = Quaternion.Identity; |
354 | m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP); | 395 | m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY |
355 | m_flags &= | 396 | | VehicleFlag.HOVER_TERRAIN_ONLY |
356 | ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | | 397 | | VehicleFlag.HOVER_GLOBAL_HEIGHT |
357 | VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); | 398 | | VehicleFlag.HOVER_UP_ONLY); |
399 | m_flags |= (VehicleFlag.NO_DEFLECTION_UP | ||
400 | | VehicleFlag.LIMIT_ROLL_ONLY | ||
401 | | VehicleFlag.LIMIT_MOTOR_UP); | ||
402 | |||
358 | break; | 403 | break; |
359 | case Vehicle.TYPE_CAR: | 404 | case Vehicle.TYPE_CAR: |
360 | m_linearMotorDirection = Vector3.Zero; | 405 | m_linearMotorDirection = Vector3.Zero; |
@@ -498,6 +543,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
498 | m_bankingEfficiency = 0; | 543 | m_bankingEfficiency = 0; |
499 | m_bankingMix = 0.7f; | 544 | m_bankingMix = 0.7f; |
500 | m_bankingTimescale = 5; | 545 | m_bankingTimescale = 5; |
546 | |||
501 | m_referenceFrame = Quaternion.Identity; | 547 | m_referenceFrame = Quaternion.Identity; |
502 | 548 | ||
503 | m_referenceFrame = Quaternion.Identity; | 549 | m_referenceFrame = Quaternion.Identity; |
@@ -510,152 +556,467 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
510 | | VehicleFlag.HOVER_GLOBAL_HEIGHT); | 556 | | VehicleFlag.HOVER_GLOBAL_HEIGHT); |
511 | break; | 557 | break; |
512 | } | 558 | } |
559 | |||
560 | // Update any physical parameters based on this type. | ||
561 | Refresh(); | ||
562 | |||
563 | m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale, | ||
564 | m_linearMotorDecayTimescale, m_linearFrictionTimescale, | ||
565 | 1f); | ||
566 | m_linearMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) | ||
567 | |||
568 | m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale, | ||
569 | m_angularMotorDecayTimescale, m_angularFrictionTimescale, | ||
570 | 1f); | ||
571 | m_angularMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) | ||
572 | |||
573 | /* Not implemented | ||
574 | m_verticalAttractionMotor = new BSVMotor("VerticalAttraction", m_verticalAttractionTimescale, | ||
575 | BSMotor.Infinite, BSMotor.InfiniteVector, | ||
576 | m_verticalAttractionEfficiency); | ||
577 | // Z goes away and we keep X and Y | ||
578 | m_verticalAttractionMotor.FrictionTimescale = new Vector3(BSMotor.Infinite, BSMotor.Infinite, 0.1f); | ||
579 | m_verticalAttractionMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) | ||
580 | */ | ||
581 | } | ||
582 | #endregion // Vehicle parameter setting | ||
583 | |||
584 | public void Refresh() | ||
585 | { | ||
586 | // If asking for a refresh, reset the physical parameters before the next simulation step. | ||
587 | PhysicsScene.PostTaintObject("BSDynamics.Refresh", Prim.LocalID, delegate() | ||
588 | { | ||
589 | SetPhysicalParameters(); | ||
590 | }); | ||
513 | } | 591 | } |
514 | 592 | ||
515 | // Some of the properties of this prim may have changed. | 593 | // Some of the properties of this prim may have changed. |
516 | // Do any updating needed for a vehicle | 594 | // Do any updating needed for a vehicle |
517 | public void Refresh() | 595 | private void SetPhysicalParameters() |
518 | { | 596 | { |
519 | if (IsActive) | 597 | if (IsActive) |
520 | { | 598 | { |
521 | // Friction effects are handled by this vehicle code | 599 | // Remember the mass so we don't have to fetch it every step |
522 | BulletSimAPI.SetFriction2(Prim.PhysBody.ptr, 0f); | 600 | m_vehicleMass = Prim.TotalMass; |
523 | BulletSimAPI.SetHitFraction2(Prim.PhysBody.ptr, 0f); | 601 | |
524 | 602 | // Friction affects are handled by this vehicle code | |
525 | // BulletSimAPI.SetAngularDamping2(Prim.PhysBody.ptr, 0.8f); | 603 | PhysicsScene.PE.SetFriction(Prim.PhysBody, BSParam.VehicleFriction); |
526 | 604 | PhysicsScene.PE.SetRestitution(Prim.PhysBody, BSParam.VehicleRestitution); | |
527 | VDetailLog("{0},BSDynamics.Refresh,zeroingFriction and adding damping", Prim.LocalID); | 605 | |
606 | // Moderate angular movement introduced by Bullet. | ||
607 | // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle. | ||
608 | // Maybe compute linear and angular factor and damping from params. | ||
609 | PhysicsScene.PE.SetAngularDamping(Prim.PhysBody, BSParam.VehicleAngularDamping); | ||
610 | PhysicsScene.PE.SetLinearFactor(Prim.PhysBody, BSParam.VehicleLinearFactor); | ||
611 | PhysicsScene.PE.SetAngularFactorV(Prim.PhysBody, BSParam.VehicleAngularFactor); | ||
612 | |||
613 | // Vehicles report collision events so we know when it's on the ground | ||
614 | PhysicsScene.PE.AddToCollisionFlags(Prim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS); | ||
615 | |||
616 | Prim.Inertia = PhysicsScene.PE.CalculateLocalInertia(Prim.PhysShape, m_vehicleMass); | ||
617 | PhysicsScene.PE.SetMassProps(Prim.PhysBody, m_vehicleMass, Prim.Inertia); | ||
618 | PhysicsScene.PE.UpdateInertiaTensor(Prim.PhysBody); | ||
619 | |||
620 | // Set the gravity for the vehicle depending on the buoyancy | ||
621 | // TODO: what should be done if prim and vehicle buoyancy differ? | ||
622 | m_VehicleGravity = Prim.ComputeGravity(m_VehicleBuoyancy); | ||
623 | // The actual vehicle gravity is set to zero in Bullet so we can do all the application of same. | ||
624 | PhysicsScene.PE.SetGravity(Prim.PhysBody, Vector3.Zero); | ||
625 | |||
626 | VDetailLog("{0},BSDynamics.SetPhysicalParameters,mass={1},inert={2},vehGrav={3},aDamp={4},frict={5},rest={6},lFact={7},aFact={8}", | ||
627 | Prim.LocalID, m_vehicleMass, Prim.Inertia, m_VehicleGravity, | ||
628 | BSParam.VehicleAngularDamping, BSParam.VehicleFriction, BSParam.VehicleRestitution, | ||
629 | BSParam.VehicleLinearFactor, BSParam.VehicleAngularFactor | ||
630 | ); | ||
631 | } | ||
632 | else | ||
633 | { | ||
634 | if (Prim.PhysBody.HasPhysicalBody) | ||
635 | PhysicsScene.PE.RemoveFromCollisionFlags(Prim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS); | ||
528 | } | 636 | } |
529 | } | 637 | } |
530 | 638 | ||
531 | public bool RemoveBodyDependencies(BSPhysObject prim) | 639 | public bool RemoveBodyDependencies(BSPhysObject prim) |
532 | { | 640 | { |
533 | // If active, we need to add our properties back when the body is rebuilt. | 641 | Refresh(); |
534 | return IsActive; | 642 | return IsActive; |
535 | } | 643 | } |
536 | 644 | ||
537 | public void RestoreBodyDependencies(BSPhysObject prim) | 645 | #region Known vehicle value functions |
646 | // Vehicle physical parameters that we buffer from constant getting and setting. | ||
647 | // The "m_known*" values are unknown until they are fetched and the m_knownHas flag is set. | ||
648 | // Changing is remembered and the parameter is stored back into the physics engine only if updated. | ||
649 | // This does two things: 1) saves continuious calls into unmanaged code, and | ||
650 | // 2) signals when a physics property update must happen back to the simulator | ||
651 | // to update values modified for the vehicle. | ||
652 | private int m_knownChanged; | ||
653 | private int m_knownHas; | ||
654 | private float m_knownTerrainHeight; | ||
655 | private float m_knownWaterLevel; | ||
656 | private Vector3 m_knownPosition; | ||
657 | private Vector3 m_knownVelocity; | ||
658 | private Vector3 m_knownForce; | ||
659 | private Vector3 m_knownForceImpulse; | ||
660 | private Quaternion m_knownOrientation; | ||
661 | private Vector3 m_knownRotationalVelocity; | ||
662 | private Vector3 m_knownRotationalForce; | ||
663 | private Vector3 m_knownRotationalImpulse; | ||
664 | private Vector3 m_knownForwardVelocity; // vehicle relative forward speed | ||
665 | |||
666 | private const int m_knownChangedPosition = 1 << 0; | ||
667 | private const int m_knownChangedVelocity = 1 << 1; | ||
668 | private const int m_knownChangedForce = 1 << 2; | ||
669 | private const int m_knownChangedForceImpulse = 1 << 3; | ||
670 | private const int m_knownChangedOrientation = 1 << 4; | ||
671 | private const int m_knownChangedRotationalVelocity = 1 << 5; | ||
672 | private const int m_knownChangedRotationalForce = 1 << 6; | ||
673 | private const int m_knownChangedRotationalImpulse = 1 << 7; | ||
674 | private const int m_knownChangedTerrainHeight = 1 << 8; | ||
675 | private const int m_knownChangedWaterLevel = 1 << 9; | ||
676 | private const int m_knownChangedForwardVelocity = 1 <<10; | ||
677 | |||
678 | public void ForgetKnownVehicleProperties() | ||
679 | { | ||
680 | m_knownHas = 0; | ||
681 | m_knownChanged = 0; | ||
682 | } | ||
683 | // Push all the changed values back into the physics engine | ||
684 | public void PushKnownChanged() | ||
685 | { | ||
686 | if (m_knownChanged != 0) | ||
687 | { | ||
688 | if ((m_knownChanged & m_knownChangedPosition) != 0) | ||
689 | Prim.ForcePosition = m_knownPosition; | ||
690 | |||
691 | if ((m_knownChanged & m_knownChangedOrientation) != 0) | ||
692 | Prim.ForceOrientation = m_knownOrientation; | ||
693 | |||
694 | if ((m_knownChanged & m_knownChangedVelocity) != 0) | ||
695 | { | ||
696 | Prim.ForceVelocity = m_knownVelocity; | ||
697 | // Fake out Bullet by making it think the velocity is the same as last time. | ||
698 | // Bullet does a bunch of smoothing for changing parameters. | ||
699 | // Since the vehicle is demanding this setting, we override Bullet's smoothing | ||
700 | // by telling Bullet the value was the same last time. | ||
701 | // PhysicsScene.PE.SetInterpolationLinearVelocity(Prim.PhysBody, m_knownVelocity); | ||
702 | } | ||
703 | |||
704 | if ((m_knownChanged & m_knownChangedForce) != 0) | ||
705 | Prim.AddForce((Vector3)m_knownForce, false /*pushForce*/, true /*inTaintTime*/); | ||
706 | |||
707 | if ((m_knownChanged & m_knownChangedForceImpulse) != 0) | ||
708 | Prim.AddForceImpulse((Vector3)m_knownForceImpulse, false /*pushforce*/, true /*inTaintTime*/); | ||
709 | |||
710 | if ((m_knownChanged & m_knownChangedRotationalVelocity) != 0) | ||
711 | { | ||
712 | Prim.ForceRotationalVelocity = m_knownRotationalVelocity; | ||
713 | // PhysicsScene.PE.SetInterpolationAngularVelocity(Prim.PhysBody, m_knownRotationalVelocity); | ||
714 | } | ||
715 | |||
716 | if ((m_knownChanged & m_knownChangedRotationalImpulse) != 0) | ||
717 | Prim.ApplyTorqueImpulse((Vector3)m_knownRotationalImpulse, true /*inTaintTime*/); | ||
718 | |||
719 | if ((m_knownChanged & m_knownChangedRotationalForce) != 0) | ||
720 | { | ||
721 | Prim.AddAngularForce((Vector3)m_knownRotationalForce, false /*pushForce*/, true /*inTaintTime*/); | ||
722 | } | ||
723 | |||
724 | // If we set one of the values (ie, the physics engine didn't do it) we must force | ||
725 | // an UpdateProperties event to send the changes up to the simulator. | ||
726 | PhysicsScene.PE.PushUpdate(Prim.PhysBody); | ||
727 | } | ||
728 | m_knownChanged = 0; | ||
729 | } | ||
730 | |||
731 | // Since the computation of terrain height can be a little involved, this routine | ||
732 | // is used to fetch the height only once for each vehicle simulation step. | ||
733 | Vector3 lastRememberedHeightPos; | ||
734 | private float GetTerrainHeight(Vector3 pos) | ||
538 | { | 735 | { |
539 | if (Prim.LocalID != prim.LocalID) | 736 | if ((m_knownHas & m_knownChangedTerrainHeight) == 0 || pos != lastRememberedHeightPos) |
540 | { | 737 | { |
541 | // The call should be on us by our prim. Error if not. | 738 | lastRememberedHeightPos = pos; |
542 | PhysicsScene.Logger.ErrorFormat("{0} RestoreBodyDependencies: called by not my prim. passedLocalID={1}, vehiclePrimLocalID={2}", | 739 | m_knownTerrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos); |
543 | LogHeader, prim.LocalID, Prim.LocalID); | 740 | m_knownHas |= m_knownChangedTerrainHeight; |
544 | return; | 741 | } |
742 | return m_knownTerrainHeight; | ||
743 | } | ||
744 | |||
745 | // Since the computation of water level can be a little involved, this routine | ||
746 | // is used ot fetch the level only once for each vehicle simulation step. | ||
747 | private float GetWaterLevel(Vector3 pos) | ||
748 | { | ||
749 | if ((m_knownHas & m_knownChangedWaterLevel) == 0) | ||
750 | { | ||
751 | m_knownWaterLevel = Prim.PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(pos); | ||
752 | m_knownHas |= m_knownChangedWaterLevel; | ||
753 | } | ||
754 | return (float)m_knownWaterLevel; | ||
755 | } | ||
756 | |||
757 | private Vector3 VehiclePosition | ||
758 | { | ||
759 | get | ||
760 | { | ||
761 | if ((m_knownHas & m_knownChangedPosition) == 0) | ||
762 | { | ||
763 | m_knownPosition = Prim.ForcePosition; | ||
764 | m_knownHas |= m_knownChangedPosition; | ||
765 | } | ||
766 | return m_knownPosition; | ||
767 | } | ||
768 | set | ||
769 | { | ||
770 | m_knownPosition = value; | ||
771 | m_knownChanged |= m_knownChangedPosition; | ||
772 | m_knownHas |= m_knownChangedPosition; | ||
545 | } | 773 | } |
546 | Refresh(); | ||
547 | } | 774 | } |
548 | 775 | ||
776 | private Quaternion VehicleOrientation | ||
777 | { | ||
778 | get | ||
779 | { | ||
780 | if ((m_knownHas & m_knownChangedOrientation) == 0) | ||
781 | { | ||
782 | m_knownOrientation = Prim.ForceOrientation; | ||
783 | m_knownHas |= m_knownChangedOrientation; | ||
784 | } | ||
785 | return m_knownOrientation; | ||
786 | } | ||
787 | set | ||
788 | { | ||
789 | m_knownOrientation = value; | ||
790 | m_knownChanged |= m_knownChangedOrientation; | ||
791 | m_knownHas |= m_knownChangedOrientation; | ||
792 | } | ||
793 | } | ||
794 | |||
795 | private Vector3 VehicleVelocity | ||
796 | { | ||
797 | get | ||
798 | { | ||
799 | if ((m_knownHas & m_knownChangedVelocity) == 0) | ||
800 | { | ||
801 | m_knownVelocity = Prim.ForceVelocity; | ||
802 | m_knownHas |= m_knownChangedVelocity; | ||
803 | } | ||
804 | return m_knownVelocity; | ||
805 | } | ||
806 | set | ||
807 | { | ||
808 | m_knownVelocity = value; | ||
809 | m_knownChanged |= m_knownChangedVelocity; | ||
810 | m_knownHas |= m_knownChangedVelocity; | ||
811 | } | ||
812 | } | ||
813 | |||
814 | private void VehicleAddForce(Vector3 pForce) | ||
815 | { | ||
816 | if ((m_knownHas & m_knownChangedForce) == 0) | ||
817 | { | ||
818 | m_knownForce = Vector3.Zero; | ||
819 | m_knownHas |= m_knownChangedForce; | ||
820 | } | ||
821 | m_knownForce += pForce; | ||
822 | m_knownChanged |= m_knownChangedForce; | ||
823 | } | ||
824 | |||
825 | private void VehicleAddForceImpulse(Vector3 pImpulse) | ||
826 | { | ||
827 | if ((m_knownHas & m_knownChangedForceImpulse) == 0) | ||
828 | { | ||
829 | m_knownForceImpulse = Vector3.Zero; | ||
830 | m_knownHas |= m_knownChangedForceImpulse; | ||
831 | } | ||
832 | m_knownForceImpulse += pImpulse; | ||
833 | m_knownChanged |= m_knownChangedForceImpulse; | ||
834 | } | ||
835 | |||
836 | private Vector3 VehicleRotationalVelocity | ||
837 | { | ||
838 | get | ||
839 | { | ||
840 | if ((m_knownHas & m_knownChangedRotationalVelocity) == 0) | ||
841 | { | ||
842 | m_knownRotationalVelocity = Prim.ForceRotationalVelocity; | ||
843 | m_knownHas |= m_knownChangedRotationalVelocity; | ||
844 | } | ||
845 | return (Vector3)m_knownRotationalVelocity; | ||
846 | } | ||
847 | set | ||
848 | { | ||
849 | m_knownRotationalVelocity = value; | ||
850 | m_knownChanged |= m_knownChangedRotationalVelocity; | ||
851 | m_knownHas |= m_knownChangedRotationalVelocity; | ||
852 | } | ||
853 | } | ||
854 | private void VehicleAddAngularForce(Vector3 aForce) | ||
855 | { | ||
856 | if ((m_knownHas & m_knownChangedRotationalForce) == 0) | ||
857 | { | ||
858 | m_knownRotationalForce = Vector3.Zero; | ||
859 | } | ||
860 | m_knownRotationalForce += aForce; | ||
861 | m_knownChanged |= m_knownChangedRotationalForce; | ||
862 | m_knownHas |= m_knownChangedRotationalForce; | ||
863 | } | ||
864 | private void VehicleAddRotationalImpulse(Vector3 pImpulse) | ||
865 | { | ||
866 | if ((m_knownHas & m_knownChangedRotationalImpulse) == 0) | ||
867 | { | ||
868 | m_knownRotationalImpulse = Vector3.Zero; | ||
869 | m_knownHas |= m_knownChangedRotationalImpulse; | ||
870 | } | ||
871 | m_knownRotationalImpulse += pImpulse; | ||
872 | m_knownChanged |= m_knownChangedRotationalImpulse; | ||
873 | } | ||
874 | |||
875 | // Vehicle relative forward velocity | ||
876 | private Vector3 VehicleForwardVelocity | ||
877 | { | ||
878 | get | ||
879 | { | ||
880 | if ((m_knownHas & m_knownChangedForwardVelocity) == 0) | ||
881 | { | ||
882 | m_knownForwardVelocity = VehicleVelocity * Quaternion.Inverse(Quaternion.Normalize(VehicleOrientation)); | ||
883 | m_knownHas |= m_knownChangedForwardVelocity; | ||
884 | } | ||
885 | return m_knownForwardVelocity; | ||
886 | } | ||
887 | } | ||
888 | private float VehicleForwardSpeed | ||
889 | { | ||
890 | get | ||
891 | { | ||
892 | return VehicleForwardVelocity.X; | ||
893 | } | ||
894 | } | ||
895 | |||
896 | #endregion // Known vehicle value functions | ||
897 | |||
549 | // One step of the vehicle properties for the next 'pTimestep' seconds. | 898 | // One step of the vehicle properties for the next 'pTimestep' seconds. |
550 | internal void Step(float pTimestep) | 899 | internal void Step(float pTimestep) |
551 | { | 900 | { |
552 | if (!IsActive) return; | 901 | if (!IsActive) return; |
553 | 902 | ||
554 | // DEBUG | 903 | ForgetKnownVehicleProperties(); |
555 | // Because Bullet does apply forces to the vehicle, our last computed | ||
556 | // linear and angular velocities are not what is happening now. | ||
557 | // Vector3 externalAngularVelocity = Prim.ForceRotationalVelocity - m_lastAngularVelocity; | ||
558 | // m_lastAngularVelocity += (externalAngularVelocity * 0.5f) * pTimestep; | ||
559 | // m_lastAngularVelocity = Prim.ForceRotationalVelocity; // DEBUG: account for what Bullet did last time | ||
560 | // m_lastLinearVelocityVector = Prim.ForceVelocity * Quaternion.Inverse(Prim.ForceOrientation); // DEBUG: | ||
561 | // END DEBUG | ||
562 | |||
563 | m_vehicleMass = Prim.Linkset.LinksetMass; | ||
564 | 904 | ||
565 | MoveLinear(pTimestep); | 905 | MoveLinear(pTimestep); |
566 | // Commented out for debug | ||
567 | MoveAngular(pTimestep); | 906 | MoveAngular(pTimestep); |
568 | // Prim.ApplyTorqueImpulse(-Prim.RotationalVelocity * m_vehicleMass, false); // DEBUG DEBUG | ||
569 | // Prim.ForceRotationalVelocity = -Prim.RotationalVelocity; // DEBUG DEBUG | ||
570 | 907 | ||
571 | LimitRotation(pTimestep); | 908 | LimitRotation(pTimestep); |
572 | 909 | ||
573 | // remember the position so next step we can limit absolute movement effects | 910 | // remember the position so next step we can limit absolute movement effects |
574 | m_lastPositionVector = Prim.ForcePosition; | 911 | m_lastPositionVector = VehiclePosition; |
575 | 912 | ||
576 | VDetailLog("{0},BSDynamics.Step,frict={1},grav={2},inertia={3},mass={4}", // DEBUG DEBUG | 913 | // If we forced the changing of some vehicle parameters, update the values and |
577 | Prim.LocalID, | 914 | // for the physics engine to note the changes so an UpdateProperties event will happen. |
578 | BulletSimAPI.GetFriction2(Prim.PhysBody.ptr), | 915 | PushKnownChanged(); |
579 | BulletSimAPI.GetGravity2(Prim.PhysBody.ptr), | 916 | |
580 | Prim.Inertia, | 917 | if (PhysicsScene.VehiclePhysicalLoggingEnabled) |
581 | m_vehicleMass | 918 | PhysicsScene.PE.DumpRigidBody(PhysicsScene.World, Prim.PhysBody); |
582 | ); | 919 | |
583 | VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}", | 920 | VDetailLog("{0},BSDynamics.Step,done,pos={1}, force={2},velocity={3},angvel={4}", |
584 | Prim.LocalID, Prim.ForcePosition, Prim.Force, Prim.ForceVelocity, Prim.RotationalVelocity); | 921 | Prim.LocalID, VehiclePosition, m_knownForce, VehicleVelocity, VehicleRotationalVelocity); |
585 | }// end Step | 922 | } |
586 | 923 | ||
587 | // Apply the effect of the linear motor. | 924 | // Called after the simulation step |
588 | // Also does hover and float. | 925 | internal void PostStep(float pTimestep) |
926 | { | ||
927 | if (!IsActive) return; | ||
928 | |||
929 | if (PhysicsScene.VehiclePhysicalLoggingEnabled) | ||
930 | PhysicsScene.PE.DumpRigidBody(PhysicsScene.World, Prim.PhysBody); | ||
931 | } | ||
932 | |||
933 | // Apply the effect of the linear motor and other linear motions (like hover and float). | ||
589 | private void MoveLinear(float pTimestep) | 934 | private void MoveLinear(float pTimestep) |
590 | { | 935 | { |
591 | // m_linearMotorDirection is the target direction we are moving relative to the vehicle coordinates | 936 | ComputeLinearVelocity(pTimestep); |
592 | // m_lastLinearVelocityVector is the current speed we are moving in that direction | ||
593 | if (m_linearMotorDirection.LengthSquared() > 0.001f) | ||
594 | { | ||
595 | Vector3 origDir = m_linearMotorDirection; // DEBUG | ||
596 | Vector3 origVel = m_lastLinearVelocityVector; // DEBUG | ||
597 | // DEBUG: the vehicle velocity rotated to be relative to vehicle coordinates for comparison | ||
598 | Vector3 vehicleVelocity = Prim.ForceVelocity * Quaternion.Inverse(Prim.ForceOrientation); // DEBUG | ||
599 | 937 | ||
600 | // Add (desiredVelocity - lastAppliedVelocity) / howLongItShouldTakeToComplete | 938 | ComputeLinearTerrainHeightCorrection(pTimestep); |
601 | Vector3 addAmount = (m_linearMotorDirection - m_lastLinearVelocityVector)/(m_linearMotorTimescale) * pTimestep; | ||
602 | m_lastLinearVelocityVector += addAmount; | ||
603 | 939 | ||
604 | float decayFactor = (1.0f / m_linearMotorDecayTimescale) * pTimestep; | 940 | ComputeLinearHover(pTimestep); |
605 | m_linearMotorDirection *= (1f - decayFactor); | ||
606 | 941 | ||
607 | // Rotate new object velocity from vehicle relative to world coordinates | 942 | ComputeLinearBlockingEndPoint(pTimestep); |
608 | m_newVelocity = m_lastLinearVelocityVector * Prim.ForceOrientation; | ||
609 | 943 | ||
610 | // Apply friction for next time | 944 | ComputeLinearMotorUp(pTimestep); |
611 | Vector3 frictionFactor = (Vector3.One / m_linearFrictionTimescale) * pTimestep; | ||
612 | m_lastLinearVelocityVector *= (Vector3.One - frictionFactor); | ||
613 | 945 | ||
614 | VDetailLog("{0},MoveLinear,nonZero,origlmDir={1},origlvVel={2},vehVel={3},add={4},decay={5},frict={6},lmDir={7},lvVec={8},newVel={9}", | 946 | ApplyGravity(pTimestep); |
615 | Prim.LocalID, origDir, origVel, vehicleVelocity, addAmount, decayFactor, frictionFactor, | 947 | |
616 | m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity); | 948 | // If not changing some axis, reduce out velocity |
617 | } | 949 | if ((m_flags & (VehicleFlag.NO_X | VehicleFlag.NO_Y | VehicleFlag.NO_Z)) != 0) |
618 | else | ||
619 | { | 950 | { |
620 | // if what remains of direction is very small, zero it. | 951 | Vector3 vel = VehicleVelocity; |
621 | m_linearMotorDirection = Vector3.Zero; | 952 | if ((m_flags & (VehicleFlag.NO_X)) != 0) |
622 | m_lastLinearVelocityVector = Vector3.Zero; | 953 | vel.X = 0; |
623 | m_newVelocity = Vector3.Zero; | 954 | if ((m_flags & (VehicleFlag.NO_Y)) != 0) |
955 | vel.Y = 0; | ||
956 | if ((m_flags & (VehicleFlag.NO_Z)) != 0) | ||
957 | vel.Z = 0; | ||
958 | VehicleVelocity = vel; | ||
959 | } | ||
624 | 960 | ||
625 | VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID); | 961 | // ================================================================== |
962 | // Clamp high or low velocities | ||
963 | float newVelocityLengthSq = VehicleVelocity.LengthSquared(); | ||
964 | if (newVelocityLengthSq > BSParam.VehicleMaxLinearVelocitySquared) | ||
965 | { | ||
966 | Vector3 origVelW = VehicleVelocity; // DEBUG DEBUG | ||
967 | VehicleVelocity /= VehicleVelocity.Length(); | ||
968 | VehicleVelocity *= BSParam.VehicleMaxLinearVelocity; | ||
969 | VDetailLog("{0}, MoveLinear,clampMax,origVelW={1},lenSq={2},maxVelSq={3},,newVelW={4}", | ||
970 | Prim.LocalID, origVelW, newVelocityLengthSq, BSParam.VehicleMaxLinearVelocitySquared, VehicleVelocity); | ||
626 | } | 971 | } |
972 | else if (newVelocityLengthSq < 0.001f) | ||
973 | VehicleVelocity = Vector3.Zero; | ||
627 | 974 | ||
628 | // m_newVelocity is velocity computed from linear motor in world coordinates | 975 | VDetailLog("{0}, MoveLinear,done,isColl={1},newVel={2}", Prim.LocalID, Prim.IsColliding, VehicleVelocity ); |
629 | 976 | ||
630 | // Gravity and Buoyancy | 977 | } // end MoveLinear() |
631 | // There is some gravity, make a gravity force vector that is applied after object velocity. | ||
632 | // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; | ||
633 | Vector3 grav = Prim.PhysicsScene.DefaultGravity * (1f - m_VehicleBuoyancy); | ||
634 | 978 | ||
635 | /* | 979 | public void ComputeLinearVelocity(float pTimestep) |
636 | * RA: Not sure why one would do this unless we are hoping external forces are doing gravity, ... | 980 | { |
637 | // Preserve the current Z velocity | 981 | // Step the motor from the current value. Get the correction needed this step. |
638 | Vector3 vel_now = m_prim.Velocity; | 982 | Vector3 origVelW = VehicleVelocity; // DEBUG |
639 | m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity | 983 | Vector3 currentVelV = VehicleVelocity * Quaternion.Inverse(VehicleOrientation); |
640 | */ | 984 | Vector3 linearMotorCorrectionV = m_linearMotor.Step(pTimestep, currentVelV); |
985 | |||
986 | // Motor is vehicle coordinates. Rotate it to world coordinates | ||
987 | Vector3 linearMotorVelocityW = linearMotorCorrectionV * VehicleOrientation; | ||
988 | |||
989 | // If we're a ground vehicle, don't add any upward Z movement | ||
990 | if ((m_flags & VehicleFlag.LIMIT_MOTOR_UP) != 0) | ||
991 | { | ||
992 | if (linearMotorVelocityW.Z > 0f) | ||
993 | linearMotorVelocityW.Z = 0f; | ||
994 | } | ||
995 | |||
996 | // Add this correction to the velocity to make it faster/slower. | ||
997 | VehicleVelocity += linearMotorVelocityW; | ||
641 | 998 | ||
642 | Vector3 pos = Prim.ForcePosition; | 999 | VDetailLog("{0}, MoveLinear,velocity,origVelW={1},velV={2},correctV={3},correctW={4},newVelW={5}", |
643 | // Vector3 accel = new Vector3(-(m_dir.X - m_lastLinearVelocityVector.X / 0.1f), -(m_dir.Y - m_lastLinearVelocityVector.Y / 0.1f), m_dir.Z - m_lastLinearVelocityVector.Z / 0.1f); | 1000 | Prim.LocalID, origVelW, currentVelV, linearMotorCorrectionV, linearMotorVelocityW, VehicleVelocity); |
1001 | } | ||
644 | 1002 | ||
1003 | public void ComputeLinearTerrainHeightCorrection(float pTimestep) | ||
1004 | { | ||
645 | // If below the terrain, move us above the ground a little. | 1005 | // If below the terrain, move us above the ground a little. |
646 | float terrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos); | 1006 | // TODO: Consider taking the rotated size of the object or possibly casting a ray. |
647 | // Taking the rotated size doesn't work here because m_prim.Size is the size of the root prim and not the linkset. | 1007 | if (VehiclePosition.Z < GetTerrainHeight(VehiclePosition)) |
648 | // TODO: Add a m_prim.LinkSet.Size similar to m_prim.LinkSet.Mass. | ||
649 | // Vector3 rotatedSize = m_prim.Size * m_prim.ForceOrientation; | ||
650 | // if (rotatedSize.Z < terrainHeight) | ||
651 | if (pos.Z < terrainHeight) | ||
652 | { | 1008 | { |
653 | pos.Z = terrainHeight + 2; | 1009 | // Force position because applying force won't get the vehicle through the terrain |
654 | Prim.ForcePosition = pos; | 1010 | Vector3 newPosition = VehiclePosition; |
655 | VDetailLog("{0},MoveLinear,terrainHeight,terrainHeight={1},pos={2}", Prim.LocalID, terrainHeight, pos); | 1011 | newPosition.Z = GetTerrainHeight(VehiclePosition) + 1f; |
1012 | VehiclePosition = newPosition; | ||
1013 | VDetailLog("{0}, MoveLinear,terrainHeight,terrainHeight={1},pos={2}", | ||
1014 | Prim.LocalID, GetTerrainHeight(VehiclePosition), VehiclePosition); | ||
656 | } | 1015 | } |
1016 | } | ||
657 | 1017 | ||
658 | // Check if hovering | 1018 | public void ComputeLinearHover(float pTimestep) |
1019 | { | ||
659 | // m_VhoverEfficiency: 0=bouncy, 1=totally damped | 1020 | // m_VhoverEfficiency: 0=bouncy, 1=totally damped |
660 | // m_VhoverTimescale: time to achieve height | 1021 | // m_VhoverTimescale: time to achieve height |
661 | if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) | 1022 | if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) |
@@ -663,11 +1024,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
663 | // We should hover, get the target height | 1024 | // We should hover, get the target height |
664 | if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0) | 1025 | if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0) |
665 | { | 1026 | { |
666 | m_VhoverTargetHeight = Prim.PhysicsScene.GetWaterLevelAtXYZ(pos) + m_VhoverHeight; | 1027 | m_VhoverTargetHeight = GetWaterLevel(VehiclePosition) + m_VhoverHeight; |
667 | } | 1028 | } |
668 | if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0) | 1029 | if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0) |
669 | { | 1030 | { |
670 | m_VhoverTargetHeight = terrainHeight + m_VhoverHeight; | 1031 | m_VhoverTargetHeight = GetTerrainHeight(VehiclePosition) + m_VhoverHeight; |
671 | } | 1032 | } |
672 | if ((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0) | 1033 | if ((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0) |
673 | { | 1034 | { |
@@ -677,45 +1038,63 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
677 | if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0) | 1038 | if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0) |
678 | { | 1039 | { |
679 | // If body is already heigher, use its height as target height | 1040 | // If body is already heigher, use its height as target height |
680 | if (pos.Z > m_VhoverTargetHeight) | 1041 | if (VehiclePosition.Z > m_VhoverTargetHeight) |
681 | m_VhoverTargetHeight = pos.Z; | 1042 | m_VhoverTargetHeight = VehiclePosition.Z; |
682 | } | 1043 | } |
1044 | |||
683 | if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) | 1045 | if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) |
684 | { | 1046 | { |
685 | if (Math.Abs(pos.Z - m_VhoverTargetHeight) > 0.2f) | 1047 | if (Math.Abs(VehiclePosition.Z - m_VhoverTargetHeight) > 0.2f) |
686 | { | 1048 | { |
1049 | Vector3 pos = VehiclePosition; | ||
687 | pos.Z = m_VhoverTargetHeight; | 1050 | pos.Z = m_VhoverTargetHeight; |
688 | Prim.ForcePosition = pos; | 1051 | VehiclePosition = pos; |
1052 | |||
1053 | VDetailLog("{0}, MoveLinear,hover,pos={1},lockHoverHeight", Prim.LocalID, pos); | ||
689 | } | 1054 | } |
690 | } | 1055 | } |
691 | else | 1056 | else |
692 | { | 1057 | { |
693 | float verticalError = pos.Z - m_VhoverTargetHeight; | 1058 | // Error is positive if below the target and negative if above. |
694 | // RA: where does the 50 come from? | 1059 | Vector3 hpos = VehiclePosition; |
695 | float verticalCorrectionVelocity = pTimestep * ((verticalError * 50.0f) / m_VhoverTimescale); | 1060 | float verticalError = m_VhoverTargetHeight - hpos.Z; |
696 | // Replace Vertical speed with correction figure if significant | 1061 | float verticalCorrection = verticalError / m_VhoverTimescale; |
697 | if (Math.Abs(verticalError) > 0.01f) | 1062 | verticalCorrection *= m_VhoverEfficiency; |
698 | { | 1063 | |
699 | m_newVelocity.Z += verticalCorrectionVelocity; | 1064 | hpos.Z += verticalCorrection; |
700 | //KF: m_VhoverEfficiency is not yet implemented | 1065 | VehiclePosition = hpos; |
701 | } | 1066 | |
702 | else if (verticalError < -0.01) | 1067 | // Since we are hovering, we need to do the opposite of falling -- get rid of world Z |
703 | { | 1068 | Vector3 vel = VehicleVelocity; |
704 | m_newVelocity.Z -= verticalCorrectionVelocity; | 1069 | vel.Z = 0f; |
705 | } | 1070 | VehicleVelocity = vel; |
706 | else | 1071 | |
707 | { | 1072 | /* |
708 | m_newVelocity.Z = 0f; | 1073 | float verticalCorrectionVelocity = verticalError / m_VhoverTimescale; |
709 | } | 1074 | Vector3 verticalCorrection = new Vector3(0f, 0f, verticalCorrectionVelocity); |
1075 | verticalCorrection *= m_vehicleMass; | ||
1076 | |||
1077 | // TODO: implement m_VhoverEfficiency correctly | ||
1078 | VehicleAddForceImpulse(verticalCorrection); | ||
1079 | */ | ||
1080 | |||
1081 | VDetailLog("{0}, MoveLinear,hover,pos={1},eff={2},hoverTS={3},height={4},target={5},err={6},corr={7}", | ||
1082 | Prim.LocalID, VehiclePosition, m_VhoverEfficiency, | ||
1083 | m_VhoverTimescale, m_VhoverHeight, m_VhoverTargetHeight, | ||
1084 | verticalError, verticalCorrection); | ||
710 | } | 1085 | } |
711 | 1086 | ||
712 | VDetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}", Prim.LocalID, pos, m_newVelocity, m_VhoverHeight, m_VhoverTargetHeight); | ||
713 | } | 1087 | } |
1088 | } | ||
714 | 1089 | ||
1090 | public bool ComputeLinearBlockingEndPoint(float pTimestep) | ||
1091 | { | ||
1092 | bool changed = false; | ||
1093 | |||
1094 | Vector3 pos = VehiclePosition; | ||
715 | Vector3 posChange = pos - m_lastPositionVector; | 1095 | Vector3 posChange = pos - m_lastPositionVector; |
716 | if (m_BlockingEndPoint != Vector3.Zero) | 1096 | if (m_BlockingEndPoint != Vector3.Zero) |
717 | { | 1097 | { |
718 | bool changed = false; | ||
719 | if (pos.X >= (m_BlockingEndPoint.X - (float)1)) | 1098 | if (pos.X >= (m_BlockingEndPoint.X - (float)1)) |
720 | { | 1099 | { |
721 | pos.X -= posChange.X + 1; | 1100 | pos.X -= posChange.X + 1; |
@@ -743,233 +1122,119 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
743 | } | 1122 | } |
744 | if (changed) | 1123 | if (changed) |
745 | { | 1124 | { |
746 | Prim.ForcePosition = pos; | 1125 | VehiclePosition = pos; |
747 | VDetailLog("{0},MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}", | 1126 | VDetailLog("{0}, MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}", |
748 | Prim.LocalID, m_BlockingEndPoint, posChange, pos); | 1127 | Prim.LocalID, m_BlockingEndPoint, posChange, pos); |
749 | } | 1128 | } |
750 | } | 1129 | } |
1130 | return changed; | ||
1131 | } | ||
751 | 1132 | ||
752 | #region downForce | 1133 | // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags : |
753 | Vector3 downForce = Vector3.Zero; | 1134 | // Prevent ground vehicles from motoring into the sky. This flag has a subtle effect when |
754 | 1135 | // used with conjunction with banking: the strength of the banking will decay when the | |
1136 | // vehicle no longer experiences collisions. The decay timescale is the same as | ||
1137 | // VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering | ||
1138 | // when they are in mid jump. | ||
1139 | // TODO: this code is wrong. Also, what should it do for boats (height from water)? | ||
1140 | // This is just using the ground and a general collision check. Should really be using | ||
1141 | // a downward raycast to find what is below. | ||
1142 | public void ComputeLinearMotorUp(float pTimestep) | ||
1143 | { | ||
755 | if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) | 1144 | if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) |
756 | { | 1145 | { |
757 | // If the vehicle is motoring into the sky, get it going back down. | 1146 | // This code tries to decide if the object is not on the ground and then pushing down |
758 | // Is this an angular force or both linear and angular?? | 1147 | /* |
759 | float distanceAboveGround = pos.Z - terrainHeight; | 1148 | float targetHeight = Type == Vehicle.TYPE_BOAT ? GetWaterLevel(VehiclePosition) : GetTerrainHeight(VehiclePosition); |
760 | if (distanceAboveGround > 2f) | 1149 | distanceAboveGround = VehiclePosition.Z - targetHeight; |
1150 | // Not colliding if the vehicle is off the ground | ||
1151 | if (!Prim.IsColliding) | ||
761 | { | 1152 | { |
762 | // downForce = new Vector3(0, 0, (-distanceAboveGround / m_bankingTimescale) * pTimestep); | ||
763 | // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale); | 1153 | // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale); |
764 | downForce = new Vector3(0, 0, -distanceAboveGround); | 1154 | VehicleVelocity += new Vector3(0, 0, -distanceAboveGround); |
765 | } | 1155 | } |
766 | // TODO: this calculation is all wrong. From the description at | 1156 | // TODO: this calculation is wrong. From the description at |
767 | // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce | 1157 | // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce |
768 | // has a decay factor. This says this force should | 1158 | // has a decay factor. This says this force should |
769 | // be computed with a motor. | 1159 | // be computed with a motor. |
770 | VDetailLog("{0},MoveLinear,limitMotorUp,distAbove={1},downForce={2}", | 1160 | // TODO: add interaction with banking. |
771 | Prim.LocalID, distanceAboveGround, downForce); | 1161 | VDetailLog("{0}, MoveLinear,limitMotorUp,distAbove={1},colliding={2},ret={3}", |
772 | } | 1162 | Prim.LocalID, distanceAboveGround, Prim.IsColliding, ret); |
773 | #endregion // downForce | 1163 | */ |
774 | 1164 | ||
775 | // If not changing some axis, reduce out velocity | 1165 | // Another approach is to measure if we're going up. If going up and not colliding, |
776 | if ((m_flags & (VehicleFlag.NO_X)) != 0) | 1166 | // the vehicle is in the air. Fix that by pushing down. |
777 | m_newVelocity.X = 0; | 1167 | if (!Prim.IsColliding && VehicleVelocity.Z > 0.1) |
778 | if ((m_flags & (VehicleFlag.NO_Y)) != 0) | 1168 | { |
779 | m_newVelocity.Y = 0; | 1169 | // Get rid of any of the velocity vector that is pushing us up. |
780 | if ((m_flags & (VehicleFlag.NO_Z)) != 0) | 1170 | float upVelocity = VehicleVelocity.Z; |
781 | m_newVelocity.Z = 0; | 1171 | VehicleVelocity += new Vector3(0, 0, -upVelocity); |
782 | 1172 | ||
783 | // Clamp REALLY high or low velocities | 1173 | /* |
784 | if (m_newVelocity.LengthSquared() > 1e6f) | 1174 | // If we're pointed up into the air, we should nose down |
785 | { | 1175 | Vector3 pointingDirection = Vector3.UnitX * VehicleOrientation; |
786 | m_newVelocity /= m_newVelocity.Length(); | 1176 | // The rotation around the Y axis is pitch up or down |
787 | m_newVelocity *= 1000f; | 1177 | if (pointingDirection.Y > 0.01f) |
1178 | { | ||
1179 | float angularCorrectionForce = -(float)Math.Asin(pointingDirection.Y); | ||
1180 | Vector3 angularCorrectionVector = new Vector3(0f, angularCorrectionForce, 0f); | ||
1181 | // Rotate into world coordinates and apply to vehicle | ||
1182 | angularCorrectionVector *= VehicleOrientation; | ||
1183 | VehicleAddAngularForce(angularCorrectionVector); | ||
1184 | VDetailLog("{0}, MoveLinear,limitMotorUp,newVel={1},pntDir={2},corrFrc={3},aCorr={4}", | ||
1185 | Prim.LocalID, VehicleVelocity, pointingDirection, angularCorrectionForce, angularCorrectionVector); | ||
1186 | } | ||
1187 | */ | ||
1188 | VDetailLog("{0}, MoveLinear,limitMotorUp,collide={1},upVel={2},newVel={3}", | ||
1189 | Prim.LocalID, Prim.IsColliding, upVelocity, VehicleVelocity); | ||
1190 | } | ||
788 | } | 1191 | } |
789 | else if (m_newVelocity.LengthSquared() < 1e-6f) | 1192 | } |
790 | m_newVelocity = Vector3.Zero; | ||
791 | 1193 | ||
792 | // Stuff new linear velocity into the vehicle | 1194 | private void ApplyGravity(float pTimeStep) |
793 | Prim.ForceVelocity = m_newVelocity; | 1195 | { |
794 | // Prim.ApplyForceImpulse((m_newVelocity - Prim.Velocity) * m_vehicleMass, false); // DEBUG DEBUG | 1196 | Vector3 appliedGravity = m_VehicleGravity * m_vehicleMass; |
795 | 1197 | ||
796 | Vector3 totalDownForce = downForce + grav; | 1198 | // Hack to reduce downward force if the vehicle is probably sitting on the ground |
797 | if (totalDownForce != Vector3.Zero) | 1199 | if (Prim.IsColliding && IsGroundVehicle) |
798 | { | 1200 | appliedGravity *= BSParam.VehicleGroundGravityFudge; |
799 | Prim.AddForce(totalDownForce * m_vehicleMass, false); | ||
800 | // Prim.ApplyForceImpulse(totalDownForce * m_vehicleMass, false); | ||
801 | } | ||
802 | 1201 | ||
803 | VDetailLog("{0},MoveLinear,done,lmDir={1},lmVel={2},newVel={3},primVel={4},totalDown={5}", | 1202 | VehicleAddForce(appliedGravity); |
804 | Prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity, Prim.Velocity, totalDownForce); | ||
805 | 1203 | ||
806 | } // end MoveLinear() | 1204 | VDetailLog("{0}, MoveLinear,applyGravity,vehGrav={1},collid={2},fudge={3},mass={4},appliedForce={3}", |
1205 | Prim.LocalID, m_VehicleGravity, | ||
1206 | Prim.IsColliding, BSParam.VehicleGroundGravityFudge, m_vehicleMass, appliedGravity); | ||
1207 | } | ||
807 | 1208 | ||
808 | // ======================================================================= | 1209 | // ======================================================================= |
1210 | // ======================================================================= | ||
809 | // Apply the effect of the angular motor. | 1211 | // Apply the effect of the angular motor. |
1212 | // The 'contribution' is how much angular correction velocity each function wants. | ||
1213 | // All the contributions are added together and the resulting velocity is | ||
1214 | // set directly on the vehicle. | ||
810 | private void MoveAngular(float pTimestep) | 1215 | private void MoveAngular(float pTimestep) |
811 | { | 1216 | { |
812 | // m_angularMotorDirection // angular velocity requested by LSL motor | 1217 | ComputeAngularTurning(pTimestep); |
813 | // m_angularMotorApply // application frame counter | ||
814 | // m_angularMotorVelocity // current angular motor velocity (ramps up and down) | ||
815 | // m_angularMotorTimescale // motor angular velocity ramp up rate | ||
816 | // m_angularMotorDecayTimescale // motor angular velocity decay rate | ||
817 | // m_angularFrictionTimescale // body angular velocity decay rate | ||
818 | // m_lastAngularVelocity // what was last applied to body | ||
819 | |||
820 | if (m_angularMotorDirection.LengthSquared() > 0.0001) | ||
821 | { | ||
822 | Vector3 origVel = m_angularMotorVelocity; | ||
823 | Vector3 origDir = m_angularMotorDirection; | ||
824 | |||
825 | // new velocity += error / ( time to get there / step interval) | ||
826 | // requested direction - current vehicle direction | ||
827 | m_angularMotorVelocity += (m_angularMotorDirection - m_angularMotorVelocity) / (m_angularMotorTimescale / pTimestep); | ||
828 | // decay requested direction | ||
829 | m_angularMotorDirection *= (1.0f - (pTimestep * 1.0f/m_angularMotorDecayTimescale)); | ||
830 | 1218 | ||
831 | VDetailLog("{0},MoveAngular,angularMotorApply,angTScale={1},timeStep={2},origvel={3},origDir={4},vel={5}", | 1219 | ComputeAngularVerticalAttraction(); |
832 | Prim.LocalID, m_angularMotorTimescale, pTimestep, origVel, origDir, m_angularMotorVelocity); | ||
833 | } | ||
834 | else | ||
835 | { | ||
836 | m_angularMotorVelocity = Vector3.Zero; | ||
837 | } | ||
838 | 1220 | ||
839 | #region Vertical attactor | 1221 | ComputeAngularDeflection(); |
840 | 1222 | ||
841 | Vector3 vertattr = Vector3.Zero; | 1223 | ComputeAngularBanking(); |
842 | Vector3 deflection = Vector3.Zero; | ||
843 | Vector3 banking = Vector3.Zero; | ||
844 | 1224 | ||
845 | // If vertical attaction timescale is reasonable and we applied an angular force last time... | 1225 | // ================================================================== |
846 | if (m_verticalAttractionTimescale < 300 && m_lastAngularVelocity != Vector3.Zero) | 1226 | if (VehicleRotationalVelocity.ApproxEquals(Vector3.Zero, 0.0001f)) |
847 | { | 1227 | { |
848 | float VAservo = pTimestep * 0.2f / m_verticalAttractionTimescale; | 1228 | // The vehicle is not adding anything angular wise. |
849 | if (Prim.IsColliding) | 1229 | VehicleRotationalVelocity = Vector3.Zero; |
850 | VAservo = pTimestep * 0.05f / (m_verticalAttractionTimescale); | 1230 | VDetailLog("{0}, MoveAngular,done,zero", Prim.LocalID); |
851 | |||
852 | VAservo *= (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency); | ||
853 | |||
854 | // Create a vector of the vehicle "up" in world coordinates | ||
855 | Vector3 verticalError = Vector3.UnitZ * Prim.ForceOrientation; | ||
856 | // verticalError.X and .Y are the World error amounts. They are 0 when there is no | ||
857 | // error (Vehicle Body is 'vertical'), and .Z will be 1. As the body leans to its | ||
858 | // side |.X| will increase to 1 and .Z fall to 0. As body inverts |.X| will fall | ||
859 | // and .Z will go // negative. Similar for tilt and |.Y|. .X and .Y must be | ||
860 | // modulated to prevent a stable inverted body. | ||
861 | |||
862 | // Error is 0 (no error) to +/- 2 (max error) | ||
863 | if (verticalError.Z < 0.0f) | ||
864 | { | ||
865 | verticalError.X = 2.0f - verticalError.X; | ||
866 | verticalError.Y = 2.0f - verticalError.Y; | ||
867 | } | ||
868 | // scale it by VAservo (timestep and timescale) | ||
869 | verticalError = verticalError * VAservo; | ||
870 | |||
871 | // As the body rotates around the X axis, then verticalError.Y increases; Rotated around Y | ||
872 | // then .X increases, so change Body angular velocity X based on Y, and Y based on X. | ||
873 | // Z is not changed. | ||
874 | vertattr.X = verticalError.Y; | ||
875 | vertattr.Y = - verticalError.X; | ||
876 | vertattr.Z = 0f; | ||
877 | |||
878 | // scaling appears better usingsquare-law | ||
879 | Vector3 angularVelocity = Prim.ForceRotationalVelocity; | ||
880 | float bounce = 1.0f - (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency); | ||
881 | vertattr.X += bounce * angularVelocity.X; | ||
882 | vertattr.Y += bounce * angularVelocity.Y; | ||
883 | |||
884 | VDetailLog("{0},MoveAngular,verticalAttraction,VAservo={1},effic={2},verticalError={3},bounce={4},vertattr={5}", | ||
885 | Prim.LocalID, VAservo, m_verticalAttractionEfficiency, verticalError, bounce, vertattr); | ||
886 | |||
887 | } | ||
888 | #endregion // Vertical attactor | ||
889 | |||
890 | #region Deflection | ||
891 | |||
892 | if (m_angularDeflectionEfficiency != 0) | ||
893 | { | ||
894 | // Compute a scaled vector that points in the preferred axis (X direction) | ||
895 | Vector3 scaledDefaultDirection = | ||
896 | new Vector3((pTimestep * 10 * (m_angularDeflectionEfficiency / m_angularDeflectionTimescale)), 0, 0); | ||
897 | // Adding the current vehicle orientation and reference frame displaces the orientation to the frame. | ||
898 | // Rotate the scaled default axix relative to the actual vehicle direction giving where it should point. | ||
899 | Vector3 preferredAxisOfMotion = scaledDefaultDirection * Quaternion.Add(Prim.ForceOrientation, m_referenceFrame); | ||
900 | |||
901 | // Scale by efficiency and timescale | ||
902 | deflection = (preferredAxisOfMotion * (m_angularDeflectionEfficiency) / m_angularDeflectionTimescale) * pTimestep; | ||
903 | |||
904 | VDetailLog("{0},MoveAngular,Deflection,perfAxis={1},deflection={2}", | ||
905 | Prim.LocalID, preferredAxisOfMotion, deflection); | ||
906 | // This deflection computation is not correct. | ||
907 | deflection = Vector3.Zero; | ||
908 | } | 1231 | } |
909 | 1232 | else | |
910 | #endregion | ||
911 | |||
912 | #region Banking | ||
913 | |||
914 | if (m_bankingEfficiency != 0) | ||
915 | { | 1233 | { |
916 | Vector3 dir = Vector3.One * Prim.ForceOrientation; | 1234 | VDetailLog("{0}, MoveAngular,done,nonZero,angVel={1}", Prim.LocalID, VehicleRotationalVelocity); |
917 | float mult = (m_bankingMix*m_bankingMix)*-1*(m_bankingMix < 0 ? -1 : 1); | ||
918 | //Changes which way it banks in and out of turns | ||
919 | |||
920 | //Use the square of the efficiency, as it looks much more how SL banking works | ||
921 | float effSquared = (m_bankingEfficiency*m_bankingEfficiency); | ||
922 | if (m_bankingEfficiency < 0) | ||
923 | effSquared *= -1; //Keep the negative! | ||
924 | |||
925 | float mix = Math.Abs(m_bankingMix); | ||
926 | if (m_angularMotorVelocity.X == 0) | ||
927 | { | ||
928 | /*if (!parent.Orientation.ApproxEquals(this.m_referenceFrame, 0.25f)) | ||
929 | { | ||
930 | Vector3 axisAngle; | ||
931 | float angle; | ||
932 | parent.Orientation.GetAxisAngle(out axisAngle, out angle); | ||
933 | Vector3 rotatedVel = parent.Velocity * parent.Orientation; | ||
934 | if ((rotatedVel.X < 0 && axisAngle.Y > 0) || (rotatedVel.X > 0 && axisAngle.Y < 0)) | ||
935 | m_angularMotorVelocity.X += (effSquared * (mult * mix)) * (1f) * 10; | ||
936 | else | ||
937 | m_angularMotorVelocity.X += (effSquared * (mult * mix)) * (-1f) * 10; | ||
938 | }*/ | ||
939 | } | ||
940 | else | ||
941 | banking.Z += (effSquared*(mult*mix))*(m_angularMotorVelocity.X) * 4; | ||
942 | if (!Prim.IsColliding && Math.Abs(m_angularMotorVelocity.X) > mix) | ||
943 | //If they are colliding, we probably shouldn't shove the prim around... probably | ||
944 | { | ||
945 | float angVelZ = m_angularMotorVelocity.X*-1; | ||
946 | /*if(angVelZ > mix) | ||
947 | angVelZ = mix; | ||
948 | else if(angVelZ < -mix) | ||
949 | angVelZ = -mix;*/ | ||
950 | //This controls how fast and how far the banking occurs | ||
951 | Vector3 bankingRot = new Vector3(angVelZ*(effSquared*mult), 0, 0); | ||
952 | if (bankingRot.X > 3) | ||
953 | bankingRot.X = 3; | ||
954 | else if (bankingRot.X < -3) | ||
955 | bankingRot.X = -3; | ||
956 | bankingRot *= Prim.ForceOrientation; | ||
957 | banking += bankingRot; | ||
958 | } | ||
959 | m_angularMotorVelocity.X *= m_bankingEfficiency == 1 ? 0.0f : 1 - m_bankingEfficiency; | ||
960 | VDetailLog("{0},MoveAngular,Banking,bEff={1},angMotVel={2},banking={3}", | ||
961 | Prim.LocalID, m_bankingEfficiency, m_angularMotorVelocity, banking); | ||
962 | } | 1235 | } |
963 | 1236 | ||
964 | #endregion | 1237 | // ================================================================== |
965 | |||
966 | m_lastVertAttractor = vertattr; | ||
967 | |||
968 | // Sum velocities | ||
969 | m_lastAngularVelocity = m_angularMotorVelocity + vertattr + banking + deflection; | ||
970 | |||
971 | #region Linear Motor Offset | ||
972 | |||
973 | //Offset section | 1238 | //Offset section |
974 | if (m_linearMotorOffset != Vector3.Zero) | 1239 | if (m_linearMotorOffset != Vector3.Zero) |
975 | { | 1240 | { |
@@ -985,8 +1250,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
985 | // | 1250 | // |
986 | // The torque created is the linear velocity crossed with the offset | 1251 | // The torque created is the linear velocity crossed with the offset |
987 | 1252 | ||
988 | // NOTE: this computation does should be in the linear section | 1253 | // TODO: this computation should be in the linear section |
989 | // because there we know the impulse being applied. | 1254 | // because that is where we know the impulse being applied. |
990 | Vector3 torqueFromOffset = Vector3.Zero; | 1255 | Vector3 torqueFromOffset = Vector3.Zero; |
991 | // torqueFromOffset = Vector3.Cross(m_linearMotorOffset, appliedImpulse); | 1256 | // torqueFromOffset = Vector3.Cross(m_linearMotorOffset, appliedImpulse); |
992 | if (float.IsNaN(torqueFromOffset.X)) | 1257 | if (float.IsNaN(torqueFromOffset.X)) |
@@ -995,47 +1260,258 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
995 | torqueFromOffset.Y = 0; | 1260 | torqueFromOffset.Y = 0; |
996 | if (float.IsNaN(torqueFromOffset.Z)) | 1261 | if (float.IsNaN(torqueFromOffset.Z)) |
997 | torqueFromOffset.Z = 0; | 1262 | torqueFromOffset.Z = 0; |
998 | torqueFromOffset *= m_vehicleMass; | 1263 | |
999 | Prim.ApplyTorqueImpulse(torqueFromOffset, true); | 1264 | VehicleAddAngularForce(torqueFromOffset * m_vehicleMass); |
1000 | VDetailLog("{0},BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset); | 1265 | VDetailLog("{0}, BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset); |
1001 | } | 1266 | } |
1002 | 1267 | ||
1003 | #endregion | 1268 | } |
1269 | |||
1270 | private void ComputeAngularTurning(float pTimestep) | ||
1271 | { | ||
1272 | // The user wants this many radians per second angular change? | ||
1273 | Vector3 currentAngularV = VehicleRotationalVelocity * Quaternion.Inverse(VehicleOrientation); | ||
1274 | Vector3 angularMotorContributionV = m_angularMotor.Step(pTimestep, currentAngularV); | ||
1275 | |||
1276 | // ================================================================== | ||
1277 | // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags : | ||
1278 | // This flag prevents linear deflection parallel to world z-axis. This is useful | ||
1279 | // for preventing ground vehicles with large linear deflection, like bumper cars, | ||
1280 | // from climbing their linear deflection into the sky. | ||
1281 | // That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement | ||
1282 | // TODO: This is here because this is where ODE put it but documentation says it | ||
1283 | // is a linear effect. Where should this check go? | ||
1284 | //if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) | ||
1285 | // { | ||
1286 | // angularMotorContributionV.X = 0f; | ||
1287 | // angularMotorContributionV.Y = 0f; | ||
1288 | // } | ||
1289 | |||
1290 | VehicleRotationalVelocity += angularMotorContributionV * VehicleOrientation; | ||
1291 | VDetailLog("{0}, MoveAngular,angularTurning,angularMotorContrib={1}", Prim.LocalID, angularMotorContributionV); | ||
1292 | } | ||
1293 | |||
1294 | // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial: | ||
1295 | // Some vehicles, like boats, should always keep their up-side up. This can be done by | ||
1296 | // enabling the "vertical attractor" behavior that springs the vehicle's local z-axis to | ||
1297 | // the world z-axis (a.k.a. "up"). To take advantage of this feature you would set the | ||
1298 | // VEHICLE_VERTICAL_ATTRACTION_TIMESCALE to control the period of the spring frequency, | ||
1299 | // and then set the VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY to control the damping. An | ||
1300 | // efficiency of 0.0 will cause the spring to wobble around its equilibrium, while an | ||
1301 | // efficiency of 1.0 will cause the spring to reach its equilibrium with exponential decay. | ||
1302 | public void ComputeAngularVerticalAttraction() | ||
1303 | { | ||
1004 | 1304 | ||
1005 | if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) | 1305 | // If vertical attaction timescale is reasonable |
1306 | if (enableAngularVerticalAttraction && m_verticalAttractionTimescale < m_verticalAttractionCutoff) | ||
1006 | { | 1307 | { |
1007 | m_lastAngularVelocity.X = 0; | 1308 | // Possible solution derived from a discussion at: |
1008 | m_lastAngularVelocity.Y = 0; | 1309 | // http://stackoverflow.com/questions/14939657/computing-vector-from-quaternion-works-computing-quaternion-from-vector-does-no |
1009 | VDetailLog("{0},MoveAngular,noDeflectionUp,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity); | 1310 | |
1311 | // Create a rotation that is only the vehicle's rotation around Z | ||
1312 | Vector3 currentEuler = Vector3.Zero; | ||
1313 | VehicleOrientation.GetEulerAngles(out currentEuler.X, out currentEuler.Y, out currentEuler.Z); | ||
1314 | Quaternion justZOrientation = Quaternion.CreateFromAxisAngle(Vector3.UnitZ, currentEuler.Z); | ||
1315 | |||
1316 | // Create the axis that is perpendicular to the up vector and the rotated up vector. | ||
1317 | Vector3 differenceAxis = Vector3.Cross(Vector3.UnitZ * justZOrientation, Vector3.UnitZ * VehicleOrientation); | ||
1318 | // Compute the angle between those to vectors. | ||
1319 | double differenceAngle = Math.Acos((double)Vector3.Dot(Vector3.UnitZ, Vector3.Normalize(Vector3.UnitZ * VehicleOrientation))); | ||
1320 | // 'differenceAngle' is the angle to rotate and 'differenceAxis' is the plane to rotate in to get the vehicle vertical | ||
1321 | |||
1322 | // Reduce the change by the time period it is to change in. Timestep is handled when velocity is applied. | ||
1323 | // TODO: add 'efficiency'. | ||
1324 | differenceAngle /= m_verticalAttractionTimescale; | ||
1325 | |||
1326 | // Create the quaterian representing the correction angle | ||
1327 | Quaternion correctionRotation = Quaternion.CreateFromAxisAngle(differenceAxis, (float)differenceAngle); | ||
1328 | |||
1329 | // Turn that quaternion into Euler values to make it into velocities to apply. | ||
1330 | Vector3 vertContributionV = Vector3.Zero; | ||
1331 | correctionRotation.GetEulerAngles(out vertContributionV.X, out vertContributionV.Y, out vertContributionV.Z); | ||
1332 | vertContributionV *= -1f; | ||
1333 | |||
1334 | VehicleRotationalVelocity += vertContributionV; | ||
1335 | |||
1336 | VDetailLog("{0}, MoveAngular,verticalAttraction,diffAxis={1},diffAng={2},corrRot={3},contrib={4}", | ||
1337 | Prim.LocalID, | ||
1338 | differenceAxis, | ||
1339 | differenceAngle, | ||
1340 | correctionRotation, | ||
1341 | vertContributionV); | ||
1342 | |||
1343 | // =================================================================== | ||
1344 | /* | ||
1345 | Vector3 vertContributionV = Vector3.Zero; | ||
1346 | Vector3 origRotVelW = VehicleRotationalVelocity; // DEBUG DEBUG | ||
1347 | |||
1348 | // Take a vector pointing up and convert it from world to vehicle relative coords. | ||
1349 | Vector3 verticalError = Vector3.Normalize(Vector3.UnitZ * VehicleOrientation); | ||
1350 | |||
1351 | // If vertical attraction correction is needed, the vector that was pointing up (UnitZ) | ||
1352 | // is now: | ||
1353 | // leaning to one side: rotated around the X axis with the Y value going | ||
1354 | // from zero (nearly straight up) to one (completely to the side)) or | ||
1355 | // leaning front-to-back: rotated around the Y axis with the value of X being between | ||
1356 | // zero and one. | ||
1357 | // The value of Z is how far the rotation is off with 1 meaning none and 0 being 90 degrees. | ||
1358 | |||
1359 | // Y error means needed rotation around X axis and visa versa. | ||
1360 | // Since the error goes from zero to one, the asin is the corresponding angle. | ||
1361 | vertContributionV.X = (float)Math.Asin(verticalError.Y); | ||
1362 | // (Tilt forward (positive X) needs to tilt back (rotate negative) around Y axis.) | ||
1363 | vertContributionV.Y = -(float)Math.Asin(verticalError.X); | ||
1364 | |||
1365 | // If verticalError.Z is negative, the vehicle is upside down. Add additional push. | ||
1366 | if (verticalError.Z < 0f) | ||
1367 | { | ||
1368 | vertContributionV.X += Math.Sign(vertContributionV.X) * PIOverFour; | ||
1369 | // vertContribution.Y -= PIOverFour; | ||
1370 | } | ||
1371 | |||
1372 | // 'vertContrbution' is now the necessary angular correction to correct tilt in one second. | ||
1373 | // Correction happens over a number of seconds. | ||
1374 | Vector3 unscaledContribVerticalErrorV = vertContributionV; // DEBUG DEBUG | ||
1375 | |||
1376 | // The correction happens over the user's time period | ||
1377 | vertContributionV /= m_verticalAttractionTimescale; | ||
1378 | |||
1379 | // Rotate the vehicle rotation to the world coordinates. | ||
1380 | VehicleRotationalVelocity += (vertContributionV * VehicleOrientation); | ||
1381 | |||
1382 | VDetailLog("{0}, MoveAngular,verticalAttraction,,origRotVW={1},vertError={2},unscaledV={3},eff={4},ts={5},vertContribV={6}", | ||
1383 | Prim.LocalID, origRotVelW, verticalError, unscaledContribVerticalErrorV, | ||
1384 | m_verticalAttractionEfficiency, m_verticalAttractionTimescale, vertContributionV); | ||
1385 | */ | ||
1010 | } | 1386 | } |
1387 | } | ||
1388 | |||
1389 | // Angular correction to correct the direction the vehicle is pointing to be | ||
1390 | // the direction is should want to be pointing. | ||
1391 | // The vehicle is moving in some direction and correct its orientation to it is pointing | ||
1392 | // in that direction. | ||
1393 | // TODO: implement reference frame. | ||
1394 | public void ComputeAngularDeflection() | ||
1395 | { | ||
1396 | // Since angularMotorUp and angularDeflection are computed independently, they will calculate | ||
1397 | // approximately the same X or Y correction. When added together (when contributions are combined) | ||
1398 | // this creates an over-correction and then wabbling as the target is overshot. | ||
1399 | // TODO: rethink how the different correction computations inter-relate. | ||
1011 | 1400 | ||
1012 | if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f)) | 1401 | if (enableAngularDeflection && m_angularDeflectionEfficiency != 0 && VehicleForwardSpeed > 0.2) |
1013 | { | 1402 | { |
1014 | m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero. | 1403 | Vector3 deflectContributionV = Vector3.Zero; |
1015 | Prim.ZeroAngularMotion(true); | 1404 | |
1016 | VDetailLog("{0},MoveAngular,zeroAngularMotion,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity); | 1405 | // The direction the vehicle is moving |
1406 | Vector3 movingDirection = VehicleVelocity; | ||
1407 | movingDirection.Normalize(); | ||
1408 | |||
1409 | // If the vehicle is going backward, it is still pointing forward | ||
1410 | movingDirection *= Math.Sign(VehicleForwardSpeed); | ||
1411 | |||
1412 | // The direction the vehicle is pointing | ||
1413 | Vector3 pointingDirection = Vector3.UnitX * VehicleOrientation; | ||
1414 | pointingDirection.Normalize(); | ||
1415 | |||
1416 | // The difference between what is and what should be. | ||
1417 | Vector3 deflectionError = movingDirection - pointingDirection; | ||
1418 | |||
1419 | // Don't try to correct very large errors (not our job) | ||
1420 | // if (Math.Abs(deflectionError.X) > PIOverFour) deflectionError.X = PIOverTwo * Math.Sign(deflectionError.X); | ||
1421 | // if (Math.Abs(deflectionError.Y) > PIOverFour) deflectionError.Y = PIOverTwo * Math.Sign(deflectionError.Y); | ||
1422 | // if (Math.Abs(deflectionError.Z) > PIOverFour) deflectionError.Z = PIOverTwo * Math.Sign(deflectionError.Z); | ||
1423 | if (Math.Abs(deflectionError.X) > PIOverFour) deflectionError.X = 0f; | ||
1424 | if (Math.Abs(deflectionError.Y) > PIOverFour) deflectionError.Y = 0f; | ||
1425 | if (Math.Abs(deflectionError.Z) > PIOverFour) deflectionError.Z = 0f; | ||
1426 | |||
1427 | // ret = m_angularDeflectionCorrectionMotor(1f, deflectionError); | ||
1428 | |||
1429 | // Scale the correction by recovery timescale and efficiency | ||
1430 | deflectContributionV = (-deflectionError) * m_angularDeflectionEfficiency; | ||
1431 | deflectContributionV /= m_angularDeflectionTimescale; | ||
1432 | |||
1433 | VehicleRotationalVelocity += deflectContributionV * VehicleOrientation; | ||
1434 | |||
1435 | VDetailLog("{0}, MoveAngular,Deflection,movingDir={1},pointingDir={2},deflectError={3},ret={4}", | ||
1436 | Prim.LocalID, movingDirection, pointingDirection, deflectionError, deflectContributionV); | ||
1437 | VDetailLog("{0}, MoveAngular,Deflection,fwdSpd={1},defEff={2},defTS={3}", | ||
1438 | Prim.LocalID, VehicleForwardSpeed, m_angularDeflectionEfficiency, m_angularDeflectionTimescale); | ||
1017 | } | 1439 | } |
1018 | else | 1440 | } |
1441 | |||
1442 | // Angular change to rotate the vehicle around the Z axis when the vehicle | ||
1443 | // is tipped around the X axis. | ||
1444 | // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial: | ||
1445 | // The vertical attractor feature must be enabled in order for the banking behavior to | ||
1446 | // function. The way banking works is this: a rotation around the vehicle's roll-axis will | ||
1447 | // produce a angular velocity around the yaw-axis, causing the vehicle to turn. The magnitude | ||
1448 | // of the yaw effect will be proportional to the | ||
1449 | // VEHICLE_BANKING_EFFICIENCY, the angle of the roll rotation, and sometimes the vehicle's | ||
1450 | // velocity along its preferred axis of motion. | ||
1451 | // The VEHICLE_BANKING_EFFICIENCY can vary between -1 and +1. When it is positive then any | ||
1452 | // positive rotation (by the right-hand rule) about the roll-axis will effect a | ||
1453 | // (negative) torque around the yaw-axis, making it turn to the right--that is the | ||
1454 | // vehicle will lean into the turn, which is how real airplanes and motorcycle's work. | ||
1455 | // Negating the banking coefficient will make it so that the vehicle leans to the | ||
1456 | // outside of the turn (not very "physical" but might allow interesting vehicles so why not?). | ||
1457 | // The VEHICLE_BANKING_MIX is a fake (i.e. non-physical) parameter that is useful for making | ||
1458 | // banking vehicles do what you want rather than what the laws of physics allow. | ||
1459 | // For example, consider a real motorcycle...it must be moving forward in order for | ||
1460 | // it to turn while banking, however video-game motorcycles are often configured | ||
1461 | // to turn in place when at a dead stop--because they are often easier to control | ||
1462 | // that way using the limited interface of the keyboard or game controller. The | ||
1463 | // VEHICLE_BANKING_MIX enables combinations of both realistic and non-realistic | ||
1464 | // banking by functioning as a slider between a banking that is correspondingly | ||
1465 | // totally static (0.0) and totally dynamic (1.0). By "static" we mean that the | ||
1466 | // banking effect depends only on the vehicle's rotation about its roll-axis compared | ||
1467 | // to "dynamic" where the banking is also proportional to its velocity along its | ||
1468 | // roll-axis. Finding the best value of the "mixture" will probably require trial and error. | ||
1469 | // The time it takes for the banking behavior to defeat a preexisting angular velocity about the | ||
1470 | // world z-axis is determined by the VEHICLE_BANKING_TIMESCALE. So if you want the vehicle to | ||
1471 | // bank quickly then give it a banking timescale of about a second or less, otherwise you can | ||
1472 | // make a sluggish vehicle by giving it a timescale of several seconds. | ||
1473 | public void ComputeAngularBanking() | ||
1474 | { | ||
1475 | if (enableAngularBanking && m_bankingEfficiency != 0 && m_verticalAttractionTimescale < m_verticalAttractionCutoff) | ||
1019 | { | 1476 | { |
1020 | // Apply to the body. | 1477 | Vector3 bankingContributionV = Vector3.Zero; |
1021 | // The above calculates the absolute angular velocity needed. Angular velocity is massless. | 1478 | |
1022 | // Since we are stuffing the angular velocity directly into the object, the computed | 1479 | // Rotate a UnitZ vector (pointing up) to how the vehicle is oriented. |
1023 | // velocity needs to be scaled by the timestep. | 1480 | // As the vehicle rolls to the right or left, the Y value will increase from |
1024 | Vector3 applyAngularForce = ((m_lastAngularVelocity * pTimestep) - Prim.ForceRotationalVelocity); | 1481 | // zero (straight up) to 1 or -1 (full tilt right or left) |
1025 | Prim.ForceRotationalVelocity = applyAngularForce; | 1482 | Vector3 rollComponents = Vector3.UnitZ * VehicleOrientation; |
1026 | 1483 | ||
1027 | // Decay the angular movement for next time | 1484 | // Figure out the yaw value for this much roll. |
1028 | Vector3 decayamount = (Vector3.One / m_angularFrictionTimescale) * pTimestep; | 1485 | float yawAngle = m_angularMotorDirection.X * m_bankingEfficiency; |
1029 | m_lastAngularVelocity *= Vector3.One - decayamount; | 1486 | // actual error = static turn error + dynamic turn error |
1030 | 1487 | float mixedYawAngle =(yawAngle * (1f - m_bankingMix)) + ((yawAngle * m_bankingMix) * VehicleForwardSpeed); | |
1031 | VDetailLog("{0},MoveAngular,done,newRotVel={1},decay={2},lastAngular={3}", | 1488 | |
1032 | Prim.LocalID, applyAngularForce, decayamount, m_lastAngularVelocity); | 1489 | // TODO: the banking effect should not go to infinity but what to limit it to? |
1490 | // And what should happen when this is being added to a user defined yaw that is already PI*4? | ||
1491 | mixedYawAngle = ClampInRange(-12, mixedYawAngle, 12); | ||
1492 | |||
1493 | // Build the force vector to change rotation from what it is to what it should be | ||
1494 | bankingContributionV.Z = -mixedYawAngle; | ||
1495 | |||
1496 | // Don't do it all at once. Fudge because 1 second is too fast with most user defined roll as PI*4. | ||
1497 | bankingContributionV /= m_bankingTimescale * BSParam.VehicleAngularBankingTimescaleFudge; | ||
1498 | |||
1499 | //VehicleRotationalVelocity += bankingContributionV * VehicleOrientation; | ||
1500 | VehicleRotationalVelocity += bankingContributionV; | ||
1501 | |||
1502 | |||
1503 | VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},rollComp={3},yAng={4},mYAng={5},ret={6}", | ||
1504 | Prim.LocalID, rollComponents, VehicleForwardSpeed, rollComponents, yawAngle, mixedYawAngle, bankingContributionV); | ||
1033 | } | 1505 | } |
1034 | } //end MoveAngular | 1506 | } |
1035 | 1507 | ||
1508 | // This is from previous instantiations of XXXDynamics.cs. | ||
1509 | // Applies roll reference frame. | ||
1510 | // TODO: is this the right way to separate the code to do this operation? | ||
1511 | // Should this be in MoveAngular()? | ||
1036 | internal void LimitRotation(float timestep) | 1512 | internal void LimitRotation(float timestep) |
1037 | { | 1513 | { |
1038 | Quaternion rotq = Prim.ForceOrientation; | 1514 | Quaternion rotq = VehicleOrientation; |
1039 | Quaternion m_rot = rotq; | 1515 | Quaternion m_rot = rotq; |
1040 | if (m_RollreferenceFrame != Quaternion.Identity) | 1516 | if (m_RollreferenceFrame != Quaternion.Identity) |
1041 | { | 1517 | { |
@@ -1063,12 +1539,18 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1063 | } | 1539 | } |
1064 | if (rotq != m_rot) | 1540 | if (rotq != m_rot) |
1065 | { | 1541 | { |
1066 | Prim.ForceOrientation = m_rot; | 1542 | VehicleOrientation = m_rot; |
1067 | VDetailLog("{0},LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot); | 1543 | VDetailLog("{0}, LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot); |
1068 | } | 1544 | } |
1069 | 1545 | ||
1070 | } | 1546 | } |
1071 | 1547 | ||
1548 | private float ClampInRange(float low, float val, float high) | ||
1549 | { | ||
1550 | return Math.Max(low, Math.Min(val, high)); | ||
1551 | // return Utils.Clamp(val, low, high); | ||
1552 | } | ||
1553 | |||
1072 | // Invoke the detailed logger and output something if it's enabled. | 1554 | // Invoke the detailed logger and output something if it's enabled. |
1073 | private void VDetailLog(string msg, params Object[] args) | 1555 | private void VDetailLog(string msg, params Object[] args) |
1074 | { | 1556 | { |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs index 0df4310..4ece1eb 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs | |||
@@ -32,6 +32,15 @@ using OMV = OpenMetaverse; | |||
32 | 32 | ||
33 | namespace OpenSim.Region.Physics.BulletSPlugin | 33 | namespace OpenSim.Region.Physics.BulletSPlugin |
34 | { | 34 | { |
35 | |||
36 | // A BSPrim can get individual information about its linkedness attached | ||
37 | // to it through an instance of a subclass of LinksetInfo. | ||
38 | // Each type of linkset will define the information needed for its type. | ||
39 | public abstract class BSLinksetInfo | ||
40 | { | ||
41 | public virtual void Clear() { } | ||
42 | } | ||
43 | |||
35 | public abstract class BSLinkset | 44 | public abstract class BSLinkset |
36 | { | 45 | { |
37 | // private static string LogHeader = "[BULLETSIM LINKSET]"; | 46 | // private static string LogHeader = "[BULLETSIM LINKSET]"; |
@@ -43,11 +52,11 @@ public abstract class BSLinkset | |||
43 | Manual = 2 // linkset tied together manually (code moves all the pieces) | 52 | Manual = 2 // linkset tied together manually (code moves all the pieces) |
44 | } | 53 | } |
45 | // Create the correct type of linkset for this child | 54 | // Create the correct type of linkset for this child |
46 | public static BSLinkset Factory(BSScene physScene, BSPhysObject parent) | 55 | public static BSLinkset Factory(BSScene physScene, BSPrimLinkable parent) |
47 | { | 56 | { |
48 | BSLinkset ret = null; | 57 | BSLinkset ret = null; |
49 | 58 | ||
50 | switch ((int)physScene.Params.linksetImplementation) | 59 | switch ((int)BSParam.LinksetImplementation) |
51 | { | 60 | { |
52 | case (int)LinksetImplementation.Constraint: | 61 | case (int)LinksetImplementation.Constraint: |
53 | ret = new BSLinksetConstraints(physScene, parent); | 62 | ret = new BSLinksetConstraints(physScene, parent); |
@@ -62,10 +71,14 @@ public abstract class BSLinkset | |||
62 | ret = new BSLinksetCompound(physScene, parent); | 71 | ret = new BSLinksetCompound(physScene, parent); |
63 | break; | 72 | break; |
64 | } | 73 | } |
74 | if (ret == null) | ||
75 | { | ||
76 | physScene.Logger.ErrorFormat("[BULLETSIM LINKSET] Factory could not create linkset. Parent name={1}, ID={2}", parent.Name, parent.LocalID); | ||
77 | } | ||
65 | return ret; | 78 | return ret; |
66 | } | 79 | } |
67 | 80 | ||
68 | public BSPhysObject LinksetRoot { get; protected set; } | 81 | public BSPrimLinkable LinksetRoot { get; protected set; } |
69 | 82 | ||
70 | public BSScene PhysicsScene { get; private set; } | 83 | public BSScene PhysicsScene { get; private set; } |
71 | 84 | ||
@@ -73,7 +86,7 @@ public abstract class BSLinkset | |||
73 | public int LinksetID { get; private set; } | 86 | public int LinksetID { get; private set; } |
74 | 87 | ||
75 | // The children under the root in this linkset. | 88 | // The children under the root in this linkset. |
76 | protected HashSet<BSPhysObject> m_children; | 89 | protected HashSet<BSPrimLinkable> m_children; |
77 | 90 | ||
78 | // We lock the diddling of linkset classes to prevent any badness. | 91 | // We lock the diddling of linkset classes to prevent any badness. |
79 | // This locks the modification of the instances of this class. Changes | 92 | // This locks the modification of the instances of this class. Changes |
@@ -82,27 +95,13 @@ public abstract class BSLinkset | |||
82 | 95 | ||
83 | // Some linksets have a preferred physical shape. | 96 | // Some linksets have a preferred physical shape. |
84 | // Returns SHAPE_UNKNOWN if there is no preference. Causes the correct shape to be selected. | 97 | // Returns SHAPE_UNKNOWN if there is no preference. Causes the correct shape to be selected. |
85 | public virtual BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor) | 98 | public virtual BSPhysicsShapeType PreferredPhysicalShape(BSPrimLinkable requestor) |
86 | { | 99 | { |
87 | return BSPhysicsShapeType.SHAPE_UNKNOWN; | 100 | return BSPhysicsShapeType.SHAPE_UNKNOWN; |
88 | } | 101 | } |
89 | 102 | ||
90 | // Linksets move around the children so the linkset might need to compute the child position | ||
91 | public virtual OMV.Vector3 Position(BSPhysObject member) | ||
92 | { return member.RawPosition; } | ||
93 | public virtual OMV.Quaternion Orientation(BSPhysObject member) | ||
94 | { return member.RawOrientation; } | ||
95 | // TODO: does this need to be done for Velocity and RotationalVelocityy? | ||
96 | |||
97 | // We keep the prim's mass in the linkset structure since it could be dependent on other prims | 103 | // We keep the prim's mass in the linkset structure since it could be dependent on other prims |
98 | protected float m_mass; | 104 | public float LinksetMass { get; protected set; } |
99 | public float LinksetMass | ||
100 | { | ||
101 | get | ||
102 | { | ||
103 | return m_mass; | ||
104 | } | ||
105 | } | ||
106 | 105 | ||
107 | public virtual bool LinksetIsColliding { get { return false; } } | 106 | public virtual bool LinksetIsColliding { get { return false; } } |
108 | 107 | ||
@@ -116,7 +115,7 @@ public abstract class BSLinkset | |||
116 | get { return ComputeLinksetGeometricCenter(); } | 115 | get { return ComputeLinksetGeometricCenter(); } |
117 | } | 116 | } |
118 | 117 | ||
119 | protected void Initialize(BSScene scene, BSPhysObject parent) | 118 | protected BSLinkset(BSScene scene, BSPrimLinkable parent) |
120 | { | 119 | { |
121 | // A simple linkset of one (no children) | 120 | // A simple linkset of one (no children) |
122 | LinksetID = m_nextLinksetID++; | 121 | LinksetID = m_nextLinksetID++; |
@@ -125,22 +124,25 @@ public abstract class BSLinkset | |||
125 | m_nextLinksetID = 1; | 124 | m_nextLinksetID = 1; |
126 | PhysicsScene = scene; | 125 | PhysicsScene = scene; |
127 | LinksetRoot = parent; | 126 | LinksetRoot = parent; |
128 | m_children = new HashSet<BSPhysObject>(); | 127 | m_children = new HashSet<BSPrimLinkable>(); |
129 | m_mass = parent.RawMass; | 128 | LinksetMass = parent.RawMass; |
129 | Rebuilding = false; | ||
130 | |||
131 | parent.ClearDisplacement(); | ||
130 | } | 132 | } |
131 | 133 | ||
132 | // Link to a linkset where the child knows the parent. | 134 | // Link to a linkset where the child knows the parent. |
133 | // Parent changing should not happen so do some sanity checking. | 135 | // Parent changing should not happen so do some sanity checking. |
134 | // We return the parent's linkset so the child can track its membership. | 136 | // We return the parent's linkset so the child can track its membership. |
135 | // Called at runtime. | 137 | // Called at runtime. |
136 | public BSLinkset AddMeToLinkset(BSPhysObject child) | 138 | public BSLinkset AddMeToLinkset(BSPrimLinkable child) |
137 | { | 139 | { |
138 | lock (m_linksetActivityLock) | 140 | lock (m_linksetActivityLock) |
139 | { | 141 | { |
140 | // Don't add the root to its own linkset | 142 | // Don't add the root to its own linkset |
141 | if (!IsRoot(child)) | 143 | if (!IsRoot(child)) |
142 | AddChildToLinkset(child); | 144 | AddChildToLinkset(child); |
143 | m_mass = ComputeLinksetMass(); | 145 | LinksetMass = ComputeLinksetMass(); |
144 | } | 146 | } |
145 | return this; | 147 | return this; |
146 | } | 148 | } |
@@ -149,7 +151,7 @@ public abstract class BSLinkset | |||
149 | // Returns a new linkset for the child which is a linkset of one (just the | 151 | // Returns a new linkset for the child which is a linkset of one (just the |
150 | // orphened child). | 152 | // orphened child). |
151 | // Called at runtime. | 153 | // Called at runtime. |
152 | public BSLinkset RemoveMeFromLinkset(BSPhysObject child) | 154 | public BSLinkset RemoveMeFromLinkset(BSPrimLinkable child) |
153 | { | 155 | { |
154 | lock (m_linksetActivityLock) | 156 | lock (m_linksetActivityLock) |
155 | { | 157 | { |
@@ -159,7 +161,7 @@ public abstract class BSLinkset | |||
159 | return this; | 161 | return this; |
160 | } | 162 | } |
161 | RemoveChildFromLinkset(child); | 163 | RemoveChildFromLinkset(child); |
162 | m_mass = ComputeLinksetMass(); | 164 | LinksetMass = ComputeLinksetMass(); |
163 | } | 165 | } |
164 | 166 | ||
165 | // The child is down to a linkset of just itself | 167 | // The child is down to a linkset of just itself |
@@ -167,7 +169,7 @@ public abstract class BSLinkset | |||
167 | } | 169 | } |
168 | 170 | ||
169 | // Return 'true' if the passed object is the root object of this linkset | 171 | // Return 'true' if the passed object is the root object of this linkset |
170 | public bool IsRoot(BSPhysObject requestor) | 172 | public bool IsRoot(BSPrimLinkable requestor) |
171 | { | 173 | { |
172 | return (requestor.LocalID == LinksetRoot.LocalID); | 174 | return (requestor.LocalID == LinksetRoot.LocalID); |
173 | } | 175 | } |
@@ -178,14 +180,14 @@ public abstract class BSLinkset | |||
178 | public bool HasAnyChildren { get { return (m_children.Count > 0); } } | 180 | public bool HasAnyChildren { get { return (m_children.Count > 0); } } |
179 | 181 | ||
180 | // Return 'true' if this child is in this linkset | 182 | // Return 'true' if this child is in this linkset |
181 | public bool HasChild(BSPhysObject child) | 183 | public bool HasChild(BSPrimLinkable child) |
182 | { | 184 | { |
183 | bool ret = false; | 185 | bool ret = false; |
184 | lock (m_linksetActivityLock) | 186 | lock (m_linksetActivityLock) |
185 | { | 187 | { |
186 | ret = m_children.Contains(child); | 188 | ret = m_children.Contains(child); |
187 | /* Safer version but the above should work | 189 | /* Safer version but the above should work |
188 | foreach (BSPhysObject bp in m_children) | 190 | foreach (BSPrimLinkable bp in m_children) |
189 | { | 191 | { |
190 | if (child.LocalID == bp.LocalID) | 192 | if (child.LocalID == bp.LocalID) |
191 | { | 193 | { |
@@ -200,14 +202,14 @@ public abstract class BSLinkset | |||
200 | 202 | ||
201 | // Perform an action on each member of the linkset including root prim. | 203 | // Perform an action on each member of the linkset including root prim. |
202 | // Depends on the action on whether this should be done at taint time. | 204 | // Depends on the action on whether this should be done at taint time. |
203 | public delegate bool ForEachMemberAction(BSPhysObject obj); | 205 | public delegate bool ForEachMemberAction(BSPrimLinkable obj); |
204 | public virtual bool ForEachMember(ForEachMemberAction action) | 206 | public virtual bool ForEachMember(ForEachMemberAction action) |
205 | { | 207 | { |
206 | bool ret = false; | 208 | bool ret = false; |
207 | lock (m_linksetActivityLock) | 209 | lock (m_linksetActivityLock) |
208 | { | 210 | { |
209 | action(LinksetRoot); | 211 | action(LinksetRoot); |
210 | foreach (BSPhysObject po in m_children) | 212 | foreach (BSPrimLinkable po in m_children) |
211 | { | 213 | { |
212 | if (action(po)) | 214 | if (action(po)) |
213 | break; | 215 | break; |
@@ -218,16 +220,23 @@ public abstract class BSLinkset | |||
218 | 220 | ||
219 | // I am the root of a linkset and a new child is being added | 221 | // I am the root of a linkset and a new child is being added |
220 | // Called while LinkActivity is locked. | 222 | // Called while LinkActivity is locked. |
221 | protected abstract void AddChildToLinkset(BSPhysObject child); | 223 | protected abstract void AddChildToLinkset(BSPrimLinkable child); |
222 | 224 | ||
223 | // I am the root of a linkset and one of my children is being removed. | 225 | // I am the root of a linkset and one of my children is being removed. |
224 | // Safe to call even if the child is not really in my linkset. | 226 | // Safe to call even if the child is not really in my linkset. |
225 | protected abstract void RemoveChildFromLinkset(BSPhysObject child); | 227 | protected abstract void RemoveChildFromLinkset(BSPrimLinkable child); |
226 | 228 | ||
227 | // When physical properties are changed the linkset needs to recalculate | 229 | // When physical properties are changed the linkset needs to recalculate |
228 | // its internal properties. | 230 | // its internal properties. |
229 | // May be called at runtime or taint-time. | 231 | // May be called at runtime or taint-time. |
230 | public abstract void Refresh(BSPhysObject requestor); | 232 | public virtual void Refresh(BSPrimLinkable requestor) |
233 | { | ||
234 | LinksetMass = ComputeLinksetMass(); | ||
235 | } | ||
236 | |||
237 | // Flag denoting the linkset is in the process of being rebuilt. | ||
238 | // Used to know not the schedule a rebuild in the middle of a rebuild. | ||
239 | protected bool Rebuilding { get; set; } | ||
231 | 240 | ||
232 | // The object is going dynamic (physical). Do any setup necessary | 241 | // The object is going dynamic (physical). Do any setup necessary |
233 | // for a dynamic linkset. | 242 | // for a dynamic linkset. |
@@ -235,30 +244,26 @@ public abstract class BSLinkset | |||
235 | // has not yet been fully constructed. | 244 | // has not yet been fully constructed. |
236 | // Return 'true' if any properties updated on the passed object. | 245 | // Return 'true' if any properties updated on the passed object. |
237 | // Called at taint-time! | 246 | // Called at taint-time! |
238 | public abstract bool MakeDynamic(BSPhysObject child); | 247 | public abstract bool MakeDynamic(BSPrimLinkable child); |
239 | 248 | ||
240 | // The object is going static (non-physical). Do any setup necessary | 249 | // The object is going static (non-physical). Do any setup necessary |
241 | // for a static linkset. | 250 | // for a static linkset. |
242 | // Return 'true' if any properties updated on the passed object. | 251 | // Return 'true' if any properties updated on the passed object. |
243 | // Called at taint-time! | 252 | // Called at taint-time! |
244 | public abstract bool MakeStatic(BSPhysObject child); | 253 | public abstract bool MakeStatic(BSPrimLinkable child); |
245 | 254 | ||
246 | // Called when a parameter update comes from the physics engine for any object | 255 | // Called when a parameter update comes from the physics engine for any object |
247 | // of the linkset is received. | 256 | // of the linkset is received. |
257 | // Passed flag is update came from physics engine (true) or the user (false). | ||
248 | // Called at taint-time!! | 258 | // Called at taint-time!! |
249 | public abstract void UpdateProperties(BSPhysObject physObject); | 259 | public abstract void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable physObject); |
250 | 260 | ||
251 | // Routine used when rebuilding the body of the root of the linkset | 261 | // Routine used when rebuilding the body of the root of the linkset |
252 | // Destroy all the constraints have have been made to root. | 262 | // Destroy all the constraints have have been made to root. |
253 | // This is called when the root body is changing. | 263 | // This is called when the root body is changing. |
254 | // Returns 'true' of something was actually removed and would need restoring | 264 | // Returns 'true' of something was actually removed and would need restoring |
255 | // Called at taint-time!! | 265 | // Called at taint-time!! |
256 | public abstract bool RemoveBodyDependencies(BSPrim child); | 266 | public abstract bool RemoveBodyDependencies(BSPrimLinkable child); |
257 | |||
258 | // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true', | ||
259 | // this routine will restore the removed constraints. | ||
260 | // Called at taint-time!! | ||
261 | public abstract void RestoreBodyDependencies(BSPrim child); | ||
262 | 267 | ||
263 | // ================================================================ | 268 | // ================================================================ |
264 | protected virtual float ComputeLinksetMass() | 269 | protected virtual float ComputeLinksetMass() |
@@ -268,7 +273,7 @@ public abstract class BSLinkset | |||
268 | { | 273 | { |
269 | lock (m_linksetActivityLock) | 274 | lock (m_linksetActivityLock) |
270 | { | 275 | { |
271 | foreach (BSPhysObject bp in m_children) | 276 | foreach (BSPrimLinkable bp in m_children) |
272 | { | 277 | { |
273 | mass += bp.RawMass; | 278 | mass += bp.RawMass; |
274 | } | 279 | } |
@@ -277,6 +282,7 @@ public abstract class BSLinkset | |||
277 | return mass; | 282 | return mass; |
278 | } | 283 | } |
279 | 284 | ||
285 | // Computes linkset's center of mass in world coordinates. | ||
280 | protected virtual OMV.Vector3 ComputeLinksetCenterOfMass() | 286 | protected virtual OMV.Vector3 ComputeLinksetCenterOfMass() |
281 | { | 287 | { |
282 | OMV.Vector3 com; | 288 | OMV.Vector3 com; |
@@ -285,7 +291,7 @@ public abstract class BSLinkset | |||
285 | com = LinksetRoot.Position * LinksetRoot.RawMass; | 291 | com = LinksetRoot.Position * LinksetRoot.RawMass; |
286 | float totalMass = LinksetRoot.RawMass; | 292 | float totalMass = LinksetRoot.RawMass; |
287 | 293 | ||
288 | foreach (BSPhysObject bp in m_children) | 294 | foreach (BSPrimLinkable bp in m_children) |
289 | { | 295 | { |
290 | com += bp.Position * bp.RawMass; | 296 | com += bp.Position * bp.RawMass; |
291 | totalMass += bp.RawMass; | 297 | totalMass += bp.RawMass; |
@@ -304,9 +310,9 @@ public abstract class BSLinkset | |||
304 | { | 310 | { |
305 | com = LinksetRoot.Position; | 311 | com = LinksetRoot.Position; |
306 | 312 | ||
307 | foreach (BSPhysObject bp in m_children) | 313 | foreach (BSPrimLinkable bp in m_children) |
308 | { | 314 | { |
309 | com += bp.Position * bp.RawMass; | 315 | com += bp.Position; |
310 | } | 316 | } |
311 | com /= (m_children.Count + 1); | 317 | com /= (m_children.Count + 1); |
312 | } | 318 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs index b9c2cf9..e05562a 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs | |||
@@ -28,22 +28,80 @@ using System; | |||
28 | using System.Collections.Generic; | 28 | using System.Collections.Generic; |
29 | using System.Text; | 29 | using System.Text; |
30 | 30 | ||
31 | using OpenSim.Framework; | ||
32 | |||
31 | using OMV = OpenMetaverse; | 33 | using OMV = OpenMetaverse; |
32 | 34 | ||
33 | namespace OpenSim.Region.Physics.BulletSPlugin | 35 | namespace OpenSim.Region.Physics.BulletSPlugin |
34 | { | 36 | { |
37 | |||
38 | // When a child is linked, the relationship position of the child to the parent | ||
39 | // is remembered so the child's world position can be recomputed when it is | ||
40 | // removed from the linkset. | ||
41 | sealed class BSLinksetCompoundInfo : BSLinksetInfo | ||
42 | { | ||
43 | public int Index; | ||
44 | public OMV.Vector3 OffsetFromRoot; | ||
45 | public OMV.Vector3 OffsetFromCenterOfMass; | ||
46 | public OMV.Quaternion OffsetRot; | ||
47 | public BSLinksetCompoundInfo(int indx, OMV.Vector3 p, OMV.Quaternion r) | ||
48 | { | ||
49 | Index = indx; | ||
50 | OffsetFromRoot = p; | ||
51 | OffsetFromCenterOfMass = p; | ||
52 | OffsetRot = r; | ||
53 | } | ||
54 | // 'centerDisplacement' is the distance from the root the the center-of-mass (Bullet 'zero' of the shape) | ||
55 | public BSLinksetCompoundInfo(int indx, BSPrimLinkable root, BSPrimLinkable child, OMV.Vector3 centerDisplacement) | ||
56 | { | ||
57 | // Each child position and rotation is given relative to the center-of-mass. | ||
58 | OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(root.RawOrientation); | ||
59 | OMV.Vector3 displacementFromRoot = (child.RawPosition - root.RawPosition) * invRootOrientation; | ||
60 | OMV.Vector3 displacementFromCOM = displacementFromRoot - centerDisplacement; | ||
61 | OMV.Quaternion displacementRot = child.RawOrientation * invRootOrientation; | ||
62 | |||
63 | // Save relative position for recomputing child's world position after moving linkset. | ||
64 | Index = indx; | ||
65 | OffsetFromRoot = displacementFromRoot; | ||
66 | OffsetFromCenterOfMass = displacementFromCOM; | ||
67 | OffsetRot = displacementRot; | ||
68 | } | ||
69 | public override void Clear() | ||
70 | { | ||
71 | Index = 0; | ||
72 | OffsetFromRoot = OMV.Vector3.Zero; | ||
73 | OffsetFromCenterOfMass = OMV.Vector3.Zero; | ||
74 | OffsetRot = OMV.Quaternion.Identity; | ||
75 | } | ||
76 | public override string ToString() | ||
77 | { | ||
78 | StringBuilder buff = new StringBuilder(); | ||
79 | buff.Append("<i="); | ||
80 | buff.Append(Index.ToString()); | ||
81 | buff.Append(",p="); | ||
82 | buff.Append(OffsetFromRoot.ToString()); | ||
83 | buff.Append(",m="); | ||
84 | buff.Append(OffsetFromCenterOfMass.ToString()); | ||
85 | buff.Append(",r="); | ||
86 | buff.Append(OffsetRot.ToString()); | ||
87 | buff.Append(">"); | ||
88 | return buff.ToString(); | ||
89 | } | ||
90 | }; | ||
91 | |||
35 | public sealed class BSLinksetCompound : BSLinkset | 92 | public sealed class BSLinksetCompound : BSLinkset |
36 | { | 93 | { |
37 | private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]"; | 94 | private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]"; |
38 | 95 | ||
39 | public BSLinksetCompound(BSScene scene, BSPhysObject parent) | 96 | public BSLinksetCompound(BSScene scene, BSPrimLinkable parent) |
97 | : base(scene, parent) | ||
40 | { | 98 | { |
41 | base.Initialize(scene, parent); | ||
42 | } | 99 | } |
43 | 100 | ||
44 | // For compound implimented linksets, if there are children, use compound shape for the root. | 101 | // For compound implimented linksets, if there are children, use compound shape for the root. |
45 | public override BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor) | 102 | public override BSPhysicsShapeType PreferredPhysicalShape(BSPrimLinkable requestor) |
46 | { | 103 | { |
104 | // Returning 'unknown' means we don't have a preference. | ||
47 | BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | 105 | BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN; |
48 | if (IsRoot(requestor) && HasAnyChildren) | 106 | if (IsRoot(requestor) && HasAnyChildren) |
49 | { | 107 | { |
@@ -55,41 +113,57 @@ public sealed class BSLinksetCompound : BSLinkset | |||
55 | 113 | ||
56 | // When physical properties are changed the linkset needs to recalculate | 114 | // When physical properties are changed the linkset needs to recalculate |
57 | // its internal properties. | 115 | // its internal properties. |
58 | // This is queued in the 'post taint' queue so the | 116 | public override void Refresh(BSPrimLinkable requestor) |
59 | // refresh will happen once after all the other taints are applied. | ||
60 | public override void Refresh(BSPhysObject requestor) | ||
61 | { | 117 | { |
62 | // External request for Refresh (from BSPrim) is not necessary | 118 | base.Refresh(requestor); |
63 | // InternalRefresh(requestor); | 119 | |
120 | // Something changed so do the rebuilding thing | ||
121 | // ScheduleRebuild(); | ||
64 | } | 122 | } |
65 | 123 | ||
66 | private void InternalRefresh(BSPhysObject requestor) | 124 | // Schedule a refresh to happen after all the other taint processing. |
125 | private void ScheduleRebuild(BSPrimLinkable requestor) | ||
67 | { | 126 | { |
68 | DetailLog("{0},BSLinksetCompound.Refresh,schedulingRefresh,requestor={1}", LinksetRoot.LocalID, requestor.LocalID); | 127 | DetailLog("{0},BSLinksetCompound.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}", |
69 | // Queue to happen after all the other taint processing | 128 | requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren)); |
70 | PhysicsScene.PostTaintObject("BSLinksetCompound.Refresh", requestor.LocalID, delegate() | 129 | // When rebuilding, it is possible to set properties that would normally require a rebuild. |
130 | // If already rebuilding, don't request another rebuild. | ||
131 | // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding. | ||
132 | if (!Rebuilding && HasAnyChildren) | ||
71 | { | 133 | { |
72 | if (IsRoot(requestor) && HasAnyChildren) | 134 | PhysicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate() |
73 | RecomputeLinksetCompound(); | 135 | { |
74 | }); | 136 | if (HasAnyChildren) |
137 | RecomputeLinksetCompound(); | ||
138 | }); | ||
139 | } | ||
75 | } | 140 | } |
76 | 141 | ||
77 | // The object is going dynamic (physical). Do any setup necessary | 142 | // The object is going dynamic (physical). Do any setup necessary for a dynamic linkset. |
78 | // for a dynamic linkset. | ||
79 | // Only the state of the passed object can be modified. The rest of the linkset | 143 | // Only the state of the passed object can be modified. The rest of the linkset |
80 | // has not yet been fully constructed. | 144 | // has not yet been fully constructed. |
81 | // Return 'true' if any properties updated on the passed object. | 145 | // Return 'true' if any properties updated on the passed object. |
82 | // Called at taint-time! | 146 | // Called at taint-time! |
83 | public override bool MakeDynamic(BSPhysObject child) | 147 | public override bool MakeDynamic(BSPrimLinkable child) |
84 | { | 148 | { |
85 | bool ret = false; | 149 | bool ret = false; |
86 | DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child)); | 150 | DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child)); |
87 | if (!IsRoot(child)) | 151 | if (IsRoot(child)) |
152 | { | ||
153 | // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly. | ||
154 | ScheduleRebuild(LinksetRoot); | ||
155 | } | ||
156 | else | ||
88 | { | 157 | { |
89 | // Physical children are removed from the world as the shape ofthe root compound | 158 | // The origional prims are removed from the world as the shape of the root compound |
90 | // shape takes over. | 159 | // shape takes over. |
91 | BulletSimAPI.AddToCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); | 160 | PhysicsScene.PE.AddToCollisionFlags(child.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); |
92 | BulletSimAPI.ForceActivationState2(child.PhysBody.ptr, ActivationState.DISABLE_SIMULATION); | 161 | PhysicsScene.PE.ForceActivationState(child.PhysBody, ActivationState.DISABLE_SIMULATION); |
162 | // We don't want collisions from the old linkset children. | ||
163 | PhysicsScene.PE.RemoveFromCollisionFlags(child.PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | ||
164 | |||
165 | child.PhysBody.collisionType = CollisionType.LinksetChild; | ||
166 | |||
93 | ret = true; | 167 | ret = true; |
94 | } | 168 | } |
95 | return ret; | 169 | return ret; |
@@ -100,73 +174,181 @@ public sealed class BSLinksetCompound : BSLinkset | |||
100 | // This doesn't normally happen -- OpenSim removes the objects from the physical | 174 | // This doesn't normally happen -- OpenSim removes the objects from the physical |
101 | // world if it is a static linkset. | 175 | // world if it is a static linkset. |
102 | // Called at taint-time! | 176 | // Called at taint-time! |
103 | public override bool MakeStatic(BSPhysObject child) | 177 | public override bool MakeStatic(BSPrimLinkable child) |
104 | { | 178 | { |
105 | bool ret = false; | 179 | bool ret = false; |
106 | DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); | 180 | DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); |
107 | if (!IsRoot(child)) | 181 | if (IsRoot(child)) |
182 | { | ||
183 | ScheduleRebuild(LinksetRoot); | ||
184 | } | ||
185 | else | ||
108 | { | 186 | { |
109 | // The non-physical children can come back to life. | 187 | // The non-physical children can come back to life. |
110 | BulletSimAPI.RemoveFromCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); | 188 | PhysicsScene.PE.RemoveFromCollisionFlags(child.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); |
111 | // Don't force activation so setting of DISABLE_SIMULATION can stay. | 189 | |
112 | BulletSimAPI.Activate2(child.PhysBody.ptr, false); | 190 | child.PhysBody.collisionType = CollisionType.LinksetChild; |
191 | |||
192 | // Don't force activation so setting of DISABLE_SIMULATION can stay if used. | ||
193 | PhysicsScene.PE.Activate(child.PhysBody, false); | ||
113 | ret = true; | 194 | ret = true; |
114 | } | 195 | } |
115 | return ret; | 196 | return ret; |
116 | } | 197 | } |
117 | 198 | ||
118 | // Called at taint-time!! | 199 | // 'physicalUpdate' is true if these changes came directly from the physics engine. Don't need to rebuild then. |
119 | public override void UpdateProperties(BSPhysObject updated) | 200 | // Called at taint-time. |
120 | { | 201 | public override void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable updated) |
121 | // Nothing to do for constraints on property updates | ||
122 | } | ||
123 | |||
124 | // The children move around in relationship to the root. | ||
125 | // Just grab the current values of wherever it is right now. | ||
126 | public override OMV.Vector3 Position(BSPhysObject member) | ||
127 | { | 202 | { |
128 | return BulletSimAPI.GetPosition2(member.PhysBody.ptr); | 203 | // The user moving a child around requires the rebuilding of the linkset compound shape |
129 | } | 204 | // One problem is this happens when a border is crossed -- the simulator implementation |
205 | // stores the position into the group which causes the move of the object | ||
206 | // but it also means all the child positions get updated. | ||
207 | // What would cause an unnecessary rebuild so we make sure the linkset is in a | ||
208 | // region before bothering to do a rebuild. | ||
209 | if (!IsRoot(updated) && PhysicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition)) | ||
210 | { | ||
211 | // If a child of the linkset is updating only the position or rotation, that can be done | ||
212 | // without rebuilding the linkset. | ||
213 | // If a handle for the child can be fetch, we update the child here. If a rebuild was | ||
214 | // scheduled by someone else, the rebuild will just replace this setting. | ||
215 | |||
216 | bool updatedChild = false; | ||
217 | // Anything other than updating position or orientation usually means a physical update | ||
218 | // and that is caused by us updating the object. | ||
219 | if ((whichUpdated & ~(UpdatedProperties.Position | UpdatedProperties.Orientation)) == 0) | ||
220 | { | ||
221 | // Find the physical instance of the child | ||
222 | if (LinksetRoot.PhysShape.HasPhysicalShape && PhysicsScene.PE.IsCompound(LinksetRoot.PhysShape)) | ||
223 | { | ||
224 | // It is possible that the linkset is still under construction and the child is not yet | ||
225 | // inserted into the compound shape. A rebuild of the linkset in a pre-step action will | ||
226 | // build the whole thing with the new position or rotation. | ||
227 | // The index must be checked because Bullet references the child array but does no validity | ||
228 | // checking of the child index passed. | ||
229 | int numLinksetChildren = PhysicsScene.PE.GetNumberOfCompoundChildren(LinksetRoot.PhysShape); | ||
230 | if (updated.LinksetChildIndex < numLinksetChildren) | ||
231 | { | ||
232 | BulletShape linksetChildShape = PhysicsScene.PE.GetChildShapeFromCompoundShapeIndex(LinksetRoot.PhysShape, updated.LinksetChildIndex); | ||
233 | if (linksetChildShape.HasPhysicalShape) | ||
234 | { | ||
235 | // Found the child shape within the compound shape | ||
236 | PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape, updated.LinksetChildIndex, | ||
237 | updated.RawPosition - LinksetRoot.RawPosition, | ||
238 | updated.RawOrientation * OMV.Quaternion.Inverse(LinksetRoot.RawOrientation), | ||
239 | true /* shouldRecalculateLocalAabb */); | ||
240 | updatedChild = true; | ||
241 | DetailLog("{0},BSLinksetCompound.UpdateProperties,changeChildPosRot,whichUpdated={1},pos={2},rot={3}", | ||
242 | updated.LocalID, whichUpdated, updated.RawPosition, updated.RawOrientation); | ||
243 | } | ||
244 | else // DEBUG DEBUG | ||
245 | { // DEBUG DEBUG | ||
246 | DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noChildShape,shape={1}", | ||
247 | updated.LocalID, linksetChildShape); | ||
248 | } // DEBUG DEBUG | ||
249 | } | ||
250 | else // DEBUG DEBUG | ||
251 | { // DEBUG DEBUG | ||
252 | // the child is not yet in the compound shape. This is non-fatal. | ||
253 | DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,childNotInCompoundShape,numChildren={1},index={2}", | ||
254 | updated.LocalID, numLinksetChildren, updated.LinksetChildIndex); | ||
255 | } // DEBUG DEBUG | ||
256 | } | ||
257 | else // DEBUG DEBUG | ||
258 | { // DEBUG DEBUG | ||
259 | DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noBodyOrNotCompound", updated.LocalID); | ||
260 | } // DEBUG DEBUG | ||
130 | 261 | ||
131 | public override OMV.Quaternion Orientation(BSPhysObject member) | 262 | if (!updatedChild) |
132 | { | 263 | { |
133 | return BulletSimAPI.GetOrientation2(member.PhysBody.ptr); | 264 | // If couldn't do the individual child, the linkset needs a rebuild to incorporate the new child info. |
265 | // Note: there are several ways through this code that will not update the child if | ||
266 | // the linkset is being rebuilt. In this case, scheduling a rebuild is a NOOP since | ||
267 | // there will already be a rebuild scheduled. | ||
268 | DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild.schedulingRebuild,whichUpdated={1}", | ||
269 | updated.LocalID, whichUpdated); | ||
270 | updated.LinksetInfo = null; // setting to 'null' causes relative position to be recomputed. | ||
271 | ScheduleRebuild(updated); | ||
272 | } | ||
273 | } | ||
274 | } | ||
134 | } | 275 | } |
135 | 276 | ||
136 | // Routine called when rebuilding the body of some member of the linkset. | 277 | // Routine called when rebuilding the body of some member of the linkset. |
137 | // Since we don't keep in world relationships, do nothing unless it's a child changing. | 278 | // Since we don't keep in world relationships, do nothing unless it's a child changing. |
138 | // Returns 'true' of something was actually removed and would need restoring | 279 | // Returns 'true' of something was actually removed and would need restoring |
139 | // Called at taint-time!! | 280 | // Called at taint-time!! |
140 | public override bool RemoveBodyDependencies(BSPrim child) | 281 | public override bool RemoveBodyDependencies(BSPrimLinkable child) |
141 | { | 282 | { |
142 | bool ret = false; | 283 | bool ret = false; |
143 | 284 | ||
144 | DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}", | 285 | DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}", |
145 | child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"), IsRoot(child)); | 286 | child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody, IsRoot(child)); |
146 | 287 | ||
147 | if (!IsRoot(child)) | 288 | if (!IsRoot(child)) |
148 | { | 289 | { |
149 | // Cause the current shape to be freed and the new one to be built. | 290 | // Because it is a convenient time, recompute child world position and rotation based on |
150 | InternalRefresh(LinksetRoot); | 291 | // its position in the linkset. |
151 | ret = true; | 292 | RecomputeChildWorldPosition(child, true /* inTaintTime */); |
293 | child.LinksetInfo = null; | ||
152 | } | 294 | } |
153 | 295 | ||
296 | // Cannot schedule a refresh/rebuild here because this routine is called when | ||
297 | // the linkset is being rebuilt. | ||
298 | // InternalRefresh(LinksetRoot); | ||
299 | |||
154 | return ret; | 300 | return ret; |
155 | } | 301 | } |
156 | 302 | ||
157 | // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true', | 303 | // When the linkset is built, the child shape is added to the compound shape relative to the |
158 | // this routine will restore the removed constraints. | 304 | // root shape. The linkset then moves around but this does not move the actual child |
159 | // Called at taint-time!! | 305 | // prim. The child prim's location must be recomputed based on the location of the root shape. |
160 | public override void RestoreBodyDependencies(BSPrim child) | 306 | private void RecomputeChildWorldPosition(BSPrimLinkable child, bool inTaintTime) |
161 | { | 307 | { |
162 | // The Refresh operation queued by RemoveBodyDependencies() will build any missing constraints. | 308 | // For the moment (20130201), disable this computation (converting the child physical addr back to |
309 | // a region address) until we have a good handle on center-of-mass offsets and what the physics | ||
310 | // engine moving a child actually means. | ||
311 | // The simulator keeps track of where children should be as the linkset moves. Setting | ||
312 | // the pos/rot here does not effect that knowledge as there is no good way for the | ||
313 | // physics engine to send the simulator an update for a child. | ||
314 | |||
315 | /* | ||
316 | BSLinksetCompoundInfo lci = child.LinksetInfo as BSLinksetCompoundInfo; | ||
317 | if (lci != null) | ||
318 | { | ||
319 | if (inTaintTime) | ||
320 | { | ||
321 | OMV.Vector3 oldPos = child.RawPosition; | ||
322 | child.ForcePosition = LinksetRoot.RawPosition + lci.OffsetFromRoot; | ||
323 | child.ForceOrientation = LinksetRoot.RawOrientation * lci.OffsetRot; | ||
324 | DetailLog("{0},BSLinksetCompound.RecomputeChildWorldPosition,oldPos={1},lci={2},newPos={3}", | ||
325 | child.LocalID, oldPos, lci, child.RawPosition); | ||
326 | } | ||
327 | else | ||
328 | { | ||
329 | // TaintedObject is not used here so the raw position is set now and not at taint-time. | ||
330 | child.Position = LinksetRoot.RawPosition + lci.OffsetFromRoot; | ||
331 | child.Orientation = LinksetRoot.RawOrientation * lci.OffsetRot; | ||
332 | } | ||
333 | } | ||
334 | else | ||
335 | { | ||
336 | // This happens when children have been added to the linkset but the linkset | ||
337 | // has not been constructed yet. So like, at taint time, adding children to a linkset | ||
338 | // and then changing properties of the children (makePhysical, for instance) | ||
339 | // but the post-print action of actually rebuilding the linkset has not yet happened. | ||
340 | // PhysicsScene.Logger.WarnFormat("{0} Restoring linkset child position failed because of no relative position computed. ID={1}", | ||
341 | // LogHeader, child.LocalID); | ||
342 | DetailLog("{0},BSLinksetCompound.recomputeChildWorldPosition,noRelativePositonInfo", child.LocalID); | ||
343 | } | ||
344 | */ | ||
163 | } | 345 | } |
164 | 346 | ||
165 | // ================================================================ | 347 | // ================================================================ |
166 | 348 | ||
167 | // Add a new child to the linkset. | 349 | // Add a new child to the linkset. |
168 | // Called while LinkActivity is locked. | 350 | // Called while LinkActivity is locked. |
169 | protected override void AddChildToLinkset(BSPhysObject child) | 351 | protected override void AddChildToLinkset(BSPrimLinkable child) |
170 | { | 352 | { |
171 | if (!HasChild(child)) | 353 | if (!HasChild(child)) |
172 | { | 354 | { |
@@ -174,24 +356,28 @@ public sealed class BSLinksetCompound : BSLinkset | |||
174 | 356 | ||
175 | DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); | 357 | DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); |
176 | 358 | ||
177 | // Cause constraints and assorted properties to be recomputed before the next simulation step. | 359 | // Rebuild the compound shape with the new child shape included |
178 | InternalRefresh(LinksetRoot); | 360 | ScheduleRebuild(child); |
179 | } | 361 | } |
180 | return; | 362 | return; |
181 | } | 363 | } |
182 | 364 | ||
183 | // Remove the specified child from the linkset. | 365 | // Remove the specified child from the linkset. |
184 | // Safe to call even if the child is not really in my linkset. | 366 | // Safe to call even if the child is not really in the linkset. |
185 | protected override void RemoveChildFromLinkset(BSPhysObject child) | 367 | protected override void RemoveChildFromLinkset(BSPrimLinkable child) |
186 | { | 368 | { |
369 | child.ClearDisplacement(); | ||
370 | |||
187 | if (m_children.Remove(child)) | 371 | if (m_children.Remove(child)) |
188 | { | 372 | { |
189 | DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", | 373 | DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", |
190 | child.LocalID, | 374 | child.LocalID, |
191 | LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"), | 375 | LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, |
192 | child.LocalID, child.PhysBody.ptr.ToString("X")); | 376 | child.LocalID, child.PhysBody.AddrString); |
193 | 377 | ||
194 | // Cause the child's body to be rebuilt and thus restored to normal operation | 378 | // Cause the child's body to be rebuilt and thus restored to normal operation |
379 | RecomputeChildWorldPosition(child, false); | ||
380 | child.LinksetInfo = null; | ||
195 | child.ForceBodyShapeRebuild(false); | 381 | child.ForceBodyShapeRebuild(false); |
196 | 382 | ||
197 | if (!HasAnyChildren) | 383 | if (!HasAnyChildren) |
@@ -201,8 +387,8 @@ public sealed class BSLinksetCompound : BSLinkset | |||
201 | } | 387 | } |
202 | else | 388 | else |
203 | { | 389 | { |
204 | // Schedule a rebuild of the linkset before the next simulation tick. | 390 | // Rebuild the compound shape with the child removed |
205 | InternalRefresh(LinksetRoot); | 391 | ScheduleRebuild(LinksetRoot); |
206 | } | 392 | } |
207 | } | 393 | } |
208 | return; | 394 | return; |
@@ -213,63 +399,116 @@ public sealed class BSLinksetCompound : BSLinkset | |||
213 | // Constraint linksets are rebuilt every time. | 399 | // Constraint linksets are rebuilt every time. |
214 | // Note that this works for rebuilding just the root after a linkset is taken apart. | 400 | // Note that this works for rebuilding just the root after a linkset is taken apart. |
215 | // Called at taint time!! | 401 | // Called at taint time!! |
402 | private bool disableCOM = true; // DEBUG DEBUG: disable until we get this debugged | ||
216 | private void RecomputeLinksetCompound() | 403 | private void RecomputeLinksetCompound() |
217 | { | 404 | { |
218 | // Cause the root shape to be rebuilt as a compound object with just the root in it | 405 | try |
219 | LinksetRoot.ForceBodyShapeRebuild(true); | 406 | { |
407 | // Suppress rebuilding while rebuilding. (We know rebuilding is on only one thread.) | ||
408 | Rebuilding = true; | ||
220 | 409 | ||
221 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}", | 410 | // Cause the root shape to be rebuilt as a compound object with just the root in it |
222 | LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren); | 411 | LinksetRoot.ForceBodyShapeRebuild(true /* inTaintTime */); |
223 | 412 | ||
224 | // Add a shape for each of the other children in the linkset | 413 | // The center of mass for the linkset is the geometric center of the group. |
225 | ForEachMember(delegate(BSPhysObject cPrim) | 414 | // Compute a displacement for each component so it is relative to the center-of-mass. |
226 | { | 415 | // Bullet presumes an object's origin (relative <0,0,0>) is its center-of-mass |
227 | if (!IsRoot(cPrim)) | 416 | OMV.Vector3 centerOfMassW = LinksetRoot.RawPosition; |
417 | if (!disableCOM) // DEBUG DEBUG | ||
228 | { | 418 | { |
229 | // Each child position and rotation is given relative to the root. | 419 | // Compute a center-of-mass in world coordinates. |
230 | OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation); | 420 | centerOfMassW = ComputeLinksetCenterOfMass(); |
231 | OMV.Vector3 displacementPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation; | 421 | } |
232 | OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation; | 422 | |
423 | OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation); | ||
424 | |||
425 | // 'centerDisplacement' is the value to subtract from children to give physical offset position | ||
426 | OMV.Vector3 centerDisplacement = (centerOfMassW - LinksetRoot.RawPosition) * invRootOrientation; | ||
427 | LinksetRoot.SetEffectiveCenterOfMassW(centerDisplacement); | ||
233 | 428 | ||
234 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}", | 429 | // This causes the physical position of the root prim to be offset to accomodate for the displacements |
235 | LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, displacementPos, displacementRot); | 430 | LinksetRoot.ForcePosition = LinksetRoot.RawPosition; |
236 | 431 | ||
237 | if (cPrim.PhysShape.isNativeShape) | 432 | // Update the local transform for the root child shape so it is offset from the <0,0,0> which is COM |
433 | PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape, 0 /* childIndex */, | ||
434 | -centerDisplacement, | ||
435 | OMV.Quaternion.Identity, // LinksetRoot.RawOrientation, | ||
436 | false /* shouldRecalculateLocalAabb (is done later after linkset built) */); | ||
437 | |||
438 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,com={1},rootPos={2},centerDisp={3}", | ||
439 | LinksetRoot.LocalID, centerOfMassW, LinksetRoot.RawPosition, centerDisplacement); | ||
440 | |||
441 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}", | ||
442 | LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren); | ||
443 | |||
444 | // Add a shape for each of the other children in the linkset | ||
445 | int memberIndex = 1; | ||
446 | ForEachMember(delegate(BSPrimLinkable cPrim) | ||
447 | { | ||
448 | if (IsRoot(cPrim)) | ||
238 | { | 449 | { |
239 | // Native shapes are not shared so we need to create a new one. | 450 | cPrim.LinksetChildIndex = 0; |
240 | // A mesh or hull is created because scale is not available on a native shape. | ||
241 | // (TODO: Bullet does have a btScaledCollisionShape. Can that be used?) | ||
242 | BulletShape saveShape = cPrim.PhysShape; | ||
243 | cPrim.PhysShape.ptr = IntPtr.Zero; // Don't let the create free the child's shape | ||
244 | PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null); | ||
245 | BulletShape newShape = cPrim.PhysShape; | ||
246 | cPrim.PhysShape = saveShape; | ||
247 | BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, newShape.ptr, displacementPos, displacementRot); | ||
248 | } | 451 | } |
249 | else | 452 | else |
250 | { | 453 | { |
251 | // For the shared shapes (meshes and hulls), just use the shape in the child. | 454 | cPrim.LinksetChildIndex = memberIndex; |
252 | if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape)) | 455 | |
456 | if (cPrim.PhysShape.isNativeShape) | ||
253 | { | 457 | { |
254 | PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}", | 458 | // A native shape is turned into a hull collision shape because native |
255 | LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape); | 459 | // shapes are not shared so we have to hullify it so it will be tracked |
460 | // and freed at the correct time. This also solves the scaling problem | ||
461 | // (native shapes scale but hull/meshes are assumed to not be). | ||
462 | // TODO: decide of the native shape can just be used in the compound shape. | ||
463 | // Use call to CreateGeomNonSpecial(). | ||
464 | BulletShape saveShape = cPrim.PhysShape; | ||
465 | cPrim.PhysShape.Clear(); // Don't let the create free the child's shape | ||
466 | PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null); | ||
467 | BulletShape newShape = cPrim.PhysShape; | ||
468 | cPrim.PhysShape = saveShape; | ||
469 | |||
470 | OMV.Vector3 offsetPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation - centerDisplacement; | ||
471 | OMV.Quaternion offsetRot = cPrim.RawOrientation * invRootOrientation; | ||
472 | PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, newShape, offsetPos, offsetRot); | ||
473 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addNative,indx={1},rShape={2},cShape={3},offPos={4},offRot={5}", | ||
474 | LinksetRoot.LocalID, memberIndex, LinksetRoot.PhysShape, newShape, offsetPos, offsetRot); | ||
256 | } | 475 | } |
257 | BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, cPrim.PhysShape.ptr, displacementPos, displacementRot); | 476 | else |
258 | } | 477 | { |
259 | } | 478 | // For the shared shapes (meshes and hulls), just use the shape in the child. |
260 | return false; // 'false' says to move onto the next child in the list | 479 | // The reference count added here will be decremented when the compound shape |
261 | }); | 480 | // is destroyed in BSShapeCollection (the child shapes are looped over and dereferenced). |
481 | if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape)) | ||
482 | { | ||
483 | PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}", | ||
484 | LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape); | ||
485 | } | ||
486 | OMV.Vector3 offsetPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation - centerDisplacement; | ||
487 | OMV.Quaternion offsetRot = cPrim.RawOrientation * invRootOrientation; | ||
488 | PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, cPrim.PhysShape, offsetPos, offsetRot); | ||
489 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addNonNative,indx={1},rShape={2},cShape={3},offPos={4},offRot={5}", | ||
490 | LinksetRoot.LocalID, memberIndex, LinksetRoot.PhysShape, cPrim.PhysShape, offsetPos, offsetRot); | ||
262 | 491 | ||
263 | // With all of the linkset packed into the root prim, it has the mass of everyone. | 492 | } |
264 | float linksetMass = LinksetMass; | 493 | memberIndex++; |
265 | LinksetRoot.UpdatePhysicalMassProperties(linksetMass); | 494 | } |
495 | return false; // 'false' says to move onto the next child in the list | ||
496 | }); | ||
266 | 497 | ||
267 | BulletSimAPI.RecalculateCompoundShapeLocalAabb2(LinksetRoot.PhysShape.ptr); | 498 | // With all of the linkset packed into the root prim, it has the mass of everyone. |
499 | LinksetMass = ComputeLinksetMass(); | ||
500 | LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true); | ||
268 | 501 | ||
269 | // DEBUG: see of inter-linkset collisions are causing problems for constraint linksets. | 502 | // Enable the physical position updator to return the position and rotation of the root shape |
270 | // BulletSimAPI.SetCollisionFilterMask2(LinksetRoot.BSBody.ptr, | 503 | PhysicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, CollisionFlags.BS_RETURN_ROOT_COMPOUND_SHAPE); |
271 | // (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask); | 504 | } |
505 | finally | ||
506 | { | ||
507 | Rebuilding = false; | ||
508 | } | ||
272 | 509 | ||
510 | // See that the Aabb surrounds the new shape | ||
511 | PhysicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape); | ||
273 | } | 512 | } |
274 | } | 513 | } |
275 | } \ No newline at end of file | 514 | } \ No newline at end of file |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs index c855fda..6d252ca 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs | |||
@@ -36,23 +36,27 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
36 | { | 36 | { |
37 | // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]"; | 37 | // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]"; |
38 | 38 | ||
39 | public BSLinksetConstraints(BSScene scene, BSPhysObject parent) | 39 | public BSLinksetConstraints(BSScene scene, BSPrimLinkable parent) : base(scene, parent) |
40 | { | 40 | { |
41 | base.Initialize(scene, parent); | ||
42 | } | 41 | } |
43 | 42 | ||
44 | // When physical properties are changed the linkset needs to recalculate | 43 | // When physical properties are changed the linkset needs to recalculate |
45 | // its internal properties. | 44 | // its internal properties. |
46 | // This is queued in the 'post taint' queue so the | 45 | // This is queued in the 'post taint' queue so the |
47 | // refresh will happen once after all the other taints are applied. | 46 | // refresh will happen once after all the other taints are applied. |
48 | public override void Refresh(BSPhysObject requestor) | 47 | public override void Refresh(BSPrimLinkable requestor) |
49 | { | 48 | { |
50 | // Queue to happen after all the other taint processing | 49 | base.Refresh(requestor); |
51 | PhysicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate() | 50 | |
52 | { | 51 | if (HasAnyChildren && IsRoot(requestor)) |
53 | if (HasAnyChildren && IsRoot(requestor)) | 52 | { |
54 | RecomputeLinksetConstraints(); | 53 | // Queue to happen after all the other taint processing |
55 | }); | 54 | PhysicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate() |
55 | { | ||
56 | if (HasAnyChildren && IsRoot(requestor)) | ||
57 | RecomputeLinksetConstraints(); | ||
58 | }); | ||
59 | } | ||
56 | } | 60 | } |
57 | 61 | ||
58 | // The object is going dynamic (physical). Do any setup necessary | 62 | // The object is going dynamic (physical). Do any setup necessary |
@@ -61,7 +65,7 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
61 | // has not yet been fully constructed. | 65 | // has not yet been fully constructed. |
62 | // Return 'true' if any properties updated on the passed object. | 66 | // Return 'true' if any properties updated on the passed object. |
63 | // Called at taint-time! | 67 | // Called at taint-time! |
64 | public override bool MakeDynamic(BSPhysObject child) | 68 | public override bool MakeDynamic(BSPrimLinkable child) |
65 | { | 69 | { |
66 | // What is done for each object in BSPrim is what we want. | 70 | // What is done for each object in BSPrim is what we want. |
67 | return false; | 71 | return false; |
@@ -72,41 +76,29 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
72 | // This doesn't normally happen -- OpenSim removes the objects from the physical | 76 | // This doesn't normally happen -- OpenSim removes the objects from the physical |
73 | // world if it is a static linkset. | 77 | // world if it is a static linkset. |
74 | // Called at taint-time! | 78 | // Called at taint-time! |
75 | public override bool MakeStatic(BSPhysObject child) | 79 | public override bool MakeStatic(BSPrimLinkable child) |
76 | { | 80 | { |
77 | // What is done for each object in BSPrim is what we want. | 81 | // What is done for each object in BSPrim is what we want. |
78 | return false; | 82 | return false; |
79 | } | 83 | } |
80 | 84 | ||
81 | // Called at taint-time!! | 85 | // Called at taint-time!! |
82 | public override void UpdateProperties(BSPhysObject updated) | 86 | public override void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable pObj) |
83 | { | 87 | { |
84 | // Nothing to do for constraints on property updates | 88 | // Nothing to do for constraints on property updates |
85 | } | 89 | } |
86 | 90 | ||
87 | // The children of the linkset are moved around by the constraints. | ||
88 | // Just grab the current values of wherever it is right now. | ||
89 | public override OMV.Vector3 Position(BSPhysObject member) | ||
90 | { | ||
91 | return BulletSimAPI.GetPosition2(member.PhysBody.ptr); | ||
92 | } | ||
93 | |||
94 | public override OMV.Quaternion Orientation(BSPhysObject member) | ||
95 | { | ||
96 | return BulletSimAPI.GetOrientation2(member.PhysBody.ptr); | ||
97 | } | ||
98 | |||
99 | // Routine called when rebuilding the body of some member of the linkset. | 91 | // Routine called when rebuilding the body of some member of the linkset. |
100 | // Destroy all the constraints have have been made to root and set | 92 | // Destroy all the constraints have have been made to root and set |
101 | // up to rebuild the constraints before the next simulation step. | 93 | // up to rebuild the constraints before the next simulation step. |
102 | // Returns 'true' of something was actually removed and would need restoring | 94 | // Returns 'true' of something was actually removed and would need restoring |
103 | // Called at taint-time!! | 95 | // Called at taint-time!! |
104 | public override bool RemoveBodyDependencies(BSPrim child) | 96 | public override bool RemoveBodyDependencies(BSPrimLinkable child) |
105 | { | 97 | { |
106 | bool ret = false; | 98 | bool ret = false; |
107 | 99 | ||
108 | DetailLog("{0},BSLinksetConstraint.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}", | 100 | DetailLog("{0},BSLinksetConstraint.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}", |
109 | child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X")); | 101 | child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString); |
110 | 102 | ||
111 | lock (m_linksetActivityLock) | 103 | lock (m_linksetActivityLock) |
112 | { | 104 | { |
@@ -118,19 +110,11 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
118 | return ret; | 110 | return ret; |
119 | } | 111 | } |
120 | 112 | ||
121 | // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true', | ||
122 | // this routine will restore the removed constraints. | ||
123 | // Called at taint-time!! | ||
124 | public override void RestoreBodyDependencies(BSPrim child) | ||
125 | { | ||
126 | // The Refresh operation queued by RemoveBodyDependencies() will build any missing constraints. | ||
127 | } | ||
128 | |||
129 | // ================================================================ | 113 | // ================================================================ |
130 | 114 | ||
131 | // Add a new child to the linkset. | 115 | // Add a new child to the linkset. |
132 | // Called while LinkActivity is locked. | 116 | // Called while LinkActivity is locked. |
133 | protected override void AddChildToLinkset(BSPhysObject child) | 117 | protected override void AddChildToLinkset(BSPrimLinkable child) |
134 | { | 118 | { |
135 | if (!HasChild(child)) | 119 | if (!HasChild(child)) |
136 | { | 120 | { |
@@ -146,17 +130,17 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
146 | 130 | ||
147 | // Remove the specified child from the linkset. | 131 | // Remove the specified child from the linkset. |
148 | // Safe to call even if the child is not really in my linkset. | 132 | // Safe to call even if the child is not really in my linkset. |
149 | protected override void RemoveChildFromLinkset(BSPhysObject child) | 133 | protected override void RemoveChildFromLinkset(BSPrimLinkable child) |
150 | { | 134 | { |
151 | if (m_children.Remove(child)) | 135 | if (m_children.Remove(child)) |
152 | { | 136 | { |
153 | BSPhysObject rootx = LinksetRoot; // capture the root and body as of now | 137 | BSPrimLinkable rootx = LinksetRoot; // capture the root and body as of now |
154 | BSPhysObject childx = child; | 138 | BSPrimLinkable childx = child; |
155 | 139 | ||
156 | DetailLog("{0},BSLinksetConstraints.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", | 140 | DetailLog("{0},BSLinksetConstraints.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", |
157 | childx.LocalID, | 141 | childx.LocalID, |
158 | rootx.LocalID, rootx.PhysBody.ptr.ToString("X"), | 142 | rootx.LocalID, rootx.PhysBody.AddrString, |
159 | childx.LocalID, childx.PhysBody.ptr.ToString("X")); | 143 | childx.LocalID, childx.PhysBody.AddrString); |
160 | 144 | ||
161 | PhysicsScene.TaintedObject("BSLinksetConstraints.RemoveChildFromLinkset", delegate() | 145 | PhysicsScene.TaintedObject("BSLinksetConstraints.RemoveChildFromLinkset", delegate() |
162 | { | 146 | { |
@@ -175,13 +159,13 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
175 | 159 | ||
176 | // Create a constraint between me (root of linkset) and the passed prim (the child). | 160 | // Create a constraint between me (root of linkset) and the passed prim (the child). |
177 | // Called at taint time! | 161 | // Called at taint time! |
178 | private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BSPhysObject childPrim) | 162 | private void PhysicallyLinkAChildToRoot(BSPrimLinkable rootPrim, BSPrimLinkable childPrim) |
179 | { | 163 | { |
180 | // Don't build the constraint when asked. Put it off until just before the simulation step. | 164 | // Don't build the constraint when asked. Put it off until just before the simulation step. |
181 | Refresh(rootPrim); | 165 | Refresh(rootPrim); |
182 | } | 166 | } |
183 | 167 | ||
184 | private BSConstraint BuildConstraint(BSPhysObject rootPrim, BSPhysObject childPrim) | 168 | private BSConstraint BuildConstraint(BSPrimLinkable rootPrim, BSPrimLinkable childPrim) |
185 | { | 169 | { |
186 | // Zero motion for children so they don't interpolate | 170 | // Zero motion for children so they don't interpolate |
187 | childPrim.ZeroMotion(true); | 171 | childPrim.ZeroMotion(true); |
@@ -195,8 +179,8 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
195 | 179 | ||
196 | DetailLog("{0},BSLinksetConstraint.BuildConstraint,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}", | 180 | DetailLog("{0},BSLinksetConstraint.BuildConstraint,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}", |
197 | rootPrim.LocalID, | 181 | rootPrim.LocalID, |
198 | rootPrim.LocalID, rootPrim.PhysBody.ptr.ToString("X"), | 182 | rootPrim.LocalID, rootPrim.PhysBody.AddrString, |
199 | childPrim.LocalID, childPrim.PhysBody.ptr.ToString("X"), | 183 | childPrim.LocalID, childPrim.PhysBody.AddrString, |
200 | rootPrim.Position, childPrim.Position, midPoint); | 184 | rootPrim.Position, childPrim.Position, midPoint); |
201 | 185 | ||
202 | // create a constraint that allows no freedom of movement between the two objects | 186 | // create a constraint that allows no freedom of movement between the two objects |
@@ -239,14 +223,14 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
239 | constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero); | 223 | constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero); |
240 | 224 | ||
241 | // tweek the constraint to increase stability | 225 | // tweek the constraint to increase stability |
242 | constrain.UseFrameOffset(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintUseFrameOffset)); | 226 | constrain.UseFrameOffset(BSParam.LinkConstraintUseFrameOffset); |
243 | constrain.TranslationalLimitMotor(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintEnableTransMotor), | 227 | constrain.TranslationalLimitMotor(BSParam.LinkConstraintEnableTransMotor, |
244 | PhysicsScene.Params.linkConstraintTransMotorMaxVel, | 228 | BSParam.LinkConstraintTransMotorMaxVel, |
245 | PhysicsScene.Params.linkConstraintTransMotorMaxForce); | 229 | BSParam.LinkConstraintTransMotorMaxForce); |
246 | constrain.SetCFMAndERP(PhysicsScene.Params.linkConstraintCFM, PhysicsScene.Params.linkConstraintERP); | 230 | constrain.SetCFMAndERP(BSParam.LinkConstraintCFM, BSParam.LinkConstraintERP); |
247 | if (PhysicsScene.Params.linkConstraintSolverIterations != 0f) | 231 | if (BSParam.LinkConstraintSolverIterations != 0f) |
248 | { | 232 | { |
249 | constrain.SetSolverIterations(PhysicsScene.Params.linkConstraintSolverIterations); | 233 | constrain.SetSolverIterations(BSParam.LinkConstraintSolverIterations); |
250 | } | 234 | } |
251 | return constrain; | 235 | return constrain; |
252 | } | 236 | } |
@@ -255,19 +239,19 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
255 | // The root and child bodies are passed in because we need to remove the constraint between | 239 | // The root and child bodies are passed in because we need to remove the constraint between |
256 | // the bodies that were present at unlink time. | 240 | // the bodies that were present at unlink time. |
257 | // Called at taint time! | 241 | // Called at taint time! |
258 | private bool PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BSPhysObject childPrim) | 242 | private bool PhysicallyUnlinkAChildFromRoot(BSPrimLinkable rootPrim, BSPrimLinkable childPrim) |
259 | { | 243 | { |
260 | bool ret = false; | 244 | bool ret = false; |
261 | DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}", | 245 | DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}", |
262 | rootPrim.LocalID, | 246 | rootPrim.LocalID, |
263 | rootPrim.LocalID, rootPrim.PhysBody.ptr.ToString("X"), | 247 | rootPrim.LocalID, rootPrim.PhysBody.AddrString, |
264 | childPrim.LocalID, childPrim.PhysBody.ptr.ToString("X")); | 248 | childPrim.LocalID, childPrim.PhysBody.AddrString); |
265 | 249 | ||
266 | // Find the constraint for this link and get rid of it from the overall collection and from my list | 250 | // Find the constraint for this link and get rid of it from the overall collection and from my list |
267 | if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody)) | 251 | if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody)) |
268 | { | 252 | { |
269 | // Make the child refresh its location | 253 | // Make the child refresh its location |
270 | BulletSimAPI.PushUpdate2(childPrim.PhysBody.ptr); | 254 | PhysicsScene.PE.PushUpdate(childPrim.PhysBody); |
271 | ret = true; | 255 | ret = true; |
272 | } | 256 | } |
273 | 257 | ||
@@ -277,7 +261,7 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
277 | // Remove linkage between myself and any possible children I might have. | 261 | // Remove linkage between myself and any possible children I might have. |
278 | // Returns 'true' of any constraints were destroyed. | 262 | // Returns 'true' of any constraints were destroyed. |
279 | // Called at taint time! | 263 | // Called at taint time! |
280 | private bool PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim) | 264 | private bool PhysicallyUnlinkAllChildrenFromRoot(BSPrimLinkable rootPrim) |
281 | { | 265 | { |
282 | DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID); | 266 | DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID); |
283 | 267 | ||
@@ -292,20 +276,17 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
292 | private void RecomputeLinksetConstraints() | 276 | private void RecomputeLinksetConstraints() |
293 | { | 277 | { |
294 | float linksetMass = LinksetMass; | 278 | float linksetMass = LinksetMass; |
295 | LinksetRoot.UpdatePhysicalMassProperties(linksetMass); | 279 | LinksetRoot.UpdatePhysicalMassProperties(linksetMass, true); |
296 | 280 | ||
297 | // DEBUG: see of inter-linkset collisions are causing problems | ||
298 | // BulletSimAPI.SetCollisionFilterMask2(LinksetRoot.BSBody.ptr, | ||
299 | // (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask); | ||
300 | DetailLog("{0},BSLinksetConstraint.RecomputeLinksetConstraints,set,rBody={1},linksetMass={2}", | 281 | DetailLog("{0},BSLinksetConstraint.RecomputeLinksetConstraints,set,rBody={1},linksetMass={2}", |
301 | LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"), linksetMass); | 282 | LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, linksetMass); |
302 | 283 | ||
303 | foreach (BSPhysObject child in m_children) | 284 | foreach (BSPrimLinkable child in m_children) |
304 | { | 285 | { |
305 | // A child in the linkset physically shows the mass of the whole linkset. | 286 | // A child in the linkset physically shows the mass of the whole linkset. |
306 | // This allows Bullet to apply enough force on the child to move the whole linkset. | 287 | // This allows Bullet to apply enough force on the child to move the whole linkset. |
307 | // (Also do the mass stuff before recomputing the constraint so mass is not zero.) | 288 | // (Also do the mass stuff before recomputing the constraint so mass is not zero.) |
308 | child.UpdatePhysicalMassProperties(linksetMass); | 289 | child.UpdatePhysicalMassProperties(linksetMass, true); |
309 | 290 | ||
310 | BSConstraint constrain; | 291 | BSConstraint constrain; |
311 | if (!PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain)) | 292 | if (!PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain)) |
@@ -315,11 +296,7 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
315 | } | 296 | } |
316 | constrain.RecomputeConstraintVariables(linksetMass); | 297 | constrain.RecomputeConstraintVariables(linksetMass); |
317 | 298 | ||
318 | // DEBUG: see of inter-linkset collisions are causing problems | 299 | // PhysicsScene.PE.DumpConstraint(PhysicsScene.World, constrain.Constraint); // DEBUG DEBUG |
319 | // BulletSimAPI.SetCollisionFilterMask2(child.BSBody.ptr, | ||
320 | // (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask); | ||
321 | |||
322 | // BulletSimAPI.DumpConstraint2(PhysicsScene.World.ptr, constrain.Constraint.ptr); // DEBUG DEBUG | ||
323 | } | 300 | } |
324 | 301 | ||
325 | } | 302 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs new file mode 100755 index 0000000..ee77d6e --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs | |||
@@ -0,0 +1,203 @@ | |||
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 copyrightD | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Text; | ||
30 | using System.Reflection; | ||
31 | using Nini.Config; | ||
32 | |||
33 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
34 | { | ||
35 | |||
36 | public struct MaterialAttributes | ||
37 | { | ||
38 | // Material type values that correspond with definitions for LSL | ||
39 | public enum Material : int | ||
40 | { | ||
41 | Stone = 0, | ||
42 | Metal, | ||
43 | Glass, | ||
44 | Wood, | ||
45 | Flesh, | ||
46 | Plastic, | ||
47 | Rubber, | ||
48 | Light, | ||
49 | // Hereafter are BulletSim additions | ||
50 | Avatar, | ||
51 | NumberOfTypes // the count of types in the enum. | ||
52 | } | ||
53 | |||
54 | // Names must be in the order of the above enum. | ||
55 | // These names must coorespond to the lower case field names in the MaterialAttributes | ||
56 | // structure as reflection is used to select the field to put the value in. | ||
57 | public static readonly string[] MaterialAttribs = { "Density", "Friction", "Restitution"}; | ||
58 | |||
59 | public MaterialAttributes(string t, float d, float f, float r) | ||
60 | { | ||
61 | type = t; | ||
62 | density = d; | ||
63 | friction = f; | ||
64 | restitution = r; | ||
65 | } | ||
66 | public string type; | ||
67 | public float density; | ||
68 | public float friction; | ||
69 | public float restitution; | ||
70 | } | ||
71 | |||
72 | public static class BSMaterials | ||
73 | { | ||
74 | // Attributes for each material type | ||
75 | private static readonly MaterialAttributes[] Attributes; | ||
76 | |||
77 | // Map of material name to material type code | ||
78 | public static readonly Dictionary<string, MaterialAttributes.Material> MaterialMap; | ||
79 | |||
80 | static BSMaterials() | ||
81 | { | ||
82 | // Attribute sets for both the non-physical and physical instances of materials. | ||
83 | Attributes = new MaterialAttributes[(int)MaterialAttributes.Material.NumberOfTypes * 2]; | ||
84 | |||
85 | // Map of name to type code. | ||
86 | MaterialMap = new Dictionary<string, MaterialAttributes.Material>(); | ||
87 | MaterialMap.Add("Stone", MaterialAttributes.Material.Stone); | ||
88 | MaterialMap.Add("Metal", MaterialAttributes.Material.Metal); | ||
89 | MaterialMap.Add("Glass", MaterialAttributes.Material.Glass); | ||
90 | MaterialMap.Add("Wood", MaterialAttributes.Material.Wood); | ||
91 | MaterialMap.Add("Flesh", MaterialAttributes.Material.Flesh); | ||
92 | MaterialMap.Add("Plastic", MaterialAttributes.Material.Plastic); | ||
93 | MaterialMap.Add("Rubber", MaterialAttributes.Material.Rubber); | ||
94 | MaterialMap.Add("Light", MaterialAttributes.Material.Light); | ||
95 | MaterialMap.Add("Avatar", MaterialAttributes.Material.Avatar); | ||
96 | } | ||
97 | |||
98 | // This is where all the default material attributes are defined. | ||
99 | public static void InitializeFromDefaults(ConfigurationParameters parms) | ||
100 | { | ||
101 | // Values from http://wiki.secondlife.com/wiki/PRIM_MATERIAL | ||
102 | float dDensity = parms.defaultDensity; | ||
103 | float dFriction = parms.defaultFriction; | ||
104 | float dRestitution = parms.defaultRestitution; | ||
105 | Attributes[(int)MaterialAttributes.Material.Stone] = | ||
106 | new MaterialAttributes("stone",dDensity, 0.8f, 0.4f); | ||
107 | Attributes[(int)MaterialAttributes.Material.Metal] = | ||
108 | new MaterialAttributes("metal",dDensity, 0.3f, 0.4f); | ||
109 | Attributes[(int)MaterialAttributes.Material.Glass] = | ||
110 | new MaterialAttributes("glass",dDensity, 0.2f, 0.7f); | ||
111 | Attributes[(int)MaterialAttributes.Material.Wood] = | ||
112 | new MaterialAttributes("wood",dDensity, 0.6f, 0.5f); | ||
113 | Attributes[(int)MaterialAttributes.Material.Flesh] = | ||
114 | new MaterialAttributes("flesh",dDensity, 0.9f, 0.3f); | ||
115 | Attributes[(int)MaterialAttributes.Material.Plastic] = | ||
116 | new MaterialAttributes("plastic",dDensity, 0.4f, 0.7f); | ||
117 | Attributes[(int)MaterialAttributes.Material.Rubber] = | ||
118 | new MaterialAttributes("rubber",dDensity, 0.9f, 0.9f); | ||
119 | Attributes[(int)MaterialAttributes.Material.Light] = | ||
120 | new MaterialAttributes("light",dDensity, dFriction, dRestitution); | ||
121 | Attributes[(int)MaterialAttributes.Material.Avatar] = | ||
122 | new MaterialAttributes("avatar",3.5f, 0.2f, 0f); | ||
123 | |||
124 | Attributes[(int)MaterialAttributes.Material.Stone + (int)MaterialAttributes.Material.NumberOfTypes] = | ||
125 | new MaterialAttributes("stonePhysical",dDensity, 0.8f, 0.4f); | ||
126 | Attributes[(int)MaterialAttributes.Material.Metal + (int)MaterialAttributes.Material.NumberOfTypes] = | ||
127 | new MaterialAttributes("metalPhysical",dDensity, 0.3f, 0.4f); | ||
128 | Attributes[(int)MaterialAttributes.Material.Glass + (int)MaterialAttributes.Material.NumberOfTypes] = | ||
129 | new MaterialAttributes("glassPhysical",dDensity, 0.2f, 0.7f); | ||
130 | Attributes[(int)MaterialAttributes.Material.Wood + (int)MaterialAttributes.Material.NumberOfTypes] = | ||
131 | new MaterialAttributes("woodPhysical",dDensity, 0.6f, 0.5f); | ||
132 | Attributes[(int)MaterialAttributes.Material.Flesh + (int)MaterialAttributes.Material.NumberOfTypes] = | ||
133 | new MaterialAttributes("fleshPhysical",dDensity, 0.9f, 0.3f); | ||
134 | Attributes[(int)MaterialAttributes.Material.Plastic + (int)MaterialAttributes.Material.NumberOfTypes] = | ||
135 | new MaterialAttributes("plasticPhysical",dDensity, 0.4f, 0.7f); | ||
136 | Attributes[(int)MaterialAttributes.Material.Rubber + (int)MaterialAttributes.Material.NumberOfTypes] = | ||
137 | new MaterialAttributes("rubberPhysical",dDensity, 0.9f, 0.9f); | ||
138 | Attributes[(int)MaterialAttributes.Material.Light + (int)MaterialAttributes.Material.NumberOfTypes] = | ||
139 | new MaterialAttributes("lightPhysical",dDensity, dFriction, dRestitution); | ||
140 | Attributes[(int)MaterialAttributes.Material.Avatar + (int)MaterialAttributes.Material.NumberOfTypes] = | ||
141 | new MaterialAttributes("avatarPhysical",3.5f, 0.2f, 0f); | ||
142 | } | ||
143 | |||
144 | // Under the [BulletSim] section, one can change the individual material | ||
145 | // attribute values. The format of the configuration parameter is: | ||
146 | // <materialName><Attribute>["Physical"] = floatValue | ||
147 | // For instance: | ||
148 | // [BulletSim] | ||
149 | // StoneFriction = 0.2 | ||
150 | // FleshRestitutionPhysical = 0.8 | ||
151 | // Materials can have different parameters for their static and | ||
152 | // physical instantiations. When setting the non-physical value, | ||
153 | // both values are changed. Setting the physical value only changes | ||
154 | // the physical value. | ||
155 | public static void InitializefromParameters(IConfig pConfig) | ||
156 | { | ||
157 | foreach (KeyValuePair<string, MaterialAttributes.Material> kvp in MaterialMap) | ||
158 | { | ||
159 | string matName = kvp.Key; | ||
160 | foreach (string attribName in MaterialAttributes.MaterialAttribs) | ||
161 | { | ||
162 | string paramName = matName + attribName; | ||
163 | if (pConfig.Contains(paramName)) | ||
164 | { | ||
165 | float paramValue = pConfig.GetFloat(paramName); | ||
166 | SetAttributeValue((int)kvp.Value, attribName, paramValue); | ||
167 | // set the physical value also | ||
168 | SetAttributeValue((int)kvp.Value + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue); | ||
169 | } | ||
170 | paramName += "Physical"; | ||
171 | if (pConfig.Contains(paramName)) | ||
172 | { | ||
173 | float paramValue = pConfig.GetFloat(paramName); | ||
174 | SetAttributeValue((int)kvp.Value + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue); | ||
175 | } | ||
176 | } | ||
177 | } | ||
178 | } | ||
179 | |||
180 | // Use reflection to set the value in the attribute structure. | ||
181 | private static void SetAttributeValue(int matType, string attribName, float val) | ||
182 | { | ||
183 | // Get the current attribute values for this material | ||
184 | MaterialAttributes thisAttrib = Attributes[matType]; | ||
185 | // Find the field for the passed attribute name (eg, find field named 'friction') | ||
186 | FieldInfo fieldInfo = thisAttrib.GetType().GetField(attribName.ToLower()); | ||
187 | if (fieldInfo != null) | ||
188 | { | ||
189 | fieldInfo.SetValue(thisAttrib, val); | ||
190 | // Copy new attributes back to array -- since MaterialAttributes is 'struct', passed by value, not reference. | ||
191 | Attributes[matType] = thisAttrib; | ||
192 | } | ||
193 | } | ||
194 | |||
195 | // Given a material type, return a structure of attributes. | ||
196 | public static MaterialAttributes GetAttributes(MaterialAttributes.Material type, bool isPhysical) | ||
197 | { | ||
198 | int ind = (int)type; | ||
199 | if (isPhysical) ind += (int)MaterialAttributes.Material.NumberOfTypes; | ||
200 | return Attributes[ind]; | ||
201 | } | ||
202 | } | ||
203 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs index bc6e4c4..9501e2d 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs | |||
@@ -1,104 +1,486 @@ | |||
1 | using System; | 1 | /* |
2 | using System.Collections.Generic; | 2 | * Copyright (c) Contributors, http://opensimulator.org/ |
3 | using System.Text; | 3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. |
4 | using OpenMetaverse; | 4 | * |
5 | 5 | * Redistribution and use in source and binary forms, with or without | |
6 | namespace OpenSim.Region.Physics.BulletSPlugin | 6 | * modification, are permitted provided that the following conditions are met: |
7 | { | 7 | * * Redistributions of source code must retain the above copyright |
8 | public abstract class BSMotor | 8 | * notice, this list of conditions and the following disclaimer. |
9 | { | 9 | * * Redistributions in binary form must reproduce the above copyright |
10 | public virtual void Reset() { } | 10 | * notice, this list of conditions and the following disclaimer in the |
11 | public virtual void Zero() { } | 11 | * documentation and/or other materials provided with the distribution. |
12 | } | 12 | * * Neither the name of the OpenSimulator Project nor the |
13 | // Can all the incremental stepping be replaced with motor classes? | 13 | * names of its contributors may be used to endorse or promote products |
14 | public class BSVMotor : BSMotor | 14 | * derived from this software without specific prior written permission. |
15 | { | 15 | * |
16 | public Vector3 FrameOfReference { get; set; } | 16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY |
17 | public Vector3 Offset { get; set; } | 17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
18 | 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
19 | public float TimeScale { get; set; } | 19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY |
20 | public float TargetValueDecayTimeScale { get; set; } | 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
21 | public Vector3 CurrentValueReductionTimescale { get; set; } | 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
22 | public float Efficiency { get; set; } | 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
23 | 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
24 | public Vector3 TargetValue { get; private set; } | 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
25 | public Vector3 CurrentValue { get; private set; } | 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | 26 | * | |
27 | 27 | */ | |
28 | 28 | using System; | |
29 | BSVMotor(float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency) | 29 | using System.Collections.Generic; |
30 | { | 30 | using System.Text; |
31 | TimeScale = timeScale; | 31 | using OpenMetaverse; |
32 | TargetValueDecayTimeScale = decayTimeScale; | 32 | using OpenSim.Framework; |
33 | CurrentValueReductionTimescale = frictionTimeScale; | 33 | |
34 | Efficiency = efficiency; | 34 | namespace OpenSim.Region.Physics.BulletSPlugin |
35 | } | 35 | { |
36 | public void SetCurrent(Vector3 current) | 36 | public abstract class BSMotor |
37 | { | 37 | { |
38 | CurrentValue = current; | 38 | // Timescales and other things can be turned off by setting them to 'infinite'. |
39 | } | 39 | public const float Infinite = 12345.6f; |
40 | public void SetTarget(Vector3 target) | 40 | public readonly static Vector3 InfiniteVector = new Vector3(BSMotor.Infinite, BSMotor.Infinite, BSMotor.Infinite); |
41 | { | 41 | |
42 | TargetValue = target; | 42 | public BSMotor(string useName) |
43 | } | 43 | { |
44 | public Vector3 Step(float timeStep) | 44 | UseName = useName; |
45 | { | 45 | PhysicsScene = null; |
46 | if (CurrentValue.LengthSquared() > 0.001f) | 46 | Enabled = true; |
47 | { | 47 | } |
48 | // Vector3 origDir = Target; // DEBUG | 48 | public virtual bool Enabled { get; set; } |
49 | // Vector3 origVel = CurrentValue; // DEBUG | 49 | public virtual void Reset() { } |
50 | 50 | public virtual void Zero() { } | |
51 | // Add (desiredVelocity - currentAppliedVelocity) / howLongItShouldTakeToComplete | 51 | public virtual void GenerateTestOutput(float timeStep) { } |
52 | Vector3 addAmount = (TargetValue - CurrentValue)/(TargetValue) * timeStep; | 52 | |
53 | CurrentValue += addAmount; | 53 | // A name passed at motor creation for easily identifyable debugging messages. |
54 | 54 | public string UseName { get; private set; } | |
55 | float decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep; | 55 | |
56 | TargetValue *= (1f - decayFactor); | 56 | // Used only for outputting debug information. Might not be set so check for null. |
57 | 57 | public BSScene PhysicsScene { get; set; } | |
58 | Vector3 frictionFactor = (Vector3.One / CurrentValueReductionTimescale) * timeStep; | 58 | protected void MDetailLog(string msg, params Object[] parms) |
59 | CurrentValue *= (Vector3.One - frictionFactor); | 59 | { |
60 | } | 60 | if (PhysicsScene != null) |
61 | else | 61 | { |
62 | { | 62 | PhysicsScene.DetailLog(msg, parms); |
63 | // if what remains of direction is very small, zero it. | 63 | } |
64 | TargetValue = Vector3.Zero; | 64 | } |
65 | CurrentValue = Vector3.Zero; | 65 | } |
66 | 66 | ||
67 | // VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID); | 67 | // Motor which moves CurrentValue to TargetValue over TimeScale seconds. |
68 | } | 68 | // The TargetValue decays in TargetValueDecayTimeScale and |
69 | return CurrentValue; | 69 | // the CurrentValue will be held back by FrictionTimeScale. |
70 | } | 70 | // This motor will "zero itself" over time in that the targetValue will |
71 | } | 71 | // decay to zero and the currentValue will follow it to that zero. |
72 | 72 | // The overall effect is for the returned correction value to go from large | |
73 | public class BSFMotor : BSMotor | 73 | // values (the total difference between current and target minus friction) |
74 | { | 74 | // to small and eventually zero values. |
75 | public float TimeScale { get; set; } | 75 | // TimeScale and TargetDelayTimeScale may be 'infinite' which means no decay. |
76 | public float DecayTimeScale { get; set; } | 76 | |
77 | public float Friction { get; set; } | 77 | // For instance, if something is moving at speed X and the desired speed is Y, |
78 | public float Efficiency { get; set; } | 78 | // CurrentValue is X and TargetValue is Y. As the motor is stepped, new |
79 | 79 | // values of CurrentValue are returned that approach the TargetValue. | |
80 | public float Target { get; private set; } | 80 | // The feature of decaying TargetValue is so vehicles will eventually |
81 | public float CurrentValue { get; private set; } | 81 | // come to a stop rather than run forever. This can be disabled by |
82 | 82 | // setting TargetValueDecayTimescale to 'infinite'. | |
83 | BSFMotor(float timeScale, float decayTimescale, float friction, float efficiency) | 83 | // The change from CurrentValue to TargetValue is linear over TimeScale seconds. |
84 | { | 84 | public class BSVMotor : BSMotor |
85 | } | 85 | { |
86 | public void SetCurrent(float target) | 86 | // public Vector3 FrameOfReference { get; set; } |
87 | { | 87 | // public Vector3 Offset { get; set; } |
88 | } | 88 | |
89 | public void SetTarget(float target) | 89 | public virtual float TimeScale { get; set; } |
90 | { | 90 | public virtual float TargetValueDecayTimeScale { get; set; } |
91 | } | 91 | public virtual Vector3 FrictionTimescale { get; set; } |
92 | public float Step(float timeStep) | 92 | public virtual float Efficiency { get; set; } |
93 | { | 93 | |
94 | return 0f; | 94 | public virtual float ErrorZeroThreshold { get; set; } |
95 | } | 95 | |
96 | } | 96 | public virtual Vector3 TargetValue { get; protected set; } |
97 | public class BSPIDMotor : BSMotor | 97 | public virtual Vector3 CurrentValue { get; protected set; } |
98 | { | 98 | public virtual Vector3 LastError { get; protected set; } |
99 | // TODO: write and use this one | 99 | |
100 | BSPIDMotor() | 100 | public virtual bool ErrorIsZero() |
101 | { | 101 | { |
102 | } | 102 | return ErrorIsZero(LastError); |
103 | } | 103 | } |
104 | } | 104 | public virtual bool ErrorIsZero(Vector3 err) |
105 | { | ||
106 | return (err == Vector3.Zero || err.ApproxEquals(Vector3.Zero, ErrorZeroThreshold)); | ||
107 | } | ||
108 | |||
109 | public BSVMotor(string useName) | ||
110 | : base(useName) | ||
111 | { | ||
112 | TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite; | ||
113 | Efficiency = 1f; | ||
114 | FrictionTimescale = BSMotor.InfiniteVector; | ||
115 | CurrentValue = TargetValue = Vector3.Zero; | ||
116 | ErrorZeroThreshold = 0.001f; | ||
117 | } | ||
118 | public BSVMotor(string useName, float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency) | ||
119 | : this(useName) | ||
120 | { | ||
121 | TimeScale = timeScale; | ||
122 | TargetValueDecayTimeScale = decayTimeScale; | ||
123 | FrictionTimescale = frictionTimeScale; | ||
124 | Efficiency = efficiency; | ||
125 | CurrentValue = TargetValue = Vector3.Zero; | ||
126 | } | ||
127 | public void SetCurrent(Vector3 current) | ||
128 | { | ||
129 | CurrentValue = current; | ||
130 | } | ||
131 | public void SetTarget(Vector3 target) | ||
132 | { | ||
133 | TargetValue = target; | ||
134 | } | ||
135 | public override void Zero() | ||
136 | { | ||
137 | base.Zero(); | ||
138 | CurrentValue = TargetValue = Vector3.Zero; | ||
139 | } | ||
140 | |||
141 | // Compute the next step and return the new current value. | ||
142 | // Returns the correction needed to move 'current' to 'target'. | ||
143 | public virtual Vector3 Step(float timeStep) | ||
144 | { | ||
145 | if (!Enabled) return TargetValue; | ||
146 | |||
147 | Vector3 origTarget = TargetValue; // DEBUG | ||
148 | Vector3 origCurrVal = CurrentValue; // DEBUG | ||
149 | |||
150 | Vector3 correction = Vector3.Zero; | ||
151 | Vector3 error = TargetValue - CurrentValue; | ||
152 | LastError = error; | ||
153 | if (!ErrorIsZero(error)) | ||
154 | { | ||
155 | correction = StepError(timeStep, error); | ||
156 | |||
157 | CurrentValue += correction; | ||
158 | |||
159 | // The desired value reduces to zero which also reduces the difference with current. | ||
160 | // If the decay time is infinite, don't decay at all. | ||
161 | float decayFactor = 0f; | ||
162 | if (TargetValueDecayTimeScale != BSMotor.Infinite) | ||
163 | { | ||
164 | decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep; | ||
165 | TargetValue *= (1f - decayFactor); | ||
166 | } | ||
167 | |||
168 | // The amount we can correct the error is reduced by the friction | ||
169 | Vector3 frictionFactor = Vector3.Zero; | ||
170 | if (FrictionTimescale != BSMotor.InfiniteVector) | ||
171 | { | ||
172 | // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep; | ||
173 | // Individual friction components can be 'infinite' so compute each separately. | ||
174 | frictionFactor.X = (FrictionTimescale.X == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.X); | ||
175 | frictionFactor.Y = (FrictionTimescale.Y == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.Y); | ||
176 | frictionFactor.Z = (FrictionTimescale.Z == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.Z); | ||
177 | frictionFactor *= timeStep; | ||
178 | CurrentValue *= (Vector3.One - frictionFactor); | ||
179 | } | ||
180 | |||
181 | MDetailLog("{0}, BSVMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}", | ||
182 | BSScene.DetailLogZero, UseName, origCurrVal, origTarget, | ||
183 | timeStep, error, correction); | ||
184 | MDetailLog("{0}, BSVMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},frictTS={4},frictFact={5},tgt={6},curr={7}", | ||
185 | BSScene.DetailLogZero, UseName, | ||
186 | TargetValueDecayTimeScale, decayFactor, FrictionTimescale, frictionFactor, | ||
187 | TargetValue, CurrentValue); | ||
188 | } | ||
189 | else | ||
190 | { | ||
191 | // Difference between what we have and target is small. Motor is done. | ||
192 | if (TargetValue.ApproxEquals(Vector3.Zero, ErrorZeroThreshold)) | ||
193 | { | ||
194 | // The target can step down to nearly zero but not get there. If close to zero | ||
195 | // it is really zero. | ||
196 | TargetValue = Vector3.Zero; | ||
197 | } | ||
198 | CurrentValue = TargetValue; | ||
199 | MDetailLog("{0}, BSVMotor.Step,zero,{1},origTgt={2},origCurr={3},currTgt={4},currCurr={5}", | ||
200 | BSScene.DetailLogZero, UseName, origCurrVal, origTarget, TargetValue, CurrentValue); | ||
201 | } | ||
202 | |||
203 | return correction; | ||
204 | } | ||
205 | // version of step that sets the current value before doing the step | ||
206 | public virtual Vector3 Step(float timeStep, Vector3 current) | ||
207 | { | ||
208 | CurrentValue = current; | ||
209 | return Step(timeStep); | ||
210 | } | ||
211 | public virtual Vector3 StepError(float timeStep, Vector3 error) | ||
212 | { | ||
213 | if (!Enabled) return Vector3.Zero; | ||
214 | |||
215 | Vector3 returnCorrection = Vector3.Zero; | ||
216 | if (!ErrorIsZero(error)) | ||
217 | { | ||
218 | // correction = error / secondsItShouldTakeToCorrect | ||
219 | Vector3 correctionAmount; | ||
220 | if (TimeScale == 0f || TimeScale == BSMotor.Infinite) | ||
221 | correctionAmount = error * timeStep; | ||
222 | else | ||
223 | correctionAmount = error / TimeScale * timeStep; | ||
224 | |||
225 | returnCorrection = correctionAmount; | ||
226 | MDetailLog("{0}, BSVMotor.Step,nonZero,{1},timeStep={2},timeScale={3},err={4},corr={5}", | ||
227 | BSScene.DetailLogZero, UseName, timeStep, TimeScale, error, correctionAmount); | ||
228 | } | ||
229 | return returnCorrection; | ||
230 | } | ||
231 | |||
232 | // The user sets all the parameters and calls this which outputs values until error is zero. | ||
233 | public override void GenerateTestOutput(float timeStep) | ||
234 | { | ||
235 | // maximum number of outputs to generate. | ||
236 | int maxOutput = 50; | ||
237 | MDetailLog("{0},BSVMotor.Test,{1},===================================== BEGIN Test Output", BSScene.DetailLogZero, UseName); | ||
238 | MDetailLog("{0},BSVMotor.Test,{1},timeScale={2},targDlyTS={3},frictTS={4},eff={5},curr={6},tgt={7}", | ||
239 | BSScene.DetailLogZero, UseName, | ||
240 | TimeScale, TargetValueDecayTimeScale, FrictionTimescale, Efficiency, | ||
241 | CurrentValue, TargetValue); | ||
242 | |||
243 | LastError = BSMotor.InfiniteVector; | ||
244 | while (maxOutput-- > 0 && !LastError.ApproxEquals(Vector3.Zero, ErrorZeroThreshold)) | ||
245 | { | ||
246 | Vector3 lastStep = Step(timeStep); | ||
247 | MDetailLog("{0},BSVMotor.Test,{1},cur={2},tgt={3},lastError={4},lastStep={5}", | ||
248 | BSScene.DetailLogZero, UseName, CurrentValue, TargetValue, LastError, lastStep); | ||
249 | } | ||
250 | MDetailLog("{0},BSVMotor.Test,{1},===================================== END Test Output", BSScene.DetailLogZero, UseName); | ||
251 | |||
252 | |||
253 | } | ||
254 | |||
255 | public override string ToString() | ||
256 | { | ||
257 | return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4},frictTS={5}>", | ||
258 | UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale, FrictionTimescale); | ||
259 | } | ||
260 | } | ||
261 | |||
262 | // ============================================================================ | ||
263 | // ============================================================================ | ||
264 | public class BSFMotor : BSMotor | ||
265 | { | ||
266 | public virtual float TimeScale { get; set; } | ||
267 | public virtual float TargetValueDecayTimeScale { get; set; } | ||
268 | public virtual float FrictionTimescale { get; set; } | ||
269 | public virtual float Efficiency { get; set; } | ||
270 | |||
271 | public virtual float ErrorZeroThreshold { get; set; } | ||
272 | |||
273 | public virtual float TargetValue { get; protected set; } | ||
274 | public virtual float CurrentValue { get; protected set; } | ||
275 | public virtual float LastError { get; protected set; } | ||
276 | |||
277 | public virtual bool ErrorIsZero() | ||
278 | { | ||
279 | return ErrorIsZero(LastError); | ||
280 | } | ||
281 | public virtual bool ErrorIsZero(float err) | ||
282 | { | ||
283 | return (err >= -ErrorZeroThreshold && err <= ErrorZeroThreshold); | ||
284 | } | ||
285 | |||
286 | public BSFMotor(string useName, float timeScale, float decayTimescale, float friction, float efficiency) | ||
287 | : base(useName) | ||
288 | { | ||
289 | TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite; | ||
290 | Efficiency = 1f; | ||
291 | FrictionTimescale = BSMotor.Infinite; | ||
292 | CurrentValue = TargetValue = 0f; | ||
293 | ErrorZeroThreshold = 0.01f; | ||
294 | } | ||
295 | public void SetCurrent(float current) | ||
296 | { | ||
297 | CurrentValue = current; | ||
298 | } | ||
299 | public void SetTarget(float target) | ||
300 | { | ||
301 | TargetValue = target; | ||
302 | } | ||
303 | public override void Zero() | ||
304 | { | ||
305 | base.Zero(); | ||
306 | CurrentValue = TargetValue = 0f; | ||
307 | } | ||
308 | |||
309 | public virtual float Step(float timeStep) | ||
310 | { | ||
311 | if (!Enabled) return TargetValue; | ||
312 | |||
313 | float origTarget = TargetValue; // DEBUG | ||
314 | float origCurrVal = CurrentValue; // DEBUG | ||
315 | |||
316 | float correction = 0f; | ||
317 | float error = TargetValue - CurrentValue; | ||
318 | LastError = error; | ||
319 | if (!ErrorIsZero(error)) | ||
320 | { | ||
321 | correction = StepError(timeStep, error); | ||
322 | |||
323 | CurrentValue += correction; | ||
324 | |||
325 | // The desired value reduces to zero which also reduces the difference with current. | ||
326 | // If the decay time is infinite, don't decay at all. | ||
327 | float decayFactor = 0f; | ||
328 | if (TargetValueDecayTimeScale != BSMotor.Infinite) | ||
329 | { | ||
330 | decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep; | ||
331 | TargetValue *= (1f - decayFactor); | ||
332 | } | ||
333 | |||
334 | // The amount we can correct the error is reduced by the friction | ||
335 | float frictionFactor = 0f; | ||
336 | if (FrictionTimescale != BSMotor.Infinite) | ||
337 | { | ||
338 | // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep; | ||
339 | // Individual friction components can be 'infinite' so compute each separately. | ||
340 | frictionFactor = 1f / FrictionTimescale; | ||
341 | frictionFactor *= timeStep; | ||
342 | CurrentValue *= (1f - frictionFactor); | ||
343 | } | ||
344 | |||
345 | MDetailLog("{0}, BSFMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}", | ||
346 | BSScene.DetailLogZero, UseName, origCurrVal, origTarget, | ||
347 | timeStep, error, correction); | ||
348 | MDetailLog("{0}, BSFMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},frictTS={4},frictFact={5},tgt={6},curr={7}", | ||
349 | BSScene.DetailLogZero, UseName, | ||
350 | TargetValueDecayTimeScale, decayFactor, FrictionTimescale, frictionFactor, | ||
351 | TargetValue, CurrentValue); | ||
352 | } | ||
353 | else | ||
354 | { | ||
355 | // Difference between what we have and target is small. Motor is done. | ||
356 | if (Util.InRange<float>(TargetValue, -ErrorZeroThreshold, ErrorZeroThreshold)) | ||
357 | { | ||
358 | // The target can step down to nearly zero but not get there. If close to zero | ||
359 | // it is really zero. | ||
360 | TargetValue = 0f; | ||
361 | } | ||
362 | CurrentValue = TargetValue; | ||
363 | MDetailLog("{0}, BSFMotor.Step,zero,{1},origTgt={2},origCurr={3},ret={4}", | ||
364 | BSScene.DetailLogZero, UseName, origCurrVal, origTarget, CurrentValue); | ||
365 | } | ||
366 | |||
367 | return CurrentValue; | ||
368 | } | ||
369 | |||
370 | public virtual float StepError(float timeStep, float error) | ||
371 | { | ||
372 | if (!Enabled) return 0f; | ||
373 | |||
374 | float returnCorrection = 0f; | ||
375 | if (!ErrorIsZero(error)) | ||
376 | { | ||
377 | // correction = error / secondsItShouldTakeToCorrect | ||
378 | float correctionAmount; | ||
379 | if (TimeScale == 0f || TimeScale == BSMotor.Infinite) | ||
380 | correctionAmount = error * timeStep; | ||
381 | else | ||
382 | correctionAmount = error / TimeScale * timeStep; | ||
383 | |||
384 | returnCorrection = correctionAmount; | ||
385 | MDetailLog("{0}, BSFMotor.Step,nonZero,{1},timeStep={2},timeScale={3},err={4},corr={5}", | ||
386 | BSScene.DetailLogZero, UseName, timeStep, TimeScale, error, correctionAmount); | ||
387 | } | ||
388 | return returnCorrection; | ||
389 | } | ||
390 | |||
391 | public override string ToString() | ||
392 | { | ||
393 | return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4},frictTS={5}>", | ||
394 | UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale, FrictionTimescale); | ||
395 | } | ||
396 | |||
397 | } | ||
398 | |||
399 | // ============================================================================ | ||
400 | // ============================================================================ | ||
401 | // Proportional, Integral, Derivitive Motor | ||
402 | // Good description at http://www.answers.com/topic/pid-controller . Includes processes for choosing p, i and d factors. | ||
403 | public class BSPIDVMotor : BSVMotor | ||
404 | { | ||
405 | // Larger makes more overshoot, smaller means converge quicker. Range of 0.1 to 10. | ||
406 | public Vector3 proportionFactor { get; set; } | ||
407 | public Vector3 integralFactor { get; set; } | ||
408 | public Vector3 derivFactor { get; set; } | ||
409 | |||
410 | // The factors are vectors for the three dimensions. This is the proportional of each | ||
411 | // that is applied. This could be multiplied through the actual factors but it | ||
412 | // is sometimes easier to manipulate the factors and their mix separately. | ||
413 | // to | ||
414 | public Vector3 FactorMix; | ||
415 | |||
416 | // Arbritrary factor range. | ||
417 | // EfficiencyHigh means move quickly to the correct number. EfficiencyLow means might over correct. | ||
418 | public float EfficiencyHigh = 0.4f; | ||
419 | public float EfficiencyLow = 4.0f; | ||
420 | |||
421 | // Running integration of the error | ||
422 | Vector3 RunningIntegration { get; set; } | ||
423 | |||
424 | public BSPIDVMotor(string useName) | ||
425 | : base(useName) | ||
426 | { | ||
427 | proportionFactor = new Vector3(1.00f, 1.00f, 1.00f); | ||
428 | integralFactor = new Vector3(1.00f, 1.00f, 1.00f); | ||
429 | derivFactor = new Vector3(1.00f, 1.00f, 1.00f); | ||
430 | FactorMix = new Vector3(0.5f, 0.25f, 0.25f); | ||
431 | RunningIntegration = Vector3.Zero; | ||
432 | LastError = Vector3.Zero; | ||
433 | } | ||
434 | |||
435 | public override void Zero() | ||
436 | { | ||
437 | base.Zero(); | ||
438 | } | ||
439 | |||
440 | public override float Efficiency | ||
441 | { | ||
442 | get { return base.Efficiency; } | ||
443 | set | ||
444 | { | ||
445 | base.Efficiency = Util.Clamp(value, 0f, 1f); | ||
446 | |||
447 | // Compute factors based on efficiency. | ||
448 | // If efficiency is high (1f), use a factor value that moves the error value to zero with little overshoot. | ||
449 | // If efficiency is low (0f), use a factor value that overcorrects. | ||
450 | // TODO: might want to vary contribution of different factor depending on efficiency. | ||
451 | float factor = ((1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow) / 3f; | ||
452 | // float factor = (1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow; | ||
453 | |||
454 | proportionFactor = new Vector3(factor, factor, factor); | ||
455 | integralFactor = new Vector3(factor, factor, factor); | ||
456 | derivFactor = new Vector3(factor, factor, factor); | ||
457 | |||
458 | MDetailLog("{0},BSPIDVMotor.setEfficiency,eff={1},factor={2}", BSScene.DetailLogZero, Efficiency, factor); | ||
459 | } | ||
460 | } | ||
461 | |||
462 | // Advance the PID computation on this error. | ||
463 | public override Vector3 StepError(float timeStep, Vector3 error) | ||
464 | { | ||
465 | if (!Enabled) return Vector3.Zero; | ||
466 | |||
467 | // Add up the error so we can integrate over the accumulated errors | ||
468 | RunningIntegration += error * timeStep; | ||
469 | |||
470 | // A simple derivitive is the rate of change from the last error. | ||
471 | Vector3 derivitive = (error - LastError) * timeStep; | ||
472 | LastError = error; | ||
473 | |||
474 | // Correction = (proportionOfPresentError + accumulationOfPastError + rateOfChangeOfError) | ||
475 | Vector3 ret = error * timeStep * proportionFactor * FactorMix.X | ||
476 | + RunningIntegration * integralFactor * FactorMix.Y | ||
477 | + derivitive * derivFactor * FactorMix.Z | ||
478 | ; | ||
479 | |||
480 | MDetailLog("{0},BSPIDVMotor.step,ts={1},err={2},runnInt={3},deriv={4},ret={5}", | ||
481 | BSScene.DetailLogZero, timeStep, error, RunningIntegration, derivitive, ret); | ||
482 | |||
483 | return ret; | ||
484 | } | ||
485 | } | ||
486 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs new file mode 100755 index 0000000..385ed9e --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs | |||
@@ -0,0 +1,815 @@ | |||
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 copyrightD | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Text; | ||
30 | |||
31 | using OpenSim.Region.Physics.Manager; | ||
32 | |||
33 | using OpenMetaverse; | ||
34 | using Nini.Config; | ||
35 | |||
36 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
37 | { | ||
38 | public static class BSParam | ||
39 | { | ||
40 | private static string LogHeader = "[BULLETSIM PARAMETERS]"; | ||
41 | |||
42 | // Tuning notes: | ||
43 | // From: http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=6575 | ||
44 | // Contact points can be added even if the distance is positive. The constraint solver can deal with | ||
45 | // contacts with positive distances as well as negative (penetration). Contact points are discarded | ||
46 | // if the distance exceeds a certain threshold. | ||
47 | // Bullet has a contact processing threshold and a contact breaking threshold. | ||
48 | // If the distance is larger than the contact breaking threshold, it will be removed after one frame. | ||
49 | // If the distance is larger than the contact processing threshold, the constraint solver will ignore it. | ||
50 | |||
51 | // This is separate/independent from the collision margin. The collision margin increases the object a bit | ||
52 | // to improve collision detection performance and accuracy. | ||
53 | // =================== | ||
54 | // From: | ||
55 | |||
56 | // Level of Detail values kept as float because that's what the Meshmerizer wants | ||
57 | public static float MeshLOD { get; private set; } | ||
58 | public static float MeshCircularLOD { get; private set; } | ||
59 | public static float MeshMegaPrimLOD { get; private set; } | ||
60 | public static float MeshMegaPrimThreshold { get; private set; } | ||
61 | public static float SculptLOD { get; private set; } | ||
62 | |||
63 | public static int CrossingFailuresBeforeOutOfBounds { get; private set; } | ||
64 | public static float UpdateVelocityChangeThreshold { get; private set; } | ||
65 | |||
66 | public static float MinimumObjectMass { get; private set; } | ||
67 | public static float MaximumObjectMass { get; private set; } | ||
68 | public static float MaxLinearVelocity { get; private set; } | ||
69 | public static float MaxLinearVelocitySquared { get; private set; } | ||
70 | public static float MaxAngularVelocity { get; private set; } | ||
71 | public static float MaxAngularVelocitySquared { get; private set; } | ||
72 | public static float MaxAddForceMagnitude { get; private set; } | ||
73 | public static float MaxAddForceMagnitudeSquared { get; private set; } | ||
74 | public static float DensityScaleFactor { get; private set; } | ||
75 | |||
76 | public static float LinearDamping { get; private set; } | ||
77 | public static float AngularDamping { get; private set; } | ||
78 | public static float DeactivationTime { get; private set; } | ||
79 | public static float LinearSleepingThreshold { get; private set; } | ||
80 | public static float AngularSleepingThreshold { get; private set; } | ||
81 | public static float CcdMotionThreshold { get; private set; } | ||
82 | public static float CcdSweptSphereRadius { get; private set; } | ||
83 | public static float ContactProcessingThreshold { get; private set; } | ||
84 | |||
85 | public static bool ShouldMeshSculptedPrim { get; private set; } // cause scuplted prims to get meshed | ||
86 | public static bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes | ||
87 | public static bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects | ||
88 | public static bool ShouldRemoveZeroWidthTriangles { get; private set; } | ||
89 | |||
90 | public static float TerrainImplementation { get; private set; } | ||
91 | public static int TerrainMeshMagnification { get; private set; } | ||
92 | public static float TerrainFriction { get; private set; } | ||
93 | public static float TerrainHitFraction { get; private set; } | ||
94 | public static float TerrainRestitution { get; private set; } | ||
95 | public static float TerrainContactProcessingThreshold { get; private set; } | ||
96 | public static float TerrainCollisionMargin { get; private set; } | ||
97 | |||
98 | public static float DefaultFriction { get; private set; } | ||
99 | public static float DefaultDensity { get; private set; } | ||
100 | public static float DefaultRestitution { get; private set; } | ||
101 | public static float CollisionMargin { get; private set; } | ||
102 | public static float Gravity { get; private set; } | ||
103 | |||
104 | // Physics Engine operation | ||
105 | public static float MaxPersistantManifoldPoolSize { get; private set; } | ||
106 | public static float MaxCollisionAlgorithmPoolSize { get; private set; } | ||
107 | public static bool ShouldDisableContactPoolDynamicAllocation { get; private set; } | ||
108 | public static bool ShouldForceUpdateAllAabbs { get; private set; } | ||
109 | public static bool ShouldRandomizeSolverOrder { get; private set; } | ||
110 | public static bool ShouldSplitSimulationIslands { get; private set; } | ||
111 | public static bool ShouldEnableFrictionCaching { get; private set; } | ||
112 | public static float NumberOfSolverIterations { get; private set; } | ||
113 | public static bool UseSingleSidedMeshes { get; private set; } | ||
114 | public static float GlobalContactBreakingThreshold { get; private set; } | ||
115 | |||
116 | // Avatar parameters | ||
117 | public static float AvatarFriction { get; private set; } | ||
118 | public static float AvatarStandingFriction { get; private set; } | ||
119 | public static float AvatarAlwaysRunFactor { get; private set; } | ||
120 | public static float AvatarDensity { get; private set; } | ||
121 | public static float AvatarRestitution { get; private set; } | ||
122 | public static float AvatarCapsuleWidth { get; private set; } | ||
123 | public static float AvatarCapsuleDepth { get; private set; } | ||
124 | public static float AvatarCapsuleHeight { get; private set; } | ||
125 | public static float AvatarContactProcessingThreshold { get; private set; } | ||
126 | public static float AvatarBelowGroundUpCorrectionMeters { get; private set; } | ||
127 | public static float AvatarStepHeight { get; private set; } | ||
128 | public static float AvatarStepApproachFactor { get; private set; } | ||
129 | public static float AvatarStepForceFactor { get; private set; } | ||
130 | |||
131 | // Vehicle parameters | ||
132 | public static float VehicleMaxLinearVelocity { get; private set; } | ||
133 | public static float VehicleMaxLinearVelocitySquared { get; private set; } | ||
134 | public static float VehicleMaxAngularVelocity { get; private set; } | ||
135 | public static float VehicleMaxAngularVelocitySq { get; private set; } | ||
136 | public static float VehicleAngularDamping { get; private set; } | ||
137 | public static float VehicleFriction { get; private set; } | ||
138 | public static float VehicleRestitution { get; private set; } | ||
139 | public static Vector3 VehicleLinearFactor { get; private set; } | ||
140 | public static Vector3 VehicleAngularFactor { get; private set; } | ||
141 | public static float VehicleGroundGravityFudge { get; private set; } | ||
142 | public static float VehicleAngularBankingTimescaleFudge { get; private set; } | ||
143 | public static bool VehicleDebuggingEnabled { get; private set; } | ||
144 | |||
145 | // Convex Hulls | ||
146 | public static int CSHullMaxDepthSplit { get; private set; } | ||
147 | public static int CSHullMaxDepthSplitForSimpleShapes { get; private set; } | ||
148 | public static float CSHullConcavityThresholdPercent { get; private set; } | ||
149 | public static float CSHullVolumeConservationThresholdPercent { get; private set; } | ||
150 | public static int CSHullMaxVertices { get; private set; } | ||
151 | public static float CSHullMaxSkinWidth { get; private set; } | ||
152 | |||
153 | // Linkset implementation parameters | ||
154 | public static float LinksetImplementation { get; private set; } | ||
155 | public static bool LinkConstraintUseFrameOffset { get; private set; } | ||
156 | public static bool LinkConstraintEnableTransMotor { get; private set; } | ||
157 | public static float LinkConstraintTransMotorMaxVel { get; private set; } | ||
158 | public static float LinkConstraintTransMotorMaxForce { get; private set; } | ||
159 | public static float LinkConstraintERP { get; private set; } | ||
160 | public static float LinkConstraintCFM { get; private set; } | ||
161 | public static float LinkConstraintSolverIterations { get; private set; } | ||
162 | |||
163 | public static float PID_D { get; private set; } // derivative | ||
164 | public static float PID_P { get; private set; } // proportional | ||
165 | |||
166 | // Various constants that come from that other virtual world that shall not be named. | ||
167 | public const float MinGravityZ = -1f; | ||
168 | public const float MaxGravityZ = 28f; | ||
169 | public const float MinFriction = 0f; | ||
170 | public const float MaxFriction = 255f; | ||
171 | public const float MinDensity = 0.01f; | ||
172 | public const float MaxDensity = 22587f; | ||
173 | public const float MinRestitution = 0f; | ||
174 | public const float MaxRestitution = 1f; | ||
175 | |||
176 | // ===================================================================================== | ||
177 | // ===================================================================================== | ||
178 | |||
179 | // Base parameter definition that gets and sets parameter values via a string | ||
180 | public abstract class ParameterDefnBase | ||
181 | { | ||
182 | public string name; // string name of the parameter | ||
183 | public string desc; // a short description of what the parameter means | ||
184 | public ParameterDefnBase(string pName, string pDesc) | ||
185 | { | ||
186 | name = pName; | ||
187 | desc = pDesc; | ||
188 | } | ||
189 | // Set the parameter value to the default | ||
190 | public abstract void AssignDefault(BSScene s); | ||
191 | // Get the value as a string | ||
192 | public abstract string GetValue(BSScene s); | ||
193 | // Set the value to this string value | ||
194 | public abstract void SetValue(BSScene s, string valAsString); | ||
195 | // set the value on a particular object (usually sets in physics engine) | ||
196 | public abstract void SetOnObject(BSScene s, BSPhysObject obj); | ||
197 | public abstract bool HasSetOnObject { get; } | ||
198 | } | ||
199 | |||
200 | // Specific parameter definition for a parameter of a specific type. | ||
201 | public delegate T PGetValue<T>(BSScene s); | ||
202 | public delegate void PSetValue<T>(BSScene s, T val); | ||
203 | public delegate void PSetOnObject<T>(BSScene scene, BSPhysObject obj); | ||
204 | public sealed class ParameterDefn<T> : ParameterDefnBase | ||
205 | { | ||
206 | private T defaultValue; | ||
207 | private PSetValue<T> setter; | ||
208 | private PGetValue<T> getter; | ||
209 | private PSetOnObject<T> objectSet; | ||
210 | public ParameterDefn(string pName, string pDesc, T pDefault, PGetValue<T> pGetter, PSetValue<T> pSetter) | ||
211 | : base(pName, pDesc) | ||
212 | { | ||
213 | defaultValue = pDefault; | ||
214 | setter = pSetter; | ||
215 | getter = pGetter; | ||
216 | objectSet = null; | ||
217 | } | ||
218 | public ParameterDefn(string pName, string pDesc, T pDefault, PGetValue<T> pGetter, PSetValue<T> pSetter, PSetOnObject<T> pObjSetter) | ||
219 | : base(pName, pDesc) | ||
220 | { | ||
221 | defaultValue = pDefault; | ||
222 | setter = pSetter; | ||
223 | getter = pGetter; | ||
224 | objectSet = pObjSetter; | ||
225 | } | ||
226 | /* Wish I could simplify using this definition but CLR doesn't store references so closure around delegates of references won't work | ||
227 | public ParameterDefn(string pName, string pDesc, T pDefault, ref T loc) | ||
228 | : base(pName, pDesc) | ||
229 | { | ||
230 | defaultValue = pDefault; | ||
231 | setter = (s, v) => { loc = v; }; | ||
232 | getter = (s) => { return loc; }; | ||
233 | objectSet = null; | ||
234 | } | ||
235 | */ | ||
236 | public override void AssignDefault(BSScene s) | ||
237 | { | ||
238 | setter(s, defaultValue); | ||
239 | } | ||
240 | public override string GetValue(BSScene s) | ||
241 | { | ||
242 | return getter(s).ToString(); | ||
243 | } | ||
244 | public override void SetValue(BSScene s, string valAsString) | ||
245 | { | ||
246 | // Get the generic type of the setter | ||
247 | Type genericType = setter.GetType().GetGenericArguments()[0]; | ||
248 | // Find the 'Parse' method on that type | ||
249 | System.Reflection.MethodInfo parser = null; | ||
250 | try | ||
251 | { | ||
252 | parser = genericType.GetMethod("Parse", new Type[] { typeof(String) } ); | ||
253 | } | ||
254 | catch (Exception e) | ||
255 | { | ||
256 | s.Logger.ErrorFormat("{0} Exception getting parser for type '{1}': {2}", LogHeader, genericType, e); | ||
257 | parser = null; | ||
258 | } | ||
259 | if (parser != null) | ||
260 | { | ||
261 | // Parse the input string | ||
262 | try | ||
263 | { | ||
264 | T setValue = (T)parser.Invoke(genericType, new Object[] { valAsString }); | ||
265 | // Store the parsed value | ||
266 | setter(s, setValue); | ||
267 | // s.Logger.DebugFormat("{0} Parameter {1} = {2}", LogHeader, name, setValue); | ||
268 | } | ||
269 | catch | ||
270 | { | ||
271 | s.Logger.ErrorFormat("{0} Failed parsing parameter value '{1}' as type '{2}'", LogHeader, valAsString, genericType); | ||
272 | } | ||
273 | } | ||
274 | else | ||
275 | { | ||
276 | s.Logger.ErrorFormat("{0} Could not find parameter parser for type '{1}'", LogHeader, genericType); | ||
277 | } | ||
278 | } | ||
279 | public override bool HasSetOnObject | ||
280 | { | ||
281 | get { return objectSet != null; } | ||
282 | } | ||
283 | public override void SetOnObject(BSScene s, BSPhysObject obj) | ||
284 | { | ||
285 | if (objectSet != null) | ||
286 | objectSet(s, obj); | ||
287 | } | ||
288 | } | ||
289 | |||
290 | // List of all of the externally visible parameters. | ||
291 | // For each parameter, this table maps a text name to getter and setters. | ||
292 | // To add a new externally referencable/settable parameter, add the paramter storage | ||
293 | // location somewhere in the program and make an entry in this table with the | ||
294 | // getters and setters. | ||
295 | // It is easiest to find an existing definition and copy it. | ||
296 | // | ||
297 | // A ParameterDefn<T>() takes the following parameters: | ||
298 | // -- the text name of the parameter. This is used for console input and ini file. | ||
299 | // -- a short text description of the parameter. This shows up in the console listing. | ||
300 | // -- a default value | ||
301 | // -- a delegate for getting the value | ||
302 | // -- a delegate for setting the value | ||
303 | // -- an optional delegate to update the value in the world. Most often used to | ||
304 | // push the new value to an in-world object. | ||
305 | // | ||
306 | // The single letter parameters for the delegates are: | ||
307 | // s = BSScene | ||
308 | // o = BSPhysObject | ||
309 | // v = value (appropriate type) | ||
310 | private static ParameterDefnBase[] ParameterDefinitions = | ||
311 | { | ||
312 | new ParameterDefn<bool>("MeshSculptedPrim", "Whether to create meshes for sculpties", | ||
313 | true, | ||
314 | (s) => { return ShouldMeshSculptedPrim; }, | ||
315 | (s,v) => { ShouldMeshSculptedPrim = v; } ), | ||
316 | new ParameterDefn<bool>("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects", | ||
317 | false, | ||
318 | (s) => { return ShouldForceSimplePrimMeshing; }, | ||
319 | (s,v) => { ShouldForceSimplePrimMeshing = v; } ), | ||
320 | new ParameterDefn<bool>("UseHullsForPhysicalObjects", "If true, create hulls for physical objects", | ||
321 | true, | ||
322 | (s) => { return ShouldUseHullsForPhysicalObjects; }, | ||
323 | (s,v) => { ShouldUseHullsForPhysicalObjects = v; } ), | ||
324 | new ParameterDefn<bool>("ShouldRemoveZeroWidthTriangles", "If true, remove degenerate triangles from meshes", | ||
325 | true, | ||
326 | (s) => { return ShouldRemoveZeroWidthTriangles; }, | ||
327 | (s,v) => { ShouldRemoveZeroWidthTriangles = v; } ), | ||
328 | |||
329 | new ParameterDefn<int>("CrossingFailuresBeforeOutOfBounds", "How forgiving we are about getting into adjactent regions", | ||
330 | 5, | ||
331 | (s) => { return CrossingFailuresBeforeOutOfBounds; }, | ||
332 | (s,v) => { CrossingFailuresBeforeOutOfBounds = v; } ), | ||
333 | new ParameterDefn<float>("UpdateVelocityChangeThreshold", "Change in updated velocity required before reporting change to simulator", | ||
334 | 0.1f, | ||
335 | (s) => { return UpdateVelocityChangeThreshold; }, | ||
336 | (s,v) => { UpdateVelocityChangeThreshold = v; } ), | ||
337 | |||
338 | new ParameterDefn<float>("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)", | ||
339 | 32f, | ||
340 | (s) => { return MeshLOD; }, | ||
341 | (s,v) => { MeshLOD = v; } ), | ||
342 | new ParameterDefn<float>("MeshLevelOfDetailCircular", "Level of detail for prims with circular cuts or shapes", | ||
343 | 32f, | ||
344 | (s) => { return MeshCircularLOD; }, | ||
345 | (s,v) => { MeshCircularLOD = v; } ), | ||
346 | new ParameterDefn<float>("MeshLevelOfDetailMegaPrimThreshold", "Size (in meters) of a mesh before using MeshMegaPrimLOD", | ||
347 | 10f, | ||
348 | (s) => { return MeshMegaPrimThreshold; }, | ||
349 | (s,v) => { MeshMegaPrimThreshold = v; } ), | ||
350 | new ParameterDefn<float>("MeshLevelOfDetailMegaPrim", "Level of detail to render meshes larger than threshold meters", | ||
351 | 32f, | ||
352 | (s) => { return MeshMegaPrimLOD; }, | ||
353 | (s,v) => { MeshMegaPrimLOD = v; } ), | ||
354 | new ParameterDefn<float>("SculptLevelOfDetail", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)", | ||
355 | 32f, | ||
356 | (s) => { return SculptLOD; }, | ||
357 | (s,v) => { SculptLOD = v; } ), | ||
358 | |||
359 | new ParameterDefn<int>("MaxSubStep", "In simulation step, maximum number of substeps", | ||
360 | 10, | ||
361 | (s) => { return s.m_maxSubSteps; }, | ||
362 | (s,v) => { s.m_maxSubSteps = (int)v; } ), | ||
363 | new ParameterDefn<float>("FixedTimeStep", "In simulation step, seconds of one substep (1/60)", | ||
364 | 1f / 60f, | ||
365 | (s) => { return s.m_fixedTimeStep; }, | ||
366 | (s,v) => { s.m_fixedTimeStep = v; } ), | ||
367 | new ParameterDefn<float>("NominalFrameRate", "The base frame rate we claim", | ||
368 | 55f, | ||
369 | (s) => { return s.NominalFrameRate; }, | ||
370 | (s,v) => { s.NominalFrameRate = (int)v; } ), | ||
371 | new ParameterDefn<int>("MaxCollisionsPerFrame", "Max collisions returned at end of each frame", | ||
372 | 2048, | ||
373 | (s) => { return s.m_maxCollisionsPerFrame; }, | ||
374 | (s,v) => { s.m_maxCollisionsPerFrame = (int)v; } ), | ||
375 | new ParameterDefn<int>("MaxUpdatesPerFrame", "Max updates returned at end of each frame", | ||
376 | 8000, | ||
377 | (s) => { return s.m_maxUpdatesPerFrame; }, | ||
378 | (s,v) => { s.m_maxUpdatesPerFrame = (int)v; } ), | ||
379 | |||
380 | new ParameterDefn<float>("MinObjectMass", "Minimum object mass (0.0001)", | ||
381 | 0.0001f, | ||
382 | (s) => { return MinimumObjectMass; }, | ||
383 | (s,v) => { MinimumObjectMass = v; } ), | ||
384 | new ParameterDefn<float>("MaxObjectMass", "Maximum object mass (10000.01)", | ||
385 | 10000.01f, | ||
386 | (s) => { return MaximumObjectMass; }, | ||
387 | (s,v) => { MaximumObjectMass = v; } ), | ||
388 | new ParameterDefn<float>("MaxLinearVelocity", "Maximum velocity magnitude that can be assigned to an object", | ||
389 | 1000.0f, | ||
390 | (s) => { return MaxLinearVelocity; }, | ||
391 | (s,v) => { MaxLinearVelocity = v; MaxLinearVelocitySquared = v * v; } ), | ||
392 | new ParameterDefn<float>("MaxAngularVelocity", "Maximum rotational velocity magnitude that can be assigned to an object", | ||
393 | 1000.0f, | ||
394 | (s) => { return MaxAngularVelocity; }, | ||
395 | (s,v) => { MaxAngularVelocity = v; MaxAngularVelocitySquared = v * v; } ), | ||
396 | // LL documentation says thie number should be 20f for llApplyImpulse and 200f for llRezObject | ||
397 | new ParameterDefn<float>("MaxAddForceMagnitude", "Maximum force that can be applied by llApplyImpulse (SL says 20f)", | ||
398 | 20000.0f, | ||
399 | (s) => { return MaxAddForceMagnitude; }, | ||
400 | (s,v) => { MaxAddForceMagnitude = v; MaxAddForceMagnitudeSquared = v * v; } ), | ||
401 | // Density is passed around as 100kg/m3. This scales that to 1kg/m3. | ||
402 | new ParameterDefn<float>("DensityScaleFactor", "Conversion for simulator/viewer density (100kg/m3) to physical density (1kg/m3)", | ||
403 | 0.01f, | ||
404 | (s) => { return DensityScaleFactor; }, | ||
405 | (s,v) => { DensityScaleFactor = v; } ), | ||
406 | |||
407 | new ParameterDefn<float>("PID_D", "Derivitive factor for motion smoothing", | ||
408 | 2200f, | ||
409 | (s) => { return (float)PID_D; }, | ||
410 | (s,v) => { PID_D = v; } ), | ||
411 | new ParameterDefn<float>("PID_P", "Parameteric factor for motion smoothing", | ||
412 | 900f, | ||
413 | (s) => { return (float)PID_P; }, | ||
414 | (s,v) => { PID_P = v; } ), | ||
415 | |||
416 | new ParameterDefn<float>("DefaultFriction", "Friction factor used on new objects", | ||
417 | 0.2f, | ||
418 | (s) => { return DefaultFriction; }, | ||
419 | (s,v) => { DefaultFriction = v; s.UnmanagedParams[0].defaultFriction = v; } ), | ||
420 | new ParameterDefn<float>("DefaultDensity", "Density for new objects" , | ||
421 | 10.000006836f, // Aluminum g/cm3 | ||
422 | (s) => { return DefaultDensity; }, | ||
423 | (s,v) => { DefaultDensity = v; s.UnmanagedParams[0].defaultDensity = v; } ), | ||
424 | new ParameterDefn<float>("DefaultRestitution", "Bouncyness of an object" , | ||
425 | 0f, | ||
426 | (s) => { return DefaultRestitution; }, | ||
427 | (s,v) => { DefaultRestitution = v; s.UnmanagedParams[0].defaultRestitution = v; } ), | ||
428 | new ParameterDefn<float>("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)", | ||
429 | 0.04f, | ||
430 | (s) => { return CollisionMargin; }, | ||
431 | (s,v) => { CollisionMargin = v; s.UnmanagedParams[0].collisionMargin = v; } ), | ||
432 | new ParameterDefn<float>("Gravity", "Vertical force of gravity (negative means down)", | ||
433 | -9.80665f, | ||
434 | (s) => { return Gravity; }, | ||
435 | (s,v) => { Gravity = v; s.UnmanagedParams[0].gravity = v; }, | ||
436 | (s,o) => { s.PE.SetGravity(o.PhysBody, new Vector3(0f,0f,Gravity)); } ), | ||
437 | |||
438 | |||
439 | new ParameterDefn<float>("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)", | ||
440 | 0f, | ||
441 | (s) => { return LinearDamping; }, | ||
442 | (s,v) => { LinearDamping = v; }, | ||
443 | (s,o) => { s.PE.SetDamping(o.PhysBody, LinearDamping, AngularDamping); } ), | ||
444 | new ParameterDefn<float>("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)", | ||
445 | 0f, | ||
446 | (s) => { return AngularDamping; }, | ||
447 | (s,v) => { AngularDamping = v; }, | ||
448 | (s,o) => { s.PE.SetDamping(o.PhysBody, LinearDamping, AngularDamping); } ), | ||
449 | new ParameterDefn<float>("DeactivationTime", "Seconds before considering an object potentially static", | ||
450 | 0.2f, | ||
451 | (s) => { return DeactivationTime; }, | ||
452 | (s,v) => { DeactivationTime = v; }, | ||
453 | (s,o) => { s.PE.SetDeactivationTime(o.PhysBody, DeactivationTime); } ), | ||
454 | new ParameterDefn<float>("LinearSleepingThreshold", "Seconds to measure linear movement before considering static", | ||
455 | 0.8f, | ||
456 | (s) => { return LinearSleepingThreshold; }, | ||
457 | (s,v) => { LinearSleepingThreshold = v;}, | ||
458 | (s,o) => { s.PE.SetSleepingThresholds(o.PhysBody, LinearSleepingThreshold, AngularSleepingThreshold); } ), | ||
459 | new ParameterDefn<float>("AngularSleepingThreshold", "Seconds to measure angular movement before considering static", | ||
460 | 1.0f, | ||
461 | (s) => { return AngularSleepingThreshold; }, | ||
462 | (s,v) => { AngularSleepingThreshold = v;}, | ||
463 | (s,o) => { s.PE.SetSleepingThresholds(o.PhysBody, LinearSleepingThreshold, AngularSleepingThreshold); } ), | ||
464 | new ParameterDefn<float>("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" , | ||
465 | 0.0f, // set to zero to disable | ||
466 | (s) => { return CcdMotionThreshold; }, | ||
467 | (s,v) => { CcdMotionThreshold = v;}, | ||
468 | (s,o) => { s.PE.SetCcdMotionThreshold(o.PhysBody, CcdMotionThreshold); } ), | ||
469 | new ParameterDefn<float>("CcdSweptSphereRadius", "Continuious collision detection test radius" , | ||
470 | 0.2f, | ||
471 | (s) => { return CcdSweptSphereRadius; }, | ||
472 | (s,v) => { CcdSweptSphereRadius = v;}, | ||
473 | (s,o) => { s.PE.SetCcdSweptSphereRadius(o.PhysBody, CcdSweptSphereRadius); } ), | ||
474 | new ParameterDefn<float>("ContactProcessingThreshold", "Distance above which contacts can be discarded (0 means no discard)" , | ||
475 | 0.0f, | ||
476 | (s) => { return ContactProcessingThreshold; }, | ||
477 | (s,v) => { ContactProcessingThreshold = v;}, | ||
478 | (s,o) => { s.PE.SetContactProcessingThreshold(o.PhysBody, ContactProcessingThreshold); } ), | ||
479 | |||
480 | new ParameterDefn<float>("TerrainImplementation", "Type of shape to use for terrain (0=heightmap, 1=mesh)", | ||
481 | (float)BSTerrainPhys.TerrainImplementation.Mesh, | ||
482 | (s) => { return TerrainImplementation; }, | ||
483 | (s,v) => { TerrainImplementation = v; } ), | ||
484 | new ParameterDefn<int>("TerrainMeshMagnification", "Number of times the 256x256 heightmap is multiplied to create the terrain mesh" , | ||
485 | 2, | ||
486 | (s) => { return TerrainMeshMagnification; }, | ||
487 | (s,v) => { TerrainMeshMagnification = v; } ), | ||
488 | new ParameterDefn<float>("TerrainFriction", "Factor to reduce movement against terrain surface" , | ||
489 | 0.3f, | ||
490 | (s) => { return TerrainFriction; }, | ||
491 | (s,v) => { TerrainFriction = v; /* TODO: set on real terrain */} ), | ||
492 | new ParameterDefn<float>("TerrainHitFraction", "Distance to measure hit collisions" , | ||
493 | 0.8f, | ||
494 | (s) => { return TerrainHitFraction; }, | ||
495 | (s,v) => { TerrainHitFraction = v; /* TODO: set on real terrain */ } ), | ||
496 | new ParameterDefn<float>("TerrainRestitution", "Bouncyness" , | ||
497 | 0f, | ||
498 | (s) => { return TerrainRestitution; }, | ||
499 | (s,v) => { TerrainRestitution = v; /* TODO: set on real terrain */ } ), | ||
500 | new ParameterDefn<float>("TerrainContactProcessingThreshold", "Distance from terrain to stop processing collisions" , | ||
501 | 0.0f, | ||
502 | (s) => { return TerrainContactProcessingThreshold; }, | ||
503 | (s,v) => { TerrainContactProcessingThreshold = v; /* TODO: set on real terrain */ } ), | ||
504 | new ParameterDefn<float>("TerrainCollisionMargin", "Margin where collision checking starts" , | ||
505 | 0.08f, | ||
506 | (s) => { return TerrainCollisionMargin; }, | ||
507 | (s,v) => { TerrainCollisionMargin = v; /* TODO: set on real terrain */ } ), | ||
508 | |||
509 | new ParameterDefn<float>("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.", | ||
510 | 0.2f, | ||
511 | (s) => { return AvatarFriction; }, | ||
512 | (s,v) => { AvatarFriction = v; } ), | ||
513 | new ParameterDefn<float>("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.", | ||
514 | 0.95f, | ||
515 | (s) => { return AvatarStandingFriction; }, | ||
516 | (s,v) => { AvatarStandingFriction = v; } ), | ||
517 | new ParameterDefn<float>("AvatarAlwaysRunFactor", "Speed multiplier if avatar is set to always run", | ||
518 | 1.3f, | ||
519 | (s) => { return AvatarAlwaysRunFactor; }, | ||
520 | (s,v) => { AvatarAlwaysRunFactor = v; } ), | ||
521 | new ParameterDefn<float>("AvatarDensity", "Density of an avatar. Changed on avatar recreation.", | ||
522 | 3.5f, | ||
523 | (s) => { return AvatarDensity; }, | ||
524 | (s,v) => { AvatarDensity = v; } ), | ||
525 | new ParameterDefn<float>("AvatarRestitution", "Bouncyness. Changed on avatar recreation.", | ||
526 | 0f, | ||
527 | (s) => { return AvatarRestitution; }, | ||
528 | (s,v) => { AvatarRestitution = v; } ), | ||
529 | new ParameterDefn<float>("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule", | ||
530 | 0.6f, | ||
531 | (s) => { return AvatarCapsuleWidth; }, | ||
532 | (s,v) => { AvatarCapsuleWidth = v; } ), | ||
533 | new ParameterDefn<float>("AvatarCapsuleDepth", "The distance between the front and back of the avatar capsule", | ||
534 | 0.45f, | ||
535 | (s) => { return AvatarCapsuleDepth; }, | ||
536 | (s,v) => { AvatarCapsuleDepth = v; } ), | ||
537 | new ParameterDefn<float>("AvatarCapsuleHeight", "Default height of space around avatar", | ||
538 | 1.5f, | ||
539 | (s) => { return AvatarCapsuleHeight; }, | ||
540 | (s,v) => { AvatarCapsuleHeight = v; } ), | ||
541 | new ParameterDefn<float>("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions", | ||
542 | 0.1f, | ||
543 | (s) => { return AvatarContactProcessingThreshold; }, | ||
544 | (s,v) => { AvatarContactProcessingThreshold = v; } ), | ||
545 | new ParameterDefn<float>("AvatarBelowGroundUpCorrectionMeters", "Meters to move avatar up if it seems to be below ground", | ||
546 | 1.0f, | ||
547 | (s) => { return AvatarBelowGroundUpCorrectionMeters; }, | ||
548 | (s,v) => { AvatarBelowGroundUpCorrectionMeters = v; } ), | ||
549 | new ParameterDefn<float>("AvatarStepHeight", "Height of a step obstacle to consider step correction", | ||
550 | 0.3f, | ||
551 | (s) => { return AvatarStepHeight; }, | ||
552 | (s,v) => { AvatarStepHeight = v; } ), | ||
553 | new ParameterDefn<float>("AvatarStepApproachFactor", "Factor to control angle of approach to step (0=straight on)", | ||
554 | 0.6f, | ||
555 | (s) => { return AvatarStepApproachFactor; }, | ||
556 | (s,v) => { AvatarStepApproachFactor = v; } ), | ||
557 | new ParameterDefn<float>("AvatarStepForceFactor", "Controls the amount of force up applied to step up onto a step", | ||
558 | 2.0f, | ||
559 | (s) => { return AvatarStepForceFactor; }, | ||
560 | (s,v) => { AvatarStepForceFactor = v; } ), | ||
561 | |||
562 | new ParameterDefn<float>("VehicleMaxLinearVelocity", "Maximum velocity magnitude that can be assigned to a vehicle", | ||
563 | 1000.0f, | ||
564 | (s) => { return (float)VehicleMaxLinearVelocity; }, | ||
565 | (s,v) => { VehicleMaxLinearVelocity = v; VehicleMaxLinearVelocitySquared = v * v; } ), | ||
566 | new ParameterDefn<float>("VehicleMaxAngularVelocity", "Maximum rotational velocity magnitude that can be assigned to a vehicle", | ||
567 | 12.0f, | ||
568 | (s) => { return (float)VehicleMaxAngularVelocity; }, | ||
569 | (s,v) => { VehicleMaxAngularVelocity = v; VehicleMaxAngularVelocitySq = v * v; } ), | ||
570 | new ParameterDefn<float>("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)", | ||
571 | 0.0f, | ||
572 | (s) => { return VehicleAngularDamping; }, | ||
573 | (s,v) => { VehicleAngularDamping = v; } ), | ||
574 | new ParameterDefn<Vector3>("VehicleLinearFactor", "Fraction of physical linear changes applied to vehicle (<0,0,0> to <1,1,1>)", | ||
575 | new Vector3(1f, 1f, 1f), | ||
576 | (s) => { return VehicleLinearFactor; }, | ||
577 | (s,v) => { VehicleLinearFactor = v; } ), | ||
578 | new ParameterDefn<Vector3>("VehicleAngularFactor", "Fraction of physical angular changes applied to vehicle (<0,0,0> to <1,1,1>)", | ||
579 | new Vector3(1f, 1f, 1f), | ||
580 | (s) => { return VehicleAngularFactor; }, | ||
581 | (s,v) => { VehicleAngularFactor = v; } ), | ||
582 | new ParameterDefn<float>("VehicleFriction", "Friction of vehicle on the ground (0.0 - 1.0)", | ||
583 | 0.0f, | ||
584 | (s) => { return VehicleFriction; }, | ||
585 | (s,v) => { VehicleFriction = v; } ), | ||
586 | new ParameterDefn<float>("VehicleRestitution", "Bouncyness factor for vehicles (0.0 - 1.0)", | ||
587 | 0.0f, | ||
588 | (s) => { return VehicleRestitution; }, | ||
589 | (s,v) => { VehicleRestitution = v; } ), | ||
590 | new ParameterDefn<float>("VehicleGroundGravityFudge", "Factor to multiply gravity if a ground vehicle is probably on the ground (0.0 - 1.0)", | ||
591 | 0.2f, | ||
592 | (s) => { return VehicleGroundGravityFudge; }, | ||
593 | (s,v) => { VehicleGroundGravityFudge = v; } ), | ||
594 | new ParameterDefn<float>("VehicleAngularBankingTimescaleFudge", "Factor to multiple angular banking timescale. Tune to increase realism.", | ||
595 | 60.0f, | ||
596 | (s) => { return VehicleAngularBankingTimescaleFudge; }, | ||
597 | (s,v) => { VehicleAngularBankingTimescaleFudge = v; } ), | ||
598 | new ParameterDefn<bool>("VehicleDebuggingEnable", "Turn on/off vehicle debugging", | ||
599 | false, | ||
600 | (s) => { return VehicleDebuggingEnabled; }, | ||
601 | (s,v) => { VehicleDebuggingEnabled = v; } ), | ||
602 | |||
603 | new ParameterDefn<float>("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)", | ||
604 | 0f, | ||
605 | (s) => { return MaxPersistantManifoldPoolSize; }, | ||
606 | (s,v) => { MaxPersistantManifoldPoolSize = v; s.UnmanagedParams[0].maxPersistantManifoldPoolSize = v; } ), | ||
607 | new ParameterDefn<float>("MaxCollisionAlgorithmPoolSize", "Number of collisions pooled (0 means default of 4096)", | ||
608 | 0f, | ||
609 | (s) => { return MaxCollisionAlgorithmPoolSize; }, | ||
610 | (s,v) => { MaxCollisionAlgorithmPoolSize = v; s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize = v; } ), | ||
611 | new ParameterDefn<bool>("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count", | ||
612 | false, | ||
613 | (s) => { return ShouldDisableContactPoolDynamicAllocation; }, | ||
614 | (s,v) => { ShouldDisableContactPoolDynamicAllocation = v; | ||
615 | s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = NumericBool(v); } ), | ||
616 | new ParameterDefn<bool>("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step", | ||
617 | false, | ||
618 | (s) => { return ShouldForceUpdateAllAabbs; }, | ||
619 | (s,v) => { ShouldForceUpdateAllAabbs = v; s.UnmanagedParams[0].shouldForceUpdateAllAabbs = NumericBool(v); } ), | ||
620 | new ParameterDefn<bool>("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction", | ||
621 | true, | ||
622 | (s) => { return ShouldRandomizeSolverOrder; }, | ||
623 | (s,v) => { ShouldRandomizeSolverOrder = v; s.UnmanagedParams[0].shouldRandomizeSolverOrder = NumericBool(v); } ), | ||
624 | new ParameterDefn<bool>("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands", | ||
625 | true, | ||
626 | (s) => { return ShouldSplitSimulationIslands; }, | ||
627 | (s,v) => { ShouldSplitSimulationIslands = v; s.UnmanagedParams[0].shouldSplitSimulationIslands = NumericBool(v); } ), | ||
628 | new ParameterDefn<bool>("ShouldEnableFrictionCaching", "Enable friction computation caching", | ||
629 | true, | ||
630 | (s) => { return ShouldEnableFrictionCaching; }, | ||
631 | (s,v) => { ShouldEnableFrictionCaching = v; s.UnmanagedParams[0].shouldEnableFrictionCaching = NumericBool(v); } ), | ||
632 | new ParameterDefn<float>("NumberOfSolverIterations", "Number of internal iterations (0 means default)", | ||
633 | 0f, // zero says use Bullet default | ||
634 | (s) => { return NumberOfSolverIterations; }, | ||
635 | (s,v) => { NumberOfSolverIterations = v; s.UnmanagedParams[0].numberOfSolverIterations = v; } ), | ||
636 | new ParameterDefn<bool>("UseSingleSidedMeshes", "Whether to compute collisions based on single sided meshes.", | ||
637 | true, | ||
638 | (s) => { return UseSingleSidedMeshes; }, | ||
639 | (s,v) => { UseSingleSidedMeshes = v; s.UnmanagedParams[0].useSingleSidedMeshes = NumericBool(v); } ), | ||
640 | new ParameterDefn<float>("GlobalContactBreakingThreshold", "Amount of shape radius before breaking a collision contact (0 says Bullet default (0.2))", | ||
641 | 0f, | ||
642 | (s) => { return GlobalContactBreakingThreshold; }, | ||
643 | (s,v) => { GlobalContactBreakingThreshold = v; s.UnmanagedParams[0].globalContactBreakingThreshold = v; } ), | ||
644 | |||
645 | new ParameterDefn<int>("CSHullMaxDepthSplit", "CS impl: max depth to split for hull. 1-10 but > 7 is iffy", | ||
646 | 7, | ||
647 | (s) => { return CSHullMaxDepthSplit; }, | ||
648 | (s,v) => { CSHullMaxDepthSplit = v; } ), | ||
649 | new ParameterDefn<int>("CSHullMaxDepthSplitForSimpleShapes", "CS impl: max depth setting for simple prim shapes", | ||
650 | 2, | ||
651 | (s) => { return CSHullMaxDepthSplitForSimpleShapes; }, | ||
652 | (s,v) => { CSHullMaxDepthSplitForSimpleShapes = v; } ), | ||
653 | new ParameterDefn<float>("CSHullConcavityThresholdPercent", "CS impl: concavity threshold percent (0-20)", | ||
654 | 5f, | ||
655 | (s) => { return CSHullConcavityThresholdPercent; }, | ||
656 | (s,v) => { CSHullConcavityThresholdPercent = v; } ), | ||
657 | new ParameterDefn<float>("CSHullVolumeConservationThresholdPercent", "percent volume conservation to collapse hulls (0-30)", | ||
658 | 5f, | ||
659 | (s) => { return CSHullVolumeConservationThresholdPercent; }, | ||
660 | (s,v) => { CSHullVolumeConservationThresholdPercent = v; } ), | ||
661 | new ParameterDefn<int>("CSHullMaxVertices", "CS impl: maximum number of vertices in output hulls. Keep < 50.", | ||
662 | 32, | ||
663 | (s) => { return CSHullMaxVertices; }, | ||
664 | (s,v) => { CSHullMaxVertices = v; } ), | ||
665 | new ParameterDefn<float>("CSHullMaxSkinWidth", "CS impl: skin width to apply to output hulls.", | ||
666 | 0, | ||
667 | (s) => { return CSHullMaxSkinWidth; }, | ||
668 | (s,v) => { CSHullMaxSkinWidth = v; } ), | ||
669 | |||
670 | new ParameterDefn<float>("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)", | ||
671 | (float)BSLinkset.LinksetImplementation.Compound, | ||
672 | (s) => { return LinksetImplementation; }, | ||
673 | (s,v) => { LinksetImplementation = v; } ), | ||
674 | new ParameterDefn<bool>("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.", | ||
675 | false, | ||
676 | (s) => { return LinkConstraintUseFrameOffset; }, | ||
677 | (s,v) => { LinkConstraintUseFrameOffset = v; } ), | ||
678 | new ParameterDefn<bool>("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints", | ||
679 | true, | ||
680 | (s) => { return LinkConstraintEnableTransMotor; }, | ||
681 | (s,v) => { LinkConstraintEnableTransMotor = v; } ), | ||
682 | new ParameterDefn<float>("LinkConstraintTransMotorMaxVel", "Maximum velocity to be applied by translational motor in linkset constraints", | ||
683 | 5.0f, | ||
684 | (s) => { return LinkConstraintTransMotorMaxVel; }, | ||
685 | (s,v) => { LinkConstraintTransMotorMaxVel = v; } ), | ||
686 | new ParameterDefn<float>("LinkConstraintTransMotorMaxForce", "Maximum force to be applied by translational motor in linkset constraints", | ||
687 | 0.1f, | ||
688 | (s) => { return LinkConstraintTransMotorMaxForce; }, | ||
689 | (s,v) => { LinkConstraintTransMotorMaxForce = v; } ), | ||
690 | new ParameterDefn<float>("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1", | ||
691 | 0.1f, | ||
692 | (s) => { return LinkConstraintCFM; }, | ||
693 | (s,v) => { LinkConstraintCFM = v; } ), | ||
694 | new ParameterDefn<float>("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2", | ||
695 | 0.1f, | ||
696 | (s) => { return LinkConstraintERP; }, | ||
697 | (s,v) => { LinkConstraintERP = v; } ), | ||
698 | new ParameterDefn<float>("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)", | ||
699 | 40, | ||
700 | (s) => { return LinkConstraintSolverIterations; }, | ||
701 | (s,v) => { LinkConstraintSolverIterations = v; } ), | ||
702 | |||
703 | new ParameterDefn<int>("PhysicsMetricFrames", "Frames between outputting detailed phys metrics. (0 is off)", | ||
704 | 0, | ||
705 | (s) => { return s.PhysicsMetricDumpFrames; }, | ||
706 | (s,v) => { s.PhysicsMetricDumpFrames = v; } ), | ||
707 | new ParameterDefn<float>("ResetBroadphasePool", "Setting this is any value resets the broadphase collision pool", | ||
708 | 0f, | ||
709 | (s) => { return 0f; }, | ||
710 | (s,v) => { BSParam.ResetBroadphasePoolTainted(s, v); } ), | ||
711 | new ParameterDefn<float>("ResetConstraintSolver", "Setting this is any value resets the constraint solver", | ||
712 | 0f, | ||
713 | (s) => { return 0f; }, | ||
714 | (s,v) => { BSParam.ResetConstraintSolverTainted(s, v); } ), | ||
715 | }; | ||
716 | |||
717 | // Convert a boolean to our numeric true and false values | ||
718 | public static float NumericBool(bool b) | ||
719 | { | ||
720 | return (b ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse); | ||
721 | } | ||
722 | |||
723 | // Convert numeric true and false values to a boolean | ||
724 | public static bool BoolNumeric(float b) | ||
725 | { | ||
726 | return (b == ConfigurationParameters.numericTrue ? true : false); | ||
727 | } | ||
728 | |||
729 | // Search through the parameter definitions and return the matching | ||
730 | // ParameterDefn structure. | ||
731 | // Case does not matter as names are compared after converting to lower case. | ||
732 | // Returns 'false' if the parameter is not found. | ||
733 | internal static bool TryGetParameter(string paramName, out ParameterDefnBase defn) | ||
734 | { | ||
735 | bool ret = false; | ||
736 | ParameterDefnBase foundDefn = null; | ||
737 | string pName = paramName.ToLower(); | ||
738 | |||
739 | foreach (ParameterDefnBase parm in ParameterDefinitions) | ||
740 | { | ||
741 | if (pName == parm.name.ToLower()) | ||
742 | { | ||
743 | foundDefn = parm; | ||
744 | ret = true; | ||
745 | break; | ||
746 | } | ||
747 | } | ||
748 | defn = foundDefn; | ||
749 | return ret; | ||
750 | } | ||
751 | |||
752 | // Pass through the settable parameters and set the default values | ||
753 | internal static void SetParameterDefaultValues(BSScene physicsScene) | ||
754 | { | ||
755 | foreach (ParameterDefnBase parm in ParameterDefinitions) | ||
756 | { | ||
757 | parm.AssignDefault(physicsScene); | ||
758 | } | ||
759 | } | ||
760 | |||
761 | // Get user set values out of the ini file. | ||
762 | internal static void SetParameterConfigurationValues(BSScene physicsScene, IConfig cfg) | ||
763 | { | ||
764 | foreach (ParameterDefnBase parm in ParameterDefinitions) | ||
765 | { | ||
766 | parm.SetValue(physicsScene, cfg.GetString(parm.name, parm.GetValue(physicsScene))); | ||
767 | } | ||
768 | } | ||
769 | |||
770 | internal static PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1]; | ||
771 | |||
772 | // This creates an array in the correct format for returning the list of | ||
773 | // parameters. This is used by the 'list' option of the 'physics' command. | ||
774 | internal static void BuildParameterTable() | ||
775 | { | ||
776 | if (SettableParameters.Length < ParameterDefinitions.Length) | ||
777 | { | ||
778 | List<PhysParameterEntry> entries = new List<PhysParameterEntry>(); | ||
779 | for (int ii = 0; ii < ParameterDefinitions.Length; ii++) | ||
780 | { | ||
781 | ParameterDefnBase pd = ParameterDefinitions[ii]; | ||
782 | entries.Add(new PhysParameterEntry(pd.name, pd.desc)); | ||
783 | } | ||
784 | |||
785 | // make the list alphabetical for ease of finding anything | ||
786 | entries.Sort((ppe1, ppe2) => { return ppe1.name.CompareTo(ppe2.name); }); | ||
787 | |||
788 | SettableParameters = entries.ToArray(); | ||
789 | } | ||
790 | } | ||
791 | |||
792 | // ===================================================================== | ||
793 | // ===================================================================== | ||
794 | // There are parameters that, when set, cause things to happen in the physics engine. | ||
795 | // This causes the broadphase collision cache to be cleared. | ||
796 | private static void ResetBroadphasePoolTainted(BSScene pPhysScene, float v) | ||
797 | { | ||
798 | BSScene physScene = pPhysScene; | ||
799 | physScene.TaintedObject("BSParam.ResetBroadphasePoolTainted", delegate() | ||
800 | { | ||
801 | physScene.PE.ResetBroadphasePool(physScene.World); | ||
802 | }); | ||
803 | } | ||
804 | |||
805 | // This causes the constraint solver cache to be cleared and reset. | ||
806 | private static void ResetConstraintSolverTainted(BSScene pPhysScene, float v) | ||
807 | { | ||
808 | BSScene physScene = pPhysScene; | ||
809 | physScene.TaintedObject("BSParam.ResetConstraintSolver", delegate() | ||
810 | { | ||
811 | physScene.PE.ResetConstraintSolver(physScene.World); | ||
812 | }); | ||
813 | } | ||
814 | } | ||
815 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs index f6a890e..6bb88c7 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs | |||
@@ -45,6 +45,26 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
45 | * ForceVariableName: direct reference (store and fetch) to the value in the physics engine. | 45 | * ForceVariableName: direct reference (store and fetch) to the value in the physics engine. |
46 | * The last two (and certainly the last one) should be referenced only in taint-time. | 46 | * The last two (and certainly the last one) should be referenced only in taint-time. |
47 | */ | 47 | */ |
48 | |||
49 | /* | ||
50 | * As of 20121221, the following are the call sequences (going down) for different script physical functions: | ||
51 | * llApplyImpulse llApplyRotImpulse llSetTorque llSetForce | ||
52 | * SOP.ApplyImpulse SOP.ApplyAngularImpulse SOP.SetAngularImpulse SOP.SetForce | ||
53 | * SOG.ApplyImpulse SOG.ApplyAngularImpulse SOG.SetAngularImpulse | ||
54 | * PA.AddForce PA.AddAngularForce PA.Torque = v PA.Force = v | ||
55 | * BS.ApplyCentralForce BS.ApplyTorque | ||
56 | */ | ||
57 | |||
58 | // Flags used to denote which properties updates when making UpdateProperties calls to linksets, etc. | ||
59 | public enum UpdatedProperties : uint | ||
60 | { | ||
61 | Position = 1 << 0, | ||
62 | Orientation = 1 << 1, | ||
63 | Velocity = 1 << 2, | ||
64 | Acceleration = 1 << 3, | ||
65 | RotationalVelocity = 1 << 4, | ||
66 | EntPropUpdates = Position | Orientation | Velocity | Acceleration | RotationalVelocity, | ||
67 | } | ||
48 | public abstract class BSPhysObject : PhysicsActor | 68 | public abstract class BSPhysObject : PhysicsActor |
49 | { | 69 | { |
50 | protected BSPhysObject() | 70 | protected BSPhysObject() |
@@ -55,15 +75,40 @@ public abstract class BSPhysObject : PhysicsActor | |||
55 | PhysicsScene = parentScene; | 75 | PhysicsScene = parentScene; |
56 | LocalID = localID; | 76 | LocalID = localID; |
57 | PhysObjectName = name; | 77 | PhysObjectName = name; |
78 | Name = name; // PhysicsActor also has the name of the object. Someday consolidate. | ||
58 | TypeName = typeName; | 79 | TypeName = typeName; |
59 | 80 | ||
60 | Linkset = BSLinkset.Factory(PhysicsScene, this); | 81 | // Initialize variables kept in base. |
61 | LastAssetBuildFailed = false; | 82 | GravModifier = 1.0f; |
83 | Gravity = new OMV.Vector3(0f, 0f, BSParam.Gravity); | ||
84 | |||
85 | // We don't have any physical representation yet. | ||
86 | PhysBody = new BulletBody(localID); | ||
87 | PhysShape = new BulletShape(); | ||
88 | |||
89 | PrimAssetState = PrimAssetCondition.Unknown; | ||
90 | |||
91 | // Default material type. Also sets Friction, Restitution and Density. | ||
92 | SetMaterial((int)MaterialAttributes.Material.Wood); | ||
62 | 93 | ||
63 | CollisionCollection = new CollisionEventUpdate(); | 94 | CollisionCollection = new CollisionEventUpdate(); |
95 | CollisionsLastTick = CollisionCollection; | ||
64 | SubscribedEventsMs = 0; | 96 | SubscribedEventsMs = 0; |
65 | CollidingStep = 0; | 97 | CollidingStep = 0; |
66 | CollidingGroundStep = 0; | 98 | CollidingGroundStep = 0; |
99 | CollisionAccumulation = 0; | ||
100 | ColliderIsMoving = false; | ||
101 | CollisionScore = 0; | ||
102 | |||
103 | // All axis free. | ||
104 | LockedAxis = LockedAxisFree; | ||
105 | } | ||
106 | |||
107 | // Tell the object to clean up. | ||
108 | public virtual void Destroy() | ||
109 | { | ||
110 | UnRegisterAllPreStepActions(); | ||
111 | UnRegisterAllPostStepActions(); | ||
67 | } | 112 | } |
68 | 113 | ||
69 | public BSScene PhysicsScene { get; protected set; } | 114 | public BSScene PhysicsScene { get; protected set; } |
@@ -71,13 +116,15 @@ public abstract class BSPhysObject : PhysicsActor | |||
71 | public string PhysObjectName { get; protected set; } | 116 | public string PhysObjectName { get; protected set; } |
72 | public string TypeName { get; protected set; } | 117 | public string TypeName { get; protected set; } |
73 | 118 | ||
74 | public BSLinkset Linkset { get; set; } | ||
75 | 119 | ||
76 | // Return the object mass without calculating it or having side effects | 120 | // Return the object mass without calculating it or having side effects |
77 | public abstract float RawMass { get; } | 121 | public abstract float RawMass { get; } |
78 | // Set the raw mass but also update physical mass properties (inertia, ...) | 122 | // Set the raw mass but also update physical mass properties (inertia, ...) |
79 | public abstract void UpdatePhysicalMassProperties(float mass); | 123 | // 'inWorld' true if the object has already been added to the dynamic world. |
124 | public abstract void UpdatePhysicalMassProperties(float mass, bool inWorld); | ||
80 | 125 | ||
126 | // The gravity being applied to the object. A function of default grav, GravityModifier and Buoyancy. | ||
127 | public virtual OMV.Vector3 Gravity { get; set; } | ||
81 | // The last value calculated for the prim's inertia | 128 | // The last value calculated for the prim's inertia |
82 | public OMV.Vector3 Inertia { get; set; } | 129 | public OMV.Vector3 Inertia { get; set; } |
83 | 130 | ||
@@ -86,12 +133,17 @@ public abstract class BSPhysObject : PhysicsActor | |||
86 | // Reference to the physical shape (btCollisionShape) of this object | 133 | // Reference to the physical shape (btCollisionShape) of this object |
87 | public BulletShape PhysShape; | 134 | public BulletShape PhysShape; |
88 | 135 | ||
89 | // 'true' if the mesh's underlying asset failed to build. | 136 | // The physical representation of the prim might require an asset fetch. |
90 | // This will keep us from looping after the first time the build failed. | 137 | // The asset state is first 'Unknown' then 'Waiting' then either 'Failed' or 'Fetched'. |
91 | public bool LastAssetBuildFailed { get; set; } | 138 | public enum PrimAssetCondition |
139 | { | ||
140 | Unknown, Waiting, Failed, Fetched | ||
141 | } | ||
142 | public PrimAssetCondition PrimAssetState { get; set; } | ||
92 | 143 | ||
93 | // The objects base shape information. Null if not a prim type shape. | 144 | // The objects base shape information. Null if not a prim type shape. |
94 | public PrimitiveBaseShape BaseShape { get; protected set; } | 145 | public PrimitiveBaseShape BaseShape { get; protected set; } |
146 | |||
95 | // Some types of objects have preferred physical representations. | 147 | // Some types of objects have preferred physical representations. |
96 | // Returns SHAPE_UNKNOWN if there is no preference. | 148 | // Returns SHAPE_UNKNOWN if there is no preference. |
97 | public virtual BSPhysicsShapeType PreferredPhysicalShape | 149 | public virtual BSPhysicsShapeType PreferredPhysicalShape |
@@ -105,29 +157,46 @@ public abstract class BSPhysObject : PhysicsActor | |||
105 | public EntityProperties CurrentEntityProperties { get; set; } | 157 | public EntityProperties CurrentEntityProperties { get; set; } |
106 | public EntityProperties LastEntityProperties { get; set; } | 158 | public EntityProperties LastEntityProperties { get; set; } |
107 | 159 | ||
108 | public abstract OMV.Vector3 Scale { get; set; } | 160 | public virtual OMV.Vector3 Scale { get; set; } |
161 | |||
162 | // It can be confusing for an actor to know if it should move or update an object | ||
163 | // depeneding on the setting of 'selected', 'physical, ... | ||
164 | // This flag is the true test -- if true, the object is being acted on in the physical world | ||
165 | public abstract bool IsPhysicallyActive { get; } | ||
166 | |||
167 | // Detailed state of the object. | ||
109 | public abstract bool IsSolid { get; } | 168 | public abstract bool IsSolid { get; } |
110 | public abstract bool IsStatic { get; } | 169 | public abstract bool IsStatic { get; } |
170 | public abstract bool IsSelected { get; } | ||
171 | |||
172 | // Materialness | ||
173 | public MaterialAttributes.Material Material { get; private set; } | ||
174 | public override void SetMaterial(int material) | ||
175 | { | ||
176 | Material = (MaterialAttributes.Material)material; | ||
177 | |||
178 | // Setting the material sets the material attributes also. | ||
179 | MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false); | ||
180 | Friction = matAttrib.friction; | ||
181 | Restitution = matAttrib.restitution; | ||
182 | Density = matAttrib.density / BSParam.DensityScaleFactor; | ||
183 | DetailLog("{0},{1}.SetMaterial,Mat={2},frict={3},rest={4},den={5}", LocalID, TypeName, Material, Friction, Restitution, Density); | ||
184 | } | ||
111 | 185 | ||
112 | // Stop all physical motion. | 186 | // Stop all physical motion. |
113 | public abstract void ZeroMotion(bool inTaintTime); | 187 | public abstract void ZeroMotion(bool inTaintTime); |
114 | public abstract void ZeroAngularMotion(bool inTaintTime); | 188 | public abstract void ZeroAngularMotion(bool inTaintTime); |
115 | 189 | ||
116 | // Step the vehicle simulation for this object. A NOOP if the vehicle was not configured. | ||
117 | public virtual void StepVehicle(float timeStep) { } | ||
118 | |||
119 | // Update the physical location and motion of the object. Called with data from Bullet. | 190 | // Update the physical location and motion of the object. Called with data from Bullet. |
120 | public abstract void UpdateProperties(EntityProperties entprop); | 191 | public abstract void UpdateProperties(EntityProperties entprop); |
121 | 192 | ||
122 | // Tell the object to clean up. | ||
123 | public abstract void Destroy(); | ||
124 | |||
125 | public abstract OMV.Vector3 RawPosition { get; set; } | 193 | public abstract OMV.Vector3 RawPosition { get; set; } |
126 | public abstract OMV.Vector3 ForcePosition { get; set; } | 194 | public abstract OMV.Vector3 ForcePosition { get; set; } |
127 | 195 | ||
128 | public abstract OMV.Quaternion RawOrientation { get; set; } | 196 | public abstract OMV.Quaternion RawOrientation { get; set; } |
129 | public abstract OMV.Quaternion ForceOrientation { get; set; } | 197 | public abstract OMV.Quaternion ForceOrientation { get; set; } |
130 | 198 | ||
199 | public abstract OMV.Vector3 RawVelocity { get; set; } | ||
131 | public abstract OMV.Vector3 ForceVelocity { get; set; } | 200 | public abstract OMV.Vector3 ForceVelocity { get; set; } |
132 | 201 | ||
133 | public abstract OMV.Vector3 ForceRotationalVelocity { get; set; } | 202 | public abstract OMV.Vector3 ForceRotationalVelocity { get; set; } |
@@ -136,6 +205,32 @@ public abstract class BSPhysObject : PhysicsActor | |||
136 | 205 | ||
137 | public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; } | 206 | public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; } |
138 | 207 | ||
208 | // The current velocity forward | ||
209 | public virtual float ForwardSpeed | ||
210 | { | ||
211 | get | ||
212 | { | ||
213 | OMV.Vector3 characterOrientedVelocity = RawVelocity * OMV.Quaternion.Inverse(OMV.Quaternion.Normalize(RawOrientation)); | ||
214 | return characterOrientedVelocity.X; | ||
215 | } | ||
216 | } | ||
217 | // The forward speed we are trying to achieve (TargetVelocity) | ||
218 | public virtual float TargetVelocitySpeed | ||
219 | { | ||
220 | get | ||
221 | { | ||
222 | OMV.Vector3 characterOrientedVelocity = TargetVelocity * OMV.Quaternion.Inverse(OMV.Quaternion.Normalize(RawOrientation)); | ||
223 | return characterOrientedVelocity.X; | ||
224 | } | ||
225 | } | ||
226 | |||
227 | // The user can optionally set the center of mass. The user's setting will override any | ||
228 | // computed center-of-mass (like in linksets). | ||
229 | public OMV.Vector3? UserSetCenterOfMass { get; set; } | ||
230 | |||
231 | public OMV.Vector3 LockedAxis { get; set; } // zero means locked. one means free. | ||
232 | public readonly OMV.Vector3 LockedAxisFree = new OMV.Vector3(1f, 1f, 1f); // All axis are free | ||
233 | |||
139 | #region Collisions | 234 | #region Collisions |
140 | 235 | ||
141 | // Requested number of milliseconds between collision events. Zero means disabled. | 236 | // Requested number of milliseconds between collision events. Zero means disabled. |
@@ -146,38 +241,82 @@ public abstract class BSPhysObject : PhysicsActor | |||
146 | protected long CollidingStep { get; set; } | 241 | protected long CollidingStep { get; set; } |
147 | // The simulation step that last had a collision with the ground | 242 | // The simulation step that last had a collision with the ground |
148 | protected long CollidingGroundStep { get; set; } | 243 | protected long CollidingGroundStep { get; set; } |
244 | // The simulation step that last collided with an object | ||
245 | protected long CollidingObjectStep { get; set; } | ||
149 | // The collision flags we think are set in Bullet | 246 | // The collision flags we think are set in Bullet |
150 | protected CollisionFlags CurrentCollisionFlags { get; set; } | 247 | protected CollisionFlags CurrentCollisionFlags { get; set; } |
248 | // On a collision, check the collider and remember if the last collider was moving | ||
249 | // Used to modify the standing of avatars (avatars on stationary things stand still) | ||
250 | protected bool ColliderIsMoving; | ||
251 | |||
252 | // Count of collisions for this object | ||
253 | protected long CollisionAccumulation { get; set; } | ||
254 | |||
255 | public override bool IsColliding { | ||
256 | get { return (CollidingStep == PhysicsScene.SimulationStep); } | ||
257 | set { | ||
258 | if (value) | ||
259 | CollidingStep = PhysicsScene.SimulationStep; | ||
260 | else | ||
261 | CollidingStep = 0; | ||
262 | } | ||
263 | } | ||
264 | public override bool CollidingGround { | ||
265 | get { return (CollidingGroundStep == PhysicsScene.SimulationStep); } | ||
266 | set | ||
267 | { | ||
268 | if (value) | ||
269 | CollidingGroundStep = PhysicsScene.SimulationStep; | ||
270 | else | ||
271 | CollidingGroundStep = 0; | ||
272 | } | ||
273 | } | ||
274 | public override bool CollidingObj { | ||
275 | get { return (CollidingObjectStep == PhysicsScene.SimulationStep); } | ||
276 | set { | ||
277 | if (value) | ||
278 | CollidingObjectStep = PhysicsScene.SimulationStep; | ||
279 | else | ||
280 | CollidingObjectStep = 0; | ||
281 | } | ||
282 | } | ||
151 | 283 | ||
152 | // The collisions that have been collected this tick | 284 | // The collisions that have been collected this tick |
153 | protected CollisionEventUpdate CollisionCollection; | 285 | protected CollisionEventUpdate CollisionCollection; |
286 | // Remember collisions from last tick for fancy collision based actions | ||
287 | // (like a BSCharacter walking up stairs). | ||
288 | protected CollisionEventUpdate CollisionsLastTick; | ||
154 | 289 | ||
155 | // The simulation step is telling this object about a collision. | 290 | // The simulation step is telling this object about a collision. |
156 | // Return 'true' if a collision was processed and should be sent up. | 291 | // Return 'true' if a collision was processed and should be sent up. |
292 | // Return 'false' if this object is not enabled/subscribed/appropriate for or has already seen this collision. | ||
157 | // Called at taint time from within the Step() function | 293 | // Called at taint time from within the Step() function |
158 | public virtual bool Collide(uint collidingWith, BSPhysObject collidee, | 294 | public virtual bool Collide(uint collidingWith, BSPhysObject collidee, |
159 | OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) | 295 | OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) |
160 | { | 296 | { |
161 | bool ret = false; | 297 | bool ret = false; |
162 | 298 | ||
163 | // The following lines make IsColliding() and IsCollidingGround() work | 299 | // The following lines make IsColliding(), CollidingGround() and CollidingObj work |
164 | CollidingStep = PhysicsScene.SimulationStep; | 300 | CollidingStep = PhysicsScene.SimulationStep; |
165 | if (collidingWith <= PhysicsScene.TerrainManager.HighestTerrainID) | 301 | if (collidingWith <= PhysicsScene.TerrainManager.HighestTerrainID) |
166 | { | 302 | { |
167 | CollidingGroundStep = PhysicsScene.SimulationStep; | 303 | CollidingGroundStep = PhysicsScene.SimulationStep; |
168 | } | 304 | } |
169 | 305 | else | |
170 | // prims in the same linkset cannot collide with each other | ||
171 | if (collidee != null && (this.Linkset.LinksetID == collidee.Linkset.LinksetID)) | ||
172 | { | 306 | { |
173 | return ret; | 307 | CollidingObjectStep = PhysicsScene.SimulationStep; |
174 | } | 308 | } |
175 | 309 | ||
176 | // if someone has subscribed for collision events.... | 310 | CollisionAccumulation++; |
311 | |||
312 | // For movement tests, remember if we are colliding with an object that is moving. | ||
313 | ColliderIsMoving = collidee != null ? (collidee.RawVelocity != OMV.Vector3.Zero) : false; | ||
314 | |||
315 | // If someone has subscribed for collision events log the collision so it will be reported up | ||
177 | if (SubscribedEvents()) { | 316 | if (SubscribedEvents()) { |
178 | CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); | 317 | CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); |
179 | DetailLog("{0},{1}.Collison.AddCollider,call,with={2},point={3},normal={4},depth={5}", | 318 | DetailLog("{0},{1}.Collison.AddCollider,call,with={2},point={3},normal={4},depth={5},colliderMoving={6}", |
180 | LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth); | 319 | LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth, ColliderIsMoving); |
181 | 320 | ||
182 | ret = true; | 321 | ret = true; |
183 | } | 322 | } |
@@ -191,8 +330,9 @@ public abstract class BSPhysObject : PhysicsActor | |||
191 | public virtual bool SendCollisions() | 330 | public virtual bool SendCollisions() |
192 | { | 331 | { |
193 | bool ret = true; | 332 | bool ret = true; |
333 | |||
194 | // If the 'no collision' call, force it to happen right now so quick collision_end | 334 | // If the 'no collision' call, force it to happen right now so quick collision_end |
195 | bool force = CollisionCollection.Count == 0; | 335 | bool force = (CollisionCollection.Count == 0 && CollisionsLastTick.Count != 0); |
196 | 336 | ||
197 | // throttle the collisions to the number of milliseconds specified in the subscription | 337 | // throttle the collisions to the number of milliseconds specified in the subscription |
198 | if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime)) | 338 | if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime)) |
@@ -207,11 +347,16 @@ public abstract class BSPhysObject : PhysicsActor | |||
207 | ret = false; | 347 | ret = false; |
208 | } | 348 | } |
209 | 349 | ||
210 | // DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count); | 350 | DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count); |
211 | base.SendCollisionUpdate(CollisionCollection); | 351 | base.SendCollisionUpdate(CollisionCollection); |
212 | 352 | ||
213 | // The collisionCollection structure is passed around in the simulator. | 353 | // Remember the collisions from this tick for some collision specific processing. |
354 | CollisionsLastTick = CollisionCollection; | ||
355 | |||
356 | // The CollisionCollection instance is passed around in the simulator. | ||
214 | // Make sure we don't have a handle to that one and that a new one is used for next time. | 357 | // Make sure we don't have a handle to that one and that a new one is used for next time. |
358 | // This fixes an interesting 'gotcha'. If we call CollisionCollection.Clear() here, | ||
359 | // a race condition is created for the other users of this instance. | ||
215 | CollisionCollection = new CollisionEventUpdate(); | 360 | CollisionCollection = new CollisionEventUpdate(); |
216 | } | 361 | } |
217 | return ret; | 362 | return ret; |
@@ -229,7 +374,8 @@ public abstract class BSPhysObject : PhysicsActor | |||
229 | 374 | ||
230 | PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate() | 375 | PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate() |
231 | { | 376 | { |
232 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | 377 | if (PhysBody.HasPhysicalBody) |
378 | CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | ||
233 | }); | 379 | }); |
234 | } | 380 | } |
235 | else | 381 | else |
@@ -243,21 +389,187 @@ public abstract class BSPhysObject : PhysicsActor | |||
243 | SubscribedEventsMs = 0; | 389 | SubscribedEventsMs = 0; |
244 | PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate() | 390 | PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate() |
245 | { | 391 | { |
246 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | 392 | // Make sure there is a body there because sometimes destruction happens in an un-ideal order. |
393 | if (PhysBody.HasPhysicalBody) | ||
394 | CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | ||
247 | }); | 395 | }); |
248 | } | 396 | } |
249 | // Return 'true' if the simulator wants collision events | 397 | // Return 'true' if the simulator wants collision events |
250 | public override bool SubscribedEvents() { | 398 | public override bool SubscribedEvents() { |
251 | return (SubscribedEventsMs > 0); | 399 | return (SubscribedEventsMs > 0); |
252 | } | 400 | } |
401 | // Because 'CollisionScore' is called many times while sorting, it should not be recomputed | ||
402 | // each time called. So this is built to be light weight for each collision and to do | ||
403 | // all the processing when the user asks for the info. | ||
404 | public void ComputeCollisionScore() | ||
405 | { | ||
406 | // Scale the collision count by the time since the last collision. | ||
407 | // The "+1" prevents dividing by zero. | ||
408 | long timeAgo = PhysicsScene.SimulationStep - CollidingStep + 1; | ||
409 | CollisionScore = CollisionAccumulation / timeAgo; | ||
410 | } | ||
411 | public override float CollisionScore { get; set; } | ||
253 | 412 | ||
254 | #endregion // Collisions | 413 | #endregion // Collisions |
255 | 414 | ||
415 | #region Per Simulation Step actions | ||
416 | // There are some actions that must be performed for a physical object before each simulation step. | ||
417 | // These actions are optional so, rather than scanning all the physical objects and asking them | ||
418 | // if they have anything to do, a physical object registers for an event call before the step is performed. | ||
419 | // This bookkeeping makes it easy to add, remove and clean up after all these registrations. | ||
420 | private Dictionary<string, BSScene.PreStepAction> RegisteredPrestepActions = new Dictionary<string, BSScene.PreStepAction>(); | ||
421 | private Dictionary<string, BSScene.PostStepAction> RegisteredPoststepActions = new Dictionary<string, BSScene.PostStepAction>(); | ||
422 | protected void RegisterPreStepAction(string op, uint id, BSScene.PreStepAction actn) | ||
423 | { | ||
424 | string identifier = op + "-" + id.ToString(); | ||
425 | |||
426 | lock (RegisteredPrestepActions) | ||
427 | { | ||
428 | // Clean out any existing action | ||
429 | UnRegisterPreStepAction(op, id); | ||
430 | RegisteredPrestepActions[identifier] = actn; | ||
431 | PhysicsScene.BeforeStep += actn; | ||
432 | } | ||
433 | DetailLog("{0},BSPhysObject.RegisterPreStepAction,id={1}", LocalID, identifier); | ||
434 | } | ||
435 | |||
436 | // Unregister a pre step action. Safe to call if the action has not been registered. | ||
437 | // Returns 'true' if an action was actually removed | ||
438 | protected bool UnRegisterPreStepAction(string op, uint id) | ||
439 | { | ||
440 | string identifier = op + "-" + id.ToString(); | ||
441 | bool removed = false; | ||
442 | lock (RegisteredPrestepActions) | ||
443 | { | ||
444 | if (RegisteredPrestepActions.ContainsKey(identifier)) | ||
445 | { | ||
446 | PhysicsScene.BeforeStep -= RegisteredPrestepActions[identifier]; | ||
447 | RegisteredPrestepActions.Remove(identifier); | ||
448 | removed = true; | ||
449 | } | ||
450 | } | ||
451 | DetailLog("{0},BSPhysObject.UnRegisterPreStepAction,id={1},removed={2}", LocalID, identifier, removed); | ||
452 | return removed; | ||
453 | } | ||
454 | |||
455 | protected void UnRegisterAllPreStepActions() | ||
456 | { | ||
457 | lock (RegisteredPrestepActions) | ||
458 | { | ||
459 | foreach (KeyValuePair<string, BSScene.PreStepAction> kvp in RegisteredPrestepActions) | ||
460 | { | ||
461 | PhysicsScene.BeforeStep -= kvp.Value; | ||
462 | } | ||
463 | RegisteredPrestepActions.Clear(); | ||
464 | } | ||
465 | DetailLog("{0},BSPhysObject.UnRegisterAllPreStepActions,", LocalID); | ||
466 | } | ||
467 | |||
468 | protected void RegisterPostStepAction(string op, uint id, BSScene.PostStepAction actn) | ||
469 | { | ||
470 | string identifier = op + "-" + id.ToString(); | ||
471 | |||
472 | lock (RegisteredPoststepActions) | ||
473 | { | ||
474 | // Clean out any existing action | ||
475 | UnRegisterPostStepAction(op, id); | ||
476 | RegisteredPoststepActions[identifier] = actn; | ||
477 | PhysicsScene.AfterStep += actn; | ||
478 | } | ||
479 | DetailLog("{0},BSPhysObject.RegisterPostStepAction,id={1}", LocalID, identifier); | ||
480 | } | ||
481 | |||
482 | // Unregister a pre step action. Safe to call if the action has not been registered. | ||
483 | // Returns 'true' if an action was actually removed. | ||
484 | protected bool UnRegisterPostStepAction(string op, uint id) | ||
485 | { | ||
486 | string identifier = op + "-" + id.ToString(); | ||
487 | bool removed = false; | ||
488 | lock (RegisteredPoststepActions) | ||
489 | { | ||
490 | if (RegisteredPoststepActions.ContainsKey(identifier)) | ||
491 | { | ||
492 | PhysicsScene.AfterStep -= RegisteredPoststepActions[identifier]; | ||
493 | RegisteredPoststepActions.Remove(identifier); | ||
494 | removed = true; | ||
495 | } | ||
496 | } | ||
497 | DetailLog("{0},BSPhysObject.UnRegisterPostStepAction,id={1},removed={2}", LocalID, identifier, removed); | ||
498 | return removed; | ||
499 | } | ||
500 | |||
501 | protected void UnRegisterAllPostStepActions() | ||
502 | { | ||
503 | lock (RegisteredPoststepActions) | ||
504 | { | ||
505 | foreach (KeyValuePair<string, BSScene.PostStepAction> kvp in RegisteredPoststepActions) | ||
506 | { | ||
507 | PhysicsScene.AfterStep -= kvp.Value; | ||
508 | } | ||
509 | RegisteredPoststepActions.Clear(); | ||
510 | } | ||
511 | DetailLog("{0},BSPhysObject.UnRegisterAllPostStepActions,", LocalID); | ||
512 | } | ||
513 | |||
514 | // When an update to the physical properties happens, this event is fired to let | ||
515 | // different actors to modify the update before it is passed around | ||
516 | public delegate void PreUpdatePropertyAction(ref EntityProperties entprop); | ||
517 | public event PreUpdatePropertyAction OnPreUpdateProperty; | ||
518 | protected void TriggerPreUpdatePropertyAction(ref EntityProperties entprop) | ||
519 | { | ||
520 | PreUpdatePropertyAction actions = OnPreUpdateProperty; | ||
521 | if (actions != null) | ||
522 | actions(ref entprop); | ||
523 | } | ||
524 | |||
525 | private Dictionary<string, PreUpdatePropertyAction> RegisteredPreUpdatePropertyActions = new Dictionary<string, PreUpdatePropertyAction>(); | ||
526 | public void RegisterPreUpdatePropertyAction(string identifier, PreUpdatePropertyAction actn) | ||
527 | { | ||
528 | lock (RegisteredPreUpdatePropertyActions) | ||
529 | { | ||
530 | // Clean out any existing action | ||
531 | UnRegisterPreUpdatePropertyAction(identifier); | ||
532 | RegisteredPreUpdatePropertyActions[identifier] = actn; | ||
533 | OnPreUpdateProperty += actn; | ||
534 | } | ||
535 | DetailLog("{0},BSPhysObject.RegisterPreUpdatePropertyAction,id={1}", LocalID, identifier); | ||
536 | } | ||
537 | public bool UnRegisterPreUpdatePropertyAction(string identifier) | ||
538 | { | ||
539 | bool removed = false; | ||
540 | lock (RegisteredPreUpdatePropertyActions) | ||
541 | { | ||
542 | if (RegisteredPreUpdatePropertyActions.ContainsKey(identifier)) | ||
543 | { | ||
544 | OnPreUpdateProperty -= RegisteredPreUpdatePropertyActions[identifier]; | ||
545 | RegisteredPreUpdatePropertyActions.Remove(identifier); | ||
546 | removed = true; | ||
547 | } | ||
548 | } | ||
549 | DetailLog("{0},BSPhysObject.UnRegisterPreUpdatePropertyAction,id={1},removed={2}", LocalID, identifier, removed); | ||
550 | return removed; | ||
551 | } | ||
552 | public void UnRegisterAllPreUpdatePropertyActions() | ||
553 | { | ||
554 | lock (RegisteredPreUpdatePropertyActions) | ||
555 | { | ||
556 | foreach (KeyValuePair<string, PreUpdatePropertyAction> kvp in RegisteredPreUpdatePropertyActions) | ||
557 | { | ||
558 | OnPreUpdateProperty -= kvp.Value; | ||
559 | } | ||
560 | RegisteredPreUpdatePropertyActions.Clear(); | ||
561 | } | ||
562 | DetailLog("{0},BSPhysObject.UnRegisterAllPreUpdatePropertyAction,", LocalID); | ||
563 | } | ||
564 | |||
565 | #endregion // Per Simulation Step actions | ||
566 | |||
256 | // High performance detailed logging routine used by the physical objects. | 567 | // High performance detailed logging routine used by the physical objects. |
257 | protected void DetailLog(string msg, params Object[] args) | 568 | protected void DetailLog(string msg, params Object[] args) |
258 | { | 569 | { |
259 | if (PhysicsScene.PhysicsLogging.Enabled) | 570 | if (PhysicsScene.PhysicsLogging.Enabled) |
260 | PhysicsScene.DetailLog(msg, args); | 571 | PhysicsScene.DetailLog(msg, args); |
261 | } | 572 | } |
573 | |||
262 | } | 574 | } |
263 | } | 575 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs index 20f5180..9442854 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs | |||
@@ -59,13 +59,7 @@ public class BSPlugin : IPhysicsPlugin | |||
59 | { | 59 | { |
60 | if (_mScene == null) | 60 | if (_mScene == null) |
61 | { | 61 | { |
62 | if (Util.IsWindows()) | 62 | _mScene = new BSScene(GetName(), sceneIdentifier); |
63 | Util.LoadArchSpecificWindowsDll("BulletSim.dll"); | ||
64 | // If not Windows, loading is performed by the | ||
65 | // Mono loader as specified in | ||
66 | // "bin/Physics/OpenSim.Region.Physics.BulletSPlugin.dll.config". | ||
67 | |||
68 | _mScene = new BSScene(sceneIdentifier); | ||
69 | } | 63 | } |
70 | return (_mScene); | 64 | return (_mScene); |
71 | } | 65 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index 2b3fa25..6a5461a 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | |||
@@ -39,51 +39,49 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
39 | { | 39 | { |
40 | 40 | ||
41 | [Serializable] | 41 | [Serializable] |
42 | public sealed class BSPrim : BSPhysObject | 42 | public class BSPrim : BSPhysObject |
43 | { | 43 | { |
44 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 44 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
45 | private static readonly string LogHeader = "[BULLETS PRIM]"; | 45 | private static readonly string LogHeader = "[BULLETS PRIM]"; |
46 | 46 | ||
47 | // _size is what the user passed. Scale is what we pass to the physics engine with the mesh. | 47 | // _size is what the user passed. Scale is what we pass to the physics engine with the mesh. |
48 | // Often Scale is unity because the meshmerizer will apply _size when creating the mesh. | ||
49 | private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user | 48 | private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user |
50 | 49 | ||
51 | private bool _grabbed; | 50 | private bool _grabbed; |
52 | private bool _isSelected; | 51 | private bool _isSelected; |
53 | private bool _isVolumeDetect; | 52 | private bool _isVolumeDetect; |
53 | |||
54 | // _position is what the simulator thinks the positions of the prim is. | ||
54 | private OMV.Vector3 _position; | 55 | private OMV.Vector3 _position; |
56 | |||
55 | private float _mass; // the mass of this object | 57 | private float _mass; // the mass of this object |
56 | private float _density; | ||
57 | private OMV.Vector3 _force; | 58 | private OMV.Vector3 _force; |
58 | private OMV.Vector3 _velocity; | 59 | private OMV.Vector3 _velocity; |
59 | private OMV.Vector3 _torque; | 60 | private OMV.Vector3 _torque; |
60 | private float _collisionScore; | ||
61 | private OMV.Vector3 _acceleration; | 61 | private OMV.Vector3 _acceleration; |
62 | private OMV.Quaternion _orientation; | 62 | private OMV.Quaternion _orientation; |
63 | private int _physicsActorType; | 63 | private int _physicsActorType; |
64 | private bool _isPhysical; | 64 | private bool _isPhysical; |
65 | private bool _flying; | 65 | private bool _flying; |
66 | private float _friction; | ||
67 | private float _restitution; | ||
68 | private bool _setAlwaysRun; | 66 | private bool _setAlwaysRun; |
69 | private bool _throttleUpdates; | 67 | private bool _throttleUpdates; |
70 | private bool _isColliding; | ||
71 | private bool _collidingGround; | ||
72 | private bool _collidingObj; | ||
73 | private bool _floatOnWater; | 68 | private bool _floatOnWater; |
74 | private OMV.Vector3 _rotationalVelocity; | 69 | private OMV.Vector3 _rotationalVelocity; |
75 | private bool _kinematic; | 70 | private bool _kinematic; |
76 | private float _buoyancy; | 71 | private float _buoyancy; |
77 | 72 | ||
78 | private BSDynamics _vehicle; | 73 | private int CrossingFailures { get; set; } |
79 | 74 | ||
75 | public BSDynamics VehicleController { get; private set; } | ||
76 | |||
77 | private BSVMotor _targetMotor; | ||
80 | private OMV.Vector3 _PIDTarget; | 78 | private OMV.Vector3 _PIDTarget; |
81 | private bool _usePID; | ||
82 | private float _PIDTau; | 79 | private float _PIDTau; |
83 | private bool _useHoverPID; | 80 | |
81 | private BSFMotor _hoverMotor; | ||
84 | private float _PIDHoverHeight; | 82 | private float _PIDHoverHeight; |
85 | private PIDHoverType _PIDHoverType; | 83 | private PIDHoverType _PIDHoverType; |
86 | private float _PIDHoverTao; | 84 | private float _PIDHoverTau; |
87 | 85 | ||
88 | public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, | 86 | public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, |
89 | OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) | 87 | OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) |
@@ -93,31 +91,29 @@ public sealed class BSPrim : BSPhysObject | |||
93 | _physicsActorType = (int)ActorTypes.Prim; | 91 | _physicsActorType = (int)ActorTypes.Prim; |
94 | _position = pos; | 92 | _position = pos; |
95 | _size = size; | 93 | _size = size; |
96 | Scale = size; // the scale will be set by CreateGeom depending on object type | 94 | Scale = size; // prims are the size the user wants them to be (different for BSCharactes). |
97 | _orientation = rotation; | 95 | _orientation = rotation; |
98 | _buoyancy = 1f; | 96 | _buoyancy = 0f; |
99 | _velocity = OMV.Vector3.Zero; | 97 | _velocity = OMV.Vector3.Zero; |
100 | _rotationalVelocity = OMV.Vector3.Zero; | 98 | _rotationalVelocity = OMV.Vector3.Zero; |
101 | BaseShape = pbs; | 99 | BaseShape = pbs; |
102 | _isPhysical = pisPhysical; | 100 | _isPhysical = pisPhysical; |
103 | _isVolumeDetect = false; | 101 | _isVolumeDetect = false; |
104 | _friction = PhysicsScene.Params.defaultFriction; // TODO: compute based on object material | ||
105 | _density = PhysicsScene.Params.defaultDensity; // TODO: compute based on object material | ||
106 | _restitution = PhysicsScene.Params.defaultRestitution; | ||
107 | _vehicle = new BSDynamics(PhysicsScene, this); // add vehicleness | ||
108 | _mass = CalculateMass(); | ||
109 | 102 | ||
110 | // No body or shape yet | 103 | VehicleController = new BSDynamics(PhysicsScene, this); // add vehicleness |
111 | PhysBody = new BulletBody(LocalID, IntPtr.Zero); | 104 | |
112 | PhysShape = new BulletShape(IntPtr.Zero); | 105 | _mass = CalculateMass(); |
113 | 106 | ||
114 | DetailLog("{0},BSPrim.constructor,call", LocalID); | 107 | DetailLog("{0},BSPrim.constructor,call", LocalID); |
115 | // do the actual object creation at taint time | 108 | // do the actual object creation at taint time |
116 | PhysicsScene.TaintedObject("BSPrim.create", delegate() | 109 | PhysicsScene.TaintedObject("BSPrim.create", delegate() |
117 | { | 110 | { |
111 | // Make sure the object is being created with some sanity. | ||
112 | ExtremeSanityCheck(true /* inTaintTime */); | ||
113 | |||
118 | CreateGeomAndObject(true); | 114 | CreateGeomAndObject(true); |
119 | 115 | ||
120 | CurrentCollisionFlags = BulletSimAPI.GetCollisionFlags2(PhysBody.ptr); | 116 | CurrentCollisionFlags = PhysicsScene.PE.GetCollisionFlags(PhysBody); |
121 | }); | 117 | }); |
122 | } | 118 | } |
123 | 119 | ||
@@ -125,15 +121,7 @@ public sealed class BSPrim : BSPhysObject | |||
125 | public override void Destroy() | 121 | public override void Destroy() |
126 | { | 122 | { |
127 | // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID); | 123 | // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID); |
128 | 124 | base.Destroy(); | |
129 | // Undo any links between me and any other object | ||
130 | BSPhysObject parentBefore = Linkset.LinksetRoot; | ||
131 | int childrenBefore = Linkset.NumberOfChildren; | ||
132 | |||
133 | Linkset = Linkset.RemoveMeFromLinkset(this); | ||
134 | |||
135 | DetailLog("{0},BSPrim.Destroy,call,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}", | ||
136 | LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren); | ||
137 | 125 | ||
138 | // Undo any vehicle properties | 126 | // Undo any vehicle properties |
139 | this.VehicleType = (int)Vehicle.TYPE_NONE; | 127 | this.VehicleType = (int)Vehicle.TYPE_NONE; |
@@ -142,8 +130,10 @@ public sealed class BSPrim : BSPhysObject | |||
142 | { | 130 | { |
143 | DetailLog("{0},BSPrim.Destroy,taint,", LocalID); | 131 | DetailLog("{0},BSPrim.Destroy,taint,", LocalID); |
144 | // If there are physical body and shape, release my use of same. | 132 | // If there are physical body and shape, release my use of same. |
145 | PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null); | 133 | PhysicsScene.Shapes.DereferenceBody(PhysBody, null); |
146 | PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null); | 134 | PhysBody.Clear(); |
135 | PhysicsScene.Shapes.DereferenceShape(PhysShape, null); | ||
136 | PhysShape.Clear(); | ||
147 | }); | 137 | }); |
148 | } | 138 | } |
149 | 139 | ||
@@ -157,31 +147,37 @@ public sealed class BSPrim : BSPhysObject | |||
157 | // We presume the scale and size are the same. If scale must be changed for | 147 | // We presume the scale and size are the same. If scale must be changed for |
158 | // the physical shape, that is done when the geometry is built. | 148 | // the physical shape, that is done when the geometry is built. |
159 | _size = value; | 149 | _size = value; |
150 | Scale = _size; | ||
160 | ForceBodyShapeRebuild(false); | 151 | ForceBodyShapeRebuild(false); |
161 | } | 152 | } |
162 | } | 153 | } |
163 | // Scale is what we set in the physics engine. It is different than 'size' in that | ||
164 | // 'size' can be encorporated into the mesh. In that case, the scale is <1,1,1>. | ||
165 | public override OMV.Vector3 Scale { get; set; } | ||
166 | 154 | ||
167 | public override PrimitiveBaseShape Shape { | 155 | public override PrimitiveBaseShape Shape { |
168 | set { | 156 | set { |
169 | BaseShape = value; | 157 | BaseShape = value; |
158 | PrimAssetState = PrimAssetCondition.Unknown; | ||
170 | ForceBodyShapeRebuild(false); | 159 | ForceBodyShapeRebuild(false); |
171 | } | 160 | } |
172 | } | 161 | } |
173 | // Whatever the linkset wants is what I want. | 162 | // 'unknown' says to choose the best type |
174 | public override BSPhysicsShapeType PreferredPhysicalShape | 163 | public override BSPhysicsShapeType PreferredPhysicalShape |
175 | { get { return Linkset.PreferredPhysicalShape(this); } } | 164 | { get { return BSPhysicsShapeType.SHAPE_UNKNOWN; } } |
176 | 165 | ||
177 | public override bool ForceBodyShapeRebuild(bool inTaintTime) | 166 | public override bool ForceBodyShapeRebuild(bool inTaintTime) |
178 | { | 167 | { |
179 | LastAssetBuildFailed = false; | 168 | if (inTaintTime) |
180 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ForceBodyShapeRebuild", delegate() | ||
181 | { | 169 | { |
182 | _mass = CalculateMass(); // changing the shape changes the mass | 170 | _mass = CalculateMass(); // changing the shape changes the mass |
183 | CreateGeomAndObject(true); | 171 | CreateGeomAndObject(true); |
184 | }); | 172 | } |
173 | else | ||
174 | { | ||
175 | PhysicsScene.TaintedObject("BSPrim.ForceBodyShapeRebuild", delegate() | ||
176 | { | ||
177 | _mass = CalculateMass(); // changing the shape changes the mass | ||
178 | CreateGeomAndObject(true); | ||
179 | }); | ||
180 | } | ||
185 | return true; | 181 | return true; |
186 | } | 182 | } |
187 | public override bool Grabbed { | 183 | public override bool Grabbed { |
@@ -189,46 +185,44 @@ public sealed class BSPrim : BSPhysObject | |||
189 | } | 185 | } |
190 | } | 186 | } |
191 | public override bool Selected { | 187 | public override bool Selected { |
192 | set { | 188 | set |
193 | _isSelected = value; | 189 | { |
194 | PhysicsScene.TaintedObject("BSPrim.setSelected", delegate() | 190 | if (value != _isSelected) |
195 | { | 191 | { |
196 | DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected); | 192 | _isSelected = value; |
197 | SetObjectDynamic(false); | 193 | PhysicsScene.TaintedObject("BSPrim.setSelected", delegate() |
198 | }); | 194 | { |
195 | DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected); | ||
196 | SetObjectDynamic(false); | ||
197 | }); | ||
198 | } | ||
199 | } | 199 | } |
200 | } | 200 | } |
201 | public override void CrossingFailure() { return; } | 201 | public override bool IsSelected |
202 | { | ||
203 | get { return _isSelected; } | ||
204 | } | ||
202 | 205 | ||
203 | // link me to the specified parent | 206 | public override void CrossingFailure() |
204 | public override void link(PhysicsActor obj) { | 207 | { |
205 | BSPrim parent = obj as BSPrim; | 208 | CrossingFailures++; |
206 | if (parent != null) | 209 | if (CrossingFailures > BSParam.CrossingFailuresBeforeOutOfBounds) |
207 | { | 210 | { |
208 | BSPhysObject parentBefore = Linkset.LinksetRoot; | 211 | base.RaiseOutOfBounds(RawPosition); |
209 | int childrenBefore = Linkset.NumberOfChildren; | 212 | } |
210 | 213 | else if (CrossingFailures == BSParam.CrossingFailuresBeforeOutOfBounds) | |
211 | Linkset = parent.Linkset.AddMeToLinkset(this); | 214 | { |
212 | 215 | m_log.WarnFormat("{0} Too many crossing failures for {1}", LogHeader, Name); | |
213 | DetailLog("{0},BSPrim.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}", | ||
214 | LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren); | ||
215 | } | 216 | } |
216 | return; | 217 | return; |
217 | } | 218 | } |
218 | 219 | ||
220 | // link me to the specified parent | ||
221 | public override void link(PhysicsActor obj) { | ||
222 | } | ||
223 | |||
219 | // delink me from my linkset | 224 | // delink me from my linkset |
220 | public override void delink() { | 225 | public override void delink() { |
221 | // TODO: decide if this parent checking needs to happen at taint time | ||
222 | // Race condition here: if link() and delink() in same simulation tick, the delink will not happen | ||
223 | |||
224 | BSPhysObject parentBefore = Linkset.LinksetRoot; | ||
225 | int childrenBefore = Linkset.NumberOfChildren; | ||
226 | |||
227 | Linkset = Linkset.RemoveMeFromLinkset(this); | ||
228 | |||
229 | DetailLog("{0},BSPrim.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ", | ||
230 | LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren); | ||
231 | return; | ||
232 | } | 226 | } |
233 | 227 | ||
234 | // Set motion values to zero. | 228 | // Set motion values to zero. |
@@ -244,7 +238,8 @@ public sealed class BSPrim : BSPhysObject | |||
244 | // Zero some other properties in the physics engine | 238 | // Zero some other properties in the physics engine |
245 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() | 239 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() |
246 | { | 240 | { |
247 | BulletSimAPI.ClearAllForces2(PhysBody.ptr); | 241 | if (PhysBody.HasPhysicalBody) |
242 | PhysicsScene.PE.ClearAllForces(PhysBody); | ||
248 | }); | 243 | }); |
249 | } | 244 | } |
250 | public override void ZeroAngularMotion(bool inTaintTime) | 245 | public override void ZeroAngularMotion(bool inTaintTime) |
@@ -253,16 +248,107 @@ public sealed class BSPrim : BSPhysObject | |||
253 | // Zero some other properties in the physics engine | 248 | // Zero some other properties in the physics engine |
254 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() | 249 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() |
255 | { | 250 | { |
256 | BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); | 251 | // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity); |
257 | BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); | 252 | if (PhysBody.HasPhysicalBody) |
253 | { | ||
254 | PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity); | ||
255 | PhysicsScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity); | ||
256 | } | ||
258 | }); | 257 | }); |
259 | } | 258 | } |
260 | 259 | ||
260 | bool TryExperimentalLockAxisCode = false; | ||
261 | BSConstraint LockAxisConstraint = null; | ||
261 | public override void LockAngularMotion(OMV.Vector3 axis) | 262 | public override void LockAngularMotion(OMV.Vector3 axis) |
262 | { | 263 | { |
263 | DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis); | 264 | DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis); |
265 | |||
266 | // "1" means free, "0" means locked | ||
267 | OMV.Vector3 locking = new OMV.Vector3(1f, 1f, 1f); | ||
268 | if (axis.X != 1) locking.X = 0f; | ||
269 | if (axis.Y != 1) locking.Y = 0f; | ||
270 | if (axis.Z != 1) locking.Z = 0f; | ||
271 | LockedAxis = locking; | ||
272 | |||
273 | if (TryExperimentalLockAxisCode && LockedAxis != LockedAxisFree) | ||
274 | { | ||
275 | // Lock that axis by creating a 6DOF constraint that has one end in the world and | ||
276 | // the other in the object. | ||
277 | // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=20817 | ||
278 | // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=26380 | ||
279 | |||
280 | PhysicsScene.TaintedObject("BSPrim.LockAngularMotion", delegate() | ||
281 | { | ||
282 | CleanUpLockAxisPhysicals(true /* inTaintTime */); | ||
283 | |||
284 | BSConstraint6Dof axisConstrainer = new BSConstraint6Dof(PhysicsScene.World, PhysBody, | ||
285 | OMV.Vector3.Zero, OMV.Quaternion.Inverse(RawOrientation), | ||
286 | true /* useLinearReferenceFrameB */, true /* disableCollisionsBetweenLinkedBodies */); | ||
287 | LockAxisConstraint = axisConstrainer; | ||
288 | PhysicsScene.Constraints.AddConstraint(LockAxisConstraint); | ||
289 | |||
290 | // The constraint is tied to the world and oriented to the prim. | ||
291 | |||
292 | // Free to move linearly | ||
293 | OMV.Vector3 linearLow = OMV.Vector3.Zero; | ||
294 | OMV.Vector3 linearHigh = PhysicsScene.TerrainManager.DefaultRegionSize; | ||
295 | axisConstrainer.SetLinearLimits(linearLow, linearHigh); | ||
296 | |||
297 | // Angular with some axis locked | ||
298 | float f2PI = (float)Math.PI * 2f; | ||
299 | OMV.Vector3 angularLow = new OMV.Vector3(-f2PI, -f2PI, -f2PI); | ||
300 | OMV.Vector3 angularHigh = new OMV.Vector3(f2PI, f2PI, f2PI); | ||
301 | if (LockedAxis.X != 1f) | ||
302 | { | ||
303 | angularLow.X = 0f; | ||
304 | angularHigh.X = 0f; | ||
305 | } | ||
306 | if (LockedAxis.Y != 1f) | ||
307 | { | ||
308 | angularLow.Y = 0f; | ||
309 | angularHigh.Y = 0f; | ||
310 | } | ||
311 | if (LockedAxis.Z != 1f) | ||
312 | { | ||
313 | angularLow.Z = 0f; | ||
314 | angularHigh.Z = 0f; | ||
315 | } | ||
316 | axisConstrainer.SetAngularLimits(angularLow, angularHigh); | ||
317 | |||
318 | DetailLog("{0},BSPrim.LockAngularMotion,create,linLow={1},linHi={2},angLow={3},angHi={4}", | ||
319 | LocalID, linearLow, linearHigh, angularLow, angularHigh); | ||
320 | |||
321 | // Constants from one of the posts mentioned above and used in Bullet's ConstraintDemo. | ||
322 | axisConstrainer.TranslationalLimitMotor(true /* enable */, 5.0f, 0.1f); | ||
323 | |||
324 | axisConstrainer.RecomputeConstraintVariables(RawMass); | ||
325 | }); | ||
326 | } | ||
327 | else | ||
328 | { | ||
329 | // Everything seems unlocked | ||
330 | CleanUpLockAxisPhysicals(false /* inTaintTime */); | ||
331 | } | ||
332 | |||
264 | return; | 333 | return; |
265 | } | 334 | } |
335 | // Get rid of any constraint built for LockAxis | ||
336 | // Most often the constraint is removed when the constraint collection is cleaned for this prim. | ||
337 | private void CleanUpLockAxisPhysicals(bool inTaintTime) | ||
338 | { | ||
339 | if (LockAxisConstraint != null) | ||
340 | { | ||
341 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.CleanUpLockAxisPhysicals", delegate() | ||
342 | { | ||
343 | if (LockAxisConstraint != null) | ||
344 | { | ||
345 | PhysicsScene.Constraints.RemoveAndDestroyConstraint(LockAxisConstraint); | ||
346 | LockAxisConstraint = null; | ||
347 | DetailLog("{0},BSPrim.CleanUpLockAxisPhysicals,destroyingConstraint", LocalID); | ||
348 | } | ||
349 | }); | ||
350 | } | ||
351 | } | ||
266 | 352 | ||
267 | public override OMV.Vector3 RawPosition | 353 | public override OMV.Vector3 RawPosition |
268 | { | 354 | { |
@@ -271,41 +357,41 @@ public sealed class BSPrim : BSPhysObject | |||
271 | } | 357 | } |
272 | public override OMV.Vector3 Position { | 358 | public override OMV.Vector3 Position { |
273 | get { | 359 | get { |
274 | // child prims move around based on their parent. Need to get the latest location | ||
275 | if (!Linkset.IsRoot(this)) | ||
276 | _position = Linkset.Position(this); | ||
277 | |||
278 | // don't do the GetObjectPosition for root elements because this function is called a zillion times. | 360 | // don't do the GetObjectPosition for root elements because this function is called a zillion times. |
279 | // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr); | 361 | // _position = ForcePosition; |
280 | return _position; | 362 | return _position; |
281 | } | 363 | } |
282 | set { | 364 | set { |
283 | // If the position must be forced into the physics engine, use ForcePosition. | 365 | // If the position must be forced into the physics engine, use ForcePosition. |
366 | // All positions are given in world positions. | ||
284 | if (_position == value) | 367 | if (_position == value) |
285 | { | 368 | { |
369 | DetailLog("{0},BSPrim.setPosition,call,positionNotChanging,pos={1},orient={2}", LocalID, _position, _orientation); | ||
286 | return; | 370 | return; |
287 | } | 371 | } |
288 | _position = value; | 372 | _position = value; |
289 | // TODO: what does it mean to set the position of a child prim?? Rebuild the constraint? | ||
290 | PositionSanityCheck(false); | 373 | PositionSanityCheck(false); |
374 | |||
291 | PhysicsScene.TaintedObject("BSPrim.setPosition", delegate() | 375 | PhysicsScene.TaintedObject("BSPrim.setPosition", delegate() |
292 | { | 376 | { |
293 | // DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); | 377 | DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); |
294 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | 378 | ForcePosition = _position; |
295 | ActivateIfPhysical(false); | ||
296 | }); | 379 | }); |
297 | } | 380 | } |
298 | } | 381 | } |
382 | |||
299 | public override OMV.Vector3 ForcePosition { | 383 | public override OMV.Vector3 ForcePosition { |
300 | get { | 384 | get { |
301 | _position = BulletSimAPI.GetPosition2(PhysBody.ptr); | 385 | _position = PhysicsScene.PE.GetPosition(PhysBody); |
302 | return _position; | 386 | return _position; |
303 | } | 387 | } |
304 | set { | 388 | set { |
305 | _position = value; | 389 | _position = value; |
306 | // PositionSanityCheck(); // Don't do this! Causes a loop and caller should know better. | 390 | if (PhysBody.HasPhysicalBody) |
307 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | 391 | { |
308 | ActivateIfPhysical(false); | 392 | PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); |
393 | ActivateIfPhysical(false); | ||
394 | } | ||
309 | } | 395 | } |
310 | } | 396 | } |
311 | 397 | ||
@@ -316,119 +402,231 @@ public sealed class BSPrim : BSPhysObject | |||
316 | { | 402 | { |
317 | bool ret = false; | 403 | bool ret = false; |
318 | 404 | ||
319 | float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); | 405 | // We don't care where non-physical items are placed |
406 | if (!IsPhysicallyActive) | ||
407 | return ret; | ||
408 | |||
409 | if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(RawPosition)) | ||
410 | { | ||
411 | // The physical object is out of the known/simulated area. | ||
412 | // Upper levels of code will handle the transition to other areas so, for | ||
413 | // the time, we just ignore the position. | ||
414 | return ret; | ||
415 | } | ||
416 | |||
417 | float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition); | ||
320 | OMV.Vector3 upForce = OMV.Vector3.Zero; | 418 | OMV.Vector3 upForce = OMV.Vector3.Zero; |
321 | if (Position.Z < terrainHeight) | 419 | float approxSize = Math.Max(Size.X, Math.Max(Size.Y, Size.Z)); |
420 | if ((RawPosition.Z + approxSize / 2f) < terrainHeight) | ||
322 | { | 421 | { |
323 | DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight); | 422 | DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, RawPosition, terrainHeight); |
324 | float targetHeight = terrainHeight + (Size.Z / 2f); | 423 | float targetHeight = terrainHeight + (Size.Z / 2f); |
325 | // Upforce proportional to the distance away from the terrain. Correct the error in 1 sec. | 424 | // If the object is below ground it just has to be moved up because pushing will |
326 | upForce.Z = (terrainHeight - Position.Z) * 1f; | 425 | // not get it through the terrain |
426 | _position.Z = targetHeight; | ||
427 | if (inTaintTime) | ||
428 | { | ||
429 | ForcePosition = _position; | ||
430 | } | ||
431 | // If we are throwing the object around, zero its other forces | ||
432 | ZeroMotion(inTaintTime); | ||
327 | ret = true; | 433 | ret = true; |
328 | } | 434 | } |
329 | 435 | ||
330 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) | 436 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) |
331 | { | 437 | { |
332 | float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position); | 438 | float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position); |
333 | // TODO: a floating motor so object will bob in the water | 439 | // TODO: a floating motor so object will bob in the water |
334 | if (Math.Abs(Position.Z - waterHeight) > 0.1f) | 440 | if (Math.Abs(RawPosition.Z - waterHeight) > 0.1f) |
335 | { | 441 | { |
336 | // Upforce proportional to the distance away from the water. Correct the error in 1 sec. | 442 | // Upforce proportional to the distance away from the water. Correct the error in 1 sec. |
337 | upForce.Z = (waterHeight - Position.Z) * 1f; | 443 | upForce.Z = (waterHeight - RawPosition.Z) * 1f; |
444 | |||
445 | // Apply upforce and overcome gravity. | ||
446 | OMV.Vector3 correctionForce = upForce - PhysicsScene.DefaultGravity; | ||
447 | DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, _position, upForce, correctionForce); | ||
448 | AddForce(correctionForce, false, inTaintTime); | ||
338 | ret = true; | 449 | ret = true; |
339 | } | 450 | } |
340 | } | 451 | } |
341 | 452 | ||
342 | // TODO: check for out of bounds | 453 | return ret; |
454 | } | ||
455 | |||
456 | // Occasionally things will fly off and really get lost. | ||
457 | // Find the wanderers and bring them back. | ||
458 | // Return 'true' if some parameter need some sanity. | ||
459 | private bool ExtremeSanityCheck(bool inTaintTime) | ||
460 | { | ||
461 | bool ret = false; | ||
343 | 462 | ||
344 | // The above code computes a force to apply to correct any out-of-bounds problems. Apply same. | 463 | uint wayOutThere = Constants.RegionSize * Constants.RegionSize; |
345 | if (ret) | 464 | // There have been instances of objects getting thrown way out of bounds and crashing |
465 | // the border crossing code. | ||
466 | if ( _position.X < -Constants.RegionSize || _position.X > wayOutThere | ||
467 | || _position.Y < -Constants.RegionSize || _position.Y > wayOutThere | ||
468 | || _position.Z < -Constants.RegionSize || _position.Z > wayOutThere) | ||
346 | { | 469 | { |
347 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.PositionSanityCheck:belowTerrain", delegate() | 470 | _position = new OMV.Vector3(10, 10, 50); |
348 | { | 471 | ZeroMotion(inTaintTime); |
349 | // Apply upforce and overcome gravity. | 472 | ret = true; |
350 | ForceVelocity = ForceVelocity + upForce - PhysicsScene.DefaultGravity; | 473 | } |
351 | }); | 474 | if (_velocity.LengthSquared() > BSParam.MaxLinearVelocity) |
475 | { | ||
476 | _velocity = Util.ClampV(_velocity, BSParam.MaxLinearVelocity); | ||
477 | ret = true; | ||
352 | } | 478 | } |
479 | if (_rotationalVelocity.LengthSquared() > BSParam.MaxAngularVelocitySquared) | ||
480 | { | ||
481 | _rotationalVelocity = Util.ClampV(_rotationalVelocity, BSParam.MaxAngularVelocity); | ||
482 | ret = true; | ||
483 | } | ||
484 | |||
353 | return ret; | 485 | return ret; |
354 | } | 486 | } |
355 | 487 | ||
356 | // Return the effective mass of the object. | 488 | // Return the effective mass of the object. |
357 | // If there are multiple items in the linkset, add them together for the root | 489 | // The definition of this call is to return the mass of the prim. |
490 | // If the simulator cares about the mass of the linkset, it will sum it itself. | ||
358 | public override float Mass | 491 | public override float Mass |
359 | { | 492 | { |
360 | get | 493 | get { return _mass; } |
361 | { | 494 | } |
362 | return Linkset.LinksetMass; | 495 | // TotalMass returns the mass of the large object the prim may be in (overridden by linkset code) |
363 | // return _mass; | 496 | public virtual float TotalMass |
364 | } | 497 | { |
498 | get { return _mass; } | ||
365 | } | 499 | } |
366 | |||
367 | // used when we only want this prim's mass and not the linkset thing | 500 | // used when we only want this prim's mass and not the linkset thing |
368 | public override float RawMass { | 501 | public override float RawMass { |
369 | get { return _mass; } | 502 | get { return _mass; } |
370 | } | 503 | } |
371 | // Set the physical mass to the passed mass. | 504 | // Set the physical mass to the passed mass. |
372 | // Note that this does not change _mass! | 505 | // Note that this does not change _mass! |
373 | public override void UpdatePhysicalMassProperties(float physMass) | 506 | public override void UpdatePhysicalMassProperties(float physMass, bool inWorld) |
374 | { | 507 | { |
375 | if (IsStatic) | 508 | if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape) |
376 | { | 509 | { |
377 | Inertia = OMV.Vector3.Zero; | 510 | if (IsStatic) |
378 | BulletSimAPI.SetMassProps2(PhysBody.ptr, 0f, Inertia); | 511 | { |
379 | BulletSimAPI.UpdateInertiaTensor2(PhysBody.ptr); | 512 | PhysicsScene.PE.SetGravity(PhysBody, PhysicsScene.DefaultGravity); |
513 | Inertia = OMV.Vector3.Zero; | ||
514 | PhysicsScene.PE.SetMassProps(PhysBody, 0f, Inertia); | ||
515 | PhysicsScene.PE.UpdateInertiaTensor(PhysBody); | ||
516 | } | ||
517 | else | ||
518 | { | ||
519 | if (inWorld) | ||
520 | { | ||
521 | // Changing interesting properties doesn't change proxy and collision cache | ||
522 | // information. The Bullet solution is to re-add the object to the world | ||
523 | // after parameters are changed. | ||
524 | PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody); | ||
525 | } | ||
526 | |||
527 | // The computation of mass props requires gravity to be set on the object. | ||
528 | Gravity = ComputeGravity(Buoyancy); | ||
529 | PhysicsScene.PE.SetGravity(PhysBody, Gravity); | ||
530 | |||
531 | Inertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape, physMass); | ||
532 | PhysicsScene.PE.SetMassProps(PhysBody, physMass, Inertia); | ||
533 | PhysicsScene.PE.UpdateInertiaTensor(PhysBody); | ||
534 | |||
535 | DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2},grav={3},inWorld={4}", | ||
536 | LocalID, physMass, Inertia, Gravity, inWorld); | ||
537 | |||
538 | if (inWorld) | ||
539 | { | ||
540 | AddObjectToPhysicalWorld(); | ||
541 | } | ||
542 | } | ||
380 | } | 543 | } |
381 | else | 544 | } |
545 | |||
546 | // Return what gravity should be set to this very moment | ||
547 | public OMV.Vector3 ComputeGravity(float buoyancy) | ||
548 | { | ||
549 | OMV.Vector3 ret = PhysicsScene.DefaultGravity; | ||
550 | |||
551 | if (!IsStatic) | ||
382 | { | 552 | { |
383 | Inertia = BulletSimAPI.CalculateLocalInertia2(PhysShape.ptr, physMass); | 553 | ret *= (1f - buoyancy); |
384 | BulletSimAPI.SetMassProps2(PhysBody.ptr, physMass, Inertia); | 554 | ret *= GravModifier; |
385 | BulletSimAPI.UpdateInertiaTensor2(PhysBody.ptr); | ||
386 | // center of mass is at the zero of the object | ||
387 | // DEBUG DEBUG BulletSimAPI.SetCenterOfMassByPosRot2(PhysBody.ptr, ForcePosition, ForceOrientation); | ||
388 | DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2}", LocalID, physMass, Inertia); | ||
389 | } | 555 | } |
556 | |||
557 | return ret; | ||
390 | } | 558 | } |
391 | 559 | ||
392 | // Is this used? | 560 | // Is this used? |
393 | public override OMV.Vector3 CenterOfMass | 561 | public override OMV.Vector3 CenterOfMass |
394 | { | 562 | { |
395 | get { return Linkset.CenterOfMass; } | 563 | get { return RawPosition; } |
396 | } | 564 | } |
397 | 565 | ||
398 | // Is this used? | 566 | // Is this used? |
399 | public override OMV.Vector3 GeometricCenter | 567 | public override OMV.Vector3 GeometricCenter |
400 | { | 568 | { |
401 | get { return Linkset.GeometricCenter; } | 569 | get { return RawPosition; } |
402 | } | 570 | } |
403 | 571 | ||
404 | public override OMV.Vector3 Force { | 572 | public override OMV.Vector3 Force { |
405 | get { return _force; } | 573 | get { return _force; } |
406 | set { | 574 | set { |
407 | _force = value; | 575 | _force = value; |
408 | PhysicsScene.TaintedObject("BSPrim.setForce", delegate() | 576 | if (_force != OMV.Vector3.Zero) |
409 | { | 577 | { |
410 | // DetailLog("{0},BSPrim.setForce,taint,force={1}", LocalID, _force); | 578 | // If the force is non-zero, it must be reapplied each tick because |
411 | BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); | 579 | // Bullet clears the forces applied last frame. |
412 | }); | 580 | RegisterPreStepAction("BSPrim.setForce", LocalID, |
581 | delegate(float timeStep) | ||
582 | { | ||
583 | if (!IsPhysicallyActive || _force == OMV.Vector3.Zero) | ||
584 | { | ||
585 | UnRegisterPreStepAction("BSPrim.setForce", LocalID); | ||
586 | return; | ||
587 | } | ||
588 | |||
589 | DetailLog("{0},BSPrim.setForce,preStep,force={1}", LocalID, _force); | ||
590 | if (PhysBody.HasPhysicalBody) | ||
591 | { | ||
592 | PhysicsScene.PE.ApplyCentralForce(PhysBody, _force); | ||
593 | ActivateIfPhysical(false); | ||
594 | } | ||
595 | } | ||
596 | ); | ||
597 | } | ||
598 | else | ||
599 | { | ||
600 | UnRegisterPreStepAction("BSPrim.setForce", LocalID); | ||
601 | } | ||
413 | } | 602 | } |
414 | } | 603 | } |
415 | 604 | ||
416 | public override int VehicleType { | 605 | public override int VehicleType { |
417 | get { | 606 | get { |
418 | return (int)_vehicle.Type; // if we are a vehicle, return that type | 607 | return (int)VehicleController.Type; // if we are a vehicle, return that type |
419 | } | 608 | } |
420 | set { | 609 | set { |
421 | Vehicle type = (Vehicle)value; | 610 | Vehicle type = (Vehicle)value; |
422 | 611 | ||
423 | // Tell the scene about the vehicle so it will get processing each frame. | ||
424 | PhysicsScene.VehicleInSceneTypeChanged(this, type); | ||
425 | |||
426 | PhysicsScene.TaintedObject("setVehicleType", delegate() | 612 | PhysicsScene.TaintedObject("setVehicleType", delegate() |
427 | { | 613 | { |
428 | // Done at taint time so we're sure the physics engine is not using the variables | 614 | // Done at taint time so we're sure the physics engine is not using the variables |
429 | // Vehicle code changes the parameters for this vehicle type. | 615 | // Vehicle code changes the parameters for this vehicle type. |
430 | _vehicle.ProcessTypeChange(type); | 616 | VehicleController.ProcessTypeChange(type); |
431 | ActivateIfPhysical(false); | 617 | ActivateIfPhysical(false); |
618 | |||
619 | // If an active vehicle, register the vehicle code to be called before each step | ||
620 | if (VehicleController.Type == Vehicle.TYPE_NONE) | ||
621 | { | ||
622 | UnRegisterPreStepAction("BSPrim.Vehicle", LocalID); | ||
623 | UnRegisterPostStepAction("BSPrim.Vehicle", LocalID); | ||
624 | } | ||
625 | else | ||
626 | { | ||
627 | RegisterPreStepAction("BSPrim.Vehicle", LocalID, VehicleController.Step); | ||
628 | RegisterPostStepAction("BSPrim.Vehicle", LocalID, VehicleController.PostStep); | ||
629 | } | ||
432 | }); | 630 | }); |
433 | } | 631 | } |
434 | } | 632 | } |
@@ -436,7 +634,7 @@ public sealed class BSPrim : BSPhysObject | |||
436 | { | 634 | { |
437 | PhysicsScene.TaintedObject("BSPrim.VehicleFloatParam", delegate() | 635 | PhysicsScene.TaintedObject("BSPrim.VehicleFloatParam", delegate() |
438 | { | 636 | { |
439 | _vehicle.ProcessFloatVehicleParam((Vehicle)param, value); | 637 | VehicleController.ProcessFloatVehicleParam((Vehicle)param, value); |
440 | ActivateIfPhysical(false); | 638 | ActivateIfPhysical(false); |
441 | }); | 639 | }); |
442 | } | 640 | } |
@@ -444,7 +642,7 @@ public sealed class BSPrim : BSPhysObject | |||
444 | { | 642 | { |
445 | PhysicsScene.TaintedObject("BSPrim.VehicleVectorParam", delegate() | 643 | PhysicsScene.TaintedObject("BSPrim.VehicleVectorParam", delegate() |
446 | { | 644 | { |
447 | _vehicle.ProcessVectorVehicleParam((Vehicle)param, value); | 645 | VehicleController.ProcessVectorVehicleParam((Vehicle)param, value); |
448 | ActivateIfPhysical(false); | 646 | ActivateIfPhysical(false); |
449 | }); | 647 | }); |
450 | } | 648 | } |
@@ -452,7 +650,7 @@ public sealed class BSPrim : BSPhysObject | |||
452 | { | 650 | { |
453 | PhysicsScene.TaintedObject("BSPrim.VehicleRotationParam", delegate() | 651 | PhysicsScene.TaintedObject("BSPrim.VehicleRotationParam", delegate() |
454 | { | 652 | { |
455 | _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation); | 653 | VehicleController.ProcessRotationVehicleParam((Vehicle)param, rotation); |
456 | ActivateIfPhysical(false); | 654 | ActivateIfPhysical(false); |
457 | }); | 655 | }); |
458 | } | 656 | } |
@@ -460,27 +658,10 @@ public sealed class BSPrim : BSPhysObject | |||
460 | { | 658 | { |
461 | PhysicsScene.TaintedObject("BSPrim.VehicleFlags", delegate() | 659 | PhysicsScene.TaintedObject("BSPrim.VehicleFlags", delegate() |
462 | { | 660 | { |
463 | _vehicle.ProcessVehicleFlags(param, remove); | 661 | VehicleController.ProcessVehicleFlags(param, remove); |
464 | }); | 662 | }); |
465 | } | 663 | } |
466 | 664 | ||
467 | // Called each simulation step to advance vehicle characteristics. | ||
468 | // Called from Scene when doing simulation step so we're in taint processing time. | ||
469 | public override void StepVehicle(float timeStep) | ||
470 | { | ||
471 | if (IsPhysical && _vehicle.IsActive) | ||
472 | { | ||
473 | _vehicle.Step(timeStep); | ||
474 | /* // TEST TEST DEBUG DEBUG -- trying to reduce the extra action of Bullet simulation step | ||
475 | PhysicsScene.PostTaintObject("BSPrim.StepVehicles", LocalID, delegate() | ||
476 | { | ||
477 | // This resets the interpolation values and recomputes the tensor variables | ||
478 | BulletSimAPI.SetCenterOfMassByPosRot2(BSBody.ptr, ForcePosition, ForceOrientation); | ||
479 | }); | ||
480 | */ | ||
481 | } | ||
482 | } | ||
483 | |||
484 | // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more | 665 | // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more |
485 | public override void SetVolumeDetect(int param) { | 666 | public override void SetVolumeDetect(int param) { |
486 | bool newValue = (param != 0); | 667 | bool newValue = (param != 0); |
@@ -495,6 +676,81 @@ public sealed class BSPrim : BSPhysObject | |||
495 | } | 676 | } |
496 | return; | 677 | return; |
497 | } | 678 | } |
679 | public override void SetMaterial(int material) | ||
680 | { | ||
681 | base.SetMaterial(material); | ||
682 | PhysicsScene.TaintedObject("BSPrim.SetMaterial", delegate() | ||
683 | { | ||
684 | UpdatePhysicalParameters(); | ||
685 | }); | ||
686 | } | ||
687 | public override float Friction | ||
688 | { | ||
689 | get { return base.Friction; } | ||
690 | set | ||
691 | { | ||
692 | if (base.Friction != value) | ||
693 | { | ||
694 | base.Friction = value; | ||
695 | PhysicsScene.TaintedObject("BSPrim.setFriction", delegate() | ||
696 | { | ||
697 | UpdatePhysicalParameters(); | ||
698 | }); | ||
699 | } | ||
700 | } | ||
701 | } | ||
702 | public override float Restitution | ||
703 | { | ||
704 | get { return base.Restitution; } | ||
705 | set | ||
706 | { | ||
707 | if (base.Restitution != value) | ||
708 | { | ||
709 | base.Restitution = value; | ||
710 | PhysicsScene.TaintedObject("BSPrim.setRestitution", delegate() | ||
711 | { | ||
712 | UpdatePhysicalParameters(); | ||
713 | }); | ||
714 | } | ||
715 | } | ||
716 | } | ||
717 | // The simulator/viewer keep density as 100kg/m3. | ||
718 | // Remember to use BSParam.DensityScaleFactor to create the physical density. | ||
719 | public override float Density | ||
720 | { | ||
721 | get { return base.Density; } | ||
722 | set | ||
723 | { | ||
724 | if (base.Density != value) | ||
725 | { | ||
726 | base.Density = value; | ||
727 | PhysicsScene.TaintedObject("BSPrim.setDensity", delegate() | ||
728 | { | ||
729 | UpdatePhysicalParameters(); | ||
730 | }); | ||
731 | } | ||
732 | } | ||
733 | } | ||
734 | public override float GravModifier | ||
735 | { | ||
736 | get { return base.GravModifier; } | ||
737 | set | ||
738 | { | ||
739 | if (base.GravModifier != value) | ||
740 | { | ||
741 | base.GravModifier = value; | ||
742 | PhysicsScene.TaintedObject("BSPrim.setGravityModifier", delegate() | ||
743 | { | ||
744 | UpdatePhysicalParameters(); | ||
745 | }); | ||
746 | } | ||
747 | } | ||
748 | } | ||
749 | public override OMV.Vector3 RawVelocity | ||
750 | { | ||
751 | get { return _velocity; } | ||
752 | set { _velocity = value; } | ||
753 | } | ||
498 | public override OMV.Vector3 Velocity { | 754 | public override OMV.Vector3 Velocity { |
499 | get { return _velocity; } | 755 | get { return _velocity; } |
500 | set { | 756 | set { |
@@ -502,30 +758,53 @@ public sealed class BSPrim : BSPhysObject | |||
502 | PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate() | 758 | PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate() |
503 | { | 759 | { |
504 | // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity); | 760 | // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity); |
505 | BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); | 761 | ForceVelocity = _velocity; |
506 | }); | 762 | }); |
507 | } | 763 | } |
508 | } | 764 | } |
509 | public override OMV.Vector3 ForceVelocity { | 765 | public override OMV.Vector3 ForceVelocity { |
510 | get { return _velocity; } | 766 | get { return _velocity; } |
511 | set { | 767 | set { |
512 | _velocity = value; | 768 | PhysicsScene.AssertInTaintTime("BSPrim.ForceVelocity"); |
513 | BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); | 769 | |
770 | _velocity = Util.ClampV(value, BSParam.MaxLinearVelocity); | ||
771 | if (PhysBody.HasPhysicalBody) | ||
772 | { | ||
773 | DetailLog("{0},BSPrim.ForceVelocity,taint,vel={1}", LocalID, _velocity); | ||
774 | PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity); | ||
775 | ActivateIfPhysical(false); | ||
776 | } | ||
514 | } | 777 | } |
515 | } | 778 | } |
516 | public override OMV.Vector3 Torque { | 779 | public override OMV.Vector3 Torque { |
517 | get { return _torque; } | 780 | get { return _torque; } |
518 | set { | 781 | set { |
519 | _torque = value; | 782 | _torque = value; |
520 | AddAngularForce(_torque, false, false); | 783 | if (_torque != OMV.Vector3.Zero) |
784 | { | ||
785 | // If the torque is non-zero, it must be reapplied each tick because | ||
786 | // Bullet clears the forces applied last frame. | ||
787 | RegisterPreStepAction("BSPrim.setTorque", LocalID, | ||
788 | delegate(float timeStep) | ||
789 | { | ||
790 | if (!IsPhysicallyActive || _torque == OMV.Vector3.Zero) | ||
791 | { | ||
792 | UnRegisterPreStepAction("BSPrim.setTorque", LocalID); | ||
793 | return; | ||
794 | } | ||
795 | |||
796 | if (PhysBody.HasPhysicalBody) | ||
797 | AddAngularForce(_torque, false, true); | ||
798 | } | ||
799 | ); | ||
800 | } | ||
801 | else | ||
802 | { | ||
803 | UnRegisterPreStepAction("BSPrim.setTorque", LocalID); | ||
804 | } | ||
521 | // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque); | 805 | // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque); |
522 | } | 806 | } |
523 | } | 807 | } |
524 | public override float CollisionScore { | ||
525 | get { return _collisionScore; } | ||
526 | set { _collisionScore = value; | ||
527 | } | ||
528 | } | ||
529 | public override OMV.Vector3 Acceleration { | 808 | public override OMV.Vector3 Acceleration { |
530 | get { return _acceleration; } | 809 | get { return _acceleration; } |
531 | set { _acceleration = value; } | 810 | set { _acceleration = value; } |
@@ -537,23 +816,16 @@ public sealed class BSPrim : BSPhysObject | |||
537 | } | 816 | } |
538 | public override OMV.Quaternion Orientation { | 817 | public override OMV.Quaternion Orientation { |
539 | get { | 818 | get { |
540 | // Children move around because tied to parent. Get a fresh value. | ||
541 | if (!Linkset.IsRoot(this)) | ||
542 | { | ||
543 | _orientation = Linkset.Orientation(this); | ||
544 | } | ||
545 | return _orientation; | 819 | return _orientation; |
546 | } | 820 | } |
547 | set { | 821 | set { |
548 | if (_orientation == value) | 822 | if (_orientation == value) |
549 | return; | 823 | return; |
550 | _orientation = value; | 824 | _orientation = value; |
551 | // TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint? | 825 | |
552 | PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate() | 826 | PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate() |
553 | { | 827 | { |
554 | // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr); | 828 | ForceOrientation = _orientation; |
555 | // DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation); | ||
556 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | ||
557 | }); | 829 | }); |
558 | } | 830 | } |
559 | } | 831 | } |
@@ -562,13 +834,14 @@ public sealed class BSPrim : BSPhysObject | |||
562 | { | 834 | { |
563 | get | 835 | get |
564 | { | 836 | { |
565 | _orientation = BulletSimAPI.GetOrientation2(PhysBody.ptr); | 837 | _orientation = PhysicsScene.PE.GetOrientation(PhysBody); |
566 | return _orientation; | 838 | return _orientation; |
567 | } | 839 | } |
568 | set | 840 | set |
569 | { | 841 | { |
570 | _orientation = value; | 842 | _orientation = value; |
571 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | 843 | if (PhysBody.HasPhysicalBody) |
844 | PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); | ||
572 | } | 845 | } |
573 | } | 846 | } |
574 | public override int PhysicsActorType { | 847 | public override int PhysicsActorType { |
@@ -583,10 +856,11 @@ public sealed class BSPrim : BSPhysObject | |||
583 | _isPhysical = value; | 856 | _isPhysical = value; |
584 | PhysicsScene.TaintedObject("BSPrim.setIsPhysical", delegate() | 857 | PhysicsScene.TaintedObject("BSPrim.setIsPhysical", delegate() |
585 | { | 858 | { |
586 | // DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical); | 859 | DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical); |
587 | SetObjectDynamic(true); | 860 | SetObjectDynamic(true); |
588 | // whether phys-to-static or static-to-phys, the object is not moving. | 861 | // whether phys-to-static or static-to-phys, the object is not moving. |
589 | ZeroMotion(true); | 862 | ZeroMotion(true); |
863 | |||
590 | }); | 864 | }); |
591 | } | 865 | } |
592 | } | 866 | } |
@@ -604,6 +878,12 @@ public sealed class BSPrim : BSPhysObject | |||
604 | get { return !IsPhantom && !_isVolumeDetect; } | 878 | get { return !IsPhantom && !_isVolumeDetect; } |
605 | } | 879 | } |
606 | 880 | ||
881 | // The object is moving and is actively being dynamic in the physical world | ||
882 | public override bool IsPhysicallyActive | ||
883 | { | ||
884 | get { return !_isSelected && IsPhysical; } | ||
885 | } | ||
886 | |||
607 | // Make gravity work if the object is physical and not selected | 887 | // Make gravity work if the object is physical and not selected |
608 | // Called at taint-time!! | 888 | // Called at taint-time!! |
609 | private void SetObjectDynamic(bool forceRebuild) | 889 | private void SetObjectDynamic(bool forceRebuild) |
@@ -618,19 +898,24 @@ public sealed class BSPrim : BSPhysObject | |||
618 | // isSolid: other objects bounce off of this object | 898 | // isSolid: other objects bounce off of this object |
619 | // isVolumeDetect: other objects pass through but can generate collisions | 899 | // isVolumeDetect: other objects pass through but can generate collisions |
620 | // collisionEvents: whether this object returns collision events | 900 | // collisionEvents: whether this object returns collision events |
621 | private void UpdatePhysicalParameters() | 901 | public virtual void UpdatePhysicalParameters() |
622 | { | 902 | { |
623 | // DetailLog("{0},BSPrim.UpdatePhysicalParameters,entry,body={1},shape={2}", LocalID, BSBody, BSShape); | 903 | if (!PhysBody.HasPhysicalBody) |
904 | { | ||
905 | // This would only happen if updates are called for during initialization when the body is not set up yet. | ||
906 | DetailLog("{0},BSPrim.UpdatePhysicalParameters,taint,calledWithNoPhysBody", LocalID); | ||
907 | return; | ||
908 | } | ||
624 | 909 | ||
625 | // Mangling all the physical properties requires the object not be in the physical world. | 910 | // Mangling all the physical properties requires the object not be in the physical world. |
626 | // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found). | 911 | // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found). |
627 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, PhysBody.ptr); | 912 | PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody); |
628 | 913 | ||
629 | // Set up the object physicalness (does gravity and collisions move this object) | 914 | // Set up the object physicalness (does gravity and collisions move this object) |
630 | MakeDynamic(IsStatic); | 915 | MakeDynamic(IsStatic); |
631 | 916 | ||
632 | // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters) | 917 | // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters) |
633 | _vehicle.Refresh(); | 918 | VehicleController.Refresh(); |
634 | 919 | ||
635 | // Arrange for collision events if the simulator wants them | 920 | // Arrange for collision events if the simulator wants them |
636 | EnableCollisions(SubscribedEvents()); | 921 | EnableCollisions(SubscribedEvents()); |
@@ -638,25 +923,13 @@ public sealed class BSPrim : BSPhysObject | |||
638 | // Make solid or not (do things bounce off or pass through this object). | 923 | // Make solid or not (do things bounce off or pass through this object). |
639 | MakeSolid(IsSolid); | 924 | MakeSolid(IsSolid); |
640 | 925 | ||
641 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, PhysBody.ptr); | 926 | AddObjectToPhysicalWorld(); |
642 | 927 | ||
643 | // Rebuild its shape | 928 | // Rebuild its shape |
644 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr); | 929 | PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, PhysBody); |
645 | |||
646 | // Collision filter can be set only when the object is in the world | ||
647 | if (PhysBody.collisionFilter != 0 || PhysBody.collisionMask != 0) | ||
648 | { | ||
649 | BulletSimAPI.SetCollisionFilterMask2(PhysBody.ptr, (uint)PhysBody.collisionFilter, (uint)PhysBody.collisionMask); | ||
650 | } | ||
651 | |||
652 | // Recompute any linkset parameters. | ||
653 | // When going from non-physical to physical, this re-enables the constraints that | ||
654 | // had been automatically disabled when the mass was set to zero. | ||
655 | // For compound based linksets, this enables and disables interactions of the children. | ||
656 | Linkset.Refresh(this); | ||
657 | 930 | ||
658 | DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},body={6},shape={7}", | 931 | DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},cType={6},body={7},shape={8}", |
659 | LocalID, IsStatic, IsSolid, _mass, SubscribedEvents(), CurrentCollisionFlags, PhysBody, PhysShape); | 932 | LocalID, IsStatic, IsSolid, Mass, SubscribedEvents(), CurrentCollisionFlags, PhysBody.collisionType, PhysBody, PhysShape); |
660 | } | 933 | } |
661 | 934 | ||
662 | // "Making dynamic" means changing to and from static. | 935 | // "Making dynamic" means changing to and from static. |
@@ -664,79 +937,78 @@ public sealed class BSPrim : BSPhysObject | |||
664 | // When dynamic, the object can fall and be pushed by others. | 937 | // When dynamic, the object can fall and be pushed by others. |
665 | // This is independent of its 'solidness' which controls what passes through | 938 | // This is independent of its 'solidness' which controls what passes through |
666 | // this object and what interacts with it. | 939 | // this object and what interacts with it. |
667 | private void MakeDynamic(bool makeStatic) | 940 | protected virtual void MakeDynamic(bool makeStatic) |
668 | { | 941 | { |
669 | if (makeStatic) | 942 | if (makeStatic) |
670 | { | 943 | { |
671 | // Become a Bullet 'static' object type | 944 | // Become a Bullet 'static' object type |
672 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT); | 945 | CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT); |
673 | // Stop all movement | 946 | // Stop all movement |
674 | ZeroMotion(true); | 947 | ZeroMotion(true); |
675 | // Center of mass is at the center of the object | 948 | |
676 | // DEBUG DEBUG BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.PhysBody.ptr, _position, _orientation); | 949 | // Set various physical properties so other object interact properly |
950 | PhysicsScene.PE.SetFriction(PhysBody, Friction); | ||
951 | PhysicsScene.PE.SetRestitution(PhysBody, Restitution); | ||
952 | PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); | ||
953 | |||
677 | // Mass is zero which disables a bunch of physics stuff in Bullet | 954 | // Mass is zero which disables a bunch of physics stuff in Bullet |
678 | UpdatePhysicalMassProperties(0f); | 955 | UpdatePhysicalMassProperties(0f, false); |
679 | // Set collision detection parameters | 956 | // Set collision detection parameters |
680 | if (PhysicsScene.Params.ccdMotionThreshold > 0f) | 957 | if (BSParam.CcdMotionThreshold > 0f) |
681 | { | 958 | { |
682 | BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold); | 959 | PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); |
683 | BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); | 960 | PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); |
684 | } | 961 | } |
685 | // There can be special things needed for implementing linksets | 962 | |
686 | Linkset.MakeStatic(this); | ||
687 | // The activation state is 'disabled' so Bullet will not try to act on it. | 963 | // The activation state is 'disabled' so Bullet will not try to act on it. |
688 | BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_SIMULATION); | 964 | // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_SIMULATION); |
689 | // Start it out sleeping and physical actions could wake it up. | 965 | // Start it out sleeping and physical actions could wake it up. |
690 | // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ISLAND_SLEEPING); | 966 | PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ISLAND_SLEEPING); |
691 | 967 | ||
692 | PhysBody.collisionFilter = CollisionFilterGroups.StaticObjectFilter; | 968 | // This collides like a static object |
693 | PhysBody.collisionMask = CollisionFilterGroups.StaticObjectMask; | 969 | PhysBody.collisionType = CollisionType.Static; |
694 | } | 970 | } |
695 | else | 971 | else |
696 | { | 972 | { |
697 | // Not a Bullet static object | 973 | // Not a Bullet static object |
698 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT); | 974 | CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT); |
699 | 975 | ||
700 | // Set various physical properties so internal dynamic properties will get computed correctly as they are set | 976 | // Set various physical properties so other object interact properly |
701 | BulletSimAPI.SetFriction2(PhysBody.ptr, PhysicsScene.Params.defaultFriction); | 977 | PhysicsScene.PE.SetFriction(PhysBody, Friction); |
702 | BulletSimAPI.SetRestitution2(PhysBody.ptr, PhysicsScene.Params.defaultRestitution); | 978 | PhysicsScene.PE.SetRestitution(PhysBody, Restitution); |
979 | // DetailLog("{0},BSPrim.MakeDynamic,frict={1},rest={2}", LocalID, Friction, Restitution); | ||
703 | 980 | ||
704 | // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 | 981 | // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 |
705 | // Since this can be called multiple times, only zero forces when becoming physical | 982 | // Since this can be called multiple times, only zero forces when becoming physical |
706 | // BulletSimAPI.ClearAllForces2(BSBody.ptr); | 983 | // PhysicsScene.PE.ClearAllForces(BSBody); |
707 | 984 | ||
708 | // For good measure, make sure the transform is set through to the motion state | 985 | // For good measure, make sure the transform is set through to the motion state |
709 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | 986 | ForcePosition = _position; |
710 | 987 | ForceVelocity = _velocity; | |
711 | // Center of mass is at the center of the object | 988 | ForceRotationalVelocity = _rotationalVelocity; |
712 | // DEBUG DEBUG BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.PhysBody.ptr, _position, _orientation); | ||
713 | 989 | ||
714 | // A dynamic object has mass | 990 | // A dynamic object has mass |
715 | UpdatePhysicalMassProperties(RawMass); | 991 | UpdatePhysicalMassProperties(RawMass, false); |
716 | 992 | ||
717 | // Set collision detection parameters | 993 | // Set collision detection parameters |
718 | if (PhysicsScene.Params.ccdMotionThreshold > 0f) | 994 | if (BSParam.CcdMotionThreshold > 0f) |
719 | { | 995 | { |
720 | BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold); | 996 | PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); |
721 | BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); | 997 | PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); |
722 | } | 998 | } |
723 | 999 | ||
724 | // Various values for simulation limits | 1000 | // Various values for simulation limits |
725 | BulletSimAPI.SetDamping2(PhysBody.ptr, PhysicsScene.Params.linearDamping, PhysicsScene.Params.angularDamping); | 1001 | PhysicsScene.PE.SetDamping(PhysBody, BSParam.LinearDamping, BSParam.AngularDamping); |
726 | BulletSimAPI.SetDeactivationTime2(PhysBody.ptr, PhysicsScene.Params.deactivationTime); | 1002 | PhysicsScene.PE.SetDeactivationTime(PhysBody, BSParam.DeactivationTime); |
727 | BulletSimAPI.SetSleepingThresholds2(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold); | 1003 | PhysicsScene.PE.SetSleepingThresholds(PhysBody, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold); |
728 | BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, PhysicsScene.Params.contactProcessingThreshold); | 1004 | PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); |
729 | 1005 | ||
730 | // There might be special things needed for implementing linksets. | 1006 | // This collides like an object. |
731 | Linkset.MakeDynamic(this); | 1007 | PhysBody.collisionType = CollisionType.Dynamic; |
732 | 1008 | ||
733 | // Force activation of the object so Bullet will act on it. | 1009 | // Force activation of the object so Bullet will act on it. |
734 | // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects. | 1010 | // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects. |
735 | BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ACTIVE_TAG); | 1011 | PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG); |
736 | // BulletSimAPI.Activate2(BSBody.ptr, true); | ||
737 | |||
738 | PhysBody.collisionFilter = CollisionFilterGroups.ObjectFilter; | ||
739 | PhysBody.collisionMask = CollisionFilterGroups.ObjectMask; | ||
740 | } | 1012 | } |
741 | } | 1013 | } |
742 | 1014 | ||
@@ -746,7 +1018,7 @@ public sealed class BSPrim : BSPhysObject | |||
746 | // the functions after this one set up the state of a possibly newly created collision body. | 1018 | // the functions after this one set up the state of a possibly newly created collision body. |
747 | private void MakeSolid(bool makeSolid) | 1019 | private void MakeSolid(bool makeSolid) |
748 | { | 1020 | { |
749 | CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(PhysBody.ptr); | 1021 | CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysicsScene.PE.GetBodyType(PhysBody); |
750 | if (makeSolid) | 1022 | if (makeSolid) |
751 | { | 1023 | { |
752 | // Verify the previous code created the correct shape for this type of thing. | 1024 | // Verify the previous code created the correct shape for this type of thing. |
@@ -754,7 +1026,7 @@ public sealed class BSPrim : BSPhysObject | |||
754 | { | 1026 | { |
755 | m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType); | 1027 | m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType); |
756 | } | 1028 | } |
757 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); | 1029 | CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); |
758 | } | 1030 | } |
759 | else | 1031 | else |
760 | { | 1032 | { |
@@ -762,9 +1034,10 @@ public sealed class BSPrim : BSPhysObject | |||
762 | { | 1034 | { |
763 | m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType); | 1035 | m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType); |
764 | } | 1036 | } |
765 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); | 1037 | CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); |
766 | PhysBody.collisionFilter = CollisionFilterGroups.VolumeDetectFilter; | 1038 | |
767 | PhysBody.collisionMask = CollisionFilterGroups.VolumeDetectMask; | 1039 | // Change collision info from a static object to a ghosty collision object |
1040 | PhysBody.collisionType = CollisionType.VolumeDetect; | ||
768 | } | 1041 | } |
769 | } | 1042 | } |
770 | 1043 | ||
@@ -773,8 +1046,8 @@ public sealed class BSPrim : BSPhysObject | |||
773 | // Called in taint-time!! | 1046 | // Called in taint-time!! |
774 | private void ActivateIfPhysical(bool forceIt) | 1047 | private void ActivateIfPhysical(bool forceIt) |
775 | { | 1048 | { |
776 | if (IsPhysical) | 1049 | if (IsPhysical && PhysBody.HasPhysicalBody) |
777 | BulletSimAPI.Activate2(PhysBody.ptr, forceIt); | 1050 | PhysicsScene.PE.Activate(PhysBody, forceIt); |
778 | } | 1051 | } |
779 | 1052 | ||
780 | // Turn on or off the flag controlling whether collision events are returned to the simulator. | 1053 | // Turn on or off the flag controlling whether collision events are returned to the simulator. |
@@ -782,11 +1055,27 @@ public sealed class BSPrim : BSPhysObject | |||
782 | { | 1055 | { |
783 | if (wantsCollisionEvents) | 1056 | if (wantsCollisionEvents) |
784 | { | 1057 | { |
785 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | 1058 | CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); |
1059 | } | ||
1060 | else | ||
1061 | { | ||
1062 | CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | ||
1063 | } | ||
1064 | } | ||
1065 | |||
1066 | // Add me to the physical world. | ||
1067 | // Object MUST NOT already be in the world. | ||
1068 | // This routine exists because some assorted properties get mangled by adding to the world. | ||
1069 | internal void AddObjectToPhysicalWorld() | ||
1070 | { | ||
1071 | if (PhysBody.HasPhysicalBody) | ||
1072 | { | ||
1073 | PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody); | ||
786 | } | 1074 | } |
787 | else | 1075 | else |
788 | { | 1076 | { |
789 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | 1077 | m_log.ErrorFormat("{0} Attempt to add physical object without body. id={1}", LogHeader, LocalID); |
1078 | DetailLog("{0},BSPrim.AddObjectToPhysicalWorld,addObjectWithoutBody,cType={1}", LocalID, PhysBody.collisionType); | ||
790 | } | 1079 | } |
791 | } | 1080 | } |
792 | 1081 | ||
@@ -805,18 +1094,6 @@ public sealed class BSPrim : BSPhysObject | |||
805 | get { return _throttleUpdates; } | 1094 | get { return _throttleUpdates; } |
806 | set { _throttleUpdates = value; } | 1095 | set { _throttleUpdates = value; } |
807 | } | 1096 | } |
808 | public override bool IsColliding { | ||
809 | get { return (CollidingStep == PhysicsScene.SimulationStep); } | ||
810 | set { _isColliding = value; } | ||
811 | } | ||
812 | public override bool CollidingGround { | ||
813 | get { return (CollidingGroundStep == PhysicsScene.SimulationStep); } | ||
814 | set { _collidingGround = value; } | ||
815 | } | ||
816 | public override bool CollidingObj { | ||
817 | get { return _collidingObj; } | ||
818 | set { _collidingObj = value; } | ||
819 | } | ||
820 | public bool IsPhantom { | 1097 | public bool IsPhantom { |
821 | get { | 1098 | get { |
822 | // SceneObjectPart removes phantom objects from the physics scene | 1099 | // SceneObjectPart removes phantom objects from the physics scene |
@@ -831,32 +1108,23 @@ public sealed class BSPrim : BSPhysObject | |||
831 | PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate() | 1108 | PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate() |
832 | { | 1109 | { |
833 | if (_floatOnWater) | 1110 | if (_floatOnWater) |
834 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); | 1111 | CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); |
835 | else | 1112 | else |
836 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); | 1113 | CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); |
837 | }); | 1114 | }); |
838 | } | 1115 | } |
839 | } | 1116 | } |
840 | public override OMV.Vector3 RotationalVelocity { | 1117 | public override OMV.Vector3 RotationalVelocity { |
841 | get { | 1118 | get { |
842 | /* | ||
843 | OMV.Vector3 pv = OMV.Vector3.Zero; | ||
844 | // if close to zero, report zero | ||
845 | // This is copied from ODE but I'm not sure why it returns zero but doesn't | ||
846 | // zero the property in the physics engine. | ||
847 | if (_rotationalVelocity.ApproxEquals(pv, 0.2f)) | ||
848 | return pv; | ||
849 | */ | ||
850 | |||
851 | return _rotationalVelocity; | 1119 | return _rotationalVelocity; |
852 | } | 1120 | } |
853 | set { | 1121 | set { |
854 | _rotationalVelocity = value; | 1122 | _rotationalVelocity = value; |
1123 | Util.ClampV(_rotationalVelocity, BSParam.MaxAngularVelocity); | ||
855 | // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); | 1124 | // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); |
856 | PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate() | 1125 | PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate() |
857 | { | 1126 | { |
858 | DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); | 1127 | ForceRotationalVelocity = _rotationalVelocity; |
859 | BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity); | ||
860 | }); | 1128 | }); |
861 | } | 1129 | } |
862 | } | 1130 | } |
@@ -865,8 +1133,14 @@ public sealed class BSPrim : BSPhysObject | |||
865 | return _rotationalVelocity; | 1133 | return _rotationalVelocity; |
866 | } | 1134 | } |
867 | set { | 1135 | set { |
868 | _rotationalVelocity = value; | 1136 | _rotationalVelocity = Util.ClampV(value, BSParam.MaxAngularVelocity); |
869 | BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity); | 1137 | if (PhysBody.HasPhysicalBody) |
1138 | { | ||
1139 | DetailLog("{0},BSPrim.ForceRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); | ||
1140 | PhysicsScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity); | ||
1141 | // PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity); | ||
1142 | ActivateIfPhysical(false); | ||
1143 | } | ||
870 | } | 1144 | } |
871 | } | 1145 | } |
872 | public override bool Kinematic { | 1146 | public override bool Kinematic { |
@@ -890,27 +1164,130 @@ public sealed class BSPrim : BSPhysObject | |||
890 | set { | 1164 | set { |
891 | _buoyancy = value; | 1165 | _buoyancy = value; |
892 | // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); | 1166 | // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); |
893 | // Buoyancy is faked by changing the gravity applied to the object | 1167 | // Force the recalculation of the various inertia,etc variables in the object |
894 | float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); | 1168 | UpdatePhysicalMassProperties(RawMass, true); |
895 | BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav)); | 1169 | DetailLog("{0},BSPrim.ForceBuoyancy,buoy={1},mass={2},grav={3}", LocalID, _buoyancy, RawMass, Gravity); |
1170 | ActivateIfPhysical(false); | ||
896 | } | 1171 | } |
897 | } | 1172 | } |
898 | 1173 | ||
899 | // Used for MoveTo | 1174 | // Used for MoveTo |
900 | public override OMV.Vector3 PIDTarget { | 1175 | public override OMV.Vector3 PIDTarget { |
901 | set { _PIDTarget = value; } | 1176 | set |
902 | } | 1177 | { |
903 | public override bool PIDActive { | 1178 | // TODO: add a sanity check -- don't move more than a region or something like that. |
904 | set { _usePID = value; } | 1179 | _PIDTarget = value; |
1180 | } | ||
905 | } | 1181 | } |
906 | public override float PIDTau { | 1182 | public override float PIDTau { |
907 | set { _PIDTau = value; } | 1183 | set { _PIDTau = value; } |
908 | } | 1184 | } |
1185 | public override bool PIDActive { | ||
1186 | set { | ||
1187 | if (value) | ||
1188 | { | ||
1189 | // We're taking over after this. | ||
1190 | ZeroMotion(true); | ||
1191 | |||
1192 | _targetMotor = new BSVMotor("BSPrim.PIDTarget", | ||
1193 | _PIDTau, // timeScale | ||
1194 | BSMotor.Infinite, // decay time scale | ||
1195 | BSMotor.InfiniteVector, // friction timescale | ||
1196 | 1f // efficiency | ||
1197 | ); | ||
1198 | _targetMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages. | ||
1199 | _targetMotor.SetTarget(_PIDTarget); | ||
1200 | _targetMotor.SetCurrent(RawPosition); | ||
1201 | /* | ||
1202 | _targetMotor = new BSPIDVMotor("BSPrim.PIDTarget"); | ||
1203 | _targetMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages. | ||
1204 | |||
1205 | _targetMotor.SetTarget(_PIDTarget); | ||
1206 | _targetMotor.SetCurrent(RawPosition); | ||
1207 | _targetMotor.TimeScale = _PIDTau; | ||
1208 | _targetMotor.Efficiency = 1f; | ||
1209 | */ | ||
1210 | |||
1211 | RegisterPreStepAction("BSPrim.PIDTarget", LocalID, delegate(float timeStep) | ||
1212 | { | ||
1213 | if (!IsPhysicallyActive) | ||
1214 | { | ||
1215 | UnRegisterPreStepAction("BSPrim.PIDTarget", LocalID); | ||
1216 | return; | ||
1217 | } | ||
1218 | |||
1219 | OMV.Vector3 origPosition = RawPosition; // DEBUG DEBUG (for printout below) | ||
1220 | |||
1221 | // 'movePosition' is where we'd like the prim to be at this moment. | ||
1222 | OMV.Vector3 movePosition = RawPosition + _targetMotor.Step(timeStep); | ||
1223 | |||
1224 | // If we are very close to our target, turn off the movement motor. | ||
1225 | if (_targetMotor.ErrorIsZero()) | ||
1226 | { | ||
1227 | DetailLog("{0},BSPrim.PIDTarget,zeroMovement,movePos={1},pos={2},mass={3}", | ||
1228 | LocalID, movePosition, RawPosition, Mass); | ||
1229 | ForcePosition = _targetMotor.TargetValue; | ||
1230 | _targetMotor.Enabled = false; | ||
1231 | } | ||
1232 | else | ||
1233 | { | ||
1234 | _position = movePosition; | ||
1235 | PositionSanityCheck(true /* intaintTime */); | ||
1236 | ForcePosition = _position; | ||
1237 | } | ||
1238 | DetailLog("{0},BSPrim.PIDTarget,move,fromPos={1},movePos={2}", LocalID, origPosition, movePosition); | ||
1239 | }); | ||
1240 | } | ||
1241 | else | ||
1242 | { | ||
1243 | // Stop any targetting | ||
1244 | UnRegisterPreStepAction("BSPrim.PIDTarget", LocalID); | ||
1245 | } | ||
1246 | } | ||
1247 | } | ||
909 | 1248 | ||
910 | // Used for llSetHoverHeight and maybe vehicle height | 1249 | // Used for llSetHoverHeight and maybe vehicle height |
911 | // Hover Height will override MoveTo target's Z | 1250 | // Hover Height will override MoveTo target's Z |
912 | public override bool PIDHoverActive { | 1251 | public override bool PIDHoverActive { |
913 | set { _useHoverPID = value; } | 1252 | set { |
1253 | if (value) | ||
1254 | { | ||
1255 | // Turning the target on | ||
1256 | _hoverMotor = new BSFMotor("BSPrim.Hover", | ||
1257 | _PIDHoverTau, // timeScale | ||
1258 | BSMotor.Infinite, // decay time scale | ||
1259 | BSMotor.Infinite, // friction timescale | ||
1260 | 1f // efficiency | ||
1261 | ); | ||
1262 | _hoverMotor.SetTarget(ComputeCurrentPIDHoverHeight()); | ||
1263 | _hoverMotor.SetCurrent(RawPosition.Z); | ||
1264 | _hoverMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages. | ||
1265 | |||
1266 | RegisterPreStepAction("BSPrim.Hover", LocalID, delegate(float timeStep) | ||
1267 | { | ||
1268 | // Don't do hovering while the object is selected. | ||
1269 | if (!IsPhysicallyActive) | ||
1270 | return; | ||
1271 | |||
1272 | _hoverMotor.SetCurrent(RawPosition.Z); | ||
1273 | _hoverMotor.SetTarget(ComputeCurrentPIDHoverHeight()); | ||
1274 | float targetHeight = _hoverMotor.Step(timeStep); | ||
1275 | |||
1276 | // 'targetHeight' is where we'd like the Z of the prim to be at this moment. | ||
1277 | // Compute the amount of force to push us there. | ||
1278 | float moveForce = (targetHeight - RawPosition.Z) * Mass; | ||
1279 | // Undo anything the object thinks it's doing at the moment | ||
1280 | moveForce = -RawVelocity.Z * Mass; | ||
1281 | |||
1282 | PhysicsScene.PE.ApplyCentralImpulse(PhysBody, new OMV.Vector3(0f, 0f, moveForce)); | ||
1283 | DetailLog("{0},BSPrim.Hover,move,targHt={1},moveForce={2},mass={3}", LocalID, targetHeight, moveForce, Mass); | ||
1284 | }); | ||
1285 | } | ||
1286 | else | ||
1287 | { | ||
1288 | UnRegisterPreStepAction("BSPrim.Hover", LocalID); | ||
1289 | } | ||
1290 | } | ||
914 | } | 1291 | } |
915 | public override float PIDHoverHeight { | 1292 | public override float PIDHoverHeight { |
916 | set { _PIDHoverHeight = value; } | 1293 | set { _PIDHoverHeight = value; } |
@@ -919,8 +1296,35 @@ public sealed class BSPrim : BSPhysObject | |||
919 | set { _PIDHoverType = value; } | 1296 | set { _PIDHoverType = value; } |
920 | } | 1297 | } |
921 | public override float PIDHoverTau { | 1298 | public override float PIDHoverTau { |
922 | set { _PIDHoverTao = value; } | 1299 | set { _PIDHoverTau = value; } |
923 | } | 1300 | } |
1301 | // Based on current position, determine what we should be hovering at now. | ||
1302 | // Must recompute often. What if we walked offa cliff> | ||
1303 | private float ComputeCurrentPIDHoverHeight() | ||
1304 | { | ||
1305 | float ret = _PIDHoverHeight; | ||
1306 | float groundHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition); | ||
1307 | |||
1308 | switch (_PIDHoverType) | ||
1309 | { | ||
1310 | case PIDHoverType.Ground: | ||
1311 | ret = groundHeight + _PIDHoverHeight; | ||
1312 | break; | ||
1313 | case PIDHoverType.GroundAndWater: | ||
1314 | float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(RawPosition); | ||
1315 | if (groundHeight > waterHeight) | ||
1316 | { | ||
1317 | ret = groundHeight + _PIDHoverHeight; | ||
1318 | } | ||
1319 | else | ||
1320 | { | ||
1321 | ret = waterHeight + _PIDHoverHeight; | ||
1322 | } | ||
1323 | break; | ||
1324 | } | ||
1325 | return ret; | ||
1326 | } | ||
1327 | |||
924 | 1328 | ||
925 | // For RotLookAt | 1329 | // For RotLookAt |
926 | public override OMV.Quaternion APIDTarget { set { return; } } | 1330 | public override OMV.Quaternion APIDTarget { set { return; } } |
@@ -928,54 +1332,73 @@ public sealed class BSPrim : BSPhysObject | |||
928 | public override float APIDStrength { set { return; } } | 1332 | public override float APIDStrength { set { return; } } |
929 | public override float APIDDamping { set { return; } } | 1333 | public override float APIDDamping { set { return; } } |
930 | 1334 | ||
931 | private List<OMV.Vector3> m_accumulatedForces = new List<OMV.Vector3>(); | ||
932 | public override void AddForce(OMV.Vector3 force, bool pushforce) { | 1335 | public override void AddForce(OMV.Vector3 force, bool pushforce) { |
933 | AddForce(force, pushforce, false); | 1336 | // Per documentation, max force is limited. |
1337 | OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude); | ||
1338 | |||
1339 | // Since this force is being applied in only one step, make this a force per second. | ||
1340 | addForce /= PhysicsScene.LastTimeStep; | ||
1341 | AddForce(addForce, pushforce, false /* inTaintTime */); | ||
934 | } | 1342 | } |
1343 | |||
935 | // Applying a force just adds this to the total force on the object. | 1344 | // Applying a force just adds this to the total force on the object. |
1345 | // This added force will only last the next simulation tick. | ||
936 | public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { | 1346 | public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { |
937 | // for an object, doesn't matter if force is a pushforce or not | 1347 | // for an object, doesn't matter if force is a pushforce or not |
938 | if (force.IsFinite()) | 1348 | if (IsPhysicallyActive) |
939 | { | ||
940 | // _force += force; | ||
941 | lock (m_accumulatedForces) | ||
942 | m_accumulatedForces.Add(new OMV.Vector3(force)); | ||
943 | } | ||
944 | else | ||
945 | { | 1349 | { |
946 | m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); | 1350 | if (force.IsFinite()) |
947 | return; | ||
948 | } | ||
949 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate() | ||
950 | { | ||
951 | OMV.Vector3 fSum = OMV.Vector3.Zero; | ||
952 | lock (m_accumulatedForces) | ||
953 | { | 1351 | { |
954 | // Sum the accumulated additional forces for one big force to apply once. | 1352 | // DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce); |
955 | foreach (OMV.Vector3 v in m_accumulatedForces) | 1353 | |
1354 | OMV.Vector3 addForce = force; | ||
1355 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate() | ||
956 | { | 1356 | { |
957 | fSum += v; | 1357 | // Bullet adds this central force to the total force for this tick |
958 | } | 1358 | DetailLog("{0},BSPrim.addForce,taint,force={1}", LocalID, addForce); |
959 | m_accumulatedForces.Clear(); | 1359 | if (PhysBody.HasPhysicalBody) |
1360 | { | ||
1361 | PhysicsScene.PE.ApplyCentralForce(PhysBody, addForce); | ||
1362 | ActivateIfPhysical(false); | ||
1363 | } | ||
1364 | }); | ||
960 | } | 1365 | } |
961 | DetailLog("{0},BSPrim.AddForce,taint,force={1}", LocalID, fSum); | 1366 | else |
962 | if (fSum != OMV.Vector3.Zero) | 1367 | { |
963 | BulletSimAPI.ApplyCentralForce2(PhysBody.ptr, fSum); | 1368 | m_log.WarnFormat("{0}: AddForce: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); |
964 | }); | 1369 | return; |
1370 | } | ||
1371 | } | ||
965 | } | 1372 | } |
966 | 1373 | ||
967 | // An impulse force is scaled by the mass of the object. | 1374 | public void AddForceImpulse(OMV.Vector3 impulse, bool pushforce, bool inTaintTime) { |
968 | public void ApplyForceImpulse(OMV.Vector3 impulse, bool inTaintTime) | 1375 | // for an object, doesn't matter if force is a pushforce or not |
969 | { | 1376 | if (!IsPhysicallyActive) |
970 | OMV.Vector3 applyImpulse = impulse; | ||
971 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyForceImpulse", delegate() | ||
972 | { | 1377 | { |
973 | DetailLog("{0},BSPrim.ApplyForceImpulse,taint,tImpulse={1}", LocalID, applyImpulse); | 1378 | if (impulse.IsFinite()) |
974 | BulletSimAPI.ApplyCentralImpulse2(PhysBody.ptr, applyImpulse); | 1379 | { |
975 | }); | 1380 | OMV.Vector3 addImpulse = Util.ClampV(impulse, BSParam.MaxAddForceMagnitude); |
1381 | // DetailLog("{0},BSPrim.addForceImpulse,call,impulse={1}", LocalID, impulse); | ||
1382 | |||
1383 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddImpulse", delegate() | ||
1384 | { | ||
1385 | // Bullet adds this impulse immediately to the velocity | ||
1386 | DetailLog("{0},BSPrim.addForceImpulse,taint,impulseforce={1}", LocalID, addImpulse); | ||
1387 | if (PhysBody.HasPhysicalBody) | ||
1388 | { | ||
1389 | PhysicsScene.PE.ApplyCentralImpulse(PhysBody, addImpulse); | ||
1390 | ActivateIfPhysical(false); | ||
1391 | } | ||
1392 | }); | ||
1393 | } | ||
1394 | else | ||
1395 | { | ||
1396 | m_log.WarnFormat("{0}: AddForceImpulse: Got a NaN impulse applied to a prim. LocalID={1}", LogHeader, LocalID); | ||
1397 | return; | ||
1398 | } | ||
1399 | } | ||
976 | } | 1400 | } |
977 | 1401 | ||
978 | private List<OMV.Vector3> m_accumulatedAngularForces = new List<OMV.Vector3>(); | ||
979 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { | 1402 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { |
980 | AddAngularForce(force, pushforce, false); | 1403 | AddAngularForce(force, pushforce, false); |
981 | } | 1404 | } |
@@ -983,42 +1406,38 @@ public sealed class BSPrim : BSPhysObject | |||
983 | { | 1406 | { |
984 | if (force.IsFinite()) | 1407 | if (force.IsFinite()) |
985 | { | 1408 | { |
986 | // _force += force; | 1409 | OMV.Vector3 angForce = force; |
987 | lock (m_accumulatedAngularForces) | 1410 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate() |
988 | m_accumulatedAngularForces.Add(new OMV.Vector3(force)); | 1411 | { |
1412 | if (PhysBody.HasPhysicalBody) | ||
1413 | { | ||
1414 | DetailLog("{0},BSPrim.AddAngularForce,taint,angForce={1}", LocalID, angForce); | ||
1415 | PhysicsScene.PE.ApplyTorque(PhysBody, angForce); | ||
1416 | ActivateIfPhysical(false); | ||
1417 | } | ||
1418 | }); | ||
989 | } | 1419 | } |
990 | else | 1420 | else |
991 | { | 1421 | { |
992 | m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); | 1422 | m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); |
993 | return; | 1423 | return; |
994 | } | 1424 | } |
995 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate() | ||
996 | { | ||
997 | OMV.Vector3 fSum = OMV.Vector3.Zero; | ||
998 | lock (m_accumulatedAngularForces) | ||
999 | { | ||
1000 | // Sum the accumulated additional forces for one big force to apply once. | ||
1001 | foreach (OMV.Vector3 v in m_accumulatedAngularForces) | ||
1002 | { | ||
1003 | fSum += v; | ||
1004 | } | ||
1005 | m_accumulatedAngularForces.Clear(); | ||
1006 | } | ||
1007 | DetailLog("{0},BSPrim.AddAngularForce,taint,aForce={1}", LocalID, fSum); | ||
1008 | if (fSum != OMV.Vector3.Zero) | ||
1009 | { | ||
1010 | BulletSimAPI.ApplyTorque2(PhysBody.ptr, fSum); | ||
1011 | _torque = fSum; | ||
1012 | } | ||
1013 | }); | ||
1014 | } | 1425 | } |
1426 | |||
1015 | // A torque impulse. | 1427 | // A torque impulse. |
1428 | // ApplyTorqueImpulse adds torque directly to the angularVelocity. | ||
1429 | // AddAngularForce accumulates the force and applied it to the angular velocity all at once. | ||
1430 | // Computed as: angularVelocity += impulse * inertia; | ||
1016 | public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime) | 1431 | public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime) |
1017 | { | 1432 | { |
1018 | OMV.Vector3 applyImpulse = impulse; | 1433 | OMV.Vector3 applyImpulse = impulse; |
1019 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate() | 1434 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate() |
1020 | { | 1435 | { |
1021 | BulletSimAPI.ApplyTorqueImpulse2(PhysBody.ptr, applyImpulse); | 1436 | if (PhysBody.HasPhysicalBody) |
1437 | { | ||
1438 | PhysicsScene.PE.ApplyTorqueImpulse(PhysBody, applyImpulse); | ||
1439 | ActivateIfPhysical(false); | ||
1440 | } | ||
1022 | }); | 1441 | }); |
1023 | } | 1442 | } |
1024 | 1443 | ||
@@ -1301,23 +1720,10 @@ public sealed class BSPrim : BSPhysObject | |||
1301 | profileEnd = 1.0f - (float)BaseShape.ProfileEnd * 2.0e-5f; | 1720 | profileEnd = 1.0f - (float)BaseShape.ProfileEnd * 2.0e-5f; |
1302 | volume *= (profileEnd - profileBegin); | 1721 | volume *= (profileEnd - profileBegin); |
1303 | 1722 | ||
1304 | returnMass = _density * volume; | 1723 | returnMass = Density * BSParam.DensityScaleFactor * volume; |
1305 | 1724 | DetailLog("{0},BSPrim.CalculateMass,den={1},vol={2},mass={3}", LocalID, Density, volume, returnMass); | |
1306 | /* Comment out code that computes the mass of the linkset. That is done in the Linkset class. | ||
1307 | if (IsRootOfLinkset) | ||
1308 | { | ||
1309 | foreach (BSPrim prim in _childrenPrims) | ||
1310 | { | ||
1311 | returnMass += prim.CalculateMass(); | ||
1312 | } | ||
1313 | } | ||
1314 | */ | ||
1315 | |||
1316 | if (returnMass <= 0) | ||
1317 | returnMass = 0.0001f; | ||
1318 | 1725 | ||
1319 | if (returnMass > PhysicsScene.MaximumObjectMass) | 1726 | returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass); |
1320 | returnMass = PhysicsScene.MaximumObjectMass; | ||
1321 | 1727 | ||
1322 | return returnMass; | 1728 | return returnMass; |
1323 | }// end CalculateMass | 1729 | }// end CalculateMass |
@@ -1326,135 +1732,73 @@ public sealed class BSPrim : BSPhysObject | |||
1326 | // Rebuild the geometry and object. | 1732 | // Rebuild the geometry and object. |
1327 | // This is called when the shape changes so we need to recreate the mesh/hull. | 1733 | // This is called when the shape changes so we need to recreate the mesh/hull. |
1328 | // Called at taint-time!!! | 1734 | // Called at taint-time!!! |
1329 | private void CreateGeomAndObject(bool forceRebuild) | 1735 | public void CreateGeomAndObject(bool forceRebuild) |
1330 | { | 1736 | { |
1331 | // If this prim is part of a linkset, we must remove and restore the physical | ||
1332 | // links if the body is rebuilt. | ||
1333 | bool needToRestoreLinkset = false; | ||
1334 | bool needToRestoreVehicle = false; | ||
1335 | |||
1336 | // Create the correct physical representation for this type of object. | 1737 | // Create the correct physical representation for this type of object. |
1337 | // Updates PhysBody and PhysShape with the new information. | 1738 | // Updates base.PhysBody and base.PhysShape with the new information. |
1338 | // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary. | 1739 | // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary. |
1339 | // Returns 'true' if either the body or the shape was changed. | 1740 | PhysicsScene.Shapes.GetBodyAndShape(false /*forceRebuild */, PhysicsScene.World, this, null, delegate(BulletBody dBody) |
1340 | PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, null, delegate(BulletBody dBody) | ||
1341 | { | 1741 | { |
1342 | // Called if the current prim body is about to be destroyed. | 1742 | // Called if the current prim body is about to be destroyed. |
1343 | // Remove all the physical dependencies on the old body. | 1743 | // Remove all the physical dependencies on the old body. |
1344 | // (Maybe someday make the changing of BSShape an event handled by BSLinkset.) | 1744 | // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...) |
1345 | needToRestoreLinkset = Linkset.RemoveBodyDependencies(this); | 1745 | RemoveBodyDependencies(); |
1346 | needToRestoreVehicle = _vehicle.RemoveBodyDependencies(this); | ||
1347 | }); | 1746 | }); |
1348 | 1747 | ||
1349 | if (needToRestoreLinkset) | ||
1350 | { | ||
1351 | // If physical body dependencies were removed, restore them | ||
1352 | Linkset.RestoreBodyDependencies(this); | ||
1353 | } | ||
1354 | if (needToRestoreVehicle) | ||
1355 | { | ||
1356 | // If physical body dependencies were removed, restore them | ||
1357 | _vehicle.RestoreBodyDependencies(this); | ||
1358 | } | ||
1359 | |||
1360 | // Make sure the properties are set on the new object | 1748 | // Make sure the properties are set on the new object |
1361 | UpdatePhysicalParameters(); | 1749 | UpdatePhysicalParameters(); |
1362 | return; | 1750 | return; |
1363 | } | 1751 | } |
1364 | 1752 | ||
1365 | // The physics engine says that properties have updated. Update same and inform | 1753 | protected virtual void RemoveBodyDependencies() |
1366 | // the world that things have changed. | 1754 | { |
1367 | // TODO: do we really need to check for changed? Maybe just copy values and call RequestPhysicsterseUpdate() | 1755 | VehicleController.RemoveBodyDependencies(this); |
1368 | enum UpdatedProperties { | ||
1369 | Position = 1 << 0, | ||
1370 | Rotation = 1 << 1, | ||
1371 | Velocity = 1 << 2, | ||
1372 | Acceleration = 1 << 3, | ||
1373 | RotationalVel = 1 << 4 | ||
1374 | } | 1756 | } |
1375 | 1757 | ||
1376 | const float ROTATION_TOLERANCE = 0.01f; | 1758 | // The physics engine says that properties have updated. Update same and inform |
1377 | const float VELOCITY_TOLERANCE = 0.001f; | 1759 | // the world that things have changed. |
1378 | const float POSITION_TOLERANCE = 0.05f; | ||
1379 | const float ACCELERATION_TOLERANCE = 0.01f; | ||
1380 | const float ROTATIONAL_VELOCITY_TOLERANCE = 0.01f; | ||
1381 | |||
1382 | public override void UpdateProperties(EntityProperties entprop) | 1760 | public override void UpdateProperties(EntityProperties entprop) |
1383 | { | 1761 | { |
1384 | /* | 1762 | TriggerPreUpdatePropertyAction(ref entprop); |
1385 | UpdatedProperties changed = 0; | 1763 | |
1386 | // assign to the local variables so the normal set action does not happen | 1764 | // A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet |
1387 | // if (_position != entprop.Position) | 1765 | // TODO: handle physics introduced by Bullet with computed vehicle physics. |
1388 | if (!_position.ApproxEquals(entprop.Position, POSITION_TOLERANCE)) | 1766 | if (VehicleController.IsActive) |
1389 | { | ||
1390 | _position = entprop.Position; | ||
1391 | changed |= UpdatedProperties.Position; | ||
1392 | } | ||
1393 | // if (_orientation != entprop.Rotation) | ||
1394 | if (!_orientation.ApproxEquals(entprop.Rotation, ROTATION_TOLERANCE)) | ||
1395 | { | ||
1396 | _orientation = entprop.Rotation; | ||
1397 | changed |= UpdatedProperties.Rotation; | ||
1398 | } | ||
1399 | // if (_velocity != entprop.Velocity) | ||
1400 | if (!_velocity.ApproxEquals(entprop.Velocity, VELOCITY_TOLERANCE)) | ||
1401 | { | ||
1402 | _velocity = entprop.Velocity; | ||
1403 | changed |= UpdatedProperties.Velocity; | ||
1404 | } | ||
1405 | // if (_acceleration != entprop.Acceleration) | ||
1406 | if (!_acceleration.ApproxEquals(entprop.Acceleration, ACCELERATION_TOLERANCE)) | ||
1407 | { | ||
1408 | _acceleration = entprop.Acceleration; | ||
1409 | changed |= UpdatedProperties.Acceleration; | ||
1410 | } | ||
1411 | // if (_rotationalVelocity != entprop.RotationalVelocity) | ||
1412 | if (!_rotationalVelocity.ApproxEquals(entprop.RotationalVelocity, ROTATIONAL_VELOCITY_TOLERANCE)) | ||
1413 | { | ||
1414 | _rotationalVelocity = entprop.RotationalVelocity; | ||
1415 | changed |= UpdatedProperties.RotationalVel; | ||
1416 | } | ||
1417 | if (changed != 0) | ||
1418 | { | 1767 | { |
1419 | // Only update the position of single objects and linkset roots | 1768 | entprop.RotationalVelocity = OMV.Vector3.Zero; |
1420 | if (Linkset.IsRoot(this)) | ||
1421 | { | ||
1422 | base.RequestPhysicsterseUpdate(); | ||
1423 | } | ||
1424 | } | 1769 | } |
1425 | */ | ||
1426 | 1770 | ||
1427 | // Don't check for damping here -- it's done in BulletSim and SceneObjectPart. | 1771 | // DetailLog("{0},BSPrim.UpdateProperties,entry,entprop={1}", LocalID, entprop); // DEBUG DEBUG |
1428 | 1772 | ||
1429 | // Updates only for individual prims and for the root object of a linkset. | 1773 | // Assign directly to the local variables so the normal set actions do not happen |
1430 | if (Linkset.IsRoot(this)) | 1774 | _position = entprop.Position; |
1431 | { | 1775 | _orientation = entprop.Rotation; |
1432 | // Assign directly to the local variables so the normal set action does not happen | 1776 | // DEBUG DEBUG DEBUG -- smooth velocity changes a bit. The simulator seems to be |
1433 | _position = entprop.Position; | 1777 | // very sensitive to velocity changes. |
1434 | _orientation = entprop.Rotation; | 1778 | if (entprop.Velocity == OMV.Vector3.Zero || !entprop.Velocity.ApproxEquals(_velocity, BSParam.UpdateVelocityChangeThreshold)) |
1435 | _velocity = entprop.Velocity; | 1779 | _velocity = entprop.Velocity; |
1436 | _acceleration = entprop.Acceleration; | 1780 | _acceleration = entprop.Acceleration; |
1437 | _rotationalVelocity = entprop.RotationalVelocity; | 1781 | _rotationalVelocity = entprop.RotationalVelocity; |
1438 | 1782 | ||
1439 | // The sanity check can change the velocity and/or position. | 1783 | // DetailLog("{0},BSPrim.UpdateProperties,afterAssign,entprop={1}", LocalID, entprop); // DEBUG DEBUG |
1440 | if (PositionSanityCheck(true)) | ||
1441 | { | ||
1442 | entprop.Position = _position; | ||
1443 | entprop.Velocity = _velocity; | ||
1444 | } | ||
1445 | 1784 | ||
1446 | // remember the current and last set values | 1785 | // The sanity check can change the velocity and/or position. |
1447 | LastEntityProperties = CurrentEntityProperties; | 1786 | if (PositionSanityCheck(true /* inTaintTime */ )) |
1448 | CurrentEntityProperties = entprop; | 1787 | { |
1788 | entprop.Position = _position; | ||
1789 | entprop.Velocity = _velocity; | ||
1790 | entprop.RotationalVelocity = _rotationalVelocity; | ||
1791 | entprop.Acceleration = _acceleration; | ||
1792 | } | ||
1449 | 1793 | ||
1450 | OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation; | 1794 | OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation; // DEBUG DEBUG DEBUG |
1451 | DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},dir={3},vel={4},rotVel={5}", | 1795 | DetailLog("{0},BSPrim.UpdateProperties,call,entProp={1},dir={2}", LocalID, entprop, direction); |
1452 | LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity); | ||
1453 | 1796 | ||
1454 | // BulletSimAPI.DumpRigidBody2(PhysicsScene.World.ptr, BSBody.ptr); // DEBUG DEBUG DEBUG | 1797 | // remember the current and last set values |
1798 | LastEntityProperties = CurrentEntityProperties; | ||
1799 | CurrentEntityProperties = entprop; | ||
1455 | 1800 | ||
1456 | base.RequestPhysicsterseUpdate(); | 1801 | base.RequestPhysicsterseUpdate(); |
1457 | } | ||
1458 | /* | 1802 | /* |
1459 | else | 1803 | else |
1460 | { | 1804 | { |
@@ -1464,9 +1808,6 @@ public sealed class BSPrim : BSPhysObject | |||
1464 | entprop.Acceleration, entprop.RotationalVelocity); | 1808 | entprop.Acceleration, entprop.RotationalVelocity); |
1465 | } | 1809 | } |
1466 | */ | 1810 | */ |
1467 | |||
1468 | // The linkset implimentation might want to know about this. | ||
1469 | Linkset.UpdateProperties(this); | ||
1470 | } | 1811 | } |
1471 | } | 1812 | } |
1472 | } | 1813 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs new file mode 100755 index 0000000..f1c3b5c --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs | |||
@@ -0,0 +1,153 @@ | |||
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 | * The quotations from http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial | ||
28 | * are Copyright (c) 2009 Linden Research, Inc and are used under their license | ||
29 | * of Creative Commons Attribution-Share Alike 3.0 | ||
30 | * (http://creativecommons.org/licenses/by-sa/3.0/). | ||
31 | */ | ||
32 | |||
33 | using System; | ||
34 | using System.Collections.Generic; | ||
35 | using System.Reflection; | ||
36 | using System.Runtime.InteropServices; | ||
37 | using OpenMetaverse; | ||
38 | using OpenSim.Framework; | ||
39 | using OpenSim.Region.Physics.Manager; | ||
40 | |||
41 | using OMV = OpenMetaverse; | ||
42 | |||
43 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
44 | { | ||
45 | public class BSPrimDisplaced : BSPrim | ||
46 | { | ||
47 | // The purpose of this module is to do any mapping between what the simulator thinks | ||
48 | // the prim position and orientation is and what the physical position/orientation. | ||
49 | // This difference happens because Bullet assumes the center-of-mass is the <0,0,0> | ||
50 | // of the prim/linkset. The simulator tracks the location of the prim/linkset by | ||
51 | // the location of the root prim. So, if center-of-mass is anywhere but the origin | ||
52 | // of the root prim, the physical origin is displaced from the simulator origin. | ||
53 | // | ||
54 | // This routine works by capturing the Force* setting of position/orientation/... and | ||
55 | // adjusting the simulator values (being set) into the physical values. | ||
56 | // The conversion is also done in the opposite direction (physical origin -> simulator origin). | ||
57 | // | ||
58 | // The updateParameter call is also captured and the values from the physics engine | ||
59 | // are converted into simulator origin values before being passed to the base | ||
60 | // class. | ||
61 | |||
62 | public virtual OMV.Vector3 PositionDisplacement { get; set; } | ||
63 | public virtual OMV.Quaternion OrientationDisplacement { get; set; } | ||
64 | |||
65 | public BSPrimDisplaced(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, | ||
66 | OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) | ||
67 | : base(localID, primName, parent_scene, pos, size, rotation, pbs, pisPhysical) | ||
68 | { | ||
69 | ClearDisplacement(); | ||
70 | } | ||
71 | |||
72 | public void ClearDisplacement() | ||
73 | { | ||
74 | PositionDisplacement = OMV.Vector3.Zero; | ||
75 | OrientationDisplacement = OMV.Quaternion.Identity; | ||
76 | } | ||
77 | |||
78 | // Set this sets and computes the displacement from the passed prim to the center-of-mass. | ||
79 | // A user set value for center-of-mass overrides whatever might be passed in here. | ||
80 | // The displacement is in local coordinates (relative to root prim in linkset oriented coordinates). | ||
81 | public virtual void SetEffectiveCenterOfMassW(Vector3 centerOfMassDisplacement) | ||
82 | { | ||
83 | Vector3 comDisp; | ||
84 | if (UserSetCenterOfMass.HasValue) | ||
85 | comDisp = (OMV.Vector3)UserSetCenterOfMass; | ||
86 | else | ||
87 | comDisp = centerOfMassDisplacement; | ||
88 | |||
89 | if (comDisp == Vector3.Zero) | ||
90 | { | ||
91 | // If there is no diplacement. Things get reset. | ||
92 | PositionDisplacement = OMV.Vector3.Zero; | ||
93 | OrientationDisplacement = OMV.Quaternion.Identity; | ||
94 | } | ||
95 | else | ||
96 | { | ||
97 | // Remember the displacement from root as well as the origional rotation of the | ||
98 | // new center-of-mass. | ||
99 | PositionDisplacement = comDisp; | ||
100 | OrientationDisplacement = OMV.Quaternion.Identity; | ||
101 | } | ||
102 | } | ||
103 | |||
104 | public override Vector3 ForcePosition | ||
105 | { | ||
106 | get { return base.ForcePosition; } | ||
107 | set | ||
108 | { | ||
109 | if (PositionDisplacement != OMV.Vector3.Zero) | ||
110 | base.ForcePosition = value - (PositionDisplacement * RawOrientation); | ||
111 | else | ||
112 | base.ForcePosition = value; | ||
113 | } | ||
114 | } | ||
115 | |||
116 | public override Quaternion ForceOrientation | ||
117 | { | ||
118 | get { return base.ForceOrientation; } | ||
119 | set | ||
120 | { | ||
121 | base.ForceOrientation = value; | ||
122 | } | ||
123 | } | ||
124 | |||
125 | // TODO: decide if this is the right place for these variables. | ||
126 | // Somehow incorporate the optional settability by the user. | ||
127 | // Is this used? | ||
128 | public override OMV.Vector3 CenterOfMass | ||
129 | { | ||
130 | get { return RawPosition; } | ||
131 | } | ||
132 | |||
133 | // Is this used? | ||
134 | public override OMV.Vector3 GeometricCenter | ||
135 | { | ||
136 | get { return RawPosition; } | ||
137 | } | ||
138 | |||
139 | public override void UpdateProperties(EntityProperties entprop) | ||
140 | { | ||
141 | // Undo any center-of-mass displacement that might have been done. | ||
142 | if (PositionDisplacement != OMV.Vector3.Zero || OrientationDisplacement != OMV.Quaternion.Identity) | ||
143 | { | ||
144 | // Correct for any rotation around the center-of-mass | ||
145 | // TODO!!! | ||
146 | entprop.Position = entprop.Position + (PositionDisplacement * entprop.Rotation); | ||
147 | // entprop.Rotation = something; | ||
148 | } | ||
149 | |||
150 | base.UpdateProperties(entprop); | ||
151 | } | ||
152 | } | ||
153 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs new file mode 100755 index 0000000..d65d407 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs | |||
@@ -0,0 +1,182 @@ | |||
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 copyrightD | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Linq; | ||
30 | using System.Text; | ||
31 | |||
32 | using OpenSim.Framework; | ||
33 | |||
34 | using OMV = OpenMetaverse; | ||
35 | |||
36 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
37 | { | ||
38 | public class BSPrimLinkable : BSPrimDisplaced | ||
39 | { | ||
40 | public BSLinkset Linkset { get; set; } | ||
41 | // The index of this child prim. | ||
42 | public int LinksetChildIndex { get; set; } | ||
43 | |||
44 | public BSLinksetInfo LinksetInfo { get; set; } | ||
45 | |||
46 | public BSPrimLinkable(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, | ||
47 | OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) | ||
48 | : base(localID, primName, parent_scene, pos, size, rotation, pbs, pisPhysical) | ||
49 | { | ||
50 | Linkset = BSLinkset.Factory(PhysicsScene, this); | ||
51 | |||
52 | PhysicsScene.TaintedObject("BSPrimLinksetCompound.Refresh", delegate() | ||
53 | { | ||
54 | Linkset.Refresh(this); | ||
55 | }); | ||
56 | } | ||
57 | |||
58 | public override void Destroy() | ||
59 | { | ||
60 | Linkset = Linkset.RemoveMeFromLinkset(this); | ||
61 | base.Destroy(); | ||
62 | } | ||
63 | |||
64 | public override BSPhysicsShapeType PreferredPhysicalShape | ||
65 | { get { return Linkset.PreferredPhysicalShape(this); } } | ||
66 | |||
67 | public override void link(Manager.PhysicsActor obj) | ||
68 | { | ||
69 | BSPrimLinkable parent = obj as BSPrimLinkable; | ||
70 | if (parent != null) | ||
71 | { | ||
72 | BSPhysObject parentBefore = Linkset.LinksetRoot; | ||
73 | int childrenBefore = Linkset.NumberOfChildren; | ||
74 | |||
75 | Linkset = parent.Linkset.AddMeToLinkset(this); | ||
76 | |||
77 | DetailLog("{0},BSPrimLinkset.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}", | ||
78 | LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren); | ||
79 | } | ||
80 | return; | ||
81 | } | ||
82 | |||
83 | public override void delink() | ||
84 | { | ||
85 | // TODO: decide if this parent checking needs to happen at taint time | ||
86 | // Race condition here: if link() and delink() in same simulation tick, the delink will not happen | ||
87 | |||
88 | BSPhysObject parentBefore = Linkset.LinksetRoot; | ||
89 | int childrenBefore = Linkset.NumberOfChildren; | ||
90 | |||
91 | Linkset = Linkset.RemoveMeFromLinkset(this); | ||
92 | |||
93 | DetailLog("{0},BSPrimLinkset.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ", | ||
94 | LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren); | ||
95 | return; | ||
96 | } | ||
97 | |||
98 | // When simulator changes position, this might be moving a child of the linkset. | ||
99 | public override OMV.Vector3 Position | ||
100 | { | ||
101 | get { return base.Position; } | ||
102 | set | ||
103 | { | ||
104 | base.Position = value; | ||
105 | PhysicsScene.TaintedObject("BSPrimLinkset.setPosition", delegate() | ||
106 | { | ||
107 | Linkset.UpdateProperties(UpdatedProperties.Position, this); | ||
108 | }); | ||
109 | } | ||
110 | } | ||
111 | |||
112 | // When simulator changes orientation, this might be moving a child of the linkset. | ||
113 | public override OMV.Quaternion Orientation | ||
114 | { | ||
115 | get { return base.Orientation; } | ||
116 | set | ||
117 | { | ||
118 | base.Orientation = value; | ||
119 | PhysicsScene.TaintedObject("BSPrimLinkset.setOrientation", delegate() | ||
120 | { | ||
121 | Linkset.UpdateProperties(UpdatedProperties.Orientation, this); | ||
122 | }); | ||
123 | } | ||
124 | } | ||
125 | |||
126 | public override float TotalMass | ||
127 | { | ||
128 | get { return Linkset.LinksetMass; } | ||
129 | } | ||
130 | |||
131 | public override void UpdatePhysicalParameters() | ||
132 | { | ||
133 | base.UpdatePhysicalParameters(); | ||
134 | // Recompute any linkset parameters. | ||
135 | // When going from non-physical to physical, this re-enables the constraints that | ||
136 | // had been automatically disabled when the mass was set to zero. | ||
137 | // For compound based linksets, this enables and disables interactions of the children. | ||
138 | if (Linkset != null) // null can happen during initialization | ||
139 | Linkset.Refresh(this); | ||
140 | } | ||
141 | |||
142 | protected override void MakeDynamic(bool makeStatic) | ||
143 | { | ||
144 | base.MakeDynamic(makeStatic); | ||
145 | if (makeStatic) | ||
146 | Linkset.MakeStatic(this); | ||
147 | else | ||
148 | Linkset.MakeDynamic(this); | ||
149 | } | ||
150 | |||
151 | // Body is being taken apart. Remove physical dependencies and schedule a rebuild. | ||
152 | protected override void RemoveBodyDependencies() | ||
153 | { | ||
154 | Linkset.RemoveBodyDependencies(this); | ||
155 | base.RemoveBodyDependencies(); | ||
156 | } | ||
157 | |||
158 | public override void UpdateProperties(EntityProperties entprop) | ||
159 | { | ||
160 | if (Linkset.IsRoot(this)) | ||
161 | { | ||
162 | // Properties are only updated for the roots of a linkset. | ||
163 | // TODO: this will have to change when linksets are articulated. | ||
164 | base.UpdateProperties(entprop); | ||
165 | } | ||
166 | // The linkset might like to know about changing locations | ||
167 | Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this); | ||
168 | } | ||
169 | |||
170 | public override bool Collide(uint collidingWith, BSPhysObject collidee, | ||
171 | OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) | ||
172 | { | ||
173 | // prims in the same linkset cannot collide with each other | ||
174 | BSPrimLinkable convCollidee = collidee as BSPrimLinkable; | ||
175 | if (convCollidee != null && (this.Linkset.LinksetID == convCollidee.Linkset.LinksetID)) | ||
176 | { | ||
177 | return false; | ||
178 | } | ||
179 | return base.Collide(collidingWith, collidee, contactPoint, contactNormal, pentrationDepth); | ||
180 | } | ||
181 | } | ||
182 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index 27a78d1..e6aefd5 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | |||
@@ -26,6 +26,8 @@ | |||
26 | */ | 26 | */ |
27 | using System; | 27 | using System; |
28 | using System.Collections.Generic; | 28 | using System.Collections.Generic; |
29 | using System.Linq; | ||
30 | using System.Reflection; | ||
29 | using System.Runtime.InteropServices; | 31 | using System.Runtime.InteropServices; |
30 | using System.Text; | 32 | using System.Text; |
31 | using System.Threading; | 33 | using System.Threading; |
@@ -38,40 +40,22 @@ using Nini.Config; | |||
38 | using log4net; | 40 | using log4net; |
39 | using OpenMetaverse; | 41 | using OpenMetaverse; |
40 | 42 | ||
41 | // TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim) | ||
42 | // Test sculpties (verified that they don't work) | ||
43 | // Compute physics FPS reasonably | ||
44 | // Based on material, set density and friction | ||
45 | // Don't use constraints in linksets of non-physical objects. Means having to move children manually. | ||
46 | // Four states of prim: Physical, regular, phantom and selected. Are we modeling these correctly? | ||
47 | // In SL one can set both physical and phantom (gravity, does not effect others, makes collisions with ground) | ||
48 | // At the moment, physical and phantom causes object to drop through the terrain | ||
49 | // Physical phantom objects and related typing (collision options ) | ||
50 | // Check out llVolumeDetect. Must do something for that. | ||
51 | // Use collision masks for collision with terrain and phantom objects | ||
52 | // More efficient memory usage when passing hull information from BSPrim to BulletSim | ||
53 | // Should prim.link() and prim.delink() membership checking happen at taint time? | ||
54 | // Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once. | ||
55 | // Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect | ||
56 | // Implement LockAngularMotion | ||
57 | // Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation) | ||
58 | // Remove mesh and Hull stuff. Use mesh passed to bullet and use convexdecom from bullet. | ||
59 | // Add PID movement operations. What does ScenePresence.MoveToTarget do? | ||
60 | // Check terrain size. 128 or 127? | ||
61 | // Raycast | ||
62 | // | ||
63 | namespace OpenSim.Region.Physics.BulletSPlugin | 43 | namespace OpenSim.Region.Physics.BulletSPlugin |
64 | { | 44 | { |
65 | public sealed class BSScene : PhysicsScene, IPhysicsParameters | 45 | public sealed class BSScene : PhysicsScene, IPhysicsParameters |
66 | { | 46 | { |
67 | private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); | 47 | internal static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); |
68 | private static readonly string LogHeader = "[BULLETS SCENE]"; | 48 | internal static readonly string LogHeader = "[BULLETS SCENE]"; |
69 | 49 | ||
70 | // The name of the region we're working for. | 50 | // The name of the region we're working for. |
71 | public string RegionName { get; private set; } | 51 | public string RegionName { get; private set; } |
72 | 52 | ||
73 | public string BulletSimVersion = "?"; | 53 | public string BulletSimVersion = "?"; |
74 | 54 | ||
55 | // The handle to the underlying managed or unmanaged version of Bullet being used. | ||
56 | public string BulletEngineName { get; private set; } | ||
57 | public BSAPITemplate PE; | ||
58 | |||
75 | public Dictionary<uint, BSPhysObject> PhysObjects; | 59 | public Dictionary<uint, BSPhysObject> PhysObjects; |
76 | public BSShapeCollection Shapes; | 60 | public BSShapeCollection Shapes; |
77 | 61 | ||
@@ -82,32 +66,29 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
82 | // every tick so OpenSim will update its animation. | 66 | // every tick so OpenSim will update its animation. |
83 | private HashSet<BSPhysObject> m_avatars = new HashSet<BSPhysObject>(); | 67 | private HashSet<BSPhysObject> m_avatars = new HashSet<BSPhysObject>(); |
84 | 68 | ||
85 | // List of all the objects that have vehicle properties and should be called | ||
86 | // to update each physics step. | ||
87 | private List<BSPhysObject> m_vehicles = new List<BSPhysObject>(); | ||
88 | |||
89 | // let my minuions use my logger | 69 | // let my minuions use my logger |
90 | public ILog Logger { get { return m_log; } } | 70 | public ILog Logger { get { return m_log; } } |
91 | 71 | ||
92 | public IMesher mesher; | 72 | public IMesher mesher; |
93 | // Level of Detail values kept as float because that's what the Meshmerizer wants | ||
94 | public float MeshLOD { get; private set; } | ||
95 | public float MeshMegaPrimLOD { get; private set; } | ||
96 | public float MeshMegaPrimThreshold { get; private set; } | ||
97 | public float SculptLOD { get; private set; } | ||
98 | |||
99 | public uint WorldID { get; private set; } | 73 | public uint WorldID { get; private set; } |
100 | public BulletSim World { get; private set; } | 74 | public BulletWorld World { get; private set; } |
101 | 75 | ||
102 | // All the constraints that have been allocated in this instance. | 76 | // All the constraints that have been allocated in this instance. |
103 | public BSConstraintCollection Constraints { get; private set; } | 77 | public BSConstraintCollection Constraints { get; private set; } |
104 | 78 | ||
105 | // Simulation parameters | 79 | // Simulation parameters |
106 | private int m_maxSubSteps; | 80 | internal int m_maxSubSteps; |
107 | private float m_fixedTimeStep; | 81 | internal float m_fixedTimeStep; |
108 | private long m_simulationStep = 0; | 82 | internal long m_simulationStep = 0; |
83 | internal float NominalFrameRate { get; set; } | ||
109 | public long SimulationStep { get { return m_simulationStep; } } | 84 | public long SimulationStep { get { return m_simulationStep; } } |
110 | private int m_taintsToProcessPerStep; | 85 | internal float LastTimeStep { get; private set; } |
86 | |||
87 | // Physical objects can register for prestep or poststep events | ||
88 | public delegate void PreStepAction(float timeStep); | ||
89 | public delegate void PostStepAction(float timeStep); | ||
90 | public event PreStepAction BeforeStep; | ||
91 | public event PostStepAction AfterStep; | ||
111 | 92 | ||
112 | // A value of the time now so all the collision and update routines do not have to get their own | 93 | // A value of the time now so all the collision and update routines do not have to get their own |
113 | // Set to 'now' just before all the prims and actors are called for collisions and updates | 94 | // Set to 'now' just before all the prims and actors are called for collisions and updates |
@@ -121,31 +102,22 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
121 | public bool InTaintTime { get; private set; } | 102 | public bool InTaintTime { get; private set; } |
122 | 103 | ||
123 | // Pinned memory used to pass step information between managed and unmanaged | 104 | // Pinned memory used to pass step information between managed and unmanaged |
124 | private int m_maxCollisionsPerFrame; | 105 | internal int m_maxCollisionsPerFrame; |
125 | private CollisionDesc[] m_collisionArray; | 106 | internal CollisionDesc[] m_collisionArray; |
126 | private GCHandle m_collisionArrayPinnedHandle; | ||
127 | 107 | ||
128 | private int m_maxUpdatesPerFrame; | 108 | internal int m_maxUpdatesPerFrame; |
129 | private EntityProperties[] m_updateArray; | 109 | internal EntityProperties[] m_updateArray; |
130 | private GCHandle m_updateArrayPinnedHandle; | ||
131 | |||
132 | public bool ShouldMeshSculptedPrim { get; private set; } // cause scuplted prims to get meshed | ||
133 | public bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes | ||
134 | public bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects | ||
135 | |||
136 | public float PID_D { get; private set; } // derivative | ||
137 | public float PID_P { get; private set; } // proportional | ||
138 | 110 | ||
139 | public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero | 111 | public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero |
140 | public const uint GROUNDPLANE_ID = 1; | 112 | public const uint GROUNDPLANE_ID = 1; |
141 | public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here | 113 | public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here |
142 | 114 | ||
143 | private float m_waterLevel; | 115 | public float SimpleWaterLevel { get; set; } |
144 | public BSTerrainManager TerrainManager { get; private set; } | 116 | public BSTerrainManager TerrainManager { get; private set; } |
145 | 117 | ||
146 | public ConfigurationParameters Params | 118 | public ConfigurationParameters Params |
147 | { | 119 | { |
148 | get { return m_params[0]; } | 120 | get { return UnmanagedParams[0]; } |
149 | } | 121 | } |
150 | public Vector3 DefaultGravity | 122 | public Vector3 DefaultGravity |
151 | { | 123 | { |
@@ -157,8 +129,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
157 | get { return Params.gravity; } | 129 | get { return Params.gravity; } |
158 | } | 130 | } |
159 | 131 | ||
160 | public float MaximumObjectMass { get; private set; } | ||
161 | |||
162 | // When functions in the unmanaged code must be called, it is only | 132 | // When functions in the unmanaged code must be called, it is only |
163 | // done at a known time just before the simulation step. The taint | 133 | // done at a known time just before the simulation step. The taint |
164 | // system saves all these function calls and executes them in | 134 | // system saves all these function calls and executes them in |
@@ -181,13 +151,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
181 | 151 | ||
182 | // A pointer to an instance if this structure is passed to the C++ code | 152 | // A pointer to an instance if this structure is passed to the C++ code |
183 | // Used to pass basic configuration values to the unmanaged code. | 153 | // Used to pass basic configuration values to the unmanaged code. |
184 | ConfigurationParameters[] m_params; | 154 | internal ConfigurationParameters[] UnmanagedParams; |
185 | GCHandle m_paramsHandle; | ||
186 | |||
187 | // Handle to the callback used by the unmanaged code to call into the managed code. | ||
188 | // Used for debug logging. | ||
189 | // Need to store the handle in a persistant variable so it won't be freed. | ||
190 | private BulletSimAPI.DebugLogCallback m_DebugLogCallbackHandle; | ||
191 | 155 | ||
192 | // Sometimes you just have to log everything. | 156 | // Sometimes you just have to log everything. |
193 | public Logging.LogWriter PhysicsLogging; | 157 | public Logging.LogWriter PhysicsLogging; |
@@ -195,15 +159,24 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
195 | private string m_physicsLoggingDir; | 159 | private string m_physicsLoggingDir; |
196 | private string m_physicsLoggingPrefix; | 160 | private string m_physicsLoggingPrefix; |
197 | private int m_physicsLoggingFileMinutes; | 161 | private int m_physicsLoggingFileMinutes; |
162 | private bool m_physicsLoggingDoFlush; | ||
163 | private bool m_physicsPhysicalDumpEnabled; | ||
164 | public int PhysicsMetricDumpFrames { get; set; } | ||
198 | // 'true' of the vehicle code is to log lots of details | 165 | // 'true' of the vehicle code is to log lots of details |
199 | public bool VehicleLoggingEnabled { get; private set; } | 166 | public bool VehicleLoggingEnabled { get; private set; } |
167 | public bool VehiclePhysicalLoggingEnabled { get; private set; } | ||
200 | 168 | ||
201 | #region Construction and Initialization | 169 | #region Construction and Initialization |
202 | public BSScene(string identifier) | 170 | public BSScene(string engineType, string identifier) |
203 | { | 171 | { |
204 | m_initialized = false; | 172 | m_initialized = false; |
205 | // we are passed the name of the region we're working for. | 173 | |
174 | // The name of the region we're working for is passed to us. Keep for identification. | ||
206 | RegionName = identifier; | 175 | RegionName = identifier; |
176 | |||
177 | // Set identifying variables in the PhysicsScene interface. | ||
178 | EngineType = engineType; | ||
179 | Name = EngineType + "/" + RegionName; | ||
207 | } | 180 | } |
208 | 181 | ||
209 | public override void Initialise(IMesher meshmerizer, IConfigSource config) | 182 | public override void Initialise(IMesher meshmerizer, IConfigSource config) |
@@ -216,17 +189,13 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
216 | Shapes = new BSShapeCollection(this); | 189 | Shapes = new BSShapeCollection(this); |
217 | 190 | ||
218 | // Allocate pinned memory to pass parameters. | 191 | // Allocate pinned memory to pass parameters. |
219 | m_params = new ConfigurationParameters[1]; | 192 | UnmanagedParams = new ConfigurationParameters[1]; |
220 | m_paramsHandle = GCHandle.Alloc(m_params, GCHandleType.Pinned); | ||
221 | 193 | ||
222 | // Set default values for physics parameters plus any overrides from the ini file | 194 | // Set default values for physics parameters plus any overrides from the ini file |
223 | GetInitialParameterValues(config); | 195 | GetInitialParameterValues(config); |
224 | 196 | ||
225 | // allocate more pinned memory close to the above in an attempt to get the memory all together | 197 | // Get the connection to the physics engine (could be native or one of many DLLs) |
226 | m_collisionArray = new CollisionDesc[m_maxCollisionsPerFrame]; | 198 | PE = SelectUnderlyingBulletEngine(BulletEngineName); |
227 | m_collisionArrayPinnedHandle = GCHandle.Alloc(m_collisionArray, GCHandleType.Pinned); | ||
228 | m_updateArray = new EntityProperties[m_maxUpdatesPerFrame]; | ||
229 | m_updateArrayPinnedHandle = GCHandle.Alloc(m_updateArray, GCHandleType.Pinned); | ||
230 | 199 | ||
231 | // Enable very detailed logging. | 200 | // Enable very detailed logging. |
232 | // By creating an empty logger when not logging, the log message invocation code | 201 | // By creating an empty logger when not logging, the log message invocation code |
@@ -234,28 +203,16 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
234 | if (m_physicsLoggingEnabled) | 203 | if (m_physicsLoggingEnabled) |
235 | { | 204 | { |
236 | PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes); | 205 | PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes); |
206 | PhysicsLogging.ErrorLogger = m_log; // for DEBUG. Let's the logger output error messages. | ||
237 | } | 207 | } |
238 | else | 208 | else |
239 | { | 209 | { |
240 | PhysicsLogging = new Logging.LogWriter(); | 210 | PhysicsLogging = new Logging.LogWriter(); |
241 | } | 211 | } |
242 | 212 | ||
243 | // If Debug logging level, enable logging from the unmanaged code | 213 | // Allocate memory for returning of the updates and collisions from the physics engine |
244 | m_DebugLogCallbackHandle = null; | 214 | m_collisionArray = new CollisionDesc[m_maxCollisionsPerFrame]; |
245 | if (m_log.IsDebugEnabled || PhysicsLogging.Enabled) | 215 | m_updateArray = new EntityProperties[m_maxUpdatesPerFrame]; |
246 | { | ||
247 | m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader); | ||
248 | if (PhysicsLogging.Enabled) | ||
249 | // The handle is saved in a variable to make sure it doesn't get freed after this call | ||
250 | m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLoggerPhysLog); | ||
251 | else | ||
252 | m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLogger); | ||
253 | } | ||
254 | |||
255 | // Get the version of the DLL | ||
256 | // TODO: this doesn't work yet. Something wrong with marshaling the returned string. | ||
257 | // BulletSimVersion = BulletSimAPI.GetVersion(); | ||
258 | // m_log.WarnFormat("{0}: BulletSim.dll version='{1}'", LogHeader, BulletSimVersion); | ||
259 | 216 | ||
260 | // The bounding box for the simulated world. The origin is 0,0,0 unless we're | 217 | // The bounding box for the simulated world. The origin is 0,0,0 unless we're |
261 | // a child in a mega-region. | 218 | // a child in a mega-region. |
@@ -263,18 +220,14 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
263 | // area. It tracks active objects no matter where they are. | 220 | // area. It tracks active objects no matter where they are. |
264 | Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); | 221 | Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); |
265 | 222 | ||
266 | // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader); | 223 | World = PE.Initialize(worldExtent, Params, m_maxCollisionsPerFrame, ref m_collisionArray, m_maxUpdatesPerFrame, ref m_updateArray); |
267 | World = new BulletSim(0, this, BulletSimAPI.Initialize2(worldExtent, m_paramsHandle.AddrOfPinnedObject(), | ||
268 | m_maxCollisionsPerFrame, m_collisionArrayPinnedHandle.AddrOfPinnedObject(), | ||
269 | m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject(), | ||
270 | m_DebugLogCallbackHandle)); | ||
271 | 224 | ||
272 | Constraints = new BSConstraintCollection(World); | 225 | Constraints = new BSConstraintCollection(World); |
273 | 226 | ||
274 | TerrainManager = new BSTerrainManager(this); | 227 | TerrainManager = new BSTerrainManager(this); |
275 | TerrainManager.CreateInitialGroundPlaneAndTerrain(); | 228 | TerrainManager.CreateInitialGroundPlaneAndTerrain(); |
276 | 229 | ||
277 | m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)Params.linksetImplementation); | 230 | m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation); |
278 | 231 | ||
279 | InTaintTime = false; | 232 | InTaintTime = false; |
280 | m_initialized = true; | 233 | m_initialized = true; |
@@ -285,9 +238,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
285 | private void GetInitialParameterValues(IConfigSource config) | 238 | private void GetInitialParameterValues(IConfigSource config) |
286 | { | 239 | { |
287 | ConfigurationParameters parms = new ConfigurationParameters(); | 240 | ConfigurationParameters parms = new ConfigurationParameters(); |
288 | m_params[0] = parms; | 241 | UnmanagedParams[0] = parms; |
289 | 242 | ||
290 | SetParameterDefaultValues(); | 243 | BSParam.SetParameterDefaultValues(this); |
291 | 244 | ||
292 | if (config != null) | 245 | if (config != null) |
293 | { | 246 | { |
@@ -295,19 +248,34 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
295 | IConfig pConfig = config.Configs["BulletSim"]; | 248 | IConfig pConfig = config.Configs["BulletSim"]; |
296 | if (pConfig != null) | 249 | if (pConfig != null) |
297 | { | 250 | { |
298 | SetParameterConfigurationValues(pConfig); | 251 | BSParam.SetParameterConfigurationValues(this, pConfig); |
252 | |||
253 | // There are two Bullet implementations to choose from | ||
254 | BulletEngineName = pConfig.GetString("BulletEngine", "BulletUnmanaged"); | ||
299 | 255 | ||
300 | // Very detailed logging for physics debugging | 256 | // Very detailed logging for physics debugging |
257 | // TODO: the boolean values can be moved to the normal parameter processing. | ||
301 | m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false); | 258 | m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false); |
302 | m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", "."); | 259 | m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", "."); |
303 | m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-"); | 260 | m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-"); |
304 | m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5); | 261 | m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5); |
262 | m_physicsLoggingDoFlush = pConfig.GetBoolean("PhysicsLoggingDoFlush", false); | ||
263 | m_physicsPhysicalDumpEnabled = pConfig.GetBoolean("PhysicsPhysicalDumpEnabled", false); | ||
305 | // Very detailed logging for vehicle debugging | 264 | // Very detailed logging for vehicle debugging |
306 | VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false); | 265 | VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false); |
266 | VehiclePhysicalLoggingEnabled = pConfig.GetBoolean("VehiclePhysicalLoggingEnabled", false); | ||
307 | 267 | ||
308 | // Do any replacements in the parameters | 268 | // Do any replacements in the parameters |
309 | m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName); | 269 | m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName); |
310 | } | 270 | } |
271 | |||
272 | // The material characteristics. | ||
273 | BSMaterials.InitializeFromDefaults(Params); | ||
274 | if (pConfig != null) | ||
275 | { | ||
276 | // Let the user add new and interesting material property values. | ||
277 | BSMaterials.InitializefromParameters(pConfig); | ||
278 | } | ||
311 | } | 279 | } |
312 | } | 280 | } |
313 | 281 | ||
@@ -326,16 +294,41 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
326 | return ret; | 294 | return ret; |
327 | } | 295 | } |
328 | 296 | ||
329 | // Called directly from unmanaged code so don't do much | 297 | // Select the connection to the actual Bullet implementation. |
330 | private void BulletLogger(string msg) | 298 | // The main engine selection is the engineName up to the first hypen. |
299 | // So "Bullet-2.80-OpenCL-Intel" specifies the 'bullet' class here and the whole name | ||
300 | // is passed to the engine to do its special selection, etc. | ||
301 | private BSAPITemplate SelectUnderlyingBulletEngine(string engineName) | ||
331 | { | 302 | { |
332 | m_log.Debug("[BULLETS UNMANAGED]:" + msg); | 303 | // For the moment, do a simple switch statement. |
333 | } | 304 | // Someday do fancyness with looking up the interfaces in the assembly. |
305 | BSAPITemplate ret = null; | ||
334 | 306 | ||
335 | // Called directly from unmanaged code so don't do much | 307 | string selectionName = engineName.ToLower(); |
336 | private void BulletLoggerPhysLog(string msg) | 308 | int hyphenIndex = engineName.IndexOf("-"); |
337 | { | 309 | if (hyphenIndex > 0) |
338 | DetailLog("[BULLETS UNMANAGED]:" + msg); | 310 | selectionName = engineName.ToLower().Substring(0, hyphenIndex - 1); |
311 | |||
312 | switch (selectionName) | ||
313 | { | ||
314 | case "bulletunmanaged": | ||
315 | ret = new BSAPIUnman(engineName, this); | ||
316 | break; | ||
317 | case "bulletxna": | ||
318 | ret = new BSAPIXNA(engineName, this); | ||
319 | break; | ||
320 | } | ||
321 | |||
322 | if (ret == null) | ||
323 | { | ||
324 | m_log.ErrorFormat("{0) COULD NOT SELECT BULLET ENGINE: '[BulletSim]PhysicsEngine' must be either 'BulletUnmanaged-*' or 'BulletXNA-*'", LogHeader); | ||
325 | } | ||
326 | else | ||
327 | { | ||
328 | m_log.WarnFormat("{0} Selected bullet engine {1} -> {2}/{3}", LogHeader, engineName, ret.BulletEngineName, ret.BulletEngineVersion); | ||
329 | } | ||
330 | |||
331 | return ret; | ||
339 | } | 332 | } |
340 | 333 | ||
341 | public override void Dispose() | 334 | public override void Dispose() |
@@ -345,8 +338,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
345 | // make sure no stepping happens while we're deleting stuff | 338 | // make sure no stepping happens while we're deleting stuff |
346 | m_initialized = false; | 339 | m_initialized = false; |
347 | 340 | ||
348 | TerrainManager.ReleaseGroundPlaneAndTerrain(); | ||
349 | |||
350 | foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects) | 341 | foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects) |
351 | { | 342 | { |
352 | kvp.Value.Destroy(); | 343 | kvp.Value.Destroy(); |
@@ -366,8 +357,15 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
366 | Shapes = null; | 357 | Shapes = null; |
367 | } | 358 | } |
368 | 359 | ||
360 | if (TerrainManager != null) | ||
361 | { | ||
362 | TerrainManager.ReleaseGroundPlaneAndTerrain(); | ||
363 | TerrainManager.Dispose(); | ||
364 | TerrainManager = null; | ||
365 | } | ||
366 | |||
369 | // Anything left in the unmanaged code should be cleaned out | 367 | // Anything left in the unmanaged code should be cleaned out |
370 | BulletSimAPI.Shutdown2(World.ptr); | 368 | PE.Shutdown(World); |
371 | 369 | ||
372 | // Not logging any more | 370 | // Not logging any more |
373 | PhysicsLogging.Close(); | 371 | PhysicsLogging.Close(); |
@@ -389,12 +387,14 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
389 | if (!m_initialized) return null; | 387 | if (!m_initialized) return null; |
390 | 388 | ||
391 | BSCharacter actor = new BSCharacter(localID, avName, this, position, size, isFlying); | 389 | BSCharacter actor = new BSCharacter(localID, avName, this, position, size, isFlying); |
392 | lock (PhysObjects) PhysObjects.Add(localID, actor); | 390 | lock (PhysObjects) |
391 | PhysObjects.Add(localID, actor); | ||
393 | 392 | ||
394 | // TODO: Remove kludge someday. | 393 | // TODO: Remove kludge someday. |
395 | // We must generate a collision for avatars whether they collide or not. | 394 | // We must generate a collision for avatars whether they collide or not. |
396 | // This is required by OpenSim to update avatar animations, etc. | 395 | // This is required by OpenSim to update avatar animations, etc. |
397 | lock (m_avatars) m_avatars.Add(actor); | 396 | lock (m_avatars) |
397 | m_avatars.Add(actor); | ||
398 | 398 | ||
399 | return actor; | 399 | return actor; |
400 | } | 400 | } |
@@ -410,9 +410,11 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
410 | { | 410 | { |
411 | try | 411 | try |
412 | { | 412 | { |
413 | lock (PhysObjects) PhysObjects.Remove(actor.LocalID); | 413 | lock (PhysObjects) |
414 | PhysObjects.Remove(bsactor.LocalID); | ||
414 | // Remove kludge someday | 415 | // Remove kludge someday |
415 | lock (m_avatars) m_avatars.Remove(bsactor); | 416 | lock (m_avatars) |
417 | m_avatars.Remove(bsactor); | ||
416 | } | 418 | } |
417 | catch (Exception e) | 419 | catch (Exception e) |
418 | { | 420 | { |
@@ -421,13 +423,18 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
421 | bsactor.Destroy(); | 423 | bsactor.Destroy(); |
422 | // bsactor.dispose(); | 424 | // bsactor.dispose(); |
423 | } | 425 | } |
426 | else | ||
427 | { | ||
428 | m_log.ErrorFormat("{0}: Requested to remove avatar that is not a BSCharacter. ID={1}, type={2}", | ||
429 | LogHeader, actor.LocalID, actor.GetType().Name); | ||
430 | } | ||
424 | } | 431 | } |
425 | 432 | ||
426 | public override void RemovePrim(PhysicsActor prim) | 433 | public override void RemovePrim(PhysicsActor prim) |
427 | { | 434 | { |
428 | if (!m_initialized) return; | 435 | if (!m_initialized) return; |
429 | 436 | ||
430 | BSPrim bsprim = prim as BSPrim; | 437 | BSPhysObject bsprim = prim as BSPhysObject; |
431 | if (bsprim != null) | 438 | if (bsprim != null) |
432 | { | 439 | { |
433 | DetailLog("{0},RemovePrim,call", bsprim.LocalID); | 440 | DetailLog("{0},RemovePrim,call", bsprim.LocalID); |
@@ -456,9 +463,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
456 | 463 | ||
457 | if (!m_initialized) return null; | 464 | if (!m_initialized) return null; |
458 | 465 | ||
459 | DetailLog("{0},AddPrimShape,call", localID); | 466 | DetailLog("{0},BSScene.AddPrimShape,call", localID); |
460 | 467 | ||
461 | BSPrim prim = new BSPrim(localID, primName, this, position, size, rotation, pbs, isPhysical); | 468 | BSPhysObject prim = new BSPrimLinkable(localID, primName, this, position, size, rotation, pbs, isPhysical); |
462 | lock (PhysObjects) PhysObjects.Add(localID, prim); | 469 | lock (PhysObjects) PhysObjects.Add(localID, prim); |
463 | return prim; | 470 | return prim; |
464 | } | 471 | } |
@@ -474,41 +481,56 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
474 | // Simulate one timestep | 481 | // Simulate one timestep |
475 | public override float Simulate(float timeStep) | 482 | public override float Simulate(float timeStep) |
476 | { | 483 | { |
484 | // prevent simulation until we've been initialized | ||
485 | if (!m_initialized) return 5.0f; | ||
486 | |||
487 | LastTimeStep = timeStep; | ||
488 | |||
477 | int updatedEntityCount = 0; | 489 | int updatedEntityCount = 0; |
478 | IntPtr updatedEntitiesPtr; | ||
479 | int collidersCount = 0; | 490 | int collidersCount = 0; |
480 | IntPtr collidersPtr; | ||
481 | 491 | ||
482 | int beforeTime = 0; | 492 | int beforeTime = 0; |
483 | int simTime = 0; | 493 | int simTime = 0; |
484 | 494 | ||
485 | // prevent simulation until we've been initialized | ||
486 | if (!m_initialized) return 5.0f; | ||
487 | |||
488 | // update the prim states while we know the physics engine is not busy | 495 | // update the prim states while we know the physics engine is not busy |
489 | int numTaints = _taintOperations.Count; | 496 | int numTaints = _taintOperations.Count; |
497 | |||
498 | InTaintTime = true; // Only used for debugging so locking is not necessary. | ||
499 | |||
490 | ProcessTaints(); | 500 | ProcessTaints(); |
491 | 501 | ||
492 | // Some of the prims operate with special vehicle properties | 502 | // Some of the physical objects requre individual, pre-step calls |
493 | ProcessVehicles(timeStep); | 503 | // (vehicles and avatar movement, in particular) |
494 | ProcessTaints(); // the vehicles might have added taints | 504 | TriggerPreStepEvent(timeStep); |
505 | |||
506 | // the prestep actions might have added taints | ||
507 | numTaints += _taintOperations.Count; | ||
508 | ProcessTaints(); | ||
509 | |||
510 | InTaintTime = false; // Only used for debugging so locking is not necessary. | ||
511 | |||
512 | // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world. | ||
513 | // Only enable this in a limited test world with few objects. | ||
514 | if (m_physicsPhysicalDumpEnabled) | ||
515 | PE.DumpAllInfo(World); | ||
495 | 516 | ||
496 | // step the physical world one interval | 517 | // step the physical world one interval |
497 | m_simulationStep++; | 518 | m_simulationStep++; |
498 | int numSubSteps = 0; | 519 | int numSubSteps = 0; |
499 | |||
500 | try | 520 | try |
501 | { | 521 | { |
502 | if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG | 522 | if (PhysicsLogging.Enabled) |
503 | if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount(); | 523 | beforeTime = Util.EnvironmentTickCount(); |
504 | 524 | ||
505 | numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep, | 525 | numSubSteps = PE.PhysicsStep(World, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out collidersCount); |
506 | out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr); | ||
507 | 526 | ||
508 | if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime); | 527 | if (PhysicsLogging.Enabled) |
509 | DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}", | 528 | { |
510 | DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount); | 529 | simTime = Util.EnvironmentTickCountSubtract(beforeTime); |
511 | if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG | 530 | DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}", |
531 | DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, | ||
532 | updatedEntityCount, collidersCount, ObjectsWithCollisions.Count); | ||
533 | } | ||
512 | } | 534 | } |
513 | catch (Exception e) | 535 | catch (Exception e) |
514 | { | 536 | { |
@@ -520,9 +542,10 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
520 | collidersCount = 0; | 542 | collidersCount = 0; |
521 | } | 543 | } |
522 | 544 | ||
523 | // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in | 545 | if (PhysicsMetricDumpFrames != 0 && ((m_simulationStep % PhysicsMetricDumpFrames) == 0)) |
546 | PE.DumpPhysicsStatistics(World); | ||
524 | 547 | ||
525 | // Get a value for 'now' so all the collision and update routines don't have to get their own | 548 | // Get a value for 'now' so all the collision and update routines don't have to get their own. |
526 | SimulationNowTime = Util.EnvironmentTickCount(); | 549 | SimulationNowTime = Util.EnvironmentTickCount(); |
527 | 550 | ||
528 | // If there were collisions, process them by sending the event to the prim. | 551 | // If there were collisions, process them by sending the event to the prim. |
@@ -535,8 +558,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
535 | uint cB = m_collisionArray[ii].bID; | 558 | uint cB = m_collisionArray[ii].bID; |
536 | Vector3 point = m_collisionArray[ii].point; | 559 | Vector3 point = m_collisionArray[ii].point; |
537 | Vector3 normal = m_collisionArray[ii].normal; | 560 | Vector3 normal = m_collisionArray[ii].normal; |
538 | SendCollision(cA, cB, point, normal, 0.01f); | 561 | float penetration = m_collisionArray[ii].penetration; |
539 | SendCollision(cB, cA, point, -normal, 0.01f); | 562 | SendCollision(cA, cB, point, normal, penetration); |
563 | SendCollision(cB, cA, point, -normal, penetration); | ||
540 | } | 564 | } |
541 | } | 565 | } |
542 | 566 | ||
@@ -562,12 +586,16 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
562 | 586 | ||
563 | // Objects that are done colliding are removed from the ObjectsWithCollisions list. | 587 | // Objects that are done colliding are removed from the ObjectsWithCollisions list. |
564 | // Not done above because it is inside an iteration of ObjectWithCollisions. | 588 | // Not done above because it is inside an iteration of ObjectWithCollisions. |
589 | // This complex collision processing is required to create an empty collision | ||
590 | // event call after all real collisions have happened on an object. This enables | ||
591 | // the simulator to generate the 'collision end' event. | ||
565 | if (ObjectsWithNoMoreCollisions.Count > 0) | 592 | if (ObjectsWithNoMoreCollisions.Count > 0) |
566 | { | 593 | { |
567 | foreach (BSPhysObject po in ObjectsWithNoMoreCollisions) | 594 | foreach (BSPhysObject po in ObjectsWithNoMoreCollisions) |
568 | ObjectsWithCollisions.Remove(po); | 595 | ObjectsWithCollisions.Remove(po); |
569 | ObjectsWithNoMoreCollisions.Clear(); | 596 | ObjectsWithNoMoreCollisions.Clear(); |
570 | } | 597 | } |
598 | // Done with collisions. | ||
571 | 599 | ||
572 | // If any of the objects had updated properties, tell the object it has been changed by the physics engine | 600 | // If any of the objects had updated properties, tell the object it has been changed by the physics engine |
573 | if (updatedEntityCount > 0) | 601 | if (updatedEntityCount > 0) |
@@ -583,17 +611,17 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
583 | } | 611 | } |
584 | } | 612 | } |
585 | 613 | ||
586 | ProcessPostStepTaints(); | 614 | TriggerPostStepEvent(timeStep); |
587 | 615 | ||
588 | // This causes the unmanaged code to output ALL the values found in ALL the objects in the world. | 616 | // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world. |
589 | // Only enable this in a limited test world with few objects. | 617 | // Only enable this in a limited test world with few objects. |
590 | // BulletSimAPI.DumpAllInfo2(World.ptr); // DEBUG DEBUG DEBUG | 618 | if (m_physicsPhysicalDumpEnabled) |
619 | PE.DumpAllInfo(World); | ||
591 | 620 | ||
592 | // The physics engine returns the number of milliseconds it simulated this call. | 621 | // The physics engine returns the number of milliseconds it simulated this call. |
593 | // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS. | 622 | // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS. |
594 | // We multiply by 55 to give a recognizable running rate (55 or less). | 623 | // Multiply by a fixed nominal frame rate to give a rate similar to the simulator (usually 55). |
595 | return numSubSteps * m_fixedTimeStep * 1000 * 55; | 624 | return (float)numSubSteps * m_fixedTimeStep * 1000f * NominalFrameRate; |
596 | // return timeStep * 1000 * 55; | ||
597 | } | 625 | } |
598 | 626 | ||
599 | // Something has collided | 627 | // Something has collided |
@@ -639,12 +667,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
639 | 667 | ||
640 | public override void SetWaterLevel(float baseheight) | 668 | public override void SetWaterLevel(float baseheight) |
641 | { | 669 | { |
642 | m_waterLevel = baseheight; | 670 | SimpleWaterLevel = baseheight; |
643 | } | ||
644 | // Someday.... | ||
645 | public float GetWaterLevelAtXYZ(Vector3 loc) | ||
646 | { | ||
647 | return m_waterLevel; | ||
648 | } | 671 | } |
649 | 672 | ||
650 | public override void DeleteTerrain() | 673 | public override void DeleteTerrain() |
@@ -675,12 +698,35 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
675 | 698 | ||
676 | public override Dictionary<uint, float> GetTopColliders() | 699 | public override Dictionary<uint, float> GetTopColliders() |
677 | { | 700 | { |
678 | return new Dictionary<uint, float>(); | 701 | Dictionary<uint, float> topColliders; |
702 | |||
703 | lock (PhysObjects) | ||
704 | { | ||
705 | foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects) | ||
706 | { | ||
707 | kvp.Value.ComputeCollisionScore(); | ||
708 | } | ||
709 | |||
710 | List<BSPhysObject> orderedPrims = new List<BSPhysObject>(PhysObjects.Values); | ||
711 | orderedPrims.OrderByDescending(p => p.CollisionScore); | ||
712 | topColliders = orderedPrims.Take(25).ToDictionary(p => p.LocalID, p => p.CollisionScore); | ||
713 | } | ||
714 | |||
715 | return topColliders; | ||
679 | } | 716 | } |
680 | 717 | ||
681 | public override bool IsThreaded { get { return false; } } | 718 | public override bool IsThreaded { get { return false; } } |
682 | 719 | ||
683 | #region Taints | 720 | #region Taints |
721 | // The simulation execution order is: | ||
722 | // Simulate() | ||
723 | // DoOneTimeTaints | ||
724 | // TriggerPreStepEvent | ||
725 | // DoOneTimeTaints | ||
726 | // Step() | ||
727 | // ProcessAndSendToSimulatorCollisions | ||
728 | // ProcessAndSendToSimulatorPropertyUpdates | ||
729 | // TriggerPostStepEvent | ||
684 | 730 | ||
685 | // Calls to the PhysicsActors can't directly call into the physics engine | 731 | // Calls to the PhysicsActors can't directly call into the physics engine |
686 | // because it might be busy. We delay changes to a known time. | 732 | // because it might be busy. We delay changes to a known time. |
@@ -707,58 +753,35 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
707 | TaintedObject(ident, callback); | 753 | TaintedObject(ident, callback); |
708 | } | 754 | } |
709 | 755 | ||
756 | private void TriggerPreStepEvent(float timeStep) | ||
757 | { | ||
758 | PreStepAction actions = BeforeStep; | ||
759 | if (actions != null) | ||
760 | actions(timeStep); | ||
761 | |||
762 | } | ||
763 | |||
764 | private void TriggerPostStepEvent(float timeStep) | ||
765 | { | ||
766 | PostStepAction actions = AfterStep; | ||
767 | if (actions != null) | ||
768 | actions(timeStep); | ||
769 | |||
770 | } | ||
771 | |||
710 | // When someone tries to change a property on a BSPrim or BSCharacter, the object queues | 772 | // When someone tries to change a property on a BSPrim or BSCharacter, the object queues |
711 | // a callback into itself to do the actual property change. That callback is called | 773 | // a callback into itself to do the actual property change. That callback is called |
712 | // here just before the physics engine is called to step the simulation. | 774 | // here just before the physics engine is called to step the simulation. |
713 | public void ProcessTaints() | 775 | public void ProcessTaints() |
714 | { | 776 | { |
715 | InTaintTime = true; // Only used for debugging so locking is not necessary. | ||
716 | ProcessRegularTaints(); | 777 | ProcessRegularTaints(); |
717 | ProcessPostTaintTaints(); | 778 | ProcessPostTaintTaints(); |
718 | InTaintTime = false; | ||
719 | } | 779 | } |
720 | 780 | ||
721 | private void ProcessRegularTaints() | 781 | private void ProcessRegularTaints() |
722 | { | 782 | { |
723 | if (_taintOperations.Count > 0) // save allocating new list if there is nothing to process | 783 | if (_taintOperations.Count > 0) // save allocating new list if there is nothing to process |
724 | { | 784 | { |
725 | /* | ||
726 | // Code to limit the number of taints processed per step. Meant to limit step time. | ||
727 | // Unsure if a good idea as code assumes that taints are done before the step. | ||
728 | int taintCount = m_taintsToProcessPerStep; | ||
729 | TaintCallbackEntry oneCallback = new TaintCallbackEntry(); | ||
730 | while (_taintOperations.Count > 0 && taintCount-- > 0) | ||
731 | { | ||
732 | bool gotOne = false; | ||
733 | lock (_taintLock) | ||
734 | { | ||
735 | if (_taintOperations.Count > 0) | ||
736 | { | ||
737 | oneCallback = _taintOperations[0]; | ||
738 | _taintOperations.RemoveAt(0); | ||
739 | gotOne = true; | ||
740 | } | ||
741 | } | ||
742 | if (gotOne) | ||
743 | { | ||
744 | try | ||
745 | { | ||
746 | DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", DetailLogZero, oneCallback.ident); | ||
747 | oneCallback.callback(); | ||
748 | } | ||
749 | catch (Exception e) | ||
750 | { | ||
751 | DetailLog("{0},BSScene.ProcessTaints,doTaintException,id={1}", DetailLogZero, oneCallback.ident); // DEBUG DEBUG DEBUG | ||
752 | m_log.ErrorFormat("{0}: ProcessTaints: {1}: Exception: {2}", LogHeader, oneCallback.ident, e); | ||
753 | } | ||
754 | } | ||
755 | } | ||
756 | if (_taintOperations.Count > 0) | ||
757 | { | ||
758 | DetailLog("{0},BSScene.ProcessTaints,leftTaintsOnList,numNotProcessed={1}", DetailLogZero, _taintOperations.Count); | ||
759 | } | ||
760 | */ | ||
761 | |||
762 | // swizzle a new list into the list location so we can process what's there | 785 | // swizzle a new list into the list location so we can process what's there |
763 | List<TaintCallbackEntry> oldList; | 786 | List<TaintCallbackEntry> oldList; |
764 | lock (_taintLock) | 787 | lock (_taintLock) |
@@ -797,6 +820,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
797 | return; | 820 | return; |
798 | } | 821 | } |
799 | 822 | ||
823 | // Taints that happen after the normal taint processing but before the simulation step. | ||
800 | private void ProcessPostTaintTaints() | 824 | private void ProcessPostTaintTaints() |
801 | { | 825 | { |
802 | if (_postTaintOperations.Count > 0) | 826 | if (_postTaintOperations.Count > 0) |
@@ -824,45 +848,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
824 | } | 848 | } |
825 | } | 849 | } |
826 | 850 | ||
827 | public void PostStepTaintObject(String ident, TaintCallback callback) | ||
828 | { | ||
829 | if (!m_initialized) return; | ||
830 | |||
831 | lock (_taintLock) | ||
832 | { | ||
833 | _postStepOperations.Add(new TaintCallbackEntry(ident, callback)); | ||
834 | } | ||
835 | |||
836 | return; | ||
837 | } | ||
838 | |||
839 | private void ProcessPostStepTaints() | ||
840 | { | ||
841 | if (_postStepOperations.Count > 0) | ||
842 | { | ||
843 | List<TaintCallbackEntry> oldList; | ||
844 | lock (_taintLock) | ||
845 | { | ||
846 | oldList = _postStepOperations; | ||
847 | _postStepOperations = new List<TaintCallbackEntry>(); | ||
848 | } | ||
849 | |||
850 | foreach (TaintCallbackEntry tcbe in oldList) | ||
851 | { | ||
852 | try | ||
853 | { | ||
854 | DetailLog("{0},BSScene.ProcessPostStepTaints,doTaint,id={1}", DetailLogZero, tcbe.ident); // DEBUG DEBUG DEBUG | ||
855 | tcbe.callback(); | ||
856 | } | ||
857 | catch (Exception e) | ||
858 | { | ||
859 | m_log.ErrorFormat("{0}: ProcessPostStepTaints: {1}: Exception: {2}", LogHeader, tcbe.ident, e); | ||
860 | } | ||
861 | } | ||
862 | oldList.Clear(); | ||
863 | } | ||
864 | } | ||
865 | |||
866 | // Only used for debugging. Does not change state of anything so locking is not necessary. | 851 | // Only used for debugging. Does not change state of anything so locking is not necessary. |
867 | public bool AssertInTaintTime(string whereFrom) | 852 | public bool AssertInTaintTime(string whereFrom) |
868 | { | 853 | { |
@@ -870,517 +855,19 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
870 | { | 855 | { |
871 | DetailLog("{0},BSScene.AssertInTaintTime,NOT IN TAINT TIME,Region={1},Where={2}", DetailLogZero, RegionName, whereFrom); | 856 | DetailLog("{0},BSScene.AssertInTaintTime,NOT IN TAINT TIME,Region={1},Where={2}", DetailLogZero, RegionName, whereFrom); |
872 | m_log.ErrorFormat("{0} NOT IN TAINT TIME!! Region={1}, Where={2}", LogHeader, RegionName, whereFrom); | 857 | m_log.ErrorFormat("{0} NOT IN TAINT TIME!! Region={1}, Where={2}", LogHeader, RegionName, whereFrom); |
873 | Util.PrintCallStack(); // Prints the stack into the DEBUG log file. | 858 | // Util.PrintCallStack(DetailLog); |
874 | } | 859 | } |
875 | return InTaintTime; | 860 | return InTaintTime; |
876 | } | 861 | } |
877 | 862 | ||
878 | #endregion // Taints | 863 | #endregion // Taints |
879 | 864 | ||
880 | #region Vehicles | ||
881 | |||
882 | public void VehicleInSceneTypeChanged(BSPrim vehic, Vehicle newType) | ||
883 | { | ||
884 | RemoveVehiclePrim(vehic); | ||
885 | if (newType != Vehicle.TYPE_NONE) | ||
886 | { | ||
887 | // make it so the scene will call us each tick to do vehicle things | ||
888 | AddVehiclePrim(vehic); | ||
889 | } | ||
890 | } | ||
891 | |||
892 | // Make so the scene will call this prim for vehicle actions each tick. | ||
893 | // Safe to call if prim is already in the vehicle list. | ||
894 | public void AddVehiclePrim(BSPrim vehicle) | ||
895 | { | ||
896 | lock (m_vehicles) | ||
897 | { | ||
898 | if (!m_vehicles.Contains(vehicle)) | ||
899 | { | ||
900 | m_vehicles.Add(vehicle); | ||
901 | } | ||
902 | } | ||
903 | } | ||
904 | |||
905 | // Remove a prim from our list of vehicles. | ||
906 | // Safe to call if the prim is not in the vehicle list. | ||
907 | public void RemoveVehiclePrim(BSPrim vehicle) | ||
908 | { | ||
909 | lock (m_vehicles) | ||
910 | { | ||
911 | if (m_vehicles.Contains(vehicle)) | ||
912 | { | ||
913 | m_vehicles.Remove(vehicle); | ||
914 | } | ||
915 | } | ||
916 | } | ||
917 | |||
918 | // Some prims have extra vehicle actions | ||
919 | // Called at taint time! | ||
920 | private void ProcessVehicles(float timeStep) | ||
921 | { | ||
922 | foreach (BSPhysObject pobj in m_vehicles) | ||
923 | { | ||
924 | pobj.StepVehicle(timeStep); | ||
925 | } | ||
926 | } | ||
927 | #endregion Vehicles | ||
928 | |||
929 | #region INI and command line parameter processing | ||
930 | |||
931 | delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val); | ||
932 | delegate float ParamGet(BSScene scene); | ||
933 | delegate void ParamSet(BSScene scene, string paramName, uint localID, float val); | ||
934 | delegate void SetOnObject(BSScene scene, BSPhysObject obj, float val); | ||
935 | |||
936 | private struct ParameterDefn | ||
937 | { | ||
938 | public string name; // string name of the parameter | ||
939 | public string desc; // a short description of what the parameter means | ||
940 | public float defaultValue; // default value if not specified anywhere else | ||
941 | public ParamUser userParam; // get the value from the configuration file | ||
942 | public ParamGet getter; // return the current value stored for this parameter | ||
943 | public ParamSet setter; // set the current value for this parameter | ||
944 | public SetOnObject onObject; // set the value on an object in the physical domain | ||
945 | public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s) | ||
946 | { | ||
947 | name = n; | ||
948 | desc = d; | ||
949 | defaultValue = v; | ||
950 | userParam = u; | ||
951 | getter = g; | ||
952 | setter = s; | ||
953 | onObject = null; | ||
954 | } | ||
955 | public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s, SetOnObject o) | ||
956 | { | ||
957 | name = n; | ||
958 | desc = d; | ||
959 | defaultValue = v; | ||
960 | userParam = u; | ||
961 | getter = g; | ||
962 | setter = s; | ||
963 | onObject = o; | ||
964 | } | ||
965 | } | ||
966 | |||
967 | // List of all of the externally visible parameters. | ||
968 | // For each parameter, this table maps a text name to getter and setters. | ||
969 | // To add a new externally referencable/settable parameter, add the paramter storage | ||
970 | // location somewhere in the program and make an entry in this table with the | ||
971 | // getters and setters. | ||
972 | // It is easiest to find an existing definition and copy it. | ||
973 | // Parameter values are floats. Booleans are converted to a floating value. | ||
974 | // | ||
975 | // A ParameterDefn() takes the following parameters: | ||
976 | // -- the text name of the parameter. This is used for console input and ini file. | ||
977 | // -- a short text description of the parameter. This shows up in the console listing. | ||
978 | // -- a delegate for fetching the parameter from the ini file. | ||
979 | // Should handle fetching the right type from the ini file and converting it. | ||
980 | // -- a delegate for getting the value as a float | ||
981 | // -- a delegate for setting the value from a float | ||
982 | // | ||
983 | // The single letter parameters for the delegates are: | ||
984 | // s = BSScene | ||
985 | // o = BSPhysObject | ||
986 | // p = string parameter name | ||
987 | // l = localID of referenced object | ||
988 | // v = float value | ||
989 | // cf = parameter configuration class (for fetching values from ini file) | ||
990 | private ParameterDefn[] ParameterDefinitions = | ||
991 | { | ||
992 | new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties", | ||
993 | ConfigurationParameters.numericTrue, | ||
994 | (s,cf,p,v) => { s.ShouldMeshSculptedPrim = cf.GetBoolean(p, s.BoolNumeric(v)); }, | ||
995 | (s) => { return s.NumericBool(s.ShouldMeshSculptedPrim); }, | ||
996 | (s,p,l,v) => { s.ShouldMeshSculptedPrim = s.BoolNumeric(v); } ), | ||
997 | new ParameterDefn("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects", | ||
998 | ConfigurationParameters.numericFalse, | ||
999 | (s,cf,p,v) => { s.ShouldForceSimplePrimMeshing = cf.GetBoolean(p, s.BoolNumeric(v)); }, | ||
1000 | (s) => { return s.NumericBool(s.ShouldForceSimplePrimMeshing); }, | ||
1001 | (s,p,l,v) => { s.ShouldForceSimplePrimMeshing = s.BoolNumeric(v); } ), | ||
1002 | new ParameterDefn("UseHullsForPhysicalObjects", "If true, create hulls for physical objects", | ||
1003 | ConfigurationParameters.numericTrue, | ||
1004 | (s,cf,p,v) => { s.ShouldUseHullsForPhysicalObjects = cf.GetBoolean(p, s.BoolNumeric(v)); }, | ||
1005 | (s) => { return s.NumericBool(s.ShouldUseHullsForPhysicalObjects); }, | ||
1006 | (s,p,l,v) => { s.ShouldUseHullsForPhysicalObjects = s.BoolNumeric(v); } ), | ||
1007 | |||
1008 | new ParameterDefn("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)", | ||
1009 | 8f, | ||
1010 | (s,cf,p,v) => { s.MeshLOD = (float)cf.GetInt(p, (int)v); }, | ||
1011 | (s) => { return s.MeshLOD; }, | ||
1012 | (s,p,l,v) => { s.MeshLOD = v; } ), | ||
1013 | new ParameterDefn("MeshLevelOfDetailMegaPrim", "Level of detail to render meshes larger than threshold meters", | ||
1014 | 16f, | ||
1015 | (s,cf,p,v) => { s.MeshMegaPrimLOD = (float)cf.GetInt(p, (int)v); }, | ||
1016 | (s) => { return s.MeshMegaPrimLOD; }, | ||
1017 | (s,p,l,v) => { s.MeshMegaPrimLOD = v; } ), | ||
1018 | new ParameterDefn("MeshLevelOfDetailMegaPrimThreshold", "Size (in meters) of a mesh before using MeshMegaPrimLOD", | ||
1019 | 10f, | ||
1020 | (s,cf,p,v) => { s.MeshMegaPrimThreshold = (float)cf.GetInt(p, (int)v); }, | ||
1021 | (s) => { return s.MeshMegaPrimThreshold; }, | ||
1022 | (s,p,l,v) => { s.MeshMegaPrimThreshold = v; } ), | ||
1023 | new ParameterDefn("SculptLevelOfDetail", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)", | ||
1024 | 32f, | ||
1025 | (s,cf,p,v) => { s.SculptLOD = (float)cf.GetInt(p, (int)v); }, | ||
1026 | (s) => { return s.SculptLOD; }, | ||
1027 | (s,p,l,v) => { s.SculptLOD = v; } ), | ||
1028 | |||
1029 | new ParameterDefn("MaxSubStep", "In simulation step, maximum number of substeps", | ||
1030 | 10f, | ||
1031 | (s,cf,p,v) => { s.m_maxSubSteps = cf.GetInt(p, (int)v); }, | ||
1032 | (s) => { return (float)s.m_maxSubSteps; }, | ||
1033 | (s,p,l,v) => { s.m_maxSubSteps = (int)v; } ), | ||
1034 | new ParameterDefn("FixedTimeStep", "In simulation step, seconds of one substep (1/60)", | ||
1035 | 1f / 60f, | ||
1036 | (s,cf,p,v) => { s.m_fixedTimeStep = cf.GetFloat(p, v); }, | ||
1037 | (s) => { return (float)s.m_fixedTimeStep; }, | ||
1038 | (s,p,l,v) => { s.m_fixedTimeStep = v; } ), | ||
1039 | new ParameterDefn("MaxCollisionsPerFrame", "Max collisions returned at end of each frame", | ||
1040 | 2048f, | ||
1041 | (s,cf,p,v) => { s.m_maxCollisionsPerFrame = cf.GetInt(p, (int)v); }, | ||
1042 | (s) => { return (float)s.m_maxCollisionsPerFrame; }, | ||
1043 | (s,p,l,v) => { s.m_maxCollisionsPerFrame = (int)v; } ), | ||
1044 | new ParameterDefn("MaxUpdatesPerFrame", "Max updates returned at end of each frame", | ||
1045 | 8000f, | ||
1046 | (s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); }, | ||
1047 | (s) => { return (float)s.m_maxUpdatesPerFrame; }, | ||
1048 | (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ), | ||
1049 | new ParameterDefn("MaxTaintsToProcessPerStep", "Number of update taints to process before each simulation step", | ||
1050 | 500f, | ||
1051 | (s,cf,p,v) => { s.m_taintsToProcessPerStep = cf.GetInt(p, (int)v); }, | ||
1052 | (s) => { return (float)s.m_taintsToProcessPerStep; }, | ||
1053 | (s,p,l,v) => { s.m_taintsToProcessPerStep = (int)v; } ), | ||
1054 | new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)", | ||
1055 | 10000.01f, | ||
1056 | (s,cf,p,v) => { s.MaximumObjectMass = cf.GetFloat(p, v); }, | ||
1057 | (s) => { return (float)s.MaximumObjectMass; }, | ||
1058 | (s,p,l,v) => { s.MaximumObjectMass = v; } ), | ||
1059 | |||
1060 | new ParameterDefn("PID_D", "Derivitive factor for motion smoothing", | ||
1061 | 2200f, | ||
1062 | (s,cf,p,v) => { s.PID_D = cf.GetFloat(p, v); }, | ||
1063 | (s) => { return (float)s.PID_D; }, | ||
1064 | (s,p,l,v) => { s.PID_D = v; } ), | ||
1065 | new ParameterDefn("PID_P", "Parameteric factor for motion smoothing", | ||
1066 | 900f, | ||
1067 | (s,cf,p,v) => { s.PID_P = cf.GetFloat(p, v); }, | ||
1068 | (s) => { return (float)s.PID_P; }, | ||
1069 | (s,p,l,v) => { s.PID_P = v; } ), | ||
1070 | |||
1071 | new ParameterDefn("DefaultFriction", "Friction factor used on new objects", | ||
1072 | 0.5f, | ||
1073 | (s,cf,p,v) => { s.m_params[0].defaultFriction = cf.GetFloat(p, v); }, | ||
1074 | (s) => { return s.m_params[0].defaultFriction; }, | ||
1075 | (s,p,l,v) => { s.m_params[0].defaultFriction = v; } ), | ||
1076 | new ParameterDefn("DefaultDensity", "Density for new objects" , | ||
1077 | 10.000006836f, // Aluminum g/cm3 | ||
1078 | (s,cf,p,v) => { s.m_params[0].defaultDensity = cf.GetFloat(p, v); }, | ||
1079 | (s) => { return s.m_params[0].defaultDensity; }, | ||
1080 | (s,p,l,v) => { s.m_params[0].defaultDensity = v; } ), | ||
1081 | new ParameterDefn("DefaultRestitution", "Bouncyness of an object" , | ||
1082 | 0f, | ||
1083 | (s,cf,p,v) => { s.m_params[0].defaultRestitution = cf.GetFloat(p, v); }, | ||
1084 | (s) => { return s.m_params[0].defaultRestitution; }, | ||
1085 | (s,p,l,v) => { s.m_params[0].defaultRestitution = v; } ), | ||
1086 | new ParameterDefn("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)", | ||
1087 | 0f, | ||
1088 | (s,cf,p,v) => { s.m_params[0].collisionMargin = cf.GetFloat(p, v); }, | ||
1089 | (s) => { return s.m_params[0].collisionMargin; }, | ||
1090 | (s,p,l,v) => { s.m_params[0].collisionMargin = v; } ), | ||
1091 | new ParameterDefn("Gravity", "Vertical force of gravity (negative means down)", | ||
1092 | -9.80665f, | ||
1093 | (s,cf,p,v) => { s.m_params[0].gravity = cf.GetFloat(p, v); }, | ||
1094 | (s) => { return s.m_params[0].gravity; }, | ||
1095 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].gravity, p, PhysParameterEntry.APPLY_TO_NONE, v); }, | ||
1096 | (s,o,v) => { BulletSimAPI.SetGravity2(s.World.ptr, new Vector3(0f,0f,v)); } ), | ||
1097 | |||
1098 | |||
1099 | new ParameterDefn("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)", | ||
1100 | 0f, | ||
1101 | (s,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); }, | ||
1102 | (s) => { return s.m_params[0].linearDamping; }, | ||
1103 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearDamping, p, l, v); }, | ||
1104 | (s,o,v) => { BulletSimAPI.SetDamping2(o.PhysBody.ptr, v, s.m_params[0].angularDamping); } ), | ||
1105 | new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)", | ||
1106 | 0f, | ||
1107 | (s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); }, | ||
1108 | (s) => { return s.m_params[0].angularDamping; }, | ||
1109 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularDamping, p, l, v); }, | ||
1110 | (s,o,v) => { BulletSimAPI.SetDamping2(o.PhysBody.ptr, s.m_params[0].linearDamping, v); } ), | ||
1111 | new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static", | ||
1112 | 0.2f, | ||
1113 | (s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); }, | ||
1114 | (s) => { return s.m_params[0].deactivationTime; }, | ||
1115 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].deactivationTime, p, l, v); }, | ||
1116 | (s,o,v) => { BulletSimAPI.SetDeactivationTime2(o.PhysBody.ptr, v); } ), | ||
1117 | new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static", | ||
1118 | 0.8f, | ||
1119 | (s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); }, | ||
1120 | (s) => { return s.m_params[0].linearSleepingThreshold; }, | ||
1121 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearSleepingThreshold, p, l, v); }, | ||
1122 | (s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.PhysBody.ptr, v, v); } ), | ||
1123 | new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static", | ||
1124 | 1.0f, | ||
1125 | (s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); }, | ||
1126 | (s) => { return s.m_params[0].angularSleepingThreshold; }, | ||
1127 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularSleepingThreshold, p, l, v); }, | ||
1128 | (s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.PhysBody.ptr, v, v); } ), | ||
1129 | new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" , | ||
1130 | 0f, // set to zero to disable | ||
1131 | (s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); }, | ||
1132 | (s) => { return s.m_params[0].ccdMotionThreshold; }, | ||
1133 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdMotionThreshold, p, l, v); }, | ||
1134 | (s,o,v) => { BulletSimAPI.SetCcdMotionThreshold2(o.PhysBody.ptr, v); } ), | ||
1135 | new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" , | ||
1136 | 0f, | ||
1137 | (s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); }, | ||
1138 | (s) => { return s.m_params[0].ccdSweptSphereRadius; }, | ||
1139 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdSweptSphereRadius, p, l, v); }, | ||
1140 | (s,o,v) => { BulletSimAPI.SetCcdSweptSphereRadius2(o.PhysBody.ptr, v); } ), | ||
1141 | new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" , | ||
1142 | 0.1f, | ||
1143 | (s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); }, | ||
1144 | (s) => { return s.m_params[0].contactProcessingThreshold; }, | ||
1145 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].contactProcessingThreshold, p, l, v); }, | ||
1146 | (s,o,v) => { BulletSimAPI.SetContactProcessingThreshold2(o.PhysBody.ptr, v); } ), | ||
1147 | |||
1148 | new ParameterDefn("TerrainImplementation", "Type of shape to use for terrain (0=heightmap, 1=mesh)", | ||
1149 | (float)BSTerrainPhys.TerrainImplementation.Mesh, | ||
1150 | (s,cf,p,v) => { s.m_params[0].terrainImplementation = cf.GetFloat(p,v); }, | ||
1151 | (s) => { return s.m_params[0].terrainImplementation; }, | ||
1152 | (s,p,l,v) => { s.m_params[0].terrainImplementation = v; } ), | ||
1153 | new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" , | ||
1154 | 0.5f, | ||
1155 | (s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); }, | ||
1156 | (s) => { return s.m_params[0].terrainFriction; }, | ||
1157 | (s,p,l,v) => { s.m_params[0].terrainFriction = v; /* TODO: set on real terrain */} ), | ||
1158 | new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" , | ||
1159 | 0.8f, | ||
1160 | (s,cf,p,v) => { s.m_params[0].terrainHitFraction = cf.GetFloat(p, v); }, | ||
1161 | (s) => { return s.m_params[0].terrainHitFraction; }, | ||
1162 | (s,p,l,v) => { s.m_params[0].terrainHitFraction = v; /* TODO: set on real terrain */ } ), | ||
1163 | new ParameterDefn("TerrainRestitution", "Bouncyness" , | ||
1164 | 0f, | ||
1165 | (s,cf,p,v) => { s.m_params[0].terrainRestitution = cf.GetFloat(p, v); }, | ||
1166 | (s) => { return s.m_params[0].terrainRestitution; }, | ||
1167 | (s,p,l,v) => { s.m_params[0].terrainRestitution = v; /* TODO: set on real terrain */ } ), | ||
1168 | new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.", | ||
1169 | 0.2f, | ||
1170 | (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); }, | ||
1171 | (s) => { return s.m_params[0].avatarFriction; }, | ||
1172 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarFriction, p, l, v); } ), | ||
1173 | new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.", | ||
1174 | 10f, | ||
1175 | (s,cf,p,v) => { s.m_params[0].avatarStandingFriction = cf.GetFloat(p, v); }, | ||
1176 | (s) => { return s.m_params[0].avatarStandingFriction; }, | ||
1177 | (s,p,l,v) => { s.m_params[0].avatarStandingFriction = v; } ), | ||
1178 | new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.", | ||
1179 | 60f, | ||
1180 | (s,cf,p,v) => { s.m_params[0].avatarDensity = cf.GetFloat(p, v); }, | ||
1181 | (s) => { return s.m_params[0].avatarDensity; }, | ||
1182 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarDensity, p, l, v); } ), | ||
1183 | new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.", | ||
1184 | 0f, | ||
1185 | (s,cf,p,v) => { s.m_params[0].avatarRestitution = cf.GetFloat(p, v); }, | ||
1186 | (s) => { return s.m_params[0].avatarRestitution; }, | ||
1187 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarRestitution, p, l, v); } ), | ||
1188 | new ParameterDefn("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule", | ||
1189 | 0.6f, | ||
1190 | (s,cf,p,v) => { s.m_params[0].avatarCapsuleWidth = cf.GetFloat(p, v); }, | ||
1191 | (s) => { return s.m_params[0].avatarCapsuleWidth; }, | ||
1192 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarCapsuleWidth, p, l, v); } ), | ||
1193 | new ParameterDefn("AvatarCapsuleDepth", "The distance between the front and back of the avatar capsule", | ||
1194 | 0.45f, | ||
1195 | (s,cf,p,v) => { s.m_params[0].avatarCapsuleDepth = cf.GetFloat(p, v); }, | ||
1196 | (s) => { return s.m_params[0].avatarCapsuleDepth; }, | ||
1197 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarCapsuleDepth, p, l, v); } ), | ||
1198 | new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar", | ||
1199 | 1.5f, | ||
1200 | (s,cf,p,v) => { s.m_params[0].avatarCapsuleHeight = cf.GetFloat(p, v); }, | ||
1201 | (s) => { return s.m_params[0].avatarCapsuleHeight; }, | ||
1202 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarCapsuleHeight, p, l, v); } ), | ||
1203 | new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions", | ||
1204 | 0.1f, | ||
1205 | (s,cf,p,v) => { s.m_params[0].avatarContactProcessingThreshold = cf.GetFloat(p, v); }, | ||
1206 | (s) => { return s.m_params[0].avatarContactProcessingThreshold; }, | ||
1207 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ), | ||
1208 | |||
1209 | |||
1210 | new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)", | ||
1211 | 0f, | ||
1212 | (s,cf,p,v) => { s.m_params[0].maxPersistantManifoldPoolSize = cf.GetFloat(p, v); }, | ||
1213 | (s) => { return s.m_params[0].maxPersistantManifoldPoolSize; }, | ||
1214 | (s,p,l,v) => { s.m_params[0].maxPersistantManifoldPoolSize = v; } ), | ||
1215 | new ParameterDefn("MaxCollisionAlgorithmPoolSize", "Number of collisions pooled (0 means default of 4096)", | ||
1216 | 0f, | ||
1217 | (s,cf,p,v) => { s.m_params[0].maxCollisionAlgorithmPoolSize = cf.GetFloat(p, v); }, | ||
1218 | (s) => { return s.m_params[0].maxCollisionAlgorithmPoolSize; }, | ||
1219 | (s,p,l,v) => { s.m_params[0].maxCollisionAlgorithmPoolSize = v; } ), | ||
1220 | new ParameterDefn("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count", | ||
1221 | ConfigurationParameters.numericFalse, | ||
1222 | (s,cf,p,v) => { s.m_params[0].shouldDisableContactPoolDynamicAllocation = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, | ||
1223 | (s) => { return s.m_params[0].shouldDisableContactPoolDynamicAllocation; }, | ||
1224 | (s,p,l,v) => { s.m_params[0].shouldDisableContactPoolDynamicAllocation = v; } ), | ||
1225 | new ParameterDefn("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step", | ||
1226 | ConfigurationParameters.numericFalse, | ||
1227 | (s,cf,p,v) => { s.m_params[0].shouldForceUpdateAllAabbs = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, | ||
1228 | (s) => { return s.m_params[0].shouldForceUpdateAllAabbs; }, | ||
1229 | (s,p,l,v) => { s.m_params[0].shouldForceUpdateAllAabbs = v; } ), | ||
1230 | new ParameterDefn("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction", | ||
1231 | ConfigurationParameters.numericTrue, | ||
1232 | (s,cf,p,v) => { s.m_params[0].shouldRandomizeSolverOrder = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, | ||
1233 | (s) => { return s.m_params[0].shouldRandomizeSolverOrder; }, | ||
1234 | (s,p,l,v) => { s.m_params[0].shouldRandomizeSolverOrder = v; } ), | ||
1235 | new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands", | ||
1236 | ConfigurationParameters.numericTrue, | ||
1237 | (s,cf,p,v) => { s.m_params[0].shouldSplitSimulationIslands = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, | ||
1238 | (s) => { return s.m_params[0].shouldSplitSimulationIslands; }, | ||
1239 | (s,p,l,v) => { s.m_params[0].shouldSplitSimulationIslands = v; } ), | ||
1240 | new ParameterDefn("ShouldEnableFrictionCaching", "Enable friction computation caching", | ||
1241 | ConfigurationParameters.numericFalse, | ||
1242 | (s,cf,p,v) => { s.m_params[0].shouldEnableFrictionCaching = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, | ||
1243 | (s) => { return s.m_params[0].shouldEnableFrictionCaching; }, | ||
1244 | (s,p,l,v) => { s.m_params[0].shouldEnableFrictionCaching = v; } ), | ||
1245 | new ParameterDefn("NumberOfSolverIterations", "Number of internal iterations (0 means default)", | ||
1246 | 0f, // zero says use Bullet default | ||
1247 | (s,cf,p,v) => { s.m_params[0].numberOfSolverIterations = cf.GetFloat(p, v); }, | ||
1248 | (s) => { return s.m_params[0].numberOfSolverIterations; }, | ||
1249 | (s,p,l,v) => { s.m_params[0].numberOfSolverIterations = v; } ), | ||
1250 | |||
1251 | new ParameterDefn("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)", | ||
1252 | (float)BSLinkset.LinksetImplementation.Compound, | ||
1253 | (s,cf,p,v) => { s.m_params[0].linksetImplementation = cf.GetFloat(p,v); }, | ||
1254 | (s) => { return s.m_params[0].linksetImplementation; }, | ||
1255 | (s,p,l,v) => { s.m_params[0].linksetImplementation = v; } ), | ||
1256 | new ParameterDefn("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.", | ||
1257 | ConfigurationParameters.numericFalse, | ||
1258 | (s,cf,p,v) => { s.m_params[0].linkConstraintUseFrameOffset = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, | ||
1259 | (s) => { return s.m_params[0].linkConstraintUseFrameOffset; }, | ||
1260 | (s,p,l,v) => { s.m_params[0].linkConstraintUseFrameOffset = v; } ), | ||
1261 | new ParameterDefn("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints", | ||
1262 | ConfigurationParameters.numericTrue, | ||
1263 | (s,cf,p,v) => { s.m_params[0].linkConstraintEnableTransMotor = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, | ||
1264 | (s) => { return s.m_params[0].linkConstraintEnableTransMotor; }, | ||
1265 | (s,p,l,v) => { s.m_params[0].linkConstraintEnableTransMotor = v; } ), | ||
1266 | new ParameterDefn("LinkConstraintTransMotorMaxVel", "Maximum velocity to be applied by translational motor in linkset constraints", | ||
1267 | 5.0f, | ||
1268 | (s,cf,p,v) => { s.m_params[0].linkConstraintTransMotorMaxVel = cf.GetFloat(p, v); }, | ||
1269 | (s) => { return s.m_params[0].linkConstraintTransMotorMaxVel; }, | ||
1270 | (s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxVel = v; } ), | ||
1271 | new ParameterDefn("LinkConstraintTransMotorMaxForce", "Maximum force to be applied by translational motor in linkset constraints", | ||
1272 | 0.1f, | ||
1273 | (s,cf,p,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = cf.GetFloat(p, v); }, | ||
1274 | (s) => { return s.m_params[0].linkConstraintTransMotorMaxForce; }, | ||
1275 | (s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = v; } ), | ||
1276 | new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1", | ||
1277 | 0.1f, | ||
1278 | (s,cf,p,v) => { s.m_params[0].linkConstraintCFM = cf.GetFloat(p, v); }, | ||
1279 | (s) => { return s.m_params[0].linkConstraintCFM; }, | ||
1280 | (s,p,l,v) => { s.m_params[0].linkConstraintCFM = v; } ), | ||
1281 | new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2", | ||
1282 | 0.1f, | ||
1283 | (s,cf,p,v) => { s.m_params[0].linkConstraintERP = cf.GetFloat(p, v); }, | ||
1284 | (s) => { return s.m_params[0].linkConstraintERP; }, | ||
1285 | (s,p,l,v) => { s.m_params[0].linkConstraintERP = v; } ), | ||
1286 | new ParameterDefn("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)", | ||
1287 | 40, | ||
1288 | (s,cf,p,v) => { s.m_params[0].linkConstraintSolverIterations = cf.GetFloat(p, v); }, | ||
1289 | (s) => { return s.m_params[0].linkConstraintSolverIterations; }, | ||
1290 | (s,p,l,v) => { s.m_params[0].linkConstraintSolverIterations = v; } ), | ||
1291 | |||
1292 | new ParameterDefn("LogPhysicsStatisticsFrames", "Frames between outputting detailed phys stats. (0 is off)", | ||
1293 | 0f, | ||
1294 | (s,cf,p,v) => { s.m_params[0].physicsLoggingFrames = cf.GetInt(p, (int)v); }, | ||
1295 | (s) => { return (float)s.m_params[0].physicsLoggingFrames; }, | ||
1296 | (s,p,l,v) => { s.m_params[0].physicsLoggingFrames = (int)v; } ), | ||
1297 | }; | ||
1298 | |||
1299 | // Convert a boolean to our numeric true and false values | ||
1300 | public float NumericBool(bool b) | ||
1301 | { | ||
1302 | return (b ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse); | ||
1303 | } | ||
1304 | |||
1305 | // Convert numeric true and false values to a boolean | ||
1306 | public bool BoolNumeric(float b) | ||
1307 | { | ||
1308 | return (b == ConfigurationParameters.numericTrue ? true : false); | ||
1309 | } | ||
1310 | |||
1311 | // Search through the parameter definitions and return the matching | ||
1312 | // ParameterDefn structure. | ||
1313 | // Case does not matter as names are compared after converting to lower case. | ||
1314 | // Returns 'false' if the parameter is not found. | ||
1315 | private bool TryGetParameter(string paramName, out ParameterDefn defn) | ||
1316 | { | ||
1317 | bool ret = false; | ||
1318 | ParameterDefn foundDefn = new ParameterDefn(); | ||
1319 | string pName = paramName.ToLower(); | ||
1320 | |||
1321 | foreach (ParameterDefn parm in ParameterDefinitions) | ||
1322 | { | ||
1323 | if (pName == parm.name.ToLower()) | ||
1324 | { | ||
1325 | foundDefn = parm; | ||
1326 | ret = true; | ||
1327 | break; | ||
1328 | } | ||
1329 | } | ||
1330 | defn = foundDefn; | ||
1331 | return ret; | ||
1332 | } | ||
1333 | |||
1334 | // Pass through the settable parameters and set the default values | ||
1335 | private void SetParameterDefaultValues() | ||
1336 | { | ||
1337 | foreach (ParameterDefn parm in ParameterDefinitions) | ||
1338 | { | ||
1339 | parm.setter(this, parm.name, PhysParameterEntry.APPLY_TO_NONE, parm.defaultValue); | ||
1340 | } | ||
1341 | } | ||
1342 | |||
1343 | // Get user set values out of the ini file. | ||
1344 | private void SetParameterConfigurationValues(IConfig cfg) | ||
1345 | { | ||
1346 | foreach (ParameterDefn parm in ParameterDefinitions) | ||
1347 | { | ||
1348 | parm.userParam(this, cfg, parm.name, parm.defaultValue); | ||
1349 | } | ||
1350 | } | ||
1351 | |||
1352 | private PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1]; | ||
1353 | |||
1354 | // This creates an array in the correct format for returning the list of | ||
1355 | // parameters. This is used by the 'list' option of the 'physics' command. | ||
1356 | private void BuildParameterTable() | ||
1357 | { | ||
1358 | if (SettableParameters.Length < ParameterDefinitions.Length) | ||
1359 | { | ||
1360 | List<PhysParameterEntry> entries = new List<PhysParameterEntry>(); | ||
1361 | for (int ii = 0; ii < ParameterDefinitions.Length; ii++) | ||
1362 | { | ||
1363 | ParameterDefn pd = ParameterDefinitions[ii]; | ||
1364 | entries.Add(new PhysParameterEntry(pd.name, pd.desc)); | ||
1365 | } | ||
1366 | |||
1367 | // make the list in alphabetical order for estetic reasons | ||
1368 | entries.Sort(delegate(PhysParameterEntry ppe1, PhysParameterEntry ppe2) | ||
1369 | { | ||
1370 | return ppe1.name.CompareTo(ppe2.name); | ||
1371 | }); | ||
1372 | |||
1373 | SettableParameters = entries.ToArray(); | ||
1374 | } | ||
1375 | } | ||
1376 | |||
1377 | |||
1378 | #region IPhysicsParameters | 865 | #region IPhysicsParameters |
1379 | // Get the list of parameters this physics engine supports | 866 | // Get the list of parameters this physics engine supports |
1380 | public PhysParameterEntry[] GetParameterList() | 867 | public PhysParameterEntry[] GetParameterList() |
1381 | { | 868 | { |
1382 | BuildParameterTable(); | 869 | BSParam.BuildParameterTable(); |
1383 | return SettableParameters; | 870 | return BSParam.SettableParameters; |
1384 | } | 871 | } |
1385 | 872 | ||
1386 | // Set parameter on a specific or all instances. | 873 | // Set parameter on a specific or all instances. |
@@ -1389,63 +876,65 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
1389 | // will use the next time since it's pinned and shared memory. | 876 | // will use the next time since it's pinned and shared memory. |
1390 | // Some of the values require calling into the physics engine to get the new | 877 | // Some of the values require calling into the physics engine to get the new |
1391 | // value activated ('terrainFriction' for instance). | 878 | // value activated ('terrainFriction' for instance). |
1392 | public bool SetPhysicsParameter(string parm, float val, uint localID) | 879 | public bool SetPhysicsParameter(string parm, string val, uint localID) |
1393 | { | 880 | { |
1394 | bool ret = false; | 881 | bool ret = false; |
1395 | ParameterDefn theParam; | 882 | |
1396 | if (TryGetParameter(parm, out theParam)) | 883 | BSParam.ParameterDefnBase theParam; |
884 | if (BSParam.TryGetParameter(parm, out theParam)) | ||
1397 | { | 885 | { |
1398 | theParam.setter(this, parm, localID, val); | 886 | // Set the value in the C# code |
887 | theParam.SetValue(this, val); | ||
888 | |||
889 | // Optionally set the parameter in the unmanaged code | ||
890 | if (theParam.HasSetOnObject) | ||
891 | { | ||
892 | // update all the localIDs specified | ||
893 | // If the local ID is APPLY_TO_NONE, just change the default value | ||
894 | // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs | ||
895 | // If the localID is a specific object, apply the parameter change to only that object | ||
896 | List<uint> objectIDs = new List<uint>(); | ||
897 | switch (localID) | ||
898 | { | ||
899 | case PhysParameterEntry.APPLY_TO_NONE: | ||
900 | // This will cause a call into the physical world if some operation is specified (SetOnObject). | ||
901 | objectIDs.Add(TERRAIN_ID); | ||
902 | TaintedUpdateParameter(parm, objectIDs, val); | ||
903 | break; | ||
904 | case PhysParameterEntry.APPLY_TO_ALL: | ||
905 | lock (PhysObjects) objectIDs = new List<uint>(PhysObjects.Keys); | ||
906 | TaintedUpdateParameter(parm, objectIDs, val); | ||
907 | break; | ||
908 | default: | ||
909 | // setting only one localID | ||
910 | objectIDs.Add(localID); | ||
911 | TaintedUpdateParameter(parm, objectIDs, val); | ||
912 | break; | ||
913 | } | ||
914 | } | ||
915 | |||
1399 | ret = true; | 916 | ret = true; |
1400 | } | 917 | } |
1401 | return ret; | 918 | return ret; |
1402 | } | 919 | } |
1403 | 920 | ||
1404 | // update all the localIDs specified | ||
1405 | // If the local ID is APPLY_TO_NONE, just change the default value | ||
1406 | // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs | ||
1407 | // If the localID is a specific object, apply the parameter change to only that object | ||
1408 | private void UpdateParameterObject(ref float defaultLoc, string parm, uint localID, float val) | ||
1409 | { | ||
1410 | List<uint> objectIDs = new List<uint>(); | ||
1411 | switch (localID) | ||
1412 | { | ||
1413 | case PhysParameterEntry.APPLY_TO_NONE: | ||
1414 | defaultLoc = val; // setting only the default value | ||
1415 | // This will cause a call into the physical world if some operation is specified (SetOnObject). | ||
1416 | objectIDs.Add(TERRAIN_ID); | ||
1417 | TaintedUpdateParameter(parm, objectIDs, val); | ||
1418 | break; | ||
1419 | case PhysParameterEntry.APPLY_TO_ALL: | ||
1420 | defaultLoc = val; // setting ALL also sets the default value | ||
1421 | lock (PhysObjects) objectIDs = new List<uint>(PhysObjects.Keys); | ||
1422 | TaintedUpdateParameter(parm, objectIDs, val); | ||
1423 | break; | ||
1424 | default: | ||
1425 | // setting only one localID | ||
1426 | objectIDs.Add(localID); | ||
1427 | TaintedUpdateParameter(parm, objectIDs, val); | ||
1428 | break; | ||
1429 | } | ||
1430 | } | ||
1431 | |||
1432 | // schedule the actual updating of the paramter to when the phys engine is not busy | 921 | // schedule the actual updating of the paramter to when the phys engine is not busy |
1433 | private void TaintedUpdateParameter(string parm, List<uint> lIDs, float val) | 922 | private void TaintedUpdateParameter(string parm, List<uint> lIDs, string val) |
1434 | { | 923 | { |
1435 | float xval = val; | 924 | string xval = val; |
1436 | List<uint> xlIDs = lIDs; | 925 | List<uint> xlIDs = lIDs; |
1437 | string xparm = parm; | 926 | string xparm = parm; |
1438 | TaintedObject("BSScene.UpdateParameterSet", delegate() { | 927 | TaintedObject("BSScene.UpdateParameterSet", delegate() { |
1439 | ParameterDefn thisParam; | 928 | BSParam.ParameterDefnBase thisParam; |
1440 | if (TryGetParameter(xparm, out thisParam)) | 929 | if (BSParam.TryGetParameter(xparm, out thisParam)) |
1441 | { | 930 | { |
1442 | if (thisParam.onObject != null) | 931 | if (thisParam.HasSetOnObject) |
1443 | { | 932 | { |
1444 | foreach (uint lID in xlIDs) | 933 | foreach (uint lID in xlIDs) |
1445 | { | 934 | { |
1446 | BSPhysObject theObject = null; | 935 | BSPhysObject theObject = null; |
1447 | PhysObjects.TryGetValue(lID, out theObject); | 936 | if (PhysObjects.TryGetValue(lID, out theObject)) |
1448 | thisParam.onObject(this, theObject, xval); | 937 | thisParam.SetOnObject(this, theObject); |
1449 | } | 938 | } |
1450 | } | 939 | } |
1451 | } | 940 | } |
@@ -1454,14 +943,14 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
1454 | 943 | ||
1455 | // Get parameter. | 944 | // Get parameter. |
1456 | // Return 'false' if not able to get the parameter. | 945 | // Return 'false' if not able to get the parameter. |
1457 | public bool GetPhysicsParameter(string parm, out float value) | 946 | public bool GetPhysicsParameter(string parm, out string value) |
1458 | { | 947 | { |
1459 | float val = 0f; | 948 | string val = String.Empty; |
1460 | bool ret = false; | 949 | bool ret = false; |
1461 | ParameterDefn theParam; | 950 | BSParam.ParameterDefnBase theParam; |
1462 | if (TryGetParameter(parm, out theParam)) | 951 | if (BSParam.TryGetParameter(parm, out theParam)) |
1463 | { | 952 | { |
1464 | val = theParam.getter(this); | 953 | val = theParam.GetValue(this); |
1465 | ret = true; | 954 | ret = true; |
1466 | } | 955 | } |
1467 | value = val; | 956 | value = val; |
@@ -1470,24 +959,12 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
1470 | 959 | ||
1471 | #endregion IPhysicsParameters | 960 | #endregion IPhysicsParameters |
1472 | 961 | ||
1473 | #endregion Runtime settable parameters | ||
1474 | |||
1475 | // Debugging routine for dumping detailed physical information for vehicle prims | ||
1476 | private void DumpVehicles() | ||
1477 | { | ||
1478 | foreach (BSPrim prim in m_vehicles) | ||
1479 | { | ||
1480 | BulletSimAPI.DumpRigidBody2(World.ptr, prim.PhysBody.ptr); | ||
1481 | BulletSimAPI.DumpCollisionShape2(World.ptr, prim.PhysShape.ptr); | ||
1482 | } | ||
1483 | } | ||
1484 | |||
1485 | // Invoke the detailed logger and output something if it's enabled. | 962 | // Invoke the detailed logger and output something if it's enabled. |
1486 | public void DetailLog(string msg, params Object[] args) | 963 | public void DetailLog(string msg, params Object[] args) |
1487 | { | 964 | { |
1488 | PhysicsLogging.Write(msg, args); | 965 | PhysicsLogging.Write(msg, args); |
1489 | // Add the Flush() if debugging crashes. Gets all the messages written out. | 966 | // Add the Flush() if debugging crashes. Gets all the messages written out. |
1490 | // PhysicsLogging.Flush(); | 967 | if (m_physicsLoggingDoFlush) PhysicsLogging.Flush(); |
1491 | } | 968 | } |
1492 | // Used to fill in the LocalID when there isn't one. It's the correct number of characters. | 969 | // Used to fill in the LocalID when there isn't one. It's the correct number of characters. |
1493 | public const string DetailLogZero = "0000000000"; | 970 | public const string DetailLogZero = "0000000000"; |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs index 892c34b..220fbbc 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs | |||
@@ -45,7 +45,7 @@ public sealed class BSShapeCollection : IDisposable | |||
45 | // Description of a Mesh | 45 | // Description of a Mesh |
46 | private struct MeshDesc | 46 | private struct MeshDesc |
47 | { | 47 | { |
48 | public IntPtr ptr; | 48 | public BulletShape shape; |
49 | public int referenceCount; | 49 | public int referenceCount; |
50 | public DateTime lastReferenced; | 50 | public DateTime lastReferenced; |
51 | public UInt64 shapeKey; | 51 | public UInt64 shapeKey; |
@@ -55,7 +55,7 @@ public sealed class BSShapeCollection : IDisposable | |||
55 | // Meshes and hulls have the same shape hash key but we only need hulls for efficient collision calculations. | 55 | // Meshes and hulls have the same shape hash key but we only need hulls for efficient collision calculations. |
56 | private struct HullDesc | 56 | private struct HullDesc |
57 | { | 57 | { |
58 | public IntPtr ptr; | 58 | public BulletShape shape; |
59 | public int referenceCount; | 59 | public int referenceCount; |
60 | public DateTime lastReferenced; | 60 | public DateTime lastReferenced; |
61 | public UInt64 shapeKey; | 61 | public UInt64 shapeKey; |
@@ -65,9 +65,16 @@ public sealed class BSShapeCollection : IDisposable | |||
65 | private Dictionary<System.UInt64, MeshDesc> Meshes = new Dictionary<System.UInt64, MeshDesc>(); | 65 | private Dictionary<System.UInt64, MeshDesc> Meshes = new Dictionary<System.UInt64, MeshDesc>(); |
66 | private Dictionary<System.UInt64, HullDesc> Hulls = new Dictionary<System.UInt64, HullDesc>(); | 66 | private Dictionary<System.UInt64, HullDesc> Hulls = new Dictionary<System.UInt64, HullDesc>(); |
67 | 67 | ||
68 | private bool DDetail = false; | ||
69 | |||
68 | public BSShapeCollection(BSScene physScene) | 70 | public BSShapeCollection(BSScene physScene) |
69 | { | 71 | { |
70 | PhysicsScene = physScene; | 72 | PhysicsScene = physScene; |
73 | // Set the next to 'true' for very detailed shape update detailed logging (detailed details?) | ||
74 | // While detailed debugging is still active, this is better than commenting out all the | ||
75 | // DetailLog statements. When debugging slows down, this and the protected logging | ||
76 | // statements can be commented/removed. | ||
77 | DDetail = true; | ||
71 | } | 78 | } |
72 | 79 | ||
73 | public void Dispose() | 80 | public void Dispose() |
@@ -91,7 +98,7 @@ public sealed class BSShapeCollection : IDisposable | |||
91 | // higher level dependencies on the shape or body. Mostly used for LinkSets to | 98 | // higher level dependencies on the shape or body. Mostly used for LinkSets to |
92 | // remove the physical constraints before the body is destroyed. | 99 | // remove the physical constraints before the body is destroyed. |
93 | // Called at taint-time!! | 100 | // Called at taint-time!! |
94 | public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPhysObject prim, | 101 | public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim, |
95 | ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback) | 102 | ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback) |
96 | { | 103 | { |
97 | PhysicsScene.AssertInTaintTime("BSShapeCollection.GetBodyAndShape"); | 104 | PhysicsScene.AssertInTaintTime("BSShapeCollection.GetBodyAndShape"); |
@@ -109,8 +116,7 @@ public sealed class BSShapeCollection : IDisposable | |||
109 | // rebuild the body around it. | 116 | // rebuild the body around it. |
110 | // Updates prim.BSBody with information/pointers to requested body | 117 | // Updates prim.BSBody with information/pointers to requested body |
111 | // Returns 'true' if BSBody was changed. | 118 | // Returns 'true' if BSBody was changed. |
112 | bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World, | 119 | bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World, bodyCallback); |
113 | prim.PhysShape, bodyCallback); | ||
114 | ret = newGeom || newBody; | 120 | ret = newGeom || newBody; |
115 | } | 121 | } |
116 | DetailLog("{0},BSShapeCollection.GetBodyAndShape,taintExit,force={1},ret={2},body={3},shape={4}", | 122 | DetailLog("{0},BSShapeCollection.GetBodyAndShape,taintExit,force={1},ret={2},body={3},shape={4}", |
@@ -119,51 +125,52 @@ public sealed class BSShapeCollection : IDisposable | |||
119 | return ret; | 125 | return ret; |
120 | } | 126 | } |
121 | 127 | ||
128 | public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim) | ||
129 | { | ||
130 | return GetBodyAndShape(forceRebuild, sim, prim, null, null); | ||
131 | } | ||
132 | |||
122 | // Track another user of a body. | 133 | // Track another user of a body. |
123 | // We presume the caller has allocated the body. | 134 | // We presume the caller has allocated the body. |
124 | // Bodies only have one user so the body is just put into the world if not already there. | 135 | // Bodies only have one user so the body is just put into the world if not already there. |
125 | public void ReferenceBody(BulletBody body, bool inTaintTime) | 136 | private void ReferenceBody(BulletBody body) |
126 | { | 137 | { |
127 | lock (m_collectionActivityLock) | 138 | lock (m_collectionActivityLock) |
128 | { | 139 | { |
129 | DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body); | 140 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body); |
130 | PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.ReferenceBody", delegate() | 141 | if (!PhysicsScene.PE.IsInWorld(PhysicsScene.World, body)) |
131 | { | 142 | { |
132 | if (!BulletSimAPI.IsInWorld2(body.ptr)) | 143 | PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, body); |
133 | { | 144 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body); |
134 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr); | 145 | } |
135 | DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body); | ||
136 | } | ||
137 | }); | ||
138 | } | 146 | } |
139 | } | 147 | } |
140 | 148 | ||
141 | // Release the usage of a body. | 149 | // Release the usage of a body. |
142 | // Called when releasing use of a BSBody. BSShape is handled separately. | 150 | // Called when releasing use of a BSBody. BSShape is handled separately. |
143 | public void DereferenceBody(BulletBody body, bool inTaintTime, BodyDestructionCallback bodyCallback ) | 151 | // Called in taint time. |
152 | public void DereferenceBody(BulletBody body, BodyDestructionCallback bodyCallback ) | ||
144 | { | 153 | { |
145 | if (body.ptr == IntPtr.Zero) | 154 | if (!body.HasPhysicalBody) |
146 | return; | 155 | return; |
147 | 156 | ||
157 | PhysicsScene.AssertInTaintTime("BSShapeCollection.DereferenceBody"); | ||
158 | |||
148 | lock (m_collectionActivityLock) | 159 | lock (m_collectionActivityLock) |
149 | { | 160 | { |
150 | PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceBody", delegate() | 161 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1}", body.ID, body); |
151 | { | 162 | // If the caller needs to know the old body is going away, pass the event up. |
152 | DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1},inTaintTime={2}", | 163 | if (bodyCallback != null) bodyCallback(body); |
153 | body.ID, body, inTaintTime); | ||
154 | // If the caller needs to know the old body is going away, pass the event up. | ||
155 | if (bodyCallback != null) bodyCallback(body); | ||
156 | 164 | ||
157 | if (BulletSimAPI.IsInWorld2(body.ptr)) | 165 | if (PhysicsScene.PE.IsInWorld(PhysicsScene.World, body)) |
158 | { | 166 | { |
159 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr); | 167 | PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, body); |
160 | DetailLog("{0},BSShapeCollection.DereferenceBody,removingFromWorld. Body={1}", body.ID, body); | 168 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,removingFromWorld. Body={1}", body.ID, body); |
161 | } | 169 | } |
162 | 170 | ||
163 | // Zero any reference to the shape so it is not freed when the body is deleted. | 171 | // Zero any reference to the shape so it is not freed when the body is deleted. |
164 | BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, body.ptr, IntPtr.Zero); | 172 | PhysicsScene.PE.SetCollisionShape(PhysicsScene.World, body, null); |
165 | BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, body.ptr); | 173 | PhysicsScene.PE.DestroyObject(PhysicsScene.World, body); |
166 | }); | ||
167 | } | 174 | } |
168 | } | 175 | } |
169 | 176 | ||
@@ -184,17 +191,17 @@ public sealed class BSShapeCollection : IDisposable | |||
184 | { | 191 | { |
185 | // There is an existing instance of this mesh. | 192 | // There is an existing instance of this mesh. |
186 | meshDesc.referenceCount++; | 193 | meshDesc.referenceCount++; |
187 | DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}", | 194 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}", |
188 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); | 195 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); |
189 | } | 196 | } |
190 | else | 197 | else |
191 | { | 198 | { |
192 | // This is a new reference to a mesh | 199 | // This is a new reference to a mesh |
193 | meshDesc.ptr = shape.ptr; | 200 | meshDesc.shape = shape.Clone(); |
194 | meshDesc.shapeKey = shape.shapeKey; | 201 | meshDesc.shapeKey = shape.shapeKey; |
195 | // We keep a reference to the underlying IMesh data so a hull can be built | 202 | // We keep a reference to the underlying IMesh data so a hull can be built |
196 | meshDesc.referenceCount = 1; | 203 | meshDesc.referenceCount = 1; |
197 | DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}", | 204 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}", |
198 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); | 205 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); |
199 | ret = true; | 206 | ret = true; |
200 | } | 207 | } |
@@ -207,16 +214,16 @@ public sealed class BSShapeCollection : IDisposable | |||
207 | { | 214 | { |
208 | // There is an existing instance of this hull. | 215 | // There is an existing instance of this hull. |
209 | hullDesc.referenceCount++; | 216 | hullDesc.referenceCount++; |
210 | DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}", | 217 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}", |
211 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); | 218 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); |
212 | } | 219 | } |
213 | else | 220 | else |
214 | { | 221 | { |
215 | // This is a new reference to a hull | 222 | // This is a new reference to a hull |
216 | hullDesc.ptr = shape.ptr; | 223 | hullDesc.shape = shape.Clone(); |
217 | hullDesc.shapeKey = shape.shapeKey; | 224 | hullDesc.shapeKey = shape.shapeKey; |
218 | hullDesc.referenceCount = 1; | 225 | hullDesc.referenceCount = 1; |
219 | DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}", | 226 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}", |
220 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); | 227 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); |
221 | ret = true; | 228 | ret = true; |
222 | 229 | ||
@@ -234,44 +241,43 @@ public sealed class BSShapeCollection : IDisposable | |||
234 | } | 241 | } |
235 | 242 | ||
236 | // Release the usage of a shape. | 243 | // Release the usage of a shape. |
237 | public void DereferenceShape(BulletShape shape, bool inTaintTime, ShapeDestructionCallback shapeCallback) | 244 | public void DereferenceShape(BulletShape shape, ShapeDestructionCallback shapeCallback) |
238 | { | 245 | { |
239 | if (shape.ptr == IntPtr.Zero) | 246 | if (!shape.HasPhysicalShape) |
240 | return; | 247 | return; |
241 | 248 | ||
242 | PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceShape", delegate() | 249 | PhysicsScene.AssertInTaintTime("BSShapeCollection.DereferenceShape"); |
250 | |||
251 | if (shape.HasPhysicalShape) | ||
243 | { | 252 | { |
244 | if (shape.ptr != IntPtr.Zero) | 253 | if (shape.isNativeShape) |
245 | { | 254 | { |
246 | if (shape.isNativeShape) | 255 | // Native shapes are not tracked and are released immediately |
247 | { | 256 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1}", |
248 | // Native shapes are not tracked and are released immediately | 257 | BSScene.DetailLogZero, shape.AddrString); |
249 | DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}", | 258 | if (shapeCallback != null) shapeCallback(shape); |
250 | BSScene.DetailLogZero, shape.ptr.ToString("X"), inTaintTime); | 259 | PhysicsScene.PE.DeleteCollisionShape(PhysicsScene.World, shape); |
251 | if (shapeCallback != null) shapeCallback(shape); | 260 | } |
252 | BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr); | 261 | else |
253 | } | 262 | { |
254 | else | 263 | switch (shape.type) |
255 | { | 264 | { |
256 | switch (shape.type) | 265 | case BSPhysicsShapeType.SHAPE_HULL: |
257 | { | 266 | DereferenceHull(shape, shapeCallback); |
258 | case BSPhysicsShapeType.SHAPE_HULL: | 267 | break; |
259 | DereferenceHull(shape, shapeCallback); | 268 | case BSPhysicsShapeType.SHAPE_MESH: |
260 | break; | 269 | DereferenceMesh(shape, shapeCallback); |
261 | case BSPhysicsShapeType.SHAPE_MESH: | 270 | break; |
262 | DereferenceMesh(shape, shapeCallback); | 271 | case BSPhysicsShapeType.SHAPE_COMPOUND: |
263 | break; | 272 | DereferenceCompound(shape, shapeCallback); |
264 | case BSPhysicsShapeType.SHAPE_COMPOUND: | 273 | break; |
265 | DereferenceCompound(shape, shapeCallback); | 274 | case BSPhysicsShapeType.SHAPE_UNKNOWN: |
266 | break; | 275 | break; |
267 | case BSPhysicsShapeType.SHAPE_UNKNOWN: | 276 | default: |
268 | break; | 277 | break; |
269 | default: | ||
270 | break; | ||
271 | } | ||
272 | } | 278 | } |
273 | } | 279 | } |
274 | }); | 280 | } |
275 | } | 281 | } |
276 | 282 | ||
277 | // Count down the reference count for a mesh shape | 283 | // Count down the reference count for a mesh shape |
@@ -286,7 +292,7 @@ public sealed class BSShapeCollection : IDisposable | |||
286 | if (shapeCallback != null) shapeCallback(shape); | 292 | if (shapeCallback != null) shapeCallback(shape); |
287 | meshDesc.lastReferenced = System.DateTime.Now; | 293 | meshDesc.lastReferenced = System.DateTime.Now; |
288 | Meshes[shape.shapeKey] = meshDesc; | 294 | Meshes[shape.shapeKey] = meshDesc; |
289 | DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}", | 295 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}", |
290 | BSScene.DetailLogZero, shape, meshDesc.referenceCount); | 296 | BSScene.DetailLogZero, shape, meshDesc.referenceCount); |
291 | 297 | ||
292 | } | 298 | } |
@@ -307,7 +313,7 @@ public sealed class BSShapeCollection : IDisposable | |||
307 | 313 | ||
308 | hullDesc.lastReferenced = System.DateTime.Now; | 314 | hullDesc.lastReferenced = System.DateTime.Now; |
309 | Hulls[shape.shapeKey] = hullDesc; | 315 | Hulls[shape.shapeKey] = hullDesc; |
310 | DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}", | 316 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}", |
311 | BSScene.DetailLogZero, shape, hullDesc.referenceCount); | 317 | BSScene.DetailLogZero, shape, hullDesc.referenceCount); |
312 | } | 318 | } |
313 | } | 319 | } |
@@ -320,57 +326,56 @@ public sealed class BSShapeCollection : IDisposable | |||
320 | // Called at taint-time. | 326 | // Called at taint-time. |
321 | private void DereferenceCompound(BulletShape shape, ShapeDestructionCallback shapeCallback) | 327 | private void DereferenceCompound(BulletShape shape, ShapeDestructionCallback shapeCallback) |
322 | { | 328 | { |
323 | if (!BulletSimAPI.IsCompound2(shape.ptr)) | 329 | if (!PhysicsScene.PE.IsCompound(shape)) |
324 | { | 330 | { |
325 | // Failed the sanity check!! | 331 | // Failed the sanity check!! |
326 | PhysicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}", | 332 | PhysicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}", |
327 | LogHeader, shape.type, shape.ptr.ToString("X")); | 333 | LogHeader, shape.type, shape.AddrString); |
328 | DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}", | 334 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}", |
329 | BSScene.DetailLogZero, shape.type, shape.ptr.ToString("X")); | 335 | BSScene.DetailLogZero, shape.type, shape.AddrString); |
330 | return; | 336 | return; |
331 | } | 337 | } |
332 | 338 | ||
333 | int numChildren = BulletSimAPI.GetNumberOfCompoundChildren2(shape.ptr); | 339 | int numChildren = PhysicsScene.PE.GetNumberOfCompoundChildren(shape); |
334 | DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", BSScene.DetailLogZero, shape, numChildren); | 340 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", BSScene.DetailLogZero, shape, numChildren); |
335 | 341 | ||
336 | for (int ii = numChildren - 1; ii >= 0; ii--) | 342 | for (int ii = numChildren - 1; ii >= 0; ii--) |
337 | { | 343 | { |
338 | IntPtr childShape = BulletSimAPI.RemoveChildShapeFromCompoundShapeIndex2(shape.ptr, ii); | 344 | BulletShape childShape = PhysicsScene.PE.RemoveChildShapeFromCompoundShapeIndex(shape, ii); |
339 | DereferenceAnonCollisionShape(childShape); | 345 | DereferenceAnonCollisionShape(childShape); |
340 | } | 346 | } |
341 | BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr); | 347 | PhysicsScene.PE.DeleteCollisionShape(PhysicsScene.World, shape); |
342 | } | 348 | } |
343 | 349 | ||
344 | // Sometimes we have a pointer to a collision shape but don't know what type it is. | 350 | // Sometimes we have a pointer to a collision shape but don't know what type it is. |
345 | // Figure out type and call the correct dereference routine. | 351 | // Figure out type and call the correct dereference routine. |
346 | // Called at taint-time. | 352 | // Called at taint-time. |
347 | private void DereferenceAnonCollisionShape(IntPtr cShape) | 353 | private void DereferenceAnonCollisionShape(BulletShape shapeInfo) |
348 | { | 354 | { |
349 | MeshDesc meshDesc; | 355 | MeshDesc meshDesc; |
350 | HullDesc hullDesc; | 356 | HullDesc hullDesc; |
351 | 357 | ||
352 | BulletShape shapeInfo = new BulletShape(cShape); | 358 | if (TryGetMeshByPtr(shapeInfo, out meshDesc)) |
353 | if (TryGetMeshByPtr(cShape, out meshDesc)) | ||
354 | { | 359 | { |
355 | shapeInfo.type = BSPhysicsShapeType.SHAPE_MESH; | 360 | shapeInfo.type = BSPhysicsShapeType.SHAPE_MESH; |
356 | shapeInfo.shapeKey = meshDesc.shapeKey; | 361 | shapeInfo.shapeKey = meshDesc.shapeKey; |
357 | } | 362 | } |
358 | else | 363 | else |
359 | { | 364 | { |
360 | if (TryGetHullByPtr(cShape, out hullDesc)) | 365 | if (TryGetHullByPtr(shapeInfo, out hullDesc)) |
361 | { | 366 | { |
362 | shapeInfo.type = BSPhysicsShapeType.SHAPE_HULL; | 367 | shapeInfo.type = BSPhysicsShapeType.SHAPE_HULL; |
363 | shapeInfo.shapeKey = hullDesc.shapeKey; | 368 | shapeInfo.shapeKey = hullDesc.shapeKey; |
364 | } | 369 | } |
365 | else | 370 | else |
366 | { | 371 | { |
367 | if (BulletSimAPI.IsCompound2(cShape)) | 372 | if (PhysicsScene.PE.IsCompound(shapeInfo)) |
368 | { | 373 | { |
369 | shapeInfo.type = BSPhysicsShapeType.SHAPE_COMPOUND; | 374 | shapeInfo.type = BSPhysicsShapeType.SHAPE_COMPOUND; |
370 | } | 375 | } |
371 | else | 376 | else |
372 | { | 377 | { |
373 | if (BulletSimAPI.IsNativeShape2(cShape)) | 378 | if (PhysicsScene.PE.IsNativeShape(shapeInfo)) |
374 | { | 379 | { |
375 | shapeInfo.isNativeShape = true; | 380 | shapeInfo.isNativeShape = true; |
376 | shapeInfo.type = BSPhysicsShapeType.SHAPE_BOX; // (technically, type doesn't matter) | 381 | shapeInfo.type = BSPhysicsShapeType.SHAPE_BOX; // (technically, type doesn't matter) |
@@ -379,16 +384,16 @@ public sealed class BSShapeCollection : IDisposable | |||
379 | } | 384 | } |
380 | } | 385 | } |
381 | 386 | ||
382 | DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo); | 387 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo); |
383 | 388 | ||
384 | if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN) | 389 | if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN) |
385 | { | 390 | { |
386 | DereferenceShape(shapeInfo, true, null); | 391 | DereferenceShape(shapeInfo, null); |
387 | } | 392 | } |
388 | else | 393 | else |
389 | { | 394 | { |
390 | PhysicsScene.Logger.ErrorFormat("{0} Could not decypher shape type. Region={1}, addr={2}", | 395 | PhysicsScene.Logger.ErrorFormat("{0} Could not decypher shape type. Region={1}, addr={2}", |
391 | LogHeader, PhysicsScene.RegionName, cShape.ToString("X")); | 396 | LogHeader, PhysicsScene.RegionName, shapeInfo.AddrString); |
392 | } | 397 | } |
393 | } | 398 | } |
394 | 399 | ||
@@ -408,19 +413,18 @@ public sealed class BSShapeCollection : IDisposable | |||
408 | if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE) | 413 | if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE) |
409 | { | 414 | { |
410 | // an avatar capsule is close to a native shape (it is not shared) | 415 | // an avatar capsule is close to a native shape (it is not shared) |
411 | ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE, | 416 | GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE, FixedShapeKey.KEY_CAPSULE, shapeCallback); |
412 | FixedShapeKey.KEY_CAPSULE, shapeCallback); | 417 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape); |
413 | DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape); | ||
414 | ret = true; | 418 | ret = true; |
415 | haveShape = true; | 419 | haveShape = true; |
416 | } | 420 | } |
417 | 421 | ||
418 | // Compound shapes are handled special as they are rebuilt from scratch. | 422 | // Compound shapes are handled special as they are rebuilt from scratch. |
419 | // This isn't too great a hardship since most of the child shapes will already been created. | 423 | // This isn't too great a hardship since most of the child shapes will have already been created. |
420 | if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND) | 424 | if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND) |
421 | { | 425 | { |
422 | ret = GetReferenceToCompoundShape(prim, shapeCallback); | 426 | ret = GetReferenceToCompoundShape(prim, shapeCallback); |
423 | DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape); | 427 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape); |
424 | haveShape = true; | 428 | haveShape = true; |
425 | } | 429 | } |
426 | 430 | ||
@@ -432,8 +436,9 @@ public sealed class BSShapeCollection : IDisposable | |||
432 | return ret; | 436 | return ret; |
433 | } | 437 | } |
434 | 438 | ||
435 | // Create a mesh/hull shape or a native shape if 'nativeShapePossible' is 'true'. | 439 | // Create a mesh, hull or native shape. |
436 | private bool CreateGeomNonSpecial(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback) | 440 | // Return 'true' if the prim's shape was changed. |
441 | public bool CreateGeomNonSpecial(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback) | ||
437 | { | 442 | { |
438 | bool ret = false; | 443 | bool ret = false; |
439 | bool haveShape = false; | 444 | bool haveShape = false; |
@@ -442,46 +447,48 @@ public sealed class BSShapeCollection : IDisposable | |||
442 | 447 | ||
443 | // If the prim attributes are simple, this could be a simple Bullet native shape | 448 | // If the prim attributes are simple, this could be a simple Bullet native shape |
444 | if (!haveShape | 449 | if (!haveShape |
445 | && pbs != null | ||
446 | && nativeShapePossible | 450 | && nativeShapePossible |
447 | && ((pbs.SculptEntry && !PhysicsScene.ShouldMeshSculptedPrim) | 451 | && pbs != null |
448 | || (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 | 452 | && !pbs.SculptEntry |
449 | && pbs.ProfileHollow == 0 | 453 | && ((pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim) || PrimHasNoCuts(pbs)) ) |
450 | && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0 | 454 | { |
451 | && pbs.PathBegin == 0 && pbs.PathEnd == 0 | 455 | // Get the scale of any existing shape so we can see if the new shape is same native type and same size. |
452 | && pbs.PathTaperX == 0 && pbs.PathTaperY == 0 | 456 | OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero; |
453 | && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 | 457 | if (prim.PhysShape.HasPhysicalShape) |
454 | && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) ) | 458 | scaleOfExistingShape = PhysicsScene.PE.GetLocalScaling(prim.PhysShape); |
455 | { | 459 | |
456 | // It doesn't look like Bullet scales spheres so make sure the scales are all equal | 460 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,maybeNative,force={1},primScale={2},primSize={3},primShape={4}", |
461 | prim.LocalID, forceRebuild, prim.Scale, prim.Size, prim.PhysShape.type); | ||
462 | |||
463 | // It doesn't look like Bullet scales native spheres so make sure the scales are all equal | ||
457 | if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) | 464 | if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) |
458 | && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z) | 465 | && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z) |
459 | { | 466 | { |
460 | haveShape = true; | 467 | haveShape = true; |
461 | if (forceRebuild | 468 | if (forceRebuild |
462 | || prim.Scale != prim.Size | 469 | || prim.Scale != scaleOfExistingShape |
463 | || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_SPHERE | 470 | || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_SPHERE |
464 | ) | 471 | ) |
465 | { | 472 | { |
466 | ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE, | 473 | ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE, |
467 | FixedShapeKey.KEY_SPHERE, shapeCallback); | 474 | FixedShapeKey.KEY_SPHERE, shapeCallback); |
468 | DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}", | ||
469 | prim.LocalID, forceRebuild, prim.PhysShape); | ||
470 | } | 475 | } |
476 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},rebuilt={2},shape={3}", | ||
477 | prim.LocalID, forceRebuild, ret, prim.PhysShape); | ||
471 | } | 478 | } |
472 | if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) | 479 | if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) |
473 | { | 480 | { |
474 | haveShape = true; | 481 | haveShape = true; |
475 | if (forceRebuild | 482 | if (forceRebuild |
476 | || prim.Scale != prim.Size | 483 | || prim.Scale != scaleOfExistingShape |
477 | || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_BOX | 484 | || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_BOX |
478 | ) | 485 | ) |
479 | { | 486 | { |
480 | ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX, | 487 | ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX, |
481 | FixedShapeKey.KEY_BOX, shapeCallback); | 488 | FixedShapeKey.KEY_BOX, shapeCallback); |
482 | DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}", | ||
483 | prim.LocalID, forceRebuild, prim.PhysShape); | ||
484 | } | 489 | } |
490 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},rebuilt={2},shape={3}", | ||
491 | prim.LocalID, forceRebuild, ret, prim.PhysShape); | ||
485 | } | 492 | } |
486 | } | 493 | } |
487 | 494 | ||
@@ -494,23 +501,36 @@ public sealed class BSShapeCollection : IDisposable | |||
494 | return ret; | 501 | return ret; |
495 | } | 502 | } |
496 | 503 | ||
504 | // return 'true' if this shape description does not include any cutting or twisting. | ||
505 | private bool PrimHasNoCuts(PrimitiveBaseShape pbs) | ||
506 | { | ||
507 | return pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 | ||
508 | && pbs.ProfileHollow == 0 | ||
509 | && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0 | ||
510 | && pbs.PathBegin == 0 && pbs.PathEnd == 0 | ||
511 | && pbs.PathTaperX == 0 && pbs.PathTaperY == 0 | ||
512 | && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 | ||
513 | && pbs.PathShearX == 0 && pbs.PathShearY == 0; | ||
514 | } | ||
515 | |||
516 | // return 'true' if the prim's shape was changed. | ||
497 | public bool CreateGeomMeshOrHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback) | 517 | public bool CreateGeomMeshOrHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback) |
498 | { | 518 | { |
499 | 519 | ||
500 | bool ret = false; | 520 | bool ret = false; |
501 | // Note that if it's a native shape, the check for physical/non-physical is not | 521 | // Note that if it's a native shape, the check for physical/non-physical is not |
502 | // made. Native shapes work in either case. | 522 | // made. Native shapes work in either case. |
503 | if (prim.IsPhysical && PhysicsScene.ShouldUseHullsForPhysicalObjects) | 523 | if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects) |
504 | { | 524 | { |
505 | // Update prim.BSShape to reference a hull of this shape. | 525 | // Update prim.BSShape to reference a hull of this shape. |
506 | ret = GetReferenceToHull(prim,shapeCallback); | 526 | ret = GetReferenceToHull(prim, shapeCallback); |
507 | DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}", | 527 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}", |
508 | prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); | 528 | prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); |
509 | } | 529 | } |
510 | else | 530 | else |
511 | { | 531 | { |
512 | ret = GetReferenceToMesh(prim, shapeCallback); | 532 | ret = GetReferenceToMesh(prim, shapeCallback); |
513 | DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}", | 533 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}", |
514 | prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); | 534 | prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); |
515 | } | 535 | } |
516 | return ret; | 536 | return ret; |
@@ -523,14 +543,15 @@ public sealed class BSShapeCollection : IDisposable | |||
523 | ShapeDestructionCallback shapeCallback) | 543 | ShapeDestructionCallback shapeCallback) |
524 | { | 544 | { |
525 | // release any previous shape | 545 | // release any previous shape |
526 | DereferenceShape(prim.PhysShape, true, shapeCallback); | 546 | DereferenceShape(prim.PhysShape, shapeCallback); |
527 | 547 | ||
528 | BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey); | 548 | BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey); |
529 | 549 | ||
530 | // Don't need to do a 'ReferenceShape()' here because native shapes are not shared. | 550 | // Don't need to do a 'ReferenceShape()' here because native shapes are not shared. |
531 | DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}", | 551 | if (DDetail) DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}", |
532 | prim.LocalID, newShape, prim.Scale); | 552 | prim.LocalID, newShape, prim.Scale); |
533 | 553 | ||
554 | // native shapes are scaled by Bullet | ||
534 | prim.PhysShape = newShape; | 555 | prim.PhysShape = newShape; |
535 | return true; | 556 | return true; |
536 | } | 557 | } |
@@ -550,20 +571,17 @@ public sealed class BSShapeCollection : IDisposable | |||
550 | 571 | ||
551 | if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE) | 572 | if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE) |
552 | { | 573 | { |
553 | // The proper scale has been calculated in the prim. | 574 | |
554 | newShape = new BulletShape( | 575 | newShape = PhysicsScene.PE.BuildCapsuleShape(PhysicsScene.World, 1f, 1f, prim.Scale); |
555 | BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1f, 1f, prim.Scale) | 576 | if (DDetail) DetailLog("{0},BSShapeCollection.BuildPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale); |
556 | , shapeType); | ||
557 | DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale); | ||
558 | } | 577 | } |
559 | else | 578 | else |
560 | { | 579 | { |
561 | // Native shapes are scaled in Bullet so set the scaling to the size | 580 | // Native shapes are scaled in Bullet so set the scaling to the size |
562 | prim.Scale = prim.Size; | 581 | newShape = PhysicsScene.PE.BuildNativeShape(PhysicsScene.World, nativeShapeData); |
563 | nativeShapeData.Scale = prim.Scale; | 582 | |
564 | newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, nativeShapeData), shapeType); | ||
565 | } | 583 | } |
566 | if (newShape.ptr == IntPtr.Zero) | 584 | if (!newShape.HasPhysicalShape) |
567 | { | 585 | { |
568 | PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", | 586 | PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", |
569 | LogHeader, prim.LocalID, shapeType); | 587 | LogHeader, prim.LocalID, shapeType); |
@@ -580,7 +598,7 @@ public sealed class BSShapeCollection : IDisposable | |||
580 | // Called at taint-time! | 598 | // Called at taint-time! |
581 | private bool GetReferenceToMesh(BSPhysObject prim, ShapeDestructionCallback shapeCallback) | 599 | private bool GetReferenceToMesh(BSPhysObject prim, ShapeDestructionCallback shapeCallback) |
582 | { | 600 | { |
583 | BulletShape newShape = new BulletShape(IntPtr.Zero); | 601 | BulletShape newShape = new BulletShape(); |
584 | 602 | ||
585 | float lod; | 603 | float lod; |
586 | System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod); | 604 | System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod); |
@@ -589,62 +607,96 @@ public sealed class BSShapeCollection : IDisposable | |||
589 | if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH) | 607 | if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH) |
590 | return false; | 608 | return false; |
591 | 609 | ||
592 | DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2}", | 610 | if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2},size={3},lod={4}", |
593 | prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X")); | 611 | prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X"), prim.Size, lod); |
594 | 612 | ||
595 | // Since we're recreating new, get rid of the reference to the previous shape | 613 | // Since we're recreating new, get rid of the reference to the previous shape |
596 | DereferenceShape(prim.PhysShape, true, shapeCallback); | 614 | DereferenceShape(prim.PhysShape, shapeCallback); |
597 | 615 | ||
598 | newShape = CreatePhysicalMesh(prim.PhysObjectName, newMeshKey, prim.BaseShape, prim.Size, lod); | 616 | newShape = CreatePhysicalMesh(prim, newMeshKey, prim.BaseShape, prim.Size, lod); |
599 | // Take evasive action if the mesh was not constructed. | 617 | // Take evasive action if the mesh was not constructed. |
600 | newShape = VerifyMeshCreated(newShape, prim); | 618 | newShape = VerifyMeshCreated(newShape, prim); |
601 | 619 | ||
602 | ReferenceShape(newShape); | 620 | ReferenceShape(newShape); |
603 | 621 | ||
604 | // meshes are already scaled by the meshmerizer | ||
605 | prim.Scale = new OMV.Vector3(1f, 1f, 1f); | ||
606 | prim.PhysShape = newShape; | 622 | prim.PhysShape = newShape; |
607 | 623 | ||
608 | return true; // 'true' means a new shape has been added to this prim | 624 | return true; // 'true' means a new shape has been added to this prim |
609 | } | 625 | } |
610 | 626 | ||
611 | private BulletShape CreatePhysicalMesh(string objName, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) | 627 | private BulletShape CreatePhysicalMesh(BSPhysObject prim, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) |
612 | { | 628 | { |
613 | IMesh meshData = null; | 629 | BulletShape newShape = new BulletShape(); |
614 | IntPtr meshPtr = IntPtr.Zero; | 630 | |
615 | MeshDesc meshDesc; | 631 | MeshDesc meshDesc; |
616 | if (Meshes.TryGetValue(newMeshKey, out meshDesc)) | 632 | if (Meshes.TryGetValue(newMeshKey, out meshDesc)) |
617 | { | 633 | { |
618 | // If the mesh has already been built just use it. | 634 | // If the mesh has already been built just use it. |
619 | meshPtr = meshDesc.ptr; | 635 | newShape = meshDesc.shape.Clone(); |
620 | } | 636 | } |
621 | else | 637 | else |
622 | { | 638 | { |
623 | // Pass false for physicalness as this creates some sort of bounding box which we don't need | 639 | IMesh meshData = PhysicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, |
624 | meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false); | 640 | true, |
641 | false, // say it is not physical so a bounding box is not built | ||
642 | false, // do not cache the mesh and do not use previously built versions | ||
643 | false // It's NOT for ODE | ||
644 | ); | ||
625 | 645 | ||
626 | if (meshData != null) | 646 | if (meshData != null) |
627 | { | 647 | { |
648 | |||
628 | int[] indices = meshData.getIndexListAsInt(); | 649 | int[] indices = meshData.getIndexListAsInt(); |
629 | List<OMV.Vector3> vertices = meshData.getVertexList(); | 650 | int realIndicesIndex = indices.Length; |
651 | float[] verticesAsFloats = meshData.getVertexListAsFloat(); | ||
630 | 652 | ||
631 | float[] verticesAsFloats = new float[vertices.Count * 3]; | 653 | if (BSParam.ShouldRemoveZeroWidthTriangles) |
632 | int vi = 0; | ||
633 | foreach (OMV.Vector3 vv in vertices) | ||
634 | { | 654 | { |
635 | verticesAsFloats[vi++] = vv.X; | 655 | // Remove degenerate triangles. These are triangles with two of the vertices |
636 | verticesAsFloats[vi++] = vv.Y; | 656 | // are the same. This is complicated by the problem that vertices are not |
637 | verticesAsFloats[vi++] = vv.Z; | 657 | // made unique in sculpties so we have to compare the values in the vertex. |
658 | realIndicesIndex = 0; | ||
659 | for (int tri = 0; tri < indices.Length; tri += 3) | ||
660 | { | ||
661 | // Compute displacements into vertex array for each vertex of the triangle | ||
662 | int v1 = indices[tri + 0] * 3; | ||
663 | int v2 = indices[tri + 1] * 3; | ||
664 | int v3 = indices[tri + 2] * 3; | ||
665 | // Check to see if any two of the vertices are the same | ||
666 | if (!( ( verticesAsFloats[v1 + 0] == verticesAsFloats[v2 + 0] | ||
667 | && verticesAsFloats[v1 + 1] == verticesAsFloats[v2 + 1] | ||
668 | && verticesAsFloats[v1 + 2] == verticesAsFloats[v2 + 2]) | ||
669 | || ( verticesAsFloats[v2 + 0] == verticesAsFloats[v3 + 0] | ||
670 | && verticesAsFloats[v2 + 1] == verticesAsFloats[v3 + 1] | ||
671 | && verticesAsFloats[v2 + 2] == verticesAsFloats[v3 + 2]) | ||
672 | || ( verticesAsFloats[v1 + 0] == verticesAsFloats[v3 + 0] | ||
673 | && verticesAsFloats[v1 + 1] == verticesAsFloats[v3 + 1] | ||
674 | && verticesAsFloats[v1 + 2] == verticesAsFloats[v3 + 2]) ) | ||
675 | ) | ||
676 | { | ||
677 | // None of the vertices of the triangles are the same. This is a good triangle; | ||
678 | indices[realIndicesIndex + 0] = indices[tri + 0]; | ||
679 | indices[realIndicesIndex + 1] = indices[tri + 1]; | ||
680 | indices[realIndicesIndex + 2] = indices[tri + 2]; | ||
681 | realIndicesIndex += 3; | ||
682 | } | ||
683 | } | ||
638 | } | 684 | } |
685 | DetailLog("{0},BSShapeCollection.CreatePhysicalMesh,origTri={1},realTri={2},numVerts={3}", | ||
686 | BSScene.DetailLogZero, indices.Length / 3, realIndicesIndex / 3, verticesAsFloats.Length / 3); | ||
639 | 687 | ||
640 | // m_log.DebugFormat("{0}: BSShapeCollection.CreatePhysicalMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}", | 688 | if (realIndicesIndex != 0) |
641 | // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count); | 689 | { |
642 | 690 | newShape = PhysicsScene.PE.CreateMeshShape(PhysicsScene.World, | |
643 | meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr, | 691 | realIndicesIndex, indices, verticesAsFloats.Length / 3, verticesAsFloats); |
644 | indices.GetLength(0), indices, vertices.Count, verticesAsFloats); | 692 | } |
693 | else | ||
694 | { | ||
695 | PhysicsScene.Logger.DebugFormat("{0} All mesh triangles degenerate. Prim {1} at {2} in {3}", | ||
696 | LogHeader, prim.PhysObjectName, prim.RawPosition, PhysicsScene.Name); | ||
697 | } | ||
645 | } | 698 | } |
646 | } | 699 | } |
647 | BulletShape newShape = new BulletShape(meshPtr, BSPhysicsShapeType.SHAPE_MESH); | ||
648 | newShape.shapeKey = newMeshKey; | 700 | newShape.shapeKey = newMeshKey; |
649 | 701 | ||
650 | return newShape; | 702 | return newShape; |
@@ -652,6 +704,7 @@ public sealed class BSShapeCollection : IDisposable | |||
652 | 704 | ||
653 | // See that hull shape exists in the physical world and update prim.BSShape. | 705 | // See that hull shape exists in the physical world and update prim.BSShape. |
654 | // We could be creating the hull because scale changed or whatever. | 706 | // We could be creating the hull because scale changed or whatever. |
707 | // Return 'true' if a new hull was built. Otherwise, returning a shared hull instance. | ||
655 | private bool GetReferenceToHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback) | 708 | private bool GetReferenceToHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback) |
656 | { | 709 | { |
657 | BulletShape newShape; | 710 | BulletShape newShape; |
@@ -663,19 +716,18 @@ public sealed class BSShapeCollection : IDisposable | |||
663 | if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL) | 716 | if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL) |
664 | return false; | 717 | return false; |
665 | 718 | ||
666 | DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}", | 719 | if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}", |
667 | prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X")); | 720 | prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X")); |
668 | 721 | ||
669 | // Remove usage of the previous shape. | 722 | // Remove usage of the previous shape. |
670 | DereferenceShape(prim.PhysShape, true, shapeCallback); | 723 | DereferenceShape(prim.PhysShape, shapeCallback); |
671 | 724 | ||
672 | newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, prim.BaseShape, prim.Size, lod); | 725 | newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, prim.BaseShape, prim.Size, lod); |
726 | // It might not have been created if we're waiting for an asset. | ||
673 | newShape = VerifyMeshCreated(newShape, prim); | 727 | newShape = VerifyMeshCreated(newShape, prim); |
674 | 728 | ||
675 | ReferenceShape(newShape); | 729 | ReferenceShape(newShape); |
676 | 730 | ||
677 | // hulls are already scaled by the meshmerizer | ||
678 | prim.Scale = new OMV.Vector3(1f, 1f, 1f); | ||
679 | prim.PhysShape = newShape; | 731 | prim.PhysShape = newShape; |
680 | return true; // 'true' means a new shape has been added to this prim | 732 | return true; // 'true' means a new shape has been added to this prim |
681 | } | 733 | } |
@@ -684,18 +736,20 @@ public sealed class BSShapeCollection : IDisposable | |||
684 | private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) | 736 | private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) |
685 | { | 737 | { |
686 | 738 | ||
739 | BulletShape newShape = new BulletShape(); | ||
687 | IntPtr hullPtr = IntPtr.Zero; | 740 | IntPtr hullPtr = IntPtr.Zero; |
741 | |||
688 | HullDesc hullDesc; | 742 | HullDesc hullDesc; |
689 | if (Hulls.TryGetValue(newHullKey, out hullDesc)) | 743 | if (Hulls.TryGetValue(newHullKey, out hullDesc)) |
690 | { | 744 | { |
691 | // If the hull shape already is created, just use it. | 745 | // If the hull shape already has been created, just use the one shared instance. |
692 | hullPtr = hullDesc.ptr; | 746 | newShape = hullDesc.shape.Clone(); |
693 | } | 747 | } |
694 | else | 748 | else |
695 | { | 749 | { |
696 | // Build a new hull in the physical world | 750 | // Build a new hull in the physical world. |
697 | // Pass false for physicalness as this creates some sort of bounding box which we don't need | 751 | // Pass true for physicalness as this prevents the creation of bounding box which is not needed |
698 | IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false); | 752 | IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false, false, false); |
699 | if (meshData != null) | 753 | if (meshData != null) |
700 | { | 754 | { |
701 | 755 | ||
@@ -714,15 +768,35 @@ public sealed class BSShapeCollection : IDisposable | |||
714 | convVertices.Add(new float3(vv.X, vv.Y, vv.Z)); | 768 | convVertices.Add(new float3(vv.X, vv.Y, vv.Z)); |
715 | } | 769 | } |
716 | 770 | ||
771 | uint maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplit; | ||
772 | if (BSParam.CSHullMaxDepthSplit != BSParam.CSHullMaxDepthSplitForSimpleShapes) | ||
773 | { | ||
774 | // Simple primitive shapes we know are convex so they are better implemented with | ||
775 | // fewer hulls. | ||
776 | // Check for simple shape (prim without cuts) and reduce split parameter if so. | ||
777 | if (PrimHasNoCuts(pbs)) | ||
778 | { | ||
779 | maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplitForSimpleShapes; | ||
780 | } | ||
781 | } | ||
782 | |||
717 | // setup and do convex hull conversion | 783 | // setup and do convex hull conversion |
718 | m_hulls = new List<ConvexResult>(); | 784 | m_hulls = new List<ConvexResult>(); |
719 | DecompDesc dcomp = new DecompDesc(); | 785 | DecompDesc dcomp = new DecompDesc(); |
720 | dcomp.mIndices = convIndices; | 786 | dcomp.mIndices = convIndices; |
721 | dcomp.mVertices = convVertices; | 787 | dcomp.mVertices = convVertices; |
788 | dcomp.mDepth = maxDepthSplit; | ||
789 | dcomp.mCpercent = BSParam.CSHullConcavityThresholdPercent; | ||
790 | dcomp.mPpercent = BSParam.CSHullVolumeConservationThresholdPercent; | ||
791 | dcomp.mMaxVertices = (uint)BSParam.CSHullMaxVertices; | ||
792 | dcomp.mSkinWidth = BSParam.CSHullMaxSkinWidth; | ||
722 | ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn); | 793 | ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn); |
723 | // create the hull into the _hulls variable | 794 | // create the hull into the _hulls variable |
724 | convexBuilder.process(dcomp); | 795 | convexBuilder.process(dcomp); |
725 | 796 | ||
797 | DetailLog("{0},BSShapeCollection.CreatePhysicalHull,key={1},inVert={2},inInd={3},split={4},hulls={5}", | ||
798 | BSScene.DetailLogZero, newHullKey, indices.GetLength(0), vertices.Count, maxDepthSplit, m_hulls.Count); | ||
799 | |||
726 | // Convert the vertices and indices for passing to unmanaged. | 800 | // Convert the vertices and indices for passing to unmanaged. |
727 | // The hull information is passed as a large floating point array. | 801 | // The hull information is passed as a large floating point array. |
728 | // The format is: | 802 | // The format is: |
@@ -777,14 +851,13 @@ public sealed class BSShapeCollection : IDisposable | |||
777 | } | 851 | } |
778 | } | 852 | } |
779 | // create the hull data structure in Bullet | 853 | // create the hull data structure in Bullet |
780 | hullPtr = BulletSimAPI.CreateHullShape2(PhysicsScene.World.ptr, hullCount, convHulls); | 854 | newShape = PhysicsScene.PE.CreateHullShape(PhysicsScene.World, hullCount, convHulls); |
781 | } | 855 | } |
782 | } | 856 | } |
783 | 857 | ||
784 | BulletShape newShape = new BulletShape(hullPtr, BSPhysicsShapeType.SHAPE_HULL); | ||
785 | newShape.shapeKey = newHullKey; | 858 | newShape.shapeKey = newHullKey; |
786 | 859 | ||
787 | return newShape; // 'true' means a new shape has been added to this prim | 860 | return newShape; |
788 | } | 861 | } |
789 | 862 | ||
790 | // Callback from convex hull creater with a newly created hull. | 863 | // Callback from convex hull creater with a newly created hull. |
@@ -803,13 +876,12 @@ public sealed class BSShapeCollection : IDisposable | |||
803 | // Don't need to do this as the shape is freed when the new root shape is created below. | 876 | // Don't need to do this as the shape is freed when the new root shape is created below. |
804 | // DereferenceShape(prim.PhysShape, true, shapeCallback); | 877 | // DereferenceShape(prim.PhysShape, true, shapeCallback); |
805 | 878 | ||
806 | BulletShape cShape = new BulletShape( | 879 | BulletShape cShape = PhysicsScene.PE.CreateCompoundShape(PhysicsScene.World, false); |
807 | BulletSimAPI.CreateCompoundShape2(PhysicsScene.World.ptr, false), BSPhysicsShapeType.SHAPE_COMPOUND); | ||
808 | 880 | ||
809 | // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape. | 881 | // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape. |
810 | CreateGeomMeshOrHull(prim, shapeCallback); | 882 | CreateGeomMeshOrHull(prim, shapeCallback); |
811 | BulletSimAPI.AddChildShapeToCompoundShape2(cShape.ptr, prim.PhysShape.ptr, OMV.Vector3.Zero, OMV.Quaternion.Identity); | 883 | PhysicsScene.PE.AddChildShapeToCompoundShape(cShape, prim.PhysShape, OMV.Vector3.Zero, OMV.Quaternion.Identity); |
812 | DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}", | 884 | if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}", |
813 | prim.LocalID, cShape, prim.PhysShape); | 885 | prim.LocalID, cShape, prim.PhysShape); |
814 | 886 | ||
815 | prim.PhysShape = cShape; | 887 | prim.PhysShape = cShape; |
@@ -822,14 +894,19 @@ public sealed class BSShapeCollection : IDisposable | |||
822 | private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod) | 894 | private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod) |
823 | { | 895 | { |
824 | // level of detail based on size and type of the object | 896 | // level of detail based on size and type of the object |
825 | float lod = PhysicsScene.MeshLOD; | 897 | float lod = BSParam.MeshLOD; |
898 | |||
899 | // prims with curvy internal cuts need higher lod | ||
900 | if (pbs.HollowShape == HollowShape.Circle) | ||
901 | lod = BSParam.MeshCircularLOD; | ||
902 | |||
826 | if (pbs.SculptEntry) | 903 | if (pbs.SculptEntry) |
827 | lod = PhysicsScene.SculptLOD; | 904 | lod = BSParam.SculptLOD; |
828 | 905 | ||
829 | // Mega prims usually get more detail because one can interact with shape approximations at this size. | 906 | // Mega prims usually get more detail because one can interact with shape approximations at this size. |
830 | float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z)); | 907 | float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z)); |
831 | if (maxAxis > PhysicsScene.MeshMegaPrimThreshold) | 908 | if (maxAxis > BSParam.MeshMegaPrimThreshold) |
832 | lod = PhysicsScene.MeshMegaPrimLOD; | 909 | lod = BSParam.MeshMegaPrimLOD; |
833 | 910 | ||
834 | retLod = lod; | 911 | retLod = lod; |
835 | return pbs.GetMeshKey(size, lod); | 912 | return pbs.GetMeshKey(size, lod); |
@@ -851,51 +928,88 @@ public sealed class BSShapeCollection : IDisposable | |||
851 | private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim) | 928 | private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim) |
852 | { | 929 | { |
853 | // If the shape was successfully created, nothing more to do | 930 | // If the shape was successfully created, nothing more to do |
854 | if (newShape.ptr != IntPtr.Zero) | 931 | if (newShape.HasPhysicalShape) |
855 | return newShape; | 932 | return newShape; |
856 | 933 | ||
857 | // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset | 934 | // VerifyMeshCreated is called after trying to create the mesh. If we think the asset had been |
858 | if (prim.BaseShape.SculptEntry && !prim.LastAssetBuildFailed && prim.BaseShape.SculptTexture != OMV.UUID.Zero) | 935 | // fetched but we end up here again, the meshing of the asset must have failed. |
936 | // Prevent trying to keep fetching the mesh by declaring failure. | ||
937 | if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched) | ||
859 | { | 938 | { |
860 | prim.LastAssetBuildFailed = true; | 939 | prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed; |
861 | BSPhysObject xprim = prim; | 940 | PhysicsScene.Logger.WarnFormat("{0} Fetched asset would not mesh. {1}, texture={2}", |
862 | DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset,lID={1},lastFailed={2}", | 941 | LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture); |
863 | LogHeader, prim.LocalID, prim.LastAssetBuildFailed); | ||
864 | Util.FireAndForget(delegate | ||
865 | { | ||
866 | RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod; | ||
867 | if (assetProvider != null) | ||
868 | { | ||
869 | BSPhysObject yprim = xprim; // probably not necessary, but, just in case. | ||
870 | assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset) | ||
871 | { | ||
872 | if (!yprim.BaseShape.SculptEntry) | ||
873 | return; | ||
874 | if (yprim.BaseShape.SculptTexture.ToString() != asset.ID) | ||
875 | return; | ||
876 | |||
877 | yprim.BaseShape.SculptData = asset.Data; | ||
878 | // This will cause the prim to see that the filler shape is not the right | ||
879 | // one and try again to build the object. | ||
880 | // No race condition with the normal shape setting since the rebuild is at taint time. | ||
881 | yprim.ForceBodyShapeRebuild(false); | ||
882 | |||
883 | }); | ||
884 | } | ||
885 | }); | ||
886 | } | 942 | } |
887 | else | 943 | else |
888 | { | 944 | { |
889 | if (prim.LastAssetBuildFailed) | 945 | // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset |
946 | if (prim.BaseShape.SculptEntry | ||
947 | && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Failed | ||
948 | && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Waiting | ||
949 | && prim.BaseShape.SculptTexture != OMV.UUID.Zero | ||
950 | ) | ||
890 | { | 951 | { |
891 | PhysicsScene.Logger.ErrorFormat("{0} Mesh failed to fetch asset. lID={1}, texture={2}", | 952 | DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset", prim.LocalID); |
892 | LogHeader, prim.LocalID, prim.BaseShape.SculptTexture); | 953 | // Multiple requestors will know we're waiting for this asset |
954 | prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Waiting; | ||
955 | |||
956 | BSPhysObject xprim = prim; | ||
957 | Util.FireAndForget(delegate | ||
958 | { | ||
959 | RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod; | ||
960 | if (assetProvider != null) | ||
961 | { | ||
962 | BSPhysObject yprim = xprim; // probably not necessary, but, just in case. | ||
963 | assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset) | ||
964 | { | ||
965 | bool assetFound = false; | ||
966 | string mismatchIDs = String.Empty; // DEBUG DEBUG | ||
967 | if (asset != null && yprim.BaseShape.SculptEntry) | ||
968 | { | ||
969 | if (yprim.BaseShape.SculptTexture.ToString() == asset.ID) | ||
970 | { | ||
971 | yprim.BaseShape.SculptData = asset.Data; | ||
972 | // This will cause the prim to see that the filler shape is not the right | ||
973 | // one and try again to build the object. | ||
974 | // No race condition with the normal shape setting since the rebuild is at taint time. | ||
975 | yprim.ForceBodyShapeRebuild(false /* inTaintTime */); | ||
976 | assetFound = true; | ||
977 | } | ||
978 | else | ||
979 | { | ||
980 | mismatchIDs = yprim.BaseShape.SculptTexture.ToString() + "/" + asset.ID; | ||
981 | } | ||
982 | } | ||
983 | if (assetFound) | ||
984 | yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Fetched; | ||
985 | else | ||
986 | yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed; | ||
987 | DetailLog("{0},BSShapeCollection,fetchAssetCallback,found={1},isSculpt={2},ids={3}", | ||
988 | yprim.LocalID, assetFound, yprim.BaseShape.SculptEntry, mismatchIDs ); | ||
989 | |||
990 | }); | ||
991 | } | ||
992 | else | ||
993 | { | ||
994 | xprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed; | ||
995 | PhysicsScene.Logger.ErrorFormat("{0} Physical object requires asset but no asset provider. Name={1}", | ||
996 | LogHeader, PhysicsScene.Name); | ||
997 | } | ||
998 | }); | ||
999 | } | ||
1000 | else | ||
1001 | { | ||
1002 | if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Failed) | ||
1003 | { | ||
1004 | PhysicsScene.Logger.WarnFormat("{0} Mesh failed to fetch asset. obj={1}, texture={2}", | ||
1005 | LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture); | ||
1006 | } | ||
893 | } | 1007 | } |
894 | } | 1008 | } |
895 | 1009 | ||
896 | // While we figure out the real problem, stick a simple native shape on the object. | 1010 | // While we wait for the mesh defining asset to be loaded, stick in a simple box for the object. |
897 | BulletShape fillinShape = | 1011 | BulletShape fillinShape = BuildPhysicalNativeShape(prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); |
898 | BuildPhysicalNativeShape(prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); | 1012 | DetailLog("{0},BSShapeCollection.VerifyMeshCreated,boxTempShape", prim.LocalID); |
899 | 1013 | ||
900 | return fillinShape; | 1014 | return fillinShape; |
901 | } | 1015 | } |
@@ -904,49 +1018,45 @@ public sealed class BSShapeCollection : IDisposable | |||
904 | // Updates prim.BSBody with the information about the new body if one is created. | 1018 | // Updates prim.BSBody with the information about the new body if one is created. |
905 | // Returns 'true' if an object was actually created. | 1019 | // Returns 'true' if an object was actually created. |
906 | // Called at taint-time. | 1020 | // Called at taint-time. |
907 | private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletSim sim, BulletShape shape, | 1021 | private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletWorld sim, BodyDestructionCallback bodyCallback) |
908 | BodyDestructionCallback bodyCallback) | ||
909 | { | 1022 | { |
910 | bool ret = false; | 1023 | bool ret = false; |
911 | 1024 | ||
912 | // the mesh, hull or native shape must have already been created in Bullet | 1025 | // the mesh, hull or native shape must have already been created in Bullet |
913 | bool mustRebuild = (prim.PhysBody.ptr == IntPtr.Zero); | 1026 | bool mustRebuild = !prim.PhysBody.HasPhysicalBody; |
914 | 1027 | ||
915 | // If there is an existing body, verify it's of an acceptable type. | 1028 | // If there is an existing body, verify it's of an acceptable type. |
916 | // If not a solid object, body is a GhostObject. Otherwise a RigidBody. | 1029 | // If not a solid object, body is a GhostObject. Otherwise a RigidBody. |
917 | if (!mustRebuild) | 1030 | if (!mustRebuild) |
918 | { | 1031 | { |
919 | CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(prim.PhysBody.ptr); | 1032 | CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysicsScene.PE.GetBodyType(prim.PhysBody); |
920 | if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY | 1033 | if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY |
921 | || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT) | 1034 | || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT) |
922 | { | 1035 | { |
923 | // If the collisionObject is not the correct type for solidness, rebuild what's there | 1036 | // If the collisionObject is not the correct type for solidness, rebuild what's there |
924 | mustRebuild = true; | 1037 | mustRebuild = true; |
1038 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,forceRebuildBecauseChangingBodyType,bodyType={1}", prim.LocalID, bodyType); | ||
925 | } | 1039 | } |
926 | } | 1040 | } |
927 | 1041 | ||
928 | if (mustRebuild || forceRebuild) | 1042 | if (mustRebuild || forceRebuild) |
929 | { | 1043 | { |
930 | // Free any old body | 1044 | // Free any old body |
931 | DereferenceBody(prim.PhysBody, true, bodyCallback); | 1045 | DereferenceBody(prim.PhysBody, bodyCallback); |
932 | 1046 | ||
933 | BulletBody aBody; | 1047 | BulletBody aBody; |
934 | IntPtr bodyPtr = IntPtr.Zero; | ||
935 | if (prim.IsSolid) | 1048 | if (prim.IsSolid) |
936 | { | 1049 | { |
937 | bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr, | 1050 | aBody = PhysicsScene.PE.CreateBodyFromShape(sim, prim.PhysShape, prim.LocalID, prim.RawPosition, prim.RawOrientation); |
938 | prim.LocalID, prim.RawPosition, prim.RawOrientation); | 1051 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,mesh,body={1}", prim.LocalID, aBody); |
939 | DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X")); | ||
940 | } | 1052 | } |
941 | else | 1053 | else |
942 | { | 1054 | { |
943 | bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr, | 1055 | aBody = PhysicsScene.PE.CreateGhostFromShape(sim, prim.PhysShape, prim.LocalID, prim.RawPosition, prim.RawOrientation); |
944 | prim.LocalID, prim.RawPosition, prim.RawOrientation); | 1056 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,ghost,body={1}", prim.LocalID, aBody); |
945 | DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X")); | ||
946 | } | 1057 | } |
947 | aBody = new BulletBody(prim.LocalID, bodyPtr); | ||
948 | 1058 | ||
949 | ReferenceBody(aBody, true); | 1059 | ReferenceBody(aBody); |
950 | 1060 | ||
951 | prim.PhysBody = aBody; | 1061 | prim.PhysBody = aBody; |
952 | 1062 | ||
@@ -956,13 +1066,13 @@ public sealed class BSShapeCollection : IDisposable | |||
956 | return ret; | 1066 | return ret; |
957 | } | 1067 | } |
958 | 1068 | ||
959 | private bool TryGetMeshByPtr(IntPtr addr, out MeshDesc outDesc) | 1069 | private bool TryGetMeshByPtr(BulletShape shape, out MeshDesc outDesc) |
960 | { | 1070 | { |
961 | bool ret = false; | 1071 | bool ret = false; |
962 | MeshDesc foundDesc = new MeshDesc(); | 1072 | MeshDesc foundDesc = new MeshDesc(); |
963 | foreach (MeshDesc md in Meshes.Values) | 1073 | foreach (MeshDesc md in Meshes.Values) |
964 | { | 1074 | { |
965 | if (md.ptr == addr) | 1075 | if (md.shape.ReferenceSame(shape)) |
966 | { | 1076 | { |
967 | foundDesc = md; | 1077 | foundDesc = md; |
968 | ret = true; | 1078 | ret = true; |
@@ -974,13 +1084,13 @@ public sealed class BSShapeCollection : IDisposable | |||
974 | return ret; | 1084 | return ret; |
975 | } | 1085 | } |
976 | 1086 | ||
977 | private bool TryGetHullByPtr(IntPtr addr, out HullDesc outDesc) | 1087 | private bool TryGetHullByPtr(BulletShape shape, out HullDesc outDesc) |
978 | { | 1088 | { |
979 | bool ret = false; | 1089 | bool ret = false; |
980 | HullDesc foundDesc = new HullDesc(); | 1090 | HullDesc foundDesc = new HullDesc(); |
981 | foreach (HullDesc hd in Hulls.Values) | 1091 | foreach (HullDesc hd in Hulls.Values) |
982 | { | 1092 | { |
983 | if (hd.ptr == addr) | 1093 | if (hd.shape.ReferenceSame(shape)) |
984 | { | 1094 | { |
985 | foundDesc = hd; | 1095 | foundDesc = hd; |
986 | ret = true; | 1096 | ret = true; |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs index 96cd55e..ee18379 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs | |||
@@ -27,24 +27,19 @@ | |||
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.Linq; | ||
31 | using System.Text; | 30 | using System.Text; |
32 | 31 | ||
32 | using OMV = OpenMetaverse; | ||
33 | |||
33 | namespace OpenSim.Region.Physics.BulletSPlugin | 34 | namespace OpenSim.Region.Physics.BulletSPlugin |
34 | { | 35 | { |
35 | public abstract class BSShape | 36 | public abstract class BSShape |
36 | { | 37 | { |
37 | public IntPtr ptr { get; set; } | ||
38 | public BSPhysicsShapeType type { get; set; } | ||
39 | public System.UInt64 key { get; set; } | ||
40 | public int referenceCount { get; set; } | 38 | public int referenceCount { get; set; } |
41 | public DateTime lastReferenced { get; set; } | 39 | public DateTime lastReferenced { get; set; } |
42 | 40 | ||
43 | public BSShape() | 41 | public BSShape() |
44 | { | 42 | { |
45 | ptr = IntPtr.Zero; | ||
46 | type = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
47 | key = 0; | ||
48 | referenceCount = 0; | 43 | referenceCount = 0; |
49 | lastReferenced = DateTime.Now; | 44 | lastReferenced = DateTime.Now; |
50 | } | 45 | } |
@@ -63,7 +58,7 @@ public abstract class BSShape | |||
63 | } | 58 | } |
64 | 59 | ||
65 | // Compound shapes are handled special as they are rebuilt from scratch. | 60 | // Compound shapes are handled special as they are rebuilt from scratch. |
66 | // This isn't too great a hardship since most of the child shapes will already been created. | 61 | // This isn't too great a hardship since most of the child shapes will have already been created. |
67 | if (ret == null && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND) | 62 | if (ret == null && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND) |
68 | { | 63 | { |
69 | // Getting a reference to a compound shape gets you the compound shape with the root prim shape added | 64 | // Getting a reference to a compound shape gets you the compound shape with the root prim shape added |
@@ -71,6 +66,14 @@ public abstract class BSShape | |||
71 | physicsScene.DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, ret); | 66 | physicsScene.DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, ret); |
72 | } | 67 | } |
73 | 68 | ||
69 | // Avatars have their own unique shape | ||
70 | if (ret == null && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_AVATAR) | ||
71 | { | ||
72 | // Getting a reference to a compound shape gets you the compound shape with the root prim shape added | ||
73 | ret = BSShapeAvatar.GetReference(prim); | ||
74 | physicsScene.DetailLog("{0},BSShapeCollection.CreateGeom,avatarShape,shape={1}", prim.LocalID, ret); | ||
75 | } | ||
76 | |||
74 | if (ret == null) | 77 | if (ret == null) |
75 | ret = GetShapeReferenceNonSpecial(physicsScene, forceRebuild, prim); | 78 | ret = GetShapeReferenceNonSpecial(physicsScene, forceRebuild, prim); |
76 | 79 | ||
@@ -91,15 +94,17 @@ public abstract class BSShape | |||
91 | // All shapes have a static call to get a reference to the physical shape | 94 | // All shapes have a static call to get a reference to the physical shape |
92 | // protected abstract static BSShape GetReference(); | 95 | // protected abstract static BSShape GetReference(); |
93 | 96 | ||
97 | // Returns a string for debugging that uniquily identifies the memory used by this instance | ||
98 | public virtual string AddrString | ||
99 | { | ||
100 | get { return "unknown"; } | ||
101 | } | ||
102 | |||
94 | public override string ToString() | 103 | public override string ToString() |
95 | { | 104 | { |
96 | StringBuilder buff = new StringBuilder(); | 105 | StringBuilder buff = new StringBuilder(); |
97 | buff.Append("<p="); | 106 | buff.Append("<p="); |
98 | buff.Append(ptr.ToString("X")); | 107 | buff.Append(AddrString); |
99 | buff.Append(",s="); | ||
100 | buff.Append(type.ToString()); | ||
101 | buff.Append(",k="); | ||
102 | buff.Append(key.ToString("X")); | ||
103 | buff.Append(",c="); | 108 | buff.Append(",c="); |
104 | buff.Append(referenceCount.ToString()); | 109 | buff.Append(referenceCount.ToString()); |
105 | buff.Append(">"); | 110 | buff.Append(">"); |
@@ -126,7 +131,8 @@ public class BSShapeNative : BSShape | |||
126 | BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) | 131 | BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) |
127 | { | 132 | { |
128 | // Native shapes are not shared and are always built anew. | 133 | // Native shapes are not shared and are always built anew. |
129 | return new BSShapeNative(physicsScene, prim, shapeType, shapeKey); | 134 | //return new BSShapeNative(physicsScene, prim, shapeType, shapeKey); |
135 | return null; | ||
130 | } | 136 | } |
131 | 137 | ||
132 | private BSShapeNative(BSScene physicsScene, BSPhysObject prim, | 138 | private BSShapeNative(BSScene physicsScene, BSPhysObject prim, |
@@ -141,14 +147,15 @@ public class BSShapeNative : BSShape | |||
141 | nativeShapeData.HullKey = (ulong)shapeKey; | 147 | nativeShapeData.HullKey = (ulong)shapeKey; |
142 | 148 | ||
143 | 149 | ||
150 | /* | ||
144 | if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE) | 151 | if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE) |
145 | { | 152 | { |
146 | ptr = BulletSimAPI.BuildCapsuleShape2(physicsScene.World.ptr, 1f, 1f, prim.Scale); | 153 | ptr = PhysicsScene.PE.BuildCapsuleShape(physicsScene.World, 1f, 1f, prim.Scale); |
147 | physicsScene.DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale); | 154 | physicsScene.DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale); |
148 | } | 155 | } |
149 | else | 156 | else |
150 | { | 157 | { |
151 | ptr = BulletSimAPI.BuildNativeShape2(physicsScene.World.ptr, nativeShapeData); | 158 | ptr = PhysicsScene.PE.BuildNativeShape(physicsScene.World, nativeShapeData); |
152 | } | 159 | } |
153 | if (ptr == IntPtr.Zero) | 160 | if (ptr == IntPtr.Zero) |
154 | { | 161 | { |
@@ -157,15 +164,18 @@ public class BSShapeNative : BSShape | |||
157 | } | 164 | } |
158 | type = shapeType; | 165 | type = shapeType; |
159 | key = (UInt64)shapeKey; | 166 | key = (UInt64)shapeKey; |
167 | */ | ||
160 | } | 168 | } |
161 | // Make this reference to the physical shape go away since native shapes are not shared. | 169 | // Make this reference to the physical shape go away since native shapes are not shared. |
162 | public override void Dereference(BSScene physicsScene) | 170 | public override void Dereference(BSScene physicsScene) |
163 | { | 171 | { |
172 | /* | ||
164 | // Native shapes are not tracked and are released immediately | 173 | // Native shapes are not tracked and are released immediately |
165 | physicsScene.DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this); | 174 | physicsScene.DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this); |
166 | BulletSimAPI.DeleteCollisionShape2(physicsScene.World.ptr, ptr); | 175 | PhysicsScene.PE.DeleteCollisionShape(physicsScene.World, this); |
167 | ptr = IntPtr.Zero; | 176 | ptr = IntPtr.Zero; |
168 | // Garbage collection will free up this instance. | 177 | // Garbage collection will free up this instance. |
178 | */ | ||
169 | } | 179 | } |
170 | } | 180 | } |
171 | 181 | ||
@@ -205,4 +215,143 @@ public class BSShapeCompound : BSShape | |||
205 | } | 215 | } |
206 | public override void Dereference(BSScene physicsScene) { } | 216 | public override void Dereference(BSScene physicsScene) { } |
207 | } | 217 | } |
218 | |||
219 | public class BSShapeAvatar : BSShape | ||
220 | { | ||
221 | private static string LogHeader = "[BULLETSIM SHAPE AVATAR]"; | ||
222 | public BSShapeAvatar() : base() | ||
223 | { | ||
224 | } | ||
225 | public static BSShape GetReference(BSPhysObject prim) | ||
226 | { | ||
227 | return new BSShapeNull(); | ||
228 | } | ||
229 | public override void Dereference(BSScene physicsScene) { } | ||
230 | |||
231 | // From the front: | ||
232 | // A---A | ||
233 | // / \ | ||
234 | // B-------B | ||
235 | // / \ +Z | ||
236 | // C-----------C | | ||
237 | // \ / -Y --+-- +Y | ||
238 | // \ / | | ||
239 | // \ / -Z | ||
240 | // D-----D | ||
241 | // \ / | ||
242 | // E-E | ||
243 | |||
244 | // From the top A and E are just lines. | ||
245 | // B, C and D are hexagons: | ||
246 | // | ||
247 | // C1--C2 +X | ||
248 | // / \ | | ||
249 | // C0 C3 -Y --+-- +Y | ||
250 | // \ / | | ||
251 | // C5--C4 -X | ||
252 | |||
253 | // Zero goes directly through the middle so the offsets are from that middle axis | ||
254 | // and up and down from a middle horizon (A and E are the same distance from the zero). | ||
255 | // The height, width and depth is one. All scaling is done by the simulator. | ||
256 | |||
257 | // Z component -- how far the level is from the middle zero | ||
258 | private const float Aup = 0.5f; | ||
259 | private const float Bup = 0.4f; | ||
260 | private const float Cup = 0.3f; | ||
261 | private const float Dup = -0.4f; | ||
262 | private const float Eup = -0.5f; | ||
263 | |||
264 | // Y component -- distance from center to x0 and x3 | ||
265 | private const float Awid = 0.25f; | ||
266 | private const float Bwid = 0.3f; | ||
267 | private const float Cwid = 0.5f; | ||
268 | private const float Dwid = 0.3f; | ||
269 | private const float Ewid = 0.2f; | ||
270 | |||
271 | // Y component -- distance from center to x1, x2, x4 and x5 | ||
272 | private const float Afwid = 0.0f; | ||
273 | private const float Bfwid = 0.2f; | ||
274 | private const float Cfwid = 0.4f; | ||
275 | private const float Dfwid = 0.2f; | ||
276 | private const float Efwid = 0.0f; | ||
277 | |||
278 | // X component -- distance from zero to the front or back of a level | ||
279 | private const float Adep = 0f; | ||
280 | private const float Bdep = 0.3f; | ||
281 | private const float Cdep = 0.5f; | ||
282 | private const float Ddep = 0.2f; | ||
283 | private const float Edep = 0f; | ||
284 | |||
285 | private OMV.Vector3[] avatarVertices = { | ||
286 | new OMV.Vector3( 0.0f, -Awid, Aup), // A0 | ||
287 | new OMV.Vector3( 0.0f, +Awid, Aup), // A3 | ||
288 | |||
289 | new OMV.Vector3( 0.0f, -Bwid, Bup), // B0 | ||
290 | new OMV.Vector3(+Bdep, -Bfwid, Bup), // B1 | ||
291 | new OMV.Vector3(+Bdep, +Bfwid, Bup), // B2 | ||
292 | new OMV.Vector3( 0.0f, +Bwid, Bup), // B3 | ||
293 | new OMV.Vector3(-Bdep, +Bfwid, Bup), // B4 | ||
294 | new OMV.Vector3(-Bdep, -Bfwid, Bup), // B5 | ||
295 | |||
296 | new OMV.Vector3( 0.0f, -Cwid, Cup), // C0 | ||
297 | new OMV.Vector3(+Cdep, -Cfwid, Cup), // C1 | ||
298 | new OMV.Vector3(+Cdep, +Cfwid, Cup), // C2 | ||
299 | new OMV.Vector3( 0.0f, +Cwid, Cup), // C3 | ||
300 | new OMV.Vector3(-Cdep, +Cfwid, Cup), // C4 | ||
301 | new OMV.Vector3(-Cdep, -Cfwid, Cup), // C5 | ||
302 | |||
303 | new OMV.Vector3( 0.0f, -Dwid, Dup), // D0 | ||
304 | new OMV.Vector3(+Ddep, -Dfwid, Dup), // D1 | ||
305 | new OMV.Vector3(+Ddep, +Dfwid, Dup), // D2 | ||
306 | new OMV.Vector3( 0.0f, +Dwid, Dup), // D3 | ||
307 | new OMV.Vector3(-Ddep, +Dfwid, Dup), // D4 | ||
308 | new OMV.Vector3(-Ddep, -Dfwid, Dup), // D5 | ||
309 | |||
310 | new OMV.Vector3( 0.0f, -Ewid, Eup), // E0 | ||
311 | new OMV.Vector3( 0.0f, +Ewid, Eup), // E3 | ||
312 | }; | ||
313 | |||
314 | // Offsets of the vertices in the vertices array | ||
315 | private enum Ind : int | ||
316 | { | ||
317 | A0, A3, | ||
318 | B0, B1, B2, B3, B4, B5, | ||
319 | C0, C1, C2, C3, C4, C5, | ||
320 | D0, D1, D2, D3, D4, D5, | ||
321 | E0, E3 | ||
322 | } | ||
323 | |||
324 | // Comments specify trianges and quads in clockwise direction | ||
325 | private Ind[] avatarIndices = { | ||
326 | Ind.A0, Ind.B0, Ind.B1, // A0,B0,B1 | ||
327 | Ind.A0, Ind.B1, Ind.B2, Ind.B2, Ind.A3, Ind.A0, // A0,B1,B2,A3 | ||
328 | Ind.A3, Ind.B2, Ind.B3, // A3,B2,B3 | ||
329 | Ind.A3, Ind.B3, Ind.B4, // A3,B3,B4 | ||
330 | Ind.A3, Ind.B4, Ind.B5, Ind.B5, Ind.A0, Ind.A3, // A3,B4,B5,A0 | ||
331 | Ind.A0, Ind.B5, Ind.B0, // A0,B5,B0 | ||
332 | |||
333 | Ind.B0, Ind.C0, Ind.C1, Ind.C1, Ind.B1, Ind.B0, // B0,C0,C1,B1 | ||
334 | Ind.B1, Ind.C1, Ind.C2, Ind.C2, Ind.B2, Ind.B1, // B1,C1,C2,B2 | ||
335 | Ind.B2, Ind.C2, Ind.C3, Ind.C3, Ind.B3, Ind.B2, // B2,C2,C3,B3 | ||
336 | Ind.B3, Ind.C3, Ind.C4, Ind.C4, Ind.B4, Ind.B3, // B3,C3,C4,B4 | ||
337 | Ind.B4, Ind.C4, Ind.C5, Ind.C5, Ind.B5, Ind.B4, // B4,C4,C5,B5 | ||
338 | Ind.B5, Ind.C5, Ind.C0, Ind.C0, Ind.B0, Ind.B5, // B5,C5,C0,B0 | ||
339 | |||
340 | Ind.C0, Ind.D0, Ind.D1, Ind.D1, Ind.C1, Ind.C0, // C0,D0,D1,C1 | ||
341 | Ind.C1, Ind.D1, Ind.D2, Ind.D2, Ind.C2, Ind.C1, // C1,D1,D2,C2 | ||
342 | Ind.C2, Ind.D2, Ind.D3, Ind.D3, Ind.C3, Ind.C2, // C2,D2,D3,C3 | ||
343 | Ind.C3, Ind.D3, Ind.D4, Ind.D4, Ind.C4, Ind.C3, // C3,D3,D4,C4 | ||
344 | Ind.C4, Ind.D4, Ind.D5, Ind.D5, Ind.C5, Ind.C4, // C4,D4,D5,C5 | ||
345 | Ind.C5, Ind.D5, Ind.D0, Ind.D0, Ind.C0, Ind.C5, // C5,D5,D0,C0 | ||
346 | |||
347 | Ind.E0, Ind.D0, Ind.D1, // E0,D0,D1 | ||
348 | Ind.E0, Ind.D1, Ind.D2, Ind.D2, Ind.E3, Ind.E0, // E0,D1,D2,E3 | ||
349 | Ind.E3, Ind.D2, Ind.D3, // E3,D2,D3 | ||
350 | Ind.E3, Ind.D3, Ind.D4, // E3,D3,D4 | ||
351 | Ind.E3, Ind.D4, Ind.D5, Ind.D5, Ind.E0, Ind.E3, // E3,D4,D5,E0 | ||
352 | Ind.E0, Ind.D5, Ind.D0, // E0,D5,D0 | ||
353 | |||
354 | }; | ||
355 | |||
356 | } | ||
208 | } | 357 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs index 3ca756c..e4fecc3 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs | |||
@@ -44,7 +44,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys | |||
44 | { | 44 | { |
45 | static string LogHeader = "[BULLETSIM TERRAIN HEIGHTMAP]"; | 45 | static string LogHeader = "[BULLETSIM TERRAIN HEIGHTMAP]"; |
46 | 46 | ||
47 | BulletHeightMapInfo m_mapInfo = null; | 47 | BulletHMapInfo m_mapInfo = null; |
48 | 48 | ||
49 | // Constructor to build a default, flat heightmap terrain. | 49 | // Constructor to build a default, flat heightmap terrain. |
50 | public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize) | 50 | public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize) |
@@ -58,7 +58,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys | |||
58 | { | 58 | { |
59 | initialMap[ii] = BSTerrainManager.HEIGHT_INITIALIZATION; | 59 | initialMap[ii] = BSTerrainManager.HEIGHT_INITIALIZATION; |
60 | } | 60 | } |
61 | m_mapInfo = new BulletHeightMapInfo(id, initialMap, IntPtr.Zero); | 61 | m_mapInfo = new BulletHMapInfo(id, initialMap); |
62 | m_mapInfo.minCoords = minTerrainCoords; | 62 | m_mapInfo.minCoords = minTerrainCoords; |
63 | m_mapInfo.maxCoords = maxTerrainCoords; | 63 | m_mapInfo.maxCoords = maxTerrainCoords; |
64 | m_mapInfo.terrainRegionBase = TerrainBase; | 64 | m_mapInfo.terrainRegionBase = TerrainBase; |
@@ -72,7 +72,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys | |||
72 | Vector3 minCoords, Vector3 maxCoords) | 72 | Vector3 minCoords, Vector3 maxCoords) |
73 | : base(physicsScene, regionBase, id) | 73 | : base(physicsScene, regionBase, id) |
74 | { | 74 | { |
75 | m_mapInfo = new BulletHeightMapInfo(id, initialMap, IntPtr.Zero); | 75 | m_mapInfo = new BulletHMapInfo(id, initialMap); |
76 | m_mapInfo.minCoords = minCoords; | 76 | m_mapInfo.minCoords = minCoords; |
77 | m_mapInfo.maxCoords = maxCoords; | 77 | m_mapInfo.maxCoords = maxCoords; |
78 | m_mapInfo.minZ = minCoords.Z; | 78 | m_mapInfo.minZ = minCoords.Z; |
@@ -91,13 +91,11 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys | |||
91 | // Using the information in m_mapInfo, create the physical representation of the heightmap. | 91 | // Using the information in m_mapInfo, create the physical representation of the heightmap. |
92 | private void BuildHeightmapTerrain() | 92 | private void BuildHeightmapTerrain() |
93 | { | 93 | { |
94 | m_mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, m_mapInfo.ID, | ||
95 | m_mapInfo.minCoords, m_mapInfo.maxCoords, | ||
96 | m_mapInfo.heightMap, BSTerrainManager.TERRAIN_COLLISION_MARGIN); | ||
97 | |||
98 | // Create the terrain shape from the mapInfo | 94 | // Create the terrain shape from the mapInfo |
99 | m_mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(m_mapInfo.Ptr), | 95 | m_mapInfo.terrainShape = PhysicsScene.PE.CreateTerrainShape( m_mapInfo.ID, |
100 | BSPhysicsShapeType.SHAPE_TERRAIN); | 96 | new Vector3(m_mapInfo.sizeX, m_mapInfo.sizeY, 0), m_mapInfo.minZ, m_mapInfo.maxZ, |
97 | m_mapInfo.heightMap, 1f, BSParam.TerrainCollisionMargin); | ||
98 | |||
101 | 99 | ||
102 | // The terrain object initial position is at the center of the object | 100 | // The terrain object initial position is at the center of the object |
103 | Vector3 centerPos; | 101 | Vector3 centerPos; |
@@ -105,28 +103,26 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys | |||
105 | centerPos.Y = m_mapInfo.minCoords.Y + (m_mapInfo.sizeY / 2f); | 103 | centerPos.Y = m_mapInfo.minCoords.Y + (m_mapInfo.sizeY / 2f); |
106 | centerPos.Z = m_mapInfo.minZ + ((m_mapInfo.maxZ - m_mapInfo.minZ) / 2f); | 104 | centerPos.Z = m_mapInfo.minZ + ((m_mapInfo.maxZ - m_mapInfo.minZ) / 2f); |
107 | 105 | ||
108 | m_mapInfo.terrainBody = new BulletBody(m_mapInfo.ID, | 106 | m_mapInfo.terrainBody = PhysicsScene.PE.CreateBodyWithDefaultMotionState(m_mapInfo.terrainShape, |
109 | BulletSimAPI.CreateBodyWithDefaultMotionState2(m_mapInfo.terrainShape.ptr, | 107 | m_mapInfo.ID, centerPos, Quaternion.Identity); |
110 | m_mapInfo.ID, centerPos, Quaternion.Identity)); | ||
111 | 108 | ||
112 | // Set current terrain attributes | 109 | // Set current terrain attributes |
113 | BulletSimAPI.SetFriction2(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainFriction); | 110 | PhysicsScene.PE.SetFriction(m_mapInfo.terrainBody, BSParam.TerrainFriction); |
114 | BulletSimAPI.SetHitFraction2(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction); | 111 | PhysicsScene.PE.SetHitFraction(m_mapInfo.terrainBody, BSParam.TerrainHitFraction); |
115 | BulletSimAPI.SetRestitution2(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainRestitution); | 112 | PhysicsScene.PE.SetRestitution(m_mapInfo.terrainBody, BSParam.TerrainRestitution); |
116 | BulletSimAPI.SetCollisionFlags2(m_mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT); | 113 | PhysicsScene.PE.SetCollisionFlags(m_mapInfo.terrainBody, CollisionFlags.CF_STATIC_OBJECT); |
117 | 114 | ||
118 | // Return the new terrain to the world of physical objects | 115 | // Return the new terrain to the world of physical objects |
119 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr); | 116 | PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_mapInfo.terrainBody); |
120 | 117 | ||
121 | // redo its bounding box now that it is in the world | 118 | // redo its bounding box now that it is in the world |
122 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr); | 119 | PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_mapInfo.terrainBody); |
123 | 120 | ||
124 | BulletSimAPI.SetCollisionFilterMask2(m_mapInfo.terrainBody.ptr, | 121 | m_mapInfo.terrainBody.collisionType = CollisionType.Terrain; |
125 | (uint)CollisionFilterGroups.TerrainFilter, | 122 | m_mapInfo.terrainBody.ApplyCollisionMask(PhysicsScene); |
126 | (uint)CollisionFilterGroups.TerrainMask); | ||
127 | 123 | ||
128 | // Make it so the terrain will not move or be considered for movement. | 124 | // Make it so the terrain will not move or be considered for movement. |
129 | BulletSimAPI.ForceActivationState2(m_mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION); | 125 | PhysicsScene.PE.ForceActivationState(m_mapInfo.terrainBody, ActivationState.DISABLE_SIMULATION); |
130 | 126 | ||
131 | return; | 127 | return; |
132 | } | 128 | } |
@@ -136,19 +132,18 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys | |||
136 | { | 132 | { |
137 | if (m_mapInfo != null) | 133 | if (m_mapInfo != null) |
138 | { | 134 | { |
139 | if (m_mapInfo.terrainBody.ptr != IntPtr.Zero) | 135 | if (m_mapInfo.terrainBody.HasPhysicalBody) |
140 | { | 136 | { |
141 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr); | 137 | PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_mapInfo.terrainBody); |
142 | // Frees both the body and the shape. | 138 | // Frees both the body and the shape. |
143 | BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr); | 139 | PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_mapInfo.terrainBody); |
144 | BulletSimAPI.ReleaseHeightMapInfo2(m_mapInfo.Ptr); | ||
145 | } | 140 | } |
146 | } | 141 | } |
147 | m_mapInfo = null; | 142 | m_mapInfo = null; |
148 | } | 143 | } |
149 | 144 | ||
150 | // The passed position is relative to the base of the region. | 145 | // The passed position is relative to the base of the region. |
151 | public override float GetHeightAtXYZ(Vector3 pos) | 146 | public override float GetTerrainHeightAtXYZ(Vector3 pos) |
152 | { | 147 | { |
153 | float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; | 148 | float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; |
154 | 149 | ||
@@ -166,5 +161,11 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys | |||
166 | } | 161 | } |
167 | return ret; | 162 | return ret; |
168 | } | 163 | } |
164 | |||
165 | // The passed position is relative to the base of the region. | ||
166 | public override float GetWaterLevelAtXYZ(Vector3 pos) | ||
167 | { | ||
168 | return PhysicsScene.SimpleWaterLevel; | ||
169 | } | ||
169 | } | 170 | } |
170 | } | 171 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs index 23fcfd3..b2fb835 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs | |||
@@ -62,11 +62,12 @@ public abstract class BSTerrainPhys : IDisposable | |||
62 | ID = id; | 62 | ID = id; |
63 | } | 63 | } |
64 | public abstract void Dispose(); | 64 | public abstract void Dispose(); |
65 | public abstract float GetHeightAtXYZ(Vector3 pos); | 65 | public abstract float GetTerrainHeightAtXYZ(Vector3 pos); |
66 | public abstract float GetWaterLevelAtXYZ(Vector3 pos); | ||
66 | } | 67 | } |
67 | 68 | ||
68 | // ========================================================================================== | 69 | // ========================================================================================== |
69 | public sealed class BSTerrainManager | 70 | public sealed class BSTerrainManager : IDisposable |
70 | { | 71 | { |
71 | static string LogHeader = "[BULLETSIM TERRAIN MANAGER]"; | 72 | static string LogHeader = "[BULLETSIM TERRAIN MANAGER]"; |
72 | 73 | ||
@@ -75,13 +76,12 @@ public sealed class BSTerrainManager | |||
75 | public const float HEIGHT_INITIALIZATION = 24.987f; | 76 | public const float HEIGHT_INITIALIZATION = 24.987f; |
76 | public const float HEIGHT_INITIAL_LASTHEIGHT = 24.876f; | 77 | public const float HEIGHT_INITIAL_LASTHEIGHT = 24.876f; |
77 | public const float HEIGHT_GETHEIGHT_RET = 24.765f; | 78 | public const float HEIGHT_GETHEIGHT_RET = 24.765f; |
79 | public const float WATER_HEIGHT_GETHEIGHT_RET = 19.998f; | ||
78 | 80 | ||
79 | // If the min and max height are equal, we reduce the min by this | 81 | // If the min and max height are equal, we reduce the min by this |
80 | // amount to make sure that a bounding box is built for the terrain. | 82 | // amount to make sure that a bounding box is built for the terrain. |
81 | public const float HEIGHT_EQUAL_FUDGE = 0.2f; | 83 | public const float HEIGHT_EQUAL_FUDGE = 0.2f; |
82 | 84 | ||
83 | public const float TERRAIN_COLLISION_MARGIN = 0.0f; | ||
84 | |||
85 | // Until the whole simulator is changed to pass us the region size, we rely on constants. | 85 | // Until the whole simulator is changed to pass us the region size, we rely on constants. |
86 | public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); | 86 | public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); |
87 | 87 | ||
@@ -122,41 +122,49 @@ public sealed class BSTerrainManager | |||
122 | MegaRegionParentPhysicsScene = null; | 122 | MegaRegionParentPhysicsScene = null; |
123 | } | 123 | } |
124 | 124 | ||
125 | public void Dispose() | ||
126 | { | ||
127 | ReleaseGroundPlaneAndTerrain(); | ||
128 | } | ||
129 | |||
125 | // Create the initial instance of terrain and the underlying ground plane. | 130 | // Create the initial instance of terrain and the underlying ground plane. |
126 | // This is called from the initialization routine so we presume it is | 131 | // This is called from the initialization routine so we presume it is |
127 | // safe to call Bullet in real time. We hope no one is moving prims around yet. | 132 | // safe to call Bullet in real time. We hope no one is moving prims around yet. |
128 | public void CreateInitialGroundPlaneAndTerrain() | 133 | public void CreateInitialGroundPlaneAndTerrain() |
129 | { | 134 | { |
135 | DetailLog("{0},BSTerrainManager.CreateInitialGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, PhysicsScene.RegionName); | ||
130 | // The ground plane is here to catch things that are trying to drop to negative infinity | 136 | // The ground plane is here to catch things that are trying to drop to negative infinity |
131 | BulletShape groundPlaneShape = new BulletShape( | 137 | BulletShape groundPlaneShape = PhysicsScene.PE.CreateGroundPlaneShape(BSScene.GROUNDPLANE_ID, 1f, BSParam.TerrainCollisionMargin); |
132 | BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f, TERRAIN_COLLISION_MARGIN), | 138 | m_groundPlane = PhysicsScene.PE.CreateBodyWithDefaultMotionState(groundPlaneShape, |
133 | BSPhysicsShapeType.SHAPE_GROUNDPLANE); | 139 | BSScene.GROUNDPLANE_ID, Vector3.Zero, Quaternion.Identity); |
134 | m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID, | 140 | |
135 | BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID, | 141 | PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_groundPlane); |
136 | Vector3.Zero, Quaternion.Identity)); | 142 | PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_groundPlane); |
137 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr); | ||
138 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_groundPlane.ptr); | ||
139 | // Ground plane does not move | 143 | // Ground plane does not move |
140 | BulletSimAPI.ForceActivationState2(m_groundPlane.ptr, ActivationState.DISABLE_SIMULATION); | 144 | PhysicsScene.PE.ForceActivationState(m_groundPlane, ActivationState.DISABLE_SIMULATION); |
141 | // Everything collides with the ground plane. | 145 | // Everything collides with the ground plane. |
142 | BulletSimAPI.SetCollisionFilterMask2(m_groundPlane.ptr, | 146 | m_groundPlane.collisionType = CollisionType.Groundplane; |
143 | (uint)CollisionFilterGroups.GroundPlaneFilter, (uint)CollisionFilterGroups.GroundPlaneMask); | 147 | m_groundPlane.ApplyCollisionMask(PhysicsScene); |
144 | 148 | ||
145 | // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain. | ||
146 | BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize); | 149 | BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize); |
147 | m_terrains.Add(Vector3.Zero, initialTerrain); | 150 | lock (m_terrains) |
151 | { | ||
152 | // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain. | ||
153 | m_terrains.Add(Vector3.Zero, initialTerrain); | ||
154 | } | ||
148 | } | 155 | } |
149 | 156 | ||
150 | // Release all the terrain structures we might have allocated | 157 | // Release all the terrain structures we might have allocated |
151 | public void ReleaseGroundPlaneAndTerrain() | 158 | public void ReleaseGroundPlaneAndTerrain() |
152 | { | 159 | { |
153 | if (m_groundPlane.ptr != IntPtr.Zero) | 160 | DetailLog("{0},BSTerrainManager.ReleaseGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, PhysicsScene.RegionName); |
161 | if (m_groundPlane.HasPhysicalBody) | ||
154 | { | 162 | { |
155 | if (BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr)) | 163 | if (PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_groundPlane)) |
156 | { | 164 | { |
157 | BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_groundPlane.ptr); | 165 | PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_groundPlane); |
158 | } | 166 | } |
159 | m_groundPlane.ptr = IntPtr.Zero; | 167 | m_groundPlane.Clear(); |
160 | } | 168 | } |
161 | 169 | ||
162 | ReleaseTerrain(); | 170 | ReleaseTerrain(); |
@@ -165,17 +173,22 @@ public sealed class BSTerrainManager | |||
165 | // Release all the terrain we have allocated | 173 | // Release all the terrain we have allocated |
166 | public void ReleaseTerrain() | 174 | public void ReleaseTerrain() |
167 | { | 175 | { |
168 | foreach (KeyValuePair<Vector3, BSTerrainPhys> kvp in m_terrains) | 176 | lock (m_terrains) |
169 | { | 177 | { |
170 | kvp.Value.Dispose(); | 178 | foreach (KeyValuePair<Vector3, BSTerrainPhys> kvp in m_terrains) |
179 | { | ||
180 | kvp.Value.Dispose(); | ||
181 | } | ||
182 | m_terrains.Clear(); | ||
171 | } | 183 | } |
172 | m_terrains.Clear(); | ||
173 | } | 184 | } |
174 | 185 | ||
175 | // The simulator wants to set a new heightmap for the terrain. | 186 | // The simulator wants to set a new heightmap for the terrain. |
176 | public void SetTerrain(float[] heightMap) { | 187 | public void SetTerrain(float[] heightMap) { |
177 | float[] localHeightMap = heightMap; | 188 | float[] localHeightMap = heightMap; |
178 | PhysicsScene.TaintedObject("TerrainManager.SetTerrain", delegate() | 189 | // If there are multiple requests for changes to the same terrain between ticks, |
190 | // only do that last one. | ||
191 | PhysicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate() | ||
179 | { | 192 | { |
180 | if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null) | 193 | if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null) |
181 | { | 194 | { |
@@ -185,11 +198,16 @@ public sealed class BSTerrainManager | |||
185 | // the terrain is added to our parent | 198 | // the terrain is added to our parent |
186 | if (MegaRegionParentPhysicsScene is BSScene) | 199 | if (MegaRegionParentPhysicsScene is BSScene) |
187 | { | 200 | { |
188 | DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}", | 201 | DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}", BSScene.DetailLogZero, m_worldOffset, m_worldMax); |
189 | BSScene.DetailLogZero, m_worldOffset, m_worldMax); | 202 | // This looks really odd but this region is passing its terrain to its mega-region root region |
190 | ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.UpdateTerrain( | 203 | // and the creation of the terrain must happen on the root region's taint thread and not |
191 | BSScene.CHILDTERRAIN_ID, localHeightMap, | 204 | // my taint thread. |
192 | m_worldOffset, m_worldOffset + DefaultRegionSize, true); | 205 | ((BSScene)MegaRegionParentPhysicsScene).PostTaintObject("TerrainManager.SetTerrain.Mega-" + m_worldOffset.ToString(), 0, delegate() |
206 | { | ||
207 | ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.UpdateTerrain( | ||
208 | BSScene.CHILDTERRAIN_ID, localHeightMap, | ||
209 | m_worldOffset, m_worldOffset + DefaultRegionSize, true /* inTaintTime */); | ||
210 | }); | ||
193 | } | 211 | } |
194 | } | 212 | } |
195 | else | 213 | else |
@@ -198,29 +216,30 @@ public sealed class BSTerrainManager | |||
198 | DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero); | 216 | DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero); |
199 | 217 | ||
200 | UpdateTerrain(BSScene.TERRAIN_ID, localHeightMap, | 218 | UpdateTerrain(BSScene.TERRAIN_ID, localHeightMap, |
201 | m_worldOffset, m_worldOffset + DefaultRegionSize, true); | 219 | m_worldOffset, m_worldOffset + DefaultRegionSize, true /* inTaintTime */); |
202 | } | 220 | } |
203 | }); | 221 | }); |
204 | } | 222 | } |
205 | 223 | ||
206 | // If called with no mapInfo for the terrain, this will create a new mapInfo and terrain | 224 | // If called for terrain has has not been previously allocated, a new terrain will be built |
207 | // based on the passed information. The 'id' should be either the terrain id or | 225 | // based on the passed information. The 'id' should be either the terrain id or |
208 | // BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used. | 226 | // BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used. |
209 | // The latter feature is for creating child terrains for mega-regions. | 227 | // The latter feature is for creating child terrains for mega-regions. |
210 | // If called with a mapInfo in m_heightMaps and there is an existing terrain body, a new | 228 | // If there is an existing terrain body, a new |
211 | // terrain shape is created and added to the body. | 229 | // terrain shape is created and added to the body. |
212 | // This call is most often used to update the heightMap and parameters of the terrain. | 230 | // This call is most often used to update the heightMap and parameters of the terrain. |
213 | // (The above does suggest that some simplification/refactoring is in order.) | 231 | // (The above does suggest that some simplification/refactoring is in order.) |
232 | // Called during taint-time. | ||
214 | private void UpdateTerrain(uint id, float[] heightMap, | 233 | private void UpdateTerrain(uint id, float[] heightMap, |
215 | Vector3 minCoords, Vector3 maxCoords, bool inTaintTime) | 234 | Vector3 minCoords, Vector3 maxCoords, bool inTaintTime) |
216 | { | 235 | { |
217 | DetailLog("{0},BSTerrainManager.UpdateTerrain,call,minC={1},maxC={2},inTaintTime={3}", | 236 | DetailLog("{0},BSTerrainManager.UpdateTerrain,call,id={1},minC={2},maxC={3},inTaintTime={4}", |
218 | BSScene.DetailLogZero, minCoords, maxCoords, inTaintTime); | 237 | BSScene.DetailLogZero, id, minCoords, maxCoords, inTaintTime); |
219 | 238 | ||
220 | // Find high and low points of passed heightmap. | 239 | // Find high and low points of passed heightmap. |
221 | // The min and max passed in is usually the area objects can be in (maximum | 240 | // The min and max passed in is usually the area objects can be in (maximum |
222 | // object height, for instance). The terrain wants the bounding box for the | 241 | // object height, for instance). The terrain wants the bounding box for the |
223 | // terrain so we replace passed min and max Z with the actual terrain min/max Z. | 242 | // terrain so replace passed min and max Z with the actual terrain min/max Z. |
224 | float minZ = float.MaxValue; | 243 | float minZ = float.MaxValue; |
225 | float maxZ = float.MinValue; | 244 | float maxZ = float.MinValue; |
226 | foreach (float height in heightMap) | 245 | foreach (float height in heightMap) |
@@ -238,15 +257,15 @@ public sealed class BSTerrainManager | |||
238 | 257 | ||
239 | Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f); | 258 | Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f); |
240 | 259 | ||
241 | BSTerrainPhys terrainPhys; | 260 | lock (m_terrains) |
242 | if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys)) | ||
243 | { | 261 | { |
244 | // There is already a terrain in this spot. Free the old and build the new. | 262 | BSTerrainPhys terrainPhys; |
245 | DetailLog("{0},UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}", | 263 | if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys)) |
246 | BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords); | ||
247 | |||
248 | PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateTerrain:UpdateExisting", delegate() | ||
249 | { | 264 | { |
265 | // There is already a terrain in this spot. Free the old and build the new. | ||
266 | DetailLog("{0},BSTErrainManager.UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}", | ||
267 | BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords); | ||
268 | |||
250 | // Remove old terrain from the collection | 269 | // Remove old terrain from the collection |
251 | m_terrains.Remove(terrainRegionBase); | 270 | m_terrains.Remove(terrainRegionBase); |
252 | // Release any physical memory it may be using. | 271 | // Release any physical memory it may be using. |
@@ -254,6 +273,7 @@ public sealed class BSTerrainManager | |||
254 | 273 | ||
255 | if (MegaRegionParentPhysicsScene == null) | 274 | if (MegaRegionParentPhysicsScene == null) |
256 | { | 275 | { |
276 | // This terrain is not part of the mega-region scheme. Create vanilla terrain. | ||
257 | BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); | 277 | BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); |
258 | m_terrains.Add(terrainRegionBase, newTerrainPhys); | 278 | m_terrains.Add(terrainRegionBase, newTerrainPhys); |
259 | 279 | ||
@@ -271,35 +291,24 @@ public sealed class BSTerrainManager | |||
271 | // I hate doing this, but just bail | 291 | // I hate doing this, but just bail |
272 | return; | 292 | return; |
273 | } | 293 | } |
274 | }); | 294 | } |
275 | } | 295 | else |
276 | else | 296 | { |
277 | { | 297 | // We don't know about this terrain so either we are creating a new terrain or |
278 | // We don't know about this terrain so either we are creating a new terrain or | 298 | // our mega-prim child is giving us a new terrain to add to the phys world |
279 | // our mega-prim child is giving us a new terrain to add to the phys world | ||
280 | |||
281 | // if this is a child terrain, calculate a unique terrain id | ||
282 | uint newTerrainID = id; | ||
283 | if (newTerrainID >= BSScene.CHILDTERRAIN_ID) | ||
284 | newTerrainID = ++m_terrainCount; | ||
285 | |||
286 | float[] heightMapX = heightMap; | ||
287 | Vector3 minCoordsX = minCoords; | ||
288 | Vector3 maxCoordsX = maxCoords; | ||
289 | 299 | ||
290 | DetailLog("{0},UpdateTerrain:NewTerrain,call,id={1}, minC={2}, maxC={3}", | 300 | // if this is a child terrain, calculate a unique terrain id |
291 | BSScene.DetailLogZero, newTerrainID, minCoords, minCoords); | 301 | uint newTerrainID = id; |
302 | if (newTerrainID >= BSScene.CHILDTERRAIN_ID) | ||
303 | newTerrainID = ++m_terrainCount; | ||
292 | 304 | ||
293 | // Code that must happen at taint-time | 305 | DetailLog("{0},BSTerrainManager.UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}", |
294 | PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateTerrain:NewTerrain", delegate() | 306 | BSScene.DetailLogZero, newTerrainID, minCoords, minCoords); |
295 | { | ||
296 | DetailLog("{0},UpdateTerrain:NewTerrain,taint,baseX={1},baseY={2}", | ||
297 | BSScene.DetailLogZero, minCoordsX.X, minCoordsX.Y); | ||
298 | BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); | 307 | BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); |
299 | m_terrains.Add(terrainRegionBase, newTerrainPhys); | 308 | m_terrains.Add(terrainRegionBase, newTerrainPhys); |
300 | 309 | ||
301 | m_terrainModified = true; | 310 | m_terrainModified = true; |
302 | }); | 311 | } |
303 | } | 312 | } |
304 | } | 313 | } |
305 | 314 | ||
@@ -308,9 +317,9 @@ public sealed class BSTerrainManager | |||
308 | { | 317 | { |
309 | PhysicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}", | 318 | PhysicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}", |
310 | LogHeader, PhysicsScene.RegionName, terrainRegionBase, | 319 | LogHeader, PhysicsScene.RegionName, terrainRegionBase, |
311 | (BSTerrainPhys.TerrainImplementation)PhysicsScene.Params.terrainImplementation); | 320 | (BSTerrainPhys.TerrainImplementation)BSParam.TerrainImplementation); |
312 | BSTerrainPhys newTerrainPhys = null; | 321 | BSTerrainPhys newTerrainPhys = null; |
313 | switch ((int)PhysicsScene.Params.terrainImplementation) | 322 | switch ((int)BSParam.TerrainImplementation) |
314 | { | 323 | { |
315 | case (int)BSTerrainPhys.TerrainImplementation.Heightmap: | 324 | case (int)BSTerrainPhys.TerrainImplementation.Heightmap: |
316 | newTerrainPhys = new BSTerrainHeightmap(PhysicsScene, terrainRegionBase, id, | 325 | newTerrainPhys = new BSTerrainHeightmap(PhysicsScene, terrainRegionBase, id, |
@@ -323,14 +332,68 @@ public sealed class BSTerrainManager | |||
323 | default: | 332 | default: |
324 | PhysicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}", | 333 | PhysicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}", |
325 | LogHeader, | 334 | LogHeader, |
326 | (int)PhysicsScene.Params.terrainImplementation, | 335 | (int)BSParam.TerrainImplementation, |
327 | PhysicsScene.Params.terrainImplementation, | 336 | BSParam.TerrainImplementation, |
328 | PhysicsScene.RegionName, terrainRegionBase); | 337 | PhysicsScene.RegionName, terrainRegionBase); |
329 | break; | 338 | break; |
330 | } | 339 | } |
331 | return newTerrainPhys; | 340 | return newTerrainPhys; |
332 | } | 341 | } |
333 | 342 | ||
343 | // Return 'true' of this position is somewhere in known physical terrain space | ||
344 | public bool IsWithinKnownTerrain(Vector3 pos) | ||
345 | { | ||
346 | Vector3 terrainBaseXYZ; | ||
347 | BSTerrainPhys physTerrain; | ||
348 | return GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ); | ||
349 | } | ||
350 | |||
351 | // Return a new position that is over known terrain if the position is outside our terrain. | ||
352 | public Vector3 ClampPositionIntoKnownTerrain(Vector3 pPos) | ||
353 | { | ||
354 | Vector3 ret = pPos; | ||
355 | |||
356 | // First, base addresses are never negative so correct for that possible problem. | ||
357 | if (ret.X < 0f || ret.Y < 0f) | ||
358 | { | ||
359 | ret.X = Util.Clamp<float>(ret.X, 0f, 1000000f); | ||
360 | ret.Y = Util.Clamp<float>(ret.Y, 0f, 1000000f); | ||
361 | DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,zeroingNegXorY,oldPos={1},newPos={2}", | ||
362 | BSScene.DetailLogZero, pPos, ret); | ||
363 | } | ||
364 | |||
365 | // Can't do this function if we don't know about any terrain. | ||
366 | if (m_terrains.Count == 0) | ||
367 | return ret; | ||
368 | |||
369 | int loopPrevention = 10; | ||
370 | Vector3 terrainBaseXYZ; | ||
371 | BSTerrainPhys physTerrain; | ||
372 | while (!GetTerrainPhysicalAtXYZ(ret, out physTerrain, out terrainBaseXYZ)) | ||
373 | { | ||
374 | // The passed position is not within a known terrain area. | ||
375 | // NOTE that GetTerrainPhysicalAtXYZ will set 'terrainBaseXYZ' to the base of the unfound region. | ||
376 | |||
377 | // Must be off the top of a region. Find an adjacent region to move into. | ||
378 | Vector3 adjacentTerrainBase = FindAdjacentTerrainBase(terrainBaseXYZ); | ||
379 | |||
380 | ret.X = Math.Min(ret.X, adjacentTerrainBase.X + (ret.X % DefaultRegionSize.X)); | ||
381 | ret.Y = Math.Min(ret.Y, adjacentTerrainBase.Y + (ret.X % DefaultRegionSize.Y)); | ||
382 | DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,findingAdjacentRegion,adjacentRegBase={1},oldPos={2},newPos={3}", | ||
383 | BSScene.DetailLogZero, adjacentTerrainBase, pPos, ret); | ||
384 | |||
385 | if (loopPrevention-- < 0f) | ||
386 | { | ||
387 | // The 'while' is a little dangerous so this prevents looping forever if the | ||
388 | // mapping of the terrains ever gets messed up (like nothing at <0,0>) or | ||
389 | // the list of terrains is in transition. | ||
390 | DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,suppressingFindAdjacentRegionLoop", BSScene.DetailLogZero); | ||
391 | break; | ||
392 | } | ||
393 | } | ||
394 | |||
395 | return ret; | ||
396 | } | ||
334 | 397 | ||
335 | // Given an X and Y, find the height of the terrain. | 398 | // Given an X and Y, find the height of the terrain. |
336 | // Since we could be handling multiple terrains for a mega-region, | 399 | // Since we could be handling multiple terrains for a mega-region, |
@@ -341,40 +404,125 @@ public sealed class BSTerrainManager | |||
341 | private float lastHeightTX = 999999f; | 404 | private float lastHeightTX = 999999f; |
342 | private float lastHeightTY = 999999f; | 405 | private float lastHeightTY = 999999f; |
343 | private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT; | 406 | private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT; |
344 | public float GetTerrainHeightAtXYZ(Vector3 loc) | 407 | public float GetTerrainHeightAtXYZ(Vector3 pos) |
345 | { | 408 | { |
346 | float tX = loc.X; | 409 | float tX = pos.X; |
347 | float tY = loc.Y; | 410 | float tY = pos.Y; |
348 | // You'd be surprized at the number of times this routine is called | 411 | // You'd be surprized at the number of times this routine is called |
349 | // with the same parameters as last time. | 412 | // with the same parameters as last time. |
350 | if (!m_terrainModified && lastHeightTX == tX && lastHeightTY == tY) | 413 | if (!m_terrainModified && (lastHeightTX == tX) && (lastHeightTY == tY)) |
351 | return lastHeight; | 414 | return lastHeight; |
415 | m_terrainModified = false; | ||
352 | 416 | ||
353 | lastHeightTX = tX; | 417 | lastHeightTX = tX; |
354 | lastHeightTY = tY; | 418 | lastHeightTY = tY; |
355 | float ret = HEIGHT_GETHEIGHT_RET; | 419 | float ret = HEIGHT_GETHEIGHT_RET; |
356 | 420 | ||
357 | int offsetX = ((int)(tX / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X; | 421 | Vector3 terrainBaseXYZ; |
358 | int offsetY = ((int)(tY / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y; | ||
359 | Vector3 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f); | ||
360 | |||
361 | BSTerrainPhys physTerrain; | 422 | BSTerrainPhys physTerrain; |
362 | if (m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain)) | 423 | if (GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ)) |
363 | { | 424 | { |
364 | ret = physTerrain.GetHeightAtXYZ(loc - terrainBaseXYZ); | 425 | ret = physTerrain.GetTerrainHeightAtXYZ(pos - terrainBaseXYZ); |
365 | DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,loc={1},base={2},height={3}", | ||
366 | BSScene.DetailLogZero, loc, terrainBaseXYZ, ret); | ||
367 | } | 426 | } |
368 | else | 427 | else |
369 | { | 428 | { |
370 | PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}", | 429 | PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}", |
371 | LogHeader, PhysicsScene.RegionName, tX, tY); | 430 | LogHeader, PhysicsScene.RegionName, tX, tY); |
431 | DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,terrainNotFound,pos={1},base={2}", | ||
432 | BSScene.DetailLogZero, pos, terrainBaseXYZ); | ||
372 | } | 433 | } |
373 | m_terrainModified = false; | 434 | |
374 | lastHeight = ret; | 435 | lastHeight = ret; |
375 | return ret; | 436 | return ret; |
376 | } | 437 | } |
377 | 438 | ||
439 | public float GetWaterLevelAtXYZ(Vector3 pos) | ||
440 | { | ||
441 | float ret = WATER_HEIGHT_GETHEIGHT_RET; | ||
442 | |||
443 | Vector3 terrainBaseXYZ; | ||
444 | BSTerrainPhys physTerrain; | ||
445 | if (GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ)) | ||
446 | { | ||
447 | ret = physTerrain.GetWaterLevelAtXYZ(pos); | ||
448 | } | ||
449 | else | ||
450 | { | ||
451 | PhysicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: pos={1}, terrainBase={2}, height={3}", | ||
452 | LogHeader, PhysicsScene.RegionName, pos, terrainBaseXYZ, ret); | ||
453 | } | ||
454 | return ret; | ||
455 | } | ||
456 | |||
457 | // Given an address, return 'true' of there is a description of that terrain and output | ||
458 | // the descriptor class and the 'base' fo the addresses therein. | ||
459 | private bool GetTerrainPhysicalAtXYZ(Vector3 pos, out BSTerrainPhys outPhysTerrain, out Vector3 outTerrainBase) | ||
460 | { | ||
461 | bool ret = false; | ||
462 | |||
463 | Vector3 terrainBaseXYZ = Vector3.Zero; | ||
464 | if (pos.X < 0f || pos.Y < 0f) | ||
465 | { | ||
466 | // We don't handle negative addresses so just make up a base that will not be found. | ||
467 | terrainBaseXYZ = new Vector3(-DefaultRegionSize.X, -DefaultRegionSize.Y, 0f); | ||
468 | } | ||
469 | else | ||
470 | { | ||
471 | int offsetX = ((int)(pos.X / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X; | ||
472 | int offsetY = ((int)(pos.Y / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y; | ||
473 | terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f); | ||
474 | } | ||
475 | |||
476 | BSTerrainPhys physTerrain = null; | ||
477 | lock (m_terrains) | ||
478 | { | ||
479 | ret = m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain); | ||
480 | } | ||
481 | outTerrainBase = terrainBaseXYZ; | ||
482 | outPhysTerrain = physTerrain; | ||
483 | return ret; | ||
484 | } | ||
485 | |||
486 | // Given a terrain base, return a terrain base for a terrain that is closer to <0,0> than | ||
487 | // this one. Usually used to return an out of bounds object to a known place. | ||
488 | private Vector3 FindAdjacentTerrainBase(Vector3 pTerrainBase) | ||
489 | { | ||
490 | Vector3 ret = pTerrainBase; | ||
491 | |||
492 | // Can't do this function if we don't know about any terrain. | ||
493 | if (m_terrains.Count == 0) | ||
494 | return ret; | ||
495 | |||
496 | // Just some sanity | ||
497 | ret.X = Util.Clamp<float>(ret.X, 0f, 1000000f); | ||
498 | ret.Y = Util.Clamp<float>(ret.Y, 0f, 1000000f); | ||
499 | ret.Z = 0f; | ||
500 | |||
501 | lock (m_terrains) | ||
502 | { | ||
503 | // Once down to the <0,0> region, we have to be done. | ||
504 | while (ret.X > 0f || ret.Y > 0f) | ||
505 | { | ||
506 | if (ret.X > 0f) | ||
507 | { | ||
508 | ret.X = Math.Max(0f, ret.X - DefaultRegionSize.X); | ||
509 | DetailLog("{0},BSTerrainManager.FindAdjacentTerrainBase,reducingX,terrainBase={1}", BSScene.DetailLogZero, ret); | ||
510 | if (m_terrains.ContainsKey(ret)) | ||
511 | break; | ||
512 | } | ||
513 | if (ret.Y > 0f) | ||
514 | { | ||
515 | ret.Y = Math.Max(0f, ret.Y - DefaultRegionSize.Y); | ||
516 | DetailLog("{0},BSTerrainManager.FindAdjacentTerrainBase,reducingY,terrainBase={1}", BSScene.DetailLogZero, ret); | ||
517 | if (m_terrains.ContainsKey(ret)) | ||
518 | break; | ||
519 | } | ||
520 | } | ||
521 | } | ||
522 | |||
523 | return ret; | ||
524 | } | ||
525 | |||
378 | // Although no one seems to check this, I do support combining. | 526 | // Although no one seems to check this, I do support combining. |
379 | public bool SupportsCombining() | 527 | public bool SupportsCombining() |
380 | { | 528 | { |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs index dca7150..2ce1513 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs | |||
@@ -76,27 +76,43 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
76 | m_sizeX = (int)(maxCoords.X - minCoords.X); | 76 | m_sizeX = (int)(maxCoords.X - minCoords.X); |
77 | m_sizeY = (int)(maxCoords.Y - minCoords.Y); | 77 | m_sizeY = (int)(maxCoords.Y - minCoords.Y); |
78 | 78 | ||
79 | if (!BSTerrainMesh.ConvertHeightmapToMesh(PhysicsScene, initialMap, | 79 | bool meshCreationSuccess = false; |
80 | m_sizeX, m_sizeY, | 80 | if (BSParam.TerrainMeshMagnification == 1) |
81 | (float)m_sizeX, (float)m_sizeY, | 81 | { |
82 | Vector3.Zero, 1.0f, | 82 | // If a magnification of one, use the old routine that is tried and true. |
83 | out indicesCount, out indices, out verticesCount, out vertices)) | 83 | meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh(PhysicsScene, |
84 | initialMap, m_sizeX, m_sizeY, // input size | ||
85 | Vector3.Zero, // base for mesh | ||
86 | out indicesCount, out indices, out verticesCount, out vertices); | ||
87 | } | ||
88 | else | ||
89 | { | ||
90 | // Other magnifications use the newer routine | ||
91 | meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh2(PhysicsScene, | ||
92 | initialMap, m_sizeX, m_sizeY, // input size | ||
93 | BSParam.TerrainMeshMagnification, | ||
94 | physicsScene.TerrainManager.DefaultRegionSize, | ||
95 | Vector3.Zero, // base for mesh | ||
96 | out indicesCount, out indices, out verticesCount, out vertices); | ||
97 | } | ||
98 | if (!meshCreationSuccess) | ||
84 | { | 99 | { |
85 | // DISASTER!! | 100 | // DISASTER!! |
86 | PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap", ID); | 101 | PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap,id={1}", BSScene.DetailLogZero, ID); |
87 | PhysicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh! base={1}", LogHeader, TerrainBase); | 102 | PhysicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh! base={1}", LogHeader, TerrainBase); |
88 | // Something is very messed up and a crash is in our future. | 103 | // Something is very messed up and a crash is in our future. |
89 | return; | 104 | return; |
90 | } | 105 | } |
91 | 106 | ||
92 | m_terrainShape = new BulletShape(BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr, | 107 | PhysicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,id={1},indices={2},indSz={3},vertices={4},vertSz={5}", |
93 | indicesCount, indices, verticesCount, vertices), | 108 | BSScene.DetailLogZero, ID, indicesCount, indices.Length, verticesCount, vertices.Length); |
94 | BSPhysicsShapeType.SHAPE_MESH); | 109 | |
95 | if (m_terrainShape.ptr == IntPtr.Zero) | 110 | m_terrainShape = PhysicsScene.PE.CreateMeshShape(PhysicsScene.World, indicesCount, indices, verticesCount, vertices); |
111 | if (!m_terrainShape.HasPhysicalShape) | ||
96 | { | 112 | { |
97 | // DISASTER!! | 113 | // DISASTER!! |
98 | PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape", ID); | 114 | PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape,id={1}", BSScene.DetailLogZero, ID); |
99 | physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain mesh! base={1}", LogHeader, TerrainBase); | 115 | PhysicsScene.Logger.ErrorFormat("{0} Failed creation of terrain mesh! base={1}", LogHeader, TerrainBase); |
100 | // Something is very messed up and a crash is in our future. | 116 | // Something is very messed up and a crash is in our future. |
101 | return; | 117 | return; |
102 | } | 118 | } |
@@ -104,49 +120,58 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
104 | Vector3 pos = regionBase; | 120 | Vector3 pos = regionBase; |
105 | Quaternion rot = Quaternion.Identity; | 121 | Quaternion rot = Quaternion.Identity; |
106 | 122 | ||
107 | m_terrainBody = new BulletBody(id, BulletSimAPI.CreateBodyWithDefaultMotionState2( m_terrainShape.ptr, ID, pos, rot)); | 123 | m_terrainBody = PhysicsScene.PE.CreateBodyWithDefaultMotionState(m_terrainShape, ID, pos, rot); |
108 | if (m_terrainBody.ptr == IntPtr.Zero) | 124 | if (!m_terrainBody.HasPhysicalBody) |
109 | { | 125 | { |
110 | // DISASTER!! | 126 | // DISASTER!! |
111 | physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase); | 127 | PhysicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase); |
112 | // Something is very messed up and a crash is in our future. | 128 | // Something is very messed up and a crash is in our future. |
113 | return; | 129 | return; |
114 | } | 130 | } |
131 | physicsScene.PE.SetShapeCollisionMargin(m_terrainShape, BSParam.TerrainCollisionMargin); | ||
115 | 132 | ||
116 | // Set current terrain attributes | 133 | // Set current terrain attributes |
117 | BulletSimAPI.SetFriction2(m_terrainBody.ptr, PhysicsScene.Params.terrainFriction); | 134 | PhysicsScene.PE.SetFriction(m_terrainBody, BSParam.TerrainFriction); |
118 | BulletSimAPI.SetHitFraction2(m_terrainBody.ptr, PhysicsScene.Params.terrainHitFraction); | 135 | PhysicsScene.PE.SetHitFraction(m_terrainBody, BSParam.TerrainHitFraction); |
119 | BulletSimAPI.SetRestitution2(m_terrainBody.ptr, PhysicsScene.Params.terrainRestitution); | 136 | PhysicsScene.PE.SetRestitution(m_terrainBody, BSParam.TerrainRestitution); |
120 | BulletSimAPI.SetCollisionFlags2(m_terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT); | 137 | PhysicsScene.PE.SetContactProcessingThreshold(m_terrainBody, BSParam.TerrainContactProcessingThreshold); |
138 | PhysicsScene.PE.SetCollisionFlags(m_terrainBody, CollisionFlags.CF_STATIC_OBJECT); | ||
121 | 139 | ||
122 | // Static objects are not very massive. | 140 | // Static objects are not very massive. |
123 | BulletSimAPI.SetMassProps2(m_terrainBody.ptr, 0f, Vector3.Zero); | 141 | PhysicsScene.PE.SetMassProps(m_terrainBody, 0f, Vector3.Zero); |
124 | 142 | ||
125 | // Return the new terrain to the world of physical objects | 143 | // Put the new terrain to the world of physical objects |
126 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr); | 144 | PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_terrainBody); |
127 | 145 | ||
128 | // redo its bounding box now that it is in the world | 146 | // Redo its bounding box now that it is in the world |
129 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_terrainBody.ptr); | 147 | PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_terrainBody); |
130 | 148 | ||
131 | BulletSimAPI.SetCollisionFilterMask2(m_terrainBody.ptr, | 149 | m_terrainBody.collisionType = CollisionType.Terrain; |
132 | (uint)CollisionFilterGroups.TerrainFilter, | 150 | m_terrainBody.ApplyCollisionMask(PhysicsScene); |
133 | (uint)CollisionFilterGroups.TerrainMask); | 151 | |
152 | if (BSParam.UseSingleSidedMeshes) | ||
153 | { | ||
154 | PhysicsScene.DetailLog("{0},BSTerrainMesh.settingCustomMaterial,id={1}", BSScene.DetailLogZero, id); | ||
155 | PhysicsScene.PE.AddToCollisionFlags(m_terrainBody, CollisionFlags.CF_CUSTOM_MATERIAL_CALLBACK); | ||
156 | } | ||
134 | 157 | ||
135 | // Make it so the terrain will not move or be considered for movement. | 158 | // Make it so the terrain will not move or be considered for movement. |
136 | BulletSimAPI.ForceActivationState2(m_terrainBody.ptr, ActivationState.DISABLE_SIMULATION); | 159 | PhysicsScene.PE.ForceActivationState(m_terrainBody, ActivationState.DISABLE_SIMULATION); |
137 | } | 160 | } |
138 | 161 | ||
139 | public override void Dispose() | 162 | public override void Dispose() |
140 | { | 163 | { |
141 | if (m_terrainBody.ptr != IntPtr.Zero) | 164 | if (m_terrainBody.HasPhysicalBody) |
142 | { | 165 | { |
143 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr); | 166 | PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_terrainBody); |
144 | // Frees both the body and the shape. | 167 | // Frees both the body and the shape. |
145 | BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_terrainBody.ptr); | 168 | PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_terrainBody); |
169 | m_terrainBody.Clear(); | ||
170 | m_terrainShape.Clear(); | ||
146 | } | 171 | } |
147 | } | 172 | } |
148 | 173 | ||
149 | public override float GetHeightAtXYZ(Vector3 pos) | 174 | public override float GetTerrainHeightAtXYZ(Vector3 pos) |
150 | { | 175 | { |
151 | // For the moment use the saved heightmap to get the terrain height. | 176 | // For the moment use the saved heightmap to get the terrain height. |
152 | // TODO: raycast downward to find the true terrain below the position. | 177 | // TODO: raycast downward to find the true terrain below the position. |
@@ -167,14 +192,17 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
167 | return ret; | 192 | return ret; |
168 | } | 193 | } |
169 | 194 | ||
195 | // The passed position is relative to the base of the region. | ||
196 | public override float GetWaterLevelAtXYZ(Vector3 pos) | ||
197 | { | ||
198 | return PhysicsScene.SimpleWaterLevel; | ||
199 | } | ||
200 | |||
170 | // Convert the passed heightmap to mesh information suitable for CreateMeshShape2(). | 201 | // Convert the passed heightmap to mesh information suitable for CreateMeshShape2(). |
171 | // Return 'true' if successfully created. | 202 | // Return 'true' if successfully created. |
172 | public static bool ConvertHeightmapToMesh( | 203 | public static bool ConvertHeightmapToMesh( BSScene physicsScene, |
173 | BSScene physicsScene, | ||
174 | float[] heightMap, int sizeX, int sizeY, // parameters of incoming heightmap | 204 | float[] heightMap, int sizeX, int sizeY, // parameters of incoming heightmap |
175 | float extentX, float extentY, // zero based range for output vertices | ||
176 | Vector3 extentBase, // base to be added to all vertices | 205 | Vector3 extentBase, // base to be added to all vertices |
177 | float magnification, // number of vertices to create between heightMap coords | ||
178 | out int indicesCountO, out int[] indicesO, | 206 | out int indicesCountO, out int[] indicesO, |
179 | out int verticesCountO, out float[] verticesO) | 207 | out int verticesCountO, out float[] verticesO) |
180 | { | 208 | { |
@@ -188,43 +216,47 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
188 | // Simple mesh creation which assumes magnification == 1. | 216 | // Simple mesh creation which assumes magnification == 1. |
189 | // TODO: do a more general solution that scales, adds new vertices and smoothes the result. | 217 | // TODO: do a more general solution that scales, adds new vertices and smoothes the result. |
190 | 218 | ||
219 | // Create an array of vertices that is sizeX+1 by sizeY+1 (note the loop | ||
220 | // from zero to <= sizeX). The triangle indices are then generated as two triangles | ||
221 | // per heightmap point. There are sizeX by sizeY of these squares. The extra row and | ||
222 | // column of vertices are used to complete the triangles of the last row and column | ||
223 | // of the heightmap. | ||
191 | try | 224 | try |
192 | { | 225 | { |
193 | // One vertice per heightmap value plus the vertices off the top and bottom edge. | 226 | // One vertice per heightmap value plus the vertices off the side and bottom edge. |
194 | int totalVertices = (sizeX + 1) * (sizeY + 1); | 227 | int totalVertices = (sizeX + 1) * (sizeY + 1); |
195 | vertices = new float[totalVertices * 3]; | 228 | vertices = new float[totalVertices * 3]; |
196 | int totalIndices = sizeX * sizeY * 6; | 229 | int totalIndices = sizeX * sizeY * 6; |
197 | indices = new int[totalIndices]; | 230 | indices = new int[totalIndices]; |
198 | 231 | ||
199 | float magX = (float)sizeX / extentX; | 232 | if (physicsScene != null) |
200 | float magY = (float)sizeY / extentY; | 233 | physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3}", |
201 | physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}", | 234 | BSScene.DetailLogZero, totalVertices, totalIndices, extentBase); |
202 | BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY); | 235 | float minHeight = float.MaxValue; |
203 | // Note that sizeX+1 vertices are created since there is land between this and the next region. | 236 | // Note that sizeX+1 vertices are created since there is land between this and the next region. |
204 | for (int yy = 0; yy <= sizeY; yy++) | 237 | for (int yy = 0; yy <= sizeY; yy++) |
205 | { | 238 | { |
206 | for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we got through sizeX + 1 times | 239 | for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we go around sizeX + 1 times |
207 | { | 240 | { |
208 | int offset = yy * sizeX + xx; | 241 | int offset = yy * sizeX + xx; |
209 | // Extend the height from the height from the last row or column | 242 | // Extend the height with the height from the last row or column |
210 | if (yy == sizeY) offset -= sizeX; | 243 | if (yy == sizeY) offset -= sizeX; |
211 | if (xx == sizeX) offset -= 1; | 244 | if (xx == sizeX) offset -= 1; |
212 | float height = heightMap[offset]; | 245 | float height = heightMap[offset]; |
213 | vertices[verticesCount + 0] = (float)xx * magX + extentBase.X; | 246 | minHeight = Math.Min(minHeight, height); |
214 | vertices[verticesCount + 1] = (float)yy * magY + extentBase.Y; | 247 | vertices[verticesCount + 0] = (float)xx + extentBase.X; |
248 | vertices[verticesCount + 1] = (float)yy + extentBase.Y; | ||
215 | vertices[verticesCount + 2] = height + extentBase.Z; | 249 | vertices[verticesCount + 2] = height + extentBase.Z; |
216 | verticesCount += 3; | 250 | verticesCount += 3; |
217 | } | 251 | } |
218 | } | 252 | } |
219 | verticesCount = verticesCount / 3; | 253 | verticesCount = verticesCount / 3; |
220 | physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,completeVerts,verCount={1}", | ||
221 | BSScene.DetailLogZero, verticesCount); | ||
222 | 254 | ||
223 | for (int yy = 0; yy < sizeY; yy++) | 255 | for (int yy = 0; yy < sizeY; yy++) |
224 | { | 256 | { |
225 | for (int xx = 0; xx < sizeX; xx++) | 257 | for (int xx = 0; xx < sizeX; xx++) |
226 | { | 258 | { |
227 | int offset = yy * sizeX + xx; | 259 | int offset = yy * (sizeX + 1) + xx; |
228 | // Each vertices is presumed to be the upper left corner of a box of two triangles | 260 | // Each vertices is presumed to be the upper left corner of a box of two triangles |
229 | indices[indicesCount + 0] = offset; | 261 | indices[indicesCount + 0] = offset; |
230 | indices[indicesCount + 1] = offset + 1; | 262 | indices[indicesCount + 1] = offset + 1; |
@@ -235,13 +267,166 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
235 | indicesCount += 6; | 267 | indicesCount += 6; |
236 | } | 268 | } |
237 | } | 269 | } |
238 | physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,completeIndices,indCount={1}", // DEEBUG DEBUG DEBUG | 270 | |
239 | LogHeader, indicesCount); // DEBUG | 271 | ret = true; |
272 | } | ||
273 | catch (Exception e) | ||
274 | { | ||
275 | if (physicsScene != null) | ||
276 | physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}", | ||
277 | LogHeader, physicsScene.RegionName, extentBase, e); | ||
278 | } | ||
279 | |||
280 | indicesCountO = indicesCount; | ||
281 | indicesO = indices; | ||
282 | verticesCountO = verticesCount; | ||
283 | verticesO = vertices; | ||
284 | |||
285 | return ret; | ||
286 | } | ||
287 | |||
288 | private class HeightMapGetter | ||
289 | { | ||
290 | private float[] m_heightMap; | ||
291 | private int m_sizeX; | ||
292 | private int m_sizeY; | ||
293 | public HeightMapGetter(float[] pHeightMap, int pSizeX, int pSizeY) | ||
294 | { | ||
295 | m_heightMap = pHeightMap; | ||
296 | m_sizeX = pSizeX; | ||
297 | m_sizeY = pSizeY; | ||
298 | } | ||
299 | // The heightmap is extended as an infinite plane at the last height | ||
300 | public float GetHeight(int xx, int yy) | ||
301 | { | ||
302 | int offset = 0; | ||
303 | // Extend the height with the height from the last row or column | ||
304 | if (yy >= m_sizeY) | ||
305 | if (xx >= m_sizeX) | ||
306 | offset = (m_sizeY - 1) * m_sizeX + (m_sizeX - 1); | ||
307 | else | ||
308 | offset = (m_sizeY - 1) * m_sizeX + xx; | ||
309 | else | ||
310 | if (xx >= m_sizeX) | ||
311 | offset = yy * m_sizeX + (m_sizeX - 1); | ||
312 | else | ||
313 | offset = yy * m_sizeX + xx; | ||
314 | |||
315 | return m_heightMap[offset]; | ||
316 | } | ||
317 | } | ||
318 | |||
319 | // Convert the passed heightmap to mesh information suitable for CreateMeshShape2(). | ||
320 | // Version that handles magnification. | ||
321 | // Return 'true' if successfully created. | ||
322 | public static bool ConvertHeightmapToMesh2( BSScene physicsScene, | ||
323 | float[] heightMap, int sizeX, int sizeY, // parameters of incoming heightmap | ||
324 | int magnification, // number of vertices per heighmap step | ||
325 | Vector3 extent, // dimensions of the output mesh | ||
326 | Vector3 extentBase, // base to be added to all vertices | ||
327 | out int indicesCountO, out int[] indicesO, | ||
328 | out int verticesCountO, out float[] verticesO) | ||
329 | { | ||
330 | bool ret = false; | ||
331 | |||
332 | int indicesCount = 0; | ||
333 | int verticesCount = 0; | ||
334 | int[] indices = new int[0]; | ||
335 | float[] vertices = new float[0]; | ||
336 | |||
337 | HeightMapGetter hmap = new HeightMapGetter(heightMap, sizeX, sizeY); | ||
338 | |||
339 | // The vertices dimension of the output mesh | ||
340 | int meshX = sizeX * magnification; | ||
341 | int meshY = sizeY * magnification; | ||
342 | // The output size of one mesh step | ||
343 | float meshXStep = extent.X / meshX; | ||
344 | float meshYStep = extent.Y / meshY; | ||
345 | |||
346 | // Create an array of vertices that is meshX+1 by meshY+1 (note the loop | ||
347 | // from zero to <= meshX). The triangle indices are then generated as two triangles | ||
348 | // per heightmap point. There are meshX by meshY of these squares. The extra row and | ||
349 | // column of vertices are used to complete the triangles of the last row and column | ||
350 | // of the heightmap. | ||
351 | try | ||
352 | { | ||
353 | // Vertices for the output heightmap plus one on the side and bottom to complete triangles | ||
354 | int totalVertices = (meshX + 1) * (meshY + 1); | ||
355 | vertices = new float[totalVertices * 3]; | ||
356 | int totalIndices = meshX * meshY * 6; | ||
357 | indices = new int[totalIndices]; | ||
358 | |||
359 | if (physicsScene != null) | ||
360 | physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh2,inSize={1},outSize={2},totVert={3},totInd={4},extentBase={5}", | ||
361 | BSScene.DetailLogZero, new Vector2(sizeX, sizeY), new Vector2(meshX, meshY), | ||
362 | totalVertices, totalIndices, extentBase); | ||
363 | |||
364 | float minHeight = float.MaxValue; | ||
365 | // Note that sizeX+1 vertices are created since there is land between this and the next region. | ||
366 | // Loop through the output vertices and compute the mediun height in between the input vertices | ||
367 | for (int yy = 0; yy <= meshY; yy++) | ||
368 | { | ||
369 | for (int xx = 0; xx <= meshX; xx++) // Hint: the "<=" means we go around sizeX + 1 times | ||
370 | { | ||
371 | float offsetY = (float)yy * (float)sizeY / (float)meshY; // The Y that is closest to the mesh point | ||
372 | int stepY = (int)offsetY; | ||
373 | float fractionalY = offsetY - (float)stepY; | ||
374 | float offsetX = (float)xx * (float)sizeX / (float)meshX; // The X that is closest to the mesh point | ||
375 | int stepX = (int)offsetX; | ||
376 | float fractionalX = offsetX - (float)stepX; | ||
377 | |||
378 | // physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh2,xx={1},yy={2},offX={3},stepX={4},fractX={5},offY={6},stepY={7},fractY={8}", | ||
379 | // BSScene.DetailLogZero, xx, yy, offsetX, stepX, fractionalX, offsetY, stepY, fractionalY); | ||
380 | |||
381 | // get the four corners of the heightmap square the mesh point is in | ||
382 | float heightUL = hmap.GetHeight(stepX , stepY ); | ||
383 | float heightUR = hmap.GetHeight(stepX + 1, stepY ); | ||
384 | float heightLL = hmap.GetHeight(stepX , stepY + 1); | ||
385 | float heightLR = hmap.GetHeight(stepX + 1, stepY + 1); | ||
386 | |||
387 | // bilinear interplolation | ||
388 | float height = heightUL * (1 - fractionalX) * (1 - fractionalY) | ||
389 | + heightUR * fractionalX * (1 - fractionalY) | ||
390 | + heightLL * (1 - fractionalX) * fractionalY | ||
391 | + heightLR * fractionalX * fractionalY; | ||
392 | |||
393 | // physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh2,heightUL={1},heightUR={2},heightLL={3},heightLR={4},heightMap={5}", | ||
394 | // BSScene.DetailLogZero, heightUL, heightUR, heightLL, heightLR, height); | ||
395 | |||
396 | minHeight = Math.Min(minHeight, height); | ||
397 | |||
398 | vertices[verticesCount + 0] = (float)xx * meshXStep + extentBase.X; | ||
399 | vertices[verticesCount + 1] = (float)yy * meshYStep + extentBase.Y; | ||
400 | vertices[verticesCount + 2] = height + extentBase.Z; | ||
401 | verticesCount += 3; | ||
402 | } | ||
403 | } | ||
404 | // The number of vertices generated | ||
405 | verticesCount /= 3; | ||
406 | |||
407 | // Loop through all the heightmap squares and create indices for the two triangles for that square | ||
408 | for (int yy = 0; yy < meshY; yy++) | ||
409 | { | ||
410 | for (int xx = 0; xx < meshX; xx++) | ||
411 | { | ||
412 | int offset = yy * (meshX + 1) + xx; | ||
413 | // Each vertices is presumed to be the upper left corner of a box of two triangles | ||
414 | indices[indicesCount + 0] = offset; | ||
415 | indices[indicesCount + 1] = offset + 1; | ||
416 | indices[indicesCount + 2] = offset + meshX + 1; // accounting for the extra column | ||
417 | indices[indicesCount + 3] = offset + 1; | ||
418 | indices[indicesCount + 4] = offset + meshX + 2; | ||
419 | indices[indicesCount + 5] = offset + meshX + 1; | ||
420 | indicesCount += 6; | ||
421 | } | ||
422 | } | ||
423 | |||
240 | ret = true; | 424 | ret = true; |
241 | } | 425 | } |
242 | catch (Exception e) | 426 | catch (Exception e) |
243 | { | 427 | { |
244 | physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}", | 428 | if (physicsScene != null) |
429 | physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}", | ||
245 | LogHeader, physicsScene.RegionName, extentBase, e); | 430 | LogHeader, physicsScene.RegionName, extentBase, e); |
246 | } | 431 | } |
247 | 432 | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs deleted file mode 100644 index e60a760..0000000 --- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs +++ /dev/null | |||
@@ -1,1015 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyrightD | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | using System; | ||
28 | using System.Runtime.InteropServices; | ||
29 | using System.Security; | ||
30 | using System.Text; | ||
31 | using OpenMetaverse; | ||
32 | |||
33 | namespace OpenSim.Region.Physics.BulletSPlugin { | ||
34 | |||
35 | // Classes to allow some type checking for the API | ||
36 | // These hold pointers to allocated objects in the unmanaged space. | ||
37 | |||
38 | // The physics engine controller class created at initialization | ||
39 | public struct BulletSim | ||
40 | { | ||
41 | public BulletSim(uint worldId, BSScene bss, IntPtr xx) | ||
42 | { | ||
43 | ptr = xx; | ||
44 | worldID = worldId; | ||
45 | physicsScene = bss; | ||
46 | } | ||
47 | public IntPtr ptr; | ||
48 | public uint worldID; | ||
49 | // The scene is only in here so very low level routines have a handle to print debug/error messages | ||
50 | public BSScene physicsScene; | ||
51 | } | ||
52 | |||
53 | // An allocated Bullet btRigidBody | ||
54 | public struct BulletBody | ||
55 | { | ||
56 | public BulletBody(uint id, IntPtr xx) | ||
57 | { | ||
58 | ID = id; | ||
59 | ptr = xx; | ||
60 | collisionFilter = 0; | ||
61 | collisionMask = 0; | ||
62 | } | ||
63 | public IntPtr ptr; | ||
64 | public uint ID; | ||
65 | public CollisionFilterGroups collisionFilter; | ||
66 | public CollisionFilterGroups collisionMask; | ||
67 | public override string ToString() | ||
68 | { | ||
69 | StringBuilder buff = new StringBuilder(); | ||
70 | buff.Append("<id="); | ||
71 | buff.Append(ID.ToString()); | ||
72 | buff.Append(",p="); | ||
73 | buff.Append(ptr.ToString("X")); | ||
74 | if (collisionFilter != 0 || collisionMask != 0) | ||
75 | { | ||
76 | buff.Append(",f="); | ||
77 | buff.Append(collisionFilter.ToString("X")); | ||
78 | buff.Append(",m="); | ||
79 | buff.Append(collisionMask.ToString("X")); | ||
80 | } | ||
81 | buff.Append(">"); | ||
82 | return buff.ToString(); | ||
83 | } | ||
84 | } | ||
85 | |||
86 | public struct BulletShape | ||
87 | { | ||
88 | public BulletShape(IntPtr xx) | ||
89 | { | ||
90 | ptr = xx; | ||
91 | type=BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
92 | shapeKey = (System.UInt64)FixedShapeKey.KEY_NONE; | ||
93 | isNativeShape = false; | ||
94 | } | ||
95 | public BulletShape(IntPtr xx, BSPhysicsShapeType typ) | ||
96 | { | ||
97 | ptr = xx; | ||
98 | type = typ; | ||
99 | shapeKey = 0; | ||
100 | isNativeShape = false; | ||
101 | } | ||
102 | public IntPtr ptr; | ||
103 | public BSPhysicsShapeType type; | ||
104 | public System.UInt64 shapeKey; | ||
105 | public bool isNativeShape; | ||
106 | public override string ToString() | ||
107 | { | ||
108 | StringBuilder buff = new StringBuilder(); | ||
109 | buff.Append("<p="); | ||
110 | buff.Append(ptr.ToString("X")); | ||
111 | buff.Append(",s="); | ||
112 | buff.Append(type.ToString()); | ||
113 | buff.Append(",k="); | ||
114 | buff.Append(shapeKey.ToString("X")); | ||
115 | buff.Append(",n="); | ||
116 | buff.Append(isNativeShape.ToString()); | ||
117 | buff.Append(">"); | ||
118 | return buff.ToString(); | ||
119 | } | ||
120 | } | ||
121 | |||
122 | // Constraint type values as defined by Bullet | ||
123 | public enum ConstraintType : int | ||
124 | { | ||
125 | POINT2POINT_CONSTRAINT_TYPE = 3, | ||
126 | HINGE_CONSTRAINT_TYPE, | ||
127 | CONETWIST_CONSTRAINT_TYPE, | ||
128 | D6_CONSTRAINT_TYPE, | ||
129 | SLIDER_CONSTRAINT_TYPE, | ||
130 | CONTACT_CONSTRAINT_TYPE, | ||
131 | D6_SPRING_CONSTRAINT_TYPE, | ||
132 | MAX_CONSTRAINT_TYPE | ||
133 | } | ||
134 | |||
135 | // An allocated Bullet btConstraint | ||
136 | public struct BulletConstraint | ||
137 | { | ||
138 | public BulletConstraint(IntPtr xx) | ||
139 | { | ||
140 | ptr = xx; | ||
141 | } | ||
142 | public IntPtr ptr; | ||
143 | } | ||
144 | |||
145 | // An allocated HeightMapThing which holds various heightmap info. | ||
146 | // Made a class rather than a struct so there would be only one | ||
147 | // instance of this and C# will pass around pointers rather | ||
148 | // than making copies. | ||
149 | public class BulletHeightMapInfo | ||
150 | { | ||
151 | public BulletHeightMapInfo(uint id, float[] hm, IntPtr xx) { | ||
152 | ID = id; | ||
153 | Ptr = xx; | ||
154 | heightMap = hm; | ||
155 | terrainRegionBase = Vector3.Zero; | ||
156 | minCoords = new Vector3(100f, 100f, 25f); | ||
157 | maxCoords = new Vector3(101f, 101f, 26f); | ||
158 | minZ = maxZ = 0f; | ||
159 | sizeX = sizeY = 256f; | ||
160 | } | ||
161 | public uint ID; | ||
162 | public IntPtr Ptr; | ||
163 | public float[] heightMap; | ||
164 | public Vector3 terrainRegionBase; | ||
165 | public Vector3 minCoords; | ||
166 | public Vector3 maxCoords; | ||
167 | public float sizeX, sizeY; | ||
168 | public float minZ, maxZ; | ||
169 | public BulletShape terrainShape; | ||
170 | public BulletBody terrainBody; | ||
171 | } | ||
172 | |||
173 | // =============================================================================== | ||
174 | [StructLayout(LayoutKind.Sequential)] | ||
175 | public struct ConvexHull | ||
176 | { | ||
177 | Vector3 Offset; | ||
178 | int VertexCount; | ||
179 | Vector3[] Vertices; | ||
180 | } | ||
181 | public enum BSPhysicsShapeType | ||
182 | { | ||
183 | SHAPE_UNKNOWN = 0, | ||
184 | SHAPE_CAPSULE = 1, | ||
185 | SHAPE_BOX = 2, | ||
186 | SHAPE_CONE = 3, | ||
187 | SHAPE_CYLINDER = 4, | ||
188 | SHAPE_SPHERE = 5, | ||
189 | SHAPE_MESH = 6, | ||
190 | SHAPE_HULL = 7, | ||
191 | // following defined by BulletSim | ||
192 | SHAPE_GROUNDPLANE = 20, | ||
193 | SHAPE_TERRAIN = 21, | ||
194 | SHAPE_COMPOUND = 22, | ||
195 | SHAPE_HEIGHTMAP = 23, | ||
196 | }; | ||
197 | |||
198 | // The native shapes have predefined shape hash keys | ||
199 | public enum FixedShapeKey : ulong | ||
200 | { | ||
201 | KEY_NONE = 0, | ||
202 | KEY_BOX = 1, | ||
203 | KEY_SPHERE = 2, | ||
204 | KEY_CONE = 3, | ||
205 | KEY_CYLINDER = 4, | ||
206 | KEY_CAPSULE = 5, | ||
207 | } | ||
208 | |||
209 | [StructLayout(LayoutKind.Sequential)] | ||
210 | public struct ShapeData | ||
211 | { | ||
212 | public uint ID; | ||
213 | public BSPhysicsShapeType Type; | ||
214 | public Vector3 Position; | ||
215 | public Quaternion Rotation; | ||
216 | public Vector3 Velocity; | ||
217 | public Vector3 Scale; | ||
218 | public float Mass; | ||
219 | public float Buoyancy; | ||
220 | public System.UInt64 HullKey; | ||
221 | public System.UInt64 MeshKey; | ||
222 | public float Friction; | ||
223 | public float Restitution; | ||
224 | public float Collidable; // true of things bump into this | ||
225 | public float Static; // true if a static object. Otherwise gravity, etc. | ||
226 | public float Solid; // true if object cannot be passed through | ||
227 | public Vector3 Size; | ||
228 | |||
229 | // note that bools are passed as floats since bool size changes by language and architecture | ||
230 | public const float numericTrue = 1f; | ||
231 | public const float numericFalse = 0f; | ||
232 | } | ||
233 | [StructLayout(LayoutKind.Sequential)] | ||
234 | public struct SweepHit | ||
235 | { | ||
236 | public uint ID; | ||
237 | public float Fraction; | ||
238 | public Vector3 Normal; | ||
239 | public Vector3 Point; | ||
240 | } | ||
241 | [StructLayout(LayoutKind.Sequential)] | ||
242 | public struct RaycastHit | ||
243 | { | ||
244 | public uint ID; | ||
245 | public float Fraction; | ||
246 | public Vector3 Normal; | ||
247 | } | ||
248 | [StructLayout(LayoutKind.Sequential)] | ||
249 | public struct CollisionDesc | ||
250 | { | ||
251 | public uint aID; | ||
252 | public uint bID; | ||
253 | public Vector3 point; | ||
254 | public Vector3 normal; | ||
255 | } | ||
256 | [StructLayout(LayoutKind.Sequential)] | ||
257 | public struct EntityProperties | ||
258 | { | ||
259 | public uint ID; | ||
260 | public Vector3 Position; | ||
261 | public Quaternion Rotation; | ||
262 | public Vector3 Velocity; | ||
263 | public Vector3 Acceleration; | ||
264 | public Vector3 RotationalVelocity; | ||
265 | } | ||
266 | |||
267 | // Format of this structure must match the definition in the C++ code | ||
268 | [StructLayout(LayoutKind.Sequential)] | ||
269 | public struct ConfigurationParameters | ||
270 | { | ||
271 | public float defaultFriction; | ||
272 | public float defaultDensity; | ||
273 | public float defaultRestitution; | ||
274 | public float collisionMargin; | ||
275 | public float gravity; | ||
276 | |||
277 | public float linearDamping; | ||
278 | public float angularDamping; | ||
279 | public float deactivationTime; | ||
280 | public float linearSleepingThreshold; | ||
281 | public float angularSleepingThreshold; | ||
282 | public float ccdMotionThreshold; | ||
283 | public float ccdSweptSphereRadius; | ||
284 | public float contactProcessingThreshold; | ||
285 | |||
286 | public float terrainImplementation; | ||
287 | public float terrainFriction; | ||
288 | public float terrainHitFraction; | ||
289 | public float terrainRestitution; | ||
290 | public float avatarFriction; | ||
291 | public float avatarStandingFriction; | ||
292 | public float avatarDensity; | ||
293 | public float avatarRestitution; | ||
294 | public float avatarCapsuleWidth; | ||
295 | public float avatarCapsuleDepth; | ||
296 | public float avatarCapsuleHeight; | ||
297 | public float avatarContactProcessingThreshold; | ||
298 | |||
299 | public float maxPersistantManifoldPoolSize; | ||
300 | public float maxCollisionAlgorithmPoolSize; | ||
301 | public float shouldDisableContactPoolDynamicAllocation; | ||
302 | public float shouldForceUpdateAllAabbs; | ||
303 | public float shouldRandomizeSolverOrder; | ||
304 | public float shouldSplitSimulationIslands; | ||
305 | public float shouldEnableFrictionCaching; | ||
306 | public float numberOfSolverIterations; | ||
307 | |||
308 | public float linksetImplementation; | ||
309 | public float linkConstraintUseFrameOffset; | ||
310 | public float linkConstraintEnableTransMotor; | ||
311 | public float linkConstraintTransMotorMaxVel; | ||
312 | public float linkConstraintTransMotorMaxForce; | ||
313 | public float linkConstraintERP; | ||
314 | public float linkConstraintCFM; | ||
315 | public float linkConstraintSolverIterations; | ||
316 | |||
317 | public float physicsLoggingFrames; | ||
318 | |||
319 | public const float numericTrue = 1f; | ||
320 | public const float numericFalse = 0f; | ||
321 | } | ||
322 | |||
323 | |||
324 | // The states a bullet collision object can have | ||
325 | public enum ActivationState : uint | ||
326 | { | ||
327 | ACTIVE_TAG = 1, | ||
328 | ISLAND_SLEEPING, | ||
329 | WANTS_DEACTIVATION, | ||
330 | DISABLE_DEACTIVATION, | ||
331 | DISABLE_SIMULATION, | ||
332 | } | ||
333 | |||
334 | public enum CollisionObjectTypes : int | ||
335 | { | ||
336 | CO_COLLISION_OBJECT = 1 << 0, | ||
337 | CO_RIGID_BODY = 1 << 1, | ||
338 | CO_GHOST_OBJECT = 1 << 2, | ||
339 | CO_SOFT_BODY = 1 << 3, | ||
340 | CO_HF_FLUID = 1 << 4, | ||
341 | CO_USER_TYPE = 1 << 5, | ||
342 | } | ||
343 | |||
344 | // Values used by Bullet and BulletSim to control object properties. | ||
345 | // Bullet's "CollisionFlags" has more to do with operations on the | ||
346 | // object (if collisions happen, if gravity effects it, ...). | ||
347 | public enum CollisionFlags : uint | ||
348 | { | ||
349 | CF_STATIC_OBJECT = 1 << 0, | ||
350 | CF_KINEMATIC_OBJECT = 1 << 1, | ||
351 | CF_NO_CONTACT_RESPONSE = 1 << 2, | ||
352 | CF_CUSTOM_MATERIAL_CALLBACK = 1 << 3, | ||
353 | CF_CHARACTER_OBJECT = 1 << 4, | ||
354 | CF_DISABLE_VISUALIZE_OBJECT = 1 << 5, | ||
355 | CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6, | ||
356 | // Following used by BulletSim to control collisions | ||
357 | BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10, | ||
358 | BS_FLOATS_ON_WATER = 1 << 11, | ||
359 | BS_NONE = 0, | ||
360 | BS_ALL = 0xFFFFFFFF, | ||
361 | |||
362 | // These are the collision flags switched depending on physical state. | ||
363 | // The other flags are used for other things and should not be fooled with. | ||
364 | BS_ACTIVE = CF_STATIC_OBJECT | ||
365 | | CF_KINEMATIC_OBJECT | ||
366 | | CF_NO_CONTACT_RESPONSE | ||
367 | }; | ||
368 | |||
369 | // Values for collisions groups and masks | ||
370 | public enum CollisionFilterGroups : uint | ||
371 | { | ||
372 | // Don't use the bit definitions!! Define the use in a | ||
373 | // filter/mask definition below. This way collision interactions | ||
374 | // are more easily debugged. | ||
375 | BNoneFilter = 0, | ||
376 | BDefaultFilter = 1 << 0, | ||
377 | BStaticFilter = 1 << 1, | ||
378 | BKinematicFilter = 1 << 2, | ||
379 | BDebrisFilter = 1 << 3, | ||
380 | BSensorTrigger = 1 << 4, | ||
381 | BCharacterFilter = 1 << 5, | ||
382 | BAllFilter = 0xFFFFFFFF, | ||
383 | // Filter groups defined by BulletSim | ||
384 | BGroundPlaneFilter = 1 << 10, | ||
385 | BTerrainFilter = 1 << 11, | ||
386 | BRaycastFilter = 1 << 12, | ||
387 | BSolidFilter = 1 << 13, | ||
388 | BLinksetFilter = 1 << 14, | ||
389 | |||
390 | // The collsion filters and masked are defined in one place -- don't want them scattered | ||
391 | AvatarFilter = BCharacterFilter, | ||
392 | AvatarMask = BAllFilter, | ||
393 | ObjectFilter = BSolidFilter, | ||
394 | ObjectMask = BAllFilter, | ||
395 | StaticObjectFilter = BStaticFilter, | ||
396 | StaticObjectMask = BAllFilter & ~BStaticFilter, // static objects don't collide with each other | ||
397 | LinksetFilter = BLinksetFilter, | ||
398 | LinksetMask = BAllFilter & ~BLinksetFilter, // linkset objects don't collide with each other | ||
399 | VolumeDetectFilter = BSensorTrigger, | ||
400 | VolumeDetectMask = ~BSensorTrigger, | ||
401 | TerrainFilter = BTerrainFilter, | ||
402 | TerrainMask = BAllFilter & ~BStaticFilter, // static objects on the ground don't collide | ||
403 | GroundPlaneFilter = BGroundPlaneFilter, | ||
404 | GroundPlaneMask = BAllFilter | ||
405 | |||
406 | }; | ||
407 | |||
408 | // CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0 | ||
409 | // ERP controls amount of correction per tick. Usable range=0.1..0.8. Default=0.2. | ||
410 | public enum ConstraintParams : int | ||
411 | { | ||
412 | BT_CONSTRAINT_ERP = 1, // this one is not used in Bullet as of 20120730 | ||
413 | BT_CONSTRAINT_STOP_ERP, | ||
414 | BT_CONSTRAINT_CFM, | ||
415 | BT_CONSTRAINT_STOP_CFM, | ||
416 | }; | ||
417 | public enum ConstraintParamAxis : int | ||
418 | { | ||
419 | AXIS_LINEAR_X = 0, | ||
420 | AXIS_LINEAR_Y, | ||
421 | AXIS_LINEAR_Z, | ||
422 | AXIS_ANGULAR_X, | ||
423 | AXIS_ANGULAR_Y, | ||
424 | AXIS_ANGULAR_Z, | ||
425 | AXIS_LINEAR_ALL = 20, // these last three added by BulletSim so we don't have to do zillions of calls | ||
426 | AXIS_ANGULAR_ALL, | ||
427 | AXIS_ALL | ||
428 | }; | ||
429 | |||
430 | // =============================================================================== | ||
431 | static class BulletSimAPI { | ||
432 | |||
433 | // Link back to the managed code for outputting log messages | ||
434 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] | ||
435 | public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg); | ||
436 | |||
437 | // =============================================================================== | ||
438 | // Initialization and simulation | ||
439 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
440 | public static extern IntPtr Initialize2(Vector3 maxPosition, IntPtr parms, | ||
441 | int maxCollisions, IntPtr collisionArray, | ||
442 | int maxUpdates, IntPtr updateArray, | ||
443 | DebugLogCallback logRoutine); | ||
444 | |||
445 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
446 | public static extern bool UpdateParameter2(IntPtr world, uint localID, String parm, float value); | ||
447 | |||
448 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
449 | public static extern void SetHeightMap2(IntPtr world, float[] heightmap); | ||
450 | |||
451 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
452 | public static extern void Shutdown2(IntPtr sim); | ||
453 | |||
454 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
455 | public static extern int PhysicsStep2(IntPtr world, float timeStep, int maxSubSteps, float fixedTimeStep, | ||
456 | out int updatedEntityCount, | ||
457 | out IntPtr updatedEntitiesPtr, | ||
458 | out int collidersCount, | ||
459 | out IntPtr collidersPtr); | ||
460 | |||
461 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
462 | public static extern bool PushUpdate2(IntPtr obj); | ||
463 | |||
464 | // ===================================================================================== | ||
465 | // Mesh, hull, shape and body creation helper routines | ||
466 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
467 | public static extern IntPtr CreateMeshShape2(IntPtr world, | ||
468 | int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices, | ||
469 | int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices ); | ||
470 | |||
471 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
472 | public static extern IntPtr CreateHullShape2(IntPtr world, | ||
473 | int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls); | ||
474 | |||
475 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
476 | public static extern IntPtr BuildHullShapeFromMesh2(IntPtr world, IntPtr meshShape); | ||
477 | |||
478 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
479 | public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData); | ||
480 | |||
481 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
482 | public static extern bool IsNativeShape2(IntPtr shape); | ||
483 | |||
484 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
485 | public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale); | ||
486 | |||
487 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
488 | public static extern IntPtr CreateCompoundShape2(IntPtr sim, bool enableDynamicAabbTree); | ||
489 | |||
490 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
491 | public static extern int GetNumberOfCompoundChildren2(IntPtr cShape); | ||
492 | |||
493 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
494 | public static extern void AddChildShapeToCompoundShape2(IntPtr cShape, IntPtr addShape, Vector3 pos, Quaternion rot); | ||
495 | |||
496 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
497 | public static extern IntPtr GetChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx); | ||
498 | |||
499 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
500 | public static extern IntPtr RemoveChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx); | ||
501 | |||
502 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
503 | public static extern void RemoveChildShapeFromCompoundShape2(IntPtr cShape, IntPtr removeShape); | ||
504 | |||
505 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
506 | public static extern void RecalculateCompoundShapeLocalAabb2(IntPtr cShape); | ||
507 | |||
508 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
509 | public static extern IntPtr DuplicateCollisionShape2(IntPtr sim, IntPtr srcShape, uint id); | ||
510 | |||
511 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
512 | public static extern IntPtr CreateBodyFromShapeAndInfo2(IntPtr sim, IntPtr shape, uint id, IntPtr constructionInfo); | ||
513 | |||
514 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
515 | public static extern bool DeleteCollisionShape2(IntPtr world, IntPtr shape); | ||
516 | |||
517 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
518 | public static extern int GetBodyType2(IntPtr obj); | ||
519 | |||
520 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
521 | public static extern IntPtr CreateBodyFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot); | ||
522 | |||
523 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
524 | public static extern IntPtr CreateBodyWithDefaultMotionState2(IntPtr shape, uint id, Vector3 pos, Quaternion rot); | ||
525 | |||
526 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
527 | public static extern IntPtr CreateGhostFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot); | ||
528 | |||
529 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
530 | public static extern IntPtr AllocateBodyInfo2(IntPtr obj); | ||
531 | |||
532 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
533 | public static extern void ReleaseBodyInfo2(IntPtr obj); | ||
534 | |||
535 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
536 | public static extern void DestroyObject2(IntPtr sim, IntPtr obj); | ||
537 | |||
538 | // ===================================================================================== | ||
539 | // Terrain creation and helper routines | ||
540 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
541 | public static extern IntPtr CreateHeightMapInfo2(IntPtr sim, uint id, Vector3 minCoords, Vector3 maxCoords, | ||
542 | [MarshalAs(UnmanagedType.LPArray)] float[] heightMap, float collisionMargin); | ||
543 | |||
544 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
545 | public static extern IntPtr FillHeightMapInfo2(IntPtr sim, IntPtr mapInfo, uint id, Vector3 minCoords, Vector3 maxCoords, | ||
546 | [MarshalAs(UnmanagedType.LPArray)] float[] heightMap, float collisionMargin); | ||
547 | |||
548 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
549 | public static extern bool ReleaseHeightMapInfo2(IntPtr heightMapInfo); | ||
550 | |||
551 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
552 | public static extern IntPtr CreateGroundPlaneShape2(uint id, float height, float collisionMargin); | ||
553 | |||
554 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
555 | public static extern IntPtr CreateTerrainShape2(IntPtr mapInfo); | ||
556 | |||
557 | // ===================================================================================== | ||
558 | // Constraint creation and helper routines | ||
559 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
560 | public static extern IntPtr Create6DofConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, | ||
561 | Vector3 frame1loc, Quaternion frame1rot, | ||
562 | Vector3 frame2loc, Quaternion frame2rot, | ||
563 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); | ||
564 | |||
565 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
566 | public static extern IntPtr Create6DofConstraintToPoint2(IntPtr world, IntPtr obj1, IntPtr obj2, | ||
567 | Vector3 joinPoint, | ||
568 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); | ||
569 | |||
570 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
571 | public static extern IntPtr CreateHingeConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, | ||
572 | Vector3 pivotinA, Vector3 pivotinB, | ||
573 | Vector3 axisInA, Vector3 axisInB, | ||
574 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); | ||
575 | |||
576 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
577 | public static extern void SetConstraintEnable2(IntPtr constrain, float numericTrueFalse); | ||
578 | |||
579 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
580 | public static extern void SetConstraintNumSolverIterations2(IntPtr constrain, float iterations); | ||
581 | |||
582 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
583 | public static extern bool SetFrames2(IntPtr constrain, | ||
584 | Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot); | ||
585 | |||
586 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
587 | public static extern bool SetLinearLimits2(IntPtr constrain, Vector3 low, Vector3 hi); | ||
588 | |||
589 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
590 | public static extern bool SetAngularLimits2(IntPtr constrain, Vector3 low, Vector3 hi); | ||
591 | |||
592 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
593 | public static extern bool UseFrameOffset2(IntPtr constrain, float enable); | ||
594 | |||
595 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
596 | public static extern bool TranslationalLimitMotor2(IntPtr constrain, float enable, float targetVel, float maxMotorForce); | ||
597 | |||
598 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
599 | public static extern bool SetBreakingImpulseThreshold2(IntPtr constrain, float threshold); | ||
600 | |||
601 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
602 | public static extern bool CalculateTransforms2(IntPtr constrain); | ||
603 | |||
604 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
605 | public static extern bool SetConstraintParam2(IntPtr constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis); | ||
606 | |||
607 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
608 | public static extern bool DestroyConstraint2(IntPtr world, IntPtr constrain); | ||
609 | |||
610 | // ===================================================================================== | ||
611 | // btCollisionWorld entries | ||
612 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
613 | public static extern void UpdateSingleAabb2(IntPtr world, IntPtr obj); | ||
614 | |||
615 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
616 | public static extern void UpdateAabbs2(IntPtr world); | ||
617 | |||
618 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
619 | public static extern bool GetForceUpdateAllAabbs2(IntPtr world); | ||
620 | |||
621 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
622 | public static extern void SetForceUpdateAllAabbs2(IntPtr world, bool force); | ||
623 | |||
624 | // ===================================================================================== | ||
625 | // btDynamicsWorld entries | ||
626 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
627 | public static extern bool AddObjectToWorld2(IntPtr world, IntPtr obj); | ||
628 | |||
629 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
630 | public static extern bool RemoveObjectFromWorld2(IntPtr world, IntPtr obj); | ||
631 | |||
632 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
633 | public static extern bool AddConstraintToWorld2(IntPtr world, IntPtr constrain, bool disableCollisionsBetweenLinkedObjects); | ||
634 | |||
635 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
636 | public static extern bool RemoveConstraintFromWorld2(IntPtr world, IntPtr constrain); | ||
637 | // ===================================================================================== | ||
638 | // btCollisionObject entries | ||
639 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
640 | public static extern Vector3 GetAnisotripicFriction2(IntPtr constrain); | ||
641 | |||
642 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
643 | public static extern Vector3 SetAnisotripicFriction2(IntPtr constrain, Vector3 frict); | ||
644 | |||
645 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
646 | public static extern bool HasAnisotripicFriction2(IntPtr constrain); | ||
647 | |||
648 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
649 | public static extern void SetContactProcessingThreshold2(IntPtr obj, float val); | ||
650 | |||
651 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
652 | public static extern float GetContactProcessingThreshold2(IntPtr obj); | ||
653 | |||
654 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
655 | public static extern bool IsStaticObject2(IntPtr obj); | ||
656 | |||
657 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
658 | public static extern bool IsKinematicObject2(IntPtr obj); | ||
659 | |||
660 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
661 | public static extern bool IsStaticOrKinematicObject2(IntPtr obj); | ||
662 | |||
663 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
664 | public static extern bool HasContactResponse2(IntPtr obj); | ||
665 | |||
666 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
667 | public static extern void SetCollisionShape2(IntPtr sim, IntPtr obj, IntPtr shape); | ||
668 | |||
669 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
670 | public static extern IntPtr GetCollisionShape2(IntPtr obj); | ||
671 | |||
672 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
673 | public static extern int GetActivationState2(IntPtr obj); | ||
674 | |||
675 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
676 | public static extern void SetActivationState2(IntPtr obj, int state); | ||
677 | |||
678 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
679 | public static extern void SetDeactivationTime2(IntPtr obj, float dtime); | ||
680 | |||
681 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
682 | public static extern float GetDeactivationTime2(IntPtr obj); | ||
683 | |||
684 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
685 | public static extern void ForceActivationState2(IntPtr obj, ActivationState state); | ||
686 | |||
687 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
688 | public static extern void Activate2(IntPtr obj, bool forceActivation); | ||
689 | |||
690 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
691 | public static extern bool IsActive2(IntPtr obj); | ||
692 | |||
693 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
694 | public static extern void SetRestitution2(IntPtr obj, float val); | ||
695 | |||
696 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
697 | public static extern float GetRestitution2(IntPtr obj); | ||
698 | |||
699 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
700 | public static extern void SetFriction2(IntPtr obj, float val); | ||
701 | |||
702 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
703 | public static extern float GetFriction2(IntPtr obj); | ||
704 | |||
705 | /* Haven't defined the type 'Transform' | ||
706 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
707 | public static extern Transform GetWorldTransform2(IntPtr obj); | ||
708 | |||
709 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
710 | public static extern void setWorldTransform2(IntPtr obj, Transform trans); | ||
711 | */ | ||
712 | |||
713 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
714 | public static extern Vector3 GetPosition2(IntPtr obj); | ||
715 | |||
716 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
717 | public static extern Quaternion GetOrientation2(IntPtr obj); | ||
718 | |||
719 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
720 | public static extern void SetTranslation2(IntPtr obj, Vector3 position, Quaternion rotation); | ||
721 | |||
722 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
723 | public static extern IntPtr GetBroadphaseHandle2(IntPtr obj); | ||
724 | |||
725 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
726 | public static extern void SetBroadphaseHandle2(IntPtr obj, IntPtr handle); | ||
727 | |||
728 | /* | ||
729 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
730 | public static extern Transform GetInterpolationWorldTransform2(IntPtr obj); | ||
731 | |||
732 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
733 | public static extern void SetInterpolationWorldTransform2(IntPtr obj, Transform trans); | ||
734 | */ | ||
735 | |||
736 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
737 | public static extern void SetInterpolationLinearVelocity2(IntPtr obj, Vector3 vel); | ||
738 | |||
739 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
740 | public static extern void SetInterpolationAngularVelocity2(IntPtr obj, Vector3 vel); | ||
741 | |||
742 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
743 | public static extern void SetInterpolationVelocity2(IntPtr obj, Vector3 linearVel, Vector3 angularVel); | ||
744 | |||
745 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
746 | public static extern float GetHitFraction2(IntPtr obj); | ||
747 | |||
748 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
749 | public static extern void SetHitFraction2(IntPtr obj, float val); | ||
750 | |||
751 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
752 | public static extern CollisionFlags GetCollisionFlags2(IntPtr obj); | ||
753 | |||
754 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
755 | public static extern CollisionFlags SetCollisionFlags2(IntPtr obj, CollisionFlags flags); | ||
756 | |||
757 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
758 | public static extern CollisionFlags AddToCollisionFlags2(IntPtr obj, CollisionFlags flags); | ||
759 | |||
760 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
761 | public static extern CollisionFlags RemoveFromCollisionFlags2(IntPtr obj, CollisionFlags flags); | ||
762 | |||
763 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
764 | public static extern float GetCcdMotionThreshold2(IntPtr obj); | ||
765 | |||
766 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
767 | public static extern void SetCcdMotionThreshold2(IntPtr obj, float val); | ||
768 | |||
769 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
770 | public static extern float GetCcdSweptSphereRadius2(IntPtr obj); | ||
771 | |||
772 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
773 | public static extern void SetCcdSweptSphereRadius2(IntPtr obj, float val); | ||
774 | |||
775 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
776 | public static extern IntPtr GetUserPointer2(IntPtr obj); | ||
777 | |||
778 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
779 | public static extern void SetUserPointer2(IntPtr obj, IntPtr val); | ||
780 | |||
781 | // ===================================================================================== | ||
782 | // btRigidBody entries | ||
783 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
784 | public static extern void ApplyGravity2(IntPtr obj); | ||
785 | |||
786 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
787 | public static extern void SetGravity2(IntPtr obj, Vector3 val); | ||
788 | |||
789 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
790 | public static extern Vector3 GetGravity2(IntPtr obj); | ||
791 | |||
792 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
793 | public static extern void SetDamping2(IntPtr obj, float lin_damping, float ang_damping); | ||
794 | |||
795 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
796 | public static extern void SetLinearDamping2(IntPtr obj, float lin_damping); | ||
797 | |||
798 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
799 | public static extern void SetAngularDamping2(IntPtr obj, float ang_damping); | ||
800 | |||
801 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
802 | public static extern float GetLinearDamping2(IntPtr obj); | ||
803 | |||
804 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
805 | public static extern float GetAngularDamping2(IntPtr obj); | ||
806 | |||
807 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
808 | public static extern float GetLinearSleepingThreshold2(IntPtr obj); | ||
809 | |||
810 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
811 | public static extern float GetAngularSleepingThreshold2(IntPtr obj); | ||
812 | |||
813 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
814 | public static extern void ApplyDamping2(IntPtr obj, float timeStep); | ||
815 | |||
816 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
817 | public static extern void SetMassProps2(IntPtr obj, float mass, Vector3 inertia); | ||
818 | |||
819 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
820 | public static extern Vector3 GetLinearFactor2(IntPtr obj); | ||
821 | |||
822 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
823 | public static extern void SetLinearFactor2(IntPtr obj, Vector3 factor); | ||
824 | |||
825 | /* | ||
826 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
827 | public static extern void SetCenterOfMassTransform2(IntPtr obj, Transform trans); | ||
828 | */ | ||
829 | |||
830 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
831 | public static extern void SetCenterOfMassByPosRot2(IntPtr obj, Vector3 pos, Quaternion rot); | ||
832 | |||
833 | // Add a force to the object as if its mass is one. | ||
834 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
835 | public static extern void ApplyCentralForce2(IntPtr obj, Vector3 force); | ||
836 | |||
837 | // Set the force being applied to the object as if its mass is one. | ||
838 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
839 | public static extern void SetObjectForce2(IntPtr obj, Vector3 force); | ||
840 | |||
841 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
842 | public static extern Vector3 GetTotalForce2(IntPtr obj); | ||
843 | |||
844 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
845 | public static extern Vector3 GetTotalTorque2(IntPtr obj); | ||
846 | |||
847 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
848 | public static extern Vector3 GetInvInertiaDiagLocal2(IntPtr obj); | ||
849 | |||
850 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
851 | public static extern void SetInvInertiaDiagLocal2(IntPtr obj, Vector3 inert); | ||
852 | |||
853 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
854 | public static extern void SetSleepingThresholds2(IntPtr obj, float lin_threshold, float ang_threshold); | ||
855 | |||
856 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
857 | public static extern void ApplyTorque2(IntPtr obj, Vector3 torque); | ||
858 | |||
859 | // Apply force at the given point. Will add torque to the object. | ||
860 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
861 | public static extern void ApplyForce2(IntPtr obj, Vector3 force, Vector3 pos); | ||
862 | |||
863 | // Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass. | ||
864 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
865 | public static extern void ApplyCentralImpulse2(IntPtr obj, Vector3 imp); | ||
866 | |||
867 | // Apply impulse to the object's torque. Force is scaled by object's mass. | ||
868 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
869 | public static extern void ApplyTorqueImpulse2(IntPtr obj, Vector3 imp); | ||
870 | |||
871 | // Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces. | ||
872 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
873 | public static extern void ApplyImpulse2(IntPtr obj, Vector3 imp, Vector3 pos); | ||
874 | |||
875 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
876 | public static extern void ClearForces2(IntPtr obj); | ||
877 | |||
878 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
879 | public static extern void ClearAllForces2(IntPtr obj); | ||
880 | |||
881 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
882 | public static extern void UpdateInertiaTensor2(IntPtr obj); | ||
883 | |||
884 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
885 | public static extern Vector3 GetCenterOfMassPosition2(IntPtr obj); | ||
886 | |||
887 | /* | ||
888 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
889 | public static extern Transform GetCenterOfMassTransform2(IntPtr obj); | ||
890 | */ | ||
891 | |||
892 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
893 | public static extern Vector3 GetLinearVelocity2(IntPtr obj); | ||
894 | |||
895 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
896 | public static extern Vector3 GetAngularVelocity2(IntPtr obj); | ||
897 | |||
898 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
899 | public static extern void SetLinearVelocity2(IntPtr obj, Vector3 val); | ||
900 | |||
901 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
902 | public static extern void SetAngularVelocity2(IntPtr obj, Vector3 angularVelocity); | ||
903 | |||
904 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
905 | public static extern Vector3 GetVelocityInLocalPoint2(IntPtr obj, Vector3 pos); | ||
906 | |||
907 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
908 | public static extern void Translate2(IntPtr obj, Vector3 trans); | ||
909 | |||
910 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
911 | public static extern void UpdateDeactivation2(IntPtr obj, float timeStep); | ||
912 | |||
913 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
914 | public static extern bool WantsSleeping2(IntPtr obj); | ||
915 | |||
916 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
917 | public static extern void SetAngularFactor2(IntPtr obj, float factor); | ||
918 | |||
919 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
920 | public static extern void SetAngularFactorV2(IntPtr obj, Vector3 factor); | ||
921 | |||
922 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
923 | public static extern Vector3 GetAngularFactor2(IntPtr obj); | ||
924 | |||
925 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
926 | public static extern bool IsInWorld2(IntPtr obj); | ||
927 | |||
928 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
929 | public static extern void AddConstraintRef2(IntPtr obj, IntPtr constrain); | ||
930 | |||
931 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
932 | public static extern void RemoveConstraintRef2(IntPtr obj, IntPtr constrain); | ||
933 | |||
934 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
935 | public static extern IntPtr GetConstraintRef2(IntPtr obj, int index); | ||
936 | |||
937 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
938 | public static extern int GetNumConstraintRefs2(IntPtr obj); | ||
939 | |||
940 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
941 | public static extern void SetCollisionFilterMask2(IntPtr body, uint filter, uint mask); | ||
942 | |||
943 | // ===================================================================================== | ||
944 | // btCollisionShape entries | ||
945 | |||
946 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
947 | public static extern float GetAngularMotionDisc2(IntPtr shape); | ||
948 | |||
949 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
950 | public static extern float GetContactBreakingThreshold2(IntPtr shape, float defaultFactor); | ||
951 | |||
952 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
953 | public static extern bool IsPolyhedral2(IntPtr shape); | ||
954 | |||
955 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
956 | public static extern bool IsConvex2d2(IntPtr shape); | ||
957 | |||
958 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
959 | public static extern bool IsConvex2(IntPtr shape); | ||
960 | |||
961 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
962 | public static extern bool IsNonMoving2(IntPtr shape); | ||
963 | |||
964 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
965 | public static extern bool IsConcave2(IntPtr shape); | ||
966 | |||
967 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
968 | public static extern bool IsCompound2(IntPtr shape); | ||
969 | |||
970 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
971 | public static extern bool IsSoftBody2(IntPtr shape); | ||
972 | |||
973 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
974 | public static extern bool IsInfinite2(IntPtr shape); | ||
975 | |||
976 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
977 | public static extern void SetLocalScaling2(IntPtr shape, Vector3 scale); | ||
978 | |||
979 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
980 | public static extern Vector3 GetLocalScaling2(IntPtr shape); | ||
981 | |||
982 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
983 | public static extern Vector3 CalculateLocalInertia2(IntPtr shape, float mass); | ||
984 | |||
985 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
986 | public static extern int GetShapeType2(IntPtr shape); | ||
987 | |||
988 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
989 | public static extern void SetMargin2(IntPtr shape, float val); | ||
990 | |||
991 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
992 | public static extern float GetMargin2(IntPtr shape); | ||
993 | |||
994 | // ===================================================================================== | ||
995 | // Debugging | ||
996 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
997 | public static extern void DumpRigidBody2(IntPtr sim, IntPtr collisionObject); | ||
998 | |||
999 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1000 | public static extern void DumpCollisionShape2(IntPtr sim, IntPtr collisionShape); | ||
1001 | |||
1002 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1003 | public static extern void DumpConstraint2(IntPtr sim, IntPtr constrain); | ||
1004 | |||
1005 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1006 | public static extern void DumpAllInfo2(IntPtr sim); | ||
1007 | |||
1008 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1009 | public static extern void DumpMapInfo2(IntPtr sim, IntPtr manInfo); | ||
1010 | |||
1011 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1012 | public static extern void DumpPhysicsStatistics2(IntPtr sim); | ||
1013 | |||
1014 | } | ||
1015 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs new file mode 100755 index 0000000..8012d91 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs | |||
@@ -0,0 +1,269 @@ | |||
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 copyrightD | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Text; | ||
30 | using OMV = OpenMetaverse; | ||
31 | |||
32 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
33 | { | ||
34 | // Classes to allow some type checking for the API | ||
35 | // These hold pointers to allocated objects in the unmanaged space. | ||
36 | // These classes are subclassed by the various physical implementations of | ||
37 | // objects. In particular, there is a version for physical instances in | ||
38 | // unmanaged memory ("unman") and one for in managed memory ("XNA"). | ||
39 | |||
40 | // Currently, the instances of these classes are a reference to a | ||
41 | // physical representation and this has no releationship to other | ||
42 | // instances. Someday, refarb the usage of these classes so each instance | ||
43 | // refers to a particular physical instance and this class controls reference | ||
44 | // counts and such. This should be done along with adding BSShapes. | ||
45 | |||
46 | public class BulletWorld | ||
47 | { | ||
48 | public BulletWorld(uint worldId, BSScene bss) | ||
49 | { | ||
50 | worldID = worldId; | ||
51 | physicsScene = bss; | ||
52 | } | ||
53 | public uint worldID; | ||
54 | // The scene is only in here so very low level routines have a handle to print debug/error messages | ||
55 | public BSScene physicsScene; | ||
56 | } | ||
57 | |||
58 | // An allocated Bullet btRigidBody | ||
59 | public class BulletBody | ||
60 | { | ||
61 | public BulletBody(uint id) | ||
62 | { | ||
63 | ID = id; | ||
64 | collisionType = CollisionType.Static; | ||
65 | } | ||
66 | public uint ID; | ||
67 | public CollisionType collisionType; | ||
68 | |||
69 | public virtual void Clear() { } | ||
70 | public virtual bool HasPhysicalBody { get { return false; } } | ||
71 | |||
72 | // Apply the specificed collision mask into the physical world | ||
73 | public virtual bool ApplyCollisionMask(BSScene physicsScene) | ||
74 | { | ||
75 | // Should assert the body has been added to the physical world. | ||
76 | // (The collision masks are stored in the collision proxy cache which only exists for | ||
77 | // a collision body that is in the world.) | ||
78 | return physicsScene.PE.SetCollisionGroupMask(this, | ||
79 | BulletSimData.CollisionTypeMasks[collisionType].group, | ||
80 | BulletSimData.CollisionTypeMasks[collisionType].mask); | ||
81 | } | ||
82 | |||
83 | // Used for log messages for a unique display of the memory/object allocated to this instance | ||
84 | public virtual string AddrString | ||
85 | { | ||
86 | get { return "unknown"; } | ||
87 | } | ||
88 | |||
89 | public override string ToString() | ||
90 | { | ||
91 | StringBuilder buff = new StringBuilder(); | ||
92 | buff.Append("<id="); | ||
93 | buff.Append(ID.ToString()); | ||
94 | buff.Append(",p="); | ||
95 | buff.Append(AddrString); | ||
96 | buff.Append(",c="); | ||
97 | buff.Append(collisionType); | ||
98 | buff.Append(">"); | ||
99 | return buff.ToString(); | ||
100 | } | ||
101 | } | ||
102 | |||
103 | public class BulletShape | ||
104 | { | ||
105 | public BulletShape() | ||
106 | { | ||
107 | type = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
108 | shapeKey = (System.UInt64)FixedShapeKey.KEY_NONE; | ||
109 | isNativeShape = false; | ||
110 | } | ||
111 | public BSPhysicsShapeType type; | ||
112 | public System.UInt64 shapeKey; | ||
113 | public bool isNativeShape; | ||
114 | |||
115 | public virtual void Clear() { } | ||
116 | public virtual bool HasPhysicalShape { get { return false; } } | ||
117 | |||
118 | // Make another reference to this physical object. | ||
119 | public virtual BulletShape Clone() { return new BulletShape(); } | ||
120 | |||
121 | // Return 'true' if this and other refer to the same physical object | ||
122 | public virtual bool ReferenceSame(BulletShape xx) { return false; } | ||
123 | |||
124 | // Used for log messages for a unique display of the memory/object allocated to this instance | ||
125 | public virtual string AddrString | ||
126 | { | ||
127 | get { return "unknown"; } | ||
128 | } | ||
129 | |||
130 | public override string ToString() | ||
131 | { | ||
132 | StringBuilder buff = new StringBuilder(); | ||
133 | buff.Append("<p="); | ||
134 | buff.Append(AddrString); | ||
135 | buff.Append(",s="); | ||
136 | buff.Append(type.ToString()); | ||
137 | buff.Append(",k="); | ||
138 | buff.Append(shapeKey.ToString("X")); | ||
139 | buff.Append(",n="); | ||
140 | buff.Append(isNativeShape.ToString()); | ||
141 | buff.Append(">"); | ||
142 | return buff.ToString(); | ||
143 | } | ||
144 | } | ||
145 | |||
146 | // An allocated Bullet btConstraint | ||
147 | public class BulletConstraint | ||
148 | { | ||
149 | public BulletConstraint() | ||
150 | { | ||
151 | } | ||
152 | public virtual void Clear() { } | ||
153 | public virtual bool HasPhysicalConstraint { get { return false; } } | ||
154 | |||
155 | // Used for log messages for a unique display of the memory/object allocated to this instance | ||
156 | public virtual string AddrString | ||
157 | { | ||
158 | get { return "unknown"; } | ||
159 | } | ||
160 | } | ||
161 | |||
162 | // An allocated HeightMapThing which holds various heightmap info. | ||
163 | // Made a class rather than a struct so there would be only one | ||
164 | // instance of this and C# will pass around pointers rather | ||
165 | // than making copies. | ||
166 | public class BulletHMapInfo | ||
167 | { | ||
168 | public BulletHMapInfo(uint id, float[] hm) { | ||
169 | ID = id; | ||
170 | heightMap = hm; | ||
171 | terrainRegionBase = OMV.Vector3.Zero; | ||
172 | minCoords = new OMV.Vector3(100f, 100f, 25f); | ||
173 | maxCoords = new OMV.Vector3(101f, 101f, 26f); | ||
174 | minZ = maxZ = 0f; | ||
175 | sizeX = sizeY = 256f; | ||
176 | } | ||
177 | public uint ID; | ||
178 | public float[] heightMap; | ||
179 | public OMV.Vector3 terrainRegionBase; | ||
180 | public OMV.Vector3 minCoords; | ||
181 | public OMV.Vector3 maxCoords; | ||
182 | public float sizeX, sizeY; | ||
183 | public float minZ, maxZ; | ||
184 | public BulletShape terrainShape; | ||
185 | public BulletBody terrainBody; | ||
186 | } | ||
187 | |||
188 | // The general class of collsion object. | ||
189 | public enum CollisionType | ||
190 | { | ||
191 | Avatar, | ||
192 | Groundplane, | ||
193 | Terrain, | ||
194 | Static, | ||
195 | Dynamic, | ||
196 | VolumeDetect, | ||
197 | // Linkset, // A linkset should be either Static or Dynamic | ||
198 | LinksetChild, | ||
199 | Unknown | ||
200 | }; | ||
201 | |||
202 | // Hold specification of group and mask collision flags for a CollisionType | ||
203 | public struct CollisionTypeFilterGroup | ||
204 | { | ||
205 | public CollisionTypeFilterGroup(CollisionType t, uint g, uint m) | ||
206 | { | ||
207 | type = t; | ||
208 | group = g; | ||
209 | mask = m; | ||
210 | } | ||
211 | public CollisionType type; | ||
212 | public uint group; | ||
213 | public uint mask; | ||
214 | }; | ||
215 | |||
216 | public static class BulletSimData | ||
217 | { | ||
218 | |||
219 | // Map of collisionTypes to flags for collision groups and masks. | ||
220 | // An object's 'group' is the collison groups this object belongs to | ||
221 | // An object's 'filter' is the groups another object has to belong to in order to collide with me | ||
222 | // A collision happens if ((obj1.group & obj2.filter) != 0) || ((obj2.group & obj1.filter) != 0) | ||
223 | // | ||
224 | // As mentioned above, don't use the CollisionFilterGroups definitions directly in the code | ||
225 | // but, instead, use references to this dictionary. Finding and debugging | ||
226 | // collision flag problems will be made easier. | ||
227 | public static Dictionary<CollisionType, CollisionTypeFilterGroup> CollisionTypeMasks | ||
228 | = new Dictionary<CollisionType, CollisionTypeFilterGroup>() | ||
229 | { | ||
230 | { CollisionType.Avatar, | ||
231 | new CollisionTypeFilterGroup(CollisionType.Avatar, | ||
232 | (uint)CollisionFilterGroups.BCharacterGroup, | ||
233 | (uint)CollisionFilterGroups.BAllGroup) | ||
234 | }, | ||
235 | { CollisionType.Groundplane, | ||
236 | new CollisionTypeFilterGroup(CollisionType.Groundplane, | ||
237 | (uint)CollisionFilterGroups.BGroundPlaneGroup, | ||
238 | (uint)CollisionFilterGroups.BAllGroup) | ||
239 | }, | ||
240 | { CollisionType.Terrain, | ||
241 | new CollisionTypeFilterGroup(CollisionType.Terrain, | ||
242 | (uint)CollisionFilterGroups.BTerrainGroup, | ||
243 | (uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BStaticGroup)) | ||
244 | }, | ||
245 | { CollisionType.Static, | ||
246 | new CollisionTypeFilterGroup(CollisionType.Static, | ||
247 | (uint)CollisionFilterGroups.BStaticGroup, | ||
248 | (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup)) | ||
249 | }, | ||
250 | { CollisionType.Dynamic, | ||
251 | new CollisionTypeFilterGroup(CollisionType.Dynamic, | ||
252 | (uint)CollisionFilterGroups.BSolidGroup, | ||
253 | (uint)(CollisionFilterGroups.BAllGroup)) | ||
254 | }, | ||
255 | { CollisionType.VolumeDetect, | ||
256 | new CollisionTypeFilterGroup(CollisionType.VolumeDetect, | ||
257 | (uint)CollisionFilterGroups.BSensorTrigger, | ||
258 | (uint)(~CollisionFilterGroups.BSensorTrigger)) | ||
259 | }, | ||
260 | { CollisionType.LinksetChild, | ||
261 | new CollisionTypeFilterGroup(CollisionType.LinksetChild, | ||
262 | (uint)CollisionFilterGroups.BLinksetChildGroup, | ||
263 | (uint)(CollisionFilterGroups.BNoneGroup)) | ||
264 | // (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup)) | ||
265 | }, | ||
266 | }; | ||
267 | |||
268 | } | ||
269 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt new file mode 100755 index 0000000..8a15abe --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt | |||
@@ -0,0 +1,346 @@ | |||
1 | CURRENT PRIORITIES | ||
2 | ================================================= | ||
3 | Use the HACD convex hull routine in Bullet rather than the C# version. | ||
4 | Speed up hullifying large meshes. | ||
5 | Enable vehicle border crossings (at least as poorly as ODE) | ||
6 | Terrain skirts | ||
7 | Avatar created in previous region and not new region when crossing border | ||
8 | Vehicle recreated in new sim at small Z value (offset from root value?) (DONE) | ||
9 | Lock axis | ||
10 | Deleting a linkset while standing on the root will leave the physical shape of the root behind. | ||
11 | Not sure if it is because standing on it. Done with large prim linksets. | ||
12 | Linkset child rotations. | ||
13 | Nebadon spiral tube has middle sections which are rotated wrong. | ||
14 | Select linked spiral tube. Delink and note where the middle section ends up. | ||
15 | Vehicle angular vertical attraction | ||
16 | vehicle angular banking | ||
17 | Center-of-gravity | ||
18 | Vehicle angular deflection | ||
19 | Preferred orientation angular correction fix | ||
20 | when should angular and linear motor targets be zeroed? when selected? | ||
21 | Need a vehicle.clear()? Or an 'else' in prestep if not physical. | ||
22 | Teravus llMoveToTarget script debug | ||
23 | Mixing of hover, buoyancy/gravity, moveToTarget, into one force | ||
24 | Setting hover height to zero disables hover even if hover flags are on (from SL wiki) | ||
25 | limitMotorUp calibration (more down?) | ||
26 | llRotLookAt | ||
27 | llLookAt | ||
28 | Avatars walking up stairs (HALF DONE) | ||
29 | Avatar movement | ||
30 | flying into a wall doesn't stop avatar who keeps appearing to move through the obstacle (DONE) | ||
31 | walking up stairs is not calibrated correctly (stairs out of Kepler cabin) | ||
32 | avatar capsule rotation completed (NOT DONE - Bullet's capsule shape is not the solution) | ||
33 | Vehicle script tuning/debugging | ||
34 | Avanti speed script | ||
35 | Weapon shooter script | ||
36 | Move material definitions (friction, ...) into simulator. | ||
37 | Add material densities to the material types. | ||
38 | Terrain detail: double terrain mesh detail | ||
39 | One sided meshes? Should terrain be built into a closed shape? | ||
40 | When meshes get partially wedged into the terrain, they cannot push themselves out. | ||
41 | It is possible that Bullet processes collisions whether entering or leaving a mesh. | ||
42 | Ref: http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4869 | ||
43 | |||
44 | VEHICLES TODO LIST: | ||
45 | ================================================= | ||
46 | Border crossing with linked vehicle causes crash | ||
47 | 20121129.1411: editting/moving phys object across region boundries causes crash | ||
48 | getPos-> btRigidBody::upcast -> getBodyType -> BOOM | ||
49 | Vehicles (Move smoothly) | ||
50 | Some vehicles should not be able to turn if no speed or off ground. | ||
51 | What to do if vehicle and prim buoyancy differ? | ||
52 | Cannot edit/move a vehicle being ridden: it jumps back to the origional position. | ||
53 | Neb car jiggling left and right | ||
54 | Happens on terrain and any other mesh object. Flat cubes are much smoother. | ||
55 | This has been reduced but not eliminated. | ||
56 | Implement referenceFrame for all the motion routines. | ||
57 | For limitMotorUp, use raycast down to find if vehicle is in the air. | ||
58 | Verify llGetVel() is returning a smooth and good value for vehicle movement. | ||
59 | llGetVel() should return the root's velocity if requested in a child prim. | ||
60 | Implement function efficiency for lineaar and angular motion. | ||
61 | After getting off a vehicle, the root prim is phantom (can be walked through) | ||
62 | Need to force a position update for the root prim after compound shape destruction | ||
63 | Linkset explosion after three "rides" on Nebadon lite vehicle (LinksetConstraint) | ||
64 | Remove vehicle angular velocity zeroing in BSPrim.UpdateProperties(). | ||
65 | A kludge that isn't fixing the real problem of Bullet adding extra motion. | ||
66 | Incorporate inter-relationship of angular corrections. For instance, angularDeflection | ||
67 | and angularMotorUp will compute same X or Y correction. When added together | ||
68 | creates over-correction and over-shoot and wabbling. | ||
69 | Vehicle attributes are not restored when a vehicle is rezzed on region creation | ||
70 | Create vehicle, setup vehicle properties, restart region, vehicle is not reinitialized. | ||
71 | |||
72 | GENERAL TODO LIST: | ||
73 | ================================================= | ||
74 | Explore btGImpactMeshShape as alternative to convex hulls for simplified physical objects. | ||
75 | Regular triangle meshes don't do physical collisions. | ||
76 | Resitution of a prim works on another prim but not on terrain. | ||
77 | The dropped prim doesn't bounce properly on the terrain. | ||
78 | Add a sanity check for PIDTarget location. | ||
79 | Level-of-detail for mesh creation. Prims with circular interiors require lod of 32. | ||
80 | Is much saved with lower LODs? At the moment, all set to 32. | ||
81 | Collisions are inconsistant: arrows are supposed to hit and report collision. Often don't. | ||
82 | If arrow show at prim, collision reported about 1/3 of time. If collision reported, | ||
83 | both arrow and prim report it. The arrow bounces off the prim 9 out of 10 times. | ||
84 | Shooting 5m sphere "arrows" at 60m/s. | ||
85 | llMoveToTarget objects are not effected by gravity until target is removed. | ||
86 | Compute CCD parameters based on body size | ||
87 | Can solver iterations be changed per body/shape? Can be for constraints but what | ||
88 | about regular vehicles? | ||
89 | Implement llSetPhysicalMaterial. | ||
90 | extend it with Center-of-mass, rolling friction, density | ||
91 | Implement llSetForceAndTorque. | ||
92 | Change BSPrim.moveToTarget to used forces rather than changing position | ||
93 | Changing position allows one to move through walls | ||
94 | Implement an avatar mesh shape. The Bullet capsule is way too limited. | ||
95 | Consider just hand creating a vertex/index array in a new BSShapeAvatar. | ||
96 | Verify/fix phantom, volume-detect objects do not fall to infinity. Should stop at terrain. | ||
97 | Revisit CollisionMargin. Builders notice the 0.04 spacing between prims. | ||
98 | Duplicating a physical prim causes old prim to jump away | ||
99 | Dup a phys prim and the original become unselected and thus interacts w/ selected prim. | ||
100 | Scenes with hundred of thousands of static objects take a lot of physics CPU time. | ||
101 | BSPrim.Force should set a continious force on the prim. The force should be | ||
102 | applied each tick. Some limits? | ||
103 | Gun sending shooter flying. | ||
104 | Collision margin (gap between physical objects lying on each other) | ||
105 | Boundry checking (crashes related to crossing boundry) | ||
106 | Add check for border edge position for avatars and objects. | ||
107 | Verify the events are created for border crossings. | ||
108 | Avatar rotation (check out changes to ScenePresence for physical rotation) | ||
109 | Avatar running (what does phys engine need to do?) | ||
110 | Small physical objects do not interact correctly | ||
111 | Create chain of .5x.5x.1 torui and make all but top physical so to hang. | ||
112 | The chain will fall apart and pairs will dance around on ground | ||
113 | Chains of 1x1x.2 will stay connected but will dance. | ||
114 | Chains above 2x2x.4 are more stable and get stablier as torui get larger. | ||
115 | Add PID motor for avatar movement (slow to stop, ...) | ||
116 | setForce should set a constant force. Different than AddImpulse. | ||
117 | Implement raycast. | ||
118 | Implement ShapeCollection.Dispose() | ||
119 | Implement water as a plain so raycasting and collisions can happen with same. | ||
120 | Add collision penetration return | ||
121 | Add field passed back by BulletSim.dll and fill with info in ManifoldConstact.GetDistance() | ||
122 | Add osGetPhysicsEngineName() so scripters can tell whether BulletSim or ODE | ||
123 | Also osGetPhysicsEngineVerion() maybe. | ||
124 | Linkset.Position and Linkset.Orientation requre rewrite to properly return | ||
125 | child position. LinksetConstraint acts like it's at taint time!! | ||
126 | Implement LockAngularMotion -- implements llSetStatus(ROTATE_AXIS_*, T/F) | ||
127 | Should the different PID factors have non-equal contributions for different | ||
128 | values of Efficiency? | ||
129 | Selecting and deselecting physical objects causes CPU processing time to jump | ||
130 | http://www.youtube.com/watch?v=Hjg57fWg8yI&hd=1 | ||
131 | put thousand physical objects, select and deselect same. CPU time will be large. | ||
132 | Re-implement buoyancy as a separate force on the object rather than diddling gravity. | ||
133 | Register a pre-step event to add the force. | ||
134 | More efficient memory usage when passing hull information from BSPrim to BulletSim | ||
135 | Avatar movement motor check for zero or small movement. Somehow suppress small movements | ||
136 | when avatar has stopped and is just standing. Simple test for near zero has | ||
137 | the problem of preventing starting up (increase from zero) especially when falling. | ||
138 | Physical and phantom will drop through the terrain | ||
139 | |||
140 | |||
141 | LINKSETS | ||
142 | ====================================================== | ||
143 | Child prims do not report collisions | ||
144 | Allow children of a linkset to be phantom: | ||
145 | http://opensim-dev.2196679.n2.nabble.com/Setting-a-single-child-prim-to-Phantom-tp7578513.html | ||
146 | Add OS_STATUS_PHANTOM_PRIM to llSetLinkPrimitaveParamsFast. | ||
147 | Editing a child of a linkset causes the child to go phantom | ||
148 | Move a child prim once when it is physical and can never move it again without it going phantom | ||
149 | Offset the center of the linkset to be the geometric center of all the prims | ||
150 | Not quite the same as the center-of-gravity | ||
151 | Linksets should allow collisions to individual children | ||
152 | Add LocalID to children shapes in LinksetCompound and create events for individuals | ||
153 | LinksetCompound: when one of the children changes orientation (like tires | ||
154 | turning on a vehicle, the whole compound object is rebuilt. Optimize this | ||
155 | so orientation/position of individual children can change without a rebuild. | ||
156 | Verify/think through scripts in children of linksets. What do they reference | ||
157 | and return when getting position, velocity, ... | ||
158 | Confirm constraint linksets still work after making all the changes for compound linksets. | ||
159 | Use PostTaint callback to do rebuilds for constraint linksets to reduce rebuilding | ||
160 | Add 'changed' flag or similar to reduce the number of times a linkset is rebuilt. | ||
161 | For compound linksets, add ability to remove or reposition individual child shapes. | ||
162 | Speed up creation of large physical linksets | ||
163 | For instance, sitting in Neb's car (130 prims) takes several seconds to become physical. | ||
164 | REALLY bad for very large physical linksets (freezes the sim for many seconds). | ||
165 | Eliminate collisions between objects in a linkset. (LinksetConstraint) | ||
166 | Have UserPointer point to struct with localID and linksetID? | ||
167 | Objects in original linkset still collide with each other? | ||
168 | |||
169 | MORE | ||
170 | ====================================================== | ||
171 | Create tests for different interface components | ||
172 | Have test objects/scripts measure themselves and turn color if correct/bad | ||
173 | Test functions in SL and calibrate correctness there | ||
174 | Create auto rezzer and tracker to run through the tests | ||
175 | Do we need to do convex hulls all the time? Can complex meshes be left meshes? | ||
176 | There is some problem with meshes and collisions | ||
177 | Hulls are not as detailed as meshes. Hulled vehicles insides are different shape. | ||
178 | Debounce avatar contact so legs don't keep folding up when standing. | ||
179 | Implement LSL physics controls. Like STATUS_ROTATE_X. | ||
180 | Add border extensions to terrain to help region crossings and objects leaving region. | ||
181 | Use a different capsule shape for avatar when sitting | ||
182 | LL uses a pyrimidal shape scaled by the avatar's bounding box | ||
183 | http://wiki.secondlife.com/wiki/File:Avmeshforms.png | ||
184 | Performance test with lots of avatars. Can BulletSim support a thousand? | ||
185 | Optimize collisions in C++: only send up to the object subscribed to collisions. | ||
186 | Use collision subscription and remove the collsion(A,B) and collision(B,A) | ||
187 | Check whether SimMotionState needs large if statement (see TODO). | ||
188 | Implement 'top colliders' info. | ||
189 | Avatar jump | ||
190 | Performance measurement and changes to make quicker. | ||
191 | Implement detailed physics stats (GetStats()). | ||
192 | Measure performance improvement from hulls | ||
193 | Test not using ghost objects for volume detect implementation. | ||
194 | Performance of closures and delegates for taint processing | ||
195 | Are there faster ways? | ||
196 | Is any slowdown introduced by the existing implementation significant? | ||
197 | Is there are more efficient method of implementing pre and post step actions? | ||
198 | See http://www.codeproject.com/Articles/29922/Weak-Events-in-C | ||
199 | Physics Arena central pyramid: why is one side permiable? | ||
200 | In SL, perfect spheres don't seem to have rolling friction. Add special case. | ||
201 | Enforce physical parameter min/max: | ||
202 | Gravity: [-1, 28] | ||
203 | Friction: [0, 255] | ||
204 | Density: [1, 22587] | ||
205 | Restitution [0, 1] | ||
206 | http://wiki.secondlife.com/wiki/Physics_Material_Settings_test | ||
207 | Avatar attachments have no mass? http://forums-archive.secondlife.com/54/f0/31796/1.html | ||
208 | Keep avatar scaling correct. http://pennycow.blogspot.fr/2011/07/matter-of-scale.html | ||
209 | |||
210 | INTERNAL IMPROVEMENT/CLEANUP | ||
211 | ================================================= | ||
212 | Can the 'inTaintTime' flag be cleaned up and used? For instance, a call to | ||
213 | BSScene.TaintedObject() could immediately execute the callback if already in taint time. | ||
214 | Create the physical wrapper classes (BulletBody, BulletShape) by methods on | ||
215 | BSAPITemplate and make their actual implementation Bullet engine specific. | ||
216 | For the short term, just call the existing functions in ShapeCollection. | ||
217 | Consider moving prim/character body and shape destruction in destroy() | ||
218 | to postTimeTime rather than protecting all the potential sets that | ||
219 | might have been queued up. | ||
220 | Remove unused fields from ShapeData (not used in API2) | ||
221 | Remove unused fields from pinned memory shared parameter block | ||
222 | Create parameter variables in BSScene to replace same. | ||
223 | Breakout code for mesh/hull/compound/native into separate BSShape* classes | ||
224 | Standardize access to building and reference code. | ||
225 | The skeleton classes are in the sources but are not complete or linked in. | ||
226 | Make BSBody and BSShape real classes to centralize creation/changin/destruction | ||
227 | Convert state and parameter calls from BulletSimAPI direct calls to | ||
228 | calls on BSBody and BSShape | ||
229 | Generalize Dynamics and PID with standardized motors. | ||
230 | Generalize Linkset and vehicles into PropertyManagers | ||
231 | Methods for Refresh, RemoveBodyDependencies, RestoreBodyDependencies | ||
232 | Potentially add events for shape destruction, etc. | ||
233 | Better mechanism for resetting linkset set and vehicle parameters when body rebuilt. | ||
234 | BSPrim.CreateGeomAndObject is kludgy with the callbacks, etc. | ||
235 | Implement linkset by setting position of children when root updated. (LinksetManual) | ||
236 | Linkset implementation using manual prim movement. | ||
237 | LinkablePrim class? Would that simplify/centralize the linkset logic? | ||
238 | BSScene.UpdateParameterSet() is broken. How to set params on objects? | ||
239 | Add floating motor for BS_FLOATS_ON_WATER so prim and avatar will | ||
240 | bob at the water level. BSPrim.PositionSanityCheck() | ||
241 | Should taints check for existance or activeness of target? | ||
242 | When destroying linksets/etc, taints can be generated for objects that are | ||
243 | actually gone when the taint happens. Crashes don't happen because the taint closure | ||
244 | keeps the object from being freed, but that is just an accident. | ||
245 | Possibly have an 'active' flag that is checked by the taint processor? | ||
246 | Parameters for physics logging should be moved from BSScene to BSParam (at least boolean ones) | ||
247 | Can some of the physical wrapper classes (BulletBody, BulletWorld, BulletShape) be 'sealed'? | ||
248 | There are TOO MANY interfaces from BulletSim core to Bullet itself | ||
249 | Think of something to eliminate one or more of the layers | ||
250 | |||
251 | THREADING | ||
252 | ================================================= | ||
253 | Do taint action immediately if not actually executing Bullet. | ||
254 | Add lock around Bullet execution and just do taint actions if simulation is not happening. | ||
255 | |||
256 | DONE DONE DONE DONE | ||
257 | ================================================= | ||
258 | Cleanup code in BSDynamics by using motors. (Resolution: started) | ||
259 | Consider implementing terrain with a mesh rather than heightmap. (Resolution: done) | ||
260 | Would have better and adjustable resolution. | ||
261 | Build terrain mesh so heighmap is height of the center of the square meter. | ||
262 | Resolution: NOT DONE: SL and ODE define meter square as being at one corner with one diagional. | ||
263 | Terrain as mesh. (Resolution: done) | ||
264 | How are static linksets seen by the physics engine? | ||
265 | Resolution: they are not linked in physics. When moved, all the children are repositioned. | ||
266 | Convert BSCharacter to use all API2 (Resolution: done) | ||
267 | Avatar pushing difficult (too heavy?) | ||
268 | Use asset service passed to BulletSim to get sculptie bodies, etc. (Resolution: done) | ||
269 | Remove old code in DLL (all non-API2 stuff). (Resolution: done) | ||
270 | Measurements of mega-physical prim performance (with graph) (Resolution: done, email) | ||
271 | Debug Bullet internal stats output (why is timing all wrong?) | ||
272 | Resolution: Bullet stats logging only works with a single instance of Bullet (one region). | ||
273 | Implement meshes or just verify that they work. (Resolution: they do!) | ||
274 | Do prim hash codes work for sculpties and meshes? (Resolution: yes) | ||
275 | Linkset implementation using compound shapes. (Resolution: implemented LinksetCompound) | ||
276 | Compound shapes will need the LocalID in the shapes and collision | ||
277 | processing to get it from there. | ||
278 | Light cycle not banking (Resolution: It doesn't. Banking is roll adding yaw.) | ||
279 | Package Bullet source mods for Bullet internal stats output | ||
280 | (Resolution: move code into WorldData.h rather than relying on patches) | ||
281 | Single prim vehicles don't seem to properly vehiclize. | ||
282 | (Resolution: mass was not getting set properly for single prim linksets) | ||
283 | Add material type linkage and input all the material property definitions. | ||
284 | Skeleton classes and table are in the sources but are not filled or used. | ||
285 | (Resolution: | ||
286 | Neb vehicle taking > 25ms of physics time!! | ||
287 | (Resolution: compound linksets were being rebuild WAY too often) | ||
288 | Avatar height off after unsitting (floats off ground) | ||
289 | Editting appearance then moving restores. | ||
290 | Must not be initializing height when recreating capsule after unsit. | ||
291 | (Resolution: confusion of scale vs size for native objects removed) | ||
292 | Light cycle falling over when driving (Resolution: implemented angularMotorUp) | ||
293 | Should vehicle angular/linear movement friction happen after all the components | ||
294 | or does it only apply to the basic movement? | ||
295 | (Resolution: friction added before returning newly computed motor value. | ||
296 | What is expected by some vehicles (turning up friction to moderate speed)) | ||
297 | Tune terrain/object friction to be closer to SL. | ||
298 | (Resolution: added material type with friction and resolution) | ||
299 | Smooth avatar movement with motor (DONE) | ||
300 | Should motor update be all at taint-time? (Yes, DONE) | ||
301 | Fix avatar slowly sliding when standing (zero motion when stopped) (DONE) | ||
302 | (Resolution: added BSVMotor for avatar starting and stopping) | ||
303 | llApplyImpulse() | ||
304 | Compare mass/movement in OS and SL. Calibrate actions. (DONE) | ||
305 | (Resolution: tested on SL and OS. AddForce scales the force for timestep) | ||
306 | llSetBuoyancy() (DONE) | ||
307 | (Resolution: Bullet resets object gravity when added to world. Moved set gravity) | ||
308 | Avatar density is WAY off. Compare and calibrate with what's in SL. (DONE) | ||
309 | (Resolution: set default density to 3.5 (from 60) which is closer to SL) | ||
310 | Redo BulletSimAPI to allow native C# implementation of Bullet option (DONE) | ||
311 | (Resolution: added BSAPITemplate and then interfaces for C++ Bullet and C# BulletXNA | ||
312 | Meshes rendering as bounding boxes (DONE) | ||
313 | (Resolution: Added test for mesh/sculpties in native shapes so it didn't think it was a box) | ||
314 | llMoveToTarget (Resolution: added simple motor to update the position.) | ||
315 | Angular motor direction is global coordinates rather than local coordinates (DONE) | ||
316 | Add vehicle collisions so IsColliding is properly reported. (DONE) | ||
317 | Needed for banking, limitMotorUp, movementLimiting, ... | ||
318 | (Resolution: added CollisionFlags.BS_VEHICLE_COLLISION and code to use it) | ||
319 | VehicleAddForce is not scaled by the simulation step but it is only | ||
320 | applied for one step. Should it be scaled? (DONE) | ||
321 | (Resolution: use force for timed things, Impulse for immediate, non-timed things) | ||
322 | Complete implemention of preStepActions (DONE) | ||
323 | Replace vehicle step call with prestep event. | ||
324 | Is there a need for postStepActions? postStepTaints? | ||
325 | Disable activity of passive linkset children. (DONE) | ||
326 | Since the linkset is a compound object, the old prims are left lying | ||
327 | around and need to be phantomized so they don't collide, ... | ||
328 | Remove HeightmapInfo from terrain specification (DONE) | ||
329 | Since C++ code does not need terrain height, this structure et al are not needed. | ||
330 | Surfboard go wonky when turning (DONE) | ||
331 | Angular motor direction is global coordinates rather than local coordinates? | ||
332 | (Resolution: made angular motor direction correct coordinate system) | ||
333 | Mantis 6040 script http://opensimulator.org/mantis/view.php?id=6040 (DONE) | ||
334 | Msg Kayaker on OSGrid when working | ||
335 | (Resolution: LINEAR_DIRECTION is in vehicle coords. Test script does the | ||
336 | same in SL as in OS/BulletSim) | ||
337 | Boats float low in the water (DONE) | ||
338 | Boats floating at proper level (DONE) | ||
339 | When is force introduced by SetForce removed? The prestep action could go forever. (DONE) | ||
340 | (Resolution: setForce registers a prestep action which keeps applying the force) | ||
341 | Child movement in linkset (don't rebuild linkset) (DONE 20130122)) | ||
342 | Avatar standing on a moving object should start to move with the object. (DONE 20130125) | ||
343 | Angular motion around Z moves the vehicle in world Z and not vehicle Z in ODE. | ||
344 | Verify that angular motion specified around Z moves in the vehicle coordinates. | ||
345 | DONE 20130120: BulletSim properly applies force in vehicle relative coordinates. | ||
346 | Nebadon vehicles turning funny in arena (DONE) | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs b/OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs index 0d1db3b..02b03a8 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs | |||
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices; | |||
29 | // Build Number | 29 | // Build Number |
30 | // Revision | 30 | // Revision |
31 | // | 31 | // |
32 | [assembly: AssemblyVersion("0.7.5.*")] | 32 | [assembly: AssemblyVersion("0.7.6.*")] |
33 | [assembly: AssemblyFileVersion("1.0.0.0")] | 33 | |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs b/OpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs new file mode 100755 index 0000000..33232bd --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs | |||
@@ -0,0 +1,150 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Linq; | ||
31 | using System.Text; | ||
32 | |||
33 | using NUnit.Framework; | ||
34 | using log4net; | ||
35 | |||
36 | using OpenSim.Framework; | ||
37 | using OpenSim.Region.Physics.BulletSPlugin; | ||
38 | using OpenSim.Region.Physics.Manager; | ||
39 | using OpenSim.Tests.Common; | ||
40 | |||
41 | using OpenMetaverse; | ||
42 | |||
43 | namespace OpenSim.Region.Physics.BulletSPlugin.Tests | ||
44 | { | ||
45 | [TestFixture] | ||
46 | public class BasicVehicles : OpenSimTestCase | ||
47 | { | ||
48 | // Documentation on attributes: http://www.nunit.org/index.php?p=attributes&r=2.6.1 | ||
49 | // Documentation on assertions: http://www.nunit.org/index.php?p=assertions&r=2.6.1 | ||
50 | |||
51 | BSScene PhysicsScene { get; set; } | ||
52 | BSPrim TestVehicle { get; set; } | ||
53 | Vector3 TestVehicleInitPosition { get; set; } | ||
54 | float simulationTimeStep = 0.089f; | ||
55 | |||
56 | [TestFixtureSetUp] | ||
57 | public void Init() | ||
58 | { | ||
59 | Dictionary<string, string> engineParams = new Dictionary<string, string>(); | ||
60 | PhysicsScene = BulletSimTestsUtil.CreateBasicPhysicsEngine(engineParams); | ||
61 | |||
62 | PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateSphere(); | ||
63 | Vector3 pos = new Vector3(100.0f, 100.0f, 0f); | ||
64 | pos.Z = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos) + 2f; | ||
65 | TestVehicleInitPosition = pos; | ||
66 | Vector3 size = new Vector3(1f, 1f, 1f); | ||
67 | pbs.Scale = size; | ||
68 | Quaternion rot = Quaternion.Identity; | ||
69 | bool isPhys = false; | ||
70 | uint localID = 123; | ||
71 | |||
72 | PhysicsScene.AddPrimShape("testPrim", pbs, pos, size, rot, isPhys, localID); | ||
73 | TestVehicle = (BSPrim)PhysicsScene.PhysObjects[localID]; | ||
74 | // The actual prim shape creation happens at taint time | ||
75 | PhysicsScene.ProcessTaints(); | ||
76 | |||
77 | } | ||
78 | |||
79 | [TestFixtureTearDown] | ||
80 | public void TearDown() | ||
81 | { | ||
82 | if (PhysicsScene != null) | ||
83 | { | ||
84 | // The Dispose() will also free any physical objects in the scene | ||
85 | PhysicsScene.Dispose(); | ||
86 | PhysicsScene = null; | ||
87 | } | ||
88 | } | ||
89 | |||
90 | [TestCase(2f, 0.2f, 0.25f, 0.25f, 0.25f)] | ||
91 | [TestCase(2f, 0.2f, -0.25f, 0.25f, 0.25f)] | ||
92 | [TestCase(2f, 0.2f, 0.25f, -0.25f, 0.25f)] | ||
93 | [TestCase(2f, 0.2f, -0.25f, -0.25f, 0.25f)] | ||
94 | // [TestCase(2f, 0.2f, 0.785f, 0.0f, 0.25f) /*, "Leaning 45 degrees to the side" */] | ||
95 | // [TestCase(2f, 0.2f, 1.650f, 0.0f, 0.25f) /*, "Leaning more than 90 degrees to the side" */] | ||
96 | // [TestCase(2f, 0.2f, 2.750f, 0.0f, 0.25f) /*, "Almost upside down, tipped right" */] | ||
97 | // [TestCase(2f, 0.2f,-2.750f, 0.0f, 0.25f) /*, "Almost upside down, tipped left" */] | ||
98 | // [TestCase(2f, 0.2f, 0.0f, 0.785f, 0.25f) /*, "Tipped back 45 degrees" */] | ||
99 | // [TestCase(2f, 0.2f, 0.0f, 1.650f, 0.25f) /*, "Tipped back more than 90 degrees" */] | ||
100 | // [TestCase(2f, 0.2f, 0.0f, 2.750f, 0.25f) /*, "Almost upside down, tipped back" */] | ||
101 | // [TestCase(2f, 0.2f, 0.0f,-2.750f, 0.25f) /*, "Almost upside down, tipped forward" */] | ||
102 | public void AngularVerticalAttraction(float timeScale, float efficiency, float initRoll, float initPitch, float initYaw) | ||
103 | { | ||
104 | // Enough simulation steps to cover the timescale the operation should take | ||
105 | int simSteps = (int)(timeScale / simulationTimeStep) + 1; | ||
106 | |||
107 | // Tip the vehicle | ||
108 | Quaternion initOrientation = Quaternion.CreateFromEulers(initRoll, initPitch, initYaw); | ||
109 | TestVehicle.Orientation = initOrientation; | ||
110 | |||
111 | TestVehicle.Position = TestVehicleInitPosition; | ||
112 | |||
113 | // The vehicle controller is not enabled directly (by setting a vehicle type). | ||
114 | // Instead the appropriate values are set and calls are made just the parts of the | ||
115 | // controller we want to exercise. Stepping the physics engine then applies | ||
116 | // the actions of that one feature. | ||
117 | TestVehicle.VehicleController.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_EFFICIENCY, efficiency); | ||
118 | TestVehicle.VehicleController.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_TIMESCALE, timeScale); | ||
119 | TestVehicle.VehicleController.enableAngularVerticalAttraction = true; | ||
120 | |||
121 | TestVehicle.IsPhysical = true; | ||
122 | PhysicsScene.ProcessTaints(); | ||
123 | |||
124 | // Step the simulator a bunch of times and vertical attraction should orient the vehicle up | ||
125 | for (int ii = 0; ii < simSteps; ii++) | ||
126 | { | ||
127 | TestVehicle.VehicleController.ForgetKnownVehicleProperties(); | ||
128 | TestVehicle.VehicleController.ComputeAngularVerticalAttraction(); | ||
129 | TestVehicle.VehicleController.PushKnownChanged(); | ||
130 | |||
131 | PhysicsScene.Simulate(simulationTimeStep); | ||
132 | } | ||
133 | |||
134 | TestVehicle.IsPhysical = false; | ||
135 | PhysicsScene.ProcessTaints(); | ||
136 | |||
137 | // After these steps, the vehicle should be upright | ||
138 | /* | ||
139 | float finalRoll, finalPitch, finalYaw; | ||
140 | TestVehicle.Orientation.GetEulerAngles(out finalRoll, out finalPitch, out finalYaw); | ||
141 | Assert.That(finalRoll, Is.InRange(-0.01f, 0.01f)); | ||
142 | Assert.That(finalPitch, Is.InRange(-0.01f, 0.01f)); | ||
143 | Assert.That(finalYaw, Is.InRange(initYaw - 0.1f, initYaw + 0.1f)); | ||
144 | */ | ||
145 | |||
146 | Vector3 upPointer = Vector3.UnitZ * TestVehicle.Orientation; | ||
147 | Assert.That(upPointer.Z, Is.GreaterThan(0.99f)); | ||
148 | } | ||
149 | } | ||
150 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/Framework/Scenes/Scripting/IScriptHost.cs b/OpenSim/Region/Physics/BulletSPlugin/Tests/BulletSimTests.cs index f3be028..35cbc1d 100644..100755 --- a/OpenSim/Region/Framework/Scenes/Scripting/IScriptHost.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/Tests/BulletSimTests.cs | |||
@@ -1,46 +1,56 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) Contributors, http://opensimulator.org/ | 2 | * Copyright (c) Contributors, http://opensimulator.org/ |
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | 3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. |
4 | * | 4 | * |
5 | * Redistribution and use in source and binary forms, with or without | 5 | * Redistribution and use in source and binary forms, with or without |
6 | * modification, are permitted provided that the following conditions are met: | 6 | * modification, are permitted provided that the following conditions are met: |
7 | * * Redistributions of source code must retain the above copyright | 7 | * * Redistributions of source code must retain the above copyright |
8 | * notice, this list of conditions and the following disclaimer. | 8 | * notice, this list of conditions and the following disclaimer. |
9 | * * Redistributions in binary form must reproduce the above copyright | 9 | * * Redistributions in binary form must reproduce the above copyright |
10 | * notice, this list of conditions and the following disclaimer in the | 10 | * notice, this list of conditions and the following disclaimer in the |
11 | * documentation and/or other materials provided with the distribution. | 11 | * documentation and/or other materials provided with the distribution. |
12 | * * Neither the name of the OpenSimulator Project nor the | 12 | * * Neither the name of the OpenSimulator Project nor the |
13 | * names of its contributors may be used to endorse or promote products | 13 | * names of its contributors may be used to endorse or promote products |
14 | * derived from this software without specific prior written permission. | 14 | * derived from this software without specific prior written permission. |
15 | * | 15 | * |
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | 16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY |
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | 17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | 19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY |
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | 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 | 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 | 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 | 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. | 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | */ | 26 | */ |
27 | 27 | ||
28 | using OpenMetaverse; | 28 | using System; |
29 | 29 | using System.Collections.Generic; | |
30 | namespace OpenSim.Region.Framework.Scenes.Scripting | 30 | using System.Linq; |
31 | { | 31 | using System.Text; |
32 | public interface IScriptHost | 32 | |
33 | { | 33 | using NUnit.Framework; |
34 | string Name { get; set; } | 34 | using log4net; |
35 | string Description { get; set; } | 35 | |
36 | 36 | using OpenSim.Tests.Common; | |
37 | UUID UUID { get; } | 37 | |
38 | UUID OwnerID { get; } | 38 | namespace OpenSim.Region.Physics.BulletSPlugin.Tests |
39 | UUID CreatorID { get; } | 39 | { |
40 | Vector3 AbsolutePosition { get; } | 40 | [TestFixture] |
41 | 41 | public class BulletSimTests : OpenSimTestCase | |
42 | string SitName { get; set; } | 42 | { |
43 | string TouchName { get; set; } | 43 | // Documentation on attributes: http://www.nunit.org/index.php?p=attributes&r=2.6.1 |
44 | void SetText(string text, Vector3 color, double alpha); | 44 | // Documentation on assertions: http://www.nunit.org/index.php?p=assertions&r=2.6.1 |
45 | } | 45 | |
46 | } | 46 | [TestFixtureSetUp] |
47 | public void Init() | ||
48 | { | ||
49 | } | ||
50 | |||
51 | [TestFixtureTearDown] | ||
52 | public void TearDown() | ||
53 | { | ||
54 | } | ||
55 | } | ||
56 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/Tests/BulletSimTestsUtil.cs b/OpenSim/Region/Physics/BulletSPlugin/Tests/BulletSimTestsUtil.cs new file mode 100755 index 0000000..28207a4 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/Tests/BulletSimTestsUtil.cs | |||
@@ -0,0 +1,95 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.IO; | ||
30 | using System.Collections.Generic; | ||
31 | using System.Linq; | ||
32 | using System.Text; | ||
33 | |||
34 | using Nini.Config; | ||
35 | |||
36 | using OpenSim.Framework; | ||
37 | using OpenSim.Region.Physics.BulletSPlugin; | ||
38 | using OpenSim.Region.Physics.Meshing; | ||
39 | |||
40 | namespace OpenSim.Region.Physics.BulletSPlugin.Tests | ||
41 | { | ||
42 | // Utility functions for building up and tearing down the sample physics environments | ||
43 | public static class BulletSimTestsUtil | ||
44 | { | ||
45 | // 'engineName' is the Bullet engine to use. Either null (for unmanaged), "BulletUnmanaged" or "BulletXNA" | ||
46 | // 'params' is a set of keyValue pairs to set in the engine's configuration file (override defaults) | ||
47 | // May be 'null' if there are no overrides. | ||
48 | public static BSScene CreateBasicPhysicsEngine(Dictionary<string,string> paramOverrides) | ||
49 | { | ||
50 | IConfigSource openSimINI = new IniConfigSource(); | ||
51 | IConfig startupConfig = openSimINI.AddConfig("Startup"); | ||
52 | startupConfig.Set("physics", "BulletSim"); | ||
53 | startupConfig.Set("meshing", "Meshmerizer"); | ||
54 | startupConfig.Set("cacheSculptMaps", "false"); // meshmerizer shouldn't save maps | ||
55 | |||
56 | IConfig bulletSimConfig = openSimINI.AddConfig("BulletSim"); | ||
57 | // If the caller cares, specify the bullet engine otherwise it will default to "BulletUnmanaged". | ||
58 | // bulletSimConfig.Set("BulletEngine", "BulletUnmanaged"); | ||
59 | // bulletSimConfig.Set("BulletEngine", "BulletXNA"); | ||
60 | bulletSimConfig.Set("MeshSculptedPrim", "false"); | ||
61 | bulletSimConfig.Set("ForceSimplePrimMeshing", "true"); | ||
62 | if (paramOverrides != null) | ||
63 | { | ||
64 | foreach (KeyValuePair<string, string> kvp in paramOverrides) | ||
65 | { | ||
66 | bulletSimConfig.Set(kvp.Key, kvp.Value); | ||
67 | } | ||
68 | } | ||
69 | |||
70 | // If a special directory exists, put detailed logging therein. | ||
71 | // This allows local testing/debugging without having to worry that the build engine will output logs. | ||
72 | if (Directory.Exists("physlogs")) | ||
73 | { | ||
74 | bulletSimConfig.Set("PhysicsLoggingDir","./physlogs"); | ||
75 | bulletSimConfig.Set("PhysicsLoggingEnabled","True"); | ||
76 | bulletSimConfig.Set("PhysicsLoggingDoFlush","True"); | ||
77 | bulletSimConfig.Set("VehicleLoggingEnabled","True"); | ||
78 | } | ||
79 | |||
80 | BSPlugin bsPlugin = new BSPlugin(); | ||
81 | |||
82 | BSScene bsScene = (BSScene)bsPlugin.GetScene("BSTestRegion"); | ||
83 | |||
84 | // Since the asset requestor is not initialized, any mesh or sculptie will be a cube. | ||
85 | // In the future, add a fake asset fetcher to get meshes and sculpts. | ||
86 | // bsScene.RequestAssetMethod = ???; | ||
87 | |||
88 | Meshing.Meshmerizer mesher = new Meshmerizer(openSimINI); | ||
89 | bsScene.Initialise(mesher, openSimINI); | ||
90 | |||
91 | return bsScene; | ||
92 | } | ||
93 | |||
94 | } | ||
95 | } | ||
diff --git a/OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs index 8de70ef..ba24aa7 100644 --- a/OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs +++ b/OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs | |||
@@ -2190,7 +2190,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
2190 | convex = false; | 2190 | convex = false; |
2191 | try | 2191 | try |
2192 | { | 2192 | { |
2193 | _mesh = _parent_scene.mesher.CreateMesh(m_primName, _pbs, _size, (int)LevelOfDetail.High, true,convex,false); | 2193 | _mesh = _parent_scene.mesher.CreateMesh(m_primName, _pbs, _size, (int)LevelOfDetail.High, true,false,convex,false); |
2194 | } | 2194 | } |
2195 | catch | 2195 | catch |
2196 | { | 2196 | { |
@@ -2557,7 +2557,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
2557 | 2557 | ||
2558 | try | 2558 | try |
2559 | { | 2559 | { |
2560 | mesh = _parent_scene.mesher.CreateMesh(oldname, _pbs, _size, (int)LevelOfDetail.High, true, convex,false); | 2560 | mesh = _parent_scene.mesher.CreateMesh(oldname, _pbs, _size, (int)LevelOfDetail.High, true, false,convex,false); |
2561 | } | 2561 | } |
2562 | catch | 2562 | catch |
2563 | { | 2563 | { |
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/Properties/AssemblyInfo.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/Properties/AssemblyInfo.cs index 5ff945d..f611b9a 100644 --- a/OpenSim/Region/Physics/ConvexDecompositionDotNet/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/Physics/ConvexDecompositionDotNet/Properties/AssemblyInfo.cs | |||
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices; | |||
32 | // You can specify all the values or you can default the Build and Revision Numbers | 32 | // You can specify all the values or you can default the Build and Revision Numbers |
33 | // by using the '*' as shown below: | 33 | // by using the '*' as shown below: |
34 | // [assembly: AssemblyVersion("1.0.*")] | 34 | // [assembly: AssemblyVersion("1.0.*")] |
35 | [assembly: AssemblyVersion("0.7.5.*")] | 35 | [assembly: AssemblyVersion("0.7.6.*")] |
36 | [assembly: AssemblyFileVersion("1.0.0.0")] | 36 | |
diff --git a/OpenSim/Region/Physics/Manager/AssemblyInfo.cs b/OpenSim/Region/Physics/Manager/AssemblyInfo.cs index 36b4235..5da3956 100644 --- a/OpenSim/Region/Physics/Manager/AssemblyInfo.cs +++ b/OpenSim/Region/Physics/Manager/AssemblyInfo.cs | |||
@@ -55,4 +55,4 @@ using System.Runtime.InteropServices; | |||
55 | // You can specify all values by your own or you can build default build and revision | 55 | // You can specify all values by your own or you can build default build and revision |
56 | // numbers with the '*' character (the default): | 56 | // numbers with the '*' character (the default): |
57 | 57 | ||
58 | [assembly : AssemblyVersion("0.7.5.*")] | 58 | [assembly : AssemblyVersion("0.7.6.*")] |
diff --git a/OpenSim/Region/Physics/Manager/IMesher.cs b/OpenSim/Region/Physics/Manager/IMesher.cs index ecc2918..5485eb7 100644 --- a/OpenSim/Region/Physics/Manager/IMesher.cs +++ b/OpenSim/Region/Physics/Manager/IMesher.cs | |||
@@ -37,7 +37,7 @@ namespace OpenSim.Region.Physics.Manager | |||
37 | { | 37 | { |
38 | IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod); | 38 | IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod); |
39 | IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical); | 39 | IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical); |
40 | IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex, bool forOde); | 40 | IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache, bool convex, bool forOde); |
41 | IMesh GetMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex); | 41 | IMesh GetMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex); |
42 | void ReleaseMesh(IMesh mesh); | 42 | void ReleaseMesh(IMesh mesh); |
43 | void ExpireReleaseMeshs(); | 43 | void ExpireReleaseMeshs(); |
@@ -83,6 +83,7 @@ namespace OpenSim.Region.Physics.Manager | |||
83 | List<Vector3> getVertexList(); | 83 | List<Vector3> getVertexList(); |
84 | int[] getIndexListAsInt(); | 84 | int[] getIndexListAsInt(); |
85 | int[] getIndexListAsIntLocked(); | 85 | int[] getIndexListAsIntLocked(); |
86 | float[] getVertexListAsFloat(); | ||
86 | float[] getVertexListAsFloatLocked(); | 87 | float[] getVertexListAsFloatLocked(); |
87 | void getIndexListAsPtrToIntArray(out IntPtr indices, out int triStride, out int indexCount); | 88 | void getIndexListAsPtrToIntArray(out IntPtr indices, out int triStride, out int indexCount); |
88 | void getVertexListAsPtrToFloatArray(out IntPtr vertexList, out int vertexStride, out int vertexCount); | 89 | void getVertexListAsPtrToFloatArray(out IntPtr vertexList, out int vertexStride, out int vertexCount); |
diff --git a/OpenSim/Region/Physics/Manager/IPhysicsParameters.cs b/OpenSim/Region/Physics/Manager/IPhysicsParameters.cs index b8676ba..31a397c 100755 --- a/OpenSim/Region/Physics/Manager/IPhysicsParameters.cs +++ b/OpenSim/Region/Physics/Manager/IPhysicsParameters.cs | |||
@@ -60,14 +60,14 @@ namespace OpenSim.Region.Physics.Manager | |||
60 | 60 | ||
61 | // Set parameter on a specific or all instances. | 61 | // Set parameter on a specific or all instances. |
62 | // Return 'false' if not able to set the parameter. | 62 | // Return 'false' if not able to set the parameter. |
63 | bool SetPhysicsParameter(string parm, float value, uint localID); | 63 | bool SetPhysicsParameter(string parm, string value, uint localID); |
64 | 64 | ||
65 | // Get parameter. | 65 | // Get parameter. |
66 | // Return 'false' if not able to get the parameter. | 66 | // Return 'false' if not able to get the parameter. |
67 | bool GetPhysicsParameter(string parm, out float value); | 67 | bool GetPhysicsParameter(string parm, out string value); |
68 | 68 | ||
69 | // Get parameter from a particular object | 69 | // Get parameter from a particular object |
70 | // TODO: | 70 | // TODO: |
71 | // bool GetPhysicsParameter(string parm, out float value, uint localID); | 71 | // bool GetPhysicsParameter(string parm, out string value, uint localID); |
72 | } | 72 | } |
73 | } | 73 | } |
diff --git a/OpenSim/Region/Physics/Manager/PhysicsActor.cs b/OpenSim/Region/Physics/Manager/PhysicsActor.cs index 9338130..7cd364b 100644 --- a/OpenSim/Region/Physics/Manager/PhysicsActor.cs +++ b/OpenSim/Region/Physics/Manager/PhysicsActor.cs | |||
@@ -274,7 +274,7 @@ namespace OpenSim.Region.Physics.Manager | |||
274 | public virtual float Density { get; set; } | 274 | public virtual float Density { get; set; } |
275 | public virtual float GravModifier { get; set; } | 275 | public virtual float GravModifier { get; set; } |
276 | public virtual float Friction { get; set; } | 276 | public virtual float Friction { get; set; } |
277 | public virtual float Bounce { get; set; } | 277 | public virtual float Restitution { get; set; } |
278 | 278 | ||
279 | /// <summary> | 279 | /// <summary> |
280 | /// Position of this actor. | 280 | /// Position of this actor. |
@@ -349,17 +349,20 @@ namespace OpenSim.Region.Physics.Manager | |||
349 | } | 349 | } |
350 | 350 | ||
351 | /// <summary> | 351 | /// <summary> |
352 | /// Velocity of this actor. | 352 | /// The desired velocity of this actor. |
353 | /// </summary> | 353 | /// </summary> |
354 | /// <remarks> | 354 | /// <remarks> |
355 | /// Setting this provides a target velocity for physics scene updates. | 355 | /// Setting this provides a target velocity for physics scene updates. |
356 | /// Getting this returns the velocity calculated by physics scene updates, using factors such as target velocity, | 356 | /// Getting this returns the last set target. Fetch Velocity to get the current velocity. |
357 | /// time to accelerate and collisions. | ||
358 | /// </remarks> | 357 | /// </remarks> |
358 | protected Vector3 m_targetVelocity; | ||
359 | public virtual Vector3 TargetVelocity | 359 | public virtual Vector3 TargetVelocity |
360 | { | 360 | { |
361 | get { return Velocity; } | 361 | get { return m_targetVelocity; } |
362 | set { Velocity = value; } | 362 | set { |
363 | m_targetVelocity = value; | ||
364 | Velocity = m_targetVelocity; | ||
365 | } | ||
363 | } | 366 | } |
364 | 367 | ||
365 | public abstract Vector3 Velocity { get; set; } | 368 | public abstract Vector3 Velocity { get; set; } |
diff --git a/OpenSim/Region/Physics/Manager/PhysicsPluginManager.cs b/OpenSim/Region/Physics/Manager/PhysicsPluginManager.cs index 8587a2b..8ccfda5 100644 --- a/OpenSim/Region/Physics/Manager/PhysicsPluginManager.cs +++ b/OpenSim/Region/Physics/Manager/PhysicsPluginManager.cs | |||
@@ -30,7 +30,7 @@ using System.Collections.Generic; | |||
30 | using System.IO; | 30 | using System.IO; |
31 | using System.Reflection; | 31 | using System.Reflection; |
32 | using Nini.Config; | 32 | using Nini.Config; |
33 | using log4net; | 33 | using log4net; |
34 | using OpenSim.Framework; | 34 | using OpenSim.Framework; |
35 | 35 | ||
36 | namespace OpenSim.Region.Physics.Manager | 36 | namespace OpenSim.Region.Physics.Manager |
diff --git a/OpenSim/Region/Physics/Manager/PhysicsScene.cs b/OpenSim/Region/Physics/Manager/PhysicsScene.cs index 57e2d20..20a70b4 100644 --- a/OpenSim/Region/Physics/Manager/PhysicsScene.cs +++ b/OpenSim/Region/Physics/Manager/PhysicsScene.cs | |||
@@ -47,7 +47,7 @@ namespace OpenSim.Region.Physics.Manager | |||
47 | public delegate void JointDeactivated(PhysicsJoint joint); | 47 | public delegate void JointDeactivated(PhysicsJoint joint); |
48 | public delegate void JointErrorMessage(PhysicsJoint joint, string message); // this refers to an "error message due to a problem", not "amount of joint constraint violation" | 48 | public delegate void JointErrorMessage(PhysicsJoint joint, string message); // this refers to an "error message due to a problem", not "amount of joint constraint violation" |
49 | 49 | ||
50 | public enum RayFilterFlags:ushort | 50 | public enum RayFilterFlags : ushort |
51 | { | 51 | { |
52 | // the flags | 52 | // the flags |
53 | water = 0x01, | 53 | water = 0x01, |
@@ -64,7 +64,7 @@ namespace OpenSim.Region.Physics.Manager | |||
64 | ClosestHit = 0x8000, | 64 | ClosestHit = 0x8000, |
65 | 65 | ||
66 | // some combinations | 66 | // some combinations |
67 | LSLPhanton = phantom | volumedtc, | 67 | LSLPhantom = phantom | volumedtc, |
68 | PrimsNonPhantom = nonphysical | physical, | 68 | PrimsNonPhantom = nonphysical | physical, |
69 | PrimsNonPhantomAgents = nonphysical | physical | agent, | 69 | PrimsNonPhantomAgents = nonphysical | physical | agent, |
70 | 70 | ||
@@ -97,13 +97,20 @@ namespace OpenSim.Region.Physics.Manager | |||
97 | // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 97 | // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
98 | 98 | ||
99 | /// <summary> | 99 | /// <summary> |
100 | /// Name of this scene. Useful in debug messages to distinguish one OdeScene instance from another. | 100 | /// A unique identifying string for this instance of the physics engine. |
101 | /// Useful in debug messages to distinguish one OdeScene instance from another. | ||
102 | /// Usually set to include the region name that the physics engine is acting for. | ||
101 | /// </summary> | 103 | /// </summary> |
102 | public string Name { get; protected set; } | 104 | public string Name { get; protected set; } |
103 | 105 | ||
106 | /// <summary> | ||
107 | /// A string identifying the family of this physics engine. Most common values returned | ||
108 | /// are "OpenDynamicsEngine" and "BulletSim" but others are possible. | ||
109 | /// </summary> | ||
110 | public string EngineType { get; protected set; } | ||
111 | |||
104 | // The only thing that should register for this event is the SceneGraph | 112 | // The only thing that should register for this event is the SceneGraph |
105 | // Anything else could cause problems. | 113 | // Anything else could cause problems. |
106 | |||
107 | public event physicsCrash OnPhysicsCrash; | 114 | public event physicsCrash OnPhysicsCrash; |
108 | 115 | ||
109 | public static PhysicsScene Null | 116 | public static PhysicsScene Null |
diff --git a/OpenSim/Region/Physics/Manager/ZeroMesher.cs b/OpenSim/Region/Physics/Manager/ZeroMesher.cs index 16846e6..80ecf66 100644 --- a/OpenSim/Region/Physics/Manager/ZeroMesher.cs +++ b/OpenSim/Region/Physics/Manager/ZeroMesher.cs | |||
@@ -64,16 +64,21 @@ namespace OpenSim.Region.Physics.Manager | |||
64 | { | 64 | { |
65 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) | 65 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) |
66 | { | 66 | { |
67 | return CreateMesh(primName, primShape, size, lod, false); | 67 | return CreateMesh(primName, primShape, size, lod, false, false); |
68 | } | 68 | } |
69 | 69 | ||
70 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex,bool forOde) | 70 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache, bool convex,bool forOde) |
71 | { | 71 | { |
72 | return CreateMesh(primName, primShape, size, lod, false); | 72 | return CreateMesh(primName, primShape, size, lod, false); |
73 | } | 73 | } |
74 | 74 | ||
75 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical) | 75 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical) |
76 | { | 76 | { |
77 | return CreateMesh(primName, primShape, size, lod, false, false); | ||
78 | } | ||
79 | |||
80 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache) | ||
81 | { | ||
77 | // Remove the reference to the encoded JPEG2000 data so it can be GCed | 82 | // Remove the reference to the encoded JPEG2000 data so it can be GCed |
78 | primShape.SculptData = OpenMetaverse.Utils.EmptyBytes; | 83 | primShape.SculptData = OpenMetaverse.Utils.EmptyBytes; |
79 | 84 | ||
diff --git a/OpenSim/Region/Physics/Meshing/Mesh.cs b/OpenSim/Region/Physics/Meshing/Mesh.cs index 6970553..e6b32e7 100644 --- a/OpenSim/Region/Physics/Meshing/Mesh.cs +++ b/OpenSim/Region/Physics/Meshing/Mesh.cs | |||
@@ -226,7 +226,7 @@ namespace OpenSim.Region.Physics.Meshing | |||
226 | return result; | 226 | return result; |
227 | } | 227 | } |
228 | 228 | ||
229 | private float[] getVertexListAsFloat() | 229 | public float[] getVertexListAsFloat() |
230 | { | 230 | { |
231 | if (m_vertices == null) | 231 | if (m_vertices == null) |
232 | throw new NotSupportedException(); | 232 | throw new NotSupportedException(); |
diff --git a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs index f629c4d..d181b78 100644 --- a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs +++ b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs | |||
@@ -321,6 +321,9 @@ namespace OpenSim.Region.Physics.Meshing | |||
321 | 321 | ||
322 | if (primShape.SculptData.Length <= 0) | 322 | if (primShape.SculptData.Length <= 0) |
323 | { | 323 | { |
324 | // XXX: At the moment we can not log here since ODEPrim, for instance, ends up triggering this | ||
325 | // method twice - once before it has loaded sculpt data from the asset service and once afterwards. | ||
326 | // The first time will always call with unloaded SculptData if this needs to be uploaded. | ||
324 | // m_log.ErrorFormat("[MESH]: asset data for {0} is zero length", primName); | 327 | // m_log.ErrorFormat("[MESH]: asset data for {0} is zero length", primName); |
325 | return false; | 328 | return false; |
326 | } | 329 | } |
@@ -699,16 +702,21 @@ namespace OpenSim.Region.Physics.Meshing | |||
699 | 702 | ||
700 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) | 703 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) |
701 | { | 704 | { |
702 | return CreateMesh(primName, primShape, size, lod, false); | 705 | return CreateMesh(primName, primShape, size, lod, false, true); |
703 | } | 706 | } |
704 | 707 | ||
705 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex, bool forOde) | 708 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache, bool convex, bool forOde) |
706 | { | 709 | { |
707 | return CreateMesh(primName, primShape, size, lod, false); | 710 | return CreateMesh(primName, primShape, size, lod, false); |
708 | } | 711 | } |
709 | 712 | ||
710 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical) | 713 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical) |
711 | { | 714 | { |
715 | return CreateMesh(primName, primShape, size, lod, isPhysical, true); | ||
716 | } | ||
717 | |||
718 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache) | ||
719 | { | ||
712 | #if SPAM | 720 | #if SPAM |
713 | m_log.DebugFormat("[MESH]: Creating mesh for {0}", primName); | 721 | m_log.DebugFormat("[MESH]: Creating mesh for {0}", primName); |
714 | #endif | 722 | #endif |
@@ -718,9 +726,12 @@ namespace OpenSim.Region.Physics.Meshing | |||
718 | 726 | ||
719 | // If this mesh has been created already, return it instead of creating another copy | 727 | // If this mesh has been created already, return it instead of creating another copy |
720 | // For large regions with 100k+ prims and hundreds of copies of each, this can save a GB or more of memory | 728 | // For large regions with 100k+ prims and hundreds of copies of each, this can save a GB or more of memory |
721 | key = primShape.GetMeshKey(size, lod); | 729 | if (shouldCache) |
722 | if (m_uniqueMeshes.TryGetValue(key, out mesh)) | 730 | { |
723 | return mesh; | 731 | key = primShape.GetMeshKey(size, lod); |
732 | if (m_uniqueMeshes.TryGetValue(key, out mesh)) | ||
733 | return mesh; | ||
734 | } | ||
724 | 735 | ||
725 | if (size.X < 0.01f) size.X = 0.01f; | 736 | if (size.X < 0.01f) size.X = 0.01f; |
726 | if (size.Y < 0.01f) size.Y = 0.01f; | 737 | if (size.Y < 0.01f) size.Y = 0.01f; |
@@ -743,7 +754,10 @@ namespace OpenSim.Region.Physics.Meshing | |||
743 | // trim the vertex and triangle lists to free up memory | 754 | // trim the vertex and triangle lists to free up memory |
744 | mesh.TrimExcess(); | 755 | mesh.TrimExcess(); |
745 | 756 | ||
746 | m_uniqueMeshes.Add(key, mesh); | 757 | if (shouldCache) |
758 | { | ||
759 | m_uniqueMeshes.Add(key, mesh); | ||
760 | } | ||
747 | } | 761 | } |
748 | 762 | ||
749 | return mesh; | 763 | return mesh; |
diff --git a/OpenSim/Region/Physics/Meshing/Properties/AssemblyInfo.cs b/OpenSim/Region/Physics/Meshing/Properties/AssemblyInfo.cs index 4cc1731..3de061a 100644 --- a/OpenSim/Region/Physics/Meshing/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/Physics/Meshing/Properties/AssemblyInfo.cs | |||
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices; | |||
29 | // Build Number | 29 | // Build Number |
30 | // Revision | 30 | // Revision |
31 | // | 31 | // |
32 | [assembly: AssemblyVersion("0.7.5.*")] | 32 | [assembly: AssemblyVersion("0.7.6.*")] |
33 | [assembly: AssemblyFileVersion("1.0.0.0")] | 33 | |
diff --git a/OpenSim/Region/Physics/OdePlugin/AssemblyInfo.cs b/OpenSim/Region/Physics/OdePlugin/AssemblyInfo.cs index 3c4f06a..f477ed1 100644 --- a/OpenSim/Region/Physics/OdePlugin/AssemblyInfo.cs +++ b/OpenSim/Region/Physics/OdePlugin/AssemblyInfo.cs | |||
@@ -55,4 +55,4 @@ using System.Runtime.InteropServices; | |||
55 | // You can specify all values by your own or you can build default build and revision | 55 | // You can specify all values by your own or you can build default build and revision |
56 | // numbers with the '*' character (the default): | 56 | // numbers with the '*' character (the default): |
57 | 57 | ||
58 | [assembly : AssemblyVersion("0.7.5.*")] | 58 | [assembly : AssemblyVersion("0.7.6.*")] |
diff --git a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs index a59f63f..d09aa62 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs | |||
@@ -3367,6 +3367,11 @@ Console.WriteLine(" JointCreateFixed"); | |||
3367 | _pbs.SculptData = new byte[asset.Data.Length]; | 3367 | _pbs.SculptData = new byte[asset.Data.Length]; |
3368 | asset.Data.CopyTo(_pbs.SculptData, 0); | 3368 | asset.Data.CopyTo(_pbs.SculptData, 0); |
3369 | // m_assetFailed = false; | 3369 | // m_assetFailed = false; |
3370 | |||
3371 | // m_log.DebugFormat( | ||
3372 | // "[ODE PRIM]: Received mesh/sculpt data asset {0} with {1} bytes for {2} at {3} in {4}", | ||
3373 | // _pbs.SculptTexture, _pbs.SculptData.Length, Name, _position, _parent_scene.Name); | ||
3374 | |||
3370 | m_taintshape = true; | 3375 | m_taintshape = true; |
3371 | _parent_scene.AddPhysicsActorTaint(this); | 3376 | _parent_scene.AddPhysicsActorTaint(this); |
3372 | } | 3377 | } |
diff --git a/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs b/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs index 478dd95..07663b3 100644 --- a/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs +++ b/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs | |||
@@ -72,7 +72,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
72 | // http://opensimulator.org/mantis/view.php?id=2750). | 72 | // http://opensimulator.org/mantis/view.php?id=2750). |
73 | d.InitODE(); | 73 | d.InitODE(); |
74 | 74 | ||
75 | m_scene = new OdeScene(sceneIdentifier); | 75 | m_scene = new OdeScene(GetName(), sceneIdentifier); |
76 | } | 76 | } |
77 | 77 | ||
78 | return m_scene; | 78 | return m_scene; |
diff --git a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs index d53bd90..6d7f079 100644 --- a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs +++ b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs | |||
@@ -526,11 +526,12 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
526 | /// These settings need to be tweaked 'exactly' right or weird stuff happens. | 526 | /// These settings need to be tweaked 'exactly' right or weird stuff happens. |
527 | /// </summary> | 527 | /// </summary> |
528 | /// <param value="name">Name of the scene. Useful in debug messages.</param> | 528 | /// <param value="name">Name of the scene. Useful in debug messages.</param> |
529 | public OdeScene(string name) | 529 | public OdeScene(string engineType, string name) |
530 | { | 530 | { |
531 | m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType.ToString() + "." + name); | 531 | m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType.ToString() + "." + name); |
532 | 532 | ||
533 | Name = name; | 533 | Name = name; |
534 | EngineType = engineType; | ||
534 | 535 | ||
535 | nearCallback = near; | 536 | nearCallback = near; |
536 | triCallback = TriCallback; | 537 | triCallback = TriCallback; |
@@ -4095,8 +4096,8 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
4095 | lock (_prims) | 4096 | lock (_prims) |
4096 | { | 4097 | { |
4097 | List<OdePrim> orderedPrims = new List<OdePrim>(_prims); | 4098 | List<OdePrim> orderedPrims = new List<OdePrim>(_prims); |
4098 | orderedPrims.OrderByDescending(p => p.CollisionScore).Take(25); | 4099 | orderedPrims.OrderByDescending(p => p.CollisionScore); |
4099 | topColliders = orderedPrims.ToDictionary(p => p.LocalID, p => p.CollisionScore); | 4100 | topColliders = orderedPrims.Take(25).ToDictionary(p => p.LocalID, p => p.CollisionScore); |
4100 | 4101 | ||
4101 | foreach (OdePrim p in _prims) | 4102 | foreach (OdePrim p in _prims) |
4102 | p.CollisionScore = 0; | 4103 | p.CollisionScore = 0; |
diff --git a/OpenSim/Region/Physics/OdePlugin/Tests/ODETestClass.cs b/OpenSim/Region/Physics/OdePlugin/Tests/ODETestClass.cs index cbc6b95..16404c6 100644 --- a/OpenSim/Region/Physics/OdePlugin/Tests/ODETestClass.cs +++ b/OpenSim/Region/Physics/OdePlugin/Tests/ODETestClass.cs | |||
@@ -32,13 +32,14 @@ using OpenMetaverse; | |||
32 | using OpenSim.Framework; | 32 | using OpenSim.Framework; |
33 | using OpenSim.Region.Physics.Manager; | 33 | using OpenSim.Region.Physics.Manager; |
34 | using OpenSim.Region.Physics.OdePlugin; | 34 | using OpenSim.Region.Physics.OdePlugin; |
35 | using OpenSim.Tests.Common; | ||
35 | using log4net; | 36 | using log4net; |
36 | using System.Reflection; | 37 | using System.Reflection; |
37 | 38 | ||
38 | namespace OpenSim.Region.Physics.OdePlugin.Tests | 39 | namespace OpenSim.Region.Physics.OdePlugin.Tests |
39 | { | 40 | { |
40 | [TestFixture] | 41 | [TestFixture] |
41 | public class ODETestClass | 42 | public class ODETestClass : OpenSimTestCase |
42 | { | 43 | { |
43 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 44 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
44 | 45 | ||
diff --git a/OpenSim/Region/Physics/POSPlugin/AssemblyInfo.cs b/OpenSim/Region/Physics/POSPlugin/AssemblyInfo.cs index d07df02..4289863 100644 --- a/OpenSim/Region/Physics/POSPlugin/AssemblyInfo.cs +++ b/OpenSim/Region/Physics/POSPlugin/AssemblyInfo.cs | |||
@@ -55,4 +55,4 @@ using System.Runtime.InteropServices; | |||
55 | // You can specify all values by your own or you can build default build and revision | 55 | // You can specify all values by your own or you can build default build and revision |
56 | // numbers with the '*' character (the default): | 56 | // numbers with the '*' character (the default): |
57 | 57 | ||
58 | [assembly : AssemblyVersion("0.7.5.*")] | 58 | [assembly : AssemblyVersion("0.7.6.*")] |
diff --git a/OpenSim/Region/Physics/POSPlugin/POSPlugin.cs b/OpenSim/Region/Physics/POSPlugin/POSPlugin.cs index e6b42e6..ed086dd 100644 --- a/OpenSim/Region/Physics/POSPlugin/POSPlugin.cs +++ b/OpenSim/Region/Physics/POSPlugin/POSPlugin.cs | |||
@@ -49,7 +49,7 @@ namespace OpenSim.Region.Physics.POSPlugin | |||
49 | 49 | ||
50 | public PhysicsScene GetScene(string sceneIdentifier) | 50 | public PhysicsScene GetScene(string sceneIdentifier) |
51 | { | 51 | { |
52 | return new POSScene(sceneIdentifier); | 52 | return new POSScene(GetName(), sceneIdentifier); |
53 | } | 53 | } |
54 | 54 | ||
55 | public string GetName() | 55 | public string GetName() |
diff --git a/OpenSim/Region/Physics/POSPlugin/POSScene.cs b/OpenSim/Region/Physics/POSPlugin/POSScene.cs index 2f24a50..d30d482 100644 --- a/OpenSim/Region/Physics/POSPlugin/POSScene.cs +++ b/OpenSim/Region/Physics/POSPlugin/POSScene.cs | |||
@@ -43,8 +43,10 @@ namespace OpenSim.Region.Physics.POSPlugin | |||
43 | 43 | ||
44 | //protected internal string sceneIdentifier; | 44 | //protected internal string sceneIdentifier; |
45 | 45 | ||
46 | public POSScene(String _sceneIdentifier) | 46 | public POSScene(string engineType, String _sceneIdentifier) |
47 | { | 47 | { |
48 | EngineType = engineType; | ||
49 | Name = EngineType + "/" + _sceneIdentifier; | ||
48 | //sceneIdentifier = _sceneIdentifier; | 50 | //sceneIdentifier = _sceneIdentifier; |
49 | } | 51 | } |
50 | 52 | ||
diff --git a/OpenSim/Region/Physics/UbitMeshing/Mesh.cs b/OpenSim/Region/Physics/UbitMeshing/Mesh.cs index b67422f..fa06926 100644 --- a/OpenSim/Region/Physics/UbitMeshing/Mesh.cs +++ b/OpenSim/Region/Physics/UbitMeshing/Mesh.cs | |||
@@ -301,7 +301,7 @@ namespace OpenSim.Region.Physics.Meshing | |||
301 | return result; | 301 | return result; |
302 | } | 302 | } |
303 | 303 | ||
304 | private float[] getVertexListAsFloat() | 304 | public float[] getVertexListAsFloat() |
305 | { | 305 | { |
306 | if (m_bdata.m_vertices == null) | 306 | if (m_bdata.m_vertices == null) |
307 | throw new NotSupportedException(); | 307 | throw new NotSupportedException(); |
diff --git a/OpenSim/Region/Physics/UbitMeshing/Meshmerizer.cs b/OpenSim/Region/Physics/UbitMeshing/Meshmerizer.cs index 6e1a105..00cbfbd 100644 --- a/OpenSim/Region/Physics/UbitMeshing/Meshmerizer.cs +++ b/OpenSim/Region/Physics/UbitMeshing/Meshmerizer.cs | |||
@@ -1031,12 +1031,12 @@ namespace OpenSim.Region.Physics.Meshing | |||
1031 | 1031 | ||
1032 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) | 1032 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) |
1033 | { | 1033 | { |
1034 | return CreateMesh(primName, primShape, size, lod, false,false,false); | 1034 | return CreateMesh(primName, primShape, size, lod, false,false,false,false); |
1035 | } | 1035 | } |
1036 | 1036 | ||
1037 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical) | 1037 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical) |
1038 | { | 1038 | { |
1039 | return CreateMesh(primName, primShape, size, lod, false,false,false); | 1039 | return CreateMesh(primName, primShape, size, lod, false,false,false,false); |
1040 | } | 1040 | } |
1041 | 1041 | ||
1042 | public IMesh GetMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex) | 1042 | public IMesh GetMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex) |
@@ -1080,7 +1080,7 @@ namespace OpenSim.Region.Physics.Meshing | |||
1080 | 1080 | ||
1081 | private static Vector3 m_MeshUnitSize = new Vector3(1.0f, 1.0f, 1.0f); | 1081 | private static Vector3 m_MeshUnitSize = new Vector3(1.0f, 1.0f, 1.0f); |
1082 | 1082 | ||
1083 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex, bool forOde) | 1083 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache, bool convex, bool forOde) |
1084 | { | 1084 | { |
1085 | #if SPAM | 1085 | #if SPAM |
1086 | m_log.DebugFormat("[MESH]: Creating mesh for {0}", primName); | 1086 | m_log.DebugFormat("[MESH]: Creating mesh for {0}", primName); |
diff --git a/OpenSim/Region/Physics/UbitOdePlugin/ODECharacter.cs b/OpenSim/Region/Physics/UbitOdePlugin/ODECharacter.cs index f7e4c1c..bea34d4 100644 --- a/OpenSim/Region/Physics/UbitOdePlugin/ODECharacter.cs +++ b/OpenSim/Region/Physics/UbitOdePlugin/ODECharacter.cs | |||
@@ -1014,8 +1014,8 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
1014 | offset.Y += contact.pos.Y; | 1014 | offset.Y += contact.pos.Y; |
1015 | offset.Z += contact.pos.Z; | 1015 | offset.Z += contact.pos.Z; |
1016 | 1016 | ||
1017 | _position = offset; | 1017 | //_position = offset; |
1018 | return false; | 1018 | //return false; |
1019 | } | 1019 | } |
1020 | 1020 | ||
1021 | offset.X = contact.pos.X - _position.X; | 1021 | offset.X = contact.pos.X - _position.X; |
diff --git a/OpenSim/Region/Physics/UbitOdePlugin/ODEMeshWorker.cs b/OpenSim/Region/Physics/UbitOdePlugin/ODEMeshWorker.cs index 5030cec..0df71eb 100644 --- a/OpenSim/Region/Physics/UbitOdePlugin/ODEMeshWorker.cs +++ b/OpenSim/Region/Physics/UbitOdePlugin/ODEMeshWorker.cs | |||
@@ -448,7 +448,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
448 | else | 448 | else |
449 | { | 449 | { |
450 | repData.meshState = MeshState.needMesh; | 450 | repData.meshState = MeshState.needMesh; |
451 | mesh = m_mesher.CreateMesh(actor.Name, pbs, size, clod, true, convex, true); | 451 | mesh = m_mesher.CreateMesh(actor.Name, pbs, size, clod, true, false, convex, true); |
452 | if (mesh == null) | 452 | if (mesh == null) |
453 | { | 453 | { |
454 | repData.meshState = MeshState.MeshFailed; | 454 | repData.meshState = MeshState.MeshFailed; |
@@ -513,7 +513,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
513 | clod = (int)LevelOfDetail.Low; | 513 | clod = (int)LevelOfDetail.Low; |
514 | } | 514 | } |
515 | 515 | ||
516 | mesh = m_mesher.CreateMesh(actor.Name, pbs, size, clod, true, convex, true); | 516 | mesh = m_mesher.CreateMesh(actor.Name, pbs, size, clod, true, false, convex, true); |
517 | 517 | ||
518 | if (mesh == null) | 518 | if (mesh == null) |
519 | { | 519 | { |
@@ -929,4 +929,4 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
929 | repData.actor.Name); | 929 | repData.actor.Name); |
930 | } | 930 | } |
931 | } | 931 | } |
932 | } \ No newline at end of file | 932 | } |
diff --git a/OpenSim/Region/Physics/UbitOdePlugin/ODERayCastRequestManager.cs b/OpenSim/Region/Physics/UbitOdePlugin/ODERayCastRequestManager.cs index 4f598ea..2923ccf 100644 --- a/OpenSim/Region/Physics/UbitOdePlugin/ODERayCastRequestManager.cs +++ b/OpenSim/Region/Physics/UbitOdePlugin/ODERayCastRequestManager.cs | |||
@@ -300,9 +300,9 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
300 | ((ProbeSphereCallback)req.callbackMethod)(cresult); | 300 | ((ProbeSphereCallback)req.callbackMethod)(cresult); |
301 | } | 301 | } |
302 | 302 | ||
303 | private const RayFilterFlags FilterActiveSpace = RayFilterFlags.agent | RayFilterFlags.physical | RayFilterFlags.LSLPhanton; | 303 | private const RayFilterFlags FilterActiveSpace = RayFilterFlags.agent | RayFilterFlags.physical | RayFilterFlags.LSLPhantom; |
304 | // private const RayFilterFlags FilterStaticSpace = RayFilterFlags.water | RayFilterFlags.land | RayFilterFlags.nonphysical | RayFilterFlags.LSLPhanton; | 304 | // private const RayFilterFlags FilterStaticSpace = RayFilterFlags.water | RayFilterFlags.land | RayFilterFlags.nonphysical | RayFilterFlags.LSLPhanton; |
305 | private const RayFilterFlags FilterStaticSpace = RayFilterFlags.water | RayFilterFlags.nonphysical | RayFilterFlags.LSLPhanton; | 305 | private const RayFilterFlags FilterStaticSpace = RayFilterFlags.water | RayFilterFlags.nonphysical | RayFilterFlags.LSLPhantom; |
306 | 306 | ||
307 | private void doSpaceRay(ODERayRequest req) | 307 | private void doSpaceRay(ODERayRequest req) |
308 | { | 308 | { |
@@ -680,4 +680,4 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
680 | public RayFilterFlags filter; | 680 | public RayFilterFlags filter; |
681 | public Quaternion orientation; | 681 | public Quaternion orientation; |
682 | } | 682 | } |
683 | } \ No newline at end of file | 683 | } |
diff --git a/OpenSim/Region/RegionCombinerModule/Properties/AssemblyInfo.cs b/OpenSim/Region/RegionCombinerModule/Properties/AssemblyInfo.cs index 085eb59..86a3101 100644 --- a/OpenSim/Region/RegionCombinerModule/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/RegionCombinerModule/Properties/AssemblyInfo.cs | |||
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices; | |||
29 | // Build Number | 29 | // Build Number |
30 | // Revision | 30 | // Revision |
31 | // | 31 | // |
32 | [assembly: AssemblyVersion("0.7.5.*")] | 32 | [assembly: AssemblyVersion("0.7.6.*")] |
33 | [assembly: AssemblyFileVersion("1.0.0.0")] | 33 | |
diff --git a/OpenSim/Region/RegionCombinerModule/RegionCombinerLargeLandChannel.cs b/OpenSim/Region/RegionCombinerModule/RegionCombinerLargeLandChannel.cs index a133e51..b4abc1d 100644 --- a/OpenSim/Region/RegionCombinerModule/RegionCombinerLargeLandChannel.cs +++ b/OpenSim/Region/RegionCombinerModule/RegionCombinerLargeLandChannel.cs | |||
@@ -68,6 +68,11 @@ public class RegionCombinerLargeLandChannel : ILandChannel | |||
68 | RootRegionLandChannel.Clear(setupDefaultParcel); | 68 | RootRegionLandChannel.Clear(setupDefaultParcel); |
69 | } | 69 | } |
70 | 70 | ||
71 | public ILandObject GetLandObject(Vector3 position) | ||
72 | { | ||
73 | return GetLandObject(position.X, position.Y); | ||
74 | } | ||
75 | |||
71 | public ILandObject GetLandObject(int x, int y) | 76 | public ILandObject GetLandObject(int x, int y) |
72 | { | 77 | { |
73 | //m_log.DebugFormat("[BIGLANDTESTINT]: <{0},{1}>", x, y); | 78 | //m_log.DebugFormat("[BIGLANDTESTINT]: <{0},{1}>", x, y); |
diff --git a/OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs b/OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs index 905540d..7127c73 100644 --- a/OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs +++ b/OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs | |||
@@ -415,18 +415,17 @@ namespace OpenSim.Region.RegionCombinerModule | |||
415 | */ | 415 | */ |
416 | #endregion | 416 | #endregion |
417 | 417 | ||
418 | // If we're one region over +x y | 418 | // If we're one region over +x y (i.e. root region is to the west) |
419 | //xxx | 419 | //xxx |
420 | //xxy | 420 | //xxy |
421 | //xxx | 421 | //xxx |
422 | |||
423 | if (rootConn.PosX + rootConn.XEnd >= newConn.PosX && rootConn.PosY >= newConn.PosY) | 422 | if (rootConn.PosX + rootConn.XEnd >= newConn.PosX && rootConn.PosY >= newConn.PosY) |
424 | { | 423 | { |
425 | connectedYN = DoWorkForOneRegionOverPlusXY(rootConn, newConn, scene); | 424 | connectedYN = DoWorkForOneRegionOverPlusXY(rootConn, newConn, scene); |
426 | break; | 425 | break; |
427 | } | 426 | } |
428 | 427 | ||
429 | // If we're one region over x +y | 428 | // If we're one region over x +y (i.e. root region is to the south) |
430 | //xyx | 429 | //xyx |
431 | //xxx | 430 | //xxx |
432 | //xxx | 431 | //xxx |
@@ -436,7 +435,7 @@ namespace OpenSim.Region.RegionCombinerModule | |||
436 | break; | 435 | break; |
437 | } | 436 | } |
438 | 437 | ||
439 | // If we're one region over +x +y | 438 | // If we're one region over +x +y (i.e. root region is to the south-west) |
440 | //xxy | 439 | //xxy |
441 | //xxx | 440 | //xxx |
442 | //xxx | 441 | //xxx |
@@ -646,7 +645,6 @@ namespace OpenSim.Region.RegionCombinerModule | |||
646 | { | 645 | { |
647 | if (rootConn.RegionScene.EastBorders.Count == 1)// && conn.RegionScene.EastBorders.Count == 2) | 646 | if (rootConn.RegionScene.EastBorders.Count == 1)// && conn.RegionScene.EastBorders.Count == 2) |
648 | { | 647 | { |
649 | |||
650 | rootConn.RegionScene.EastBorders[0].BorderLine.Z += (int)Constants.RegionSize; | 648 | rootConn.RegionScene.EastBorders[0].BorderLine.Z += (int)Constants.RegionSize; |
651 | 649 | ||
652 | lock (rootConn.RegionScene.NorthBorders) | 650 | lock (rootConn.RegionScene.NorthBorders) |
diff --git a/OpenSim/Region/ScriptEngine/Interfaces/IScriptApi.cs b/OpenSim/Region/ScriptEngine/Interfaces/IScriptApi.cs index 2027ca6..30e99b0 100644 --- a/OpenSim/Region/ScriptEngine/Interfaces/IScriptApi.cs +++ b/OpenSim/Region/ScriptEngine/Interfaces/IScriptApi.cs | |||
@@ -26,9 +26,11 @@ | |||
26 | */ | 26 | */ |
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Threading; | ||
29 | using OpenMetaverse; | 30 | using OpenMetaverse; |
30 | using OpenSim.Framework; | 31 | using OpenSim.Framework; |
31 | using OpenSim.Region.Framework.Scenes; | 32 | using OpenSim.Region.Framework.Scenes; |
33 | using OpenSim.Region.ScriptEngine.Shared; | ||
32 | 34 | ||
33 | namespace OpenSim.Region.ScriptEngine.Interfaces | 35 | namespace OpenSim.Region.ScriptEngine.Interfaces |
34 | { | 36 | { |
@@ -38,11 +40,12 @@ namespace OpenSim.Region.ScriptEngine.Interfaces | |||
38 | /// Initialize the API | 40 | /// Initialize the API |
39 | /// </summary> | 41 | /// </summary> |
40 | /// <remarks> | 42 | /// <remarks> |
41 | /// Each API has an identifier, which is used to load the | 43 | /// Each API has an identifier, which is used to load the proper runtime assembly at load time. |
42 | /// proper runtime assembly at load time. | 44 | /// <param name='scriptEngine'>/param> |
43 | /// <param name='engine'>/param> | 45 | /// <param name='host'>/param> |
44 | /// <param name='part'></param> | 46 | /// <param name='item'>/param> |
45 | /// <param name='item'></param> | 47 | /// <param name='coopSleepHandle'>/param> |
46 | void Initialize(IScriptEngine engine, SceneObjectPart part, TaskInventoryItem item); | 48 | void Initialize( |
49 | IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item, WaitHandle coopSleepHandle); | ||
47 | } | 50 | } |
48 | } \ No newline at end of file | 51 | } \ No newline at end of file |
diff --git a/OpenSim/Region/ScriptEngine/Interfaces/IScriptEngine.cs b/OpenSim/Region/ScriptEngine/Interfaces/IScriptEngine.cs index 17c2708..b8fdd01 100644 --- a/OpenSim/Region/ScriptEngine/Interfaces/IScriptEngine.cs +++ b/OpenSim/Region/ScriptEngine/Interfaces/IScriptEngine.cs | |||
@@ -25,16 +25,17 @@ | |||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | */ | 26 | */ |
27 | 27 | ||
28 | using log4net; | ||
29 | using System; | 28 | using System; |
30 | using OpenSim.Region.ScriptEngine.Shared; | 29 | using System.Reflection; |
30 | using OpenSim.Framework; | ||
31 | using OpenSim.Region.Framework.Scenes; | 31 | using OpenSim.Region.Framework.Scenes; |
32 | using OpenSim.Region.Framework.Interfaces; | 32 | using OpenSim.Region.Framework.Interfaces; |
33 | using OpenMetaverse; | ||
34 | using Nini.Config; | ||
35 | using OpenSim.Region.ScriptEngine.Interfaces; | 33 | using OpenSim.Region.ScriptEngine.Interfaces; |
34 | using OpenSim.Region.ScriptEngine.Shared; | ||
36 | using Amib.Threading; | 35 | using Amib.Threading; |
37 | using OpenSim.Framework; | 36 | using log4net; |
37 | using Nini.Config; | ||
38 | using OpenMetaverse; | ||
38 | 39 | ||
39 | namespace OpenSim.Region.ScriptEngine.Interfaces | 40 | namespace OpenSim.Region.ScriptEngine.Interfaces |
40 | { | 41 | { |
@@ -76,6 +77,38 @@ namespace OpenSim.Region.ScriptEngine.Interfaces | |||
76 | IConfigSource ConfigSource { get; } | 77 | IConfigSource ConfigSource { get; } |
77 | string ScriptEngineName { get; } | 78 | string ScriptEngineName { get; } |
78 | string ScriptEnginePath { get; } | 79 | string ScriptEnginePath { get; } |
80 | |||
81 | /// <summary> | ||
82 | /// Return the name of the class that will be used for all running scripts. | ||
83 | /// </summary> | ||
84 | /// <remarks> | ||
85 | /// Each class goes in its own assembly so we don't need to otherwise distinguish the class name. | ||
86 | /// </remarks> | ||
87 | string ScriptClassName { get; } | ||
88 | |||
89 | /// <summary> | ||
90 | /// Return the name of the base class that will be used for all running scripts. | ||
91 | /// </summary> | ||
92 | string ScriptBaseClassName { get; } | ||
93 | |||
94 | /// <summary> | ||
95 | /// Assemblies that need to be referenced when compiling scripts. | ||
96 | /// </summary> | ||
97 | /// <remarks> | ||
98 | /// These are currently additional to those always referenced by the compiler, BUT THIS MAY CHANGE IN THE | ||
99 | /// FUTURE. | ||
100 | /// This can be null if there are no additional assemblies. | ||
101 | /// </remarks> | ||
102 | string[] ScriptReferencedAssemblies { get; } | ||
103 | |||
104 | /// <summary> | ||
105 | /// Parameters for the generated script's constructor. | ||
106 | /// </summary> | ||
107 | /// <remarks> | ||
108 | /// Can be null if there are no parameters | ||
109 | /// </remarks> | ||
110 | ParameterInfo[] ScriptBaseClassParameters { get; } | ||
111 | |||
79 | IScriptApi GetApi(UUID itemID, string name); | 112 | IScriptApi GetApi(UUID itemID, string name); |
80 | } | 113 | } |
81 | } | 114 | } |
diff --git a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs index b04f6b6..35ae44c 100644 --- a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs | |||
@@ -28,9 +28,11 @@ | |||
28 | using System; | 28 | using System; |
29 | using System.Collections; | 29 | using System.Collections; |
30 | using System.Collections.Generic; | 30 | using System.Collections.Generic; |
31 | using System.Threading; | ||
31 | using OpenMetaverse; | 32 | using OpenMetaverse; |
32 | using log4net; | 33 | using log4net; |
33 | using OpenSim.Framework; | 34 | using OpenSim.Framework; |
35 | using OpenSim.Region.Framework.Scenes; | ||
34 | using OpenSim.Region.ScriptEngine.Shared; | 36 | using OpenSim.Region.ScriptEngine.Shared; |
35 | using OpenSim.Region.ScriptEngine.Interfaces; | 37 | using OpenSim.Region.ScriptEngine.Interfaces; |
36 | 38 | ||
@@ -50,7 +52,12 @@ namespace OpenSim.Region.ScriptEngine.Interfaces | |||
50 | { | 52 | { |
51 | bool Cancel(); | 53 | bool Cancel(); |
52 | void Abort(); | 54 | void Abort(); |
53 | bool Wait(TimeSpan t); | 55 | |
56 | /// <summary> | ||
57 | /// Wait for the work item to complete. | ||
58 | /// </summary> | ||
59 | /// <param name='t'>The number of milliseconds to wait. Must be >= -1 (Timeout.Infinite).</param> | ||
60 | bool Wait(int t); | ||
54 | } | 61 | } |
55 | 62 | ||
56 | /// <summary> | 63 | /// <summary> |
@@ -59,6 +66,18 @@ namespace OpenSim.Region.ScriptEngine.Interfaces | |||
59 | public interface IScriptInstance | 66 | public interface IScriptInstance |
60 | { | 67 | { |
61 | /// <summary> | 68 | /// <summary> |
69 | /// Debug level for this script instance. | ||
70 | /// </summary> | ||
71 | /// <remarks> | ||
72 | /// Level == 0, no extra data is logged. | ||
73 | /// Level >= 1, state changes are logged. | ||
74 | /// Level >= 2, event firing is logged. | ||
75 | /// <value> | ||
76 | /// The debug level. | ||
77 | /// </value> | ||
78 | int DebugLevel { get; set; } | ||
79 | |||
80 | /// <summary> | ||
62 | /// Is the script currently running? | 81 | /// Is the script currently running? |
63 | /// </summary> | 82 | /// </summary> |
64 | bool Running { get; set; } | 83 | bool Running { get; set; } |
@@ -93,6 +112,11 @@ namespace OpenSim.Region.ScriptEngine.Interfaces | |||
93 | /// </summary> | 112 | /// </summary> |
94 | long MeasurementPeriodExecutionTime { get; } | 113 | long MeasurementPeriodExecutionTime { get; } |
95 | 114 | ||
115 | /// <summary> | ||
116 | /// Scene part in which this script instance is contained. | ||
117 | /// </summary> | ||
118 | SceneObjectPart Part { get; } | ||
119 | |||
96 | IScriptEngine Engine { get; } | 120 | IScriptEngine Engine { get; } |
97 | UUID AppDomain { get; set; } | 121 | UUID AppDomain { get; set; } |
98 | string PrimName { get; } | 122 | string PrimName { get; } |
@@ -112,8 +136,24 @@ namespace OpenSim.Region.ScriptEngine.Interfaces | |||
112 | 136 | ||
113 | uint LocalID { get; } | 137 | uint LocalID { get; } |
114 | UUID AssetID { get; } | 138 | UUID AssetID { get; } |
139 | |||
140 | /// <summary> | ||
141 | /// Inventory item containing the script used. | ||
142 | /// </summary> | ||
143 | TaskInventoryItem ScriptTask { get; } | ||
144 | |||
115 | Queue EventQueue { get; } | 145 | Queue EventQueue { get; } |
116 | 146 | ||
147 | /// <summary> | ||
148 | /// Number of events queued for processing. | ||
149 | /// </summary> | ||
150 | long EventsQueued { get; } | ||
151 | |||
152 | /// <summary> | ||
153 | /// Number of events processed by this script instance. | ||
154 | /// </summary> | ||
155 | long EventsProcessed { get; } | ||
156 | |||
117 | void ClearQueue(); | 157 | void ClearQueue(); |
118 | int StartParam { get; set; } | 158 | int StartParam { get; set; } |
119 | 159 | ||
@@ -125,7 +165,13 @@ namespace OpenSim.Region.ScriptEngine.Interfaces | |||
125 | /// <summary> | 165 | /// <summary> |
126 | /// Stop the script instance. | 166 | /// Stop the script instance. |
127 | /// </summary> | 167 | /// </summary> |
168 | /// <remarks> | ||
169 | /// This must not be called by a thread that is in the process of handling an event for this script. Otherwise | ||
170 | /// there is a danger that it will self-abort and not complete the reset. | ||
171 | /// </remarks> | ||
128 | /// <param name="timeout"></param> | 172 | /// <param name="timeout"></param> |
173 | /// How many milliseconds we will wait for an existing script event to finish before | ||
174 | /// forcibly aborting that event. | ||
129 | /// <returns>true if the script was successfully stopped, false otherwise</returns> | 175 | /// <returns>true if the script was successfully stopped, false otherwise</returns> |
130 | bool Stop(int timeout); | 176 | bool Stop(int timeout); |
131 | 177 | ||
@@ -147,8 +193,31 @@ namespace OpenSim.Region.ScriptEngine.Interfaces | |||
147 | object EventProcessor(); | 193 | object EventProcessor(); |
148 | 194 | ||
149 | int EventTime(); | 195 | int EventTime(); |
150 | void ResetScript(); | 196 | |
197 | /// <summary> | ||
198 | /// Reset the script. | ||
199 | /// </summary> | ||
200 | /// <remarks> | ||
201 | /// This must not be called by a thread that is in the process of handling an event for this script. Otherwise | ||
202 | /// there is a danger that it will self-abort and not complete the reset. Such a thread must call | ||
203 | /// ApiResetScript() instead. | ||
204 | /// </remarks> | ||
205 | /// <param name='timeout'> | ||
206 | /// How many milliseconds we will wait for an existing script event to finish before | ||
207 | /// forcibly aborting that event prior to script reset. | ||
208 | /// </param> | ||
209 | void ResetScript(int timeout); | ||
210 | |||
211 | /// <summary> | ||
212 | /// Reset the script. | ||
213 | /// </summary> | ||
214 | /// <remarks> | ||
215 | /// This must not be called by any thread other than the one executing the scripts current event. This is | ||
216 | /// because there is no wait or abort logic if another thread is in the middle of processing a script event. | ||
217 | /// Such an external thread should use ResetScript() instead. | ||
218 | /// </remarks> | ||
151 | void ApiResetScript(); | 219 | void ApiResetScript(); |
220 | |||
152 | Dictionary<string, object> GetVars(); | 221 | Dictionary<string, object> GetVars(); |
153 | void SetVars(Dictionary<string, object> vars); | 222 | void SetVars(Dictionary<string, object> vars); |
154 | DetectParams GetDetectParams(int idx); | 223 | DetectParams GetDetectParams(int idx); |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/CM_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/CM_Api.cs index b5fa6de..fce8ff8 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/CM_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/CM_Api.cs | |||
@@ -26,6 +26,7 @@ | |||
26 | */ | 26 | */ |
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Threading; | ||
29 | using System.Reflection; | 30 | using System.Reflection; |
30 | using System.Collections; | 31 | using System.Collections; |
31 | using System.Collections.Generic; | 32 | using System.Collections.Generic; |
@@ -62,7 +63,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
62 | internal TaskInventoryItem m_item; | 63 | internal TaskInventoryItem m_item; |
63 | internal bool m_CMFunctionsEnabled = false; | 64 | internal bool m_CMFunctionsEnabled = false; |
64 | 65 | ||
65 | public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, TaskInventoryItem item) | 66 | public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, TaskInventoryItem item, WaitHandle coopSleepHandle) |
66 | { | 67 | { |
67 | m_ScriptEngine = ScriptEngine; | 68 | m_ScriptEngine = ScriptEngine; |
68 | m_host = host; | 69 | m_host = host; |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 53c6e5c..bc35272 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | |||
@@ -48,6 +48,7 @@ using OpenSim.Region.Framework.Interfaces; | |||
48 | using OpenSim.Region.Framework.Scenes; | 48 | using OpenSim.Region.Framework.Scenes; |
49 | using OpenSim.Region.Framework.Scenes.Serialization; | 49 | using OpenSim.Region.Framework.Scenes.Serialization; |
50 | using OpenSim.Region.Framework.Scenes.Animation; | 50 | using OpenSim.Region.Framework.Scenes.Animation; |
51 | using OpenSim.Region.Framework.Scenes.Scripting; | ||
51 | using OpenSim.Region.Physics.Manager; | 52 | using OpenSim.Region.Physics.Manager; |
52 | using OpenSim.Region.ScriptEngine.Shared; | 53 | using OpenSim.Region.ScriptEngine.Shared; |
53 | using OpenSim.Region.ScriptEngine.Shared.Api.Plugins; | 54 | using OpenSim.Region.ScriptEngine.Shared.Api.Plugins; |
@@ -70,6 +71,8 @@ using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString; | |||
70 | using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3; | 71 | using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3; |
71 | using System.Reflection; | 72 | using System.Reflection; |
72 | using Timer = System.Timers.Timer; | 73 | using Timer = System.Timers.Timer; |
74 | using System.Linq; | ||
75 | using PermissionMask = OpenSim.Framework.PermissionMask; | ||
73 | 76 | ||
74 | namespace OpenSim.Region.ScriptEngine.Shared.Api | 77 | namespace OpenSim.Region.ScriptEngine.Shared.Api |
75 | { | 78 | { |
@@ -87,10 +90,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
87 | public class LSL_Api : MarshalByRefObject, ILSL_Api, IScriptApi | 90 | public class LSL_Api : MarshalByRefObject, ILSL_Api, IScriptApi |
88 | { | 91 | { |
89 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 92 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
93 | |||
90 | protected IScriptEngine m_ScriptEngine; | 94 | protected IScriptEngine m_ScriptEngine; |
91 | protected SceneObjectPart m_host; | 95 | protected SceneObjectPart m_host; |
92 | 96 | ||
93 | /// <summary> | 97 | /// <summary> |
98 | /// Used for script sleeps when we are using co-operative script termination. | ||
99 | /// </summary> | ||
100 | /// <remarks>null if co-operative script termination is not active</remarks> | ||
101 | WaitHandle m_coopSleepHandle; | ||
102 | |||
103 | /// <summary> | ||
94 | /// The item that hosts this script | 104 | /// The item that hosts this script |
95 | /// </summary> | 105 | /// </summary> |
96 | protected TaskInventoryItem m_item; | 106 | protected TaskInventoryItem m_item; |
@@ -100,6 +110,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
100 | protected float m_ScriptDelayFactor = 1.0f; | 110 | protected float m_ScriptDelayFactor = 1.0f; |
101 | protected float m_ScriptDistanceFactor = 1.0f; | 111 | protected float m_ScriptDistanceFactor = 1.0f; |
102 | protected float m_MinTimerInterval = 0.5f; | 112 | protected float m_MinTimerInterval = 0.5f; |
113 | protected float m_recoilScaleFactor = 0.0f; | ||
103 | 114 | ||
104 | protected DateTime m_timer = DateTime.Now; | 115 | protected DateTime m_timer = DateTime.Now; |
105 | protected bool m_waitingForScriptAnswer = false; | 116 | protected bool m_waitingForScriptAnswer = false; |
@@ -140,34 +151,48 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
140 | {"TURNLEFT", "Turning Left"}, | 151 | {"TURNLEFT", "Turning Left"}, |
141 | {"TURNRIGHT", "Turning Right"} | 152 | {"TURNRIGHT", "Turning Right"} |
142 | }; | 153 | }; |
154 | //An array of HTTP/1.1 headers that are not allowed to be used | ||
155 | //as custom headers by llHTTPRequest. | ||
156 | private string[] HttpStandardHeaders = | ||
157 | { | ||
158 | "Accept", "Accept-Charset", "Accept-Encoding", "Accept-Language", | ||
159 | "Accept-Ranges", "Age", "Allow", "Authorization", "Cache-Control", | ||
160 | "Connection", "Content-Encoding", "Content-Language", | ||
161 | "Content-Length", "Content-Location", "Content-MD5", | ||
162 | "Content-Range", "Content-Type", "Date", "ETag", "Expect", | ||
163 | "Expires", "From", "Host", "If-Match", "If-Modified-Since", | ||
164 | "If-None-Match", "If-Range", "If-Unmodified-Since", "Last-Modified", | ||
165 | "Location", "Max-Forwards", "Pragma", "Proxy-Authenticate", | ||
166 | "Proxy-Authorization", "Range", "Referer", "Retry-After", "Server", | ||
167 | "TE", "Trailer", "Transfer-Encoding", "Upgrade", "User-Agent", | ||
168 | "Vary", "Via", "Warning", "WWW-Authenticate" | ||
169 | }; | ||
143 | 170 | ||
144 | public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, TaskInventoryItem item) | 171 | public void Initialize( |
172 | IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item, WaitHandle coopSleepHandle) | ||
145 | { | 173 | { |
146 | /* | ||
147 | m_ShoutSayTimer = new Timer(1000); | ||
148 | m_ShoutSayTimer.Elapsed += SayShoutTimerElapsed; | ||
149 | m_ShoutSayTimer.AutoReset = true; | ||
150 | m_ShoutSayTimer.Start(); | ||
151 | */ | ||
152 | m_lastSayShoutCheck = DateTime.UtcNow; | 174 | m_lastSayShoutCheck = DateTime.UtcNow; |
153 | 175 | ||
154 | m_ScriptEngine = ScriptEngine; | 176 | m_ScriptEngine = scriptEngine; |
155 | m_host = host; | 177 | m_host = host; |
156 | m_item = item; | 178 | m_item = item; |
157 | m_debuggerSafe = m_ScriptEngine.Config.GetBoolean("DebuggerSafe", false); | 179 | m_debuggerSafe = m_ScriptEngine.Config.GetBoolean("DebuggerSafe", false); |
180 | m_coopSleepHandle = coopSleepHandle; | ||
158 | 181 | ||
159 | LoadLimits(); // read script limits from config. | 182 | LoadConfig(); |
160 | 183 | ||
161 | m_TransferModule = | 184 | m_TransferModule = |
162 | m_ScriptEngine.World.RequestModuleInterface<IMessageTransferModule>(); | 185 | m_ScriptEngine.World.RequestModuleInterface<IMessageTransferModule>(); |
163 | m_UrlModule = m_ScriptEngine.World.RequestModuleInterface<IUrlModule>(); | 186 | m_UrlModule = m_ScriptEngine.World.RequestModuleInterface<IUrlModule>(); |
164 | m_SoundModule = m_ScriptEngine.World.RequestModuleInterface<ISoundModule>(); | 187 | m_SoundModule = m_ScriptEngine.World.RequestModuleInterface<ISoundModule>(); |
165 | 188 | ||
166 | AsyncCommands = new AsyncCommandManager(ScriptEngine); | 189 | AsyncCommands = new AsyncCommandManager(m_ScriptEngine); |
167 | } | 190 | } |
168 | 191 | ||
169 | /* load configuration items that affect script, object and run-time behavior. */ | 192 | /// <summary> |
170 | private void LoadLimits() | 193 | /// Load configuration items that affect script, object and run-time behavior. */ |
194 | /// </summary> | ||
195 | private void LoadConfig() | ||
171 | { | 196 | { |
172 | m_ScriptDelayFactor = | 197 | m_ScriptDelayFactor = |
173 | m_ScriptEngine.Config.GetFloat("ScriptDelayFactor", 1.0f); | 198 | m_ScriptEngine.Config.GetFloat("ScriptDelayFactor", 1.0f); |
@@ -181,12 +206,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
181 | m_ScriptEngine.Config.GetInt("NotecardLineReadCharsMax", 255); | 206 | m_ScriptEngine.Config.GetInt("NotecardLineReadCharsMax", 255); |
182 | if (m_notecardLineReadCharsMax > 65535) | 207 | if (m_notecardLineReadCharsMax > 65535) |
183 | m_notecardLineReadCharsMax = 65535; | 208 | m_notecardLineReadCharsMax = 65535; |
209 | |||
184 | // load limits for particular subsystems. | 210 | // load limits for particular subsystems. |
185 | IConfig SMTPConfig; | 211 | IConfig SMTPConfig; |
186 | if ((SMTPConfig = m_ScriptEngine.ConfigSource.Configs["SMTP"]) != null) { | 212 | if ((SMTPConfig = m_ScriptEngine.ConfigSource.Configs["SMTP"]) != null) { |
187 | // there's an smtp config, so load in the snooze time. | 213 | // there's an smtp config, so load in the snooze time. |
188 | EMAIL_PAUSE_TIME = SMTPConfig.GetInt("email_pause_time", EMAIL_PAUSE_TIME); | 214 | EMAIL_PAUSE_TIME = SMTPConfig.GetInt("email_pause_time", EMAIL_PAUSE_TIME); |
189 | } | 215 | } |
216 | |||
217 | // Rezzing an object with a velocity can create recoil. This feature seems to have been | ||
218 | // removed from recent versions of SL. The code computes recoil (vel*mass) and scales | ||
219 | // it by this factor. May be zero to turn off recoil all together. | ||
220 | m_recoilScaleFactor = m_ScriptEngine.Config.GetFloat("RecoilScaleFactor", m_recoilScaleFactor); | ||
190 | } | 221 | } |
191 | 222 | ||
192 | public override Object InitializeLifetimeService() | 223 | public override Object InitializeLifetimeService() |
@@ -207,7 +238,26 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
207 | delay = (int)((float)delay * m_ScriptDelayFactor); | 238 | delay = (int)((float)delay * m_ScriptDelayFactor); |
208 | if (delay == 0) | 239 | if (delay == 0) |
209 | return; | 240 | return; |
210 | System.Threading.Thread.Sleep(delay); | 241 | |
242 | Sleep(delay); | ||
243 | } | ||
244 | |||
245 | protected virtual void Sleep(int delay) | ||
246 | { | ||
247 | if (m_coopSleepHandle == null) | ||
248 | System.Threading.Thread.Sleep(delay); | ||
249 | else | ||
250 | CheckForCoopTermination(delay); | ||
251 | } | ||
252 | |||
253 | /// <summary> | ||
254 | /// Check for co-operative termination. | ||
255 | /// </summary> | ||
256 | /// <param name='delay'>If called with 0, then just the check is performed with no wait.</param> | ||
257 | protected virtual void CheckForCoopTermination(int delay) | ||
258 | { | ||
259 | if (m_coopSleepHandle.WaitOne(delay)) | ||
260 | throw new ScriptCoopStopException(); | ||
211 | } | 261 | } |
212 | 262 | ||
213 | public Scene World | 263 | public Scene World |
@@ -339,6 +389,80 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
339 | } | 389 | } |
340 | } | 390 | } |
341 | 391 | ||
392 | /// <summary> | ||
393 | /// Get a given link entity from a linkset (linked objects and any sitting avatars). | ||
394 | /// </summary> | ||
395 | /// <remarks> | ||
396 | /// If there are any ScenePresence's in the linkset (i.e. because they are sat upon one of the prims), then | ||
397 | /// these are counted as extra entities that correspond to linknums beyond the number of prims in the linkset. | ||
398 | /// The ScenePresences receive linknums in the order in which they sat. | ||
399 | /// </remarks> | ||
400 | /// <returns> | ||
401 | /// The link entity. null if not found. | ||
402 | /// </returns> | ||
403 | /// <param name='linknum'> | ||
404 | /// Can be either a non-negative integer or ScriptBaseClass.LINK_THIS (-4). | ||
405 | /// If ScriptBaseClass.LINK_THIS then the entity containing the script is returned. | ||
406 | /// If the linkset has one entity and a linknum of zero is given, then the single entity is returned. If any | ||
407 | /// positive integer is given in this case then null is returned. | ||
408 | /// If the linkset has more than one entity and a linknum greater than zero but equal to or less than the number | ||
409 | /// of entities, then the entity which corresponds to that linknum is returned. | ||
410 | /// Otherwise, if a positive linknum is given which is greater than the number of entities in the linkset, then | ||
411 | /// null is returned. | ||
412 | /// </param> | ||
413 | public ISceneEntity GetLinkEntity(int linknum) | ||
414 | { | ||
415 | if (linknum < 0) | ||
416 | { | ||
417 | if (linknum == ScriptBaseClass.LINK_THIS) | ||
418 | return m_host; | ||
419 | else | ||
420 | return null; | ||
421 | } | ||
422 | |||
423 | int actualPrimCount = m_host.ParentGroup.PrimCount; | ||
424 | List<UUID> sittingAvatarIds = m_host.ParentGroup.GetSittingAvatars(); | ||
425 | int adjustedPrimCount = actualPrimCount + sittingAvatarIds.Count; | ||
426 | |||
427 | // Special case for a single prim. In this case the linknum is zero. However, this will not match a single | ||
428 | // prim that has any avatars sat upon it (in which case the root prim is link 1). | ||
429 | if (linknum == 0) | ||
430 | { | ||
431 | if (actualPrimCount == 1 && sittingAvatarIds.Count == 0) | ||
432 | return m_host; | ||
433 | |||
434 | return null; | ||
435 | } | ||
436 | // Special case to handle a single prim with sitting avatars. GetLinkPart() would only match zero but | ||
437 | // here we must match 1 (ScriptBaseClass.LINK_ROOT). | ||
438 | else if (linknum == ScriptBaseClass.LINK_ROOT && actualPrimCount == 1) | ||
439 | { | ||
440 | if (sittingAvatarIds.Count > 0) | ||
441 | return m_host.ParentGroup.RootPart; | ||
442 | else | ||
443 | return null; | ||
444 | } | ||
445 | else if (linknum <= adjustedPrimCount) | ||
446 | { | ||
447 | if (linknum <= actualPrimCount) | ||
448 | { | ||
449 | return m_host.ParentGroup.GetLinkNumPart(linknum); | ||
450 | } | ||
451 | else | ||
452 | { | ||
453 | ScenePresence sp = World.GetScenePresence(sittingAvatarIds[linknum - actualPrimCount - 1]); | ||
454 | if (sp != null) | ||
455 | return sp; | ||
456 | else | ||
457 | return null; | ||
458 | } | ||
459 | } | ||
460 | else | ||
461 | { | ||
462 | return null; | ||
463 | } | ||
464 | } | ||
465 | |||
342 | public List<SceneObjectPart> GetLinkParts(int linkType) | 466 | public List<SceneObjectPart> GetLinkParts(int linkType) |
343 | { | 467 | { |
344 | return GetLinkParts(m_host, linkType); | 468 | return GetLinkParts(m_host, linkType); |
@@ -392,79 +516,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
392 | } | 516 | } |
393 | } | 517 | } |
394 | 518 | ||
395 | protected UUID InventoryKey(string name, int type) | ||
396 | { | ||
397 | TaskInventoryItem item = m_host.Inventory.GetInventoryItem(name); | ||
398 | |||
399 | if (item != null && item.Type == type) | ||
400 | return item.AssetID; | ||
401 | else | ||
402 | return UUID.Zero; | ||
403 | } | ||
404 | |||
405 | /// <summary> | ||
406 | /// accepts a valid UUID, -or- a name of an inventory item. | ||
407 | /// Returns a valid UUID or UUID.Zero if key invalid and item not found | ||
408 | /// in prim inventory. | ||
409 | /// </summary> | ||
410 | /// <param name="k"></param> | ||
411 | /// <returns></returns> | ||
412 | protected UUID KeyOrName(string k) | ||
413 | { | ||
414 | UUID key; | ||
415 | |||
416 | // if we can parse the string as a key, use it. | ||
417 | // else try to locate the name in inventory of object. found returns key, | ||
418 | // not found returns UUID.Zero | ||
419 | if (!UUID.TryParse(k, out key)) | ||
420 | { | ||
421 | TaskInventoryItem item = m_host.Inventory.GetInventoryItem(k); | ||
422 | |||
423 | if (item != null) | ||
424 | key = item.AssetID; | ||
425 | else | ||
426 | key = UUID.Zero; | ||
427 | } | ||
428 | |||
429 | return key; | ||
430 | } | ||
431 | |||
432 | /// <summary> | ||
433 | /// Return the UUID of the asset matching the specified key or name | ||
434 | /// and asset type. | ||
435 | /// </summary> | ||
436 | /// <param name="k"></param> | ||
437 | /// <param name="type"></param> | ||
438 | /// <returns></returns> | ||
439 | protected UUID KeyOrName(string k, AssetType type) | ||
440 | { | ||
441 | UUID key; | ||
442 | |||
443 | if (!UUID.TryParse(k, out key)) | ||
444 | { | ||
445 | TaskInventoryItem item = m_host.Inventory.GetInventoryItem(k); | ||
446 | if (item != null && item.Type == (int)type) | ||
447 | key = item.AssetID; | ||
448 | } | ||
449 | else | ||
450 | { | ||
451 | lock (m_host.TaskInventory) | ||
452 | { | ||
453 | foreach (KeyValuePair<UUID, TaskInventoryItem> item in m_host.TaskInventory) | ||
454 | { | ||
455 | if (item.Value.Type == (int)type && item.Value.Name == k) | ||
456 | { | ||
457 | key = item.Value.ItemID; | ||
458 | break; | ||
459 | } | ||
460 | } | ||
461 | } | ||
462 | } | ||
463 | |||
464 | |||
465 | return key; | ||
466 | } | ||
467 | |||
468 | //These are the implementations of the various ll-functions used by the LSL scripts. | 519 | //These are the implementations of the various ll-functions used by the LSL scripts. |
469 | public LSL_Float llSin(double f) | 520 | public LSL_Float llSin(double f) |
470 | { | 521 | { |
@@ -1483,19 +1534,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1483 | return 0; | 1534 | return 0; |
1484 | 1535 | ||
1485 | case ScriptBaseClass.STATUS_ROTATE_X: | 1536 | case ScriptBaseClass.STATUS_ROTATE_X: |
1486 | if (m_host.GetAxisRotation(2) == 2) | 1537 | // if (m_host.GetAxisRotation(2) != 0) |
1538 | if (m_host.GetAxisRotation((int)SceneObjectGroup.axisSelect.STATUS_ROTATE_X) != 0) | ||
1487 | return 1; | 1539 | return 1; |
1488 | else | 1540 | else |
1489 | return 0; | 1541 | return 0; |
1490 | 1542 | ||
1491 | case ScriptBaseClass.STATUS_ROTATE_Y: | 1543 | case ScriptBaseClass.STATUS_ROTATE_Y: |
1492 | if (m_host.GetAxisRotation(4) == 4) | 1544 | if (m_host.GetAxisRotation((int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Y) != 0) |
1493 | return 1; | 1545 | return 1; |
1494 | else | 1546 | else |
1495 | return 0; | 1547 | return 0; |
1496 | 1548 | ||
1497 | case ScriptBaseClass.STATUS_ROTATE_Z: | 1549 | case ScriptBaseClass.STATUS_ROTATE_Z: |
1498 | if (m_host.GetAxisRotation(8) == 8) | 1550 | if (m_host.GetAxisRotation((int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Z) != 0) |
1499 | return 1; | 1551 | return 1; |
1500 | else | 1552 | else |
1501 | return 0; | 1553 | return 0; |
@@ -1715,7 +1767,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1715 | if (tex.FaceTextures[i] != null) | 1767 | if (tex.FaceTextures[i] != null) |
1716 | { | 1768 | { |
1717 | tex.FaceTextures[i].Shiny = sval; | 1769 | tex.FaceTextures[i].Shiny = sval; |
1718 | tex.FaceTextures[i].Bump = bump;; | 1770 | tex.FaceTextures[i].Bump = bump; |
1719 | } | 1771 | } |
1720 | tex.DefaultTexture.Shiny = sval; | 1772 | tex.DefaultTexture.Shiny = sval; |
1721 | tex.DefaultTexture.Bump = bump; | 1773 | tex.DefaultTexture.Bump = bump; |
@@ -1838,7 +1890,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1838 | texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f); | 1890 | texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f); |
1839 | tex.DefaultTexture.RGBA = texcolor; | 1891 | tex.DefaultTexture.RGBA = texcolor; |
1840 | } | 1892 | } |
1841 | 1893 | ||
1842 | part.UpdateTextureEntry(tex.GetBytes()); | 1894 | part.UpdateTextureEntry(tex.GetBytes()); |
1843 | return; | 1895 | return; |
1844 | } | 1896 | } |
@@ -1875,10 +1927,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1875 | part.Shape.FlexiForceX = (float)Force.x; | 1927 | part.Shape.FlexiForceX = (float)Force.x; |
1876 | part.Shape.FlexiForceY = (float)Force.y; | 1928 | part.Shape.FlexiForceY = (float)Force.y; |
1877 | part.Shape.FlexiForceZ = (float)Force.z; | 1929 | part.Shape.FlexiForceZ = (float)Force.z; |
1878 | part.Shape.PathCurve = 0x80; | 1930 | part.Shape.PathCurve = (byte)Extrusion.Flexible; |
1879 | part.ParentGroup.HasGroupChanged = true; | ||
1880 | part.ScheduleFullUpdate(); | ||
1881 | } | 1931 | } |
1932 | else | ||
1933 | { | ||
1934 | // Other values not set, they do not seem to be sent to the viewer | ||
1935 | // Setting PathCurve appears to be what actually toggles the check box and turns Flexi on and off | ||
1936 | part.Shape.PathCurve = (byte)Extrusion.Straight; | ||
1937 | part.Shape.FlexiEntry = false; | ||
1938 | } | ||
1939 | part.ParentGroup.HasGroupChanged = true; | ||
1940 | part.ScheduleFullUpdate(); | ||
1882 | } | 1941 | } |
1883 | 1942 | ||
1884 | /// <summary> | 1943 | /// <summary> |
@@ -1954,7 +2013,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1954 | rgb.x = texcolor.R; | 2013 | rgb.x = texcolor.R; |
1955 | rgb.y = texcolor.G; | 2014 | rgb.y = texcolor.G; |
1956 | rgb.z = texcolor.B; | 2015 | rgb.z = texcolor.B; |
1957 | 2016 | ||
1958 | return rgb; | 2017 | return rgb; |
1959 | } | 2018 | } |
1960 | else | 2019 | else |
@@ -1996,12 +2055,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1996 | 2055 | ||
1997 | UUID textureID = new UUID(); | 2056 | UUID textureID = new UUID(); |
1998 | 2057 | ||
1999 | textureID = InventoryKey(texture, (int)AssetType.Texture); | 2058 | textureID = ScriptUtils.GetAssetIdFromItemName(m_host, texture, (int)AssetType.Texture); |
2000 | if (textureID == UUID.Zero) | 2059 | if (textureID == UUID.Zero) |
2001 | { | 2060 | { |
2002 | if (!UUID.TryParse(texture, out textureID)) | 2061 | if (!UUID.TryParse(texture, out textureID)) |
2003 | return; | 2062 | return; |
2004 | } | 2063 | } |
2005 | 2064 | ||
2006 | Primitive.TextureEntry tex = part.Shape.Textures; | 2065 | Primitive.TextureEntry tex = part.Shape.Textures; |
2007 | 2066 | ||
@@ -2207,7 +2266,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
2207 | // IF YOU GET REGION CROSSINGS WORKING WITH THIS FUNCTION, REPLACE THE WORKAROUND. | 2266 | // IF YOU GET REGION CROSSINGS WORKING WITH THIS FUNCTION, REPLACE THE WORKAROUND. |
2208 | // | 2267 | // |
2209 | // This workaround is to prevent silent failure of this function. | 2268 | // This workaround is to prevent silent failure of this function. |
2210 | // According to the specification on the SL Wiki, providing a position outside of the | 2269 | // According to the specification on the SL Wiki, providing a position outside of the |
2211 | if (pos.x < 0 || pos.x > Constants.RegionSize || pos.y < 0 || pos.y > Constants.RegionSize) | 2270 | if (pos.x < 0 || pos.x > Constants.RegionSize || pos.y < 0 || pos.y > Constants.RegionSize) |
2212 | { | 2271 | { |
2213 | return 0; | 2272 | return 0; |
@@ -2442,7 +2501,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
2442 | { | 2501 | { |
2443 | return llGetRootRotation(); | 2502 | return llGetRootRotation(); |
2444 | } | 2503 | } |
2445 | 2504 | ||
2446 | m_host.AddScriptLPS(1); | 2505 | m_host.AddScriptLPS(1); |
2447 | Quaternion q = m_host.GetWorldRotation(); | 2506 | Quaternion q = m_host.GetWorldRotation(); |
2448 | 2507 | ||
@@ -2474,14 +2533,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
2474 | if ((avatar.AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0) | 2533 | if ((avatar.AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0) |
2475 | q = avatar.CameraRotation; // Mouselook | 2534 | q = avatar.CameraRotation; // Mouselook |
2476 | else | 2535 | else |
2477 | q = avatar.Rotation; // Currently infrequently updated so may be inaccurate | 2536 | q = avatar.GetWorldRotation(); // Currently infrequently updated so may be inaccurate |
2478 | } | 2537 | } |
2479 | else | 2538 | else |
2480 | q = part.ParentGroup.GroupRotation; // Likely never get here but just in case | 2539 | q = part.ParentGroup.GroupRotation; // Likely never get here but just in case |
2481 | } | 2540 | } |
2482 | else | 2541 | else |
2483 | q = part.ParentGroup.GroupRotation; // just the group rotation | 2542 | q = part.ParentGroup.GroupRotation; // just the group rotation |
2484 | return new LSL_Rotation(q.X, q.Y, q.Z, q.W); | 2543 | |
2544 | return new LSL_Rotation(q); | ||
2485 | } | 2545 | } |
2486 | 2546 | ||
2487 | q = part.GetWorldRotation(); | 2547 | q = part.GetWorldRotation(); |
@@ -2605,8 +2665,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
2605 | public LSL_Vector llGetTorque() | 2665 | public LSL_Vector llGetTorque() |
2606 | { | 2666 | { |
2607 | m_host.AddScriptLPS(1); | 2667 | m_host.AddScriptLPS(1); |
2608 | Vector3 torque = m_host.ParentGroup.GetTorque(); | 2668 | |
2609 | return new LSL_Vector(torque.X,torque.Y,torque.Z); | 2669 | return new LSL_Vector(m_host.ParentGroup.GetTorque()); |
2610 | } | 2670 | } |
2611 | 2671 | ||
2612 | public void llSetForceAndTorque(LSL_Vector force, LSL_Vector torque, int local) | 2672 | public void llSetForceAndTorque(LSL_Vector force, LSL_Vector torque, int local) |
@@ -2639,13 +2699,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
2639 | vel = m_host.ParentGroup.RootPart.Velocity; | 2699 | vel = m_host.ParentGroup.RootPart.Velocity; |
2640 | } | 2700 | } |
2641 | 2701 | ||
2642 | return new LSL_Vector(vel.X, vel.Y, vel.Z); | 2702 | return new LSL_Vector(vel); |
2643 | } | 2703 | } |
2644 | 2704 | ||
2645 | public LSL_Vector llGetAccel() | 2705 | public LSL_Vector llGetAccel() |
2646 | { | 2706 | { |
2647 | m_host.AddScriptLPS(1); | 2707 | m_host.AddScriptLPS(1); |
2648 | return new LSL_Vector(m_host.Acceleration.X, m_host.Acceleration.Y, m_host.Acceleration.Z); | 2708 | |
2709 | return new LSL_Vector(m_host.Acceleration); | ||
2649 | } | 2710 | } |
2650 | 2711 | ||
2651 | public void llSetAngularVelocity(LSL_Vector avel, int local) | 2712 | public void llSetAngularVelocity(LSL_Vector avel, int local) |
@@ -2712,7 +2773,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
2712 | if (m_SoundModule != null) | 2773 | if (m_SoundModule != null) |
2713 | { | 2774 | { |
2714 | m_SoundModule.SendSound(m_host.UUID, | 2775 | m_SoundModule.SendSound(m_host.UUID, |
2715 | KeyOrName(sound, AssetType.Sound), volume, false, 0, | 2776 | ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound, AssetType.Sound), volume, false, 0, |
2716 | 0, false, false); | 2777 | 0, false, false); |
2717 | } | 2778 | } |
2718 | } | 2779 | } |
@@ -2722,7 +2783,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
2722 | m_host.AddScriptLPS(1); | 2783 | m_host.AddScriptLPS(1); |
2723 | if (m_SoundModule != null) | 2784 | if (m_SoundModule != null) |
2724 | { | 2785 | { |
2725 | m_SoundModule.LoopSound(m_host.UUID, KeyOrName(sound), | 2786 | m_SoundModule.LoopSound(m_host.UUID, ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound), |
2726 | volume, 20, false); | 2787 | volume, 20, false); |
2727 | } | 2788 | } |
2728 | } | 2789 | } |
@@ -2732,7 +2793,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
2732 | m_host.AddScriptLPS(1); | 2793 | m_host.AddScriptLPS(1); |
2733 | if (m_SoundModule != null) | 2794 | if (m_SoundModule != null) |
2734 | { | 2795 | { |
2735 | m_SoundModule.LoopSound(m_host.UUID, KeyOrName(sound), | 2796 | m_SoundModule.LoopSound(m_host.UUID, ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound), |
2736 | volume, 20, true); | 2797 | volume, 20, true); |
2737 | } | 2798 | } |
2738 | } | 2799 | } |
@@ -2754,7 +2815,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
2754 | if (m_SoundModule != null) | 2815 | if (m_SoundModule != null) |
2755 | { | 2816 | { |
2756 | m_SoundModule.SendSound(m_host.UUID, | 2817 | m_SoundModule.SendSound(m_host.UUID, |
2757 | KeyOrName(sound, AssetType.Sound), volume, false, 0, | 2818 | ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound, AssetType.Sound), volume, false, 0, |
2758 | 0, true, false); | 2819 | 0, true, false); |
2759 | } | 2820 | } |
2760 | } | 2821 | } |
@@ -2766,7 +2827,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
2766 | if (m_SoundModule != null) | 2827 | if (m_SoundModule != null) |
2767 | { | 2828 | { |
2768 | m_SoundModule.SendSound(m_host.UUID, | 2829 | m_SoundModule.SendSound(m_host.UUID, |
2769 | KeyOrName(sound, AssetType.Sound), volume, true, 0, 0, | 2830 | ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound, AssetType.Sound), volume, true, 0, 0, |
2770 | false, false); | 2831 | false, false); |
2771 | } | 2832 | } |
2772 | } | 2833 | } |
@@ -2783,7 +2844,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
2783 | { | 2844 | { |
2784 | m_host.AddScriptLPS(1); | 2845 | m_host.AddScriptLPS(1); |
2785 | if (m_SoundModule != null) | 2846 | if (m_SoundModule != null) |
2786 | m_SoundModule.PreloadSound(m_host.UUID, KeyOrName(sound), 0); | 2847 | m_SoundModule.PreloadSound(m_host.UUID, ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound), 0); |
2787 | ScriptSleep(1000); | 2848 | ScriptSleep(1000); |
2788 | } | 2849 | } |
2789 | 2850 | ||
@@ -3141,11 +3202,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
3141 | 3202 | ||
3142 | PhysicsActor pa = new_group.RootPart.PhysActor; | 3203 | PhysicsActor pa = new_group.RootPart.PhysActor; |
3143 | 3204 | ||
3205 | //Recoil. | ||
3144 | if (pa != null && pa.IsPhysical && (Vector3)vel != Vector3.Zero) | 3206 | if (pa != null && pa.IsPhysical && (Vector3)vel != Vector3.Zero) |
3145 | { | 3207 | { |
3146 | float groupmass = new_group.GetMass(); | 3208 | float groupmass = new_group.GetMass(); |
3147 | vel *= -groupmass; | 3209 | Vector3 recoil = -vel * groupmass * m_recoilScaleFactor; |
3148 | llApplyImpulse(vel, 0); | 3210 | if (recoil != Vector3.Zero) |
3211 | { | ||
3212 | llApplyImpulse(recoil, 0); | ||
3213 | } | ||
3149 | } | 3214 | } |
3150 | // Variable script delay? (see (http://wiki.secondlife.com/wiki/LSL_Delay) | 3215 | // Variable script delay? (see (http://wiki.secondlife.com/wiki/LSL_Delay) |
3151 | return; | 3216 | return; |
@@ -3220,7 +3285,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
3220 | { | 3285 | { |
3221 | // m_log.Info("llSleep snoozing " + sec + "s."); | 3286 | // m_log.Info("llSleep snoozing " + sec + "s."); |
3222 | m_host.AddScriptLPS(1); | 3287 | m_host.AddScriptLPS(1); |
3223 | Thread.Sleep((int)(sec * 1000)); | 3288 | |
3289 | Sleep((int)(sec * 1000)); | ||
3224 | } | 3290 | } |
3225 | 3291 | ||
3226 | public LSL_Float llGetMass() | 3292 | public LSL_Float llGetMass() |
@@ -3268,7 +3334,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
3268 | 3334 | ||
3269 | if (!UUID.TryParse(id, out objectID)) | 3335 | if (!UUID.TryParse(id, out objectID)) |
3270 | objectID = UUID.Zero; | 3336 | objectID = UUID.Zero; |
3271 | 3337 | ||
3272 | if (objectID == UUID.Zero && name == "") | 3338 | if (objectID == UUID.Zero && name == "") |
3273 | return; | 3339 | return; |
3274 | 3340 | ||
@@ -3322,7 +3388,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
3322 | /// <summary> | 3388 | /// <summary> |
3323 | /// Attach the object containing this script to the avatar that owns it. | 3389 | /// Attach the object containing this script to the avatar that owns it. |
3324 | /// </summary> | 3390 | /// </summary> |
3325 | /// <param name='attachment'>The attachment point (e.g. ATTACH_CHEST)</param> | 3391 | /// <param name='attachmentPoint'> |
3392 | /// The attachment point (e.g. <see cref="OpenSim.Region.ScriptEngine.Shared.ScriptBase.ScriptBaseClass.ATTACH_CHEST">ATTACH_CHEST</see>) | ||
3393 | /// </param> | ||
3326 | /// <returns>true if the attach suceeded, false if it did not</returns> | 3394 | /// <returns>true if the attach suceeded, false if it did not</returns> |
3327 | public bool AttachToAvatar(int attachmentPoint) | 3395 | public bool AttachToAvatar(int attachmentPoint) |
3328 | { | 3396 | { |
@@ -3332,7 +3400,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
3332 | IAttachmentsModule attachmentsModule = m_ScriptEngine.World.AttachmentsModule; | 3400 | IAttachmentsModule attachmentsModule = m_ScriptEngine.World.AttachmentsModule; |
3333 | 3401 | ||
3334 | if (attachmentsModule != null) | 3402 | if (attachmentsModule != null) |
3335 | return attachmentsModule.AttachObject(presence, grp, (uint)attachmentPoint, false, true, false); | 3403 | return attachmentsModule.AttachObject(presence, grp, (uint)attachmentPoint, false, true, false, true); |
3336 | else | 3404 | else |
3337 | return false; | 3405 | return false; |
3338 | } | 3406 | } |
@@ -3473,20 +3541,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
3473 | msg.offline = (byte)0; //offline; | 3541 | msg.offline = (byte)0; //offline; |
3474 | msg.ParentEstateID = World.RegionInfo.EstateSettings.EstateID; | 3542 | msg.ParentEstateID = World.RegionInfo.EstateSettings.EstateID; |
3475 | msg.Position = new Vector3(m_host.AbsolutePosition); | 3543 | msg.Position = new Vector3(m_host.AbsolutePosition); |
3476 | msg.RegionID = World.RegionInfo.RegionID.Guid; | 3544 | msg.RegionID = World.RegionInfo.RegionID.Guid;//RegionID.Guid; |
3477 | msg.binaryBucket | 3545 | |
3546 | Vector3 pos = m_host.AbsolutePosition; | ||
3547 | msg.binaryBucket | ||
3478 | = Util.StringToBytes256( | 3548 | = Util.StringToBytes256( |
3479 | "{0}/{1}/{2}/{3}", | 3549 | "{0}/{1}/{2}/{3}", |
3480 | World.RegionInfo.RegionName, | 3550 | World.RegionInfo.RegionName, |
3481 | (int)Math.Floor(m_host.AbsolutePosition.X), | 3551 | (int)Math.Floor(pos.X), |
3482 | (int)Math.Floor(m_host.AbsolutePosition.Y), | 3552 | (int)Math.Floor(pos.Y), |
3483 | (int)Math.Floor(m_host.AbsolutePosition.Z)); | 3553 | (int)Math.Floor(pos.Z)); |
3484 | 3554 | ||
3485 | if (m_TransferModule != null) | 3555 | if (m_TransferModule != null) |
3486 | { | 3556 | { |
3487 | m_TransferModule.SendInstantMessage(msg, delegate(bool success) {}); | 3557 | m_TransferModule.SendInstantMessage(msg, delegate(bool success) {}); |
3488 | } | 3558 | } |
3489 | 3559 | ||
3490 | ScriptSleep(2000); | 3560 | ScriptSleep(2000); |
3491 | } | 3561 | } |
3492 | 3562 | ||
@@ -3611,7 +3681,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
3611 | public void llRotLookAt(LSL_Rotation target, double strength, double damping) | 3681 | public void llRotLookAt(LSL_Rotation target, double strength, double damping) |
3612 | { | 3682 | { |
3613 | m_host.AddScriptLPS(1); | 3683 | m_host.AddScriptLPS(1); |
3614 | 3684 | ||
3615 | // Per discussion with Melanie, for non-physical objects llLookAt appears to simply | 3685 | // Per discussion with Melanie, for non-physical objects llLookAt appears to simply |
3616 | // set the rotation of the object, copy that behavior | 3686 | // set the rotation of the object, copy that behavior |
3617 | PhysicsActor pa = m_host.PhysActor; | 3687 | PhysicsActor pa = m_host.PhysActor; |
@@ -3653,7 +3723,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
3653 | if (presence != null) | 3723 | if (presence != null) |
3654 | { | 3724 | { |
3655 | // Do NOT try to parse UUID, animations cannot be triggered by ID | 3725 | // Do NOT try to parse UUID, animations cannot be triggered by ID |
3656 | UUID animID = InventoryKey(anim, (int)AssetType.Animation); | 3726 | UUID animID = ScriptUtils.GetAssetIdFromItemName(m_host, anim, (int)AssetType.Animation); |
3657 | if (animID == UUID.Zero) | 3727 | if (animID == UUID.Zero) |
3658 | presence.Animator.AddAnimation(anim, m_host.UUID); | 3728 | presence.Animator.AddAnimation(anim, m_host.UUID); |
3659 | else | 3729 | else |
@@ -3675,12 +3745,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
3675 | 3745 | ||
3676 | if (presence != null) | 3746 | if (presence != null) |
3677 | { | 3747 | { |
3678 | UUID animID = KeyOrName(anim); | 3748 | UUID animID = ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, anim); |
3679 | 3749 | ||
3680 | if (animID == UUID.Zero) | 3750 | if (animID == UUID.Zero) |
3681 | presence.Animator.RemoveAnimation(anim); | 3751 | presence.Animator.RemoveAnimation(anim); |
3682 | else | 3752 | else |
3683 | presence.Animator.RemoveAnimation(animID); | 3753 | presence.Animator.RemoveAnimation(animID, true); |
3684 | } | 3754 | } |
3685 | } | 3755 | } |
3686 | } | 3756 | } |
@@ -3753,21 +3823,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
3753 | } | 3823 | } |
3754 | else | 3824 | else |
3755 | { | 3825 | { |
3756 | bool sitting = false; | 3826 | if (m_host.ParentGroup.GetSittingAvatars().Contains(agentID)) |
3757 | if (m_host.SitTargetAvatar == agentID) | ||
3758 | { | ||
3759 | sitting = true; | ||
3760 | } | ||
3761 | else | ||
3762 | { | ||
3763 | foreach (SceneObjectPart p in m_host.ParentGroup.Parts) | ||
3764 | { | ||
3765 | if (p.SitTargetAvatar == agentID) | ||
3766 | sitting = true; | ||
3767 | } | ||
3768 | } | ||
3769 | |||
3770 | if (sitting) | ||
3771 | { | 3827 | { |
3772 | // When agent is sitting, certain permissions are implicit if requested from sitting agent | 3828 | // When agent is sitting, certain permissions are implicit if requested from sitting agent |
3773 | implicitPerms = ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION | | 3829 | implicitPerms = ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION | |
@@ -3809,7 +3865,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
3809 | INPCModule npcModule = World.RequestModuleInterface<INPCModule>(); | 3865 | INPCModule npcModule = World.RequestModuleInterface<INPCModule>(); |
3810 | if (npcModule != null && npcModule.IsNPC(agentID, World)) | 3866 | if (npcModule != null && npcModule.IsNPC(agentID, World)) |
3811 | { | 3867 | { |
3812 | if (agentID == m_host.ParentGroup.OwnerID || npcModule.GetOwner(agentID) == m_host.ParentGroup.OwnerID) | 3868 | if (npcModule.CheckPermissions(agentID, m_host.OwnerID)) |
3813 | { | 3869 | { |
3814 | lock (m_host.TaskInventory) | 3870 | lock (m_host.TaskInventory) |
3815 | { | 3871 | { |
@@ -4184,62 +4240,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
4184 | public LSL_String llGetLinkName(int linknum) | 4240 | public LSL_String llGetLinkName(int linknum) |
4185 | { | 4241 | { |
4186 | m_host.AddScriptLPS(1); | 4242 | m_host.AddScriptLPS(1); |
4187 | // simplest case, this prims link number | ||
4188 | if (linknum == m_host.LinkNum || linknum == ScriptBaseClass.LINK_THIS) | ||
4189 | return m_host.Name; | ||
4190 | |||
4191 | // parse for sitting avatare-names | ||
4192 | List<String> nametable = new List<String>(); | ||
4193 | World.ForEachRootScenePresence(delegate(ScenePresence presence) | ||
4194 | { | ||
4195 | SceneObjectPart sitPart = presence.ParentPart; | ||
4196 | if (sitPart != null && m_host.ParentGroup.ContainsPart(sitPart.LocalId)) | ||
4197 | nametable.Add(presence.ControllingClient.Name); | ||
4198 | }); | ||
4199 | |||
4200 | int totalprims = m_host.ParentGroup.PrimCount + nametable.Count; | ||
4201 | if (totalprims > m_host.ParentGroup.PrimCount) | ||
4202 | { | ||
4203 | // sitting Avatar-Name with negativ linknum / SinglePrim | ||
4204 | if (linknum < 0 && m_host.ParentGroup.PrimCount == 1 && nametable.Count == 1) | ||
4205 | return nametable[0]; | ||
4206 | // Prim-Name / SinglePrim Sitting Avatar | ||
4207 | if (linknum == 1 && m_host.ParentGroup.PrimCount == 1 && nametable.Count == 1) | ||
4208 | return m_host.Name; | ||
4209 | // LinkNumber > of Real PrimSet = AvatarName | ||
4210 | if (linknum > m_host.ParentGroup.PrimCount && linknum <= totalprims) | ||
4211 | return nametable[totalprims - linknum]; | ||
4212 | } | ||
4213 | 4243 | ||
4214 | // Single prim | 4244 | ISceneEntity entity = GetLinkEntity(linknum); |
4215 | if (m_host.LinkNum == 0) | ||
4216 | { | ||
4217 | if (linknum == 0 || linknum == ScriptBaseClass.LINK_ROOT) | ||
4218 | return m_host.Name; | ||
4219 | else | ||
4220 | return UUID.Zero.ToString(); | ||
4221 | } | ||
4222 | 4245 | ||
4223 | // Link set | 4246 | if (entity != null) |
4224 | SceneObjectPart part = null; | 4247 | return entity.Name; |
4225 | if (m_host.LinkNum == 1) // this is the Root prim | ||
4226 | { | ||
4227 | if (linknum < 0) | ||
4228 | part = m_host.ParentGroup.GetLinkNumPart(2); | ||
4229 | else | ||
4230 | part = m_host.ParentGroup.GetLinkNumPart(linknum); | ||
4231 | } | ||
4232 | else // this is a child prim | ||
4233 | { | ||
4234 | if (linknum < 2) | ||
4235 | part = m_host.ParentGroup.GetLinkNumPart(1); | ||
4236 | else | ||
4237 | part = m_host.ParentGroup.GetLinkNumPart(linknum); | ||
4238 | } | ||
4239 | if (part != null) | ||
4240 | return part.Name; | ||
4241 | else | 4248 | else |
4242 | return UUID.Zero.ToString(); | 4249 | return ScriptBaseClass.NULL_KEY; |
4243 | } | 4250 | } |
4244 | 4251 | ||
4245 | public LSL_Integer llGetInventoryNumber(int type) | 4252 | public LSL_Integer llGetInventoryNumber(int type) |
@@ -4604,8 +4611,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
4604 | if (presence.UserLevel >= 200) return; | 4611 | if (presence.UserLevel >= 200) return; |
4605 | 4612 | ||
4606 | // agent must be over the owners land | 4613 | // agent must be over the owners land |
4607 | if (m_host.OwnerID == World.LandChannel.GetLandObject( | 4614 | if (m_host.OwnerID == World.LandChannel.GetLandObject(presence.AbsolutePosition).LandData.OwnerID) |
4608 | presence.AbsolutePosition.X, presence.AbsolutePosition.Y).LandData.OwnerID) | ||
4609 | { | 4615 | { |
4610 | if (!World.TeleportClientHome(agentId, presence.ControllingClient)) | 4616 | if (!World.TeleportClientHome(agentId, presence.ControllingClient)) |
4611 | { | 4617 | { |
@@ -4621,6 +4627,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
4621 | } | 4627 | } |
4622 | } | 4628 | } |
4623 | } | 4629 | } |
4630 | |||
4624 | ScriptSleep(5000); | 4631 | ScriptSleep(5000); |
4625 | } | 4632 | } |
4626 | 4633 | ||
@@ -4641,8 +4648,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
4641 | destination = World.RegionInfo.RegionName; | 4648 | destination = World.RegionInfo.RegionName; |
4642 | 4649 | ||
4643 | // agent must be over the owners land | 4650 | // agent must be over the owners land |
4644 | if (m_host.OwnerID == World.LandChannel.GetLandObject( | 4651 | if (m_host.OwnerID == World.LandChannel.GetLandObject(presence.AbsolutePosition).LandData.OwnerID) |
4645 | presence.AbsolutePosition.X, presence.AbsolutePosition.Y).LandData.OwnerID) | ||
4646 | { | 4652 | { |
4647 | DoLLTeleport(presence, destination, targetPos, targetLookAt); | 4653 | DoLLTeleport(presence, destination, targetPos, targetLookAt); |
4648 | } | 4654 | } |
@@ -4673,8 +4679,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
4673 | if (presence.GodLevel >= 200) return; | 4679 | if (presence.GodLevel >= 200) return; |
4674 | 4680 | ||
4675 | // agent must be over the owners land | 4681 | // agent must be over the owners land |
4676 | if (m_host.OwnerID == World.LandChannel.GetLandObject( | 4682 | if (m_host.OwnerID == World.LandChannel.GetLandObject(presence.AbsolutePosition).LandData.OwnerID) |
4677 | presence.AbsolutePosition.X, presence.AbsolutePosition.Y).LandData.OwnerID) | ||
4678 | { | 4683 | { |
4679 | World.RequestTeleportLocation(presence.ControllingClient, regionHandle, targetPos, targetLookAt, (uint)TeleportFlags.ViaLocation); | 4684 | World.RequestTeleportLocation(presence.ControllingClient, regionHandle, targetPos, targetLookAt, (uint)TeleportFlags.ViaLocation); |
4680 | } | 4685 | } |
@@ -4691,7 +4696,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
4691 | 4696 | ||
4692 | private void DoLLTeleport(ScenePresence sp, string destination, Vector3 targetPos, Vector3 targetLookAt) | 4697 | private void DoLLTeleport(ScenePresence sp, string destination, Vector3 targetPos, Vector3 targetLookAt) |
4693 | { | 4698 | { |
4694 | UUID assetID = KeyOrName(destination); | 4699 | UUID assetID = ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, destination); |
4695 | 4700 | ||
4696 | // The destinaion is not an asset ID and also doesn't name a landmark. | 4701 | // The destinaion is not an asset ID and also doesn't name a landmark. |
4697 | // Use it as a sim name | 4702 | // Use it as a sim name |
@@ -4724,7 +4729,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
4724 | UUID av = new UUID(); | 4729 | UUID av = new UUID(); |
4725 | if (!UUID.TryParse(agent,out av)) | 4730 | if (!UUID.TryParse(agent,out av)) |
4726 | { | 4731 | { |
4727 | //LSLError("First parameter to llDialog needs to be a key"); | ||
4728 | return; | 4732 | return; |
4729 | } | 4733 | } |
4730 | 4734 | ||
@@ -4765,7 +4769,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
4765 | return; | 4769 | return; |
4766 | } | 4770 | } |
4767 | // TODO: Parameter check logic required. | 4771 | // TODO: Parameter check logic required. |
4768 | m_host.CollisionSound = KeyOrName(impact_sound, AssetType.Sound); | 4772 | m_host.CollisionSound = ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, impact_sound, AssetType.Sound); |
4769 | m_host.CollisionSoundVolume = (float)impact_volume; | 4773 | m_host.CollisionSoundVolume = (float)impact_volume; |
4770 | m_host.CollisionSoundType = 1; | 4774 | m_host.CollisionSoundType = 1; |
4771 | } | 4775 | } |
@@ -4890,7 +4894,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
4890 | { | 4894 | { |
4891 | if (pushrestricted) | 4895 | if (pushrestricted) |
4892 | { | 4896 | { |
4893 | ILandObject targetlandObj = World.LandChannel.GetLandObject(PusheePos.X, PusheePos.Y); | 4897 | ILandObject targetlandObj = World.LandChannel.GetLandObject(PusheePos); |
4894 | 4898 | ||
4895 | // We didn't find the parcel but region is push restricted so assume it is NOT ok | 4899 | // We didn't find the parcel but region is push restricted so assume it is NOT ok |
4896 | if (targetlandObj == null) | 4900 | if (targetlandObj == null) |
@@ -4905,7 +4909,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
4905 | } | 4909 | } |
4906 | else | 4910 | else |
4907 | { | 4911 | { |
4908 | ILandObject targetlandObj = World.LandChannel.GetLandObject(PusheePos.X, PusheePos.Y); | 4912 | ILandObject targetlandObj = World.LandChannel.GetLandObject(PusheePos); |
4909 | if (targetlandObj == null) | 4913 | if (targetlandObj == null) |
4910 | { | 4914 | { |
4911 | // We didn't find the parcel but region isn't push restricted so assume it's ok | 4915 | // We didn't find the parcel but region isn't push restricted so assume it's ok |
@@ -4935,6 +4939,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
4935 | } | 4939 | } |
4936 | } | 4940 | } |
4937 | } | 4941 | } |
4942 | |||
4938 | if (pushAllowed) | 4943 | if (pushAllowed) |
4939 | { | 4944 | { |
4940 | float distance = (PusheePos - m_host.AbsolutePosition).Length(); | 4945 | float distance = (PusheePos - m_host.AbsolutePosition).Length(); |
@@ -4964,17 +4969,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
4964 | applied_linear_impulse *= scaling_factor; | 4969 | applied_linear_impulse *= scaling_factor; |
4965 | 4970 | ||
4966 | } | 4971 | } |
4972 | |||
4967 | if (pusheeIsAvatar) | 4973 | if (pusheeIsAvatar) |
4968 | { | 4974 | { |
4969 | if (pusheeav != null) | 4975 | if (pusheeav != null) |
4970 | { | 4976 | { |
4971 | if (pusheeav.PhysicsActor != null) | 4977 | PhysicsActor pa = pusheeav.PhysicsActor; |
4978 | |||
4979 | if (pa != null) | ||
4972 | { | 4980 | { |
4973 | if (local != 0) | 4981 | if (local != 0) |
4974 | { | 4982 | { |
4975 | applied_linear_impulse *= m_host.GetWorldRotation(); | 4983 | applied_linear_impulse *= m_host.GetWorldRotation(); |
4976 | } | 4984 | } |
4977 | pusheeav.PhysicsActor.AddForce(applied_linear_impulse, true); | 4985 | |
4986 | pa.AddForce(applied_linear_impulse, true); | ||
4978 | } | 4987 | } |
4979 | } | 4988 | } |
4980 | } | 4989 | } |
@@ -5324,8 +5333,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
5324 | public LSL_Vector llGetCenterOfMass() | 5333 | public LSL_Vector llGetCenterOfMass() |
5325 | { | 5334 | { |
5326 | m_host.AddScriptLPS(1); | 5335 | m_host.AddScriptLPS(1); |
5327 | Vector3 center = m_host.GetCenterOfMass(); | 5336 | |
5328 | return new LSL_Vector(center.X,center.Y,center.Z); | 5337 | return new LSL_Vector(m_host.GetCenterOfMass()); |
5329 | } | 5338 | } |
5330 | 5339 | ||
5331 | public LSL_List llListSort(LSL_List src, int stride, int ascending) | 5340 | public LSL_List llListSort(LSL_List src, int stride, int ascending) |
@@ -5466,7 +5475,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
5466 | // SL spits out an empty string for types other than key & string | 5475 | // SL spits out an empty string for types other than key & string |
5467 | // At the time of patching, LSL_Key is currently LSL_String, | 5476 | // At the time of patching, LSL_Key is currently LSL_String, |
5468 | // so the OR check may be a little redundant, but it's being done | 5477 | // so the OR check may be a little redundant, but it's being done |
5469 | // for completion and should LSL_Key ever be implemented | 5478 | // for completion and should LSL_Key ever be implemented |
5470 | // as it's own struct | 5479 | // as it's own struct |
5471 | else if (!(src.Data[index] is LSL_String || | 5480 | else if (!(src.Data[index] is LSL_String || |
5472 | src.Data[index] is LSL_Key || | 5481 | src.Data[index] is LSL_Key || |
@@ -5603,8 +5612,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
5603 | { | 5612 | { |
5604 | m_host.AddScriptLPS(1); | 5613 | m_host.AddScriptLPS(1); |
5605 | 5614 | ||
5606 | return string.Join(", ", | 5615 | return string.Join(", ", |
5607 | (new List<object>(src.Data)).ConvertAll<string>(o => | 5616 | (new List<object>(src.Data)).ConvertAll<string>(o => |
5608 | { | 5617 | { |
5609 | return o.ToString(); | 5618 | return o.ToString(); |
5610 | }).ToArray()); | 5619 | }).ToArray()); |
@@ -5852,9 +5861,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
5852 | } | 5861 | } |
5853 | 5862 | ||
5854 | /// <summary> | 5863 | /// <summary> |
5855 | /// Insert the list identified by <src> into the | 5864 | /// Insert the list identified by <paramref name="src"/> into the |
5856 | /// list designated by <dest> such that the first | 5865 | /// list designated by <paramref name="dest"/> such that the first |
5857 | /// new element has the index specified by <index> | 5866 | /// new element has the index specified by <paramref name="index"/> |
5858 | /// </summary> | 5867 | /// </summary> |
5859 | 5868 | ||
5860 | public LSL_List llListInsertList(LSL_List dest, LSL_List src, int index) | 5869 | public LSL_List llListInsertList(LSL_List dest, LSL_List src, int index) |
@@ -6182,12 +6191,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
6182 | } | 6191 | } |
6183 | 6192 | ||
6184 | ILandObject land; | 6193 | ILandObject land; |
6185 | Vector3 pos; | ||
6186 | UUID id = UUID.Zero; | 6194 | UUID id = UUID.Zero; |
6195 | |||
6187 | if (parcel || parcelOwned) | 6196 | if (parcel || parcelOwned) |
6188 | { | 6197 | { |
6189 | pos = m_host.ParentGroup.RootPart.GetWorldPosition(); | 6198 | land = World.LandChannel.GetLandObject(m_host.ParentGroup.RootPart.GetWorldPosition()); |
6190 | land = World.LandChannel.GetLandObject(pos.X, pos.Y); | ||
6191 | if (land == null) | 6199 | if (land == null) |
6192 | { | 6200 | { |
6193 | id = UUID.Zero; | 6201 | id = UUID.Zero; |
@@ -6213,20 +6221,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
6213 | { | 6221 | { |
6214 | if (!regionWide) | 6222 | if (!regionWide) |
6215 | { | 6223 | { |
6216 | pos = ssp.AbsolutePosition; | 6224 | land = World.LandChannel.GetLandObject(ssp.AbsolutePosition); |
6217 | land = World.LandChannel.GetLandObject(pos.X, pos.Y); | ||
6218 | if (land != null) | 6225 | if (land != null) |
6219 | { | 6226 | { |
6220 | if (parcelOwned && land.LandData.OwnerID == id || | 6227 | if (parcelOwned && land.LandData.OwnerID == id || |
6221 | parcel && land.LandData.GlobalID == id) | 6228 | parcel && land.LandData.GlobalID == id) |
6222 | { | 6229 | { |
6223 | result.Add(ssp.UUID.ToString()); | 6230 | result.Add(new LSL_Key(ssp.UUID.ToString())); |
6224 | } | 6231 | } |
6225 | } | 6232 | } |
6226 | } | 6233 | } |
6227 | else | 6234 | else |
6228 | { | 6235 | { |
6229 | result.Add(ssp.UUID.ToString()); | 6236 | result.Add(new LSL_Key(ssp.UUID.ToString())); |
6230 | } | 6237 | } |
6231 | } | 6238 | } |
6232 | // Maximum of 100 results | 6239 | // Maximum of 100 results |
@@ -6330,7 +6337,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
6330 | if (m_SoundModule != null) | 6337 | if (m_SoundModule != null) |
6331 | { | 6338 | { |
6332 | m_SoundModule.TriggerSoundLimited(m_host.UUID, | 6339 | m_SoundModule.TriggerSoundLimited(m_host.UUID, |
6333 | KeyOrName(sound, AssetType.Sound), volume, | 6340 | ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound, AssetType.Sound), volume, |
6334 | bottom_south_west, top_north_east); | 6341 | bottom_south_west, top_north_east); |
6335 | } | 6342 | } |
6336 | } | 6343 | } |
@@ -6345,14 +6352,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
6345 | if (presence != null) | 6352 | if (presence != null) |
6346 | { | 6353 | { |
6347 | // agent must be over the owners land | 6354 | // agent must be over the owners land |
6348 | ILandObject land = World.LandChannel.GetLandObject(presence.AbsolutePosition.X, presence.AbsolutePosition.Y); | 6355 | ILandObject land = World.LandChannel.GetLandObject(presence.AbsolutePosition); |
6349 | if (land == null) | 6356 | if (land == null) |
6350 | return; | 6357 | return; |
6351 | 6358 | ||
6352 | if (m_host.OwnerID == land.LandData.OwnerID) | 6359 | if (m_host.OwnerID == land.LandData.OwnerID) |
6353 | { | 6360 | { |
6354 | Vector3 pos = World.GetNearestAllowedPosition(presence, land); | 6361 | Vector3 p = World.GetNearestAllowedPosition(presence, land); |
6355 | presence.TeleportWithMomentum(pos, null); | 6362 | presence.TeleportWithMomentum(p, null); |
6356 | presence.ControllingClient.SendAlertMessage("You have been ejected from this land"); | 6363 | presence.ControllingClient.SendAlertMessage("You have been ejected from this land"); |
6357 | } | 6364 | } |
6358 | } | 6365 | } |
@@ -6374,19 +6381,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
6374 | ScenePresence presence = World.GetScenePresence(key); | 6381 | ScenePresence presence = World.GetScenePresence(key); |
6375 | if (presence != null) // object is an avatar | 6382 | if (presence != null) // object is an avatar |
6376 | { | 6383 | { |
6377 | if (m_host.OwnerID | 6384 | if (m_host.OwnerID == World.LandChannel.GetLandObject(presence.AbsolutePosition).LandData.OwnerID) |
6378 | == World.LandChannel.GetLandObject( | ||
6379 | presence.AbsolutePosition.X, presence.AbsolutePosition.Y).LandData.OwnerID) | ||
6380 | return 1; | 6385 | return 1; |
6381 | } | 6386 | } |
6382 | else // object is not an avatar | 6387 | else // object is not an avatar |
6383 | { | 6388 | { |
6384 | SceneObjectPart obj = World.GetSceneObjectPart(key); | 6389 | SceneObjectPart obj = World.GetSceneObjectPart(key); |
6390 | |||
6385 | if (obj != null) | 6391 | if (obj != null) |
6386 | if (m_host.OwnerID | 6392 | { |
6387 | == World.LandChannel.GetLandObject( | 6393 | if (m_host.OwnerID == World.LandChannel.GetLandObject(obj.AbsolutePosition).LandData.OwnerID) |
6388 | obj.AbsolutePosition.X, obj.AbsolutePosition.Y).LandData.OwnerID) | ||
6389 | return 1; | 6394 | return 1; |
6395 | } | ||
6390 | } | 6396 | } |
6391 | } | 6397 | } |
6392 | 6398 | ||
@@ -6494,8 +6500,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
6494 | // if the land is group owned and the object is group owned by the same group | 6500 | // if the land is group owned and the object is group owned by the same group |
6495 | // or | 6501 | // or |
6496 | // if the object is owned by a person with estate access. | 6502 | // if the object is owned by a person with estate access. |
6497 | 6503 | ILandObject parcel = World.LandChannel.GetLandObject(av.AbsolutePosition); | |
6498 | ILandObject parcel = World.LandChannel.GetLandObject(av.AbsolutePosition.X, av.AbsolutePosition.Y); | ||
6499 | if (parcel != null) | 6504 | if (parcel != null) |
6500 | { | 6505 | { |
6501 | if (m_host.OwnerID == parcel.LandData.OwnerID || | 6506 | if (m_host.OwnerID == parcel.LandData.OwnerID || |
@@ -6507,14 +6512,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
6507 | } | 6512 | } |
6508 | } | 6513 | } |
6509 | } | 6514 | } |
6510 | |||
6511 | } | 6515 | } |
6512 | |||
6513 | } | 6516 | } |
6514 | 6517 | ||
6515 | public LSL_Vector llGroundSlope(LSL_Vector offset) | 6518 | public LSL_Vector llGroundSlope(LSL_Vector offset) |
6516 | { | 6519 | { |
6517 | m_host.AddScriptLPS(1); | 6520 | m_host.AddScriptLPS(1); |
6521 | |||
6518 | //Get the slope normal. This gives us the equation of the plane tangent to the slope. | 6522 | //Get the slope normal. This gives us the equation of the plane tangent to the slope. |
6519 | LSL_Vector vsn = llGroundNormal(offset); | 6523 | LSL_Vector vsn = llGroundNormal(offset); |
6520 | 6524 | ||
@@ -6525,7 +6529,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
6525 | vsl.Normalize(); | 6529 | vsl.Normalize(); |
6526 | //Normalization might be overkill here | 6530 | //Normalization might be overkill here |
6527 | 6531 | ||
6528 | return new LSL_Vector(vsl.X, vsl.Y, vsl.Z); | 6532 | vsn.x = vsl.X; |
6533 | vsn.y = vsl.Y; | ||
6534 | vsn.z = vsl.Z; | ||
6535 | |||
6536 | return vsn; | ||
6529 | } | 6537 | } |
6530 | 6538 | ||
6531 | public LSL_Vector llGroundNormal(LSL_Vector offset) | 6539 | public LSL_Vector llGroundNormal(LSL_Vector offset) |
@@ -6575,7 +6583,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
6575 | //I believe the crossproduct of two normalized vectors is a normalized vector so | 6583 | //I believe the crossproduct of two normalized vectors is a normalized vector so |
6576 | //this normalization may be overkill | 6584 | //this normalization may be overkill |
6577 | 6585 | ||
6578 | return new LSL_Vector(vsn.X, vsn.Y, vsn.Z); | 6586 | return new LSL_Vector(vsn); |
6579 | } | 6587 | } |
6580 | 6588 | ||
6581 | public LSL_Vector llGroundContour(LSL_Vector offset) | 6589 | public LSL_Vector llGroundContour(LSL_Vector offset) |
@@ -6687,6 +6695,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
6687 | ps.BurstSpeedMax = 1.0f; | 6695 | ps.BurstSpeedMax = 1.0f; |
6688 | ps.BurstRate = 0.1f; | 6696 | ps.BurstRate = 0.1f; |
6689 | ps.PartMaxAge = 10.0f; | 6697 | ps.PartMaxAge = 10.0f; |
6698 | ps.BurstPartCount = 1; | ||
6690 | return ps; | 6699 | return ps; |
6691 | } | 6700 | } |
6692 | 6701 | ||
@@ -6710,8 +6719,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
6710 | 6719 | ||
6711 | private void SetParticleSystem(SceneObjectPart part, LSL_List rules) | 6720 | private void SetParticleSystem(SceneObjectPart part, LSL_List rules) |
6712 | { | 6721 | { |
6713 | |||
6714 | |||
6715 | if (rules.Length == 0) | 6722 | if (rules.Length == 0) |
6716 | { | 6723 | { |
6717 | part.RemoveParticleSystem(); | 6724 | part.RemoveParticleSystem(); |
@@ -6802,7 +6809,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
6802 | break; | 6809 | break; |
6803 | 6810 | ||
6804 | case (int)ScriptBaseClass.PSYS_SRC_TEXTURE: | 6811 | case (int)ScriptBaseClass.PSYS_SRC_TEXTURE: |
6805 | prules.Texture = KeyOrName(rules.GetLSLStringItem(i + 1)); | 6812 | prules.Texture = ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, rules.GetLSLStringItem(i + 1)); |
6806 | break; | 6813 | break; |
6807 | 6814 | ||
6808 | case (int)ScriptBaseClass.PSYS_SRC_BURST_RATE: | 6815 | case (int)ScriptBaseClass.PSYS_SRC_BURST_RATE: |
@@ -6947,7 +6954,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
6947 | m_host.OwnerID, m_host.Name, destID, | 6954 | m_host.OwnerID, m_host.Name, destID, |
6948 | (byte)InstantMessageDialog.TaskInventoryOffered, | 6955 | (byte)InstantMessageDialog.TaskInventoryOffered, |
6949 | false, string.Format("'{0}'", category), | 6956 | false, string.Format("'{0}'", category), |
6950 | // We won't go so far as to add a SLURL, but this is the format used by LL as of 2012-10-06 | 6957 | // We won't go so far as to add a SLURL, but this is the format used by LL as of 2012-10-06 |
6951 | // false, string.Format("'{0}' ( http://slurl.com/secondlife/{1}/{2}/{3}/{4} )", category, World.Name, (int)pos.X, (int)pos.Y, (int)pos.Z), | 6958 | // false, string.Format("'{0}' ( http://slurl.com/secondlife/{1}/{2}/{3}/{4} )", category, World.Name, (int)pos.X, (int)pos.Y, (int)pos.Z), |
6952 | folderID, false, pos, | 6959 | folderID, false, pos, |
6953 | bucket, false); | 6960 | bucket, false); |
@@ -7066,12 +7073,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
7066 | public LSL_String llAvatarOnLinkSitTarget(int linknum) | 7073 | public LSL_String llAvatarOnLinkSitTarget(int linknum) |
7067 | { | 7074 | { |
7068 | m_host.AddScriptLPS(1); | 7075 | m_host.AddScriptLPS(1); |
7069 | if(linknum == ScriptBaseClass.LINK_SET || | 7076 | if(linknum == ScriptBaseClass.LINK_SET || |
7070 | linknum == ScriptBaseClass.LINK_ALL_CHILDREN || | 7077 | linknum == ScriptBaseClass.LINK_ALL_CHILDREN || |
7071 | linknum == ScriptBaseClass.LINK_ALL_OTHERS) return UUID.Zero.ToString(); | 7078 | linknum == ScriptBaseClass.LINK_ALL_OTHERS) return UUID.Zero.ToString(); |
7072 | 7079 | ||
7073 | List<SceneObjectPart> parts = GetLinkParts(linknum); | 7080 | List<SceneObjectPart> parts = GetLinkParts(linknum); |
7074 | if (parts.Count == 0) return UUID.Zero.ToString(); | 7081 | if (parts.Count == 0) return UUID.Zero.ToString(); |
7075 | return parts[0].SitTargetAvatar.ToString(); | 7082 | return parts[0].SitTargetAvatar.ToString(); |
7076 | } | 7083 | } |
7077 | 7084 | ||
@@ -7080,7 +7087,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
7080 | { | 7087 | { |
7081 | m_host.AddScriptLPS(1); | 7088 | m_host.AddScriptLPS(1); |
7082 | UUID key; | 7089 | UUID key; |
7083 | ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); | 7090 | ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition); |
7091 | |||
7084 | if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageBanned)) | 7092 | if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageBanned)) |
7085 | { | 7093 | { |
7086 | int expires = 0; | 7094 | int expires = 0; |
@@ -7222,20 +7230,23 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
7222 | } | 7230 | } |
7223 | if (buttons.Length > 12) | 7231 | if (buttons.Length > 12) |
7224 | { | 7232 | { |
7225 | LSLError("No more than 12 buttons can be shown"); | 7233 | ShoutError("button list too long, must be 12 or fewer entries"); |
7226 | return; | ||
7227 | } | 7234 | } |
7228 | string[] buts = new string[buttons.Length]; | 7235 | int length = buttons.Length; |
7229 | for (int i = 0; i < buttons.Length; i++) | 7236 | if (length > 12) |
7237 | length = 12; | ||
7238 | |||
7239 | string[] buts = new string[length]; | ||
7240 | for (int i = 0; i < length; i++) | ||
7230 | { | 7241 | { |
7231 | if (buttons.Data[i].ToString() == String.Empty) | 7242 | if (buttons.Data[i].ToString() == String.Empty) |
7232 | { | 7243 | { |
7233 | LSLError("button label cannot be blank"); | 7244 | ShoutError("button label cannot be blank"); |
7234 | return; | 7245 | return; |
7235 | } | 7246 | } |
7236 | if (buttons.Data[i].ToString().Length > 24) | 7247 | if (buttons.Data[i].ToString().Length > 24) |
7237 | { | 7248 | { |
7238 | llWhisper(ScriptBaseClass.DEBUG_CHANNEL, "button label cannot be longer than 24 characters"); | 7249 | ShoutError("button label cannot be longer than 24 characters"); |
7239 | return; | 7250 | return; |
7240 | } | 7251 | } |
7241 | buts[i] = buttons.Data[i].ToString(); | 7252 | buts[i] = buttons.Data[i].ToString(); |
@@ -7371,6 +7382,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
7371 | public void llCloseRemoteDataChannel(string channel) | 7382 | public void llCloseRemoteDataChannel(string channel) |
7372 | { | 7383 | { |
7373 | m_host.AddScriptLPS(1); | 7384 | m_host.AddScriptLPS(1); |
7385 | |||
7386 | IXmlRpcRouter xmlRpcRouter = m_ScriptEngine.World.RequestModuleInterface<IXmlRpcRouter>(); | ||
7387 | if (xmlRpcRouter != null) | ||
7388 | { | ||
7389 | xmlRpcRouter.UnRegisterReceiver(channel, m_item.ItemID); | ||
7390 | } | ||
7391 | |||
7374 | IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>(); | 7392 | IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>(); |
7375 | if (xmlrpcMod != null) | 7393 | if (xmlrpcMod != null) |
7376 | xmlrpcMod.CloseXMLRPCChannel((UUID)channel); | 7394 | xmlrpcMod.CloseXMLRPCChannel((UUID)channel); |
@@ -7450,7 +7468,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
7450 | hollow = 0.70f; | 7468 | hollow = 0.70f; |
7451 | } | 7469 | } |
7452 | } | 7470 | } |
7453 | // Otherwise, hollow is limited to 95%. | 7471 | // Otherwise, hollow is limited to 95%. |
7454 | else | 7472 | else |
7455 | { | 7473 | { |
7456 | if (hollow > 0.95f) | 7474 | if (hollow > 0.95f) |
@@ -7744,9 +7762,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
7744 | UUID sculptId; | 7762 | UUID sculptId; |
7745 | 7763 | ||
7746 | if (!UUID.TryParse(map, out sculptId)) | 7764 | if (!UUID.TryParse(map, out sculptId)) |
7747 | { | 7765 | sculptId = ScriptUtils.GetAssetIdFromItemName(m_host, map, (int)AssetType.Texture); |
7748 | sculptId = InventoryKey(map, (int)AssetType.Texture); | ||
7749 | } | ||
7750 | 7766 | ||
7751 | if (sculptId == UUID.Zero) | 7767 | if (sculptId == UUID.Zero) |
7752 | return; | 7768 | return; |
@@ -7843,7 +7859,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
7843 | physdata.PhysShapeType = (PhysShapeType)part.PhysicsShapeType; | 7859 | physdata.PhysShapeType = (PhysShapeType)part.PhysicsShapeType; |
7844 | physdata.Density = part.Density; | 7860 | physdata.Density = part.Density; |
7845 | physdata.Friction = part.Friction; | 7861 | physdata.Friction = part.Friction; |
7846 | physdata.Bounce = part.Bounciness; | 7862 | physdata.Bounce = part.Restitution; |
7847 | physdata.GravitationModifier = part.GravityModifier; | 7863 | physdata.GravitationModifier = part.GravityModifier; |
7848 | 7864 | ||
7849 | if ((material_bits & (int)ScriptBaseClass.DENSITY) != 0) | 7865 | if ((material_bits & (int)ScriptBaseClass.DENSITY) != 0) |
@@ -8236,7 +8252,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
8236 | 8252 | ||
8237 | ExtraPhysicsData physdata = new ExtraPhysicsData(); | 8253 | ExtraPhysicsData physdata = new ExtraPhysicsData(); |
8238 | physdata.Density = part.Density; | 8254 | physdata.Density = part.Density; |
8239 | physdata.Bounce = part.Bounciness; | 8255 | physdata.Bounce = part.Restitution; |
8240 | physdata.GravitationModifier = part.GravityModifier; | 8256 | physdata.GravitationModifier = part.GravityModifier; |
8241 | physdata.PhysShapeType = (PhysShapeType)shape_type; | 8257 | physdata.PhysShapeType = (PhysShapeType)shape_type; |
8242 | 8258 | ||
@@ -8509,7 +8525,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
8509 | { | 8525 | { |
8510 | m_host.AddScriptLPS(1); | 8526 | m_host.AddScriptLPS(1); |
8511 | 8527 | ||
8512 | ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); | 8528 | ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition); |
8513 | 8529 | ||
8514 | if (land.LandData.OwnerID != m_host.OwnerID) | 8530 | if (land.LandData.OwnerID != m_host.OwnerID) |
8515 | return; | 8531 | return; |
@@ -8523,7 +8539,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
8523 | { | 8539 | { |
8524 | m_host.AddScriptLPS(1); | 8540 | m_host.AddScriptLPS(1); |
8525 | 8541 | ||
8526 | ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); | 8542 | ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition); |
8527 | 8543 | ||
8528 | if (land.LandData.OwnerID != m_host.OwnerID) | 8544 | if (land.LandData.OwnerID != m_host.OwnerID) |
8529 | return String.Empty; | 8545 | return String.Empty; |
@@ -8534,8 +8550,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
8534 | public LSL_Vector llGetRootPosition() | 8550 | public LSL_Vector llGetRootPosition() |
8535 | { | 8551 | { |
8536 | m_host.AddScriptLPS(1); | 8552 | m_host.AddScriptLPS(1); |
8537 | return new LSL_Vector(m_host.ParentGroup.AbsolutePosition.X, m_host.ParentGroup.AbsolutePosition.Y, | 8553 | |
8538 | m_host.ParentGroup.AbsolutePosition.Z); | 8554 | return new LSL_Vector(m_host.ParentGroup.AbsolutePosition); |
8539 | } | 8555 | } |
8540 | 8556 | ||
8541 | /// <summary> | 8557 | /// <summary> |
@@ -8558,13 +8574,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
8558 | if ((avatar.AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0) | 8574 | if ((avatar.AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0) |
8559 | q = avatar.CameraRotation; // Mouselook | 8575 | q = avatar.CameraRotation; // Mouselook |
8560 | else | 8576 | else |
8561 | q = avatar.Rotation; // Currently infrequently updated so may be inaccurate | 8577 | q = avatar.GetWorldRotation(); // Currently infrequently updated so may be inaccurate |
8562 | else | 8578 | else |
8563 | q = m_host.ParentGroup.GroupRotation; // Likely never get here but just in case | 8579 | q = m_host.ParentGroup.GroupRotation; // Likely never get here but just in case |
8564 | } | 8580 | } |
8565 | else | 8581 | else |
8566 | q = m_host.ParentGroup.GroupRotation; // just the group rotation | 8582 | q = m_host.ParentGroup.GroupRotation; // just the group rotation |
8567 | return new LSL_Rotation(q.X, q.Y, q.Z, q.W); | 8583 | |
8584 | return new LSL_Rotation(q); | ||
8568 | } | 8585 | } |
8569 | 8586 | ||
8570 | public LSL_String llGetObjectDesc() | 8587 | public LSL_String llGetObjectDesc() |
@@ -8731,8 +8748,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
8731 | 8748 | ||
8732 | public LSL_Vector llGetGeometricCenter() | 8749 | public LSL_Vector llGetGeometricCenter() |
8733 | { | 8750 | { |
8734 | Vector3 tmp = m_host.GetGeometricCenter(); | 8751 | return new LSL_Vector(m_host.GetGeometricCenter()); |
8735 | return new LSL_Vector(tmp.X, tmp.Y, tmp.Z); | ||
8736 | } | 8752 | } |
8737 | 8753 | ||
8738 | public LSL_List llGetPrimitiveParams(LSL_List rules) | 8754 | public LSL_List llGetPrimitiveParams(LSL_List rules) |
@@ -8839,9 +8855,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
8839 | break; | 8855 | break; |
8840 | 8856 | ||
8841 | case (int)ScriptBaseClass.PRIM_SIZE: | 8857 | case (int)ScriptBaseClass.PRIM_SIZE: |
8842 | res.Add(new LSL_Vector(part.Scale.X, | 8858 | res.Add(new LSL_Vector(part.Scale)); |
8843 | part.Scale.Y, | ||
8844 | part.Scale.Z)); | ||
8845 | break; | 8859 | break; |
8846 | 8860 | ||
8847 | case (int)ScriptBaseClass.PRIM_ROTATION: | 8861 | case (int)ScriptBaseClass.PRIM_ROTATION: |
@@ -8909,16 +8923,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
8909 | res.Add(new LSL_Vector(Shape.PathTaperX / 100.0, Shape.PathTaperY / 100.0, 0)); | 8923 | res.Add(new LSL_Vector(Shape.PathTaperX / 100.0, Shape.PathTaperY / 100.0, 0)); |
8910 | 8924 | ||
8911 | // float revolutions | 8925 | // float revolutions |
8912 | res.Add(new LSL_Float(Math.Round(Shape.PathRevolutions * 0.015d, 2, MidpointRounding.AwayFromZero)) + 1.0d); | 8926 | res.Add(new LSL_Float(Math.Round(Shape.PathRevolutions * 0.015d, 2, MidpointRounding.AwayFromZero)) + 1.0d); |
8913 | // Slightly inaccurate, because an unsigned byte is being used to represent | 8927 | // Slightly inaccurate, because an unsigned byte is being used to represent |
8914 | // the entire range of floating-point values from 1.0 through 4.0 (which is how | 8928 | // the entire range of floating-point values from 1.0 through 4.0 (which is how |
8915 | // SL does it). | 8929 | // SL does it). |
8916 | // | 8930 | // |
8917 | // Using these formulas to store and retrieve PathRevolutions, it is not | 8931 | // Using these formulas to store and retrieve PathRevolutions, it is not |
8918 | // possible to use all values between 1.00 and 4.00. For instance, you can't | 8932 | // possible to use all values between 1.00 and 4.00. For instance, you can't |
8919 | // represent 1.10. You can represent 1.09 and 1.11, but not 1.10. So, if you | 8933 | // represent 1.10. You can represent 1.09 and 1.11, but not 1.10. So, if you |
8920 | // use llSetPrimitiveParams to set revolutions to 1.10 and then retreive them | 8934 | // use llSetPrimitiveParams to set revolutions to 1.10 and then retreive them |
8921 | // with llGetPrimitiveParams, you'll retrieve 1.09. You can also see a similar | 8935 | // with llGetPrimitiveParams, you'll retrieve 1.09. You can also see a similar |
8922 | // behavior in the viewer as you cannot set 1.10. The viewer jumps to 1.11. | 8936 | // behavior in the viewer as you cannot set 1.10. The viewer jumps to 1.11. |
8923 | // In SL, llSetPrimitveParams and llGetPrimitiveParams can set and get a value | 8937 | // In SL, llSetPrimitveParams and llGetPrimitiveParams can set and get a value |
8924 | // such as 1.10. So, SL must store and retreive the actual user input rather | 8938 | // such as 1.10. So, SL must store and retreive the actual user input rather |
@@ -9202,9 +9216,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
9202 | case (int)ScriptBaseClass.PRIM_DESC: | 9216 | case (int)ScriptBaseClass.PRIM_DESC: |
9203 | res.Add(new LSL_String(part.Description)); | 9217 | res.Add(new LSL_String(part.Description)); |
9204 | break; | 9218 | break; |
9205 | |||
9206 | case (int)ScriptBaseClass.PRIM_ROT_LOCAL: | 9219 | case (int)ScriptBaseClass.PRIM_ROT_LOCAL: |
9207 | res.Add(new LSL_Rotation(part.RotationOffset.X, part.RotationOffset.Y, part.RotationOffset.Z, part.RotationOffset.W)); | 9220 | res.Add(new LSL_Rotation(part.RotationOffset)); |
9208 | break; | 9221 | break; |
9209 | 9222 | ||
9210 | case (int)ScriptBaseClass.PRIM_POS_LOCAL: | 9223 | case (int)ScriptBaseClass.PRIM_POS_LOCAL: |
@@ -10236,6 +10249,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
10236 | return UUID.Zero.ToString(); | 10249 | return UUID.Zero.ToString(); |
10237 | } | 10250 | } |
10238 | } | 10251 | } |
10252 | |||
10239 | public LSL_String llRequestURL() | 10253 | public LSL_String llRequestURL() |
10240 | { | 10254 | { |
10241 | m_host.AddScriptLPS(1); | 10255 | m_host.AddScriptLPS(1); |
@@ -10387,7 +10401,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
10387 | 10401 | ||
10388 | // according to the docs, this command only works if script owner and land owner are the same | 10402 | // according to the docs, this command only works if script owner and land owner are the same |
10389 | // lets add estate owners and gods, too, and use the generic permission check. | 10403 | // lets add estate owners and gods, too, and use the generic permission check. |
10390 | ILandObject landObject = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); | 10404 | ILandObject landObject = World.LandChannel.GetLandObject(m_host.AbsolutePosition); |
10391 | if (!World.Permissions.CanEditParcelProperties(m_host.OwnerID, landObject, GroupPowers.ChangeMedia)) return; | 10405 | if (!World.Permissions.CanEditParcelProperties(m_host.OwnerID, landObject, GroupPowers.ChangeMedia)) return; |
10392 | 10406 | ||
10393 | bool update = false; // send a ParcelMediaUpdate (and possibly change the land's media URL)? | 10407 | bool update = false; // send a ParcelMediaUpdate (and possibly change the land's media URL)? |
@@ -10710,22 +10724,23 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
10710 | m_host.AddScriptLPS(1); | 10724 | m_host.AddScriptLPS(1); |
10711 | 10725 | ||
10712 | if (m_item.PermsGranter == UUID.Zero) | 10726 | if (m_item.PermsGranter == UUID.Zero) |
10713 | return new LSL_Vector(); | 10727 | return Vector3.Zero; |
10714 | 10728 | ||
10715 | if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0) | 10729 | if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0) |
10716 | { | 10730 | { |
10717 | ShoutError("No permissions to track the camera"); | 10731 | ShoutError("No permissions to track the camera"); |
10718 | return new LSL_Vector(); | 10732 | return Vector3.Zero; |
10719 | } | 10733 | } |
10720 | 10734 | ||
10721 | // ScenePresence presence = World.GetScenePresence(m_host.OwnerID); | 10735 | // ScenePresence presence = World.GetScenePresence(m_host.OwnerID); |
10722 | ScenePresence presence = World.GetScenePresence(m_item.PermsGranter); | 10736 | ScenePresence presence = World.GetScenePresence(m_item.PermsGranter); |
10723 | if (presence != null) | 10737 | if (presence != null) |
10724 | { | 10738 | { |
10725 | LSL_Vector pos = new LSL_Vector(presence.CameraPosition.X, presence.CameraPosition.Y, presence.CameraPosition.Z); | 10739 | LSL_Vector pos = new LSL_Vector(presence.CameraPosition); |
10726 | return pos; | 10740 | return pos; |
10727 | } | 10741 | } |
10728 | return new LSL_Vector(); | 10742 | |
10743 | return Vector3.Zero; | ||
10729 | } | 10744 | } |
10730 | 10745 | ||
10731 | public LSL_Rotation llGetCameraRot() | 10746 | public LSL_Rotation llGetCameraRot() |
@@ -10733,22 +10748,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
10733 | m_host.AddScriptLPS(1); | 10748 | m_host.AddScriptLPS(1); |
10734 | 10749 | ||
10735 | if (m_item.PermsGranter == UUID.Zero) | 10750 | if (m_item.PermsGranter == UUID.Zero) |
10736 | return new LSL_Rotation(); | 10751 | return Quaternion.Identity; |
10737 | 10752 | ||
10738 | if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0) | 10753 | if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0) |
10739 | { | 10754 | { |
10740 | ShoutError("No permissions to track the camera"); | 10755 | ShoutError("No permissions to track the camera"); |
10741 | return new LSL_Rotation(); | 10756 | return Quaternion.Identity; |
10742 | } | 10757 | } |
10743 | 10758 | ||
10744 | // ScenePresence presence = World.GetScenePresence(m_host.OwnerID); | 10759 | // ScenePresence presence = World.GetScenePresence(m_host.OwnerID); |
10745 | ScenePresence presence = World.GetScenePresence(m_item.PermsGranter); | 10760 | ScenePresence presence = World.GetScenePresence(m_item.PermsGranter); |
10746 | if (presence != null) | 10761 | if (presence != null) |
10747 | { | 10762 | { |
10748 | return new LSL_Rotation(presence.CameraRotation.X, presence.CameraRotation.Y, presence.CameraRotation.Z, presence.CameraRotation.W); | 10763 | return new LSL_Rotation(presence.CameraRotation); |
10749 | } | 10764 | } |
10750 | 10765 | ||
10751 | return new LSL_Rotation(); | 10766 | return Quaternion.Identity; |
10752 | } | 10767 | } |
10753 | 10768 | ||
10754 | /// <summary> | 10769 | /// <summary> |
@@ -10829,7 +10844,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
10829 | { | 10844 | { |
10830 | m_host.AddScriptLPS(1); | 10845 | m_host.AddScriptLPS(1); |
10831 | UUID key; | 10846 | UUID key; |
10832 | ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); | 10847 | ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition); |
10833 | if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageBanned)) | 10848 | if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageBanned)) |
10834 | { | 10849 | { |
10835 | int expires = 0; | 10850 | int expires = 0; |
@@ -10870,7 +10885,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
10870 | { | 10885 | { |
10871 | m_host.AddScriptLPS(1); | 10886 | m_host.AddScriptLPS(1); |
10872 | UUID key; | 10887 | UUID key; |
10873 | ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); | 10888 | ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition); |
10874 | if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageAllowed)) | 10889 | if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageAllowed)) |
10875 | { | 10890 | { |
10876 | if (UUID.TryParse(avatar, out key)) | 10891 | if (UUID.TryParse(avatar, out key)) |
@@ -10897,7 +10912,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
10897 | { | 10912 | { |
10898 | m_host.AddScriptLPS(1); | 10913 | m_host.AddScriptLPS(1); |
10899 | UUID key; | 10914 | UUID key; |
10900 | ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); | 10915 | ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition); |
10901 | if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageBanned)) | 10916 | if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageBanned)) |
10902 | { | 10917 | { |
10903 | if (UUID.TryParse(avatar, out key)) | 10918 | if (UUID.TryParse(avatar, out key)) |
@@ -11129,9 +11144,60 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
11129 | IHttpRequestModule httpScriptMod = | 11144 | IHttpRequestModule httpScriptMod = |
11130 | m_ScriptEngine.World.RequestModuleInterface<IHttpRequestModule>(); | 11145 | m_ScriptEngine.World.RequestModuleInterface<IHttpRequestModule>(); |
11131 | List<string> param = new List<string>(); | 11146 | List<string> param = new List<string>(); |
11132 | foreach (object o in parameters.Data) | 11147 | bool ok; |
11148 | Int32 flag; | ||
11149 | |||
11150 | for (int i = 0; i < parameters.Data.Length; i += 2) | ||
11133 | { | 11151 | { |
11134 | param.Add(o.ToString()); | 11152 | ok = Int32.TryParse(parameters.Data[i].ToString(), out flag); |
11153 | if (!ok || flag < 0 || | ||
11154 | flag > (int)HttpRequestConstants.HTTP_PRAGMA_NO_CACHE) | ||
11155 | { | ||
11156 | throw new ScriptException("Parameter " + i.ToString() + " is an invalid flag"); | ||
11157 | } | ||
11158 | |||
11159 | param.Add(parameters.Data[i].ToString()); //Add parameter flag | ||
11160 | |||
11161 | if (flag != (int)HttpRequestConstants.HTTP_CUSTOM_HEADER) | ||
11162 | { | ||
11163 | param.Add(parameters.Data[i+1].ToString()); //Add parameter value | ||
11164 | } | ||
11165 | else | ||
11166 | { | ||
11167 | //Parameters are in pairs and custom header takes | ||
11168 | //arguments in pairs so adjust for header marker. | ||
11169 | ++i; | ||
11170 | |||
11171 | //Maximum of 8 headers are allowed based on the | ||
11172 | //Second Life documentation for llHTTPRequest. | ||
11173 | for (int count = 1; count <= 8; ++count) | ||
11174 | { | ||
11175 | //Enough parameters remaining for (another) header? | ||
11176 | if (parameters.Data.Length - i < 2) | ||
11177 | { | ||
11178 | //There must be at least one name/value pair for custom header | ||
11179 | if (count == 1) | ||
11180 | throw new ScriptException("Missing name/value for custom header at parameter " + i.ToString()); | ||
11181 | break; | ||
11182 | } | ||
11183 | |||
11184 | if (HttpStandardHeaders.Contains(parameters.Data[i].ToString(), StringComparer.OrdinalIgnoreCase)) | ||
11185 | throw new ScriptException("Name is invalid as a custom header at parameter " + i.ToString()); | ||
11186 | |||
11187 | param.Add(parameters.Data[i].ToString()); | ||
11188 | param.Add(parameters.Data[i+1].ToString()); | ||
11189 | |||
11190 | //Have we reached the end of the list of headers? | ||
11191 | //End is marked by a string with a single digit. | ||
11192 | if (i+2 >= parameters.Data.Length || | ||
11193 | Char.IsDigit(parameters.Data[i].ToString()[0])) | ||
11194 | { | ||
11195 | break; | ||
11196 | } | ||
11197 | |||
11198 | i += 2; | ||
11199 | } | ||
11200 | } | ||
11135 | } | 11201 | } |
11136 | 11202 | ||
11137 | Vector3 position = m_host.AbsolutePosition; | 11203 | Vector3 position = m_host.AbsolutePosition; |
@@ -11263,7 +11329,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
11263 | public void llResetLandBanList() | 11329 | public void llResetLandBanList() |
11264 | { | 11330 | { |
11265 | m_host.AddScriptLPS(1); | 11331 | m_host.AddScriptLPS(1); |
11266 | LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).LandData; | 11332 | LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition).LandData; |
11267 | if (land.OwnerID == m_host.OwnerID) | 11333 | if (land.OwnerID == m_host.OwnerID) |
11268 | { | 11334 | { |
11269 | foreach (LandAccessEntry entry in land.ParcelAccessList) | 11335 | foreach (LandAccessEntry entry in land.ParcelAccessList) |
@@ -11280,7 +11346,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
11280 | public void llResetLandPassList() | 11346 | public void llResetLandPassList() |
11281 | { | 11347 | { |
11282 | m_host.AddScriptLPS(1); | 11348 | m_host.AddScriptLPS(1); |
11283 | LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).LandData; | 11349 | LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition).LandData; |
11284 | if (land.OwnerID == m_host.OwnerID) | 11350 | if (land.OwnerID == m_host.OwnerID) |
11285 | { | 11351 | { |
11286 | foreach (LandAccessEntry entry in land.ParcelAccessList) | 11352 | foreach (LandAccessEntry entry in land.ParcelAccessList) |
@@ -11297,12 +11363,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
11297 | public LSL_Integer llGetParcelPrimCount(LSL_Vector pos, int category, int sim_wide) | 11363 | public LSL_Integer llGetParcelPrimCount(LSL_Vector pos, int category, int sim_wide) |
11298 | { | 11364 | { |
11299 | m_host.AddScriptLPS(1); | 11365 | m_host.AddScriptLPS(1); |
11300 | 11366 | ||
11301 | ILandObject lo = World.LandChannel.GetLandObject((float)pos.x, (float)pos.y); | 11367 | ILandObject lo = World.LandChannel.GetLandObject((float)pos.x, (float)pos.y); |
11302 | 11368 | ||
11303 | if (lo == null) | 11369 | if (lo == null) |
11304 | return 0; | 11370 | return 0; |
11305 | 11371 | ||
11306 | IPrimCounts pc = lo.PrimCounts; | 11372 | IPrimCounts pc = lo.PrimCounts; |
11307 | 11373 | ||
11308 | if (sim_wide != ScriptBaseClass.FALSE) | 11374 | if (sim_wide != ScriptBaseClass.FALSE) |
@@ -11332,7 +11398,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
11332 | else if (category == ScriptBaseClass.PARCEL_COUNT_TEMP) | 11398 | else if (category == ScriptBaseClass.PARCEL_COUNT_TEMP) |
11333 | return 0; // counts not implemented yet | 11399 | return 0; // counts not implemented yet |
11334 | } | 11400 | } |
11335 | 11401 | ||
11336 | return 0; | 11402 | return 0; |
11337 | } | 11403 | } |
11338 | 11404 | ||
@@ -11517,6 +11583,35 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
11517 | case ScriptBaseClass.OBJECT_PHYSICS_COST: | 11583 | case ScriptBaseClass.OBJECT_PHYSICS_COST: |
11518 | ret.Add(new LSL_Float(0)); | 11584 | ret.Add(new LSL_Float(0)); |
11519 | break; | 11585 | break; |
11586 | case ScriptBaseClass.OBJECT_CHARACTER_TIME: // Pathfinding | ||
11587 | ret.Add(new LSL_Float(0)); | ||
11588 | break; | ||
11589 | case ScriptBaseClass.OBJECT_ROOT: | ||
11590 | SceneObjectPart p = av.ParentPart; | ||
11591 | if (p != null) | ||
11592 | { | ||
11593 | ret.Add(new LSL_String(p.ParentGroup.RootPart.UUID.ToString())); | ||
11594 | } | ||
11595 | else | ||
11596 | { | ||
11597 | ret.Add(new LSL_String(id)); | ||
11598 | } | ||
11599 | break; | ||
11600 | case ScriptBaseClass.OBJECT_ATTACHED_POINT: | ||
11601 | ret.Add(new LSL_Integer(0)); | ||
11602 | break; | ||
11603 | case ScriptBaseClass.OBJECT_PATHFINDING_TYPE: // Pathfinding | ||
11604 | ret.Add(new LSL_Integer(ScriptBaseClass.OPT_AVATAR)); | ||
11605 | break; | ||
11606 | case ScriptBaseClass.OBJECT_PHYSICS: | ||
11607 | ret.Add(new LSL_Integer(0)); | ||
11608 | break; | ||
11609 | case ScriptBaseClass.OBJECT_PHANTOM: | ||
11610 | ret.Add(new LSL_Integer(0)); | ||
11611 | break; | ||
11612 | case ScriptBaseClass.OBJECT_TEMP_ON_REZ: | ||
11613 | ret.Add(new LSL_Integer(0)); | ||
11614 | break; | ||
11520 | default: | 11615 | default: |
11521 | // Invalid or unhandled constant. | 11616 | // Invalid or unhandled constant. |
11522 | ret.Add(new LSL_Integer(ScriptBaseClass.OBJECT_UNKNOWN_DETAIL)); | 11617 | ret.Add(new LSL_Integer(ScriptBaseClass.OBJECT_UNKNOWN_DETAIL)); |
@@ -11608,6 +11703,52 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
11608 | // The value returned in SL for normal prims is prim count | 11703 | // The value returned in SL for normal prims is prim count |
11609 | ret.Add(new LSL_Float(obj.PhysicsCost)); | 11704 | ret.Add(new LSL_Float(obj.PhysicsCost)); |
11610 | break; | 11705 | break; |
11706 | case ScriptBaseClass.OBJECT_CHARACTER_TIME: // Pathfinding | ||
11707 | ret.Add(new LSL_Float(0)); | ||
11708 | break; | ||
11709 | case ScriptBaseClass.OBJECT_ROOT: | ||
11710 | ret.Add(new LSL_String(obj.ParentGroup.RootPart.UUID.ToString())); | ||
11711 | break; | ||
11712 | case ScriptBaseClass.OBJECT_ATTACHED_POINT: | ||
11713 | ret.Add(new LSL_Integer(obj.ParentGroup.AttachmentPoint)); | ||
11714 | break; | ||
11715 | case ScriptBaseClass.OBJECT_PATHFINDING_TYPE: | ||
11716 | byte pcode = obj.Shape.PCode; | ||
11717 | if (obj.ParentGroup.AttachmentPoint != 0 | ||
11718 | || pcode == (byte)PCode.Grass | ||
11719 | || pcode == (byte)PCode.Tree | ||
11720 | || pcode == (byte)PCode.NewTree) | ||
11721 | { | ||
11722 | ret.Add(new LSL_Integer(ScriptBaseClass.OPT_OTHER)); | ||
11723 | } | ||
11724 | else | ||
11725 | { | ||
11726 | ret.Add(new LSL_Integer(ScriptBaseClass.OPT_LEGACY_LINKSET)); | ||
11727 | } | ||
11728 | break; | ||
11729 | case ScriptBaseClass.OBJECT_PHYSICS: | ||
11730 | if (obj.ParentGroup.AttachmentPoint != 0) | ||
11731 | { | ||
11732 | ret.Add(new LSL_Integer(0)); // Always false if attached | ||
11733 | } | ||
11734 | else | ||
11735 | { | ||
11736 | ret.Add(new LSL_Integer(obj.ParentGroup.UsesPhysics ? 1 : 0)); | ||
11737 | } | ||
11738 | break; | ||
11739 | case ScriptBaseClass.OBJECT_PHANTOM: | ||
11740 | if (obj.ParentGroup.AttachmentPoint != 0) | ||
11741 | { | ||
11742 | ret.Add(new LSL_Integer(0)); // Always false if attached | ||
11743 | } | ||
11744 | else | ||
11745 | { | ||
11746 | ret.Add(new LSL_Integer(obj.ParentGroup.IsPhantom ? 1 : 0)); | ||
11747 | } | ||
11748 | break; | ||
11749 | case ScriptBaseClass.OBJECT_TEMP_ON_REZ: | ||
11750 | ret.Add(new LSL_Integer(obj.ParentGroup.IsTemporary ? 1 : 0)); | ||
11751 | break; | ||
11611 | default: | 11752 | default: |
11612 | // Invalid or unhandled constant. | 11753 | // Invalid or unhandled constant. |
11613 | ret.Add(new LSL_Integer(ScriptBaseClass.OBJECT_UNKNOWN_DETAIL)); | 11754 | ret.Add(new LSL_Integer(ScriptBaseClass.OBJECT_UNKNOWN_DETAIL)); |
@@ -11618,7 +11759,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
11618 | return ret; | 11759 | return ret; |
11619 | } | 11760 | } |
11620 | } | 11761 | } |
11621 | 11762 | ||
11622 | return new LSL_List(); | 11763 | return new LSL_List(); |
11623 | } | 11764 | } |
11624 | 11765 | ||
@@ -11687,14 +11828,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
11687 | return UUID.Zero.ToString(); | 11828 | return UUID.Zero.ToString(); |
11688 | } | 11829 | } |
11689 | 11830 | ||
11831 | string reqIdentifier = UUID.Random().ToString(); | ||
11832 | |||
11690 | // was: UUID tid = tid = AsyncCommands. | 11833 | // was: UUID tid = tid = AsyncCommands. |
11691 | UUID tid = AsyncCommands.DataserverPlugin.RegisterRequest(m_host.LocalId, m_item.ItemID, assetID.ToString()); | 11834 | UUID tid = AsyncCommands.DataserverPlugin.RegisterRequest(m_host.LocalId, m_item.ItemID, reqIdentifier); |
11692 | 11835 | ||
11693 | if (NotecardCache.IsCached(assetID)) | 11836 | if (NotecardCache.IsCached(assetID)) |
11694 | { | 11837 | { |
11695 | AsyncCommands. | 11838 | AsyncCommands.DataserverPlugin.DataserverReply(reqIdentifier, NotecardCache.GetLines(assetID).ToString()); |
11696 | DataserverPlugin.DataserverReply(assetID.ToString(), | 11839 | |
11697 | NotecardCache.GetLines(assetID).ToString()); | ||
11698 | ScriptSleep(100); | 11840 | ScriptSleep(100); |
11699 | return tid.ToString(); | 11841 | return tid.ToString(); |
11700 | } | 11842 | } |
@@ -11710,9 +11852,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
11710 | string data = Encoding.UTF8.GetString(a.Data); | 11852 | string data = Encoding.UTF8.GetString(a.Data); |
11711 | //m_log.Debug(data); | 11853 | //m_log.Debug(data); |
11712 | NotecardCache.Cache(id, data); | 11854 | NotecardCache.Cache(id, data); |
11713 | AsyncCommands. | 11855 | AsyncCommands.DataserverPlugin.DataserverReply(reqIdentifier, NotecardCache.GetLines(id).ToString()); |
11714 | DataserverPlugin.DataserverReply(id.ToString(), | ||
11715 | NotecardCache.GetLines(id).ToString()); | ||
11716 | }); | 11856 | }); |
11717 | 11857 | ||
11718 | ScriptSleep(100); | 11858 | ScriptSleep(100); |
@@ -11741,13 +11881,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
11741 | return UUID.Zero.ToString(); | 11881 | return UUID.Zero.ToString(); |
11742 | } | 11882 | } |
11743 | 11883 | ||
11884 | string reqIdentifier = UUID.Random().ToString(); | ||
11885 | |||
11744 | // was: UUID tid = tid = AsyncCommands. | 11886 | // was: UUID tid = tid = AsyncCommands. |
11745 | UUID tid = AsyncCommands.DataserverPlugin.RegisterRequest(m_host.LocalId, m_item.ItemID, assetID.ToString()); | 11887 | UUID tid = AsyncCommands.DataserverPlugin.RegisterRequest(m_host.LocalId, m_item.ItemID, reqIdentifier); |
11746 | 11888 | ||
11747 | if (NotecardCache.IsCached(assetID)) | 11889 | if (NotecardCache.IsCached(assetID)) |
11748 | { | 11890 | { |
11749 | AsyncCommands.DataserverPlugin.DataserverReply(assetID.ToString(), | 11891 | AsyncCommands.DataserverPlugin.DataserverReply( |
11750 | NotecardCache.GetLine(assetID, line, m_notecardLineReadCharsMax)); | 11892 | reqIdentifier, NotecardCache.GetLine(assetID, line, m_notecardLineReadCharsMax)); |
11893 | |||
11751 | ScriptSleep(100); | 11894 | ScriptSleep(100); |
11752 | return tid.ToString(); | 11895 | return tid.ToString(); |
11753 | } | 11896 | } |
@@ -11763,8 +11906,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
11763 | string data = Encoding.UTF8.GetString(a.Data); | 11906 | string data = Encoding.UTF8.GetString(a.Data); |
11764 | //m_log.Debug(data); | 11907 | //m_log.Debug(data); |
11765 | NotecardCache.Cache(id, data); | 11908 | NotecardCache.Cache(id, data); |
11766 | AsyncCommands.DataserverPlugin.DataserverReply(id.ToString(), | 11909 | AsyncCommands.DataserverPlugin.DataserverReply( |
11767 | NotecardCache.GetLine(id, line, m_notecardLineReadCharsMax)); | 11910 | reqIdentifier, NotecardCache.GetLine(assetID, line, m_notecardLineReadCharsMax)); |
11768 | }); | 11911 | }); |
11769 | 11912 | ||
11770 | ScriptSleep(100); | 11913 | ScriptSleep(100); |
@@ -11799,7 +11942,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
11799 | 11942 | ||
11800 | LSL_List result = new LSL_List(); | 11943 | LSL_List result = new LSL_List(); |
11801 | 11944 | ||
11802 | if (obj != null && obj.OwnerID != m_host.OwnerID) | 11945 | if (obj != null && obj.OwnerID == m_host.OwnerID) |
11803 | { | 11946 | { |
11804 | LSL_List remaining = GetPrimParams(obj, rules, ref result); | 11947 | LSL_List remaining = GetPrimParams(obj, rules, ref result); |
11805 | 11948 | ||
@@ -11903,7 +12046,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
11903 | World.ForEachScenePresence(delegate(ScenePresence sp) | 12046 | World.ForEachScenePresence(delegate(ScenePresence sp) |
11904 | { | 12047 | { |
11905 | Vector3 ac = sp.AbsolutePosition - rayStart; | 12048 | Vector3 ac = sp.AbsolutePosition - rayStart; |
11906 | Vector3 bc = sp.AbsolutePosition - rayEnd; | 12049 | // Vector3 bc = sp.AbsolutePosition - rayEnd; |
11907 | 12050 | ||
11908 | double d = Math.Abs(Vector3.Mag(Vector3.Cross(ab, ac)) / Vector3.Distance(rayStart, rayEnd)); | 12051 | double d = Math.Abs(Vector3.Mag(Vector3.Cross(ab, ac)) / Vector3.Distance(rayStart, rayEnd)); |
11909 | 12052 | ||
@@ -11991,9 +12134,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
11991 | radius = Math.Abs(maxY); | 12134 | radius = Math.Abs(maxY); |
11992 | if (Math.Abs(maxZ) > radius) | 12135 | if (Math.Abs(maxZ) > radius) |
11993 | radius = Math.Abs(maxZ); | 12136 | radius = Math.Abs(maxZ); |
11994 | 12137 | radius = radius*1.413f; | |
11995 | Vector3 ac = group.AbsolutePosition - rayStart; | 12138 | Vector3 ac = group.AbsolutePosition - rayStart; |
11996 | Vector3 bc = group.AbsolutePosition - rayEnd; | 12139 | // Vector3 bc = group.AbsolutePosition - rayEnd; |
11997 | 12140 | ||
11998 | double d = Math.Abs(Vector3.Mag(Vector3.Cross(ab, ac)) / Vector3.Distance(rayStart, rayEnd)); | 12141 | double d = Math.Abs(Vector3.Mag(Vector3.Cross(ab, ac)) / Vector3.Distance(rayStart, rayEnd)); |
11999 | 12142 | ||
@@ -12006,11 +12149,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
12006 | if (d2 > 0) | 12149 | if (d2 > 0) |
12007 | return; | 12150 | return; |
12008 | 12151 | ||
12152 | ray = new Ray(rayStart, Vector3.Normalize(rayEnd - rayStart)); | ||
12009 | EntityIntersection intersection = group.TestIntersection(ray, true, false); | 12153 | EntityIntersection intersection = group.TestIntersection(ray, true, false); |
12010 | // Miss. | 12154 | // Miss. |
12011 | if (!intersection.HitTF) | 12155 | if (!intersection.HitTF) |
12012 | return; | 12156 | return; |
12013 | 12157 | ||
12158 | Vector3 b1 = group.AbsolutePosition + new Vector3(minX, minY, minZ); | ||
12159 | Vector3 b2 = group.AbsolutePosition + new Vector3(maxX, maxY, maxZ); | ||
12160 | //m_log.DebugFormat("[LLCASTRAY]: min<{0},{1},{2}>, max<{3},{4},{5}> = hitp<{6},{7},{8}>", b1.X,b1.Y,b1.Z,b2.X,b2.Y,b2.Z,intersection.ipoint.X,intersection.ipoint.Y,intersection.ipoint.Z); | ||
12161 | if (!(intersection.ipoint.X >= b1.X && intersection.ipoint.X <= b2.X && | ||
12162 | intersection.ipoint.Y >= b1.Y && intersection.ipoint.Y <= b2.Y && | ||
12163 | intersection.ipoint.Z >= b1.Z && intersection.ipoint.Z <= b2.Z)) | ||
12164 | return; | ||
12165 | |||
12014 | ContactResult result = new ContactResult (); | 12166 | ContactResult result = new ContactResult (); |
12015 | result.ConsumerID = group.LocalId; | 12167 | result.ConsumerID = group.LocalId; |
12016 | // result.Depth = intersection.distance; | 12168 | // result.Depth = intersection.distance; |
@@ -12226,7 +12378,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
12226 | if (checkNonPhysical) | 12378 | if (checkNonPhysical) |
12227 | rayfilter |= RayFilterFlags.nonphysical; | 12379 | rayfilter |= RayFilterFlags.nonphysical; |
12228 | if (detectPhantom) | 12380 | if (detectPhantom) |
12229 | rayfilter |= RayFilterFlags.LSLPhanton; | 12381 | rayfilter |= RayFilterFlags.LSLPhantom; |
12230 | 12382 | ||
12231 | Vector3 direction = dir * ( 1/dist); | 12383 | Vector3 direction = dir * ( 1/dist); |
12232 | 12384 | ||
@@ -12284,8 +12436,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
12284 | if (checkPhysical || checkNonPhysical || detectPhantom) | 12436 | if (checkPhysical || checkNonPhysical || detectPhantom) |
12285 | { | 12437 | { |
12286 | ContactResult[] objectHits = ObjectIntersection(rayStart, rayEnd, checkPhysical, checkNonPhysical, detectPhantom); | 12438 | ContactResult[] objectHits = ObjectIntersection(rayStart, rayEnd, checkPhysical, checkNonPhysical, detectPhantom); |
12287 | foreach (ContactResult r in objectHits) | 12439 | for (int iter = 0; iter < objectHits.Length; iter++) |
12288 | results.Add(r); | 12440 | { |
12441 | // Redistance the Depth because the Scene RayCaster returns distance from center to make the rezzing code simpler. | ||
12442 | objectHits[iter].Depth = Vector3.Distance(objectHits[iter].Pos, rayStart); | ||
12443 | results.Add(objectHits[iter]); | ||
12444 | } | ||
12289 | } | 12445 | } |
12290 | } | 12446 | } |
12291 | 12447 | ||
@@ -12346,7 +12502,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
12346 | else | 12502 | else |
12347 | { | 12503 | { |
12348 | ScenePresence sp = World.GetScenePresence(result.ConsumerID); | 12504 | ScenePresence sp = World.GetScenePresence(result.ConsumerID); |
12349 | /// It it a boy? a girl? | 12505 | /// It it a boy? a girl? |
12350 | if (sp != null) | 12506 | if (sp != null) |
12351 | itemID = sp.UUID; | 12507 | itemID = sp.UUID; |
12352 | } | 12508 | } |
@@ -12358,7 +12514,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
12358 | list.Add(new LSL_Integer(linkNum)); | 12514 | list.Add(new LSL_Integer(linkNum)); |
12359 | 12515 | ||
12360 | if ((dataFlags & ScriptBaseClass.RC_GET_NORMAL) == ScriptBaseClass.RC_GET_NORMAL) | 12516 | if ((dataFlags & ScriptBaseClass.RC_GET_NORMAL) == ScriptBaseClass.RC_GET_NORMAL) |
12361 | list.Add(new LSL_Vector(result.Normal.X, result.Normal.Y, result.Normal.Z)); | 12517 | list.Add(new LSL_Vector(result.Normal)); |
12362 | 12518 | ||
12363 | values++; | 12519 | values++; |
12364 | if (values >= count) | 12520 | if (values >= count) |
@@ -13233,7 +13389,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
13233 | 13389 | ||
13234 | public static void Cache(UUID assetID, string text) | 13390 | public static void Cache(UUID assetID, string text) |
13235 | { | 13391 | { |
13236 | CacheCheck(); | 13392 | CheckCache(); |
13237 | 13393 | ||
13238 | lock (m_Notecards) | 13394 | lock (m_Notecards) |
13239 | { | 13395 | { |
@@ -13271,7 +13427,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
13271 | /// Get a notecard line. | 13427 | /// Get a notecard line. |
13272 | /// </summary> | 13428 | /// </summary> |
13273 | /// <param name="assetID"></param> | 13429 | /// <param name="assetID"></param> |
13274 | /// <param name="line">Lines start at index 0</param> | 13430 | /// <param name="lineNumber">Lines start at index 0</param> |
13275 | /// <returns></returns> | 13431 | /// <returns></returns> |
13276 | public static string GetLine(UUID assetID, int lineNumber) | 13432 | public static string GetLine(UUID assetID, int lineNumber) |
13277 | { | 13433 | { |
@@ -13300,9 +13456,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
13300 | /// Get a notecard line. | 13456 | /// Get a notecard line. |
13301 | /// </summary> | 13457 | /// </summary> |
13302 | /// <param name="assetID"></param> | 13458 | /// <param name="assetID"></param> |
13303 | /// <param name="line">Lines start at index 0</param> | 13459 | /// <param name="lineNumber">Lines start at index 0</param> |
13304 | /// <param name="maxLength">Maximum length of the returned line. Longer lines will be truncated</para> | 13460 | /// <param name="maxLength"> |
13305 | /// <returns></returns> | 13461 | /// Maximum length of the returned line. |
13462 | /// </param> | ||
13463 | /// <returns> | ||
13464 | /// If the line length is longer than <paramref name="maxLength"/>, | ||
13465 | /// the return string will be truncated. | ||
13466 | /// </returns> | ||
13306 | public static string GetLine(UUID assetID, int lineNumber, int maxLength) | 13467 | public static string GetLine(UUID assetID, int lineNumber, int maxLength) |
13307 | { | 13468 | { |
13308 | string line = GetLine(assetID, lineNumber); | 13469 | string line = GetLine(assetID, lineNumber); |
@@ -13313,13 +13474,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
13313 | return line; | 13474 | return line; |
13314 | } | 13475 | } |
13315 | 13476 | ||
13316 | public static void CacheCheck() | 13477 | public static void CheckCache() |
13317 | { | 13478 | { |
13318 | foreach (UUID key in new List<UUID>(m_Notecards.Keys)) | 13479 | lock (m_Notecards) |
13319 | { | 13480 | { |
13320 | Notecard nc = m_Notecards[key]; | 13481 | foreach (UUID key in new List<UUID>(m_Notecards.Keys)) |
13321 | if (nc.lastRef.AddSeconds(30) < DateTime.Now) | 13482 | { |
13322 | m_Notecards.Remove(key); | 13483 | Notecard nc = m_Notecards[key]; |
13484 | if (nc.lastRef.AddSeconds(30) < DateTime.Now) | ||
13485 | m_Notecards.Remove(key); | ||
13486 | } | ||
13323 | } | 13487 | } |
13324 | } | 13488 | } |
13325 | } | 13489 | } |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs index ceb4660..1d6cb6d 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs | |||
@@ -30,6 +30,7 @@ using System.Reflection; | |||
30 | using System.Collections; | 30 | using System.Collections; |
31 | using System.Collections.Generic; | 31 | using System.Collections.Generic; |
32 | using System.Runtime.Remoting.Lifetime; | 32 | using System.Runtime.Remoting.Lifetime; |
33 | using System.Threading; | ||
33 | using OpenMetaverse; | 34 | using OpenMetaverse; |
34 | using Nini.Config; | 35 | using Nini.Config; |
35 | using OpenSim; | 36 | using OpenSim; |
@@ -61,9 +62,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
61 | internal bool m_LSFunctionsEnabled = false; | 62 | internal bool m_LSFunctionsEnabled = false; |
62 | internal IScriptModuleComms m_comms = null; | 63 | internal IScriptModuleComms m_comms = null; |
63 | 64 | ||
64 | public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, TaskInventoryItem item) | 65 | public void Initialize( |
66 | IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item, WaitHandle coopSleepHandle) | ||
65 | { | 67 | { |
66 | m_ScriptEngine = ScriptEngine; | 68 | m_ScriptEngine = scriptEngine; |
67 | m_host = host; | 69 | m_host = host; |
68 | 70 | ||
69 | if (m_ScriptEngine.Config.GetBoolean("AllowLightShareFunctions", false)) | 71 | if (m_ScriptEngine.Config.GetBoolean("AllowLightShareFunctions", false)) |
@@ -92,10 +94,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
92 | get { return m_ScriptEngine.World; } | 94 | get { return m_ScriptEngine.World; } |
93 | } | 95 | } |
94 | 96 | ||
95 | // | 97 | /// <summary> |
96 | //Dumps an error message on the debug console. | 98 | /// Dumps an error message on the debug console. |
97 | // | 99 | /// </summary> |
98 | |||
99 | internal void LSShoutError(string message) | 100 | internal void LSShoutError(string message) |
100 | { | 101 | { |
101 | if (message.Length > 1023) | 102 | if (message.Length > 1023) |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs index 8f34833..bd776b6 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs | |||
@@ -30,6 +30,8 @@ using System.Reflection; | |||
30 | using System.Collections; | 30 | using System.Collections; |
31 | using System.Collections.Generic; | 31 | using System.Collections.Generic; |
32 | using System.Runtime.Remoting.Lifetime; | 32 | using System.Runtime.Remoting.Lifetime; |
33 | using System.Threading; | ||
34 | using log4net; | ||
33 | using OpenMetaverse; | 35 | using OpenMetaverse; |
34 | using Nini.Config; | 36 | using Nini.Config; |
35 | using OpenSim; | 37 | using OpenSim; |
@@ -55,15 +57,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
55 | [Serializable] | 57 | [Serializable] |
56 | public class MOD_Api : MarshalByRefObject, IMOD_Api, IScriptApi | 58 | public class MOD_Api : MarshalByRefObject, IMOD_Api, IScriptApi |
57 | { | 59 | { |
60 | // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
61 | |||
58 | internal IScriptEngine m_ScriptEngine; | 62 | internal IScriptEngine m_ScriptEngine; |
59 | internal SceneObjectPart m_host; | 63 | internal SceneObjectPart m_host; |
60 | internal TaskInventoryItem m_item; | 64 | internal TaskInventoryItem m_item; |
61 | internal bool m_MODFunctionsEnabled = false; | 65 | internal bool m_MODFunctionsEnabled = false; |
62 | internal IScriptModuleComms m_comms = null; | 66 | internal IScriptModuleComms m_comms = null; |
63 | 67 | ||
64 | public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, TaskInventoryItem item) | 68 | public void Initialize( |
69 | IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item, WaitHandle coopSleepHandle) | ||
65 | { | 70 | { |
66 | m_ScriptEngine = ScriptEngine; | 71 | m_ScriptEngine = scriptEngine; |
67 | m_host = host; | 72 | m_host = host; |
68 | m_item = item; | 73 | m_item = item; |
69 | 74 | ||
@@ -107,8 +112,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
107 | if (message.Length > 1023) | 112 | if (message.Length > 1023) |
108 | message = message.Substring(0, 1023); | 113 | message = message.Substring(0, 1023); |
109 | 114 | ||
110 | World.SimChat(Utils.StringToBytes(message), | 115 | World.SimChat( |
111 | ChatTypeEnum.Shout, ScriptBaseClass.DEBUG_CHANNEL, m_host.ParentGroup.RootPart.AbsolutePosition, m_host.Name, m_host.UUID, true); | 116 | Utils.StringToBytes(message), |
117 | ChatTypeEnum.Shout, ScriptBaseClass.DEBUG_CHANNEL, | ||
118 | m_host.ParentGroup.RootPart.AbsolutePosition, m_host.Name, m_host.UUID, false); | ||
112 | 119 | ||
113 | IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>(); | 120 | IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>(); |
114 | wComm.DeliverMessage(ChatTypeEnum.Shout, ScriptBaseClass.DEBUG_CHANNEL, m_host.Name, m_host.UUID, message); | 121 | wComm.DeliverMessage(ChatTypeEnum.Shout, ScriptBaseClass.DEBUG_CHANNEL, m_host.Name, m_host.UUID, message); |
@@ -122,8 +129,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
122 | /// <returns>string result of the invocation</returns> | 129 | /// <returns>string result of the invocation</returns> |
123 | public void modInvokeN(string fname, params object[] parms) | 130 | public void modInvokeN(string fname, params object[] parms) |
124 | { | 131 | { |
132 | // m_log.DebugFormat( | ||
133 | // "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type", | ||
134 | // fname, | ||
135 | // string.Join(",", Array.ConvertAll<object, string>(parms, o => o.ToString())), | ||
136 | // ((MethodInfo)MethodBase.GetCurrentMethod()).ReturnType); | ||
137 | |||
125 | Type returntype = m_comms.LookupReturnType(fname); | 138 | Type returntype = m_comms.LookupReturnType(fname); |
126 | if (returntype != typeof(string)) | 139 | if (returntype != typeof(void)) |
127 | MODError(String.Format("return type mismatch for {0}",fname)); | 140 | MODError(String.Format("return type mismatch for {0}",fname)); |
128 | 141 | ||
129 | modInvoke(fname,parms); | 142 | modInvoke(fname,parms); |
@@ -131,6 +144,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
131 | 144 | ||
132 | public LSL_String modInvokeS(string fname, params object[] parms) | 145 | public LSL_String modInvokeS(string fname, params object[] parms) |
133 | { | 146 | { |
147 | // m_log.DebugFormat( | ||
148 | // "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type", | ||
149 | // fname, | ||
150 | // string.Join(",", Array.ConvertAll<object, string>(parms, o => o.ToString())), | ||
151 | // ((MethodInfo)MethodBase.GetCurrentMethod()).ReturnType); | ||
152 | |||
134 | Type returntype = m_comms.LookupReturnType(fname); | 153 | Type returntype = m_comms.LookupReturnType(fname); |
135 | if (returntype != typeof(string)) | 154 | if (returntype != typeof(string)) |
136 | MODError(String.Format("return type mismatch for {0}",fname)); | 155 | MODError(String.Format("return type mismatch for {0}",fname)); |
@@ -141,6 +160,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
141 | 160 | ||
142 | public LSL_Integer modInvokeI(string fname, params object[] parms) | 161 | public LSL_Integer modInvokeI(string fname, params object[] parms) |
143 | { | 162 | { |
163 | // m_log.DebugFormat( | ||
164 | // "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type", | ||
165 | // fname, | ||
166 | // string.Join(",", Array.ConvertAll<object, string>(parms, o => o.ToString())), | ||
167 | // ((MethodInfo)MethodBase.GetCurrentMethod()).ReturnType); | ||
168 | |||
144 | Type returntype = m_comms.LookupReturnType(fname); | 169 | Type returntype = m_comms.LookupReturnType(fname); |
145 | if (returntype != typeof(int)) | 170 | if (returntype != typeof(int)) |
146 | MODError(String.Format("return type mismatch for {0}",fname)); | 171 | MODError(String.Format("return type mismatch for {0}",fname)); |
@@ -151,6 +176,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
151 | 176 | ||
152 | public LSL_Float modInvokeF(string fname, params object[] parms) | 177 | public LSL_Float modInvokeF(string fname, params object[] parms) |
153 | { | 178 | { |
179 | // m_log.DebugFormat( | ||
180 | // "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type", | ||
181 | // fname, | ||
182 | // string.Join(",", Array.ConvertAll<object, string>(parms, o => o.ToString())), | ||
183 | // ((MethodInfo)MethodBase.GetCurrentMethod()).ReturnType); | ||
184 | |||
154 | Type returntype = m_comms.LookupReturnType(fname); | 185 | Type returntype = m_comms.LookupReturnType(fname); |
155 | if (returntype != typeof(float)) | 186 | if (returntype != typeof(float)) |
156 | MODError(String.Format("return type mismatch for {0}",fname)); | 187 | MODError(String.Format("return type mismatch for {0}",fname)); |
@@ -161,6 +192,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
161 | 192 | ||
162 | public LSL_Key modInvokeK(string fname, params object[] parms) | 193 | public LSL_Key modInvokeK(string fname, params object[] parms) |
163 | { | 194 | { |
195 | // m_log.DebugFormat( | ||
196 | // "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type", | ||
197 | // fname, | ||
198 | // string.Join(",", Array.ConvertAll<object, string>(parms, o => o.ToString())), | ||
199 | // ((MethodInfo)MethodBase.GetCurrentMethod()).ReturnType); | ||
200 | |||
164 | Type returntype = m_comms.LookupReturnType(fname); | 201 | Type returntype = m_comms.LookupReturnType(fname); |
165 | if (returntype != typeof(UUID)) | 202 | if (returntype != typeof(UUID)) |
166 | MODError(String.Format("return type mismatch for {0}",fname)); | 203 | MODError(String.Format("return type mismatch for {0}",fname)); |
@@ -171,6 +208,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
171 | 208 | ||
172 | public LSL_Vector modInvokeV(string fname, params object[] parms) | 209 | public LSL_Vector modInvokeV(string fname, params object[] parms) |
173 | { | 210 | { |
211 | // m_log.DebugFormat( | ||
212 | // "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type", | ||
213 | // fname, | ||
214 | // string.Join(",", Array.ConvertAll<object, string>(parms, o => o.ToString())), | ||
215 | // ((MethodInfo)MethodBase.GetCurrentMethod()).ReturnType); | ||
216 | |||
174 | Type returntype = m_comms.LookupReturnType(fname); | 217 | Type returntype = m_comms.LookupReturnType(fname); |
175 | if (returntype != typeof(OpenMetaverse.Vector3)) | 218 | if (returntype != typeof(OpenMetaverse.Vector3)) |
176 | MODError(String.Format("return type mismatch for {0}",fname)); | 219 | MODError(String.Format("return type mismatch for {0}",fname)); |
@@ -181,6 +224,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
181 | 224 | ||
182 | public LSL_Rotation modInvokeR(string fname, params object[] parms) | 225 | public LSL_Rotation modInvokeR(string fname, params object[] parms) |
183 | { | 226 | { |
227 | // m_log.DebugFormat( | ||
228 | // "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type", | ||
229 | // fname, | ||
230 | // string.Join(",", Array.ConvertAll<object, string>(parms, o => o.ToString())), | ||
231 | // ((MethodInfo)MethodBase.GetCurrentMethod()).ReturnType); | ||
232 | |||
184 | Type returntype = m_comms.LookupReturnType(fname); | 233 | Type returntype = m_comms.LookupReturnType(fname); |
185 | if (returntype != typeof(OpenMetaverse.Quaternion)) | 234 | if (returntype != typeof(OpenMetaverse.Quaternion)) |
186 | MODError(String.Format("return type mismatch for {0}",fname)); | 235 | MODError(String.Format("return type mismatch for {0}",fname)); |
@@ -191,6 +240,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
191 | 240 | ||
192 | public LSL_List modInvokeL(string fname, params object[] parms) | 241 | public LSL_List modInvokeL(string fname, params object[] parms) |
193 | { | 242 | { |
243 | // m_log.DebugFormat( | ||
244 | // "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type", | ||
245 | // fname, | ||
246 | // string.Join(",", Array.ConvertAll<object, string>(parms, o => o.ToString())), | ||
247 | // ((MethodInfo)MethodBase.GetCurrentMethod()).ReturnType); | ||
248 | |||
194 | Type returntype = m_comms.LookupReturnType(fname); | 249 | Type returntype = m_comms.LookupReturnType(fname); |
195 | if (returntype != typeof(object[])) | 250 | if (returntype != typeof(object[])) |
196 | MODError(String.Format("return type mismatch for {0}",fname)); | 251 | MODError(String.Format("return type mismatch for {0}",fname)); |
@@ -211,6 +266,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
211 | { | 266 | { |
212 | llist[i] = new LSL_Float((float)result[i]); | 267 | llist[i] = new LSL_Float((float)result[i]); |
213 | } | 268 | } |
269 | else if (result[i] is double) | ||
270 | { | ||
271 | llist[i] = new LSL_Float((double)result[i]); | ||
272 | } | ||
214 | else if (result[i] is UUID) | 273 | else if (result[i] is UUID) |
215 | { | 274 | { |
216 | llist[i] = new LSL_Key(result[i].ToString()); | 275 | llist[i] = new LSL_Key(result[i].ToString()); |
@@ -248,6 +307,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
248 | return ""; | 307 | return ""; |
249 | } | 308 | } |
250 | 309 | ||
310 | // m_log.DebugFormat( | ||
311 | // "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type", | ||
312 | // fname, | ||
313 | // string.Join(",", Array.ConvertAll<object, string>(parms, o => o.ToString())), | ||
314 | // ((MethodInfo)MethodBase.GetCurrentMethod()).ReturnType); | ||
315 | |||
251 | Type[] signature = m_comms.LookupTypeSignature(fname); | 316 | Type[] signature = m_comms.LookupTypeSignature(fname); |
252 | if (signature.Length != parms.Length) | 317 | if (signature.Length != parms.Length) |
253 | MODError(String.Format("wrong number of parameters to function {0}",fname)); | 318 | MODError(String.Format("wrong number of parameters to function {0}",fname)); |
@@ -264,6 +329,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
264 | if (result != null) | 329 | if (result != null) |
265 | return result; | 330 | return result; |
266 | 331 | ||
332 | Type returntype = m_comms.LookupReturnType(fname); | ||
333 | if (returntype == typeof(void)) | ||
334 | return null; | ||
335 | |||
267 | MODError(String.Format("Invocation of {0} failed; null return value",fname)); | 336 | MODError(String.Format("Invocation of {0} failed; null return value",fname)); |
268 | } | 337 | } |
269 | catch (Exception e) | 338 | catch (Exception e) |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs index 7c2f8ed..f4e4f44 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs | |||
@@ -62,6 +62,7 @@ using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list; | |||
62 | using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion; | 62 | using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion; |
63 | using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString; | 63 | using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString; |
64 | using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3; | 64 | using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3; |
65 | using PermissionMask = OpenSim.Framework.PermissionMask; | ||
65 | 66 | ||
66 | namespace OpenSim.Region.ScriptEngine.Shared.Api | 67 | namespace OpenSim.Region.ScriptEngine.Shared.Api |
67 | { | 68 | { |
@@ -143,9 +144,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
143 | 144 | ||
144 | protected IUrlModule m_UrlModule = null; | 145 | protected IUrlModule m_UrlModule = null; |
145 | 146 | ||
146 | public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, TaskInventoryItem item) | 147 | public void Initialize( |
148 | IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item, WaitHandle coopSleepHandle) | ||
147 | { | 149 | { |
148 | m_ScriptEngine = ScriptEngine; | 150 | m_ScriptEngine = scriptEngine; |
149 | m_host = host; | 151 | m_host = host; |
150 | m_item = item; | 152 | m_item = item; |
151 | m_debuggerSafe = m_ScriptEngine.Config.GetBoolean("DebuggerSafe", false); | 153 | m_debuggerSafe = m_ScriptEngine.Config.GetBoolean("DebuggerSafe", false); |
@@ -254,11 +256,23 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
254 | wComm.DeliverMessage(ChatTypeEnum.Shout, ScriptBaseClass.DEBUG_CHANNEL, m_host.Name, m_host.UUID, message); | 256 | wComm.DeliverMessage(ChatTypeEnum.Shout, ScriptBaseClass.DEBUG_CHANNEL, m_host.Name, m_host.UUID, message); |
255 | } | 257 | } |
256 | 258 | ||
259 | // Returns of the function is allowed. Throws a script exception if not allowed. | ||
257 | public void CheckThreatLevel(ThreatLevel level, string function) | 260 | public void CheckThreatLevel(ThreatLevel level, string function) |
258 | { | 261 | { |
259 | if (!m_OSFunctionsEnabled) | 262 | if (!m_OSFunctionsEnabled) |
260 | OSSLError(String.Format("{0} permission denied. All OS functions are disabled.", function)); // throws | 263 | OSSLError(String.Format("{0} permission denied. All OS functions are disabled.", function)); // throws |
261 | 264 | ||
265 | string reasonWhyNot = CheckThreatLevelTest(level, function); | ||
266 | if (!String.IsNullOrEmpty(reasonWhyNot)) | ||
267 | { | ||
268 | OSSLError(reasonWhyNot); | ||
269 | } | ||
270 | } | ||
271 | |||
272 | // Check to see if function is allowed. Returns an empty string if function permitted | ||
273 | // or a string explaining why this function can't be used. | ||
274 | private string CheckThreatLevelTest(ThreatLevel level, string function) | ||
275 | { | ||
262 | if (!m_FunctionPerms.ContainsKey(function)) | 276 | if (!m_FunctionPerms.ContainsKey(function)) |
263 | { | 277 | { |
264 | FunctionPerms perms = new FunctionPerms(); | 278 | FunctionPerms perms = new FunctionPerms(); |
@@ -338,10 +352,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
338 | { | 352 | { |
339 | // Allow / disallow by threat level | 353 | // Allow / disallow by threat level |
340 | if (level > m_MaxThreatLevel) | 354 | if (level > m_MaxThreatLevel) |
341 | OSSLError( | 355 | return |
342 | String.Format( | 356 | String.Format( |
343 | "{0} permission denied. Allowed threat level is {1} but function threat level is {2}.", | 357 | "{0} permission denied. Allowed threat level is {1} but function threat level is {2}.", |
344 | function, m_MaxThreatLevel, level)); | 358 | function, m_MaxThreatLevel, level); |
345 | } | 359 | } |
346 | else | 360 | else |
347 | { | 361 | { |
@@ -351,7 +365,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
351 | if (m_FunctionPerms[function].AllowedOwners.Contains(m_host.OwnerID)) | 365 | if (m_FunctionPerms[function].AllowedOwners.Contains(m_host.OwnerID)) |
352 | { | 366 | { |
353 | // prim owner is in the list of allowed owners | 367 | // prim owner is in the list of allowed owners |
354 | return; | 368 | return String.Empty; |
355 | } | 369 | } |
356 | 370 | ||
357 | UUID ownerID = m_item.OwnerID; | 371 | UUID ownerID = m_item.OwnerID; |
@@ -359,22 +373,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
359 | //OSSL only may be used if object is in the same group as the parcel | 373 | //OSSL only may be used if object is in the same group as the parcel |
360 | if (m_FunctionPerms[function].AllowedOwnerClasses.Contains("PARCEL_GROUP_MEMBER")) | 374 | if (m_FunctionPerms[function].AllowedOwnerClasses.Contains("PARCEL_GROUP_MEMBER")) |
361 | { | 375 | { |
362 | ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); | 376 | ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition); |
363 | 377 | ||
364 | if (land.LandData.GroupID == m_item.GroupID && land.LandData.GroupID != UUID.Zero) | 378 | if (land.LandData.GroupID == m_item.GroupID && land.LandData.GroupID != UUID.Zero) |
365 | { | 379 | { |
366 | return; | 380 | return String.Empty; |
367 | } | 381 | } |
368 | } | 382 | } |
369 | 383 | ||
370 | //Only Parcelowners may use the function | 384 | //Only Parcelowners may use the function |
371 | if (m_FunctionPerms[function].AllowedOwnerClasses.Contains("PARCEL_OWNER")) | 385 | if (m_FunctionPerms[function].AllowedOwnerClasses.Contains("PARCEL_OWNER")) |
372 | { | 386 | { |
373 | ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); | 387 | ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition); |
374 | 388 | ||
375 | if (land.LandData.OwnerID == ownerID) | 389 | if (land.LandData.OwnerID == ownerID) |
376 | { | 390 | { |
377 | return; | 391 | return String.Empty; |
378 | } | 392 | } |
379 | } | 393 | } |
380 | 394 | ||
@@ -384,7 +398,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
384 | //Only Estate Managers may use the function | 398 | //Only Estate Managers may use the function |
385 | if (World.RegionInfo.EstateSettings.IsEstateManagerOrOwner(ownerID) && World.RegionInfo.EstateSettings.EstateOwner != ownerID) | 399 | if (World.RegionInfo.EstateSettings.IsEstateManagerOrOwner(ownerID) && World.RegionInfo.EstateSettings.EstateOwner != ownerID) |
386 | { | 400 | { |
387 | return; | 401 | return String.Empty; |
388 | } | 402 | } |
389 | } | 403 | } |
390 | 404 | ||
@@ -393,25 +407,24 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
393 | { | 407 | { |
394 | if (World.RegionInfo.EstateSettings.EstateOwner == ownerID) | 408 | if (World.RegionInfo.EstateSettings.EstateOwner == ownerID) |
395 | { | 409 | { |
396 | return; | 410 | return String.Empty; |
397 | } | 411 | } |
398 | } | 412 | } |
399 | 413 | ||
400 | if (!m_FunctionPerms[function].AllowedCreators.Contains(m_item.CreatorID)) | 414 | if (!m_FunctionPerms[function].AllowedCreators.Contains(m_item.CreatorID)) |
401 | OSSLError( | 415 | return( |
402 | String.Format("{0} permission denied. Script creator is not in the list of users allowed to execute this function and prim owner also has no permission.", | 416 | String.Format("{0} permission denied. Script creator is not in the list of users allowed to execute this function and prim owner also has no permission.", |
403 | function)); | 417 | function)); |
404 | 418 | ||
405 | if (m_item.CreatorID != ownerID) | 419 | if (m_item.CreatorID != ownerID) |
406 | { | 420 | { |
407 | if ((m_item.CurrentPermissions & (uint)PermissionMask.Modify) != 0) | 421 | if ((m_item.CurrentPermissions & (uint)PermissionMask.Modify) != 0) |
408 | OSSLError( | 422 | return String.Format("{0} permission denied. Script permissions error.", function); |
409 | String.Format("{0} permission denied. Script permissions error.", | ||
410 | function)); | ||
411 | 423 | ||
412 | } | 424 | } |
413 | } | 425 | } |
414 | } | 426 | } |
427 | return String.Empty; | ||
415 | } | 428 | } |
416 | 429 | ||
417 | internal void OSSLDeprecated(string function, string replacement) | 430 | internal void OSSLDeprecated(string function, string replacement) |
@@ -983,7 +996,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
983 | if (animID == UUID.Zero) | 996 | if (animID == UUID.Zero) |
984 | target.Animator.RemoveAnimation(animation); | 997 | target.Animator.RemoveAnimation(animation); |
985 | else | 998 | else |
986 | target.Animator.RemoveAnimation(animID); | 999 | target.Animator.RemoveAnimation(animID, true); |
987 | } | 1000 | } |
988 | } | 1001 | } |
989 | } | 1002 | } |
@@ -1214,12 +1227,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1214 | sunHour += 24.0; | 1227 | sunHour += 24.0; |
1215 | 1228 | ||
1216 | World.RegionInfo.RegionSettings.UseEstateSun = useEstateSun; | 1229 | World.RegionInfo.RegionSettings.UseEstateSun = useEstateSun; |
1217 | World.RegionInfo.RegionSettings.SunPosition = sunHour + 6; // LL Region Sun Hour is 6 to 30 | 1230 | World.RegionInfo.RegionSettings.SunPosition = sunHour + 6; // LL Region Sun Hour is 6 to 30 |
1218 | World.RegionInfo.RegionSettings.FixedSun = sunFixed; | 1231 | World.RegionInfo.RegionSettings.FixedSun = sunFixed; |
1219 | World.RegionInfo.RegionSettings.Save(); | 1232 | World.RegionInfo.RegionSettings.Save(); |
1220 | 1233 | ||
1221 | World.EventManager.TriggerEstateToolsSunUpdate( | 1234 | World.EventManager.TriggerEstateToolsSunUpdate(World.RegionInfo.RegionHandle); |
1222 | World.RegionInfo.RegionHandle, sunFixed, useEstateSun, (float)sunHour); | ||
1223 | } | 1235 | } |
1224 | 1236 | ||
1225 | /// <summary> | 1237 | /// <summary> |
@@ -1244,8 +1256,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1244 | World.RegionInfo.EstateSettings.FixedSun = sunFixed; | 1256 | World.RegionInfo.EstateSettings.FixedSun = sunFixed; |
1245 | World.RegionInfo.EstateSettings.Save(); | 1257 | World.RegionInfo.EstateSettings.Save(); |
1246 | 1258 | ||
1247 | World.EventManager.TriggerEstateToolsSunUpdate( | 1259 | World.EventManager.TriggerEstateToolsSunUpdate(World.RegionInfo.RegionHandle); |
1248 | World.RegionInfo.RegionHandle, sunFixed, World.RegionInfo.RegionSettings.UseEstateSun, (float)sunHour); | ||
1249 | } | 1260 | } |
1250 | 1261 | ||
1251 | /// <summary> | 1262 | /// <summary> |
@@ -1501,8 +1512,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1501 | 1512 | ||
1502 | m_host.AddScriptLPS(1); | 1513 | m_host.AddScriptLPS(1); |
1503 | 1514 | ||
1504 | ILandObject land | 1515 | ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition); |
1505 | = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); | ||
1506 | 1516 | ||
1507 | if (land.LandData.OwnerID != m_host.OwnerID) | 1517 | if (land.LandData.OwnerID != m_host.OwnerID) |
1508 | return; | 1518 | return; |
@@ -1518,8 +1528,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1518 | 1528 | ||
1519 | m_host.AddScriptLPS(1); | 1529 | m_host.AddScriptLPS(1); |
1520 | 1530 | ||
1521 | ILandObject land | 1531 | ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition); |
1522 | = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); | ||
1523 | 1532 | ||
1524 | if (land.LandData.OwnerID != m_host.OwnerID) | 1533 | if (land.LandData.OwnerID != m_host.OwnerID) |
1525 | { | 1534 | { |
@@ -1569,6 +1578,32 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1569 | } | 1578 | } |
1570 | } | 1579 | } |
1571 | 1580 | ||
1581 | public string osGetPhysicsEngineType() | ||
1582 | { | ||
1583 | // High because it can be used to target attacks to known weaknesses | ||
1584 | // This would allow a new class of griefer scripts that don't even | ||
1585 | // require their user to know what they are doing (see script | ||
1586 | // kiddie) | ||
1587 | // Because it would be nice if scripts didn't blow up if the information | ||
1588 | // about the physics engine, this function returns an empty string if | ||
1589 | // the user does not have permission to see it. This as opposed to | ||
1590 | // throwing an exception. | ||
1591 | m_host.AddScriptLPS(1); | ||
1592 | string ret = String.Empty; | ||
1593 | if (String.IsNullOrEmpty(CheckThreatLevelTest(ThreatLevel.High, "osGetPhysicsEngineType"))) | ||
1594 | { | ||
1595 | if (m_ScriptEngine.World.PhysicsScene != null) | ||
1596 | { | ||
1597 | ret = m_ScriptEngine.World.PhysicsScene.EngineType; | ||
1598 | // An old physics engine might have an uninitialized engine type | ||
1599 | if (ret == null) | ||
1600 | ret = "unknown"; | ||
1601 | } | ||
1602 | } | ||
1603 | |||
1604 | return ret; | ||
1605 | } | ||
1606 | |||
1572 | public string osGetSimulatorVersion() | 1607 | public string osGetSimulatorVersion() |
1573 | { | 1608 | { |
1574 | // High because it can be used to target attacks to known weaknesses | 1609 | // High because it can be used to target attacks to known weaknesses |
@@ -1619,7 +1654,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1619 | } | 1654 | } |
1620 | } | 1655 | } |
1621 | 1656 | ||
1622 | public Object osParseJSONNew(string JSON) | 1657 | private Object osParseJSONNew(string JSON) |
1623 | { | 1658 | { |
1624 | CheckThreatLevel(ThreatLevel.None, "osParseJSONNew"); | 1659 | CheckThreatLevel(ThreatLevel.None, "osParseJSONNew"); |
1625 | 1660 | ||
@@ -1762,8 +1797,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1762 | taskItem.InvType = (int)InventoryType.Notecard; | 1797 | taskItem.InvType = (int)InventoryType.Notecard; |
1763 | taskItem.OwnerID = m_host.OwnerID; | 1798 | taskItem.OwnerID = m_host.OwnerID; |
1764 | taskItem.CreatorID = m_host.OwnerID; | 1799 | taskItem.CreatorID = m_host.OwnerID; |
1765 | taskItem.BasePermissions = (uint)PermissionMask.All; | 1800 | taskItem.BasePermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export; |
1766 | taskItem.CurrentPermissions = (uint)PermissionMask.All; | 1801 | taskItem.CurrentPermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export; |
1767 | taskItem.EveryonePermissions = 0; | 1802 | taskItem.EveryonePermissions = 0; |
1768 | taskItem.NextPermissions = (uint)PermissionMask.All; | 1803 | taskItem.NextPermissions = (uint)PermissionMask.All; |
1769 | taskItem.GroupID = m_host.GroupID; | 1804 | taskItem.GroupID = m_host.GroupID; |
@@ -2136,9 +2171,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
2136 | CheckThreatLevel(ThreatLevel.Moderate, "osGetGridHomeURI"); | 2171 | CheckThreatLevel(ThreatLevel.Moderate, "osGetGridHomeURI"); |
2137 | m_host.AddScriptLPS(1); | 2172 | m_host.AddScriptLPS(1); |
2138 | 2173 | ||
2139 | string HomeURI = String.Empty; | ||
2140 | IConfigSource config = m_ScriptEngine.ConfigSource; | 2174 | IConfigSource config = m_ScriptEngine.ConfigSource; |
2175 | string HomeURI = Util.GetConfigVarFromSections<string>(config, "HomeURI", | ||
2176 | new string[] { "Startup", "Hypergrid" }, String.Empty); | ||
2177 | |||
2178 | if (!string.IsNullOrEmpty(HomeURI)) | ||
2179 | return HomeURI; | ||
2141 | 2180 | ||
2181 | // Legacy. Remove soon! | ||
2142 | if (config.Configs["LoginService"] != null) | 2182 | if (config.Configs["LoginService"] != null) |
2143 | HomeURI = config.Configs["LoginService"].GetString("SRV_HomeURI", HomeURI); | 2183 | HomeURI = config.Configs["LoginService"].GetString("SRV_HomeURI", HomeURI); |
2144 | 2184 | ||
@@ -2153,9 +2193,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
2153 | CheckThreatLevel(ThreatLevel.Moderate, "osGetGridGatekeeperURI"); | 2193 | CheckThreatLevel(ThreatLevel.Moderate, "osGetGridGatekeeperURI"); |
2154 | m_host.AddScriptLPS(1); | 2194 | m_host.AddScriptLPS(1); |
2155 | 2195 | ||
2156 | string gatekeeperURI = String.Empty; | ||
2157 | IConfigSource config = m_ScriptEngine.ConfigSource; | 2196 | IConfigSource config = m_ScriptEngine.ConfigSource; |
2197 | string gatekeeperURI = Util.GetConfigVarFromSections<string>(config, "GatekeeperURI", | ||
2198 | new string[] { "Startup", "Hypergrid" }, String.Empty); | ||
2199 | |||
2200 | if (!string.IsNullOrEmpty(gatekeeperURI)) | ||
2201 | return gatekeeperURI; | ||
2158 | 2202 | ||
2203 | // Legacy. Remove soon! | ||
2159 | if (config.Configs["GridService"] != null) | 2204 | if (config.Configs["GridService"] != null) |
2160 | gatekeeperURI = config.Configs["GridService"].GetString("Gatekeeper", gatekeeperURI); | 2205 | gatekeeperURI = config.Configs["GridService"].GetString("Gatekeeper", gatekeeperURI); |
2161 | 2206 | ||
@@ -2532,13 +2577,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
2532 | ScenePresence sp = World.GetScenePresence(npcId); | 2577 | ScenePresence sp = World.GetScenePresence(npcId); |
2533 | 2578 | ||
2534 | if (sp != null) | 2579 | if (sp != null) |
2535 | { | 2580 | return new LSL_Vector(sp.AbsolutePosition); |
2536 | Vector3 pos = sp.AbsolutePosition; | ||
2537 | return new LSL_Vector(pos.X, pos.Y, pos.Z); | ||
2538 | } | ||
2539 | } | 2581 | } |
2540 | 2582 | ||
2541 | return new LSL_Vector(0, 0, 0); | 2583 | return Vector3.Zero; |
2542 | } | 2584 | } |
2543 | 2585 | ||
2544 | public void osNpcMoveTo(LSL_Key npc, LSL_Vector pos) | 2586 | public void osNpcMoveTo(LSL_Key npc, LSL_Vector pos) |
@@ -2595,21 +2637,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
2595 | { | 2637 | { |
2596 | UUID npcId; | 2638 | UUID npcId; |
2597 | if (!UUID.TryParse(npc.m_string, out npcId)) | 2639 | if (!UUID.TryParse(npc.m_string, out npcId)) |
2598 | return new LSL_Rotation(Quaternion.Identity.X, Quaternion.Identity.Y, Quaternion.Identity.Z, Quaternion.Identity.W); | 2640 | return new LSL_Rotation(Quaternion.Identity); |
2599 | 2641 | ||
2600 | if (!npcModule.CheckPermissions(npcId, m_host.OwnerID)) | 2642 | if (!npcModule.CheckPermissions(npcId, m_host.OwnerID)) |
2601 | return new LSL_Rotation(Quaternion.Identity.X, Quaternion.Identity.Y, Quaternion.Identity.Z, Quaternion.Identity.W); | 2643 | return new LSL_Rotation(Quaternion.Identity); |
2602 | 2644 | ||
2603 | ScenePresence sp = World.GetScenePresence(npcId); | 2645 | ScenePresence sp = World.GetScenePresence(npcId); |
2604 | 2646 | ||
2605 | if (sp != null) | 2647 | if (sp != null) |
2606 | { | 2648 | return new LSL_Rotation(sp.GetWorldRotation()); |
2607 | Quaternion rot = sp.Rotation; | ||
2608 | return new LSL_Rotation(rot.X, rot.Y, rot.Z, rot.W); | ||
2609 | } | ||
2610 | } | 2649 | } |
2611 | 2650 | ||
2612 | return new LSL_Rotation(Quaternion.Identity.X, Quaternion.Identity.Y, Quaternion.Identity.Z, Quaternion.Identity.W); | 2651 | return Quaternion.Identity; |
2613 | } | 2652 | } |
2614 | 2653 | ||
2615 | public void osNpcSetRot(LSL_Key npc, LSL_Rotation rotation) | 2654 | public void osNpcSetRot(LSL_Key npc, LSL_Rotation rotation) |
@@ -3055,20 +3094,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
3055 | 3094 | ||
3056 | UUID avatarId = new UUID(avatar); | 3095 | UUID avatarId = new UUID(avatar); |
3057 | ScenePresence presence = World.GetScenePresence(avatarId); | 3096 | ScenePresence presence = World.GetScenePresence(avatarId); |
3058 | Vector3 pos = m_host.GetWorldPosition(); | 3097 | |
3059 | bool result = World.ScriptDanger(m_host.LocalId, new Vector3((float)pos.X, (float)pos.Y, (float)pos.Z)); | 3098 | if (presence != null && World.ScriptDanger(m_host.LocalId, m_host.GetWorldPosition())) |
3060 | if (result) | ||
3061 | { | 3099 | { |
3062 | if (presence != null) | 3100 | float health = presence.Health; |
3063 | { | 3101 | health += (float)healing; |
3064 | float health = presence.Health; | 3102 | |
3065 | health += (float)healing; | 3103 | if (health >= 100) |
3066 | if (health >= 100) | 3104 | health = 100; |
3067 | { | 3105 | |
3068 | health = 100; | 3106 | presence.setHealthWithUpdate(health); |
3069 | } | ||
3070 | presence.setHealthWithUpdate(health); | ||
3071 | } | ||
3072 | } | 3107 | } |
3073 | } | 3108 | } |
3074 | 3109 | ||
@@ -3145,8 +3180,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
3145 | if (avatar != null && avatar.UUID != m_host.OwnerID) | 3180 | if (avatar != null && avatar.UUID != m_host.OwnerID) |
3146 | { | 3181 | { |
3147 | result.Add(new LSL_String(avatar.UUID.ToString())); | 3182 | result.Add(new LSL_String(avatar.UUID.ToString())); |
3148 | OpenMetaverse.Vector3 ap = avatar.AbsolutePosition; | 3183 | result.Add(new LSL_Vector(avatar.AbsolutePosition)); |
3149 | result.Add(new LSL_Vector(ap.X, ap.Y, ap.Z)); | ||
3150 | result.Add(new LSL_String(avatar.Name)); | 3184 | result.Add(new LSL_String(avatar.Name)); |
3151 | } | 3185 | } |
3152 | }); | 3186 | }); |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs index 4dd795d..884f07c 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs | |||
@@ -42,6 +42,29 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins | |||
42 | { | 42 | { |
43 | // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 43 | // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
44 | 44 | ||
45 | /// <summary> | ||
46 | /// Used by one-off and repeated sensors | ||
47 | /// </summary> | ||
48 | public class SensorInfo | ||
49 | { | ||
50 | public uint localID; | ||
51 | public UUID itemID; | ||
52 | public double interval; | ||
53 | public DateTime next; | ||
54 | |||
55 | public string name; | ||
56 | public UUID keyID; | ||
57 | public int type; | ||
58 | public double range; | ||
59 | public double arc; | ||
60 | public SceneObjectPart host; | ||
61 | |||
62 | public SensorInfo Clone() | ||
63 | { | ||
64 | return (SensorInfo)this.MemberwiseClone(); | ||
65 | } | ||
66 | } | ||
67 | |||
45 | public AsyncCommandManager m_CmdManager; | 68 | public AsyncCommandManager m_CmdManager; |
46 | 69 | ||
47 | /// <summary> | 70 | /// <summary> |
@@ -78,24 +101,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins | |||
78 | private int maximumToReturn = 16; | 101 | private int maximumToReturn = 16; |
79 | 102 | ||
80 | // | 103 | // |
81 | // SenseRepeater and Sensors | ||
82 | // | ||
83 | private class SenseRepeatClass | ||
84 | { | ||
85 | public uint localID; | ||
86 | public UUID itemID; | ||
87 | public double interval; | ||
88 | public DateTime next; | ||
89 | |||
90 | public string name; | ||
91 | public UUID keyID; | ||
92 | public int type; | ||
93 | public double range; | ||
94 | public double arc; | ||
95 | public SceneObjectPart host; | ||
96 | } | ||
97 | |||
98 | // | ||
99 | // Sensed entity | 104 | // Sensed entity |
100 | // | 105 | // |
101 | private class SensedEntity : IComparable | 106 | private class SensedEntity : IComparable |
@@ -127,7 +132,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins | |||
127 | /// | 132 | /// |
128 | /// Always lock SenseRepeatListLock when updating this list. | 133 | /// Always lock SenseRepeatListLock when updating this list. |
129 | /// </remarks> | 134 | /// </remarks> |
130 | private List<SenseRepeatClass> SenseRepeaters = new List<SenseRepeatClass>(); | 135 | private List<SensorInfo> SenseRepeaters = new List<SensorInfo>(); |
131 | private object SenseRepeatListLock = new object(); | 136 | private object SenseRepeatListLock = new object(); |
132 | 137 | ||
133 | public void SetSenseRepeatEvent(uint m_localID, UUID m_itemID, | 138 | public void SetSenseRepeatEvent(uint m_localID, UUID m_itemID, |
@@ -141,7 +146,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins | |||
141 | return; | 146 | return; |
142 | 147 | ||
143 | // Add to timer | 148 | // Add to timer |
144 | SenseRepeatClass ts = new SenseRepeatClass(); | 149 | SensorInfo ts = new SensorInfo(); |
145 | ts.localID = m_localID; | 150 | ts.localID = m_localID; |
146 | ts.itemID = m_itemID; | 151 | ts.itemID = m_itemID; |
147 | ts.interval = sec; | 152 | ts.interval = sec; |
@@ -160,11 +165,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins | |||
160 | AddSenseRepeater(ts); | 165 | AddSenseRepeater(ts); |
161 | } | 166 | } |
162 | 167 | ||
163 | private void AddSenseRepeater(SenseRepeatClass senseRepeater) | 168 | private void AddSenseRepeater(SensorInfo senseRepeater) |
164 | { | 169 | { |
165 | lock (SenseRepeatListLock) | 170 | lock (SenseRepeatListLock) |
166 | { | 171 | { |
167 | List<SenseRepeatClass> newSenseRepeaters = new List<SenseRepeatClass>(SenseRepeaters); | 172 | List<SensorInfo> newSenseRepeaters = new List<SensorInfo>(SenseRepeaters); |
168 | newSenseRepeaters.Add(senseRepeater); | 173 | newSenseRepeaters.Add(senseRepeater); |
169 | SenseRepeaters = newSenseRepeaters; | 174 | SenseRepeaters = newSenseRepeaters; |
170 | } | 175 | } |
@@ -175,8 +180,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins | |||
175 | // Remove from timer | 180 | // Remove from timer |
176 | lock (SenseRepeatListLock) | 181 | lock (SenseRepeatListLock) |
177 | { | 182 | { |
178 | List<SenseRepeatClass> newSenseRepeaters = new List<SenseRepeatClass>(); | 183 | List<SensorInfo> newSenseRepeaters = new List<SensorInfo>(); |
179 | foreach (SenseRepeatClass ts in SenseRepeaters) | 184 | foreach (SensorInfo ts in SenseRepeaters) |
180 | { | 185 | { |
181 | if (ts.localID != m_localID || ts.itemID != m_itemID) | 186 | if (ts.localID != m_localID || ts.itemID != m_itemID) |
182 | { | 187 | { |
@@ -191,7 +196,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins | |||
191 | public void CheckSenseRepeaterEvents() | 196 | public void CheckSenseRepeaterEvents() |
192 | { | 197 | { |
193 | // Go through all timers | 198 | // Go through all timers |
194 | foreach (SenseRepeatClass ts in SenseRepeaters) | 199 | foreach (SensorInfo ts in SenseRepeaters) |
195 | { | 200 | { |
196 | // Time has passed? | 201 | // Time has passed? |
197 | if (ts.next.ToUniversalTime() < DateTime.Now.ToUniversalTime()) | 202 | if (ts.next.ToUniversalTime() < DateTime.Now.ToUniversalTime()) |
@@ -208,7 +213,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins | |||
208 | double range, double arc, SceneObjectPart host) | 213 | double range, double arc, SceneObjectPart host) |
209 | { | 214 | { |
210 | // Add to timer | 215 | // Add to timer |
211 | SenseRepeatClass ts = new SenseRepeatClass(); | 216 | SensorInfo ts = new SensorInfo(); |
212 | ts.localID = m_localID; | 217 | ts.localID = m_localID; |
213 | ts.itemID = m_itemID; | 218 | ts.itemID = m_itemID; |
214 | ts.interval = 0; | 219 | ts.interval = 0; |
@@ -224,7 +229,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins | |||
224 | SensorSweep(ts); | 229 | SensorSweep(ts); |
225 | } | 230 | } |
226 | 231 | ||
227 | private void SensorSweep(SenseRepeatClass ts) | 232 | private void SensorSweep(SensorInfo ts) |
228 | { | 233 | { |
229 | if (ts.host == null) | 234 | if (ts.host == null) |
230 | { | 235 | { |
@@ -300,7 +305,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins | |||
300 | } | 305 | } |
301 | } | 306 | } |
302 | 307 | ||
303 | private List<SensedEntity> doObjectSensor(SenseRepeatClass ts) | 308 | private List<SensedEntity> doObjectSensor(SensorInfo ts) |
304 | { | 309 | { |
305 | List<EntityBase> Entities; | 310 | List<EntityBase> Entities; |
306 | List<SensedEntity> sensedEntities = new List<SensedEntity>(); | 311 | List<SensedEntity> sensedEntities = new List<SensedEntity>(); |
@@ -451,7 +456,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins | |||
451 | return sensedEntities; | 456 | return sensedEntities; |
452 | } | 457 | } |
453 | 458 | ||
454 | private List<SensedEntity> doAgentSensor(SenseRepeatClass ts) | 459 | private List<SensedEntity> doAgentSensor(SensorInfo ts) |
455 | { | 460 | { |
456 | List<SensedEntity> sensedEntities = new List<SensedEntity>(); | 461 | List<SensedEntity> sensedEntities = new List<SensedEntity>(); |
457 | 462 | ||
@@ -630,7 +635,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins | |||
630 | { | 635 | { |
631 | List<Object> data = new List<Object>(); | 636 | List<Object> data = new List<Object>(); |
632 | 637 | ||
633 | foreach (SenseRepeatClass ts in SenseRepeaters) | 638 | foreach (SensorInfo ts in SenseRepeaters) |
634 | { | 639 | { |
635 | if (ts.itemID == itemID) | 640 | if (ts.itemID == itemID) |
636 | { | 641 | { |
@@ -660,7 +665,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins | |||
660 | 665 | ||
661 | while (idx < data.Length) | 666 | while (idx < data.Length) |
662 | { | 667 | { |
663 | SenseRepeatClass ts = new SenseRepeatClass(); | 668 | SensorInfo ts = new SensorInfo(); |
664 | 669 | ||
665 | ts.localID = localID; | 670 | ts.localID = localID; |
666 | ts.itemID = itemID; | 671 | ts.itemID = itemID; |
@@ -681,5 +686,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins | |||
681 | idx += 6; | 686 | idx += 6; |
682 | } | 687 | } |
683 | } | 688 | } |
689 | |||
690 | public List<SensorInfo> GetSensorInfo() | ||
691 | { | ||
692 | List<SensorInfo> retList = new List<SensorInfo>(); | ||
693 | |||
694 | lock (SenseRepeatListLock) | ||
695 | { | ||
696 | foreach (SensorInfo i in SenseRepeaters) | ||
697 | retList.Add(i.Clone()); | ||
698 | } | ||
699 | |||
700 | return retList; | ||
701 | } | ||
684 | } | 702 | } |
685 | } | 703 | } |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/Timer.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/Timer.cs index 9ee6946..68aacd2 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/Timer.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/Timer.cs | |||
@@ -35,6 +35,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins | |||
35 | { | 35 | { |
36 | public class Timer | 36 | public class Timer |
37 | { | 37 | { |
38 | public class TimerInfo | ||
39 | { | ||
40 | public uint localID; | ||
41 | public UUID itemID; | ||
42 | //public double interval; | ||
43 | public long interval; | ||
44 | //public DateTime next; | ||
45 | public long next; | ||
46 | |||
47 | public TimerInfo Clone() | ||
48 | { | ||
49 | return (TimerInfo)this.MemberwiseClone(); | ||
50 | } | ||
51 | } | ||
52 | |||
38 | public AsyncCommandManager m_CmdManager; | 53 | public AsyncCommandManager m_CmdManager; |
39 | 54 | ||
40 | public int TimersCount | 55 | public int TimersCount |
@@ -59,17 +74,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins | |||
59 | return localID.ToString() + itemID.ToString(); | 74 | return localID.ToString() + itemID.ToString(); |
60 | } | 75 | } |
61 | 76 | ||
62 | private class TimerClass | 77 | private Dictionary<string,TimerInfo> Timers = new Dictionary<string,TimerInfo>(); |
63 | { | ||
64 | public uint localID; | ||
65 | public UUID itemID; | ||
66 | //public double interval; | ||
67 | public long interval; | ||
68 | //public DateTime next; | ||
69 | public long next; | ||
70 | } | ||
71 | |||
72 | private Dictionary<string,TimerClass> Timers = new Dictionary<string,TimerClass>(); | ||
73 | private object TimerListLock = new object(); | 78 | private object TimerListLock = new object(); |
74 | 79 | ||
75 | public void SetTimerEvent(uint m_localID, UUID m_itemID, double sec) | 80 | public void SetTimerEvent(uint m_localID, UUID m_itemID, double sec) |
@@ -81,7 +86,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins | |||
81 | } | 86 | } |
82 | 87 | ||
83 | // Add to timer | 88 | // Add to timer |
84 | TimerClass ts = new TimerClass(); | 89 | TimerInfo ts = new TimerInfo(); |
85 | ts.localID = m_localID; | 90 | ts.localID = m_localID; |
86 | ts.itemID = m_itemID; | 91 | ts.itemID = m_itemID; |
87 | ts.interval = Convert.ToInt64(sec * 10000000); // How many 100 nanoseconds (ticks) should we wait | 92 | ts.interval = Convert.ToInt64(sec * 10000000); // How many 100 nanoseconds (ticks) should we wait |
@@ -118,14 +123,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins | |||
118 | if (Timers.Count == 0) | 123 | if (Timers.Count == 0) |
119 | return; | 124 | return; |
120 | 125 | ||
121 | Dictionary<string, TimerClass>.ValueCollection tvals; | 126 | Dictionary<string, TimerInfo>.ValueCollection tvals; |
122 | lock (TimerListLock) | 127 | lock (TimerListLock) |
123 | { | 128 | { |
124 | // Go through all timers | 129 | // Go through all timers |
125 | tvals = Timers.Values; | 130 | tvals = Timers.Values; |
126 | } | 131 | } |
127 | 132 | ||
128 | foreach (TimerClass ts in tvals) | 133 | foreach (TimerInfo ts in tvals) |
129 | { | 134 | { |
130 | // Time has passed? | 135 | // Time has passed? |
131 | if (ts.next < DateTime.Now.Ticks) | 136 | if (ts.next < DateTime.Now.Ticks) |
@@ -149,8 +154,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins | |||
149 | 154 | ||
150 | lock (TimerListLock) | 155 | lock (TimerListLock) |
151 | { | 156 | { |
152 | Dictionary<string, TimerClass>.ValueCollection tvals = Timers.Values; | 157 | Dictionary<string, TimerInfo>.ValueCollection tvals = Timers.Values; |
153 | foreach (TimerClass ts in tvals) | 158 | foreach (TimerInfo ts in tvals) |
154 | { | 159 | { |
155 | if (ts.itemID == itemID) | 160 | if (ts.itemID == itemID) |
156 | { | 161 | { |
@@ -169,7 +174,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins | |||
169 | 174 | ||
170 | while (idx < data.Length) | 175 | while (idx < data.Length) |
171 | { | 176 | { |
172 | TimerClass ts = new TimerClass(); | 177 | TimerInfo ts = new TimerInfo(); |
173 | 178 | ||
174 | ts.localID = localID; | 179 | ts.localID = localID; |
175 | ts.itemID = itemID; | 180 | ts.itemID = itemID; |
@@ -183,5 +188,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins | |||
183 | } | 188 | } |
184 | } | 189 | } |
185 | } | 190 | } |
191 | |||
192 | public List<TimerInfo> GetTimersInfo() | ||
193 | { | ||
194 | List<TimerInfo> retList = new List<TimerInfo>(); | ||
195 | |||
196 | lock (TimerListLock) | ||
197 | { | ||
198 | foreach (TimerInfo i in Timers.Values) | ||
199 | retList.Add(i.Clone()); | ||
200 | } | ||
201 | |||
202 | return retList; | ||
203 | } | ||
186 | } | 204 | } |
187 | } | 205 | } |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Properties/AssemblyInfo.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Properties/AssemblyInfo.cs index d173db0..6d218a6 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Properties/AssemblyInfo.cs | |||
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices; | |||
29 | // Build Number | 29 | // Build Number |
30 | // Revision | 30 | // Revision |
31 | // | 31 | // |
32 | [assembly: AssemblyVersion("0.7.5.*")] | 32 | [assembly: AssemblyVersion("0.7.6.*")] |
33 | [assembly: AssemblyFileVersion("1.0.0.0")] | 33 | |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs index c447d1f..a652cb8 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs | |||
@@ -259,7 +259,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces | |||
259 | 259 | ||
260 | string osGetScriptEngineName(); | 260 | string osGetScriptEngineName(); |
261 | string osGetSimulatorVersion(); | 261 | string osGetSimulatorVersion(); |
262 | Object osParseJSONNew(string JSON); | 262 | string osGetPhysicsEngineType(); |
263 | Hashtable osParseJSON(string JSON); | 263 | Hashtable osParseJSON(string JSON); |
264 | 264 | ||
265 | void osMessageObject(key objectUUID,string message); | 265 | void osMessageObject(key objectUUID,string message); |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs index 0dd5a57..2f8154d 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs | |||
@@ -356,6 +356,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase | |||
356 | public const int HTTP_MIMETYPE = 1; | 356 | public const int HTTP_MIMETYPE = 1; |
357 | public const int HTTP_BODY_MAXLENGTH = 2; | 357 | public const int HTTP_BODY_MAXLENGTH = 2; |
358 | public const int HTTP_VERIFY_CERT = 3; | 358 | public const int HTTP_VERIFY_CERT = 3; |
359 | public const int HTTP_VERBOSE_THROTTLE = 4; | ||
360 | public const int HTTP_CUSTOM_HEADER = 5; | ||
361 | public const int HTTP_PRAGMA_NO_CACHE = 6; | ||
359 | 362 | ||
360 | public const int PRIM_MATERIAL = 2; | 363 | public const int PRIM_MATERIAL = 2; |
361 | public const int PRIM_PHYSICS = 3; | 364 | public const int PRIM_PHYSICS = 3; |
@@ -557,6 +560,23 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase | |||
557 | public const int OBJECT_SERVER_COST = 14; | 560 | public const int OBJECT_SERVER_COST = 14; |
558 | public const int OBJECT_STREAMING_COST = 15; | 561 | public const int OBJECT_STREAMING_COST = 15; |
559 | public const int OBJECT_PHYSICS_COST = 16; | 562 | public const int OBJECT_PHYSICS_COST = 16; |
563 | public const int OBJECT_CHARACTER_TIME = 17; | ||
564 | public const int OBJECT_ROOT = 18; | ||
565 | public const int OBJECT_ATTACHED_POINT = 19; | ||
566 | public const int OBJECT_PATHFINDING_TYPE = 20; | ||
567 | public const int OBJECT_PHYSICS = 21; | ||
568 | public const int OBJECT_PHANTOM = 22; | ||
569 | public const int OBJECT_TEMP_ON_REZ = 23; | ||
570 | |||
571 | // Pathfinding types | ||
572 | public const int OPT_OTHER = -1; | ||
573 | public const int OPT_LEGACY_LINKSET = 0; | ||
574 | public const int OPT_AVATAR = 1; | ||
575 | public const int OPT_CHARACTER = 2; | ||
576 | public const int OPT_WALKABLE = 3; | ||
577 | public const int OPT_STATIC_OBSTACLE = 4; | ||
578 | public const int OPT_MATERIAL_VOLUME = 5; | ||
579 | public const int OPT_EXCLUSION_VOLUME = 6; | ||
560 | 580 | ||
561 | // for llGetAgentList | 581 | // for llGetAgentList |
562 | public const int AGENT_LIST_PARCEL = 1; | 582 | public const int AGENT_LIST_PARCEL = 1; |
@@ -619,7 +639,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase | |||
619 | public const int TOUCH_INVALID_FACE = -1; | 639 | public const int TOUCH_INVALID_FACE = -1; |
620 | public static readonly vector TOUCH_INVALID_TEXCOORD = new vector(-1.0, -1.0, 0.0); | 640 | public static readonly vector TOUCH_INVALID_TEXCOORD = new vector(-1.0, -1.0, 0.0); |
621 | public static readonly vector TOUCH_INVALID_VECTOR = ZERO_VECTOR; | 641 | public static readonly vector TOUCH_INVALID_VECTOR = ZERO_VECTOR; |
622 | 642 | ||
623 | // constants for llGetPrimMediaParams/llSetPrimMediaParams | 643 | // constants for llGetPrimMediaParams/llSetPrimMediaParams |
624 | public const int PRIM_MEDIA_ALT_IMAGE_ENABLE = 0; | 644 | public const int PRIM_MEDIA_ALT_IMAGE_ENABLE = 0; |
625 | public const int PRIM_MEDIA_CONTROLS = 1; | 645 | public const int PRIM_MEDIA_CONTROLS = 1; |
@@ -636,10 +656,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase | |||
636 | public const int PRIM_MEDIA_WHITELIST = 12; | 656 | public const int PRIM_MEDIA_WHITELIST = 12; |
637 | public const int PRIM_MEDIA_PERMS_INTERACT = 13; | 657 | public const int PRIM_MEDIA_PERMS_INTERACT = 13; |
638 | public const int PRIM_MEDIA_PERMS_CONTROL = 14; | 658 | public const int PRIM_MEDIA_PERMS_CONTROL = 14; |
639 | 659 | ||
640 | public const int PRIM_MEDIA_CONTROLS_STANDARD = 0; | 660 | public const int PRIM_MEDIA_CONTROLS_STANDARD = 0; |
641 | public const int PRIM_MEDIA_CONTROLS_MINI = 1; | 661 | public const int PRIM_MEDIA_CONTROLS_MINI = 1; |
642 | 662 | ||
643 | public const int PRIM_MEDIA_PERM_NONE = 0; | 663 | public const int PRIM_MEDIA_PERM_NONE = 0; |
644 | public const int PRIM_MEDIA_PERM_OWNER = 1; | 664 | public const int PRIM_MEDIA_PERM_OWNER = 1; |
645 | public const int PRIM_MEDIA_PERM_GROUP = 2; | 665 | public const int PRIM_MEDIA_PERM_GROUP = 2; |
@@ -672,7 +692,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase | |||
672 | public const string TEXTURE_PLYWOOD = "89556747-24cb-43ed-920b-47caed15465f"; | 692 | public const string TEXTURE_PLYWOOD = "89556747-24cb-43ed-920b-47caed15465f"; |
673 | public const string TEXTURE_TRANSPARENT = "8dcd4a48-2d37-4909-9f78-f7a9eb4ef903"; | 693 | public const string TEXTURE_TRANSPARENT = "8dcd4a48-2d37-4909-9f78-f7a9eb4ef903"; |
674 | public const string TEXTURE_MEDIA = "8b5fec65-8d8d-9dc5-cda8-8fdf2716e361"; | 694 | public const string TEXTURE_MEDIA = "8b5fec65-8d8d-9dc5-cda8-8fdf2716e361"; |
675 | 695 | ||
676 | // Constants for osGetRegionStats | 696 | // Constants for osGetRegionStats |
677 | public const int STATS_TIME_DILATION = 0; | 697 | public const int STATS_TIME_DILATION = 0; |
678 | public const int STATS_SIM_FPS = 1; | 698 | public const int STATS_SIM_FPS = 1; |
@@ -725,7 +745,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase | |||
725 | public static readonly LSLInteger RC_GET_ROOT_KEY = 2; | 745 | public static readonly LSLInteger RC_GET_ROOT_KEY = 2; |
726 | public static readonly LSLInteger RC_GET_LINK_NUM = 4; | 746 | public static readonly LSLInteger RC_GET_LINK_NUM = 4; |
727 | 747 | ||
728 | public static readonly LSLInteger RCERR_UNKNOWN = -1; | 748 | public static readonly LSLInteger RCERR_UNKNOWN = -1; |
729 | public static readonly LSLInteger RCERR_SIM_PERF_LOW = -2; | 749 | public static readonly LSLInteger RCERR_SIM_PERF_LOW = -2; |
730 | public static readonly LSLInteger RCERR_CAST_TIME_EXCEEDED = -3; | 750 | public static readonly LSLInteger RCERR_CAST_TIME_EXCEEDED = -3; |
731 | 751 | ||
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs index afa9ae0..b63773b 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs | |||
@@ -420,6 +420,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase | |||
420 | return m_OSSL_Functions.osGetScriptEngineName(); | 420 | return m_OSSL_Functions.osGetScriptEngineName(); |
421 | } | 421 | } |
422 | 422 | ||
423 | public string osGetPhysicsEngineType() | ||
424 | { | ||
425 | return m_OSSL_Functions.osGetPhysicsEngineType(); | ||
426 | } | ||
427 | |||
423 | public string osGetSimulatorVersion() | 428 | public string osGetSimulatorVersion() |
424 | { | 429 | { |
425 | return m_OSSL_Functions.osGetSimulatorVersion(); | 430 | return m_OSSL_Functions.osGetSimulatorVersion(); |
@@ -430,11 +435,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase | |||
430 | return m_OSSL_Functions.osParseJSON(JSON); | 435 | return m_OSSL_Functions.osParseJSON(JSON); |
431 | } | 436 | } |
432 | 437 | ||
433 | public Object osParseJSONNew(string JSON) | ||
434 | { | ||
435 | return m_OSSL_Functions.osParseJSONNew(JSON); | ||
436 | } | ||
437 | |||
438 | public void osMessageObject(key objectUUID,string message) | 438 | public void osMessageObject(key objectUUID,string message) |
439 | { | 439 | { |
440 | m_OSSL_Functions.osMessageObject(objectUUID,message); | 440 | m_OSSL_Functions.osMessageObject(objectUUID,message); |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/Properties/AssemblyInfo.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/Properties/AssemblyInfo.cs index 573a803..b1825ac 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/Properties/AssemblyInfo.cs | |||
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices; | |||
29 | // Build Number | 29 | // Build Number |
30 | // Revision | 30 | // Revision |
31 | // | 31 | // |
32 | [assembly: AssemblyVersion("0.7.5.*")] | 32 | [assembly: AssemblyVersion("0.7.6.*")] |
33 | [assembly: AssemblyFileVersion("1.0.0.0")] | 33 | [assembly: AssemblyFileVersion("1.0.0.0")] |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/Properties/AssemblyInfo.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/Properties/AssemblyInfo.cs index f6d5d41..342dbff 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/Properties/AssemblyInfo.cs | |||
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices; | |||
29 | // Build Number | 29 | // Build Number |
30 | // Revision | 30 | // Revision |
31 | // | 31 | // |
32 | [assembly: AssemblyVersion("0.7.5.*")] | 32 | [assembly: AssemblyVersion("0.7.6.*")] |
33 | [assembly: AssemblyFileVersion("1.0.0.0")] | 33 | [assembly: AssemblyFileVersion("1.0.0.0")] |
diff --git a/OpenSim/Region/ScriptEngine/Shared/CodeTools/CSCodeGenerator.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/CSCodeGenerator.cs index 97dd0f6..9e32f40 100644 --- a/OpenSim/Region/ScriptEngine/Shared/CodeTools/CSCodeGenerator.cs +++ b/OpenSim/Region/ScriptEngine/Shared/CodeTools/CSCodeGenerator.cs | |||
@@ -31,7 +31,6 @@ using System.Collections.Generic; | |||
31 | using System.Reflection; | 31 | using System.Reflection; |
32 | using log4net; | 32 | using log4net; |
33 | using Tools; | 33 | using Tools; |
34 | |||
35 | using OpenSim.Region.Framework.Interfaces; | 34 | using OpenSim.Region.Framework.Interfaces; |
36 | 35 | ||
37 | namespace OpenSim.Region.ScriptEngine.Shared.CodeTools | 36 | namespace OpenSim.Region.ScriptEngine.Shared.CodeTools |
@@ -49,6 +48,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools | |||
49 | private List<string> m_warnings = new List<string>(); | 48 | private List<string> m_warnings = new List<string>(); |
50 | private IScriptModuleComms m_comms = null; | 49 | private IScriptModuleComms m_comms = null; |
51 | 50 | ||
51 | private bool m_insertCoopTerminationChecks; | ||
52 | private static string m_coopTerminationCheck = "opensim_reserved_CheckForCoopTermination();"; | ||
53 | |||
54 | /// <summary> | ||
55 | /// Keep a record of the previous node when we do the parsing. | ||
56 | /// </summary> | ||
57 | /// <remarks> | ||
58 | /// We do this here because the parser generated by CSTools does not retain a reference to its parent node. | ||
59 | /// The previous node is required so we can correctly insert co-op termination checks when required. | ||
60 | /// </remarks> | ||
61 | // private SYMBOL m_previousNode; | ||
62 | |||
52 | /// <summary> | 63 | /// <summary> |
53 | /// Creates an 'empty' CSCodeGenerator instance. | 64 | /// Creates an 'empty' CSCodeGenerator instance. |
54 | /// </summary> | 65 | /// </summary> |
@@ -58,9 +69,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools | |||
58 | ResetCounters(); | 69 | ResetCounters(); |
59 | } | 70 | } |
60 | 71 | ||
61 | public CSCodeGenerator(IScriptModuleComms comms) | 72 | public CSCodeGenerator(IScriptModuleComms comms, bool insertCoopTerminationChecks) |
62 | { | 73 | { |
63 | m_comms = comms; | 74 | m_comms = comms; |
75 | m_insertCoopTerminationChecks = insertCoopTerminationChecks; | ||
64 | ResetCounters(); | 76 | ResetCounters(); |
65 | } | 77 | } |
66 | 78 | ||
@@ -155,7 +167,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools | |||
155 | // here's the payload | 167 | // here's the payload |
156 | retstr += GenerateLine(); | 168 | retstr += GenerateLine(); |
157 | foreach (SYMBOL s in m_astRoot.kids) | 169 | foreach (SYMBOL s in m_astRoot.kids) |
158 | retstr += GenerateNode(s); | 170 | retstr += GenerateNode(m_astRoot, s); |
159 | 171 | ||
160 | // close braces! | 172 | // close braces! |
161 | m_braceCount--; | 173 | m_braceCount--; |
@@ -165,7 +177,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools | |||
165 | 177 | ||
166 | // Removes all carriage return characters which may be generated in Windows platform. Is there | 178 | // Removes all carriage return characters which may be generated in Windows platform. Is there |
167 | // cleaner way of doing this? | 179 | // cleaner way of doing this? |
168 | retstr=retstr.Replace("\r", ""); | 180 | retstr = retstr.Replace("\r", ""); |
169 | 181 | ||
170 | return retstr; | 182 | return retstr; |
171 | } | 183 | } |
@@ -191,9 +203,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools | |||
191 | /// Recursively called to generate each type of node. Will generate this | 203 | /// Recursively called to generate each type of node. Will generate this |
192 | /// node, then all it's children. | 204 | /// node, then all it's children. |
193 | /// </summary> | 205 | /// </summary> |
206 | /// <param name="previousSymbol">The parent node.</param> | ||
194 | /// <param name="s">The current node to generate code for.</param> | 207 | /// <param name="s">The current node to generate code for.</param> |
195 | /// <returns>String containing C# code for SYMBOL s.</returns> | 208 | /// <returns>String containing C# code for SYMBOL s.</returns> |
196 | private string GenerateNode(SYMBOL s) | 209 | private string GenerateNode(SYMBOL previousSymbol, SYMBOL s) |
197 | { | 210 | { |
198 | string retstr = String.Empty; | 211 | string retstr = String.Empty; |
199 | 212 | ||
@@ -207,11 +220,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools | |||
207 | else if (s is State) | 220 | else if (s is State) |
208 | retstr += GenerateState((State) s); | 221 | retstr += GenerateState((State) s); |
209 | else if (s is CompoundStatement) | 222 | else if (s is CompoundStatement) |
210 | retstr += GenerateCompoundStatement((CompoundStatement) s); | 223 | retstr += GenerateCompoundStatement(previousSymbol, (CompoundStatement) s); |
211 | else if (s is Declaration) | 224 | else if (s is Declaration) |
212 | retstr += GenerateDeclaration((Declaration) s); | 225 | retstr += GenerateDeclaration((Declaration) s); |
213 | else if (s is Statement) | 226 | else if (s is Statement) |
214 | retstr += GenerateStatement((Statement) s); | 227 | retstr += GenerateStatement(previousSymbol, (Statement) s); |
215 | else if (s is ReturnStatement) | 228 | else if (s is ReturnStatement) |
216 | retstr += GenerateReturnStatement((ReturnStatement) s); | 229 | retstr += GenerateReturnStatement((ReturnStatement) s); |
217 | else if (s is JumpLabel) | 230 | else if (s is JumpLabel) |
@@ -261,7 +274,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools | |||
261 | else | 274 | else |
262 | { | 275 | { |
263 | foreach (SYMBOL kid in s.kids) | 276 | foreach (SYMBOL kid in s.kids) |
264 | retstr += GenerateNode(kid); | 277 | retstr += GenerateNode(s, kid); |
265 | } | 278 | } |
266 | 279 | ||
267 | return retstr; | 280 | return retstr; |
@@ -295,7 +308,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools | |||
295 | retstr += GenerateLine(")"); | 308 | retstr += GenerateLine(")"); |
296 | 309 | ||
297 | foreach (SYMBOL kid in remainingKids) | 310 | foreach (SYMBOL kid in remainingKids) |
298 | retstr += GenerateNode(kid); | 311 | retstr += GenerateNode(gf, kid); |
299 | 312 | ||
300 | return retstr; | 313 | return retstr; |
301 | } | 314 | } |
@@ -312,7 +325,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools | |||
312 | foreach (SYMBOL s in gv.kids) | 325 | foreach (SYMBOL s in gv.kids) |
313 | { | 326 | { |
314 | retstr += Indent(); | 327 | retstr += Indent(); |
315 | retstr += GenerateNode(s); | 328 | retstr += GenerateNode(gv, s); |
316 | retstr += GenerateLine(";"); | 329 | retstr += GenerateLine(";"); |
317 | } | 330 | } |
318 | 331 | ||
@@ -365,7 +378,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools | |||
365 | retstr += GenerateLine(")"); | 378 | retstr += GenerateLine(")"); |
366 | 379 | ||
367 | foreach (SYMBOL kid in remainingKids) | 380 | foreach (SYMBOL kid in remainingKids) |
368 | retstr += GenerateNode(kid); | 381 | retstr += GenerateNode(se, kid); |
369 | 382 | ||
370 | return retstr; | 383 | return retstr; |
371 | } | 384 | } |
@@ -404,7 +417,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools | |||
404 | 417 | ||
405 | foreach (SYMBOL s in al.kids) | 418 | foreach (SYMBOL s in al.kids) |
406 | { | 419 | { |
407 | retstr += GenerateNode(s); | 420 | retstr += GenerateNode(al, s); |
408 | if (0 < comma--) | 421 | if (0 < comma--) |
409 | retstr += Generate(", "); | 422 | retstr += Generate(", "); |
410 | } | 423 | } |
@@ -417,7 +430,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools | |||
417 | /// </summary> | 430 | /// </summary> |
418 | /// <param name="cs">The CompoundStatement node.</param> | 431 | /// <param name="cs">The CompoundStatement node.</param> |
419 | /// <returns>String containing C# code for CompoundStatement cs.</returns> | 432 | /// <returns>String containing C# code for CompoundStatement cs.</returns> |
420 | private string GenerateCompoundStatement(CompoundStatement cs) | 433 | private string GenerateCompoundStatement(SYMBOL previousSymbol, CompoundStatement cs) |
421 | { | 434 | { |
422 | string retstr = String.Empty; | 435 | string retstr = String.Empty; |
423 | 436 | ||
@@ -425,8 +438,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools | |||
425 | retstr += GenerateIndentedLine("{"); | 438 | retstr += GenerateIndentedLine("{"); |
426 | m_braceCount++; | 439 | m_braceCount++; |
427 | 440 | ||
441 | if (m_insertCoopTerminationChecks) | ||
442 | { | ||
443 | // We have to check in event functions as well because the user can manually call these. | ||
444 | if (previousSymbol is GlobalFunctionDefinition | ||
445 | || previousSymbol is WhileStatement | ||
446 | || previousSymbol is DoWhileStatement | ||
447 | || previousSymbol is ForLoop | ||
448 | || previousSymbol is StateEvent) | ||
449 | retstr += GenerateIndentedLine(m_coopTerminationCheck); | ||
450 | } | ||
451 | |||
428 | foreach (SYMBOL kid in cs.kids) | 452 | foreach (SYMBOL kid in cs.kids) |
429 | retstr += GenerateNode(kid); | 453 | retstr += GenerateNode(cs, kid); |
430 | 454 | ||
431 | // closing brace | 455 | // closing brace |
432 | m_braceCount--; | 456 | m_braceCount--; |
@@ -450,10 +474,28 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools | |||
450 | /// </summary> | 474 | /// </summary> |
451 | /// <param name="s">The Statement node.</param> | 475 | /// <param name="s">The Statement node.</param> |
452 | /// <returns>String containing C# code for Statement s.</returns> | 476 | /// <returns>String containing C# code for Statement s.</returns> |
453 | private string GenerateStatement(Statement s) | 477 | private string GenerateStatement(SYMBOL previousSymbol, Statement s) |
454 | { | 478 | { |
455 | string retstr = String.Empty; | 479 | string retstr = String.Empty; |
456 | bool printSemicolon = true; | 480 | bool printSemicolon = true; |
481 | bool transformToBlock = false; | ||
482 | |||
483 | if (m_insertCoopTerminationChecks) | ||
484 | { | ||
485 | // A non-braced single line do while structure cannot contain multiple statements. | ||
486 | // So to insert the termination check we change this to a braced control structure instead. | ||
487 | if (previousSymbol is WhileStatement | ||
488 | || previousSymbol is DoWhileStatement | ||
489 | || previousSymbol is ForLoop) | ||
490 | { | ||
491 | transformToBlock = true; | ||
492 | |||
493 | // FIXME: This will be wrongly indented because the previous for/while/dowhile will have already indented. | ||
494 | retstr += GenerateIndentedLine("{"); | ||
495 | |||
496 | retstr += GenerateIndentedLine(m_coopTerminationCheck); | ||
497 | } | ||
498 | } | ||
457 | 499 | ||
458 | retstr += Indent(); | 500 | retstr += Indent(); |
459 | 501 | ||
@@ -466,12 +508,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools | |||
466 | // (MONO) error. | 508 | // (MONO) error. |
467 | if (!(s.kids.Top is IdentExpression && 1 == s.kids.Count)) | 509 | if (!(s.kids.Top is IdentExpression && 1 == s.kids.Count)) |
468 | foreach (SYMBOL kid in s.kids) | 510 | foreach (SYMBOL kid in s.kids) |
469 | retstr += GenerateNode(kid); | 511 | retstr += GenerateNode(s, kid); |
470 | } | 512 | } |
471 | 513 | ||
472 | if (printSemicolon) | 514 | if (printSemicolon) |
473 | retstr += GenerateLine(";"); | 515 | retstr += GenerateLine(";"); |
474 | 516 | ||
517 | if (transformToBlock) | ||
518 | { | ||
519 | // FIXME: This will be wrongly indented because the for/while/dowhile is currently handling the unindent | ||
520 | retstr += GenerateIndentedLine("}"); | ||
521 | } | ||
522 | |||
475 | return retstr; | 523 | return retstr; |
476 | } | 524 | } |
477 | 525 | ||
@@ -487,10 +535,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools | |||
487 | List<string> identifiers = new List<string>(); | 535 | List<string> identifiers = new List<string>(); |
488 | checkForMultipleAssignments(identifiers, a); | 536 | checkForMultipleAssignments(identifiers, a); |
489 | 537 | ||
490 | retstr += GenerateNode((SYMBOL) a.kids.Pop()); | 538 | retstr += GenerateNode(a, (SYMBOL) a.kids.Pop()); |
491 | retstr += Generate(String.Format(" {0} ", a.AssignmentType), a); | 539 | retstr += Generate(String.Format(" {0} ", a.AssignmentType), a); |
492 | foreach (SYMBOL kid in a.kids) | 540 | foreach (SYMBOL kid in a.kids) |
493 | retstr += GenerateNode(kid); | 541 | retstr += GenerateNode(a, kid); |
494 | 542 | ||
495 | return retstr; | 543 | return retstr; |
496 | } | 544 | } |
@@ -563,7 +611,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools | |||
563 | retstr += Generate("return ", rs); | 611 | retstr += Generate("return ", rs); |
564 | 612 | ||
565 | foreach (SYMBOL kid in rs.kids) | 613 | foreach (SYMBOL kid in rs.kids) |
566 | retstr += GenerateNode(kid); | 614 | retstr += GenerateNode(rs, kid); |
567 | 615 | ||
568 | return retstr; | 616 | return retstr; |
569 | } | 617 | } |
@@ -575,7 +623,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools | |||
575 | /// <returns>String containing C# code for JumpLabel jl.</returns> | 623 | /// <returns>String containing C# code for JumpLabel jl.</returns> |
576 | private string GenerateJumpLabel(JumpLabel jl) | 624 | private string GenerateJumpLabel(JumpLabel jl) |
577 | { | 625 | { |
578 | return Generate(String.Format("{0}:", CheckName(jl.LabelName)), jl) + " NoOp();\n"; | 626 | string labelStatement; |
627 | |||
628 | if (m_insertCoopTerminationChecks) | ||
629 | labelStatement = m_coopTerminationCheck + "\n"; | ||
630 | else | ||
631 | labelStatement = "NoOp();\n"; | ||
632 | |||
633 | return Generate(String.Format("{0}: ", CheckName(jl.LabelName)), jl) + labelStatement; | ||
579 | } | 634 | } |
580 | 635 | ||
581 | /// <summary> | 636 | /// <summary> |
@@ -598,14 +653,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools | |||
598 | string retstr = String.Empty; | 653 | string retstr = String.Empty; |
599 | 654 | ||
600 | retstr += GenerateIndented("if (", ifs); | 655 | retstr += GenerateIndented("if (", ifs); |
601 | retstr += GenerateNode((SYMBOL) ifs.kids.Pop()); | 656 | retstr += GenerateNode(ifs, (SYMBOL) ifs.kids.Pop()); |
602 | retstr += GenerateLine(")"); | 657 | retstr += GenerateLine(")"); |
603 | 658 | ||
604 | // CompoundStatement handles indentation itself but we need to do it | 659 | // CompoundStatement handles indentation itself but we need to do it |
605 | // otherwise. | 660 | // otherwise. |
606 | bool indentHere = ifs.kids.Top is Statement; | 661 | bool indentHere = ifs.kids.Top is Statement; |
607 | if (indentHere) m_braceCount++; | 662 | if (indentHere) m_braceCount++; |
608 | retstr += GenerateNode((SYMBOL) ifs.kids.Pop()); | 663 | retstr += GenerateNode(ifs, (SYMBOL) ifs.kids.Pop()); |
609 | if (indentHere) m_braceCount--; | 664 | if (indentHere) m_braceCount--; |
610 | 665 | ||
611 | if (0 < ifs.kids.Count) // do it again for an else | 666 | if (0 < ifs.kids.Count) // do it again for an else |
@@ -614,7 +669,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools | |||
614 | 669 | ||
615 | indentHere = ifs.kids.Top is Statement; | 670 | indentHere = ifs.kids.Top is Statement; |
616 | if (indentHere) m_braceCount++; | 671 | if (indentHere) m_braceCount++; |
617 | retstr += GenerateNode((SYMBOL) ifs.kids.Pop()); | 672 | retstr += GenerateNode(ifs, (SYMBOL) ifs.kids.Pop()); |
618 | if (indentHere) m_braceCount--; | 673 | if (indentHere) m_braceCount--; |
619 | } | 674 | } |
620 | 675 | ||
@@ -641,14 +696,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools | |||
641 | string retstr = String.Empty; | 696 | string retstr = String.Empty; |
642 | 697 | ||
643 | retstr += GenerateIndented("while (", ws); | 698 | retstr += GenerateIndented("while (", ws); |
644 | retstr += GenerateNode((SYMBOL) ws.kids.Pop()); | 699 | retstr += GenerateNode(ws, (SYMBOL) ws.kids.Pop()); |
645 | retstr += GenerateLine(")"); | 700 | retstr += GenerateLine(")"); |
646 | 701 | ||
647 | // CompoundStatement handles indentation itself but we need to do it | 702 | // CompoundStatement handles indentation itself but we need to do it |
648 | // otherwise. | 703 | // otherwise. |
649 | bool indentHere = ws.kids.Top is Statement; | 704 | bool indentHere = ws.kids.Top is Statement; |
650 | if (indentHere) m_braceCount++; | 705 | if (indentHere) m_braceCount++; |
651 | retstr += GenerateNode((SYMBOL) ws.kids.Pop()); | 706 | retstr += GenerateNode(ws, (SYMBOL) ws.kids.Pop()); |
652 | if (indentHere) m_braceCount--; | 707 | if (indentHere) m_braceCount--; |
653 | 708 | ||
654 | return retstr; | 709 | return retstr; |
@@ -669,11 +724,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools | |||
669 | // otherwise. | 724 | // otherwise. |
670 | bool indentHere = dws.kids.Top is Statement; | 725 | bool indentHere = dws.kids.Top is Statement; |
671 | if (indentHere) m_braceCount++; | 726 | if (indentHere) m_braceCount++; |
672 | retstr += GenerateNode((SYMBOL) dws.kids.Pop()); | 727 | retstr += GenerateNode(dws, (SYMBOL) dws.kids.Pop()); |
673 | if (indentHere) m_braceCount--; | 728 | if (indentHere) m_braceCount--; |
674 | 729 | ||
675 | retstr += GenerateIndented("while (", dws); | 730 | retstr += GenerateIndented("while (", dws); |
676 | retstr += GenerateNode((SYMBOL) dws.kids.Pop()); | 731 | retstr += GenerateNode(dws, (SYMBOL) dws.kids.Pop()); |
677 | retstr += GenerateLine(");"); | 732 | retstr += GenerateLine(");"); |
678 | 733 | ||
679 | return retstr; | 734 | return retstr; |
@@ -702,7 +757,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools | |||
702 | retstr += Generate("; "); | 757 | retstr += Generate("; "); |
703 | // for (x = 0; x < 10; x++) | 758 | // for (x = 0; x < 10; x++) |
704 | // ^^^^^^ | 759 | // ^^^^^^ |
705 | retstr += GenerateNode((SYMBOL) fl.kids.Pop()); | 760 | retstr += GenerateNode(fl, (SYMBOL) fl.kids.Pop()); |
706 | retstr += Generate("; "); | 761 | retstr += Generate("; "); |
707 | // for (x = 0; x < 10; x++) | 762 | // for (x = 0; x < 10; x++) |
708 | // ^^^ | 763 | // ^^^ |
@@ -713,7 +768,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools | |||
713 | // otherwise. | 768 | // otherwise. |
714 | bool indentHere = fl.kids.Top is Statement; | 769 | bool indentHere = fl.kids.Top is Statement; |
715 | if (indentHere) m_braceCount++; | 770 | if (indentHere) m_braceCount++; |
716 | retstr += GenerateNode((SYMBOL) fl.kids.Pop()); | 771 | retstr += GenerateNode(fl, (SYMBOL) fl.kids.Pop()); |
717 | if (indentHere) m_braceCount--; | 772 | if (indentHere) m_braceCount--; |
718 | 773 | ||
719 | return retstr; | 774 | return retstr; |
@@ -758,7 +813,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools | |||
758 | while (s is ParenthesisExpression) | 813 | while (s is ParenthesisExpression) |
759 | s = (SYMBOL)s.kids.Pop(); | 814 | s = (SYMBOL)s.kids.Pop(); |
760 | 815 | ||
761 | retstr += GenerateNode(s); | 816 | retstr += GenerateNode(fls, s); |
762 | if (0 < comma--) | 817 | if (0 < comma--) |
763 | retstr += Generate(", "); | 818 | retstr += Generate(", "); |
764 | } | 819 | } |
@@ -779,20 +834,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools | |||
779 | { | 834 | { |
780 | // special case handling for logical and/or, see Mantis 3174 | 835 | // special case handling for logical and/or, see Mantis 3174 |
781 | retstr += "((bool)("; | 836 | retstr += "((bool)("; |
782 | retstr += GenerateNode((SYMBOL)be.kids.Pop()); | 837 | retstr += GenerateNode(be, (SYMBOL)be.kids.Pop()); |
783 | retstr += "))"; | 838 | retstr += "))"; |
784 | retstr += Generate(String.Format(" {0} ", be.ExpressionSymbol.Substring(0,1)), be); | 839 | retstr += Generate(String.Format(" {0} ", be.ExpressionSymbol.Substring(0,1)), be); |
785 | retstr += "((bool)("; | 840 | retstr += "((bool)("; |
786 | foreach (SYMBOL kid in be.kids) | 841 | foreach (SYMBOL kid in be.kids) |
787 | retstr += GenerateNode(kid); | 842 | retstr += GenerateNode(be, kid); |
788 | retstr += "))"; | 843 | retstr += "))"; |
789 | } | 844 | } |
790 | else | 845 | else |
791 | { | 846 | { |
792 | retstr += GenerateNode((SYMBOL)be.kids.Pop()); | 847 | retstr += GenerateNode(be, (SYMBOL)be.kids.Pop()); |
793 | retstr += Generate(String.Format(" {0} ", be.ExpressionSymbol), be); | 848 | retstr += Generate(String.Format(" {0} ", be.ExpressionSymbol), be); |
794 | foreach (SYMBOL kid in be.kids) | 849 | foreach (SYMBOL kid in be.kids) |
795 | retstr += GenerateNode(kid); | 850 | retstr += GenerateNode(be, kid); |
796 | } | 851 | } |
797 | 852 | ||
798 | return retstr; | 853 | return retstr; |
@@ -808,7 +863,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools | |||
808 | string retstr = String.Empty; | 863 | string retstr = String.Empty; |
809 | 864 | ||
810 | retstr += Generate(ue.UnarySymbol, ue); | 865 | retstr += Generate(ue.UnarySymbol, ue); |
811 | retstr += GenerateNode((SYMBOL) ue.kids.Pop()); | 866 | retstr += GenerateNode(ue, (SYMBOL) ue.kids.Pop()); |
812 | 867 | ||
813 | return retstr; | 868 | return retstr; |
814 | } | 869 | } |
@@ -824,7 +879,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools | |||
824 | 879 | ||
825 | retstr += Generate("("); | 880 | retstr += Generate("("); |
826 | foreach (SYMBOL kid in pe.kids) | 881 | foreach (SYMBOL kid in pe.kids) |
827 | retstr += GenerateNode(kid); | 882 | retstr += GenerateNode(pe, kid); |
828 | retstr += Generate(")"); | 883 | retstr += Generate(")"); |
829 | 884 | ||
830 | return retstr; | 885 | return retstr; |
@@ -861,7 +916,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools | |||
861 | 916 | ||
862 | // we wrap all typecasted statements in parentheses | 917 | // we wrap all typecasted statements in parentheses |
863 | retstr += Generate(String.Format("({0}) (", te.TypecastType), te); | 918 | retstr += Generate(String.Format("({0}) (", te.TypecastType), te); |
864 | retstr += GenerateNode((SYMBOL) te.kids.Pop()); | 919 | retstr += GenerateNode(te, (SYMBOL) te.kids.Pop()); |
865 | retstr += Generate(")"); | 920 | retstr += Generate(")"); |
866 | 921 | ||
867 | return retstr; | 922 | return retstr; |
@@ -931,7 +986,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools | |||
931 | } | 986 | } |
932 | 987 | ||
933 | foreach (SYMBOL kid in fc.kids) | 988 | foreach (SYMBOL kid in fc.kids) |
934 | retstr += GenerateNode(kid); | 989 | retstr += GenerateNode(fc, kid); |
935 | 990 | ||
936 | retstr += Generate(")"); | 991 | retstr += Generate(")"); |
937 | 992 | ||
@@ -980,11 +1035,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools | |||
980 | string retstr = String.Empty; | 1035 | string retstr = String.Empty; |
981 | 1036 | ||
982 | retstr += Generate(String.Format("new {0}(", vc.Type), vc); | 1037 | retstr += Generate(String.Format("new {0}(", vc.Type), vc); |
983 | retstr += GenerateNode((SYMBOL) vc.kids.Pop()); | 1038 | retstr += GenerateNode(vc, (SYMBOL) vc.kids.Pop()); |
984 | retstr += Generate(", "); | 1039 | retstr += Generate(", "); |
985 | retstr += GenerateNode((SYMBOL) vc.kids.Pop()); | 1040 | retstr += GenerateNode(vc, (SYMBOL) vc.kids.Pop()); |
986 | retstr += Generate(", "); | 1041 | retstr += Generate(", "); |
987 | retstr += GenerateNode((SYMBOL) vc.kids.Pop()); | 1042 | retstr += GenerateNode(vc, (SYMBOL) vc.kids.Pop()); |
988 | retstr += Generate(")"); | 1043 | retstr += Generate(")"); |
989 | 1044 | ||
990 | return retstr; | 1045 | return retstr; |
@@ -1000,13 +1055,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools | |||
1000 | string retstr = String.Empty; | 1055 | string retstr = String.Empty; |
1001 | 1056 | ||
1002 | retstr += Generate(String.Format("new {0}(", rc.Type), rc); | 1057 | retstr += Generate(String.Format("new {0}(", rc.Type), rc); |
1003 | retstr += GenerateNode((SYMBOL) rc.kids.Pop()); | 1058 | retstr += GenerateNode(rc, (SYMBOL) rc.kids.Pop()); |
1004 | retstr += Generate(", "); | 1059 | retstr += Generate(", "); |
1005 | retstr += GenerateNode((SYMBOL) rc.kids.Pop()); | 1060 | retstr += GenerateNode(rc, (SYMBOL) rc.kids.Pop()); |
1006 | retstr += Generate(", "); | 1061 | retstr += Generate(", "); |
1007 | retstr += GenerateNode((SYMBOL) rc.kids.Pop()); | 1062 | retstr += GenerateNode(rc, (SYMBOL) rc.kids.Pop()); |
1008 | retstr += Generate(", "); | 1063 | retstr += Generate(", "); |
1009 | retstr += GenerateNode((SYMBOL) rc.kids.Pop()); | 1064 | retstr += GenerateNode(rc, (SYMBOL) rc.kids.Pop()); |
1010 | retstr += Generate(")"); | 1065 | retstr += Generate(")"); |
1011 | 1066 | ||
1012 | return retstr; | 1067 | return retstr; |
@@ -1024,7 +1079,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools | |||
1024 | retstr += Generate(String.Format("new {0}(", lc.Type), lc); | 1079 | retstr += Generate(String.Format("new {0}(", lc.Type), lc); |
1025 | 1080 | ||
1026 | foreach (SYMBOL kid in lc.kids) | 1081 | foreach (SYMBOL kid in lc.kids) |
1027 | retstr += GenerateNode(kid); | 1082 | retstr += GenerateNode(lc, kid); |
1028 | 1083 | ||
1029 | retstr += Generate(")"); | 1084 | retstr += Generate(")"); |
1030 | 1085 | ||
diff --git a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs index 03be2ab..b71afe3 100644 --- a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs +++ b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs | |||
@@ -72,6 +72,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools | |||
72 | private bool CompileWithDebugInformation; | 72 | private bool CompileWithDebugInformation; |
73 | private Dictionary<string, bool> AllowedCompilers = new Dictionary<string, bool>(StringComparer.CurrentCultureIgnoreCase); | 73 | private Dictionary<string, bool> AllowedCompilers = new Dictionary<string, bool>(StringComparer.CurrentCultureIgnoreCase); |
74 | private Dictionary<string, enumCompileType> LanguageMapping = new Dictionary<string, enumCompileType>(StringComparer.CurrentCultureIgnoreCase); | 74 | private Dictionary<string, enumCompileType> LanguageMapping = new Dictionary<string, enumCompileType>(StringComparer.CurrentCultureIgnoreCase); |
75 | private bool m_insertCoopTerminationCalls; | ||
75 | 76 | ||
76 | private string FilePrefix; | 77 | private string FilePrefix; |
77 | private string ScriptEnginesPath = null; | 78 | private string ScriptEnginesPath = null; |
@@ -95,20 +96,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools | |||
95 | private Dictionary<string, Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>>> m_lineMaps = | 96 | private Dictionary<string, Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>>> m_lineMaps = |
96 | new Dictionary<string, Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>>>(); | 97 | new Dictionary<string, Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>>>(); |
97 | 98 | ||
99 | public bool in_startup = true; | ||
100 | |||
98 | public Compiler(IScriptEngine scriptEngine) | 101 | public Compiler(IScriptEngine scriptEngine) |
99 | { | 102 | { |
100 | m_scriptEngine = scriptEngine;; | 103 | m_scriptEngine = scriptEngine; |
101 | ScriptEnginesPath = scriptEngine.ScriptEnginePath; | 104 | ScriptEnginesPath = scriptEngine.ScriptEnginePath; |
102 | ReadConfig(); | 105 | ReadConfig(); |
103 | } | 106 | } |
104 | 107 | ||
105 | public bool in_startup = true; | ||
106 | public void ReadConfig() | 108 | public void ReadConfig() |
107 | { | 109 | { |
108 | // Get some config | 110 | // Get some config |
109 | WriteScriptSourceToDebugFile = m_scriptEngine.Config.GetBoolean("WriteScriptSourceToDebugFile", false); | 111 | WriteScriptSourceToDebugFile = m_scriptEngine.Config.GetBoolean("WriteScriptSourceToDebugFile", false); |
110 | CompileWithDebugInformation = m_scriptEngine.Config.GetBoolean("CompileWithDebugInformation", true); | 112 | CompileWithDebugInformation = m_scriptEngine.Config.GetBoolean("CompileWithDebugInformation", true); |
111 | bool DeleteScriptsOnStartup = m_scriptEngine.Config.GetBoolean("DeleteScriptsOnStartup", true); | 113 | bool DeleteScriptsOnStartup = m_scriptEngine.Config.GetBoolean("DeleteScriptsOnStartup", true); |
114 | m_insertCoopTerminationCalls = m_scriptEngine.Config.GetString("ScriptStopStrategy", "abort") == "co-op"; | ||
112 | 115 | ||
113 | // Get file prefix from scriptengine name and make it file system safe: | 116 | // Get file prefix from scriptengine name and make it file system safe: |
114 | FilePrefix = "CommonCompiler"; | 117 | FilePrefix = "CommonCompiler"; |
@@ -386,7 +389,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools | |||
386 | if (language == enumCompileType.lsl) | 389 | if (language == enumCompileType.lsl) |
387 | { | 390 | { |
388 | // Its LSL, convert it to C# | 391 | // Its LSL, convert it to C# |
389 | LSL_Converter = (ICodeConverter)new CSCodeGenerator(comms); | 392 | LSL_Converter = (ICodeConverter)new CSCodeGenerator(comms, m_insertCoopTerminationCalls); |
390 | compileScript = LSL_Converter.Convert(Script); | 393 | compileScript = LSL_Converter.Convert(Script); |
391 | 394 | ||
392 | // copy converter warnings into our warnings. | 395 | // copy converter warnings into our warnings. |
@@ -411,16 +414,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools | |||
411 | { | 414 | { |
412 | case enumCompileType.cs: | 415 | case enumCompileType.cs: |
413 | case enumCompileType.lsl: | 416 | case enumCompileType.lsl: |
414 | compileScript = CreateCSCompilerScript(compileScript); | 417 | compileScript = CreateCSCompilerScript( |
418 | compileScript, | ||
419 | m_scriptEngine.ScriptClassName, | ||
420 | m_scriptEngine.ScriptBaseClassName, | ||
421 | m_scriptEngine.ScriptBaseClassParameters); | ||
415 | break; | 422 | break; |
416 | case enumCompileType.vb: | 423 | case enumCompileType.vb: |
417 | compileScript = CreateVBCompilerScript(compileScript); | 424 | compileScript = CreateVBCompilerScript( |
425 | compileScript, m_scriptEngine.ScriptClassName, m_scriptEngine.ScriptBaseClassName); | ||
418 | break; | 426 | break; |
419 | // case enumCompileType.js: | 427 | // case enumCompileType.js: |
420 | // compileScript = CreateJSCompilerScript(compileScript); | 428 | // compileScript = CreateJSCompilerScript(compileScript, m_scriptEngine.ScriptBaseClassName); |
421 | // break; | 429 | // break; |
422 | case enumCompileType.yp: | 430 | case enumCompileType.yp: |
423 | compileScript = CreateYPCompilerScript(compileScript); | 431 | compileScript = CreateYPCompilerScript( |
432 | compileScript, m_scriptEngine.ScriptClassName,m_scriptEngine.ScriptBaseClassName); | ||
424 | break; | 433 | break; |
425 | } | 434 | } |
426 | 435 | ||
@@ -451,43 +460,60 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools | |||
451 | // return compileScript; | 460 | // return compileScript; |
452 | // } | 461 | // } |
453 | 462 | ||
454 | private static string CreateCSCompilerScript(string compileScript) | 463 | private static string CreateCSCompilerScript( |
464 | string compileScript, string className, string baseClassName, ParameterInfo[] constructorParameters) | ||
455 | { | 465 | { |
456 | compileScript = String.Empty + | 466 | compileScript = string.Format( |
457 | "using OpenSim.Region.ScriptEngine.Shared; using System.Collections.Generic;\r\n" + | 467 | @"using OpenSim.Region.ScriptEngine.Shared; |
458 | String.Empty + "namespace SecondLife { " + | 468 | using System.Collections.Generic; |
459 | String.Empty + "public class Script : OpenSim.Region.ScriptEngine.Shared.ScriptBase.ScriptBaseClass { \r\n" + | 469 | |
460 | @"public Script() { } " + | 470 | namespace SecondLife |
461 | compileScript + | 471 | {{ |
462 | "} }\r\n"; | 472 | public class {0} : {1} |
473 | {{ | ||
474 | public {0}({2}) : base({3}) {{}} | ||
475 | {4} | ||
476 | }} | ||
477 | }}", | ||
478 | className, | ||
479 | baseClassName, | ||
480 | constructorParameters != null | ||
481 | ? string.Join(", ", Array.ConvertAll<ParameterInfo, string>(constructorParameters, pi => pi.ToString())) | ||
482 | : "", | ||
483 | constructorParameters != null | ||
484 | ? string.Join(", ", Array.ConvertAll<ParameterInfo, string>(constructorParameters, pi => pi.Name)) | ||
485 | : "", | ||
486 | compileScript); | ||
487 | |||
463 | return compileScript; | 488 | return compileScript; |
464 | } | 489 | } |
465 | 490 | ||
466 | private static string CreateYPCompilerScript(string compileScript) | 491 | private static string CreateYPCompilerScript(string compileScript, string className, string baseClassName) |
467 | { | 492 | { |
468 | compileScript = String.Empty + | 493 | compileScript = String.Empty + |
469 | "using OpenSim.Region.ScriptEngine.Shared.YieldProlog; " + | 494 | "using OpenSim.Region.ScriptEngine.Shared.YieldProlog; " + |
470 | "using OpenSim.Region.ScriptEngine.Shared; using System.Collections.Generic;\r\n" + | 495 | "using OpenSim.Region.ScriptEngine.Shared; using System.Collections.Generic;\r\n" + |
471 | String.Empty + "namespace SecondLife { " + | 496 | String.Empty + "namespace SecondLife { " + |
472 | String.Empty + "public class Script : OpenSim.Region.ScriptEngine.Shared.ScriptBase.ScriptBaseClass { \r\n" + | 497 | String.Empty + "public class " + className + " : " + baseClassName + " { \r\n" + |
473 | //@"public Script() { } " + | 498 | //@"public Script() { } " + |
474 | @"static OpenSim.Region.ScriptEngine.Shared.YieldProlog.YP YP=null; " + | 499 | @"static OpenSim.Region.ScriptEngine.Shared.YieldProlog.YP YP=null; " + |
475 | @"public Script() { YP= new OpenSim.Region.ScriptEngine.Shared.YieldProlog.YP(); } " + | 500 | @"public " + className + "() { YP= new OpenSim.Region.ScriptEngine.Shared.YieldProlog.YP(); } " + |
476 | |||
477 | compileScript + | 501 | compileScript + |
478 | "} }\r\n"; | 502 | "} }\r\n"; |
503 | |||
479 | return compileScript; | 504 | return compileScript; |
480 | } | 505 | } |
481 | 506 | ||
482 | private static string CreateVBCompilerScript(string compileScript) | 507 | private static string CreateVBCompilerScript(string compileScript, string className, string baseClassName) |
483 | { | 508 | { |
484 | compileScript = String.Empty + | 509 | compileScript = String.Empty + |
485 | "Imports OpenSim.Region.ScriptEngine.Shared: Imports System.Collections.Generic: " + | 510 | "Imports OpenSim.Region.ScriptEngine.Shared: Imports System.Collections.Generic: " + |
486 | String.Empty + "NameSpace SecondLife:" + | 511 | String.Empty + "NameSpace SecondLife:" + |
487 | String.Empty + "Public Class Script: Inherits OpenSim.Region.ScriptEngine.Shared.ScriptBase.ScriptBaseClass: " + | 512 | String.Empty + "Public Class " + className + ": Inherits " + baseClassName + |
488 | "\r\nPublic Sub New()\r\nEnd Sub: " + | 513 | "\r\nPublic Sub New()\r\nEnd Sub: " + |
489 | compileScript + | 514 | compileScript + |
490 | ":End Class :End Namespace\r\n"; | 515 | ":End Class :End Namespace\r\n"; |
516 | |||
491 | return compileScript; | 517 | return compileScript; |
492 | } | 518 | } |
493 | 519 | ||
@@ -549,6 +575,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools | |||
549 | parameters.ReferencedAssemblies.Add(Path.Combine(rootPath, | 575 | parameters.ReferencedAssemblies.Add(Path.Combine(rootPath, |
550 | "OpenMetaverseTypes.dll")); | 576 | "OpenMetaverseTypes.dll")); |
551 | 577 | ||
578 | if (m_scriptEngine.ScriptReferencedAssemblies != null) | ||
579 | Array.ForEach<string>( | ||
580 | m_scriptEngine.ScriptReferencedAssemblies, | ||
581 | a => parameters.ReferencedAssemblies.Add(Path.Combine(rootPath, a))); | ||
582 | |||
552 | if (lang == enumCompileType.yp) | 583 | if (lang == enumCompileType.yp) |
553 | { | 584 | { |
554 | parameters.ReferencedAssemblies.Add(Path.Combine(rootPath, | 585 | parameters.ReferencedAssemblies.Add(Path.Combine(rootPath, |
@@ -631,13 +662,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools | |||
631 | { | 662 | { |
632 | string severity = CompErr.IsWarning ? "Warning" : "Error"; | 663 | string severity = CompErr.IsWarning ? "Warning" : "Error"; |
633 | 664 | ||
634 | KeyValuePair<int, int> lslPos; | 665 | KeyValuePair<int, int> errorPos; |
635 | 666 | ||
636 | // Show 5 errors max, but check entire list for errors | 667 | // Show 5 errors max, but check entire list for errors |
637 | 668 | ||
638 | if (severity == "Error") | 669 | if (severity == "Error") |
639 | { | 670 | { |
640 | lslPos = FindErrorPosition(CompErr.Line, CompErr.Column, m_lineMaps[assembly]); | 671 | // C# scripts will not have a linemap since theres no line translation involved. |
672 | if (!m_lineMaps.ContainsKey(assembly)) | ||
673 | errorPos = new KeyValuePair<int, int>(CompErr.Line, CompErr.Column); | ||
674 | else | ||
675 | errorPos = FindErrorPosition(CompErr.Line, CompErr.Column, m_lineMaps[assembly]); | ||
676 | |||
641 | string text = CompErr.ErrorText; | 677 | string text = CompErr.ErrorText; |
642 | 678 | ||
643 | // Use LSL type names | 679 | // Use LSL type names |
@@ -647,7 +683,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools | |||
647 | // The Second Life viewer's script editor begins | 683 | // The Second Life viewer's script editor begins |
648 | // countingn lines and columns at 0, so we subtract 1. | 684 | // countingn lines and columns at 0, so we subtract 1. |
649 | errtext += String.Format("({0},{1}): {4} {2}: {3}\n", | 685 | errtext += String.Format("({0},{1}): {4} {2}: {3}\n", |
650 | lslPos.Key - 1, lslPos.Value - 1, | 686 | errorPos.Key - 1, errorPos.Value - 1, |
651 | CompErr.ErrorNumber, text, severity); | 687 | CompErr.ErrorNumber, text, severity); |
652 | hadErrors = true; | 688 | hadErrors = true; |
653 | } | 689 | } |
diff --git a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Properties/AssemblyInfo.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Properties/AssemblyInfo.cs index c65caa8..5b5c4fd 100644 --- a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Properties/AssemblyInfo.cs | |||
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices; | |||
29 | // Build Number | 29 | // Build Number |
30 | // Revision | 30 | // Revision |
31 | // | 31 | // |
32 | [assembly: AssemblyVersion("0.7.5.*")] | 32 | [assembly: AssemblyVersion("0.7.6.*")] |
33 | [assembly: AssemblyFileVersion("1.0.0.0")] | 33 | |
diff --git a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/CSCodeGeneratorTest.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/CSCodeGeneratorTest.cs index 7763619..77e087c 100644 --- a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/CSCodeGeneratorTest.cs +++ b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/CSCodeGeneratorTest.cs | |||
@@ -39,7 +39,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools.Tests | |||
39 | /// The generated C# code is compared against the expected C# code. | 39 | /// The generated C# code is compared against the expected C# code. |
40 | /// </summary> | 40 | /// </summary> |
41 | [TestFixture] | 41 | [TestFixture] |
42 | public class CSCodeGeneratorTest | 42 | public class CSCodeGeneratorTest : OpenSimTestCase |
43 | { | 43 | { |
44 | [Test] | 44 | [Test] |
45 | public void TestDefaultState() | 45 | public void TestDefaultState() |
diff --git a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/CompilerTest.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/CompilerTest.cs index 1fa6954..05a8756 100644 --- a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/CompilerTest.cs +++ b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/CompilerTest.cs | |||
@@ -41,7 +41,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools.Tests | |||
41 | /// the LSL source. | 41 | /// the LSL source. |
42 | /// </summary> | 42 | /// </summary> |
43 | [TestFixture] | 43 | [TestFixture] |
44 | public class CompilerTest | 44 | public class CompilerTest : OpenSimTestCase |
45 | { | 45 | { |
46 | private string m_testDir; | 46 | private string m_testDir; |
47 | private CSharpCodeProvider m_CSCodeProvider; | 47 | private CSharpCodeProvider m_CSCodeProvider; |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Helpers.cs b/OpenSim/Region/ScriptEngine/Shared/Helpers.cs index 22804f5..e44a106 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Helpers.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Helpers.cs | |||
@@ -82,6 +82,24 @@ namespace OpenSim.Region.ScriptEngine.Shared | |||
82 | } | 82 | } |
83 | } | 83 | } |
84 | 84 | ||
85 | /// <summary> | ||
86 | /// Used to signal when the script is stopping in co-operation with the script engine | ||
87 | /// (instead of through Thread.Abort()). | ||
88 | /// </summary> | ||
89 | [Serializable] | ||
90 | public class ScriptCoopStopException : Exception | ||
91 | { | ||
92 | public ScriptCoopStopException() | ||
93 | { | ||
94 | } | ||
95 | |||
96 | protected ScriptCoopStopException( | ||
97 | SerializationInfo info, | ||
98 | StreamingContext context) | ||
99 | { | ||
100 | } | ||
101 | } | ||
102 | |||
85 | public class DetectParams | 103 | public class DetectParams |
86 | { | 104 | { |
87 | public const int AGENT = 1; | 105 | public const int AGENT = 1; |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/Properties/AssemblyInfo.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/Properties/AssemblyInfo.cs index 470e1a1..48964b6 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/Properties/AssemblyInfo.cs | |||
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices; | |||
29 | // Build Number | 29 | // Build Number |
30 | // Revision | 30 | // Revision |
31 | // | 31 | // |
32 | [assembly: AssemblyVersion("0.7.5.*")] | 32 | [assembly: AssemblyVersion("0.7.6.*")] |
33 | [assembly: AssemblyFileVersion("1.0.0.0")] | 33 | |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs index 771db0c..26850c4 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs | |||
@@ -94,6 +94,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance | |||
94 | private UUID m_CurrentStateHash; | 94 | private UUID m_CurrentStateHash; |
95 | private UUID m_RegionID; | 95 | private UUID m_RegionID; |
96 | 96 | ||
97 | public int DebugLevel { get; set; } | ||
98 | |||
97 | public Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> LineMap { get; set; } | 99 | public Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> LineMap { get; set; } |
98 | 100 | ||
99 | private Dictionary<string,IScriptApi> m_Apis = new Dictionary<string,IScriptApi>(); | 101 | private Dictionary<string,IScriptApi> m_Apis = new Dictionary<string,IScriptApi>(); |
@@ -156,6 +158,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance | |||
156 | 158 | ||
157 | public UUID AppDomain { get; set; } | 159 | public UUID AppDomain { get; set; } |
158 | 160 | ||
161 | public SceneObjectPart Part { get; private set; } | ||
162 | |||
159 | public string PrimName { get; private set; } | 163 | public string PrimName { get; private set; } |
160 | 164 | ||
161 | public string ScriptName { get; private set; } | 165 | public string ScriptName { get; private set; } |
@@ -174,6 +178,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance | |||
174 | 178 | ||
175 | public Queue EventQueue { get; private set; } | 179 | public Queue EventQueue { get; private set; } |
176 | 180 | ||
181 | public long EventsQueued | ||
182 | { | ||
183 | get | ||
184 | { | ||
185 | lock (EventQueue) | ||
186 | return EventQueue.Count; | ||
187 | } | ||
188 | } | ||
189 | |||
190 | public long EventsProcessed { get; private set; } | ||
191 | |||
177 | public int StartParam { get; set; } | 192 | public int StartParam { get; set; } |
178 | 193 | ||
179 | public TaskInventoryItem ScriptTask { get; private set; } | 194 | public TaskInventoryItem ScriptTask { get; private set; } |
@@ -186,66 +201,124 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance | |||
186 | 201 | ||
187 | public static readonly long MaxMeasurementPeriod = 30 * TimeSpan.TicksPerMinute; | 202 | public static readonly long MaxMeasurementPeriod = 30 * TimeSpan.TicksPerMinute; |
188 | 203 | ||
204 | private bool m_coopTermination; | ||
205 | |||
206 | private EventWaitHandle m_coopSleepHandle; | ||
207 | |||
189 | public void ClearQueue() | 208 | public void ClearQueue() |
190 | { | 209 | { |
191 | m_TimerQueued = false; | 210 | m_TimerQueued = false; |
192 | EventQueue.Clear(); | 211 | EventQueue.Clear(); |
193 | } | 212 | } |
194 | 213 | ||
195 | public ScriptInstance(IScriptEngine engine, SceneObjectPart part, | 214 | public ScriptInstance( |
196 | UUID itemID, UUID assetID, string assembly, | 215 | IScriptEngine engine, SceneObjectPart part, TaskInventoryItem item, |
197 | AppDomain dom, string primName, string scriptName, | 216 | int startParam, bool postOnRez, |
198 | int startParam, bool postOnRez, StateSource stateSource, | 217 | int maxScriptQueue) |
199 | int maxScriptQueue) | ||
200 | { | 218 | { |
201 | State = "default"; | 219 | State = "default"; |
202 | EventQueue = new Queue(32); | 220 | EventQueue = new Queue(32); |
203 | 221 | ||
204 | Engine = engine; | 222 | Engine = engine; |
205 | LocalID = part.LocalId; | 223 | Part = part; |
206 | ObjectID = part.UUID; | 224 | ScriptTask = item; |
207 | RootLocalID = part.ParentGroup.LocalId; | 225 | |
208 | RootObjectID = part.ParentGroup.UUID; | 226 | // This is currently only here to allow regression tests to get away without specifying any inventory |
209 | ItemID = itemID; | 227 | // item when they are testing script logic that doesn't require an item. |
210 | AssetID = assetID; | 228 | if (ScriptTask != null) |
211 | PrimName = primName; | 229 | { |
212 | ScriptName = scriptName; | 230 | ScriptName = ScriptTask.Name; |
213 | m_Assembly = assembly; | 231 | ItemID = ScriptTask.ItemID; |
232 | AssetID = ScriptTask.AssetID; | ||
233 | } | ||
234 | |||
235 | PrimName = part.ParentGroup.Name; | ||
214 | StartParam = startParam; | 236 | StartParam = startParam; |
215 | m_MaxScriptQueue = maxScriptQueue; | 237 | m_MaxScriptQueue = maxScriptQueue; |
216 | m_stateSource = stateSource; | ||
217 | m_postOnRez = postOnRez; | 238 | m_postOnRez = postOnRez; |
218 | m_AttachedAvatar = part.ParentGroup.AttachedAvatar; | 239 | m_AttachedAvatar = part.ParentGroup.AttachedAvatar; |
219 | m_RegionID = part.ParentGroup.Scene.RegionInfo.RegionID; | 240 | m_RegionID = part.ParentGroup.Scene.RegionInfo.RegionID; |
220 | 241 | ||
221 | if (part != null) | 242 | if (Engine.Config.GetString("ScriptStopStrategy", "abort") == "co-op") |
222 | { | 243 | { |
223 | part.TaskInventory.LockItemsForRead(true); | 244 | m_coopTermination = true; |
224 | if (part.TaskInventory.ContainsKey(ItemID)) | 245 | m_coopSleepHandle = new AutoResetEvent(false); |
225 | { | ||
226 | ScriptTask = part.TaskInventory[ItemID]; | ||
227 | } | ||
228 | part.TaskInventory.LockItemsForRead(false); | ||
229 | } | 246 | } |
247 | } | ||
248 | |||
249 | /// <summary> | ||
250 | /// Load the script from an assembly into an AppDomain. | ||
251 | /// </summary> | ||
252 | /// <param name='dom'></param> | ||
253 | /// <param name='assembly'></param> | ||
254 | /// <param name='stateSource'></param> | ||
255 | /// <returns>false if load failed, true if suceeded</returns> | ||
256 | public bool Load(AppDomain dom, string assembly, StateSource stateSource) | ||
257 | { | ||
258 | m_Assembly = assembly; | ||
259 | m_stateSource = stateSource; | ||
230 | 260 | ||
231 | ApiManager am = new ApiManager(); | 261 | ApiManager am = new ApiManager(); |
232 | 262 | ||
233 | foreach (string api in am.GetApis()) | 263 | foreach (string api in am.GetApis()) |
234 | { | 264 | { |
235 | m_Apis[api] = am.CreateApi(api); | 265 | m_Apis[api] = am.CreateApi(api); |
236 | m_Apis[api].Initialize(engine, part, ScriptTask); | 266 | m_Apis[api].Initialize(Engine, Part, ScriptTask, m_coopSleepHandle); |
237 | } | 267 | } |
238 | 268 | ||
239 | try | 269 | try |
240 | { | 270 | { |
271 | object[] constructorParams; | ||
272 | |||
273 | Assembly scriptAssembly = dom.Load(Path.GetFileNameWithoutExtension(assembly)); | ||
274 | Type scriptType = scriptAssembly.GetType("SecondLife.XEngineScript"); | ||
275 | |||
276 | if (scriptType != null) | ||
277 | { | ||
278 | constructorParams = new object[] { m_coopSleepHandle }; | ||
279 | } | ||
280 | else if (!m_coopTermination) | ||
281 | { | ||
282 | scriptType = scriptAssembly.GetType("SecondLife.Script"); | ||
283 | constructorParams = null; | ||
284 | } | ||
285 | else | ||
286 | { | ||
287 | m_log.ErrorFormat( | ||
288 | "[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. You must remove all existing {6}* script DLL files before using enabling co-op termination" | ||
289 | + ", either by setting DeleteScriptsOnStartup = true in [XEngine] for one run" | ||
290 | + " or by deleting these files manually.", | ||
291 | ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, assembly); | ||
292 | |||
293 | return false; | ||
294 | } | ||
295 | |||
296 | // m_log.DebugFormat( | ||
297 | // "[SCRIPT INSTANCE]: Looking to load {0} from assembly {1} in {2}", | ||
298 | // scriptType.FullName, Path.GetFileNameWithoutExtension(assembly), Engine.World.Name); | ||
299 | |||
241 | if (dom != System.AppDomain.CurrentDomain) | 300 | if (dom != System.AppDomain.CurrentDomain) |
242 | m_Script = (IScript)dom.CreateInstanceAndUnwrap( | 301 | m_Script |
302 | = (IScript)dom.CreateInstanceAndUnwrap( | ||
243 | Path.GetFileNameWithoutExtension(assembly), | 303 | Path.GetFileNameWithoutExtension(assembly), |
244 | "SecondLife.Script"); | 304 | scriptType.FullName, |
305 | false, | ||
306 | BindingFlags.Default, | ||
307 | null, | ||
308 | constructorParams, | ||
309 | null, | ||
310 | null, | ||
311 | null); | ||
245 | else | 312 | else |
246 | m_Script = (IScript)Assembly.Load( | 313 | m_Script |
247 | Path.GetFileNameWithoutExtension(assembly)).CreateInstance( | 314 | = (IScript)scriptAssembly.CreateInstance( |
248 | "SecondLife.Script"); | 315 | scriptType.FullName, |
316 | false, | ||
317 | BindingFlags.Default, | ||
318 | null, | ||
319 | constructorParams, | ||
320 | null, | ||
321 | null); | ||
249 | 322 | ||
250 | //ILease lease = (ILease)RemotingServices.GetLifetimeService(m_Script as ScriptBaseClass); | 323 | //ILease lease = (ILease)RemotingServices.GetLifetimeService(m_Script as ScriptBaseClass); |
251 | //RemotingServices.GetLifetimeService(m_Script as ScriptBaseClass); | 324 | //RemotingServices.GetLifetimeService(m_Script as ScriptBaseClass); |
@@ -254,8 +327,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance | |||
254 | catch (Exception e) | 327 | catch (Exception e) |
255 | { | 328 | { |
256 | m_log.ErrorFormat( | 329 | m_log.ErrorFormat( |
257 | "[SCRIPT INSTANCE]: Error loading assembly {0}. Exception {1}{2}", | 330 | "[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. Error loading assembly {6}. Exception {7}{8}", |
258 | assembly, e.Message, e.StackTrace); | 331 | ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, assembly, e.Message, e.StackTrace); |
332 | |||
333 | return false; | ||
259 | } | 334 | } |
260 | 335 | ||
261 | try | 336 | try |
@@ -267,16 +342,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance | |||
267 | 342 | ||
268 | // // m_log.Debug("[Script] Script instance created"); | 343 | // // m_log.Debug("[Script] Script instance created"); |
269 | 344 | ||
270 | part.SetScriptEvents(ItemID, | 345 | Part.SetScriptEvents(ItemID, |
271 | (int)m_Script.GetStateEventFlags(State)); | 346 | (int)m_Script.GetStateEventFlags(State)); |
272 | } | 347 | } |
273 | catch (Exception e) | 348 | catch (Exception e) |
274 | { | 349 | { |
275 | m_log.ErrorFormat( | 350 | m_log.ErrorFormat( |
276 | "[SCRIPT INSTANCE]: Error loading script instance from assembly {0}. Exception {1}{2}", | 351 | "[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. Error initializing script instance. Exception {6}{7}", |
277 | assembly, e.Message, e.StackTrace); | 352 | ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, e.Message, e.StackTrace); |
278 | 353 | ||
279 | return; | 354 | return false; |
280 | } | 355 | } |
281 | 356 | ||
282 | m_SaveState = true; | 357 | m_SaveState = true; |
@@ -309,7 +384,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance | |||
309 | 384 | ||
310 | // m_log.DebugFormat("[Script] Successfully retrieved state for script {0}.{1}", PrimName, m_ScriptName); | 385 | // m_log.DebugFormat("[Script] Successfully retrieved state for script {0}.{1}", PrimName, m_ScriptName); |
311 | 386 | ||
312 | part.SetScriptEvents(ItemID, | 387 | Part.SetScriptEvents(ItemID, |
313 | (int)m_Script.GetStateEventFlags(State)); | 388 | (int)m_Script.GetStateEventFlags(State)); |
314 | 389 | ||
315 | if (!Running) | 390 | if (!Running) |
@@ -329,15 +404,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance | |||
329 | else | 404 | else |
330 | { | 405 | { |
331 | m_log.WarnFormat( | 406 | m_log.WarnFormat( |
332 | "[SCRIPT INSTANCE]: Unable to load script state file {0} for script {1} {2} in {3} {4} (assembly {5}). Memory limit exceeded", | 407 | "[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. Unable to load script state file {6}. Memory limit exceeded.", |
333 | savedState, ScriptName, ItemID, PrimName, ObjectID, assembly); | 408 | ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, savedState); |
334 | } | 409 | } |
335 | } | 410 | } |
336 | catch (Exception e) | 411 | catch (Exception e) |
337 | { | 412 | { |
338 | m_log.ErrorFormat( | 413 | m_log.ErrorFormat( |
339 | "[SCRIPT INSTANCE]: Unable to load script state file {0} for script {1} {2} in {3} {4} (assembly {5}). XML is {6}. Exception {7}{8}", | 414 | "[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. Unable to load script state file {6}. XML is {7}. Exception {8}{9}", |
340 | savedState, ScriptName, ItemID, PrimName, ObjectID, assembly, xml, e.Message, e.StackTrace); | 415 | ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, savedState, xml, e.Message, e.StackTrace); |
341 | } | 416 | } |
342 | } | 417 | } |
343 | // else | 418 | // else |
@@ -348,6 +423,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance | |||
348 | // presence.ControllingClient.SendAgentAlertMessage("Compile successful", false); | 423 | // presence.ControllingClient.SendAgentAlertMessage("Compile successful", false); |
349 | 424 | ||
350 | // } | 425 | // } |
426 | |||
427 | return true; | ||
351 | } | 428 | } |
352 | 429 | ||
353 | public void Init() | 430 | public void Init() |
@@ -521,9 +598,36 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance | |||
521 | } | 598 | } |
522 | 599 | ||
523 | // Wait for the current event to complete. | 600 | // Wait for the current event to complete. |
524 | if (!m_InSelfDelete && workItem.Wait(new TimeSpan((long)timeout * 100000))) | 601 | if (!m_InSelfDelete) |
525 | { | 602 | { |
526 | return true; | 603 | if (!m_coopTermination) |
604 | { | ||
605 | // If we're not co-operative terminating then try and wait for the event to complete before stopping | ||
606 | if (workItem.Wait(timeout)) | ||
607 | return true; | ||
608 | } | ||
609 | else | ||
610 | { | ||
611 | if (DebugLevel >= 1) | ||
612 | m_log.DebugFormat( | ||
613 | "[SCRIPT INSTANCE]: Co-operatively stopping script {0} {1} in {2} {3}", | ||
614 | ScriptName, ItemID, PrimName, ObjectID); | ||
615 | |||
616 | // This will terminate the event on next handle check by the script. | ||
617 | m_coopSleepHandle.Set(); | ||
618 | |||
619 | // For now, we will wait forever since the event should always cleanly terminate once LSL loop | ||
620 | // checking is implemented. May want to allow a shorter timeout option later. | ||
621 | if (workItem.Wait(Timeout.Infinite)) | ||
622 | { | ||
623 | if (DebugLevel >= 1) | ||
624 | m_log.DebugFormat( | ||
625 | "[SCRIPT INSTANCE]: Co-operatively stopped script {0} {1} in {2} {3}", | ||
626 | ScriptName, ItemID, PrimName, ObjectID); | ||
627 | |||
628 | return true; | ||
629 | } | ||
630 | } | ||
527 | } | 631 | } |
528 | 632 | ||
529 | lock (EventQueue) | 633 | lock (EventQueue) |
@@ -536,11 +640,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance | |||
536 | 640 | ||
537 | // If the event still hasn't stopped and we the stop isn't the result of script or object removal, then | 641 | // If the event still hasn't stopped and we the stop isn't the result of script or object removal, then |
538 | // forcibly abort the work item (this aborts the underlying thread). | 642 | // forcibly abort the work item (this aborts the underlying thread). |
643 | // Co-operative termination should never reach this point. | ||
539 | if (!m_InSelfDelete) | 644 | if (!m_InSelfDelete) |
540 | { | 645 | { |
541 | // m_log.ErrorFormat( | 646 | m_log.DebugFormat( |
542 | // "[SCRIPT INSTANCE]: Aborting script {0} {1} in prim {2} {3} {4} {5}", | 647 | "[SCRIPT INSTANCE]: Aborting unstopped script {0} {1} in prim {2}, localID {3}, timeout was {4} ms", |
543 | // ScriptName, ItemID, PrimName, ObjectID, m_InSelfDelete, DateTime.Now.Ticks); | 648 | ScriptName, ItemID, PrimName, LocalID, timeout); |
544 | 649 | ||
545 | workItem.Abort(); | 650 | workItem.Abort(); |
546 | } | 651 | } |
@@ -696,19 +801,41 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance | |||
696 | { | 801 | { |
697 | 802 | ||
698 | // m_log.DebugFormat("[XEngine]: Processing event {0} for {1}", data.EventName, this); | 803 | // m_log.DebugFormat("[XEngine]: Processing event {0} for {1}", data.EventName, this); |
804 | SceneObjectPart part = Engine.World.GetSceneObjectPart(LocalID); | ||
805 | |||
806 | if (DebugLevel >= 2) | ||
807 | m_log.DebugFormat( | ||
808 | "[SCRIPT INSTANCE]: Processing event {0} for {1}/{2}({3})/{4}({5}) @ {6}/{7}", | ||
809 | data.EventName, | ||
810 | ScriptName, | ||
811 | part.Name, | ||
812 | part.LocalId, | ||
813 | part.ParentGroup.Name, | ||
814 | part.ParentGroup.UUID, | ||
815 | part.AbsolutePosition, | ||
816 | part.ParentGroup.Scene.Name); | ||
699 | 817 | ||
700 | m_DetectParams = data.DetectParams; | 818 | m_DetectParams = data.DetectParams; |
701 | 819 | ||
702 | if (data.EventName == "state") // Hardcoded state change | 820 | if (data.EventName == "state") // Hardcoded state change |
703 | { | 821 | { |
704 | // m_log.DebugFormat("[Script] Script {0}.{1} state set to {2}", | ||
705 | // PrimName, ScriptName, data.Params[0].ToString()); | ||
706 | State = data.Params[0].ToString(); | 822 | State = data.Params[0].ToString(); |
823 | |||
824 | if (DebugLevel >= 1) | ||
825 | m_log.DebugFormat( | ||
826 | "[SCRIPT INSTANCE]: Changing state to {0} for {1}/{2}({3})/{4}({5}) @ {6}/{7}", | ||
827 | State, | ||
828 | ScriptName, | ||
829 | part.Name, | ||
830 | part.LocalId, | ||
831 | part.ParentGroup.Name, | ||
832 | part.ParentGroup.UUID, | ||
833 | part.AbsolutePosition, | ||
834 | part.ParentGroup.Scene.Name); | ||
835 | |||
707 | AsyncCommandManager.RemoveScript(Engine, | 836 | AsyncCommandManager.RemoveScript(Engine, |
708 | LocalID, ItemID); | 837 | LocalID, ItemID); |
709 | 838 | ||
710 | SceneObjectPart part = Engine.World.GetSceneObjectPart( | ||
711 | LocalID); | ||
712 | if (part != null) | 839 | if (part != null) |
713 | { | 840 | { |
714 | part.SetScriptEvents(ItemID, | 841 | part.SetScriptEvents(ItemID, |
@@ -720,8 +847,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance | |||
720 | if (Engine.World.PipeEventsForScript(LocalID) || | 847 | if (Engine.World.PipeEventsForScript(LocalID) || |
721 | data.EventName == "control") // Don't freeze avies! | 848 | data.EventName == "control") // Don't freeze avies! |
722 | { | 849 | { |
723 | SceneObjectPart part = Engine.World.GetSceneObjectPart( | ||
724 | LocalID); | ||
725 | // m_log.DebugFormat("[Script] Delivered event {2} in state {3} to {0}.{1}", | 850 | // m_log.DebugFormat("[Script] Delivered event {2} in state {3} to {0}.{1}", |
726 | // PrimName, ScriptName, data.EventName, State); | 851 | // PrimName, ScriptName, data.EventName, State); |
727 | 852 | ||
@@ -763,7 +888,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance | |||
763 | m_InEvent = false; | 888 | m_InEvent = false; |
764 | m_CurrentEvent = String.Empty; | 889 | m_CurrentEvent = String.Empty; |
765 | 890 | ||
766 | if ((!(e is TargetInvocationException) || (!(e.InnerException is SelfDeleteException) && !(e.InnerException is ScriptDeleteException))) && !(e is ThreadAbortException)) | 891 | if ((!(e is TargetInvocationException) |
892 | || (!(e.InnerException is SelfDeleteException) | ||
893 | && !(e.InnerException is ScriptDeleteException) | ||
894 | && !(e.InnerException is ScriptCoopStopException))) | ||
895 | && !(e is ThreadAbortException)) | ||
767 | { | 896 | { |
768 | try | 897 | try |
769 | { | 898 | { |
@@ -776,6 +905,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance | |||
776 | ChatTypeEnum.DebugChannel, 2147483647, | 905 | ChatTypeEnum.DebugChannel, 2147483647, |
777 | part.AbsolutePosition, | 906 | part.AbsolutePosition, |
778 | part.Name, part.UUID, false); | 907 | part.Name, part.UUID, false); |
908 | |||
909 | |||
910 | m_log.DebugFormat( | ||
911 | "[SCRIPT INSTANCE]: Runtime error in script {0}, part {1} {2} at {3} in {4}, displayed error {5}, actual exception {6}", | ||
912 | ScriptName, | ||
913 | PrimName, | ||
914 | part.UUID, | ||
915 | part.AbsolutePosition, | ||
916 | part.ParentGroup.Scene.Name, | ||
917 | text.Replace("\n", "\\n"), | ||
918 | e.InnerException); | ||
779 | } | 919 | } |
780 | catch (Exception) | 920 | catch (Exception) |
781 | { | 921 | { |
@@ -802,6 +942,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance | |||
802 | if (part != null) | 942 | if (part != null) |
803 | part.Inventory.RemoveInventoryItem(ItemID); | 943 | part.Inventory.RemoveInventoryItem(ItemID); |
804 | } | 944 | } |
945 | else if ((e is TargetInvocationException) && (e.InnerException is ScriptCoopStopException)) | ||
946 | { | ||
947 | if (DebugLevel >= 1) | ||
948 | m_log.DebugFormat( | ||
949 | "[SCRIPT INSTANCE]: Script {0}.{1} in event {2}, state {3} stopped co-operatively.", | ||
950 | PrimName, ScriptName, data.EventName, State); | ||
951 | } | ||
805 | } | 952 | } |
806 | } | 953 | } |
807 | } | 954 | } |
@@ -810,6 +957,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance | |||
810 | // script engine to run the next event. | 957 | // script engine to run the next event. |
811 | lock (EventQueue) | 958 | lock (EventQueue) |
812 | { | 959 | { |
960 | EventsProcessed++; | ||
961 | |||
813 | if (EventQueue.Count > 0 && Running && !ShuttingDown) | 962 | if (EventQueue.Count > 0 && Running && !ShuttingDown) |
814 | { | 963 | { |
815 | m_CurrentWorkItem = Engine.QueueEventHandler(this); | 964 | m_CurrentWorkItem = Engine.QueueEventHandler(this); |
@@ -834,7 +983,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance | |||
834 | return (DateTime.Now - m_EventStart).Seconds; | 983 | return (DateTime.Now - m_EventStart).Seconds; |
835 | } | 984 | } |
836 | 985 | ||
837 | public void ResetScript() | 986 | public void ResetScript(int timeout) |
838 | { | 987 | { |
839 | if (m_Script == null) | 988 | if (m_Script == null) |
840 | return; | 989 | return; |
@@ -844,7 +993,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance | |||
844 | RemoveState(); | 993 | RemoveState(); |
845 | ReleaseControls(); | 994 | ReleaseControls(); |
846 | 995 | ||
847 | Stop(0); | 996 | Stop(timeout); |
848 | SceneObjectPart part = Engine.World.GetSceneObjectPart(LocalID); | 997 | SceneObjectPart part = Engine.World.GetSceneObjectPart(LocalID); |
849 | part.Inventory.GetInventoryItem(ItemID).PermsMask = 0; | 998 | part.Inventory.GetInventoryItem(ItemID).PermsMask = 0; |
850 | part.Inventory.GetInventoryItem(ItemID).PermsGranter = UUID.Zero; | 999 | part.Inventory.GetInventoryItem(ItemID).PermsGranter = UUID.Zero; |
@@ -1015,7 +1164,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance | |||
1015 | "({0}): {1}", scriptLine - 1, | 1164 | "({0}): {1}", scriptLine - 1, |
1016 | e.InnerException.Message); | 1165 | e.InnerException.Message); |
1017 | 1166 | ||
1018 | System.Console.WriteLine(e.ToString()+"\n"); | ||
1019 | return message; | 1167 | return message; |
1020 | } | 1168 | } |
1021 | } | 1169 | } |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs new file mode 100644 index 0000000..ac822c6 --- /dev/null +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs | |||
@@ -0,0 +1,513 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Threading; | ||
31 | using Nini.Config; | ||
32 | using NUnit.Framework; | ||
33 | using OpenMetaverse; | ||
34 | using OpenSim.Framework; | ||
35 | using OpenSim.Region.CoreModules.Scripting.WorldComm; | ||
36 | using OpenSim.Region.Framework.Scenes; | ||
37 | using OpenSim.Region.Framework.Interfaces; | ||
38 | using OpenSim.Region.ScriptEngine.XEngine; | ||
39 | using OpenSim.Tests.Common; | ||
40 | using OpenSim.Tests.Common.Mock; | ||
41 | |||
42 | namespace OpenSim.Region.ScriptEngine.Shared.Instance.Tests | ||
43 | { | ||
44 | /// <summary> | ||
45 | /// Test that co-operative script thread termination is working correctly. | ||
46 | /// </summary> | ||
47 | [TestFixture] | ||
48 | public class CoopTerminationTests : OpenSimTestCase | ||
49 | { | ||
50 | private TestScene m_scene; | ||
51 | private OpenSim.Region.ScriptEngine.XEngine.XEngine m_xEngine; | ||
52 | |||
53 | private AutoResetEvent m_chatEvent; | ||
54 | private AutoResetEvent m_stoppedEvent; | ||
55 | |||
56 | private OSChatMessage m_osChatMessageReceived; | ||
57 | |||
58 | /// <summary> | ||
59 | /// Number of chat messages received so far. Reset before each test. | ||
60 | /// </summary> | ||
61 | private int m_chatMessagesReceived; | ||
62 | |||
63 | /// <summary> | ||
64 | /// Number of chat messages expected. m_chatEvent is not fired until this number is reached or exceeded. | ||
65 | /// </summary> | ||
66 | private int m_chatMessagesThreshold; | ||
67 | |||
68 | [SetUp] | ||
69 | public void Init() | ||
70 | { | ||
71 | m_osChatMessageReceived = null; | ||
72 | m_chatMessagesReceived = 0; | ||
73 | m_chatMessagesThreshold = 0; | ||
74 | m_chatEvent = new AutoResetEvent(false); | ||
75 | m_stoppedEvent = new AutoResetEvent(false); | ||
76 | |||
77 | //AppDomain.CurrentDomain.SetData("APPBASE", Environment.CurrentDirectory + "/bin"); | ||
78 | // Console.WriteLine(AppDomain.CurrentDomain.BaseDirectory); | ||
79 | m_xEngine = new OpenSim.Region.ScriptEngine.XEngine.XEngine(); | ||
80 | |||
81 | IniConfigSource configSource = new IniConfigSource(); | ||
82 | |||
83 | IConfig startupConfig = configSource.AddConfig("Startup"); | ||
84 | startupConfig.Set("DefaultScriptEngine", "XEngine"); | ||
85 | |||
86 | IConfig xEngineConfig = configSource.AddConfig("XEngine"); | ||
87 | xEngineConfig.Set("Enabled", "true"); | ||
88 | xEngineConfig.Set("StartDelay", "0"); | ||
89 | |||
90 | // These tests will not run with AppDomainLoading = true, at least on mono. For unknown reasons, the call | ||
91 | // to AssemblyResolver.OnAssemblyResolve fails. | ||
92 | xEngineConfig.Set("AppDomainLoading", "false"); | ||
93 | |||
94 | xEngineConfig.Set("ScriptStopStrategy", "co-op"); | ||
95 | |||
96 | // Make sure loops aren't actually being terminated by a script delay wait. | ||
97 | xEngineConfig.Set("ScriptDelayFactor", 0); | ||
98 | |||
99 | // This is really just set for debugging the test. | ||
100 | xEngineConfig.Set("WriteScriptSourceToDebugFile", true); | ||
101 | |||
102 | // Set to false if we need to debug test so the old scripts don't get wiped before each separate test | ||
103 | // xEngineConfig.Set("DeleteScriptsOnStartup", false); | ||
104 | |||
105 | // This is not currently used at all for co-op termination. Bumping up to demonstrate that co-op termination | ||
106 | // has an effect - without it tests will fail due to a 120 second wait for the event to finish. | ||
107 | xEngineConfig.Set("WaitForEventCompletionOnScriptStop", 120000); | ||
108 | |||
109 | m_scene = new SceneHelpers().SetupScene("My Test", TestHelpers.ParseTail(0x9999), 1000, 1000, configSource); | ||
110 | SceneHelpers.SetupSceneModules(m_scene, configSource, m_xEngine); | ||
111 | m_scene.StartScripts(); | ||
112 | } | ||
113 | |||
114 | /// <summary> | ||
115 | /// Test co-operative termination on derez of an object containing a script with a long-running event. | ||
116 | /// </summary> | ||
117 | /// <remarks> | ||
118 | /// TODO: Actually compiling the script is incidental to this test. Really want a way to compile test scripts | ||
119 | /// within the build itself. | ||
120 | /// </remarks> | ||
121 | [Test] | ||
122 | public void TestStopOnLongSleep() | ||
123 | { | ||
124 | TestHelpers.InMethod(); | ||
125 | // TestHelpers.EnableLogging(); | ||
126 | |||
127 | string script = | ||
128 | @"default | ||
129 | { | ||
130 | state_entry() | ||
131 | { | ||
132 | llSay(0, ""Thin Lizzy""); | ||
133 | llSleep(60); | ||
134 | } | ||
135 | }"; | ||
136 | |||
137 | TestStop(script); | ||
138 | } | ||
139 | |||
140 | [Test] | ||
141 | public void TestNoStopOnSingleStatementForLoop() | ||
142 | { | ||
143 | TestHelpers.InMethod(); | ||
144 | // TestHelpers.EnableLogging(); | ||
145 | |||
146 | string script = | ||
147 | @"default | ||
148 | { | ||
149 | state_entry() | ||
150 | { | ||
151 | integer i = 0; | ||
152 | for (i = 0; i <= 1; i++) llSay(0, ""Iter "" + (string)i); | ||
153 | } | ||
154 | }"; | ||
155 | |||
156 | TestSingleStatementNoStop(script); | ||
157 | } | ||
158 | |||
159 | [Test] | ||
160 | public void TestStopOnLongSingleStatementForLoop() | ||
161 | { | ||
162 | TestHelpers.InMethod(); | ||
163 | // TestHelpers.EnableLogging(); | ||
164 | |||
165 | string script = | ||
166 | @"default | ||
167 | { | ||
168 | state_entry() | ||
169 | { | ||
170 | integer i = 0; | ||
171 | llSay(0, ""Thin Lizzy""); | ||
172 | |||
173 | for (i = 0; i < 2147483647; i++) llSay(0, ""Iter "" + (string)i); | ||
174 | } | ||
175 | }"; | ||
176 | |||
177 | TestStop(script); | ||
178 | } | ||
179 | |||
180 | [Test] | ||
181 | public void TestStopOnLongCompoundStatementForLoop() | ||
182 | { | ||
183 | TestHelpers.InMethod(); | ||
184 | // TestHelpers.EnableLogging(); | ||
185 | |||
186 | string script = | ||
187 | @"default | ||
188 | { | ||
189 | state_entry() | ||
190 | { | ||
191 | integer i = 0; | ||
192 | llSay(0, ""Thin Lizzy""); | ||
193 | |||
194 | for (i = 0; i < 2147483647; i++) | ||
195 | { | ||
196 | llSay(0, ""Iter "" + (string)i); | ||
197 | } | ||
198 | } | ||
199 | }"; | ||
200 | |||
201 | TestStop(script); | ||
202 | } | ||
203 | |||
204 | [Test] | ||
205 | public void TestNoStopOnSingleStatementWhileLoop() | ||
206 | { | ||
207 | TestHelpers.InMethod(); | ||
208 | // TestHelpers.EnableLogging(); | ||
209 | |||
210 | string script = | ||
211 | @"default | ||
212 | { | ||
213 | state_entry() | ||
214 | { | ||
215 | integer i = 0; | ||
216 | while (i < 2) llSay(0, ""Iter "" + (string)i++); | ||
217 | } | ||
218 | }"; | ||
219 | |||
220 | TestSingleStatementNoStop(script); | ||
221 | } | ||
222 | |||
223 | [Test] | ||
224 | public void TestStopOnLongSingleStatementWhileLoop() | ||
225 | { | ||
226 | TestHelpers.InMethod(); | ||
227 | // TestHelpers.EnableLogging(); | ||
228 | |||
229 | string script = | ||
230 | @"default | ||
231 | { | ||
232 | state_entry() | ||
233 | { | ||
234 | integer i = 0; | ||
235 | llSay(0, ""Thin Lizzy""); | ||
236 | |||
237 | while (1 == 1) | ||
238 | llSay(0, ""Iter "" + (string)i++); | ||
239 | } | ||
240 | }"; | ||
241 | |||
242 | TestStop(script); | ||
243 | } | ||
244 | |||
245 | [Test] | ||
246 | public void TestStopOnLongCompoundStatementWhileLoop() | ||
247 | { | ||
248 | TestHelpers.InMethod(); | ||
249 | // TestHelpers.EnableLogging(); | ||
250 | |||
251 | string script = | ||
252 | @"default | ||
253 | { | ||
254 | state_entry() | ||
255 | { | ||
256 | integer i = 0; | ||
257 | llSay(0, ""Thin Lizzy""); | ||
258 | |||
259 | while (1 == 1) | ||
260 | { | ||
261 | llSay(0, ""Iter "" + (string)i++); | ||
262 | } | ||
263 | } | ||
264 | }"; | ||
265 | |||
266 | TestStop(script); | ||
267 | } | ||
268 | |||
269 | [Test] | ||
270 | public void TestNoStopOnSingleStatementDoWhileLoop() | ||
271 | { | ||
272 | TestHelpers.InMethod(); | ||
273 | // TestHelpers.EnableLogging(); | ||
274 | |||
275 | string script = | ||
276 | @"default | ||
277 | { | ||
278 | state_entry() | ||
279 | { | ||
280 | integer i = 0; | ||
281 | |||
282 | do llSay(0, ""Iter "" + (string)i++); | ||
283 | while (i < 2); | ||
284 | } | ||
285 | }"; | ||
286 | |||
287 | TestSingleStatementNoStop(script); | ||
288 | } | ||
289 | |||
290 | [Test] | ||
291 | public void TestStopOnLongSingleStatementDoWhileLoop() | ||
292 | { | ||
293 | TestHelpers.InMethod(); | ||
294 | // TestHelpers.EnableLogging(); | ||
295 | |||
296 | string script = | ||
297 | @"default | ||
298 | { | ||
299 | state_entry() | ||
300 | { | ||
301 | integer i = 0; | ||
302 | llSay(0, ""Thin Lizzy""); | ||
303 | |||
304 | do llSay(0, ""Iter "" + (string)i++); | ||
305 | while (1 == 1); | ||
306 | } | ||
307 | }"; | ||
308 | |||
309 | TestStop(script); | ||
310 | } | ||
311 | |||
312 | [Test] | ||
313 | public void TestStopOnLongCompoundStatementDoWhileLoop() | ||
314 | { | ||
315 | TestHelpers.InMethod(); | ||
316 | // TestHelpers.EnableLogging(); | ||
317 | |||
318 | string script = | ||
319 | @"default | ||
320 | { | ||
321 | state_entry() | ||
322 | { | ||
323 | integer i = 0; | ||
324 | llSay(0, ""Thin Lizzy""); | ||
325 | |||
326 | do | ||
327 | { | ||
328 | llSay(0, ""Iter "" + (string)i++); | ||
329 | } while (1 == 1); | ||
330 | } | ||
331 | }"; | ||
332 | |||
333 | TestStop(script); | ||
334 | } | ||
335 | |||
336 | [Test] | ||
337 | public void TestStopOnInfiniteJumpLoop() | ||
338 | { | ||
339 | TestHelpers.InMethod(); | ||
340 | // TestHelpers.EnableLogging(); | ||
341 | |||
342 | string script = | ||
343 | @"default | ||
344 | { | ||
345 | state_entry() | ||
346 | { | ||
347 | integer i = 0; | ||
348 | llSay(0, ""Thin Lizzy""); | ||
349 | |||
350 | @p1; | ||
351 | llSay(0, ""Iter "" + (string)i++); | ||
352 | jump p1; | ||
353 | } | ||
354 | }"; | ||
355 | |||
356 | TestStop(script); | ||
357 | } | ||
358 | |||
359 | // Disabling for now as these are not particularly useful tests (since they fail due to stack overflow before | ||
360 | // termination can even be tried. | ||
361 | // [Test] | ||
362 | public void TestStopOnInfiniteUserFunctionCallLoop() | ||
363 | { | ||
364 | TestHelpers.InMethod(); | ||
365 | // TestHelpers.EnableLogging(); | ||
366 | |||
367 | string script = | ||
368 | @" | ||
369 | integer i = 0; | ||
370 | |||
371 | ufn1() | ||
372 | { | ||
373 | llSay(0, ""Iter ufn1() "" + (string)i++); | ||
374 | ufn1(); | ||
375 | } | ||
376 | |||
377 | default | ||
378 | { | ||
379 | state_entry() | ||
380 | { | ||
381 | integer i = 0; | ||
382 | llSay(0, ""Thin Lizzy""); | ||
383 | |||
384 | ufn1(); | ||
385 | } | ||
386 | }"; | ||
387 | |||
388 | TestStop(script); | ||
389 | } | ||
390 | |||
391 | // Disabling for now as these are not particularly useful tests (since they fail due to stack overflow before | ||
392 | // termination can even be tried. | ||
393 | // [Test] | ||
394 | public void TestStopOnInfiniteManualEventCallLoop() | ||
395 | { | ||
396 | TestHelpers.InMethod(); | ||
397 | // TestHelpers.EnableLogging(); | ||
398 | |||
399 | string script = | ||
400 | @"default | ||
401 | { | ||
402 | state_entry() | ||
403 | { | ||
404 | integer i = 0; | ||
405 | llSay(0, ""Thin Lizzy""); | ||
406 | |||
407 | llSay(0, ""Iter"" + (string)i++); | ||
408 | default_event_state_entry(); | ||
409 | } | ||
410 | }"; | ||
411 | |||
412 | TestStop(script); | ||
413 | } | ||
414 | |||
415 | private SceneObjectPart CreateScript(string script, string itemName, UUID userId) | ||
416 | { | ||
417 | // UUID objectId = TestHelpers.ParseTail(0x100); | ||
418 | // UUID itemId = TestHelpers.ParseTail(0x3); | ||
419 | |||
420 | SceneObjectGroup so | ||
421 | = SceneHelpers.CreateSceneObject(1, userId, string.Format("Object for {0}", itemName), 0x100); | ||
422 | m_scene.AddNewSceneObject(so, true); | ||
423 | |||
424 | InventoryItemBase itemTemplate = new InventoryItemBase(); | ||
425 | // itemTemplate.ID = itemId; | ||
426 | itemTemplate.Name = itemName; | ||
427 | itemTemplate.Folder = so.UUID; | ||
428 | itemTemplate.InvType = (int)InventoryType.LSL; | ||
429 | |||
430 | m_scene.EventManager.OnChatFromWorld += OnChatFromWorld; | ||
431 | |||
432 | return m_scene.RezNewScript(userId, itemTemplate, script); | ||
433 | } | ||
434 | |||
435 | private void TestSingleStatementNoStop(string script) | ||
436 | { | ||
437 | // In these tests we expect to see at least 2 chat messages to confirm that the loop is working properly. | ||
438 | m_chatMessagesThreshold = 2; | ||
439 | |||
440 | UUID userId = TestHelpers.ParseTail(0x1); | ||
441 | // UUID objectId = TestHelpers.ParseTail(0x100); | ||
442 | // UUID itemId = TestHelpers.ParseTail(0x3); | ||
443 | string itemName = "TestNoStop"; | ||
444 | |||
445 | SceneObjectPart partWhereRezzed = CreateScript(script, itemName, userId); | ||
446 | |||
447 | // Wait for the script to start the event before we try stopping it. | ||
448 | m_chatEvent.WaitOne(60000); | ||
449 | |||
450 | if (m_osChatMessageReceived == null) | ||
451 | Assert.Fail("Script did not start"); | ||
452 | else | ||
453 | Assert.That(m_chatMessagesReceived, Is.EqualTo(2)); | ||
454 | |||
455 | bool running; | ||
456 | TaskInventoryItem scriptItem = partWhereRezzed.Inventory.GetInventoryItem(itemName); | ||
457 | Assert.That( | ||
458 | SceneObjectPartInventory.TryGetScriptInstanceRunning(m_scene, scriptItem, out running), Is.True); | ||
459 | Assert.That(running, Is.True); | ||
460 | } | ||
461 | |||
462 | private void TestStop(string script) | ||
463 | { | ||
464 | // In these tests we're only interested in the first message to confirm that the script has started. | ||
465 | m_chatMessagesThreshold = 1; | ||
466 | |||
467 | UUID userId = TestHelpers.ParseTail(0x1); | ||
468 | // UUID objectId = TestHelpers.ParseTail(0x100); | ||
469 | // UUID itemId = TestHelpers.ParseTail(0x3); | ||
470 | string itemName = "TestStop"; | ||
471 | |||
472 | SceneObjectPart partWhereRezzed = CreateScript(script, itemName, userId); | ||
473 | TaskInventoryItem rezzedItem = partWhereRezzed.Inventory.GetInventoryItem(itemName); | ||
474 | |||
475 | // Wait for the script to start the event before we try stopping it. | ||
476 | m_chatEvent.WaitOne(60000); | ||
477 | |||
478 | if (m_osChatMessageReceived != null) | ||
479 | Console.WriteLine("Script started with message [{0}]", m_osChatMessageReceived.Message); | ||
480 | else | ||
481 | Assert.Fail("Script did not start"); | ||
482 | |||
483 | // FIXME: This is a very poor way of trying to avoid a low-probability race condition where the script | ||
484 | // executes llSay() but has not started the next statement before we try to stop it. | ||
485 | Thread.Sleep(1000); | ||
486 | |||
487 | // We need a way of carrying on if StopScript() fail, since it won't return if the script isn't actually | ||
488 | // stopped. This kind of multi-threading is far from ideal in a regression test. | ||
489 | new Thread(() => { m_xEngine.StopScript(rezzedItem.ItemID); m_stoppedEvent.Set(); }).Start(); | ||
490 | |||
491 | if (!m_stoppedEvent.WaitOne(30000)) | ||
492 | Assert.Fail("Script did not co-operatively stop."); | ||
493 | |||
494 | bool running; | ||
495 | TaskInventoryItem scriptItem = partWhereRezzed.Inventory.GetInventoryItem(itemName); | ||
496 | Assert.That( | ||
497 | SceneObjectPartInventory.TryGetScriptInstanceRunning(m_scene, scriptItem, out running), Is.True); | ||
498 | Assert.That(running, Is.False); | ||
499 | } | ||
500 | |||
501 | private void OnChatFromWorld(object sender, OSChatMessage oscm) | ||
502 | { | ||
503 | Console.WriteLine("Got chat [{0}]", oscm.Message); | ||
504 | m_osChatMessageReceived = oscm; | ||
505 | |||
506 | if (++m_chatMessagesReceived >= m_chatMessagesThreshold) | ||
507 | { | ||
508 | m_scene.EventManager.OnChatFromWorld -= OnChatFromWorld; | ||
509 | m_chatEvent.Set(); | ||
510 | } | ||
511 | } | ||
512 | } | ||
513 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs b/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs index c9c4753..b524a18 100644 --- a/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs +++ b/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs | |||
@@ -512,7 +512,7 @@ namespace OpenSim.Region.ScriptEngine.Shared | |||
512 | else if (o is LSL_Types.LSLFloat) | 512 | else if (o is LSL_Types.LSLFloat) |
513 | size += 8; | 513 | size += 8; |
514 | else if (o is LSL_Types.LSLString) | 514 | else if (o is LSL_Types.LSLString) |
515 | size += ((LSL_Types.LSLString)o).m_string.Length; | 515 | size += ((LSL_Types.LSLString)o).m_string == null ? 0 : ((LSL_Types.LSLString)o).m_string.Length; |
516 | else if (o is LSL_Types.key) | 516 | else if (o is LSL_Types.key) |
517 | size += ((LSL_Types.key)o).value.Length; | 517 | size += ((LSL_Types.key)o).value.Length; |
518 | else if (o is LSL_Types.Vector3) | 518 | else if (o is LSL_Types.Vector3) |
@@ -633,19 +633,44 @@ namespace OpenSim.Region.ScriptEngine.Shared | |||
633 | 633 | ||
634 | public LSL_Types.Vector3 GetVector3Item(int itemIndex) | 634 | public LSL_Types.Vector3 GetVector3Item(int itemIndex) |
635 | { | 635 | { |
636 | if(m_data[itemIndex] is LSL_Types.Vector3) | 636 | if (m_data[itemIndex] is LSL_Types.Vector3) |
637 | { | ||
637 | return (LSL_Types.Vector3)m_data[itemIndex]; | 638 | return (LSL_Types.Vector3)m_data[itemIndex]; |
639 | } | ||
640 | else if(m_data[itemIndex] is OpenMetaverse.Vector3) | ||
641 | { | ||
642 | return new LSL_Types.Vector3( | ||
643 | (OpenMetaverse.Vector3)m_data[itemIndex]); | ||
644 | } | ||
638 | else | 645 | else |
646 | { | ||
639 | throw new InvalidCastException(string.Format( | 647 | throw new InvalidCastException(string.Format( |
640 | "{0} expected but {1} given", | 648 | "{0} expected but {1} given", |
641 | typeof(LSL_Types.Vector3).Name, | 649 | typeof(LSL_Types.Vector3).Name, |
642 | m_data[itemIndex] != null ? | 650 | m_data[itemIndex] != null ? |
643 | m_data[itemIndex].GetType().Name : "null")); | 651 | m_data[itemIndex].GetType().Name : "null")); |
652 | } | ||
644 | } | 653 | } |
645 | 654 | ||
646 | public LSL_Types.Quaternion GetQuaternionItem(int itemIndex) | 655 | public LSL_Types.Quaternion GetQuaternionItem(int itemIndex) |
647 | { | 656 | { |
648 | return (LSL_Types.Quaternion)m_data[itemIndex]; | 657 | if (m_data[itemIndex] is LSL_Types.Quaternion) |
658 | { | ||
659 | return (LSL_Types.Quaternion)m_data[itemIndex]; | ||
660 | } | ||
661 | else if(m_data[itemIndex] is OpenMetaverse.Quaternion) | ||
662 | { | ||
663 | return new LSL_Types.Quaternion( | ||
664 | (OpenMetaverse.Quaternion)m_data[itemIndex]); | ||
665 | } | ||
666 | else | ||
667 | { | ||
668 | throw new InvalidCastException(string.Format( | ||
669 | "{0} expected but {1} given", | ||
670 | typeof(LSL_Types.Quaternion).Name, | ||
671 | m_data[itemIndex] != null ? | ||
672 | m_data[itemIndex].GetType().Name : "null")); | ||
673 | } | ||
649 | } | 674 | } |
650 | 675 | ||
651 | public LSL_Types.key GetKeyItem(int itemIndex) | 676 | public LSL_Types.key GetKeyItem(int itemIndex) |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Properties/AssemblyInfo.cs b/OpenSim/Region/ScriptEngine/Shared/Properties/AssemblyInfo.cs index e6e8777..d08b0a6 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Properties/AssemblyInfo.cs | |||
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices; | |||
29 | // Build Number | 29 | // Build Number |
30 | // Revision | 30 | // Revision |
31 | // | 31 | // |
32 | [assembly: AssemblyVersion("0.7.5.*")] | 32 | [assembly: AssemblyVersion("0.7.6.*")] |
33 | [assembly: AssemblyFileVersion("1.0.0.0")] | 33 | [assembly: AssemblyFileVersion("1.0.0.0")] |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiHttpTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiHttpTests.cs new file mode 100644 index 0000000..ab44e38 --- /dev/null +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiHttpTests.cs | |||
@@ -0,0 +1,249 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.IO; | ||
31 | using System.Net; | ||
32 | using System.Reflection; | ||
33 | using System.Text; | ||
34 | using log4net; | ||
35 | using Nini.Config; | ||
36 | using NUnit.Framework; | ||
37 | using OpenMetaverse; | ||
38 | using OpenSim.Framework; | ||
39 | using OpenSim.Framework.Servers; | ||
40 | using OpenSim.Framework.Servers.HttpServer; | ||
41 | using OpenSim.Region.CoreModules.Scripting.LSLHttp; | ||
42 | using OpenSim.Region.Framework.Scenes; | ||
43 | using OpenSim.Region.ScriptEngine.Shared; | ||
44 | using OpenSim.Region.ScriptEngine.Shared.Api; | ||
45 | using OpenSim.Region.ScriptEngine.Shared.ScriptBase; | ||
46 | using OpenSim.Services.Interfaces; | ||
47 | using OpenSim.Tests.Common; | ||
48 | using OpenSim.Tests.Common.Mock; | ||
49 | |||
50 | namespace OpenSim.Region.ScriptEngine.Shared.Tests | ||
51 | { | ||
52 | /// <summary> | ||
53 | /// Tests for HTTP related functions in LSL | ||
54 | /// </summary> | ||
55 | [TestFixture] | ||
56 | public class LSL_ApiHttpTests : OpenSimTestCase | ||
57 | { | ||
58 | private Scene m_scene; | ||
59 | private MockScriptEngine m_engine; | ||
60 | private UrlModule m_urlModule; | ||
61 | |||
62 | private TaskInventoryItem m_scriptItem; | ||
63 | private LSL_Api m_lslApi; | ||
64 | |||
65 | [TestFixtureSetUp] | ||
66 | public void TestFixtureSetUp() | ||
67 | { | ||
68 | // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread. | ||
69 | Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest; | ||
70 | } | ||
71 | |||
72 | [TestFixtureTearDown] | ||
73 | public void TestFixureTearDown() | ||
74 | { | ||
75 | // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple | ||
76 | // threads. Possibly, later tests should be rewritten so none of them require async stuff (which regression | ||
77 | // tests really shouldn't). | ||
78 | Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod; | ||
79 | } | ||
80 | |||
81 | [SetUp] | ||
82 | public override void SetUp() | ||
83 | { | ||
84 | base.SetUp(); | ||
85 | |||
86 | // This is an unfortunate bit of clean up we have to do because MainServer manages things through static | ||
87 | // variables and the VM is not restarted between tests. | ||
88 | uint port = 9999; | ||
89 | MainServer.RemoveHttpServer(port); | ||
90 | |||
91 | BaseHttpServer server = new BaseHttpServer(port, false, 0, ""); | ||
92 | MainServer.AddHttpServer(server); | ||
93 | MainServer.Instance = server; | ||
94 | |||
95 | server.Start(); | ||
96 | |||
97 | m_engine = new MockScriptEngine(); | ||
98 | m_urlModule = new UrlModule(); | ||
99 | |||
100 | m_scene = new SceneHelpers().SetupScene(); | ||
101 | SceneHelpers.SetupSceneModules(m_scene, new IniConfigSource(), m_engine, m_urlModule); | ||
102 | |||
103 | SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene); | ||
104 | m_scriptItem = TaskInventoryHelpers.AddScript(m_scene, so.RootPart); | ||
105 | |||
106 | // This is disconnected from the actual script - the mock engine does not set up any LSL_Api atm. | ||
107 | // Possibly this could be done and we could obtain it directly from the MockScriptEngine. | ||
108 | m_lslApi = new LSL_Api(); | ||
109 | m_lslApi.Initialize(m_engine, so.RootPart, m_scriptItem, null); | ||
110 | } | ||
111 | |||
112 | [TearDown] | ||
113 | public void TearDown() | ||
114 | { | ||
115 | MainServer.Instance.Stop(); | ||
116 | } | ||
117 | |||
118 | [Test] | ||
119 | public void TestLlReleaseUrl() | ||
120 | { | ||
121 | TestHelpers.InMethod(); | ||
122 | |||
123 | m_lslApi.llRequestURL(); | ||
124 | string returnedUri = m_engine.PostedEvents[m_scriptItem.ItemID][0].Params[2].ToString(); | ||
125 | |||
126 | { | ||
127 | // Check that the initial number of URLs is correct | ||
128 | Assert.That(m_lslApi.llGetFreeURLs().value, Is.EqualTo(m_urlModule.TotalUrls - 1)); | ||
129 | } | ||
130 | |||
131 | { | ||
132 | // Check releasing a non-url | ||
133 | m_lslApi.llReleaseURL("GARBAGE"); | ||
134 | Assert.That(m_lslApi.llGetFreeURLs().value, Is.EqualTo(m_urlModule.TotalUrls - 1)); | ||
135 | } | ||
136 | |||
137 | { | ||
138 | // Check releasing a non-existing url | ||
139 | m_lslApi.llReleaseURL("http://example.com"); | ||
140 | Assert.That(m_lslApi.llGetFreeURLs().value, Is.EqualTo(m_urlModule.TotalUrls - 1)); | ||
141 | } | ||
142 | |||
143 | { | ||
144 | // Check URL release | ||
145 | m_lslApi.llReleaseURL(returnedUri); | ||
146 | Assert.That(m_lslApi.llGetFreeURLs().value, Is.EqualTo(m_urlModule.TotalUrls)); | ||
147 | |||
148 | HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(returnedUri); | ||
149 | |||
150 | bool gotExpectedException = false; | ||
151 | |||
152 | try | ||
153 | { | ||
154 | using (HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse()) | ||
155 | {} | ||
156 | } | ||
157 | catch (WebException e) | ||
158 | { | ||
159 | using (HttpWebResponse response = (HttpWebResponse)e.Response) | ||
160 | gotExpectedException = response.StatusCode == HttpStatusCode.NotFound; | ||
161 | } | ||
162 | |||
163 | Assert.That(gotExpectedException, Is.True); | ||
164 | } | ||
165 | |||
166 | { | ||
167 | // Check releasing the same URL again | ||
168 | m_lslApi.llReleaseURL(returnedUri); | ||
169 | Assert.That(m_lslApi.llGetFreeURLs().value, Is.EqualTo(m_urlModule.TotalUrls)); | ||
170 | } | ||
171 | } | ||
172 | |||
173 | [Test] | ||
174 | public void TestLlRequestUrl() | ||
175 | { | ||
176 | TestHelpers.InMethod(); | ||
177 | |||
178 | string requestId = m_lslApi.llRequestURL(); | ||
179 | Assert.That(requestId, Is.Not.EqualTo(UUID.Zero.ToString())); | ||
180 | string returnedUri; | ||
181 | |||
182 | { | ||
183 | // Check that URL is correctly set up | ||
184 | Assert.That(m_lslApi.llGetFreeURLs().value, Is.EqualTo(m_urlModule.TotalUrls - 1)); | ||
185 | |||
186 | Assert.That(m_engine.PostedEvents.ContainsKey(m_scriptItem.ItemID)); | ||
187 | |||
188 | List<EventParams> events = m_engine.PostedEvents[m_scriptItem.ItemID]; | ||
189 | Assert.That(events.Count, Is.EqualTo(1)); | ||
190 | EventParams eventParams = events[0]; | ||
191 | Assert.That(eventParams.EventName, Is.EqualTo("http_request")); | ||
192 | |||
193 | UUID returnKey; | ||
194 | string rawReturnKey = eventParams.Params[0].ToString(); | ||
195 | string method = eventParams.Params[1].ToString(); | ||
196 | returnedUri = eventParams.Params[2].ToString(); | ||
197 | |||
198 | Assert.That(UUID.TryParse(rawReturnKey, out returnKey), Is.True); | ||
199 | Assert.That(method, Is.EqualTo(ScriptBaseClass.URL_REQUEST_GRANTED)); | ||
200 | Assert.That(Uri.IsWellFormedUriString(returnedUri, UriKind.Absolute), Is.True); | ||
201 | } | ||
202 | |||
203 | { | ||
204 | // Check that request to URL works. | ||
205 | string testResponse = "Hello World"; | ||
206 | |||
207 | m_engine.ClearPostedEvents(); | ||
208 | m_engine.PostEventHook | ||
209 | += (itemId, evp) => m_lslApi.llHTTPResponse(evp.Params[0].ToString(), 200, testResponse); | ||
210 | |||
211 | // Console.WriteLine("Trying {0}", returnedUri); | ||
212 | |||
213 | AssertHttpResponse(returnedUri, testResponse); | ||
214 | |||
215 | Assert.That(m_engine.PostedEvents.ContainsKey(m_scriptItem.ItemID)); | ||
216 | |||
217 | List<EventParams> events = m_engine.PostedEvents[m_scriptItem.ItemID]; | ||
218 | Assert.That(events.Count, Is.EqualTo(1)); | ||
219 | EventParams eventParams = events[0]; | ||
220 | Assert.That(eventParams.EventName, Is.EqualTo("http_request")); | ||
221 | |||
222 | UUID returnKey; | ||
223 | string rawReturnKey = eventParams.Params[0].ToString(); | ||
224 | string method = eventParams.Params[1].ToString(); | ||
225 | string body = eventParams.Params[2].ToString(); | ||
226 | |||
227 | Assert.That(UUID.TryParse(rawReturnKey, out returnKey), Is.True); | ||
228 | Assert.That(method, Is.EqualTo("GET")); | ||
229 | Assert.That(body, Is.EqualTo("")); | ||
230 | } | ||
231 | } | ||
232 | |||
233 | private void AssertHttpResponse(string uri, string expectedResponse) | ||
234 | { | ||
235 | HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(uri); | ||
236 | |||
237 | using (HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse()) | ||
238 | { | ||
239 | using (Stream stream = webResponse.GetResponseStream()) | ||
240 | { | ||
241 | using (StreamReader reader = new StreamReader(stream)) | ||
242 | { | ||
243 | Assert.That(reader.ReadToEnd(), Is.EqualTo(expectedResponse)); | ||
244 | } | ||
245 | } | ||
246 | } | ||
247 | } | ||
248 | } | ||
249 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiInventoryTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiInventoryTests.cs index c73e22f..6dd6c17 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiInventoryTests.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiInventoryTests.cs | |||
@@ -41,6 +41,7 @@ using OpenSim.Region.OptionalModules.World.NPC; | |||
41 | using OpenSim.Region.Framework.Scenes; | 41 | using OpenSim.Region.Framework.Scenes; |
42 | using OpenSim.Region.ScriptEngine.Shared; | 42 | using OpenSim.Region.ScriptEngine.Shared; |
43 | using OpenSim.Region.ScriptEngine.Shared.Api; | 43 | using OpenSim.Region.ScriptEngine.Shared.Api; |
44 | using OpenSim.Region.ScriptEngine.Shared.Instance; | ||
44 | using OpenSim.Services.Interfaces; | 45 | using OpenSim.Services.Interfaces; |
45 | using OpenSim.Tests.Common; | 46 | using OpenSim.Tests.Common; |
46 | using OpenSim.Tests.Common.Mock; | 47 | using OpenSim.Tests.Common.Mock; |
@@ -51,14 +52,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests | |||
51 | /// Tests for inventory functions in LSL | 52 | /// Tests for inventory functions in LSL |
52 | /// </summary> | 53 | /// </summary> |
53 | [TestFixture] | 54 | [TestFixture] |
54 | public class LSL_ApiInventoryTests | 55 | public class LSL_ApiInventoryTests : OpenSimTestCase |
55 | { | 56 | { |
56 | protected Scene m_scene; | 57 | protected Scene m_scene; |
57 | protected XEngine.XEngine m_engine; | 58 | protected XEngine.XEngine m_engine; |
58 | 59 | ||
59 | [SetUp] | 60 | [SetUp] |
60 | public void SetUp() | 61 | public override void SetUp() |
61 | { | 62 | { |
63 | base.SetUp(); | ||
64 | |||
62 | IConfigSource initConfigSource = new IniConfigSource(); | 65 | IConfigSource initConfigSource = new IniConfigSource(); |
63 | IConfig config = initConfigSource.AddConfig("XEngine"); | 66 | IConfig config = initConfigSource.AddConfig("XEngine"); |
64 | config.Set("Enabled", "true"); | 67 | config.Set("Enabled", "true"); |
@@ -91,7 +94,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests | |||
91 | TaskInventoryHelpers.AddSceneObject(m_scene, so1.RootPart, inventoryItemName, itemId, userId); | 94 | TaskInventoryHelpers.AddSceneObject(m_scene, so1.RootPart, inventoryItemName, itemId, userId); |
92 | 95 | ||
93 | LSL_Api api = new LSL_Api(); | 96 | LSL_Api api = new LSL_Api(); |
94 | api.Initialize(m_engine, so1.RootPart, null); | 97 | api.Initialize(m_engine, so1.RootPart, null, null); |
95 | 98 | ||
96 | // Create a second object | 99 | // Create a second object |
97 | SceneObjectGroup so2 = SceneHelpers.CreateSceneObject(1, userId, "so2", 0x100); | 100 | SceneObjectGroup so2 = SceneHelpers.CreateSceneObject(1, userId, "so2", 0x100); |
@@ -124,7 +127,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests | |||
124 | SceneObjectGroup so1 = SceneHelpers.CreateSceneObject(1, user1Id, "so1", 0x10); | 127 | SceneObjectGroup so1 = SceneHelpers.CreateSceneObject(1, user1Id, "so1", 0x10); |
125 | m_scene.AddSceneObject(so1); | 128 | m_scene.AddSceneObject(so1); |
126 | LSL_Api api = new LSL_Api(); | 129 | LSL_Api api = new LSL_Api(); |
127 | api.Initialize(m_engine, so1.RootPart, null); | 130 | api.Initialize(m_engine, so1.RootPart, null, null); |
128 | 131 | ||
129 | // Create an object embedded inside the first | 132 | // Create an object embedded inside the first |
130 | UUID itemId = TestHelpers.ParseTail(0x20); | 133 | UUID itemId = TestHelpers.ParseTail(0x20); |
@@ -134,7 +137,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests | |||
134 | SceneObjectGroup so2 = SceneHelpers.CreateSceneObject(1, user2Id, "so2", 0x100); | 137 | SceneObjectGroup so2 = SceneHelpers.CreateSceneObject(1, user2Id, "so2", 0x100); |
135 | m_scene.AddSceneObject(so2); | 138 | m_scene.AddSceneObject(so2); |
136 | LSL_Api api2 = new LSL_Api(); | 139 | LSL_Api api2 = new LSL_Api(); |
137 | api2.Initialize(m_engine, so2.RootPart, null); | 140 | api2.Initialize(m_engine, so2.RootPart, null, null); |
138 | 141 | ||
139 | // *** Firstly, we test where llAllowInventoryDrop() has not been called. *** | 142 | // *** Firstly, we test where llAllowInventoryDrop() has not been called. *** |
140 | api.llGiveInventory(so2.UUID.ToString(), inventoryItemName); | 143 | api.llGiveInventory(so2.UUID.ToString(), inventoryItemName); |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiLinkingTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiLinkingTests.cs index 2565ae7..ac9f93b 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiLinkingTests.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiLinkingTests.cs | |||
@@ -41,6 +41,7 @@ using OpenSim.Region.OptionalModules.World.NPC; | |||
41 | using OpenSim.Region.Framework.Scenes; | 41 | using OpenSim.Region.Framework.Scenes; |
42 | using OpenSim.Region.ScriptEngine.Shared; | 42 | using OpenSim.Region.ScriptEngine.Shared; |
43 | using OpenSim.Region.ScriptEngine.Shared.Api; | 43 | using OpenSim.Region.ScriptEngine.Shared.Api; |
44 | using OpenSim.Region.ScriptEngine.Shared.Instance; | ||
44 | using OpenSim.Region.ScriptEngine.Shared.ScriptBase; | 45 | using OpenSim.Region.ScriptEngine.Shared.ScriptBase; |
45 | using OpenSim.Services.Interfaces; | 46 | using OpenSim.Services.Interfaces; |
46 | using OpenSim.Tests.Common; | 47 | using OpenSim.Tests.Common; |
@@ -56,14 +57,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests | |||
56 | /// OpenSim.Region.Framework.Scenes.Tests.SceneObjectLinkingTests. | 57 | /// OpenSim.Region.Framework.Scenes.Tests.SceneObjectLinkingTests. |
57 | /// </remarks> | 58 | /// </remarks> |
58 | [TestFixture] | 59 | [TestFixture] |
59 | public class LSL_ApiLinkingTests | 60 | public class LSL_ApiLinkingTests : OpenSimTestCase |
60 | { | 61 | { |
61 | protected Scene m_scene; | 62 | protected Scene m_scene; |
62 | protected XEngine.XEngine m_engine; | 63 | protected XEngine.XEngine m_engine; |
63 | 64 | ||
64 | [SetUp] | 65 | [SetUp] |
65 | public void SetUp() | 66 | public override void SetUp() |
66 | { | 67 | { |
68 | base.SetUp(); | ||
69 | |||
67 | IConfigSource initConfigSource = new IniConfigSource(); | 70 | IConfigSource initConfigSource = new IniConfigSource(); |
68 | IConfig config = initConfigSource.AddConfig("XEngine"); | 71 | IConfig config = initConfigSource.AddConfig("XEngine"); |
69 | config.Set("Enabled", "true"); | 72 | config.Set("Enabled", "true"); |
@@ -90,7 +93,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests | |||
90 | // FIXME: This should really be a script item (with accompanying script) | 93 | // FIXME: This should really be a script item (with accompanying script) |
91 | TaskInventoryItem grp1Item | 94 | TaskInventoryItem grp1Item |
92 | = TaskInventoryHelpers.AddNotecard( | 95 | = TaskInventoryHelpers.AddNotecard( |
93 | m_scene, grp1.RootPart, "ncItem", TestHelpers.ParseTail(0x800), TestHelpers.ParseTail(0x900)); | 96 | m_scene, grp1.RootPart, "ncItem", TestHelpers.ParseTail(0x800), TestHelpers.ParseTail(0x900), "Hello World!"); |
94 | grp1Item.PermsMask |= ScriptBaseClass.PERMISSION_CHANGE_LINKS; | 97 | grp1Item.PermsMask |= ScriptBaseClass.PERMISSION_CHANGE_LINKS; |
95 | 98 | ||
96 | SceneObjectGroup grp2 = SceneHelpers.CreateSceneObject(2, ownerId, "grp2-", 0x20); | 99 | SceneObjectGroup grp2 = SceneHelpers.CreateSceneObject(2, ownerId, "grp2-", 0x20); |
@@ -102,7 +105,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests | |||
102 | m_scene.AddSceneObject(grp2); | 105 | m_scene.AddSceneObject(grp2); |
103 | 106 | ||
104 | LSL_Api apiGrp1 = new LSL_Api(); | 107 | LSL_Api apiGrp1 = new LSL_Api(); |
105 | apiGrp1.Initialize(m_engine, grp1.RootPart, grp1Item); | 108 | apiGrp1.Initialize(m_engine, grp1.RootPart, grp1Item, null); |
106 | 109 | ||
107 | apiGrp1.llCreateLink(grp2.UUID.ToString(), ScriptBaseClass.TRUE); | 110 | apiGrp1.llCreateLink(grp2.UUID.ToString(), ScriptBaseClass.TRUE); |
108 | 111 | ||
@@ -124,12 +127,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests | |||
124 | // FIXME: This should really be a script item (with accompanying script) | 127 | // FIXME: This should really be a script item (with accompanying script) |
125 | TaskInventoryItem grp1Item | 128 | TaskInventoryItem grp1Item |
126 | = TaskInventoryHelpers.AddNotecard( | 129 | = TaskInventoryHelpers.AddNotecard( |
127 | m_scene, grp1.RootPart, "ncItem", TestHelpers.ParseTail(0x800), TestHelpers.ParseTail(0x900)); | 130 | m_scene, grp1.RootPart, "ncItem", TestHelpers.ParseTail(0x800), TestHelpers.ParseTail(0x900), "Hello World!"); |
128 | 131 | ||
129 | grp1Item.PermsMask |= ScriptBaseClass.PERMISSION_CHANGE_LINKS; | 132 | grp1Item.PermsMask |= ScriptBaseClass.PERMISSION_CHANGE_LINKS; |
130 | 133 | ||
131 | LSL_Api apiGrp1 = new LSL_Api(); | 134 | LSL_Api apiGrp1 = new LSL_Api(); |
132 | apiGrp1.Initialize(m_engine, grp1.RootPart, grp1Item); | 135 | apiGrp1.Initialize(m_engine, grp1.RootPart, grp1Item, null); |
133 | 136 | ||
134 | apiGrp1.llBreakLink(2); | 137 | apiGrp1.llBreakLink(2); |
135 | 138 | ||
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiListTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiListTests.cs index dd23be8..60de5cb 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiListTests.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiListTests.cs | |||
@@ -34,6 +34,7 @@ using OpenSim.Region.ScriptEngine.Shared; | |||
34 | using OpenSim.Region.Framework.Scenes; | 34 | using OpenSim.Region.Framework.Scenes; |
35 | using Nini.Config; | 35 | using Nini.Config; |
36 | using OpenSim.Region.ScriptEngine.Shared.Api; | 36 | using OpenSim.Region.ScriptEngine.Shared.Api; |
37 | using OpenSim.Region.ScriptEngine.Shared.Instance; | ||
37 | using OpenSim.Region.ScriptEngine.Shared.ScriptBase; | 38 | using OpenSim.Region.ScriptEngine.Shared.ScriptBase; |
38 | using OpenMetaverse; | 39 | using OpenMetaverse; |
39 | using OpenSim.Tests.Common.Mock; | 40 | using OpenSim.Tests.Common.Mock; |
@@ -46,13 +47,15 @@ using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString; | |||
46 | namespace OpenSim.Region.ScriptEngine.Shared.Tests | 47 | namespace OpenSim.Region.ScriptEngine.Shared.Tests |
47 | { | 48 | { |
48 | [TestFixture] | 49 | [TestFixture] |
49 | public class LSL_ApiListTests | 50 | public class LSL_ApiListTests : OpenSimTestCase |
50 | { | 51 | { |
51 | private LSL_Api m_lslApi; | 52 | private LSL_Api m_lslApi; |
52 | 53 | ||
53 | [SetUp] | 54 | [SetUp] |
54 | public void SetUp() | 55 | public override void SetUp() |
55 | { | 56 | { |
57 | base.SetUp(); | ||
58 | |||
56 | IConfigSource initConfigSource = new IniConfigSource(); | 59 | IConfigSource initConfigSource = new IniConfigSource(); |
57 | IConfig config = initConfigSource.AddConfig("XEngine"); | 60 | IConfig config = initConfigSource.AddConfig("XEngine"); |
58 | config.Set("Enabled", "true"); | 61 | config.Set("Enabled", "true"); |
@@ -65,7 +68,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests | |||
65 | engine.AddRegion(scene); | 68 | engine.AddRegion(scene); |
66 | 69 | ||
67 | m_lslApi = new LSL_Api(); | 70 | m_lslApi = new LSL_Api(); |
68 | m_lslApi.Initialize(engine, part, null); | 71 | m_lslApi.Initialize(engine, part, null, null); |
69 | } | 72 | } |
70 | 73 | ||
71 | [Test] | 74 | [Test] |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiNotecardTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiNotecardTests.cs new file mode 100644 index 0000000..c92bcdb --- /dev/null +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiNotecardTests.cs | |||
@@ -0,0 +1,270 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.IO; | ||
4 | using System.Net; | ||
5 | using System.Reflection; | ||
6 | using System.Text; | ||
7 | using log4net; | ||
8 | using Nini.Config; | ||
9 | using NUnit.Framework; | ||
10 | using OpenMetaverse; | ||
11 | using OpenSim.Framework; | ||
12 | using OpenSim.Framework.Servers; | ||
13 | using OpenSim.Framework.Servers.HttpServer; | ||
14 | using OpenSim.Region.CoreModules.Scripting.LSLHttp; | ||
15 | using OpenSim.Region.Framework.Scenes; | ||
16 | using OpenSim.Region.ScriptEngine.Shared; | ||
17 | using OpenSim.Region.ScriptEngine.Shared.Api; | ||
18 | using OpenSim.Region.ScriptEngine.Shared.ScriptBase; | ||
19 | using OpenSim.Services.Interfaces; | ||
20 | using OpenSim.Tests.Common; | ||
21 | using OpenSim.Tests.Common.Mock; | ||
22 | |||
23 | namespace OpenSim.Region.ScriptEngine.Shared.Tests | ||
24 | { | ||
25 | /// <summary> | ||
26 | /// Tests for notecard related functions in LSL | ||
27 | /// </summary> | ||
28 | [TestFixture] | ||
29 | public class LSL_ApiNotecardTests : OpenSimTestCase | ||
30 | { | ||
31 | private Scene m_scene; | ||
32 | private MockScriptEngine m_engine; | ||
33 | |||
34 | private SceneObjectGroup m_so; | ||
35 | private TaskInventoryItem m_scriptItem; | ||
36 | private LSL_Api m_lslApi; | ||
37 | |||
38 | [TestFixtureSetUp] | ||
39 | public void TestFixtureSetUp() | ||
40 | { | ||
41 | // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread. | ||
42 | Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest; | ||
43 | } | ||
44 | |||
45 | [TestFixtureTearDown] | ||
46 | public void TestFixureTearDown() | ||
47 | { | ||
48 | // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple | ||
49 | // threads. Possibly, later tests should be rewritten so none of them require async stuff (which regression | ||
50 | // tests really shouldn't). | ||
51 | Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod; | ||
52 | } | ||
53 | |||
54 | [SetUp] | ||
55 | public override void SetUp() | ||
56 | { | ||
57 | base.SetUp(); | ||
58 | |||
59 | m_engine = new MockScriptEngine(); | ||
60 | |||
61 | m_scene = new SceneHelpers().SetupScene(); | ||
62 | SceneHelpers.SetupSceneModules(m_scene, new IniConfigSource(), m_engine); | ||
63 | |||
64 | m_so = SceneHelpers.AddSceneObject(m_scene); | ||
65 | m_scriptItem = TaskInventoryHelpers.AddScript(m_scene, m_so.RootPart); | ||
66 | |||
67 | // This is disconnected from the actual script - the mock engine does not set up any LSL_Api atm. | ||
68 | // Possibly this could be done and we could obtain it directly from the MockScriptEngine. | ||
69 | m_lslApi = new LSL_Api(); | ||
70 | m_lslApi.Initialize(m_engine, m_so.RootPart, m_scriptItem, null); | ||
71 | } | ||
72 | |||
73 | [Test] | ||
74 | public void TestLlGetNotecardLine() | ||
75 | { | ||
76 | TestHelpers.InMethod(); | ||
77 | |||
78 | string[] ncLines = { "One", "Two", "Three" }; | ||
79 | |||
80 | TaskInventoryItem ncItem | ||
81 | = TaskInventoryHelpers.AddNotecard(m_scene, m_so.RootPart, "nc", "1", "10", string.Join("\n", ncLines)); | ||
82 | |||
83 | AssertValidNotecardLine(ncItem.Name, 0, ncLines[0]); | ||
84 | AssertValidNotecardLine(ncItem.Name, 2, ncLines[2]); | ||
85 | AssertValidNotecardLine(ncItem.Name, 3, ScriptBaseClass.EOF); | ||
86 | AssertValidNotecardLine(ncItem.Name, 4, ScriptBaseClass.EOF); | ||
87 | |||
88 | // XXX: Is this correct or do we really expect no dataserver event to fire at all? | ||
89 | AssertValidNotecardLine(ncItem.Name, -1, ""); | ||
90 | AssertValidNotecardLine(ncItem.Name, -2, ""); | ||
91 | } | ||
92 | |||
93 | [Test] | ||
94 | public void TestLlGetNotecardLine_NoNotecard() | ||
95 | { | ||
96 | TestHelpers.InMethod(); | ||
97 | |||
98 | AssertInValidNotecardLine("nc", 0); | ||
99 | } | ||
100 | |||
101 | [Test] | ||
102 | public void TestLlGetNotecardLine_NotANotecard() | ||
103 | { | ||
104 | TestHelpers.InMethod(); | ||
105 | |||
106 | TaskInventoryItem ncItem = TaskInventoryHelpers.AddScript(m_scene, m_so.RootPart, "nc1", "Not important"); | ||
107 | |||
108 | AssertInValidNotecardLine(ncItem.Name, 0); | ||
109 | } | ||
110 | |||
111 | private void AssertValidNotecardLine(string ncName, int lineNumber, string assertLine) | ||
112 | { | ||
113 | string key = m_lslApi.llGetNotecardLine(ncName, lineNumber); | ||
114 | Assert.That(key, Is.Not.EqualTo(UUID.Zero.ToString())); | ||
115 | |||
116 | Assert.That(m_engine.PostedEvents.Count, Is.EqualTo(1)); | ||
117 | Assert.That(m_engine.PostedEvents.ContainsKey(m_scriptItem.ItemID)); | ||
118 | |||
119 | List<EventParams> events = m_engine.PostedEvents[m_scriptItem.ItemID]; | ||
120 | Assert.That(events.Count, Is.EqualTo(1)); | ||
121 | EventParams eventParams = events[0]; | ||
122 | |||
123 | Assert.That(eventParams.EventName, Is.EqualTo("dataserver")); | ||
124 | Assert.That(eventParams.Params[0].ToString(), Is.EqualTo(key)); | ||
125 | Assert.That(eventParams.Params[1].ToString(), Is.EqualTo(assertLine)); | ||
126 | |||
127 | m_engine.ClearPostedEvents(); | ||
128 | } | ||
129 | |||
130 | private void AssertInValidNotecardLine(string ncName, int lineNumber) | ||
131 | { | ||
132 | string key = m_lslApi.llGetNotecardLine(ncName, lineNumber); | ||
133 | Assert.That(key, Is.EqualTo(UUID.Zero.ToString())); | ||
134 | |||
135 | Assert.That(m_engine.PostedEvents.Count, Is.EqualTo(0)); | ||
136 | } | ||
137 | |||
138 | // [Test] | ||
139 | // public void TestLlReleaseUrl() | ||
140 | // { | ||
141 | // TestHelpers.InMethod(); | ||
142 | // | ||
143 | // m_lslApi.llRequestURL(); | ||
144 | // string returnedUri = m_engine.PostedEvents[m_scriptItem.ItemID][0].Params[2].ToString(); | ||
145 | // | ||
146 | // { | ||
147 | // // Check that the initial number of URLs is correct | ||
148 | // Assert.That(m_lslApi.llGetFreeURLs().value, Is.EqualTo(m_urlModule.TotalUrls - 1)); | ||
149 | // } | ||
150 | // | ||
151 | // { | ||
152 | // // Check releasing a non-url | ||
153 | // m_lslApi.llReleaseURL("GARBAGE"); | ||
154 | // Assert.That(m_lslApi.llGetFreeURLs().value, Is.EqualTo(m_urlModule.TotalUrls - 1)); | ||
155 | // } | ||
156 | // | ||
157 | // { | ||
158 | // // Check releasing a non-existing url | ||
159 | // m_lslApi.llReleaseURL("http://example.com"); | ||
160 | // Assert.That(m_lslApi.llGetFreeURLs().value, Is.EqualTo(m_urlModule.TotalUrls - 1)); | ||
161 | // } | ||
162 | // | ||
163 | // { | ||
164 | // // Check URL release | ||
165 | // m_lslApi.llReleaseURL(returnedUri); | ||
166 | // Assert.That(m_lslApi.llGetFreeURLs().value, Is.EqualTo(m_urlModule.TotalUrls)); | ||
167 | // | ||
168 | // HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(returnedUri); | ||
169 | // | ||
170 | // bool gotExpectedException = false; | ||
171 | // | ||
172 | // try | ||
173 | // { | ||
174 | // using (HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse()) | ||
175 | // {} | ||
176 | // } | ||
177 | // catch (WebException e) | ||
178 | // { | ||
179 | // using (HttpWebResponse response = (HttpWebResponse)e.Response) | ||
180 | // gotExpectedException = response.StatusCode == HttpStatusCode.NotFound; | ||
181 | // } | ||
182 | // | ||
183 | // Assert.That(gotExpectedException, Is.True); | ||
184 | // } | ||
185 | // | ||
186 | // { | ||
187 | // // Check releasing the same URL again | ||
188 | // m_lslApi.llReleaseURL(returnedUri); | ||
189 | // Assert.That(m_lslApi.llGetFreeURLs().value, Is.EqualTo(m_urlModule.TotalUrls)); | ||
190 | // } | ||
191 | // } | ||
192 | // | ||
193 | // [Test] | ||
194 | // public void TestLlRequestUrl() | ||
195 | // { | ||
196 | // TestHelpers.InMethod(); | ||
197 | // | ||
198 | // string requestId = m_lslApi.llRequestURL(); | ||
199 | // Assert.That(requestId, Is.Not.EqualTo(UUID.Zero.ToString())); | ||
200 | // string returnedUri; | ||
201 | // | ||
202 | // { | ||
203 | // // Check that URL is correctly set up | ||
204 | // Assert.That(m_lslApi.llGetFreeURLs().value, Is.EqualTo(m_urlModule.TotalUrls - 1)); | ||
205 | // | ||
206 | // Assert.That(m_engine.PostedEvents.ContainsKey(m_scriptItem.ItemID)); | ||
207 | // | ||
208 | // List<EventParams> events = m_engine.PostedEvents[m_scriptItem.ItemID]; | ||
209 | // Assert.That(events.Count, Is.EqualTo(1)); | ||
210 | // EventParams eventParams = events[0]; | ||
211 | // Assert.That(eventParams.EventName, Is.EqualTo("http_request")); | ||
212 | // | ||
213 | // UUID returnKey; | ||
214 | // string rawReturnKey = eventParams.Params[0].ToString(); | ||
215 | // string method = eventParams.Params[1].ToString(); | ||
216 | // returnedUri = eventParams.Params[2].ToString(); | ||
217 | // | ||
218 | // Assert.That(UUID.TryParse(rawReturnKey, out returnKey), Is.True); | ||
219 | // Assert.That(method, Is.EqualTo(ScriptBaseClass.URL_REQUEST_GRANTED)); | ||
220 | // Assert.That(Uri.IsWellFormedUriString(returnedUri, UriKind.Absolute), Is.True); | ||
221 | // } | ||
222 | // | ||
223 | // { | ||
224 | // // Check that request to URL works. | ||
225 | // string testResponse = "Hello World"; | ||
226 | // | ||
227 | // m_engine.ClearPostedEvents(); | ||
228 | // m_engine.PostEventHook | ||
229 | // += (itemId, evp) => m_lslApi.llHTTPResponse(evp.Params[0].ToString(), 200, testResponse); | ||
230 | // | ||
231 | //// Console.WriteLine("Trying {0}", returnedUri); | ||
232 | // HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(returnedUri); | ||
233 | // | ||
234 | // AssertHttpResponse(returnedUri, testResponse); | ||
235 | // | ||
236 | // Assert.That(m_engine.PostedEvents.ContainsKey(m_scriptItem.ItemID)); | ||
237 | // | ||
238 | // List<EventParams> events = m_engine.PostedEvents[m_scriptItem.ItemID]; | ||
239 | // Assert.That(events.Count, Is.EqualTo(1)); | ||
240 | // EventParams eventParams = events[0]; | ||
241 | // Assert.That(eventParams.EventName, Is.EqualTo("http_request")); | ||
242 | // | ||
243 | // UUID returnKey; | ||
244 | // string rawReturnKey = eventParams.Params[0].ToString(); | ||
245 | // string method = eventParams.Params[1].ToString(); | ||
246 | // string body = eventParams.Params[2].ToString(); | ||
247 | // | ||
248 | // Assert.That(UUID.TryParse(rawReturnKey, out returnKey), Is.True); | ||
249 | // Assert.That(method, Is.EqualTo("GET")); | ||
250 | // Assert.That(body, Is.EqualTo("")); | ||
251 | // } | ||
252 | // } | ||
253 | // | ||
254 | // private void AssertHttpResponse(string uri, string expectedResponse) | ||
255 | // { | ||
256 | // HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(uri); | ||
257 | // | ||
258 | // using (HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse()) | ||
259 | // { | ||
260 | // using (Stream stream = webResponse.GetResponseStream()) | ||
261 | // { | ||
262 | // using (StreamReader reader = new StreamReader(stream)) | ||
263 | // { | ||
264 | // Assert.That(reader.ReadToEnd(), Is.EqualTo(expectedResponse)); | ||
265 | // } | ||
266 | // } | ||
267 | // } | ||
268 | // } | ||
269 | } | ||
270 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiTest.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiTest.cs index c41d1e7..e97ae06 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiTest.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiTest.cs | |||
@@ -33,6 +33,7 @@ using OpenSim.Region.ScriptEngine.Shared; | |||
33 | using OpenSim.Region.Framework.Scenes; | 33 | using OpenSim.Region.Framework.Scenes; |
34 | using Nini.Config; | 34 | using Nini.Config; |
35 | using OpenSim.Region.ScriptEngine.Shared.Api; | 35 | using OpenSim.Region.ScriptEngine.Shared.Api; |
36 | using OpenSim.Region.ScriptEngine.Shared.Instance; | ||
36 | using OpenSim.Region.ScriptEngine.Shared.ScriptBase; | 37 | using OpenSim.Region.ScriptEngine.Shared.ScriptBase; |
37 | using OpenMetaverse; | 38 | using OpenMetaverse; |
38 | using System; | 39 | using System; |
@@ -66,7 +67,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests | |||
66 | engine.AddRegion(scene); | 67 | engine.AddRegion(scene); |
67 | 68 | ||
68 | m_lslApi = new LSL_Api(); | 69 | m_lslApi = new LSL_Api(); |
69 | m_lslApi.Initialize(engine, part, null); | 70 | m_lslApi.Initialize(engine, part, null, null); |
70 | } | 71 | } |
71 | 72 | ||
72 | [Test] | 73 | [Test] |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestLSLFloat.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestLSLFloat.cs index 3ed2562..c8c7f82 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestLSLFloat.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestLSLFloat.cs | |||
@@ -33,7 +33,7 @@ using OpenSim.Region.ScriptEngine.Shared; | |||
33 | namespace OpenSim.Region.ScriptEngine.Shared.Tests | 33 | namespace OpenSim.Region.ScriptEngine.Shared.Tests |
34 | { | 34 | { |
35 | [TestFixture] | 35 | [TestFixture] |
36 | public class LSL_TypesTestLSLFloat | 36 | public class LSL_TypesTestLSLFloat : OpenSimTestCase |
37 | { | 37 | { |
38 | // Used for testing equality of two floats. | 38 | // Used for testing equality of two floats. |
39 | private double _lowPrecisionTolerance = 0.000001; | 39 | private double _lowPrecisionTolerance = 0.000001; |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestLSLInteger.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestLSLInteger.cs index 8d1169a..c664108 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestLSLInteger.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestLSLInteger.cs | |||
@@ -33,7 +33,7 @@ using OpenSim.Region.ScriptEngine.Shared; | |||
33 | namespace OpenSim.Region.ScriptEngine.Shared.Tests | 33 | namespace OpenSim.Region.ScriptEngine.Shared.Tests |
34 | { | 34 | { |
35 | [TestFixture] | 35 | [TestFixture] |
36 | public class LSL_TypesTestLSLInteger | 36 | public class LSL_TypesTestLSLInteger : OpenSimTestCase |
37 | { | 37 | { |
38 | private Dictionary<double, int> m_doubleIntSet; | 38 | private Dictionary<double, int> m_doubleIntSet; |
39 | private Dictionary<string, int> m_stringIntSet; | 39 | private Dictionary<string, int> m_stringIntSet; |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestLSLString.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestLSLString.cs index c4ca1a8..8550f2d 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestLSLString.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestLSLString.cs | |||
@@ -33,7 +33,7 @@ using OpenSim.Region.ScriptEngine.Shared; | |||
33 | namespace OpenSim.Region.ScriptEngine.Shared.Tests | 33 | namespace OpenSim.Region.ScriptEngine.Shared.Tests |
34 | { | 34 | { |
35 | [TestFixture] | 35 | [TestFixture] |
36 | public class LSL_TypesTestLSLString | 36 | public class LSL_TypesTestLSLString : OpenSimTestCase |
37 | { | 37 | { |
38 | private Dictionary<double, string> m_doubleStringSet; | 38 | private Dictionary<double, string> m_doubleStringSet; |
39 | 39 | ||
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestList.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestList.cs index b81225f..71b88bc 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestList.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestList.cs | |||
@@ -36,7 +36,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests | |||
36 | /// Tests the LSL_Types.list class. | 36 | /// Tests the LSL_Types.list class. |
37 | /// </summary> | 37 | /// </summary> |
38 | [TestFixture] | 38 | [TestFixture] |
39 | public class LSL_TypesTestList | 39 | public class LSL_TypesTestList : OpenSimTestCase |
40 | { | 40 | { |
41 | /// <summary> | 41 | /// <summary> |
42 | /// Tests concatenating a string to a list. | 42 | /// Tests concatenating a string to a list. |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestVector3.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestVector3.cs index ebf8001..0c838af 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestVector3.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestVector3.cs | |||
@@ -36,7 +36,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests | |||
36 | /// Tests for Vector3 | 36 | /// Tests for Vector3 |
37 | /// </summary> | 37 | /// </summary> |
38 | [TestFixture] | 38 | [TestFixture] |
39 | public class LSL_TypesTestVector3 | 39 | public class LSL_TypesTestVector3 : OpenSimTestCase |
40 | { | 40 | { |
41 | [Test] | 41 | [Test] |
42 | public void TestDotProduct() | 42 | public void TestDotProduct() |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAppearanceTest.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAppearanceTest.cs index c401794..c88bad5 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAppearanceTest.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAppearanceTest.cs | |||
@@ -41,6 +41,7 @@ using OpenSim.Region.OptionalModules.World.NPC; | |||
41 | using OpenSim.Region.Framework.Scenes; | 41 | using OpenSim.Region.Framework.Scenes; |
42 | using OpenSim.Region.ScriptEngine.Shared; | 42 | using OpenSim.Region.ScriptEngine.Shared; |
43 | using OpenSim.Region.ScriptEngine.Shared.Api; | 43 | using OpenSim.Region.ScriptEngine.Shared.Api; |
44 | using OpenSim.Region.ScriptEngine.Shared.Instance; | ||
44 | using OpenSim.Services.Interfaces; | 45 | using OpenSim.Services.Interfaces; |
45 | using OpenSim.Tests.Common; | 46 | using OpenSim.Tests.Common; |
46 | using OpenSim.Tests.Common.Mock; | 47 | using OpenSim.Tests.Common.Mock; |
@@ -51,14 +52,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests | |||
51 | /// Tests for OSSL_Api | 52 | /// Tests for OSSL_Api |
52 | /// </summary> | 53 | /// </summary> |
53 | [TestFixture] | 54 | [TestFixture] |
54 | public class OSSL_ApiAppearanceTest | 55 | public class OSSL_ApiAppearanceTest : OpenSimTestCase |
55 | { | 56 | { |
56 | protected Scene m_scene; | 57 | protected Scene m_scene; |
57 | protected XEngine.XEngine m_engine; | 58 | protected XEngine.XEngine m_engine; |
58 | 59 | ||
59 | [SetUp] | 60 | [SetUp] |
60 | public void SetUp() | 61 | public override void SetUp() |
61 | { | 62 | { |
63 | base.SetUp(); | ||
64 | |||
62 | IConfigSource initConfigSource = new IniConfigSource(); | 65 | IConfigSource initConfigSource = new IniConfigSource(); |
63 | IConfig config = initConfigSource.AddConfig("XEngine"); | 66 | IConfig config = initConfigSource.AddConfig("XEngine"); |
64 | config.Set("Enabled", "true"); | 67 | config.Set("Enabled", "true"); |
@@ -91,7 +94,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests | |||
91 | m_scene.AddSceneObject(so); | 94 | m_scene.AddSceneObject(so); |
92 | 95 | ||
93 | OSSL_Api osslApi = new OSSL_Api(); | 96 | OSSL_Api osslApi = new OSSL_Api(); |
94 | osslApi.Initialize(m_engine, part, null); | 97 | osslApi.Initialize(m_engine, part, null, null); |
95 | 98 | ||
96 | string notecardName = "appearanceNc"; | 99 | string notecardName = "appearanceNc"; |
97 | 100 | ||
@@ -132,7 +135,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests | |||
132 | m_scene.AddSceneObject(so); | 135 | m_scene.AddSceneObject(so); |
133 | 136 | ||
134 | OSSL_Api osslApi = new OSSL_Api(); | 137 | OSSL_Api osslApi = new OSSL_Api(); |
135 | osslApi.Initialize(m_engine, part, null); | 138 | osslApi.Initialize(m_engine, part, null, null); |
136 | 139 | ||
137 | string notecardName = "appearanceNc"; | 140 | string notecardName = "appearanceNc"; |
138 | 141 | ||
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAttachmentTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAttachmentTests.cs index 5ed1f3d..e422f5b 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAttachmentTests.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAttachmentTests.cs | |||
@@ -41,6 +41,7 @@ using OpenSim.Region.CoreModules.Framework.InventoryAccess; | |||
41 | using OpenSim.Region.Framework.Scenes; | 41 | using OpenSim.Region.Framework.Scenes; |
42 | using OpenSim.Region.ScriptEngine.Shared; | 42 | using OpenSim.Region.ScriptEngine.Shared; |
43 | using OpenSim.Region.ScriptEngine.Shared.Api; | 43 | using OpenSim.Region.ScriptEngine.Shared.Api; |
44 | using OpenSim.Region.ScriptEngine.Shared.Instance; | ||
44 | using OpenSim.Services.Interfaces; | 45 | using OpenSim.Services.Interfaces; |
45 | using OpenSim.Tests.Common; | 46 | using OpenSim.Tests.Common; |
46 | using OpenSim.Tests.Common.Mock; | 47 | using OpenSim.Tests.Common.Mock; |
@@ -98,9 +99,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests | |||
98 | SceneObjectGroup inWorldObj = SceneHelpers.AddSceneObject(m_scene, "inWorldObj", ua1.PrincipalID); | 99 | SceneObjectGroup inWorldObj = SceneHelpers.AddSceneObject(m_scene, "inWorldObj", ua1.PrincipalID); |
99 | TaskInventoryItem scriptItem = TaskInventoryHelpers.AddScript(m_scene, inWorldObj.RootPart); | 100 | TaskInventoryItem scriptItem = TaskInventoryHelpers.AddScript(m_scene, inWorldObj.RootPart); |
100 | 101 | ||
101 | new LSL_Api().Initialize(m_engine, inWorldObj.RootPart, scriptItem); | 102 | new LSL_Api().Initialize(m_engine, inWorldObj.RootPart, scriptItem, null); |
102 | OSSL_Api osslApi = new OSSL_Api(); | 103 | OSSL_Api osslApi = new OSSL_Api(); |
103 | osslApi.Initialize(m_engine, inWorldObj.RootPart, scriptItem); | 104 | osslApi.Initialize(m_engine, inWorldObj.RootPart, scriptItem, null); |
104 | 105 | ||
105 | // SceneObjectGroup sog1 = SceneHelpers.CreateSceneObject(1, ua1.PrincipalID); | 106 | // SceneObjectGroup sog1 = SceneHelpers.CreateSceneObject(1, ua1.PrincipalID); |
106 | 107 | ||
@@ -144,13 +145,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests | |||
144 | SceneObjectGroup inWorldObj = SceneHelpers.AddSceneObject(m_scene, "inWorldObj", ua1.PrincipalID); | 145 | SceneObjectGroup inWorldObj = SceneHelpers.AddSceneObject(m_scene, "inWorldObj", ua1.PrincipalID); |
145 | TaskInventoryItem scriptItem = TaskInventoryHelpers.AddScript(m_scene, inWorldObj.RootPart); | 146 | TaskInventoryItem scriptItem = TaskInventoryHelpers.AddScript(m_scene, inWorldObj.RootPart); |
146 | 147 | ||
147 | new LSL_Api().Initialize(m_engine, inWorldObj.RootPart, scriptItem); | 148 | new LSL_Api().Initialize(m_engine, inWorldObj.RootPart, scriptItem, null); |
148 | OSSL_Api osslApi = new OSSL_Api(); | 149 | OSSL_Api osslApi = new OSSL_Api(); |
149 | osslApi.Initialize(m_engine, inWorldObj.RootPart, scriptItem); | 150 | osslApi.Initialize(m_engine, inWorldObj.RootPart, scriptItem, null); |
150 | 151 | ||
151 | // Create an object embedded inside the first | 152 | // Create an object embedded inside the first |
152 | TaskInventoryHelpers.AddNotecard( | 153 | TaskInventoryHelpers.AddNotecard( |
153 | m_scene, inWorldObj.RootPart, taskInvObjItemName, taskInvObjItemId, TestHelpers.ParseTail(0x900)); | 154 | m_scene, inWorldObj.RootPart, taskInvObjItemName, taskInvObjItemId, TestHelpers.ParseTail(0x900), "Hello World!"); |
154 | 155 | ||
155 | bool exceptionCaught = false; | 156 | bool exceptionCaught = false; |
156 | 157 | ||
@@ -192,12 +193,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests | |||
192 | SceneObjectGroup inWorldObj = SceneHelpers.AddSceneObject(m_scene, "inWorldObj", ua1.PrincipalID); | 193 | SceneObjectGroup inWorldObj = SceneHelpers.AddSceneObject(m_scene, "inWorldObj", ua1.PrincipalID); |
193 | TaskInventoryItem scriptItem = TaskInventoryHelpers.AddScript(m_scene, inWorldObj.RootPart); | 194 | TaskInventoryItem scriptItem = TaskInventoryHelpers.AddScript(m_scene, inWorldObj.RootPart); |
194 | 195 | ||
195 | new LSL_Api().Initialize(m_engine, inWorldObj.RootPart, scriptItem); | 196 | new LSL_Api().Initialize(m_engine, inWorldObj.RootPart, scriptItem, null); |
196 | OSSL_Api osslApi = new OSSL_Api(); | 197 | OSSL_Api osslApi = new OSSL_Api(); |
197 | osslApi.Initialize(m_engine, inWorldObj.RootPart, scriptItem); | 198 | osslApi.Initialize(m_engine, inWorldObj.RootPart, scriptItem, null); |
198 | 199 | ||
199 | // Create an object embedded inside the first | 200 | // Create an object embedded inside the first |
200 | TaskInventoryHelpers.AddSceneObject(m_scene, inWorldObj.RootPart, taskInvObjItemName, taskInvObjItemId, ua1.PrincipalID); | 201 | TaskInventoryHelpers.AddSceneObject( |
202 | m_scene, inWorldObj.RootPart, taskInvObjItemName, taskInvObjItemId, ua1.PrincipalID); | ||
201 | 203 | ||
202 | ScenePresence sp2 = SceneHelpers.AddScenePresence(m_scene, ua2); | 204 | ScenePresence sp2 = SceneHelpers.AddScenePresence(m_scene, ua2); |
203 | 205 | ||
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs index b49bcc2..74f010e 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs | |||
@@ -42,6 +42,7 @@ using OpenSim.Region.OptionalModules.World.NPC; | |||
42 | using OpenSim.Region.Framework.Scenes; | 42 | using OpenSim.Region.Framework.Scenes; |
43 | using OpenSim.Region.ScriptEngine.Shared; | 43 | using OpenSim.Region.ScriptEngine.Shared; |
44 | using OpenSim.Region.ScriptEngine.Shared.Api; | 44 | using OpenSim.Region.ScriptEngine.Shared.Api; |
45 | using OpenSim.Region.ScriptEngine.Shared.Instance; | ||
45 | using OpenSim.Region.ScriptEngine.Shared.ScriptBase; | 46 | using OpenSim.Region.ScriptEngine.Shared.ScriptBase; |
46 | using OpenSim.Services.Interfaces; | 47 | using OpenSim.Services.Interfaces; |
47 | using OpenSim.Tests.Common; | 48 | using OpenSim.Tests.Common; |
@@ -99,7 +100,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests | |||
99 | m_scene.AddSceneObject(so); | 100 | m_scene.AddSceneObject(so); |
100 | 101 | ||
101 | OSSL_Api osslApi = new OSSL_Api(); | 102 | OSSL_Api osslApi = new OSSL_Api(); |
102 | osslApi.Initialize(m_engine, part, null); | 103 | osslApi.Initialize(m_engine, part, null, null); |
103 | 104 | ||
104 | string notecardName = "appearanceNc"; | 105 | string notecardName = "appearanceNc"; |
105 | osslApi.osOwnerSaveAppearance(notecardName); | 106 | osslApi.osOwnerSaveAppearance(notecardName); |
@@ -125,14 +126,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests | |||
125 | m_scene.AddSceneObject(so); | 126 | m_scene.AddSceneObject(so); |
126 | 127 | ||
127 | OSSL_Api osslApi = new OSSL_Api(); | 128 | OSSL_Api osslApi = new OSSL_Api(); |
128 | osslApi.Initialize(m_engine, so.RootPart, null); | 129 | osslApi.Initialize(m_engine, so.RootPart, null, null); |
129 | 130 | ||
130 | string npcRaw; | ||
131 | bool gotExpectedException = false; | 131 | bool gotExpectedException = false; |
132 | try | 132 | try |
133 | { | 133 | { |
134 | npcRaw | 134 | osslApi.osNpcCreate("Jane", "Doe", new LSL_Types.Vector3(128, 128, 128), "not existing notecard name"); |
135 | = osslApi.osNpcCreate("Jane", "Doe", new LSL_Types.Vector3(128, 128, 128), "not existing notecard name"); | ||
136 | } | 135 | } |
137 | catch (ScriptException) | 136 | catch (ScriptException) |
138 | { | 137 | { |
@@ -162,7 +161,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests | |||
162 | m_scene.AddSceneObject(so); | 161 | m_scene.AddSceneObject(so); |
163 | 162 | ||
164 | OSSL_Api osslApi = new OSSL_Api(); | 163 | OSSL_Api osslApi = new OSSL_Api(); |
165 | osslApi.Initialize(m_engine, part, null); | 164 | osslApi.Initialize(m_engine, part, null, null); |
166 | 165 | ||
167 | string notecardName = "appearanceNc"; | 166 | string notecardName = "appearanceNc"; |
168 | osslApi.osOwnerSaveAppearance(notecardName); | 167 | osslApi.osOwnerSaveAppearance(notecardName); |
@@ -196,7 +195,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests | |||
196 | m_scene.AddSceneObject(so); | 195 | m_scene.AddSceneObject(so); |
197 | 196 | ||
198 | OSSL_Api osslApi = new OSSL_Api(); | 197 | OSSL_Api osslApi = new OSSL_Api(); |
199 | osslApi.Initialize(m_engine, part, null); | 198 | osslApi.Initialize(m_engine, part, null, null); |
200 | 199 | ||
201 | osslApi.osOwnerSaveAppearance(firstAppearanceNcName); | 200 | osslApi.osOwnerSaveAppearance(firstAppearanceNcName); |
202 | 201 | ||
@@ -223,7 +222,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests | |||
223 | // Store an avatar with a different height from default in a notecard. | 222 | // Store an avatar with a different height from default in a notecard. |
224 | UUID userId = TestHelpers.ParseTail(0x1); | 223 | UUID userId = TestHelpers.ParseTail(0x1); |
225 | float firstHeight = 1.9f; | 224 | float firstHeight = 1.9f; |
226 | float secondHeight = 2.1f; | 225 | // float secondHeight = 2.1f; |
227 | string firstAppearanceNcName = "appearanceNc1"; | 226 | string firstAppearanceNcName = "appearanceNc1"; |
228 | string secondAppearanceNcName = "appearanceNc2"; | 227 | string secondAppearanceNcName = "appearanceNc2"; |
229 | 228 | ||
@@ -234,7 +233,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests | |||
234 | m_scene.AddSceneObject(so); | 233 | m_scene.AddSceneObject(so); |
235 | 234 | ||
236 | OSSL_Api osslApi = new OSSL_Api(); | 235 | OSSL_Api osslApi = new OSSL_Api(); |
237 | osslApi.Initialize(m_engine, part, null); | 236 | osslApi.Initialize(m_engine, part, null, null); |
238 | 237 | ||
239 | osslApi.osOwnerSaveAppearance(firstAppearanceNcName); | 238 | osslApi.osOwnerSaveAppearance(firstAppearanceNcName); |
240 | 239 | ||
@@ -286,10 +285,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests | |||
286 | m_scene.AddSceneObject(otherSo); | 285 | m_scene.AddSceneObject(otherSo); |
287 | 286 | ||
288 | OSSL_Api osslApi = new OSSL_Api(); | 287 | OSSL_Api osslApi = new OSSL_Api(); |
289 | osslApi.Initialize(m_engine, part, null); | 288 | osslApi.Initialize(m_engine, part, null, null); |
290 | 289 | ||
291 | OSSL_Api otherOsslApi = new OSSL_Api(); | 290 | OSSL_Api otherOsslApi = new OSSL_Api(); |
292 | otherOsslApi.Initialize(m_engine, otherPart, null); | 291 | otherOsslApi.Initialize(m_engine, otherPart, null, null); |
293 | 292 | ||
294 | string notecardName = "appearanceNc"; | 293 | string notecardName = "appearanceNc"; |
295 | osslApi.osOwnerSaveAppearance(notecardName); | 294 | osslApi.osOwnerSaveAppearance(notecardName); |
@@ -333,7 +332,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests | |||
333 | m_scene.AddSceneObject(so); | 332 | m_scene.AddSceneObject(so); |
334 | 333 | ||
335 | OSSL_Api osslApi = new OSSL_Api(); | 334 | OSSL_Api osslApi = new OSSL_Api(); |
336 | osslApi.Initialize(m_engine, part, null); | 335 | osslApi.Initialize(m_engine, part, null, null); |
337 | 336 | ||
338 | string notecardName = "appearanceNc"; | 337 | string notecardName = "appearanceNc"; |
339 | osslApi.osOwnerSaveAppearance(notecardName); | 338 | osslApi.osOwnerSaveAppearance(notecardName); |
diff --git a/OpenSim/Region/Framework/Scenes/Scripting/NullScriptHost.cs b/OpenSim/Region/ScriptEngine/XEngine/Api/Runtime/XEngineScriptBase.cs index d7198f0..f4211c8 100644 --- a/OpenSim/Region/Framework/Scenes/Scripting/NullScriptHost.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/Api/Runtime/XEngineScriptBase.cs | |||
@@ -26,66 +26,36 @@ | |||
26 | */ | 26 | */ |
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using OpenMetaverse; | 29 | using System.Runtime.Remoting; |
30 | using log4net; | 30 | using System.Runtime.Remoting.Lifetime; |
31 | using System.Security.Permissions; | ||
32 | using System.Threading; | ||
31 | using System.Reflection; | 33 | using System.Reflection; |
32 | using OpenSim.Framework; | 34 | using System.Collections; |
35 | using System.Collections.Generic; | ||
36 | using OpenSim.Region.ScriptEngine.Interfaces; | ||
37 | using OpenSim.Region.ScriptEngine.Shared; | ||
38 | using OpenSim.Region.ScriptEngine.Shared.ScriptBase; | ||
33 | 39 | ||
34 | namespace OpenSim.Region.Framework.Scenes.Scripting | 40 | namespace OpenSim.Region.ScriptEngine.XEngine.ScriptBase |
35 | { | 41 | { |
36 | public class NullScriptHost : IScriptHost | 42 | public class XEngineScriptBase : ScriptBaseClass |
37 | { | 43 | { |
38 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 44 | /// <summary> |
45 | /// Used for script sleeps when we are using co-operative script termination. | ||
46 | /// </summary> | ||
47 | /// <remarks>null if co-operative script termination is not active</remarks> | ||
48 | WaitHandle m_coopSleepHandle; | ||
39 | 49 | ||
40 | private Vector3 m_pos = new Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 30); | 50 | public XEngineScriptBase(WaitHandle coopSleepHandle) : base() |
41 | |||
42 | public string Name | ||
43 | { | ||
44 | get { return "Object"; } | ||
45 | set { } | ||
46 | } | ||
47 | |||
48 | public string SitName | ||
49 | { | ||
50 | get { return String.Empty; } | ||
51 | set { } | ||
52 | } | ||
53 | |||
54 | public string TouchName | ||
55 | { | ||
56 | get { return String.Empty; } | ||
57 | set { } | ||
58 | } | ||
59 | |||
60 | public string Description | ||
61 | { | ||
62 | get { return String.Empty; } | ||
63 | set { } | ||
64 | } | ||
65 | |||
66 | public UUID UUID | ||
67 | { | ||
68 | get { return UUID.Zero; } | ||
69 | } | ||
70 | |||
71 | public UUID OwnerID | ||
72 | { | ||
73 | get { return UUID.Zero; } | ||
74 | } | ||
75 | |||
76 | public UUID CreatorID | ||
77 | { | ||
78 | get { return UUID.Zero; } | ||
79 | } | ||
80 | |||
81 | public Vector3 AbsolutePosition | ||
82 | { | 51 | { |
83 | get { return m_pos; } | 52 | m_coopSleepHandle = coopSleepHandle; |
84 | } | 53 | } |
85 | 54 | ||
86 | public void SetText(string text, Vector3 color, double alpha) | 55 | public void opensim_reserved_CheckForCoopTermination() |
87 | { | 56 | { |
88 | m_log.Warn("Tried to SetText "+text+" on NullScriptHost"); | 57 | if (m_coopSleepHandle != null && m_coopSleepHandle.WaitOne(0)) |
58 | throw new ScriptCoopStopException(); | ||
89 | } | 59 | } |
90 | } | 60 | } |
91 | } | 61 | } \ No newline at end of file |
diff --git a/OpenSim/Region/ScriptEngine/XEngine/EventManager.cs b/OpenSim/Region/ScriptEngine/XEngine/EventManager.cs index 9405075..0ff2da3 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/EventManager.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/EventManager.cs | |||
@@ -52,7 +52,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
52 | { | 52 | { |
53 | myScriptEngine = _ScriptEngine; | 53 | myScriptEngine = _ScriptEngine; |
54 | 54 | ||
55 | m_log.Info("[XEngine] Hooking up to server events"); | 55 | // m_log.Info("[XEngine] Hooking up to server events"); |
56 | myScriptEngine.World.EventManager.OnAttach += attach; | 56 | myScriptEngine.World.EventManager.OnAttach += attach; |
57 | myScriptEngine.World.EventManager.OnObjectGrab += touch_start; | 57 | myScriptEngine.World.EventManager.OnObjectGrab += touch_start; |
58 | myScriptEngine.World.EventManager.OnObjectGrabbing += touch; | 58 | myScriptEngine.World.EventManager.OnObjectGrabbing += touch; |
@@ -62,6 +62,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
62 | myScriptEngine.World.EventManager.OnScriptNotAtTargetEvent += not_at_target; | 62 | myScriptEngine.World.EventManager.OnScriptNotAtTargetEvent += not_at_target; |
63 | myScriptEngine.World.EventManager.OnScriptAtRotTargetEvent += at_rot_target; | 63 | myScriptEngine.World.EventManager.OnScriptAtRotTargetEvent += at_rot_target; |
64 | myScriptEngine.World.EventManager.OnScriptNotAtRotTargetEvent += not_at_rot_target; | 64 | myScriptEngine.World.EventManager.OnScriptNotAtRotTargetEvent += not_at_rot_target; |
65 | myScriptEngine.World.EventManager.OnScriptMovingStartEvent += moving_start; | ||
66 | myScriptEngine.World.EventManager.OnScriptMovingEndEvent += moving_end; | ||
65 | myScriptEngine.World.EventManager.OnScriptControlEvent += control; | 67 | myScriptEngine.World.EventManager.OnScriptControlEvent += control; |
66 | myScriptEngine.World.EventManager.OnScriptColliderStart += collision_start; | 68 | myScriptEngine.World.EventManager.OnScriptColliderStart += collision_start; |
67 | myScriptEngine.World.EventManager.OnScriptColliding += collision; | 69 | myScriptEngine.World.EventManager.OnScriptColliding += collision; |
@@ -69,7 +71,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
69 | myScriptEngine.World.EventManager.OnScriptLandColliderStart += land_collision_start; | 71 | myScriptEngine.World.EventManager.OnScriptLandColliderStart += land_collision_start; |
70 | myScriptEngine.World.EventManager.OnScriptLandColliding += land_collision; | 72 | myScriptEngine.World.EventManager.OnScriptLandColliding += land_collision; |
71 | myScriptEngine.World.EventManager.OnScriptLandColliderEnd += land_collision_end; | 73 | myScriptEngine.World.EventManager.OnScriptLandColliderEnd += land_collision_end; |
72 | IMoneyModule money=myScriptEngine.World.RequestModuleInterface<IMoneyModule>(); | 74 | IMoneyModule money = myScriptEngine.World.RequestModuleInterface<IMoneyModule>(); |
73 | if (money != null) | 75 | if (money != null) |
74 | { | 76 | { |
75 | money.OnObjectPaid+=HandleObjectPaid; | 77 | money.OnObjectPaid+=HandleObjectPaid; |
@@ -419,14 +421,14 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
419 | // dataserver: not handled here | 421 | // dataserver: not handled here |
420 | // link_message: not handled here | 422 | // link_message: not handled here |
421 | 423 | ||
422 | public void moving_start(uint localID, UUID itemID) | 424 | public void moving_start(uint localID) |
423 | { | 425 | { |
424 | myScriptEngine.PostObjectEvent(localID, new EventParams( | 426 | myScriptEngine.PostObjectEvent(localID, new EventParams( |
425 | "moving_start",new object[0], | 427 | "moving_start",new object[0], |
426 | new DetectParams[0])); | 428 | new DetectParams[0])); |
427 | } | 429 | } |
428 | 430 | ||
429 | public void moving_end(uint localID, UUID itemID) | 431 | public void moving_end(uint localID) |
430 | { | 432 | { |
431 | myScriptEngine.PostObjectEvent(localID, new EventParams( | 433 | myScriptEngine.PostObjectEvent(localID, new EventParams( |
432 | "moving_end",new object[0], | 434 | "moving_end",new object[0], |
diff --git a/OpenSim/Region/ScriptEngine/XEngine/Properties/AssemblyInfo.cs b/OpenSim/Region/ScriptEngine/XEngine/Properties/AssemblyInfo.cs index bd26a8b..f0640da 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/Properties/AssemblyInfo.cs | |||
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices; | |||
29 | // Build Number | 29 | // Build Number |
30 | // Revision | 30 | // Revision |
31 | // | 31 | // |
32 | [assembly: AssemblyVersion("0.7.5.*")] | 32 | [assembly: AssemblyVersion("0.7.6.*")] |
33 | [assembly: AssemblyFileVersion("1.0.0.0")] | 33 | |
diff --git a/OpenSim/Region/ScriptEngine/XEngine/ScriptEngineConsoleCommands.cs b/OpenSim/Region/ScriptEngine/XEngine/ScriptEngineConsoleCommands.cs new file mode 100644 index 0000000..efb854d --- /dev/null +++ b/OpenSim/Region/ScriptEngine/XEngine/ScriptEngineConsoleCommands.cs | |||
@@ -0,0 +1,126 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using OpenSim.Framework; | ||
31 | using OpenSim.Framework.Console; | ||
32 | using OpenSim.Region.ScriptEngine.Interfaces; | ||
33 | using OpenSim.Region.ScriptEngine.Shared.Api; | ||
34 | using OpenSim.Region.ScriptEngine.Shared.Api.Plugins; | ||
35 | |||
36 | namespace OpenSim.Region.ScriptEngine.XEngine | ||
37 | { | ||
38 | public class ScriptEngineConsoleCommands | ||
39 | { | ||
40 | IScriptEngine m_engine; | ||
41 | |||
42 | public ScriptEngineConsoleCommands(IScriptEngine engine) | ||
43 | { | ||
44 | m_engine = engine; | ||
45 | } | ||
46 | |||
47 | public void RegisterCommands() | ||
48 | { | ||
49 | MainConsole.Instance.Commands.AddCommand( | ||
50 | "Scripts", false, "show script sensors", "show script sensors", "Show script sensors information", | ||
51 | HandleShowSensors); | ||
52 | |||
53 | MainConsole.Instance.Commands.AddCommand( | ||
54 | "Scripts", false, "show script timers", "show script timers", "Show script sensors information", | ||
55 | HandleShowTimers); | ||
56 | } | ||
57 | |||
58 | private bool IsSceneSelected() | ||
59 | { | ||
60 | return MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_engine.World; | ||
61 | } | ||
62 | |||
63 | private void HandleShowSensors(string module, string[] cmdparams) | ||
64 | { | ||
65 | if (!IsSceneSelected()) | ||
66 | return; | ||
67 | |||
68 | SensorRepeat sr = AsyncCommandManager.GetSensorRepeatPlugin(m_engine); | ||
69 | |||
70 | if (sr == null) | ||
71 | { | ||
72 | MainConsole.Instance.Output("Plugin not yet initialized"); | ||
73 | return; | ||
74 | } | ||
75 | |||
76 | List<SensorRepeat.SensorInfo> sensorInfo = sr.GetSensorInfo(); | ||
77 | |||
78 | ConsoleDisplayTable cdt = new ConsoleDisplayTable(); | ||
79 | cdt.AddColumn("Part name", 40); | ||
80 | cdt.AddColumn("Script item ID", 36); | ||
81 | cdt.AddColumn("Type", 4); | ||
82 | cdt.AddColumn("Interval", 8); | ||
83 | cdt.AddColumn("Range", 8); | ||
84 | cdt.AddColumn("Arc", 8); | ||
85 | |||
86 | foreach (SensorRepeat.SensorInfo s in sensorInfo) | ||
87 | { | ||
88 | cdt.AddRow(s.host.Name, s.itemID, s.type, s.interval, s.range, s.arc); | ||
89 | } | ||
90 | |||
91 | MainConsole.Instance.Output(cdt.ToString()); | ||
92 | MainConsole.Instance.OutputFormat("Total: {0}", sensorInfo.Count); | ||
93 | } | ||
94 | |||
95 | private void HandleShowTimers(string module, string[] cmdparams) | ||
96 | { | ||
97 | if (!IsSceneSelected()) | ||
98 | return; | ||
99 | |||
100 | Timer timerPlugin = AsyncCommandManager.GetTimerPlugin(m_engine); | ||
101 | |||
102 | if (timerPlugin == null) | ||
103 | { | ||
104 | MainConsole.Instance.Output("Plugin not yet initialized"); | ||
105 | return; | ||
106 | } | ||
107 | |||
108 | List<Timer.TimerInfo> timersInfo = timerPlugin.GetTimersInfo(); | ||
109 | |||
110 | ConsoleDisplayTable cdt = new ConsoleDisplayTable(); | ||
111 | cdt.AddColumn("Part local ID", 13); | ||
112 | cdt.AddColumn("Script item ID", 36); | ||
113 | cdt.AddColumn("Interval", 10); | ||
114 | cdt.AddColumn("Next", 8); | ||
115 | |||
116 | foreach (Timer.TimerInfo t in timersInfo) | ||
117 | { | ||
118 | // Convert from 100 ns ticks back to seconds | ||
119 | cdt.AddRow(t.localID, t.itemID, (double)t.interval / 10000000, t.next); | ||
120 | } | ||
121 | |||
122 | MainConsole.Instance.Output(cdt.ToString()); | ||
123 | MainConsole.Instance.OutputFormat("Total: {0}", timersInfo.Count); | ||
124 | } | ||
125 | } | ||
126 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineTest.cs b/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineBasicTests.cs index f331658..5abfe9a 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineTest.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineBasicTests.cs | |||
@@ -44,7 +44,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine.Tests | |||
44 | /// XEngine tests. | 44 | /// XEngine tests. |
45 | /// </summary> | 45 | /// </summary> |
46 | [TestFixture] | 46 | [TestFixture] |
47 | public class XEngineTest | 47 | public class XEngineTest : OpenSimTestCase |
48 | { | 48 | { |
49 | private TestScene m_scene; | 49 | private TestScene m_scene; |
50 | private XEngine m_xEngine; | 50 | private XEngine m_xEngine; |
diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs index 9f05666..17243ab 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs | |||
@@ -31,6 +31,7 @@ using System.Collections.Generic; | |||
31 | using System.Diagnostics; //for [DebuggerNonUserCode] | 31 | using System.Diagnostics; //for [DebuggerNonUserCode] |
32 | using System.Globalization; | 32 | using System.Globalization; |
33 | using System.IO; | 33 | using System.IO; |
34 | using System.Linq; | ||
34 | using System.Reflection; | 35 | using System.Reflection; |
35 | using System.Security; | 36 | using System.Security; |
36 | using System.Security.Policy; | 37 | using System.Security.Policy; |
@@ -46,13 +47,14 @@ using OpenSim.Framework; | |||
46 | using OpenSim.Framework.Console; | 47 | using OpenSim.Framework.Console; |
47 | using OpenSim.Region.Framework.Scenes; | 48 | using OpenSim.Region.Framework.Scenes; |
48 | using OpenSim.Region.Framework.Interfaces; | 49 | using OpenSim.Region.Framework.Interfaces; |
50 | using OpenSim.Region.ScriptEngine.Interfaces; | ||
49 | using OpenSim.Region.ScriptEngine.Shared; | 51 | using OpenSim.Region.ScriptEngine.Shared; |
50 | using OpenSim.Region.ScriptEngine.Shared.ScriptBase; | ||
51 | using OpenSim.Region.ScriptEngine.Shared.CodeTools; | 52 | using OpenSim.Region.ScriptEngine.Shared.CodeTools; |
52 | using OpenSim.Region.ScriptEngine.Shared.Instance; | 53 | using OpenSim.Region.ScriptEngine.Shared.Instance; |
53 | using OpenSim.Region.ScriptEngine.Shared.Api; | 54 | using OpenSim.Region.ScriptEngine.Shared.Api; |
54 | using OpenSim.Region.ScriptEngine.Shared.Api.Plugins; | 55 | using OpenSim.Region.ScriptEngine.Shared.Api.Plugins; |
55 | using OpenSim.Region.ScriptEngine.Interfaces; | 56 | using OpenSim.Region.ScriptEngine.Shared.ScriptBase; |
57 | using OpenSim.Region.ScriptEngine.XEngine.ScriptBase; | ||
56 | using Timer = OpenSim.Region.ScriptEngine.Shared.Api.Plugins.Timer; | 58 | using Timer = OpenSim.Region.ScriptEngine.Shared.Api.Plugins.Timer; |
57 | 59 | ||
58 | using ScriptCompileQueue = OpenSim.Framework.LocklessQueue<object[]>; | 60 | using ScriptCompileQueue = OpenSim.Framework.LocklessQueue<object[]>; |
@@ -107,6 +109,24 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
107 | private IXmlRpcRouter m_XmlRpcRouter; | 109 | private IXmlRpcRouter m_XmlRpcRouter; |
108 | private int m_EventLimit; | 110 | private int m_EventLimit; |
109 | private bool m_KillTimedOutScripts; | 111 | private bool m_KillTimedOutScripts; |
112 | |||
113 | /// <summary> | ||
114 | /// Number of milliseconds we will wait for a script event to complete on script stop before we forcibly abort | ||
115 | /// its thread. | ||
116 | /// </summary> | ||
117 | /// <remarks> | ||
118 | /// It appears that if a script thread is aborted whilst it is holding ReaderWriterLockSlim (possibly the write | ||
119 | /// lock) then the lock is not properly released. This causes mono 2.6, 2.10 and possibly | ||
120 | /// later to crash, sometimes with symptoms such as a leap to 100% script usage and a vm thead dump showing | ||
121 | /// all threads waiting on release of ReaderWriterLockSlim write thread which none of the threads listed | ||
122 | /// actually hold. | ||
123 | /// | ||
124 | /// Pausing for event completion reduces the risk of this happening. However, it may be that aborting threads | ||
125 | /// is not a mono issue per se but rather a risky activity in itself in an AppDomain that is not immediately | ||
126 | /// shutting down. | ||
127 | /// </remarks> | ||
128 | private int m_WaitForEventCompletionOnScriptStop = 1000; | ||
129 | |||
110 | private string m_ScriptEnginesPath = null; | 130 | private string m_ScriptEnginesPath = null; |
111 | 131 | ||
112 | private ExpiringCache<UUID, bool> m_runFlags = new ExpiringCache<UUID, bool>(); | 132 | private ExpiringCache<UUID, bool> m_runFlags = new ExpiringCache<UUID, bool>(); |
@@ -218,11 +238,21 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
218 | } | 238 | } |
219 | } | 239 | } |
220 | 240 | ||
241 | private ScriptEngineConsoleCommands m_consoleCommands; | ||
242 | |||
221 | public string ScriptEngineName | 243 | public string ScriptEngineName |
222 | { | 244 | { |
223 | get { return "XEngine"; } | 245 | get { return "XEngine"; } |
224 | } | 246 | } |
225 | 247 | ||
248 | public string ScriptClassName { get; private set; } | ||
249 | |||
250 | public string ScriptBaseClassName { get; private set; } | ||
251 | |||
252 | public ParameterInfo[] ScriptBaseClassParameters { get; private set; } | ||
253 | |||
254 | public string[] ScriptReferencedAssemblies { get; private set; } | ||
255 | |||
226 | public Scene World | 256 | public Scene World |
227 | { | 257 | { |
228 | get { return m_Scene; } | 258 | get { return m_Scene; } |
@@ -277,21 +307,35 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
277 | 307 | ||
278 | m_ScriptConfig = configSource.Configs["XEngine"]; | 308 | m_ScriptConfig = configSource.Configs["XEngine"]; |
279 | m_ConfigSource = configSource; | 309 | m_ConfigSource = configSource; |
310 | |||
311 | string rawScriptStopStrategy = m_ScriptConfig.GetString("ScriptStopStrategy", "abort"); | ||
312 | |||
313 | m_log.InfoFormat("[XEngine]: Script stop strategy is {0}", rawScriptStopStrategy); | ||
314 | |||
315 | if (rawScriptStopStrategy == "co-op") | ||
316 | { | ||
317 | ScriptClassName = "XEngineScript"; | ||
318 | ScriptBaseClassName = typeof(XEngineScriptBase).FullName; | ||
319 | ScriptBaseClassParameters = typeof(XEngineScriptBase).GetConstructor(new Type[] { typeof(WaitHandle) }).GetParameters(); | ||
320 | ScriptReferencedAssemblies = new string[] { Path.GetFileName(typeof(XEngineScriptBase).Assembly.Location) }; | ||
321 | } | ||
322 | else | ||
323 | { | ||
324 | ScriptClassName = "Script"; | ||
325 | ScriptBaseClassName = typeof(ScriptBaseClass).FullName; | ||
326 | } | ||
327 | |||
328 | // Console.WriteLine("ASSEMBLY NAME: {0}", ScriptReferencedAssemblies[0]); | ||
280 | } | 329 | } |
281 | 330 | ||
282 | public void AddRegion(Scene scene) | 331 | public void AddRegion(Scene scene) |
283 | { | 332 | { |
284 | if (m_ScriptConfig == null) | 333 | if (m_ScriptConfig == null) |
285 | return; | 334 | return; |
335 | |||
286 | m_ScriptFailCount = 0; | 336 | m_ScriptFailCount = 0; |
287 | m_ScriptErrorMessage = String.Empty; | 337 | m_ScriptErrorMessage = String.Empty; |
288 | 338 | ||
289 | if (m_ScriptConfig == null) | ||
290 | { | ||
291 | // m_log.ErrorFormat("[XEngine] No script configuration found. Scripts disabled"); | ||
292 | return; | ||
293 | } | ||
294 | |||
295 | m_Enabled = m_ScriptConfig.GetBoolean("Enabled", true); | 339 | m_Enabled = m_ScriptConfig.GetBoolean("Enabled", true); |
296 | 340 | ||
297 | if (!m_Enabled) | 341 | if (!m_Enabled) |
@@ -316,6 +360,9 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
316 | m_EventLimit = m_ScriptConfig.GetInt("EventLimit", 30); | 360 | m_EventLimit = m_ScriptConfig.GetInt("EventLimit", 30); |
317 | m_KillTimedOutScripts = m_ScriptConfig.GetBoolean("KillTimedOutScripts", false); | 361 | m_KillTimedOutScripts = m_ScriptConfig.GetBoolean("KillTimedOutScripts", false); |
318 | m_SaveTime = m_ScriptConfig.GetInt("SaveInterval", 120) * 1000; | 362 | m_SaveTime = m_ScriptConfig.GetInt("SaveInterval", 120) * 1000; |
363 | m_WaitForEventCompletionOnScriptStop | ||
364 | = m_ScriptConfig.GetInt("WaitForEventCompletionOnScriptStop", m_WaitForEventCompletionOnScriptStop); | ||
365 | |||
319 | m_ScriptEnginesPath = m_ScriptConfig.GetString("ScriptEnginesPath", "ScriptEngines"); | 366 | m_ScriptEnginesPath = m_ScriptConfig.GetString("ScriptEnginesPath", "ScriptEngines"); |
320 | 367 | ||
321 | m_Prio = ThreadPriority.BelowNormal; | 368 | m_Prio = ThreadPriority.BelowNormal; |
@@ -364,48 +411,59 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
364 | OnObjectRemoved += m_XmlRpcRouter.ObjectRemoved; | 411 | OnObjectRemoved += m_XmlRpcRouter.ObjectRemoved; |
365 | } | 412 | } |
366 | 413 | ||
414 | m_consoleCommands = new ScriptEngineConsoleCommands(this); | ||
415 | m_consoleCommands.RegisterCommands(); | ||
416 | |||
367 | MainConsole.Instance.Commands.AddCommand( | 417 | MainConsole.Instance.Commands.AddCommand( |
368 | "Scripts", false, "xengine status", "xengine status", "Show status information", | 418 | "Scripts", false, "xengine status", "xengine status", "Show status information", |
369 | "Show status information on the script engine.", | 419 | "Show status information on the script engine.", |
370 | HandleShowStatus); | 420 | HandleShowStatus); |
371 | 421 | ||
372 | MainConsole.Instance.Commands.AddCommand( | 422 | MainConsole.Instance.Commands.AddCommand( |
373 | "Scripts", false, "scripts show", "scripts show [<script-item-uuid>]", "Show script information", | 423 | "Scripts", false, "scripts show", "scripts show [<script-item-uuid>+]", "Show script information", |
374 | "Show information on all scripts known to the script engine." | 424 | "Show information on all scripts known to the script engine.\n" |
375 | + "If a <script-item-uuid> is given then only information on that script will be shown.", | 425 | + "If one or more <script-item-uuid>s are given then only information on that script will be shown.", |
376 | HandleShowScripts); | 426 | HandleShowScripts); |
377 | 427 | ||
378 | MainConsole.Instance.Commands.AddCommand( | 428 | MainConsole.Instance.Commands.AddCommand( |
379 | "Scripts", false, "show scripts", "show scripts [<script-item-uuid>]", "Show script information", | 429 | "Scripts", false, "show scripts", "show scripts [<script-item-uuid>+]", "Show script information", |
380 | "Synonym for scripts show command", HandleShowScripts); | 430 | "Synonym for scripts show command", HandleShowScripts); |
381 | 431 | ||
382 | MainConsole.Instance.Commands.AddCommand( | 432 | MainConsole.Instance.Commands.AddCommand( |
383 | "Scripts", false, "scripts suspend", "scripts suspend [<script-item-uuid>]", "Suspends all running scripts", | 433 | "Scripts", false, "scripts suspend", "scripts suspend [<script-item-uuid>+]", "Suspends all running scripts", |
384 | "Suspends all currently running scripts. This only suspends event delivery, it will not suspend a" | 434 | "Suspends all currently running scripts. This only suspends event delivery, it will not suspend a" |
385 | + " script that is currently processing an event.\n" | 435 | + " script that is currently processing an event.\n" |
386 | + "Suspended scripts will continue to accumulate events but won't process them.\n" | 436 | + "Suspended scripts will continue to accumulate events but won't process them.\n" |
387 | + "If a <script-item-uuid> is given then only that script will be suspended. Otherwise, all suitable scripts are suspended.", | 437 | + "If one or more <script-item-uuid>s are given then only that script will be suspended. Otherwise, all suitable scripts are suspended.", |
388 | (module, cmdparams) => HandleScriptsAction(cmdparams, HandleSuspendScript)); | 438 | (module, cmdparams) => HandleScriptsAction(cmdparams, HandleSuspendScript)); |
389 | 439 | ||
390 | MainConsole.Instance.Commands.AddCommand( | 440 | MainConsole.Instance.Commands.AddCommand( |
391 | "Scripts", false, "scripts resume", "scripts resume [<script-item-uuid>]", "Resumes all suspended scripts", | 441 | "Scripts", false, "scripts resume", "scripts resume [<script-item-uuid>+]", "Resumes all suspended scripts", |
392 | "Resumes all currently suspended scripts.\n" | 442 | "Resumes all currently suspended scripts.\n" |
393 | + "Resumed scripts will process all events accumulated whilst suspended." | 443 | + "Resumed scripts will process all events accumulated whilst suspended.\n" |
394 | + "If a <script-item-uuid> is given then only that script will be resumed. Otherwise, all suitable scripts are resumed.", | 444 | + "If one or more <script-item-uuid>s are given then only that script will be resumed. Otherwise, all suitable scripts are resumed.", |
395 | (module, cmdparams) => HandleScriptsAction(cmdparams, HandleResumeScript)); | 445 | (module, cmdparams) => HandleScriptsAction(cmdparams, HandleResumeScript)); |
396 | 446 | ||
397 | MainConsole.Instance.Commands.AddCommand( | 447 | MainConsole.Instance.Commands.AddCommand( |
398 | "Scripts", false, "scripts stop", "scripts stop [<script-item-uuid>]", "Stops all running scripts", | 448 | "Scripts", false, "scripts stop", "scripts stop [<script-item-uuid>+]", "Stops all running scripts", |
399 | "Stops all running scripts." | 449 | "Stops all running scripts.\n" |
400 | + "If a <script-item-uuid> is given then only that script will be stopped. Otherwise, all suitable scripts are stopped.", | 450 | + "If one or more <script-item-uuid>s are given then only that script will be stopped. Otherwise, all suitable scripts are stopped.", |
401 | (module, cmdparams) => HandleScriptsAction(cmdparams, HandleStopScript)); | 451 | (module, cmdparams) => HandleScriptsAction(cmdparams, HandleStopScript)); |
402 | 452 | ||
403 | MainConsole.Instance.Commands.AddCommand( | 453 | MainConsole.Instance.Commands.AddCommand( |
404 | "Scripts", false, "scripts start", "scripts start [<script-item-uuid>]", "Starts all stopped scripts", | 454 | "Scripts", false, "scripts start", "scripts start [<script-item-uuid>+]", "Starts all stopped scripts", |
405 | "Starts all stopped scripts." | 455 | "Starts all stopped scripts.\n" |
406 | + "If a <script-item-uuid> is given then only that script will be started. Otherwise, all suitable scripts are started.", | 456 | + "If one or more <script-item-uuid>s are given then only that script will be started. Otherwise, all suitable scripts are started.", |
407 | (module, cmdparams) => HandleScriptsAction(cmdparams, HandleStartScript)); | 457 | (module, cmdparams) => HandleScriptsAction(cmdparams, HandleStartScript)); |
408 | 458 | ||
459 | MainConsole.Instance.Commands.AddCommand( | ||
460 | "Scripts", false, "debug scripts log", "debug scripts log <item-id> <log-level>", "Extra debug logging for a script", | ||
461 | "Activates or deactivates extra debug logging for the given script.\n" | ||
462 | + "Level == 0, deactivate extra debug logging.\n" | ||
463 | + "Level >= 1, log state changes.\n" | ||
464 | + "Level >= 2, log event invocations.\n", | ||
465 | HandleDebugScriptLogCommand); | ||
466 | |||
409 | // MainConsole.Instance.Commands.AddCommand( | 467 | // MainConsole.Instance.Commands.AddCommand( |
410 | // "Debug", false, "debug xengine", "debug xengine [<level>]", | 468 | // "Debug", false, "debug xengine", "debug xengine [<level>]", |
411 | // "Turn on detailed xengine debugging.", | 469 | // "Turn on detailed xengine debugging.", |
@@ -414,6 +472,41 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
414 | // HandleDebugLevelCommand); | 472 | // HandleDebugLevelCommand); |
415 | } | 473 | } |
416 | 474 | ||
475 | private void HandleDebugScriptLogCommand(string module, string[] args) | ||
476 | { | ||
477 | if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene)) | ||
478 | return; | ||
479 | |||
480 | if (args.Length != 5) | ||
481 | { | ||
482 | MainConsole.Instance.Output("Usage: debug script log <item-id> <log-level>"); | ||
483 | return; | ||
484 | } | ||
485 | |||
486 | UUID itemId; | ||
487 | |||
488 | if (!ConsoleUtil.TryParseConsoleUuid(MainConsole.Instance, args[3], out itemId)) | ||
489 | return; | ||
490 | |||
491 | int newLevel; | ||
492 | |||
493 | if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, args[4], out newLevel)) | ||
494 | return; | ||
495 | |||
496 | IScriptInstance si; | ||
497 | |||
498 | lock (m_Scripts) | ||
499 | { | ||
500 | // XXX: We can't give the user feedback on a bad item id because this may apply to a different script | ||
501 | // engine | ||
502 | if (!m_Scripts.TryGetValue(itemId, out si)) | ||
503 | return; | ||
504 | } | ||
505 | |||
506 | si.DebugLevel = newLevel; | ||
507 | MainConsole.Instance.OutputFormat("Set debug level of {0} {1} to {2}", si.ScriptName, si.ItemID, newLevel); | ||
508 | } | ||
509 | |||
417 | /// <summary> | 510 | /// <summary> |
418 | /// Change debug level | 511 | /// Change debug level |
419 | /// </summary> | 512 | /// </summary> |
@@ -445,9 +538,21 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
445 | /// </summary> | 538 | /// </summary> |
446 | /// <param name="cmdparams"></param> | 539 | /// <param name="cmdparams"></param> |
447 | /// <param name="instance"></param> | 540 | /// <param name="instance"></param> |
448 | /// <returns>true if we're okay to proceed, false if not.</returns> | 541 | /// <param name="comparer">Basis on which to sort output. Can be null if no sort needs to take place</param> |
449 | private void HandleScriptsAction(string[] cmdparams, Action<IScriptInstance> action) | 542 | private void HandleScriptsAction(string[] cmdparams, Action<IScriptInstance> action) |
450 | { | 543 | { |
544 | HandleScriptsAction<object>(cmdparams, action, null); | ||
545 | } | ||
546 | |||
547 | /// <summary> | ||
548 | /// Parse the raw item id into a script instance from the command params if it's present. | ||
549 | /// </summary> | ||
550 | /// <param name="cmdparams"></param> | ||
551 | /// <param name="instance"></param> | ||
552 | /// <param name="keySelector">Basis on which to sort output. Can be null if no sort needs to take place</param> | ||
553 | private void HandleScriptsAction<TKey>( | ||
554 | string[] cmdparams, Action<IScriptInstance> action, Func<IScriptInstance, TKey> keySelector) | ||
555 | { | ||
451 | if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene)) | 556 | if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene)) |
452 | return; | 557 | return; |
453 | 558 | ||
@@ -458,35 +563,42 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
458 | 563 | ||
459 | if (cmdparams.Length == 2) | 564 | if (cmdparams.Length == 2) |
460 | { | 565 | { |
461 | foreach (IScriptInstance instance in m_Scripts.Values) | 566 | IEnumerable<IScriptInstance> scripts = m_Scripts.Values; |
567 | |||
568 | if (keySelector != null) | ||
569 | scripts = scripts.OrderBy<IScriptInstance, TKey>(keySelector); | ||
570 | |||
571 | foreach (IScriptInstance instance in scripts) | ||
462 | action(instance); | 572 | action(instance); |
463 | 573 | ||
464 | return; | 574 | return; |
465 | } | 575 | } |
466 | 576 | ||
467 | rawItemId = cmdparams[2]; | 577 | for (int i = 2; i < cmdparams.Length; i++) |
468 | |||
469 | if (!UUID.TryParse(rawItemId, out itemId)) | ||
470 | { | ||
471 | MainConsole.Instance.OutputFormat("Error - {0} is not a valid UUID", rawItemId); | ||
472 | return; | ||
473 | } | ||
474 | |||
475 | if (itemId != UUID.Zero) | ||
476 | { | 578 | { |
477 | IScriptInstance instance = GetInstance(itemId); | 579 | rawItemId = cmdparams[i]; |
478 | if (instance == null) | 580 | |
581 | if (!UUID.TryParse(rawItemId, out itemId)) | ||
479 | { | 582 | { |
480 | // Commented out for now since this will cause false reports on simulators with more than | 583 | MainConsole.Instance.OutputFormat("ERROR: {0} is not a valid UUID", rawItemId); |
481 | // one scene where the current command line set region is 'root' (which causes commands to | 584 | continue; |
482 | // go to both regions... (sigh) | ||
483 | // MainConsole.Instance.OutputFormat("Error - No item found with id {0}", itemId); | ||
484 | return; | ||
485 | } | 585 | } |
486 | else | 586 | |
587 | if (itemId != UUID.Zero) | ||
487 | { | 588 | { |
488 | action(instance); | 589 | IScriptInstance instance = GetInstance(itemId); |
489 | return; | 590 | if (instance == null) |
591 | { | ||
592 | // Commented out for now since this will cause false reports on simulators with more than | ||
593 | // one scene where the current command line set region is 'root' (which causes commands to | ||
594 | // go to both regions... (sigh) | ||
595 | // MainConsole.Instance.OutputFormat("Error - No item found with id {0}", itemId); | ||
596 | continue; | ||
597 | } | ||
598 | else | ||
599 | { | ||
600 | action(instance); | ||
601 | } | ||
490 | } | 602 | } |
491 | } | 603 | } |
492 | } | 604 | } |
@@ -505,9 +617,20 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
505 | StringBuilder sb = new StringBuilder(); | 617 | StringBuilder sb = new StringBuilder(); |
506 | sb.AppendFormat("Status of XEngine instance for {0}\n", m_Scene.RegionInfo.RegionName); | 618 | sb.AppendFormat("Status of XEngine instance for {0}\n", m_Scene.RegionInfo.RegionName); |
507 | 619 | ||
620 | long scriptsLoaded, eventsQueued = 0, eventsProcessed = 0; | ||
621 | |||
508 | lock (m_Scripts) | 622 | lock (m_Scripts) |
509 | sb.AppendFormat("Scripts loaded : {0}\n", m_Scripts.Count); | 623 | { |
624 | scriptsLoaded = m_Scripts.Count; | ||
510 | 625 | ||
626 | foreach (IScriptInstance si in m_Scripts.Values) | ||
627 | { | ||
628 | eventsQueued += si.EventsQueued; | ||
629 | eventsProcessed += si.EventsProcessed; | ||
630 | } | ||
631 | } | ||
632 | |||
633 | sb.AppendFormat("Scripts loaded : {0}\n", scriptsLoaded); | ||
511 | sb.AppendFormat("Unique scripts : {0}\n", m_uniqueScripts.Count); | 634 | sb.AppendFormat("Unique scripts : {0}\n", m_uniqueScripts.Count); |
512 | sb.AppendFormat("Scripts waiting for load : {0}\n", m_CompileQueue.Count); | 635 | sb.AppendFormat("Scripts waiting for load : {0}\n", m_CompileQueue.Count); |
513 | sb.AppendFormat("Max threads : {0}\n", m_ThreadPool.MaxThreads); | 636 | sb.AppendFormat("Max threads : {0}\n", m_ThreadPool.MaxThreads); |
@@ -516,6 +639,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
516 | sb.AppendFormat("In use threads : {0}\n", m_ThreadPool.InUseThreads); | 639 | sb.AppendFormat("In use threads : {0}\n", m_ThreadPool.InUseThreads); |
517 | sb.AppendFormat("Work items waiting : {0}\n", m_ThreadPool.WaitingCallbacks); | 640 | sb.AppendFormat("Work items waiting : {0}\n", m_ThreadPool.WaitingCallbacks); |
518 | // sb.AppendFormat("Assemblies loaded : {0}\n", m_Assemblies.Count); | 641 | // sb.AppendFormat("Assemblies loaded : {0}\n", m_Assemblies.Count); |
642 | sb.AppendFormat("Events queued : {0}\n", eventsQueued); | ||
643 | sb.AppendFormat("Events processed : {0}\n", eventsProcessed); | ||
519 | 644 | ||
520 | SensorRepeat sr = AsyncCommandManager.GetSensorRepeatPlugin(this); | 645 | SensorRepeat sr = AsyncCommandManager.GetSensorRepeatPlugin(this); |
521 | sb.AppendFormat("Sensors : {0}\n", sr != null ? sr.SensorsCount : 0); | 646 | sb.AppendFormat("Sensors : {0}\n", sr != null ? sr.SensorsCount : 0); |
@@ -546,7 +671,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
546 | } | 671 | } |
547 | } | 672 | } |
548 | 673 | ||
549 | HandleScriptsAction(cmdparams, HandleShowScript); | 674 | HandleScriptsAction<long>(cmdparams, HandleShowScript, si => si.EventsProcessed); |
550 | } | 675 | } |
551 | 676 | ||
552 | private void HandleShowScript(IScriptInstance instance) | 677 | private void HandleShowScript(IScriptInstance instance) |
@@ -572,15 +697,13 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
572 | } | 697 | } |
573 | 698 | ||
574 | StringBuilder sb = new StringBuilder(); | 699 | StringBuilder sb = new StringBuilder(); |
575 | Queue eq = instance.EventQueue; | ||
576 | 700 | ||
577 | sb.AppendFormat("Script name : {0}\n", instance.ScriptName); | 701 | sb.AppendFormat("Script name : {0}\n", instance.ScriptName); |
578 | sb.AppendFormat("Status : {0}\n", status); | 702 | sb.AppendFormat("Status : {0}\n", status); |
579 | 703 | sb.AppendFormat("Queued events : {0}\n", instance.EventsQueued); | |
580 | lock (eq) | 704 | sb.AppendFormat("Processed events : {0}\n", instance.EventsProcessed); |
581 | sb.AppendFormat("Queued events : {0}\n", eq.Count); | ||
582 | |||
583 | sb.AppendFormat("Item UUID : {0}\n", instance.ItemID); | 705 | sb.AppendFormat("Item UUID : {0}\n", instance.ItemID); |
706 | sb.AppendFormat("Asset UUID : {0}\n", instance.AssetID); | ||
584 | sb.AppendFormat("Containing part name: {0}\n", instance.PrimName); | 707 | sb.AppendFormat("Containing part name: {0}\n", instance.PrimName); |
585 | sb.AppendFormat("Containing part UUID: {0}\n", instance.ObjectID); | 708 | sb.AppendFormat("Containing part UUID: {0}\n", instance.ObjectID); |
586 | sb.AppendFormat("Position : {0}\n", sop.AbsolutePosition); | 709 | sb.AppendFormat("Position : {0}\n", sop.AbsolutePosition); |
@@ -1079,7 +1202,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1079 | } | 1202 | } |
1080 | 1203 | ||
1081 | m_log.DebugFormat( | 1204 | m_log.DebugFormat( |
1082 | "[XEngine] Loading script {0}.{1}, item UUID {2}, prim UUID {3} @ {4}.{5}", | 1205 | "[XEngine]: Loading script {0}.{1}, item UUID {2}, prim UUID {3} @ {4}.{5}", |
1083 | part.ParentGroup.RootPart.Name, item.Name, itemID, part.UUID, | 1206 | part.ParentGroup.RootPart.Name, item.Name, itemID, part.UUID, |
1084 | part.ParentGroup.RootPart.AbsolutePosition, part.ParentGroup.Scene.RegionInfo.RegionName); | 1207 | part.ParentGroup.RootPart.AbsolutePosition, part.ParentGroup.Scene.RegionInfo.RegionName); |
1085 | 1208 | ||
@@ -1089,8 +1212,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1089 | 1212 | ||
1090 | string assembly = ""; | 1213 | string assembly = ""; |
1091 | 1214 | ||
1092 | CultureInfo USCulture = new CultureInfo("en-US"); | 1215 | Culture.SetCurrentCulture(); |
1093 | Thread.CurrentThread.CurrentCulture = USCulture; | ||
1094 | 1216 | ||
1095 | Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> linemap; | 1217 | Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> linemap; |
1096 | 1218 | ||
@@ -1101,6 +1223,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1101 | lock (m_AddingAssemblies) | 1223 | lock (m_AddingAssemblies) |
1102 | { | 1224 | { |
1103 | m_Compiler.PerformScriptCompile(script, assetID.ToString(), item.OwnerID, out assembly, out linemap); | 1225 | m_Compiler.PerformScriptCompile(script, assetID.ToString(), item.OwnerID, out assembly, out linemap); |
1226 | |||
1104 | if (!m_AddingAssemblies.ContainsKey(assembly)) { | 1227 | if (!m_AddingAssemblies.ContainsKey(assembly)) { |
1105 | m_AddingAssemblies[assembly] = 1; | 1228 | m_AddingAssemblies[assembly] = 1; |
1106 | } else { | 1229 | } else { |
@@ -1150,7 +1273,9 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1150 | } | 1273 | } |
1151 | catch (Exception e) | 1274 | catch (Exception e) |
1152 | { | 1275 | { |
1153 | // m_log.ErrorFormat("[XEngine]: Exception when rezzing script {0}{1}", e.Message, e.StackTrace); | 1276 | // m_log.ErrorFormat( |
1277 | // "[XEngine]: Exception when rezzing script with item ID {0}, {1}{2}", | ||
1278 | // itemID, e.Message, e.StackTrace); | ||
1154 | 1279 | ||
1155 | // try | 1280 | // try |
1156 | // { | 1281 | // { |
@@ -1229,13 +1354,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1229 | sandbox = AppDomain.CurrentDomain; | 1354 | sandbox = AppDomain.CurrentDomain; |
1230 | } | 1355 | } |
1231 | 1356 | ||
1232 | //PolicyLevel sandboxPolicy = PolicyLevel.CreateAppDomainLevel(); | 1357 | if (!instance.Load(m_AppDomains[appDomain], assembly, stateSource)) |
1233 | //AllMembershipCondition sandboxMembershipCondition = new AllMembershipCondition(); | 1358 | return false; |
1234 | //PermissionSet sandboxPermissionSet = sandboxPolicy.GetNamedPermissionSet("Internet"); | ||
1235 | //PolicyStatement sandboxPolicyStatement = new PolicyStatement(sandboxPermissionSet); | ||
1236 | //CodeGroup sandboxCodeGroup = new UnionCodeGroup(sandboxMembershipCondition, sandboxPolicyStatement); | ||
1237 | //sandboxPolicy.RootCodeGroup = sandboxCodeGroup; | ||
1238 | //sandbox.SetAppDomainPolicy(sandboxPolicy); | ||
1239 | 1359 | ||
1240 | m_AppDomains[appDomain] = sandbox; | 1360 | m_AppDomains[appDomain] = sandbox; |
1241 | 1361 | ||
@@ -1256,12 +1376,11 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1256 | m_DomainScripts[appDomain].Add(itemID); | 1376 | m_DomainScripts[appDomain].Add(itemID); |
1257 | 1377 | ||
1258 | instance = new ScriptInstance(this, part, | 1378 | instance = new ScriptInstance(this, part, |
1259 | itemID, assetID, assembly, | 1379 | item, |
1260 | m_AppDomains[appDomain], | 1380 | startParam, postOnRez, |
1261 | part.ParentGroup.RootPart.Name, | 1381 | m_MaxScriptQueue); |
1262 | item.Name, startParam, postOnRez, | ||
1263 | stateSource, m_MaxScriptQueue); | ||
1264 | 1382 | ||
1383 | instance.Load(m_AppDomains[appDomain], assembly, stateSource); | ||
1265 | // m_log.DebugFormat( | 1384 | // m_log.DebugFormat( |
1266 | // "[XEngine] Loaded script {0}.{1}, script UUID {2}, prim UUID {3} @ {4}.{5}", | 1385 | // "[XEngine] Loaded script {0}.{1}, script UUID {2}, prim UUID {3} @ {4}.{5}", |
1267 | // part.ParentGroup.RootPart.Name, item.Name, assetID, part.UUID, | 1386 | // part.ParentGroup.RootPart.Name, item.Name, assetID, part.UUID, |
@@ -1347,9 +1466,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1347 | lockScriptsForWrite(false); | 1466 | lockScriptsForWrite(false); |
1348 | instance.ClearQueue(); | 1467 | instance.ClearQueue(); |
1349 | 1468 | ||
1350 | // Give the script some time to finish processing its last event. Simply aborting the script thread can | 1469 | instance.Stop(m_WaitForEventCompletionOnScriptStop); |
1351 | // cause issues on mono 2.6, 2.10 and possibly later where locks are not released properly on abort. | ||
1352 | instance.Stop(1000); | ||
1353 | 1470 | ||
1354 | // bool objectRemoved = false; | 1471 | // bool objectRemoved = false; |
1355 | 1472 | ||
@@ -1477,7 +1594,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1477 | m_MaxScriptQueue = maxScriptQueue; | 1594 | m_MaxScriptQueue = maxScriptQueue; |
1478 | 1595 | ||
1479 | STPStartInfo startInfo = new STPStartInfo(); | 1596 | STPStartInfo startInfo = new STPStartInfo(); |
1480 | startInfo.IdleTimeout = idleTimeout*1000; // convert to seconds as stated in .ini | 1597 | startInfo.ThreadPoolName = "XEngine"; |
1598 | startInfo.IdleTimeout = idleTimeout * 1000; // convert to seconds as stated in .ini | ||
1481 | startInfo.MaxWorkerThreads = maxThreads; | 1599 | startInfo.MaxWorkerThreads = maxThreads; |
1482 | startInfo.MinWorkerThreads = minThreads; | 1600 | startInfo.MinWorkerThreads = minThreads; |
1483 | startInfo.ThreadPriority = threadPriority;; | 1601 | startInfo.ThreadPriority = threadPriority;; |
@@ -1504,8 +1622,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1504 | /// <returns></returns> | 1622 | /// <returns></returns> |
1505 | private object ProcessEventHandler(object parms) | 1623 | private object ProcessEventHandler(object parms) |
1506 | { | 1624 | { |
1507 | CultureInfo USCulture = new CultureInfo("en-US"); | 1625 | Culture.SetCurrentCulture(); |
1508 | Thread.CurrentThread.CurrentCulture = USCulture; | ||
1509 | 1626 | ||
1510 | IScriptInstance instance = (ScriptInstance) parms; | 1627 | IScriptInstance instance = (ScriptInstance) parms; |
1511 | 1628 | ||
@@ -1693,7 +1810,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1693 | { | 1810 | { |
1694 | IScriptInstance instance = GetInstance(itemID); | 1811 | IScriptInstance instance = GetInstance(itemID); |
1695 | if (instance != null) | 1812 | if (instance != null) |
1696 | instance.ResetScript(); | 1813 | instance.ResetScript(m_WaitForEventCompletionOnScriptStop); |
1697 | } | 1814 | } |
1698 | 1815 | ||
1699 | public void StartScript(UUID itemID) | 1816 | public void StartScript(UUID itemID) |
@@ -1708,14 +1825,14 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1708 | public void StopScript(UUID itemID) | 1825 | public void StopScript(UUID itemID) |
1709 | { | 1826 | { |
1710 | IScriptInstance instance = GetInstance(itemID); | 1827 | IScriptInstance instance = GetInstance(itemID); |
1828 | |||
1711 | if (instance != null) | 1829 | if (instance != null) |
1712 | { | 1830 | { |
1713 | // Give the script some time to finish processing its last event. Simply aborting the script thread can | 1831 | instance.Stop(m_WaitForEventCompletionOnScriptStop); |
1714 | // cause issues on mono 2.6, 2.10 and possibly later where locks are not released properly on abort. | ||
1715 | instance.Stop(1000); | ||
1716 | } | 1832 | } |
1717 | else | 1833 | else |
1718 | { | 1834 | { |
1835 | // m_log.DebugFormat("[XENGINE]: Could not find script with ID {0} to stop in {1}", itemID, World.Name); | ||
1719 | m_runFlags.AddOrUpdate(itemID, false, 240); | 1836 | m_runFlags.AddOrUpdate(itemID, false, 240); |
1720 | } | 1837 | } |
1721 | } | 1838 | } |
diff --git a/OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs b/OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs index 2ac5c31..8dd7677 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs | |||
@@ -57,8 +57,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
57 | wr.Abort(); | 57 | wr.Abort(); |
58 | } | 58 | } |
59 | 59 | ||
60 | public bool Wait(TimeSpan t) | 60 | public bool Wait(int t) |
61 | { | 61 | { |
62 | // We use the integer version of WaitAll because the current version of SmartThreadPool has a bug with the | ||
63 | // TimeSpan version. The number of milliseconds in TimeSpan is an int64 so when STP casts it down to an | ||
64 | // int (32-bit) we can end up with bad values. This occurs on Windows though curious not on Mono 2.10.8 | ||
65 | // (or very likely other versions of Mono at least up until 3.0.3). | ||
62 | return SmartThreadPool.WaitAll(new IWorkItemResult[] {wr}, t, false); | 66 | return SmartThreadPool.WaitAll(new IWorkItemResult[] {wr}, t, false); |
63 | } | 67 | } |
64 | } | 68 | } |
diff --git a/OpenSim/Region/UserStatistics/ActiveConnectionsAJAX.cs b/OpenSim/Region/UserStatistics/ActiveConnectionsAJAX.cs index 3243a9a..6a1112c 100644 --- a/OpenSim/Region/UserStatistics/ActiveConnectionsAJAX.cs +++ b/OpenSim/Region/UserStatistics/ActiveConnectionsAJAX.cs | |||
@@ -32,6 +32,7 @@ using System.Reflection; | |||
32 | using System.Text; | 32 | using System.Text; |
33 | using Mono.Data.SqliteClient; | 33 | using Mono.Data.SqliteClient; |
34 | using OpenMetaverse; | 34 | using OpenMetaverse; |
35 | using OpenMetaverse.StructuredData; | ||
35 | using OpenSim.Framework; | 36 | using OpenSim.Framework; |
36 | using OpenSim.Region.Framework.Scenes; | 37 | using OpenSim.Region.Framework.Scenes; |
37 | using OpenSim.Framework.Monitoring; | 38 | using OpenSim.Framework.Monitoring; |
@@ -51,7 +52,6 @@ namespace OpenSim.Region.UserStatistics | |||
51 | 52 | ||
52 | public Hashtable ProcessModel(Hashtable pParams) | 53 | public Hashtable ProcessModel(Hashtable pParams) |
53 | { | 54 | { |
54 | |||
55 | List<Scene> m_scene = (List<Scene>)pParams["Scenes"]; | 55 | List<Scene> m_scene = (List<Scene>)pParams["Scenes"]; |
56 | 56 | ||
57 | Hashtable nh = new Hashtable(); | 57 | Hashtable nh = new Hashtable(); |
@@ -129,6 +129,86 @@ namespace OpenSim.Region.UserStatistics | |||
129 | return output.ToString(); | 129 | return output.ToString(); |
130 | } | 130 | } |
131 | 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 | |||
132 | public Dictionary<string, int> DecodeClientThrottles(byte[] throttle) | 212 | public Dictionary<string, int> DecodeClientThrottles(byte[] throttle) |
133 | { | 213 | { |
134 | Dictionary<string, int> returndict = new Dictionary<string, int>(); | 214 | Dictionary<string, int> returndict = new Dictionary<string, int>(); |
@@ -203,7 +283,7 @@ namespace OpenSim.Region.UserStatistics | |||
203 | returndic.Add("Cloud", rep.Substring((7 * pos) , 8)); pos++; | 283 | returndic.Add("Cloud", rep.Substring((7 * pos) , 8)); pos++; |
204 | returndic.Add("Task", rep.Substring((7 * pos) , 8)); pos++; | 284 | returndic.Add("Task", rep.Substring((7 * pos) , 8)); pos++; |
205 | returndic.Add("Texture", rep.Substring((7 * pos), 8)); pos++; | 285 | returndic.Add("Texture", rep.Substring((7 * pos), 8)); pos++; |
206 | returndic.Add("Asset", rep.Substring((7 * pos), 8)); | 286 | returndic.Add("Asset", rep.Substring((7 * pos), 8)); |
207 | /* | 287 | /* |
208 | * return string.Format("{0,7} {1,7} {2,7} {3,7} {4,7} {5,7} {6,7} {7,7} {8,7} {9,7}", | 288 | * return string.Format("{0,7} {1,7} {2,7} {3,7} {4,7} {5,7} {6,7} {7,7} {8,7} {9,7}", |
209 | SendQueue.Count(), | 289 | SendQueue.Count(), |
diff --git a/OpenSim/Region/UserStatistics/Clients_report.cs b/OpenSim/Region/UserStatistics/Clients_report.cs index b2bb33b..4a6f7be 100644 --- a/OpenSim/Region/UserStatistics/Clients_report.cs +++ b/OpenSim/Region/UserStatistics/Clients_report.cs | |||
@@ -31,6 +31,7 @@ using System.Collections.Generic; | |||
31 | using System.Text; | 31 | using System.Text; |
32 | using Mono.Data.SqliteClient; | 32 | using Mono.Data.SqliteClient; |
33 | using OpenMetaverse; | 33 | using OpenMetaverse; |
34 | using OpenMetaverse.StructuredData; | ||
34 | using OpenSim.Region.Framework.Scenes; | 35 | using OpenSim.Region.Framework.Scenes; |
35 | 36 | ||
36 | namespace OpenSim.Region.UserStatistics | 37 | namespace OpenSim.Region.UserStatistics |
@@ -44,6 +45,32 @@ namespace OpenSim.Region.UserStatistics | |||
44 | get { return "Client"; } | 45 | get { return "Client"; } |
45 | } | 46 | } |
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 | |||
47 | public Hashtable ProcessModel(Hashtable pParams) | 74 | public Hashtable ProcessModel(Hashtable pParams) |
48 | { | 75 | { |
49 | SqliteConnection dbConn = (SqliteConnection)pParams["DatabaseConnection"]; | 76 | SqliteConnection dbConn = (SqliteConnection)pParams["DatabaseConnection"]; |
diff --git a/OpenSim/Region/UserStatistics/Default_Report.cs b/OpenSim/Region/UserStatistics/Default_Report.cs index cdc615c..fabe3d4 100644 --- a/OpenSim/Region/UserStatistics/Default_Report.cs +++ b/OpenSim/Region/UserStatistics/Default_Report.cs | |||
@@ -32,6 +32,7 @@ using System.Reflection; | |||
32 | using System.Text; | 32 | using System.Text; |
33 | using Mono.Data.SqliteClient; | 33 | using Mono.Data.SqliteClient; |
34 | using OpenMetaverse; | 34 | using OpenMetaverse; |
35 | using OpenMetaverse.StructuredData; | ||
35 | using OpenSim.Region.Framework.Scenes; | 36 | using OpenSim.Region.Framework.Scenes; |
36 | using OpenSim.Framework.Monitoring; | 37 | using OpenSim.Framework.Monitoring; |
37 | 38 | ||
@@ -230,6 +231,31 @@ TD.align_top { vertical-align: top; } | |||
230 | return returnstruct; | 231 | return returnstruct; |
231 | } | 232 | } |
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 | } | ||
233 | } | 259 | } |
234 | 260 | ||
235 | public struct stats_default_page_values | 261 | public struct stats_default_page_values |
@@ -247,4 +273,5 @@ TD.align_top { vertical-align: top; } | |||
247 | public Dictionary<UUID, USimStatsData> sim_stat_data; | 273 | public Dictionary<UUID, USimStatsData> sim_stat_data; |
248 | public Dictionary<string, IStatsController> stats_reports; | 274 | public Dictionary<string, IStatsController> stats_reports; |
249 | } | 275 | } |
276 | |||
250 | } | 277 | } |
diff --git a/OpenSim/Region/UserStatistics/IStatsReport.cs b/OpenSim/Region/UserStatistics/IStatsReport.cs index e0ecce4..80c4487 100644 --- a/OpenSim/Region/UserStatistics/IStatsReport.cs +++ b/OpenSim/Region/UserStatistics/IStatsReport.cs | |||
@@ -34,5 +34,6 @@ namespace OpenSim.Region.UserStatistics | |||
34 | string ReportName { get; } | 34 | string ReportName { get; } |
35 | Hashtable ProcessModel(Hashtable pParams); | 35 | Hashtable ProcessModel(Hashtable pParams); |
36 | string RenderView(Hashtable pModelResult); | 36 | string RenderView(Hashtable pModelResult); |
37 | string RenderJson(Hashtable pModelResult); | ||
37 | } | 38 | } |
38 | } | 39 | } |
diff --git a/OpenSim/Region/UserStatistics/LogLinesAJAX.cs b/OpenSim/Region/UserStatistics/LogLinesAJAX.cs index 74de46b..4d45b80 100644 --- a/OpenSim/Region/UserStatistics/LogLinesAJAX.cs +++ b/OpenSim/Region/UserStatistics/LogLinesAJAX.cs | |||
@@ -33,6 +33,7 @@ using System.Text; | |||
33 | using System.Text.RegularExpressions; | 33 | using System.Text.RegularExpressions; |
34 | using Mono.Data.SqliteClient; | 34 | using Mono.Data.SqliteClient; |
35 | using OpenMetaverse; | 35 | using OpenMetaverse; |
36 | using OpenMetaverse.StructuredData; | ||
36 | using OpenSim.Region.Framework.Scenes; | 37 | using OpenSim.Region.Framework.Scenes; |
37 | using OpenSim.Framework.Monitoring; | 38 | using OpenSim.Framework.Monitoring; |
38 | 39 | ||
@@ -125,6 +126,34 @@ namespace OpenSim.Region.UserStatistics | |||
125 | return output.ToString(); | 126 | return output.ToString(); |
126 | } | 127 | } |
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 | |||
128 | #endregion | 157 | #endregion |
129 | } | 158 | } |
130 | } | 159 | } |
diff --git a/OpenSim/Region/UserStatistics/Properties/AssemblyInfo.cs b/OpenSim/Region/UserStatistics/Properties/AssemblyInfo.cs index 100cf99..1fff12a 100644 --- a/OpenSim/Region/UserStatistics/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/UserStatistics/Properties/AssemblyInfo.cs | |||
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices; | |||
29 | // Build Number | 29 | // Build Number |
30 | // Revision | 30 | // Revision |
31 | // | 31 | // |
32 | [assembly: AssemblyVersion("0.7.5.*")] | 32 | [assembly: AssemblyVersion("0.7.6.*")] |
33 | [assembly: AssemblyFileVersion("1.0.0.0")] | 33 | |
diff --git a/OpenSim/Region/UserStatistics/Prototype_distributor.cs b/OpenSim/Region/UserStatistics/Prototype_distributor.cs index 53ae557..6f8b2aa 100644 --- a/OpenSim/Region/UserStatistics/Prototype_distributor.cs +++ b/OpenSim/Region/UserStatistics/Prototype_distributor.cs | |||
@@ -36,7 +36,18 @@ namespace OpenSim.Region.UserStatistics | |||
36 | { | 36 | { |
37 | public class Prototype_distributor : IStatsController | 37 | public class Prototype_distributor : IStatsController |
38 | { | 38 | { |
39 | private string prototypejs=string.Empty; | 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 | } | ||
40 | 51 | ||
41 | public string ReportName | 52 | public string ReportName |
42 | { | 53 | { |
@@ -45,20 +56,24 @@ namespace OpenSim.Region.UserStatistics | |||
45 | public Hashtable ProcessModel(Hashtable pParams) | 56 | public Hashtable ProcessModel(Hashtable pParams) |
46 | { | 57 | { |
47 | Hashtable pResult = new Hashtable(); | 58 | Hashtable pResult = new Hashtable(); |
48 | if (prototypejs.Length == 0) | 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))) | ||
49 | { | 67 | { |
50 | StreamReader fs = new StreamReader(new FileStream(Util.dataDir() + "/data/prototype.js", FileMode.Open)); | ||
51 | prototypejs = fs.ReadToEnd(); | 68 | prototypejs = fs.ReadToEnd(); |
52 | fs.Close(); | 69 | fs.Close(); |
53 | fs.Dispose(); | ||
54 | } | 70 | } |
55 | pResult["js"] = prototypejs; | 71 | return prototypejs; |
56 | return pResult; | ||
57 | } | 72 | } |
58 | 73 | ||
59 | public string RenderView(Hashtable pModelResult) | 74 | public string RenderJson(Hashtable pModelResult) |
60 | { | 75 | { |
61 | return pModelResult["js"].ToString(); | 76 | return "{}"; |
62 | } | 77 | } |
63 | 78 | ||
64 | } | 79 | } |
diff --git a/OpenSim/Region/UserStatistics/Sessions_Report.cs b/OpenSim/Region/UserStatistics/Sessions_Report.cs index 1a2d460..0e94912 100644 --- a/OpenSim/Region/UserStatistics/Sessions_Report.cs +++ b/OpenSim/Region/UserStatistics/Sessions_Report.cs | |||
@@ -278,6 +278,11 @@ TD.align_top { vertical-align: top; } | |||
278 | public DateTime start_time; | 278 | public DateTime start_time; |
279 | } | 279 | } |
280 | 280 | ||
281 | public string RenderJson(Hashtable pModelResult) | ||
282 | { | ||
283 | return "{}"; | ||
284 | } | ||
281 | #endregion | 285 | #endregion |
282 | } | 286 | } |
287 | |||
283 | } | 288 | } |
diff --git a/OpenSim/Region/UserStatistics/SimStatsAJAX.cs b/OpenSim/Region/UserStatistics/SimStatsAJAX.cs index 28051fb..ad848a1 100644 --- a/OpenSim/Region/UserStatistics/SimStatsAJAX.cs +++ b/OpenSim/Region/UserStatistics/SimStatsAJAX.cs | |||
@@ -32,6 +32,7 @@ using System.Reflection; | |||
32 | using System.Text; | 32 | using System.Text; |
33 | using Mono.Data.SqliteClient; | 33 | using Mono.Data.SqliteClient; |
34 | using OpenMetaverse; | 34 | using OpenMetaverse; |
35 | using OpenMetaverse.StructuredData; | ||
35 | using OpenSim.Region.Framework.Scenes; | 36 | using OpenSim.Region.Framework.Scenes; |
36 | using OpenSim.Framework.Monitoring; | 37 | using OpenSim.Framework.Monitoring; |
37 | 38 | ||
@@ -218,6 +219,64 @@ namespace OpenSim.Region.UserStatistics | |||
218 | return output.ToString(); | 219 | return output.ToString(); |
219 | } | 220 | } |
220 | 221 | ||
222 | /// <summary> | ||
223 | /// Return stat information for all regions in the sim. Returns data of the form: | ||
224 | /// <pre> | ||
225 | /// {"REGIONNAME": { | ||
226 | /// "region": "REGIONNAME", | ||
227 | /// "timeDilation": "101", | ||
228 | /// ... // the rest of the stat info | ||
229 | /// }, | ||
230 | /// ... // entries for each region | ||
231 | /// } | ||
232 | /// </pre> | ||
233 | /// </summary> | ||
234 | /// <param name="pModelResult"></param> | ||
235 | /// <returns></returns> | ||
236 | public string RenderJson(Hashtable pModelResult) | ||
237 | { | ||
238 | List<Scene> all_scenes = (List<Scene>) pModelResult["hdata"]; | ||
239 | Dictionary<UUID, USimStatsData> sdatadic = (Dictionary<UUID,USimStatsData>)pModelResult["simstats"]; | ||
240 | |||
241 | OSDMap allStatsInfo = new OpenMetaverse.StructuredData.OSDMap(); | ||
242 | foreach (USimStatsData sdata in sdatadic.Values) | ||
243 | { | ||
244 | OSDMap statsInfo = new OpenMetaverse.StructuredData.OSDMap(); | ||
245 | string regionName = "unknown"; | ||
246 | foreach (Scene sn in all_scenes) | ||
247 | { | ||
248 | if (sn.RegionInfo.RegionID == sdata.RegionId) | ||
249 | { | ||
250 | regionName = sn.RegionInfo.RegionName; | ||
251 | break; | ||
252 | } | ||
253 | } | ||
254 | statsInfo.Add("region", new OSDString(regionName)); | ||
255 | statsInfo.Add("timeDilation", new OSDString(sdata.TimeDilation.ToString())); | ||
256 | statsInfo.Add("simFPS", new OSDString(sdata.SimFps.ToString())); | ||
257 | statsInfo.Add("physicsFPS", new OSDString(sdata.PhysicsFps.ToString())); | ||
258 | statsInfo.Add("agentUpdates", new OSDString(sdata.AgentUpdates.ToString())); | ||
259 | statsInfo.Add("rootAgents", new OSDString(sdata.RootAgents.ToString())); | ||
260 | statsInfo.Add("childAgents", new OSDString(sdata.ChildAgents.ToString())); | ||
261 | statsInfo.Add("totalPrims", new OSDString(sdata.TotalPrims.ToString())); | ||
262 | statsInfo.Add("activePrims", new OSDString(sdata.ActivePrims.ToString())); | ||
263 | statsInfo.Add("activeScripts", new OSDString(sdata.ActiveScripts.ToString())); | ||
264 | statsInfo.Add("scriptLinesPerSec", new OSDString(sdata.ScriptLinesPerSecond.ToString())); | ||
265 | statsInfo.Add("totalFrameTime", new OSDString(sdata.TotalFrameTime.ToString())); | ||
266 | statsInfo.Add("agentFrameTime", new OSDString(sdata.AgentFrameTime.ToString())); | ||
267 | statsInfo.Add("physicsFrameTime", new OSDString(sdata.PhysicsFrameTime.ToString())); | ||
268 | statsInfo.Add("otherFrameTime", new OSDString(sdata.OtherFrameTime.ToString())); | ||
269 | statsInfo.Add("outPacketsPerSec", new OSDString(sdata.OutPacketsPerSecond.ToString())); | ||
270 | statsInfo.Add("inPacketsPerSec", new OSDString(sdata.InPacketsPerSecond.ToString())); | ||
271 | statsInfo.Add("unackedByptes", new OSDString(sdata.UnackedBytes.ToString())); | ||
272 | statsInfo.Add("pendingDownloads", new OSDString(sdata.PendingDownloads.ToString())); | ||
273 | statsInfo.Add("pendingUploads", new OSDString(sdata.PendingUploads.ToString())); | ||
274 | |||
275 | allStatsInfo.Add(regionName, statsInfo); | ||
276 | } | ||
277 | return allStatsInfo.ToString(); | ||
278 | } | ||
279 | |||
221 | #endregion | 280 | #endregion |
222 | } | 281 | } |
223 | } | 282 | } |
diff --git a/OpenSim/Region/UserStatistics/Updater_distributor.cs b/OpenSim/Region/UserStatistics/Updater_distributor.cs index 9593cc9..601e06b 100644 --- a/OpenSim/Region/UserStatistics/Updater_distributor.cs +++ b/OpenSim/Region/UserStatistics/Updater_distributor.cs | |||
@@ -62,5 +62,9 @@ namespace OpenSim.Region.UserStatistics | |||
62 | return pModelResult["js"].ToString(); | 62 | return pModelResult["js"].ToString(); |
63 | } | 63 | } |
64 | 64 | ||
65 | public string RenderJson(Hashtable pModelResult) { | ||
66 | return "{}"; | ||
67 | } | ||
68 | |||
65 | } | 69 | } |
66 | } \ No newline at end of file | 70 | } \ No newline at end of file |
diff --git a/OpenSim/Region/UserStatistics/WebStatsModule.cs b/OpenSim/Region/UserStatistics/WebStatsModule.cs index b08233c..b98b762 100644 --- a/OpenSim/Region/UserStatistics/WebStatsModule.cs +++ b/OpenSim/Region/UserStatistics/WebStatsModule.cs | |||
@@ -94,8 +94,6 @@ namespace OpenSim.Region.UserStatistics | |||
94 | if (!enabled) | 94 | if (!enabled) |
95 | return; | 95 | return; |
96 | 96 | ||
97 | AddEventHandlers(); | ||
98 | |||
99 | if (Util.IsWindows()) | 97 | if (Util.IsWindows()) |
100 | Util.LoadArchSpecificWindowsDll("sqlite3.dll"); | 98 | Util.LoadArchSpecificWindowsDll("sqlite3.dll"); |
101 | 99 | ||
@@ -123,6 +121,10 @@ namespace OpenSim.Region.UserStatistics | |||
123 | reports.Add("clients.report", clientReport); | 121 | reports.Add("clients.report", clientReport); |
124 | reports.Add("sessions.report", sessionsReport); | 122 | reports.Add("sessions.report", sessionsReport); |
125 | 123 | ||
124 | reports.Add("sim.css", new Prototype_distributor("sim.css")); | ||
125 | reports.Add("sim.html", new Prototype_distributor("sim.html")); | ||
126 | reports.Add("jquery.js", new Prototype_distributor("jquery.js")); | ||
127 | |||
126 | //// | 128 | //// |
127 | // Add Your own Reports here (Do Not Modify Lines here Devs!) | 129 | // Add Your own Reports here (Do Not Modify Lines here Devs!) |
128 | //// | 130 | //// |
@@ -143,10 +145,14 @@ namespace OpenSim.Region.UserStatistics | |||
143 | lock (m_scenes) | 145 | lock (m_scenes) |
144 | { | 146 | { |
145 | m_scenes.Add(scene); | 147 | m_scenes.Add(scene); |
146 | if (m_simstatsCounters.ContainsKey(scene.RegionInfo.RegionID)) | 148 | updateLogMod = m_scenes.Count * 2; |
147 | m_simstatsCounters.Remove(scene.RegionInfo.RegionID); | ||
148 | 149 | ||
149 | m_simstatsCounters.Add(scene.RegionInfo.RegionID, new USimStatsData(scene.RegionInfo.RegionID)); | 150 | m_simstatsCounters.Add(scene.RegionInfo.RegionID, new USimStatsData(scene.RegionInfo.RegionID)); |
151 | |||
152 | scene.EventManager.OnRegisterCaps += OnRegisterCaps; | ||
153 | scene.EventManager.OnDeregisterCaps += OnDeRegisterCaps; | ||
154 | scene.EventManager.OnClientClosed += OnClientClosed; | ||
155 | scene.EventManager.OnMakeRootAgent += OnMakeRootAgent; | ||
150 | scene.StatsReporter.OnSendStatsResult += ReceiveClassicSimStatsPacket; | 156 | scene.StatsReporter.OnSendStatsResult += ReceiveClassicSimStatsPacket; |
151 | } | 157 | } |
152 | } | 158 | } |
@@ -157,6 +163,15 @@ namespace OpenSim.Region.UserStatistics | |||
157 | 163 | ||
158 | public void RemoveRegion(Scene scene) | 164 | public void RemoveRegion(Scene scene) |
159 | { | 165 | { |
166 | if (!enabled) | ||
167 | return; | ||
168 | |||
169 | lock (m_scenes) | ||
170 | { | ||
171 | m_scenes.Remove(scene); | ||
172 | updateLogMod = m_scenes.Count * 2; | ||
173 | m_simstatsCounters.Remove(scene.RegionInfo.RegionID); | ||
174 | } | ||
160 | } | 175 | } |
161 | 176 | ||
162 | public virtual void Close() | 177 | public virtual void Close() |
@@ -187,9 +202,7 @@ namespace OpenSim.Region.UserStatistics | |||
187 | private void ReceiveClassicSimStatsPacket(SimStats stats) | 202 | private void ReceiveClassicSimStatsPacket(SimStats stats) |
188 | { | 203 | { |
189 | if (!enabled) | 204 | if (!enabled) |
190 | { | ||
191 | return; | 205 | return; |
192 | } | ||
193 | 206 | ||
194 | try | 207 | try |
195 | { | 208 | { |
@@ -198,17 +211,25 @@ namespace OpenSim.Region.UserStatistics | |||
198 | if (concurrencyCounter > 0 || System.Environment.TickCount - lastHit > 30000) | 211 | if (concurrencyCounter > 0 || System.Environment.TickCount - lastHit > 30000) |
199 | return; | 212 | return; |
200 | 213 | ||
201 | if ((updateLogCounter++ % updateLogMod) == 0) | 214 | // We will conduct this under lock so that fields such as updateLogCounter do not potentially get |
215 | // confused if a scene is removed. | ||
216 | // XXX: Possibly the scope of this lock could be reduced though it's not critical. | ||
217 | lock (m_scenes) | ||
202 | { | 218 | { |
203 | m_loglines = readLogLines(10); | 219 | if (updateLogMod != 0 && updateLogCounter++ % updateLogMod == 0) |
204 | if (updateLogCounter > 10000) updateLogCounter = 1; | 220 | { |
205 | } | 221 | m_loglines = readLogLines(10); |
222 | |||
223 | if (updateLogCounter > 10000) | ||
224 | updateLogCounter = 1; | ||
225 | } | ||
206 | 226 | ||
207 | USimStatsData ss = m_simstatsCounters[stats.RegionUUID]; | 227 | USimStatsData ss = m_simstatsCounters[stats.RegionUUID]; |
208 | 228 | ||
209 | if ((++ss.StatsCounter % updateStatsMod) == 0) | 229 | if ((++ss.StatsCounter % updateStatsMod) == 0) |
210 | { | 230 | { |
211 | ss.ConsumeSimStats(stats); | 231 | ss.ConsumeSimStats(stats); |
232 | } | ||
212 | } | 233 | } |
213 | } | 234 | } |
214 | catch (KeyNotFoundException) | 235 | catch (KeyNotFoundException) |
@@ -238,9 +259,12 @@ namespace OpenSim.Region.UserStatistics | |||
238 | string regpath = request["uri"].ToString(); | 259 | string regpath = request["uri"].ToString(); |
239 | int response_code = 404; | 260 | int response_code = 404; |
240 | string contenttype = "text/html"; | 261 | string contenttype = "text/html"; |
262 | bool jsonFormatOutput = false; | ||
241 | 263 | ||
242 | string strOut = string.Empty; | 264 | string strOut = string.Empty; |
243 | 265 | ||
266 | // The request patch should be "/SStats/reportName" where 'reportName' | ||
267 | // is one of the names added to the 'reports' hashmap. | ||
244 | regpath = regpath.Remove(0, 8); | 268 | regpath = regpath.Remove(0, 8); |
245 | if (regpath.Length == 0) regpath = "default.report"; | 269 | if (regpath.Length == 0) regpath = "default.report"; |
246 | if (reports.ContainsKey(regpath)) | 270 | if (reports.ContainsKey(regpath)) |
@@ -248,6 +272,9 @@ namespace OpenSim.Region.UserStatistics | |||
248 | IStatsController rep = reports[regpath]; | 272 | IStatsController rep = reports[regpath]; |
249 | Hashtable repParams = new Hashtable(); | 273 | Hashtable repParams = new Hashtable(); |
250 | 274 | ||
275 | if (request.ContainsKey("json")) | ||
276 | jsonFormatOutput = true; | ||
277 | |||
251 | if (request.ContainsKey("requestvars")) | 278 | if (request.ContainsKey("requestvars")) |
252 | repParams["RequestVars"] = request["requestvars"]; | 279 | repParams["RequestVars"] = request["requestvars"]; |
253 | else | 280 | else |
@@ -267,13 +294,26 @@ namespace OpenSim.Region.UserStatistics | |||
267 | 294 | ||
268 | concurrencyCounter++; | 295 | concurrencyCounter++; |
269 | 296 | ||
270 | strOut = rep.RenderView(rep.ProcessModel(repParams)); | 297 | if (jsonFormatOutput) |
298 | { | ||
299 | strOut = rep.RenderJson(rep.ProcessModel(repParams)); | ||
300 | contenttype = "text/json"; | ||
301 | } | ||
302 | else | ||
303 | { | ||
304 | strOut = rep.RenderView(rep.ProcessModel(repParams)); | ||
305 | } | ||
271 | 306 | ||
272 | if (regpath.EndsWith("js")) | 307 | if (regpath.EndsWith("js")) |
273 | { | 308 | { |
274 | contenttype = "text/javascript"; | 309 | contenttype = "text/javascript"; |
275 | } | 310 | } |
276 | 311 | ||
312 | if (regpath.EndsWith("css")) | ||
313 | { | ||
314 | contenttype = "text/css"; | ||
315 | } | ||
316 | |||
277 | concurrencyCounter--; | 317 | concurrencyCounter--; |
278 | 318 | ||
279 | response_code = 200; | 319 | response_code = 200; |
@@ -380,7 +420,7 @@ namespace OpenSim.Region.UserStatistics | |||
380 | Encoding encoding = Encoding.ASCII; | 420 | Encoding encoding = Encoding.ASCII; |
381 | int sizeOfChar = encoding.GetByteCount("\n"); | 421 | int sizeOfChar = encoding.GetByteCount("\n"); |
382 | byte[] buffer = encoding.GetBytes("\n"); | 422 | byte[] buffer = encoding.GetBytes("\n"); |
383 | string logfile = Util.logDir() + "/" + "OpenSim.log"; | 423 | string logfile = Util.logFile(); |
384 | FileStream fs = new FileStream(logfile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); | 424 | FileStream fs = new FileStream(logfile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); |
385 | Int64 tokenCount = 0; | 425 | Int64 tokenCount = 0; |
386 | Int64 endPosition = fs.Length / sizeOfChar; | 426 | Int64 endPosition = fs.Length / sizeOfChar; |