diff options
author | Charles Krinke | 2009-03-31 02:33:19 +0000 |
---|---|---|
committer | Charles Krinke | 2009-03-31 02:33:19 +0000 |
commit | 54a27f9f5c556e518c2ba18b9a5494d517dfd041 (patch) | |
tree | 5da9db44878c217e0c1872da0f963d88575ef8ff /OpenSim/Region/CoreModules | |
parent | Update svn properties, add copyright header, formatting cleanup. (diff) | |
download | opensim-SC-54a27f9f5c556e518c2ba18b9a5494d517dfd041.zip opensim-SC-54a27f9f5c556e518c2ba18b9a5494d517dfd041.tar.gz opensim-SC-54a27f9f5c556e518c2ba18b9a5494d517dfd041.tar.bz2 opensim-SC-54a27f9f5c556e518c2ba18b9a5494d517dfd041.tar.xz |
Thank you kindly, MCortez for a patch that:
With some support from HomerH, this patch adds support for Wind
Model plugins via the mono.Addin framework.
* Adds console & OSSL access to Wind Parameters
* Adds plug-in support for custom wind models
* Provides two example Wind Model plug-ins
Documentation for the wind module is temporarily located at http://code.google.com/p/flotsam/wiki/CoreWindModule [^]
-- will move this documentation to http://opensimulator.org [^]
after the patch has been committed.
Diffstat (limited to 'OpenSim/Region/CoreModules')
5 files changed, 728 insertions, 100 deletions
diff --git a/OpenSim/Region/CoreModules/Resources/Wind.Models.addin.xml b/OpenSim/Region/CoreModules/Resources/Wind.Models.addin.xml new file mode 100644 index 0000000..972f795 --- /dev/null +++ b/OpenSim/Region/CoreModules/Resources/Wind.Models.addin.xml | |||
@@ -0,0 +1,12 @@ | |||
1 | <Addin id="WindModule.Default.WindModels" version="1.0"> | ||
2 | <Runtime> | ||
3 | <Import assembly="OpenSim.Region.CoreModules.dll"/> | ||
4 | </Runtime> | ||
5 | <Dependencies> | ||
6 | <Addin id="OpenSim" version="0.5" /> | ||
7 | </Dependencies> | ||
8 | <Extension path = "/OpenSim/WindModule"> | ||
9 | <WindModel id="ConfigurableWind" type="OpenSim.Region.CoreModules.World.Wind.Plugins.ConfigurableWind" /> | ||
10 | <WindModel id="SimpleRandomWind" type="OpenSim.Region.CoreModules.World.Wind.Plugins.SimpleRandomWind" /> | ||
11 | </Extension> | ||
12 | </Addin> | ||
diff --git a/OpenSim/Region/CoreModules/World/Wind/IWindModelPlugin.cs b/OpenSim/Region/CoreModules/World/Wind/IWindModelPlugin.cs new file mode 100644 index 0000000..29b0ed5 --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Wind/IWindModelPlugin.cs | |||
@@ -0,0 +1,56 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | |||
4 | using Nini.Config; | ||
5 | using OpenSim.Framework; | ||
6 | using OpenMetaverse; | ||
7 | using OpenSim.Region.Framework.Scenes; | ||
8 | |||
9 | namespace OpenSim.Region.CoreModules.World.Wind | ||
10 | { | ||
11 | public interface IWindModelPlugin : IPlugin | ||
12 | { | ||
13 | /// <summary> | ||
14 | /// Brief description of this plugin's wind model | ||
15 | /// </summary> | ||
16 | string Description { get; } | ||
17 | |||
18 | /// <summary> | ||
19 | /// Provides access to the wind configuration, if any. | ||
20 | /// </summary> | ||
21 | void WindConfig(Scene scene, IConfig windConfig); | ||
22 | |||
23 | /// <summary> | ||
24 | /// Update wind. | ||
25 | /// </summary> | ||
26 | void WindUpdate(uint frame); | ||
27 | |||
28 | /// <summary> | ||
29 | /// Returns the wind vector at the given local region coordinates. | ||
30 | /// </summary> | ||
31 | Vector3 WindSpeed(float x, float y, float z); | ||
32 | |||
33 | /// <summary> | ||
34 | /// Generate a 16 x 16 Vector2 array of wind speeds for LL* based viewers | ||
35 | /// </summary> | ||
36 | /// <returns>Must return a Vector2[256]</returns> | ||
37 | Vector2[] WindLLClientArray(); | ||
38 | |||
39 | /// <summary> | ||
40 | /// Retrieve a list of parameter/description pairs. | ||
41 | /// </summary> | ||
42 | /// <returns></returns> | ||
43 | Dictionary<string, string> WindParams(); | ||
44 | |||
45 | /// <summary> | ||
46 | /// Set the specified parameter | ||
47 | /// </summary> | ||
48 | void WindParamSet(string param, float value); | ||
49 | |||
50 | /// <summary> | ||
51 | /// Get the specified parameter | ||
52 | /// </summary> | ||
53 | float WindParamGet(string param); | ||
54 | |||
55 | } | ||
56 | } | ||
diff --git a/OpenSim/Region/CoreModules/World/Wind/Plugins/ConfigurableWind.cs b/OpenSim/Region/CoreModules/World/Wind/Plugins/ConfigurableWind.cs new file mode 100644 index 0000000..2f5cc31 --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Wind/Plugins/ConfigurableWind.cs | |||
@@ -0,0 +1,211 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Reflection; | ||
4 | |||
5 | using log4net; | ||
6 | using OpenMetaverse; | ||
7 | |||
8 | using OpenSim.Region.CoreModules.World.Wind; | ||
9 | |||
10 | namespace OpenSim.Region.CoreModules.World.Wind.Plugins | ||
11 | { | ||
12 | class ConfigurableWind : Mono.Addins.TypeExtensionNode, IWindModelPlugin | ||
13 | { | ||
14 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
15 | |||
16 | private Vector2[] m_windSpeeds = new Vector2[16 * 16]; | ||
17 | private Random m_rndnums = new Random(Environment.TickCount); | ||
18 | |||
19 | private float m_avgStrength = 5.0f; // Average magnitude of the wind vector | ||
20 | private float m_avgDirection = 0.0f; // Average direction of the wind in degrees | ||
21 | private float m_varStrength = 5.0f; // Max Strength Variance | ||
22 | private float m_varDirection = 30.0f;// Max Direction Variance | ||
23 | private float m_rateChange = 1.0f; // | ||
24 | |||
25 | private Vector2 m_curPredominateWind = new Vector2(); | ||
26 | |||
27 | |||
28 | |||
29 | #region IPlugin Members | ||
30 | |||
31 | public string Version | ||
32 | { | ||
33 | get { return "1.0.0.0"; } | ||
34 | } | ||
35 | |||
36 | public string Name | ||
37 | { | ||
38 | get { return "ConfigurableWind"; } | ||
39 | } | ||
40 | |||
41 | public void Initialise() | ||
42 | { | ||
43 | |||
44 | } | ||
45 | |||
46 | #endregion | ||
47 | |||
48 | #region IDisposable Members | ||
49 | |||
50 | public void Dispose() | ||
51 | { | ||
52 | m_windSpeeds = null; | ||
53 | } | ||
54 | |||
55 | #endregion | ||
56 | |||
57 | #region IWindModelPlugin Members | ||
58 | |||
59 | public void WindConfig(OpenSim.Region.Framework.Scenes.Scene scene, Nini.Config.IConfig windConfig) | ||
60 | { | ||
61 | if( windConfig != null ) | ||
62 | { | ||
63 | // Uses strength value if avg_strength not specified | ||
64 | m_avgStrength = windConfig.GetFloat("strength", 5.0F); | ||
65 | m_avgStrength = windConfig.GetFloat("avg_strength", 5.0F); | ||
66 | |||
67 | m_avgDirection = windConfig.GetFloat("avg_direction", 0.0F); | ||
68 | m_varStrength = windConfig.GetFloat("var_strength", 5.0F); | ||
69 | m_varDirection = windConfig.GetFloat("var_direction", 30.0F); | ||
70 | m_rateChange = windConfig.GetFloat("rate_change", 1.0F); | ||
71 | |||
72 | LogSettings(); | ||
73 | } | ||
74 | } | ||
75 | |||
76 | public void WindUpdate(uint frame) | ||
77 | { | ||
78 | double avgAng = m_avgDirection * (Math.PI/180.0f); | ||
79 | double varDir = m_varDirection * (Math.PI/180.0f); | ||
80 | |||
81 | // Prevailing wind algorithm | ||
82 | // Inspired by Kanker Greenacre | ||
83 | |||
84 | // TODO: | ||
85 | // * This should probably be based on in-world time. | ||
86 | // * should probably move all these local variables to class members and constants | ||
87 | double time = DateTime.Now.TimeOfDay.Seconds / 86400; | ||
88 | |||
89 | double theta = time * (2 * Math.PI) * m_rateChange; | ||
90 | |||
91 | double offset = Math.Sin(theta) * Math.Sin(theta*2) * Math.Sin(theta*9) * Math.Cos(theta*4); | ||
92 | |||
93 | double windDir = avgAng + (varDir * offset); | ||
94 | |||
95 | offset = Math.Sin(theta) * Math.Sin(theta*4) + (Math.Sin(theta*13) / 3); | ||
96 | double windSpeed = m_avgStrength + (m_varStrength * offset); | ||
97 | |||
98 | if (windSpeed<0) | ||
99 | windSpeed=0; | ||
100 | |||
101 | |||
102 | |||
103 | m_curPredominateWind.X = (float)Math.Cos(windDir); | ||
104 | m_curPredominateWind.Y = (float)Math.Sin(windDir); | ||
105 | |||
106 | m_curPredominateWind.Normalize(); | ||
107 | m_curPredominateWind.X *= (float)windSpeed; | ||
108 | m_curPredominateWind.Y *= (float)windSpeed; | ||
109 | |||
110 | for (int y = 0; y < 16; y++) | ||
111 | { | ||
112 | for (int x = 0; x < 16; x++) | ||
113 | { | ||
114 | m_windSpeeds[y * 16 + x] = m_curPredominateWind; | ||
115 | } | ||
116 | } | ||
117 | } | ||
118 | |||
119 | public Vector3 WindSpeed(float fX, float fY, float fZ) | ||
120 | { | ||
121 | return new Vector3(m_curPredominateWind, 0.0f); | ||
122 | } | ||
123 | |||
124 | public Vector2[] WindLLClientArray() | ||
125 | { | ||
126 | return m_windSpeeds; | ||
127 | } | ||
128 | |||
129 | public string Description | ||
130 | { | ||
131 | get | ||
132 | { | ||
133 | return "Provides a predominate wind direction that can change within configured variances for direction and speed."; | ||
134 | } | ||
135 | } | ||
136 | |||
137 | public System.Collections.Generic.Dictionary<string, string> WindParams() | ||
138 | { | ||
139 | Dictionary<string, string> Params = new Dictionary<string, string>(); | ||
140 | |||
141 | Params.Add("avgStrength", "average wind strength"); | ||
142 | Params.Add("avgDirection", "average wind direction in degrees"); | ||
143 | Params.Add("varStrength", "allowable variance in wind strength"); | ||
144 | Params.Add("varDirection", "allowable variance in wind direction in +/- degrees"); | ||
145 | Params.Add("rateChange", "rate of change"); | ||
146 | |||
147 | return Params; | ||
148 | } | ||
149 | |||
150 | public void WindParamSet(string param, float value) | ||
151 | { | ||
152 | switch (param) | ||
153 | { | ||
154 | case "avgStrength": | ||
155 | m_avgStrength = value; | ||
156 | break; | ||
157 | case "avgDirection": | ||
158 | m_avgDirection = value; | ||
159 | break; | ||
160 | case "varStrength": | ||
161 | m_varStrength = value; | ||
162 | break; | ||
163 | case "varDirection": | ||
164 | m_varDirection = value; | ||
165 | break; | ||
166 | case "rateChange": | ||
167 | m_rateChange = value; | ||
168 | break; | ||
169 | } | ||
170 | } | ||
171 | |||
172 | public float WindParamGet(string param) | ||
173 | { | ||
174 | switch (param) | ||
175 | { | ||
176 | case "avgStrength": | ||
177 | return m_avgStrength; | ||
178 | case "avgDirection": | ||
179 | return m_avgDirection; | ||
180 | case "varStrength": | ||
181 | return m_varStrength; | ||
182 | case "varDirection": | ||
183 | return m_varDirection; | ||
184 | case "rateChange": | ||
185 | return m_rateChange; | ||
186 | default: | ||
187 | throw new Exception(String.Format("Unknown {0} parameter {1}", this.Name, param)); | ||
188 | |||
189 | } | ||
190 | } | ||
191 | |||
192 | |||
193 | |||
194 | #endregion | ||
195 | |||
196 | |||
197 | private void LogSettings() | ||
198 | { | ||
199 | m_log.InfoFormat("[ConfigurableWind] Average Strength : {0}", m_avgStrength); | ||
200 | m_log.InfoFormat("[ConfigurableWind] Average Direction : {0}", m_avgDirection); | ||
201 | m_log.InfoFormat("[ConfigurableWind] Varience Strength : {0}", m_varStrength); | ||
202 | m_log.InfoFormat("[ConfigurableWind] Varience Direction : {0}", m_varDirection); | ||
203 | m_log.InfoFormat("[ConfigurableWind] Rate Change : {0}", m_rateChange); | ||
204 | } | ||
205 | |||
206 | #region IWindModelPlugin Members | ||
207 | |||
208 | |||
209 | #endregion | ||
210 | } | ||
211 | } | ||
diff --git a/OpenSim/Region/CoreModules/World/Wind/Plugins/SimpleRandomWind.cs b/OpenSim/Region/CoreModules/World/Wind/Plugins/SimpleRandomWind.cs new file mode 100644 index 0000000..040a3c4 --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Wind/Plugins/SimpleRandomWind.cs | |||
@@ -0,0 +1,139 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | |||
4 | using OpenMetaverse; | ||
5 | |||
6 | |||
7 | namespace OpenSim.Region.CoreModules.World.Wind.Plugins | ||
8 | { | ||
9 | class SimpleRandomWind : Mono.Addins.TypeExtensionNode, IWindModelPlugin | ||
10 | { | ||
11 | private Vector2[] m_windSpeeds = new Vector2[16 * 16]; | ||
12 | private float m_strength = 1.0f; | ||
13 | private Random m_rndnums = new Random(Environment.TickCount); | ||
14 | |||
15 | |||
16 | #region IPlugin Members | ||
17 | |||
18 | public string Version | ||
19 | { | ||
20 | get { return "1.0.0.0"; } | ||
21 | } | ||
22 | |||
23 | public string Name | ||
24 | { | ||
25 | get { return "SimpleRandomWind"; } | ||
26 | } | ||
27 | |||
28 | public void Initialise() | ||
29 | { | ||
30 | |||
31 | } | ||
32 | |||
33 | #endregion | ||
34 | |||
35 | #region IDisposable Members | ||
36 | |||
37 | public void Dispose() | ||
38 | { | ||
39 | m_windSpeeds = null; | ||
40 | } | ||
41 | |||
42 | #endregion | ||
43 | |||
44 | #region IWindModelPlugin Members | ||
45 | |||
46 | public void WindConfig(OpenSim.Region.Framework.Scenes.Scene scene, Nini.Config.IConfig windConfig) | ||
47 | { | ||
48 | if( windConfig != null ) | ||
49 | { | ||
50 | if( windConfig.Contains("strength") ) | ||
51 | { | ||
52 | m_strength = windConfig.GetFloat("strength", 1.0F); | ||
53 | } | ||
54 | } | ||
55 | } | ||
56 | |||
57 | public void WindUpdate(uint frame) | ||
58 | { | ||
59 | for (int y = 0; y < 16; y++) | ||
60 | { | ||
61 | for (int x = 0; x < 16; x++) | ||
62 | { | ||
63 | m_windSpeeds[y * 16 + x].X = (float)(m_rndnums.NextDouble() * 2d - 1d); // -1 to 1 | ||
64 | m_windSpeeds[y * 16 + x].Y = (float)(m_rndnums.NextDouble() * 2d - 1d); // -1 to 1 | ||
65 | m_windSpeeds[y * 16 + x].X *= m_strength; | ||
66 | m_windSpeeds[y * 16 + x].Y *= m_strength; | ||
67 | } | ||
68 | } | ||
69 | } | ||
70 | |||
71 | public Vector3 WindSpeed(float fX, float fY, float fZ) | ||
72 | { | ||
73 | Vector3 windVector = new Vector3(0.0f, 0.0f, 0.0f); | ||
74 | |||
75 | int x = (int)fX / 16; | ||
76 | int y = (int)fY / 16; | ||
77 | |||
78 | if (x < 0) x = 0; | ||
79 | if (x > 15) x = 15; | ||
80 | if (y < 0) y = 0; | ||
81 | if (y > 15) y = 15; | ||
82 | |||
83 | if (m_windSpeeds != null) | ||
84 | { | ||
85 | windVector.X = m_windSpeeds[y * 16 + x].X; | ||
86 | windVector.Y = m_windSpeeds[y * 16 + x].Y; | ||
87 | } | ||
88 | |||
89 | return windVector; | ||
90 | |||
91 | } | ||
92 | |||
93 | public Vector2[] WindLLClientArray() | ||
94 | { | ||
95 | return m_windSpeeds; | ||
96 | } | ||
97 | |||
98 | public string Description | ||
99 | { | ||
100 | get | ||
101 | { | ||
102 | return "Provides a simple wind model that creates random wind of a given strength in 16m x 16m patches."; | ||
103 | } | ||
104 | } | ||
105 | |||
106 | public System.Collections.Generic.Dictionary<string, string> WindParams() | ||
107 | { | ||
108 | Dictionary<string, string> Params = new Dictionary<string, string>(); | ||
109 | |||
110 | Params.Add("strength", "wind strength"); | ||
111 | |||
112 | return Params; | ||
113 | } | ||
114 | |||
115 | public void WindParamSet(string param, float value) | ||
116 | { | ||
117 | switch (param) | ||
118 | { | ||
119 | case "strength": | ||
120 | m_strength = value; | ||
121 | break; | ||
122 | } | ||
123 | } | ||
124 | |||
125 | public float WindParamGet(string param) | ||
126 | { | ||
127 | switch (param) | ||
128 | { | ||
129 | case "strength": | ||
130 | return m_strength; | ||
131 | default: | ||
132 | throw new Exception(String.Format("Unknown {0} parameter {1}", this.Name, param)); | ||
133 | } | ||
134 | } | ||
135 | |||
136 | #endregion | ||
137 | |||
138 | } | ||
139 | } | ||
diff --git a/OpenSim/Region/CoreModules/World/Wind/WindModule.cs b/OpenSim/Region/CoreModules/World/Wind/WindModule.cs index 87e6fd9..26901a4 100644 --- a/OpenSim/Region/CoreModules/World/Wind/WindModule.cs +++ b/OpenSim/Region/CoreModules/World/Wind/WindModule.cs | |||
@@ -27,57 +27,125 @@ | |||
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.Reflection; | ||
31 | using log4net; | ||
32 | using Mono.Addins; | ||
30 | using Nini.Config; | 33 | using Nini.Config; |
31 | using OpenMetaverse; | 34 | using OpenMetaverse; |
32 | using OpenSim.Framework; | 35 | using OpenSim.Framework; |
33 | using OpenSim.Region.Framework.Interfaces; | 36 | using OpenSim.Region.Framework.Interfaces; |
34 | using OpenSim.Region.Framework.Scenes; | 37 | using OpenSim.Region.Framework.Scenes; |
35 | 38 | ||
39 | using OpenSim.Region.CoreModules.World.Wind; | ||
40 | |||
36 | namespace OpenSim.Region.CoreModules | 41 | namespace OpenSim.Region.CoreModules |
37 | { | 42 | { |
38 | public class WindModule : IWindModule | 43 | public class WindModule : IWindModule |
39 | { | 44 | { |
40 | // private static readonly log4net.ILog m_log | 45 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
41 | // = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); | ||
42 | 46 | ||
43 | private int m_frame = 0; | 47 | private uint m_frame = 0; |
44 | private int m_frame_mod = 150; | 48 | private uint m_frameLastUpdateClientArray = 0; |
49 | private int m_frameUpdateRate = 150; | ||
45 | private Random m_rndnums = new Random(Environment.TickCount); | 50 | private Random m_rndnums = new Random(Environment.TickCount); |
46 | private Scene m_scene = null; | 51 | private Scene m_scene = null; |
47 | private bool m_ready = false; | 52 | private bool m_ready = false; |
48 | private float m_strength = 1.0F; | 53 | |
49 | private bool m_enabled = true; | 54 | private bool m_enabled = true; |
50 | 55 | ||
56 | private IWindModelPlugin m_activeWindPlugin = null; | ||
57 | private const string m_dWindPluginName = "SimpleRandomWind"; | ||
58 | private Dictionary<string, IWindModelPlugin> m_availableWindPlugins = new Dictionary<string, IWindModelPlugin>(); | ||
59 | |||
51 | // Simplified windSpeeds based on the fact that the client protocal tracks at a resolution of 16m | 60 | // Simplified windSpeeds based on the fact that the client protocal tracks at a resolution of 16m |
52 | private Vector2[] windSpeeds = new Vector2[16 * 16]; | 61 | private Vector2[] windSpeeds = new Vector2[16 * 16]; |
53 | 62 | ||
54 | private Dictionary<UUID, ulong> m_rootAgents = new Dictionary<UUID, ulong>(); | 63 | #region IRegion Methods |
55 | 64 | ||
56 | public void Initialise(Scene scene, IConfigSource config) | 65 | public void Initialise(Scene scene, IConfigSource config) |
57 | { | 66 | { |
58 | IConfig windConfig = config.Configs["Wind"]; | 67 | IConfig windConfig = config.Configs["Wind"]; |
68 | string desiredWindPlugin = m_dWindPluginName; | ||
59 | 69 | ||
60 | if (windConfig != null) | 70 | if (windConfig != null) |
61 | { | 71 | { |
62 | m_enabled = windConfig.GetBoolean("enabled", true); | 72 | m_enabled = windConfig.GetBoolean("enabled", true); |
63 | m_strength = windConfig.GetFloat("strength", 1.0F); | 73 | |
74 | m_frameUpdateRate = windConfig.GetInt("wind_update_rate", 150); | ||
75 | |||
76 | // Determine which wind model plugin is desired | ||
77 | if (windConfig.Contains("wind_plugin")) | ||
78 | { | ||
79 | desiredWindPlugin = windConfig.GetString("wind_plugin"); | ||
80 | } | ||
64 | } | 81 | } |
65 | 82 | ||
66 | if (m_enabled) | 83 | if (m_enabled) |
67 | { | 84 | { |
85 | m_log.InfoFormat("[WIND] Enabled with an update rate of {0} frames.", m_frameUpdateRate); | ||
68 | 86 | ||
69 | m_scene = scene; | 87 | m_scene = scene; |
70 | m_frame = 0; | 88 | m_frame = 0; |
71 | 89 | ||
90 | // Register all the Wind Model Plug-ins | ||
91 | foreach (IWindModelPlugin windPlugin in AddinManager.GetExtensionObjects("/OpenSim/WindModule")) | ||
92 | { | ||
93 | m_log.InfoFormat("[WIND] Found Plugin: {0}", windPlugin.Name); | ||
94 | m_availableWindPlugins.Add(windPlugin.Name, windPlugin); | ||
95 | } | ||
96 | |||
97 | // Check for desired plugin | ||
98 | if (m_availableWindPlugins.ContainsKey(desiredWindPlugin)) | ||
99 | { | ||
100 | m_activeWindPlugin = m_availableWindPlugins[desiredWindPlugin]; | ||
101 | |||
102 | m_log.InfoFormat("[WIND] {0} plugin found, initializing.", desiredWindPlugin); | ||
103 | |||
104 | if (windConfig != null) | ||
105 | { | ||
106 | m_activeWindPlugin.Initialise(); | ||
107 | m_activeWindPlugin.WindConfig(m_scene, windConfig); | ||
108 | } | ||
109 | } | ||
110 | |||
111 | |||
112 | // if the plug-in wasn't found, default to no wind. | ||
113 | if (m_activeWindPlugin == null) | ||
114 | { | ||
115 | m_log.ErrorFormat("[WIND] Could not find specified wind plug-in: {0}", desiredWindPlugin); | ||
116 | m_log.ErrorFormat("[WIND] Defaulting to no wind."); | ||
117 | } | ||
72 | 118 | ||
73 | scene.EventManager.OnFrame += WindUpdate; | 119 | // This one puts an entry in the main help screen |
74 | scene.EventManager.OnMakeChildAgent += MakeChildAgent; | 120 | m_scene.AddCommand(this, String.Empty, "wind", "Usage: wind <plugin> <param> [value] - Get or Update Wind paramaters", null); |
75 | scene.EventManager.OnAvatarEnteringNewParcel += AvatarEnteringParcel; | 121 | |
76 | scene.EventManager.OnClientClosed += ClientLoggedOut; | 122 | // This one enables the ability to type just the base command without any parameters |
77 | scene.RegisterModuleInterface<IWindModule>(this); | 123 | m_scene.AddCommand(this, "wind", "", "", HandleConsoleCommand); |
78 | 124 | ||
125 | // Get a list of the parameters for each plugin | ||
126 | foreach (IWindModelPlugin windPlugin in m_availableWindPlugins.Values) | ||
127 | { | ||
128 | m_scene.AddCommand(this, String.Format("wind base wind_plugin {0}", windPlugin.Name), String.Format("{0} - {1}", windPlugin.Name, windPlugin.Description), "", HandleConsoleBaseCommand); | ||
129 | m_scene.AddCommand(this, String.Format("wind base wind_update_rate"), "Change the wind update rate.", "", HandleConsoleBaseCommand); | ||
130 | |||
131 | foreach (KeyValuePair<string, string> kvp in windPlugin.WindParams()) | ||
132 | { | ||
133 | m_scene.AddCommand(this, String.Format("wind {0} {1}", windPlugin.Name, kvp.Key), String.Format("{0} : {1} - {2}", windPlugin.Name, kvp.Key, kvp.Value), "", HandleConsoleParamCommand); | ||
134 | } | ||
135 | } | ||
136 | |||
137 | |||
138 | // Register event handlers for when Avatars enter the region, and frame ticks | ||
139 | m_scene.EventManager.OnFrame += WindUpdate; | ||
140 | m_scene.EventManager.OnMakeRootAgent += OnAgentEnteredRegion; | ||
141 | |||
142 | // Register the wind module | ||
143 | m_scene.RegisterModuleInterface<IWindModule>(this); | ||
144 | |||
145 | // Generate initial wind values | ||
79 | GenWindPos(); | 146 | GenWindPos(); |
80 | 147 | ||
148 | // Mark Module Ready for duty | ||
81 | m_ready = true; | 149 | m_ready = true; |
82 | 150 | ||
83 | } | 151 | } |
@@ -93,12 +161,19 @@ namespace OpenSim.Region.CoreModules | |||
93 | if (m_enabled) | 161 | if (m_enabled) |
94 | { | 162 | { |
95 | m_ready = false; | 163 | m_ready = false; |
164 | |||
165 | // REVIEW: If a region module is closed, is there a possibility that it'll re-open/initialize ?? | ||
166 | m_activeWindPlugin = null; | ||
167 | foreach (IWindModelPlugin windPlugin in m_availableWindPlugins.Values) | ||
168 | { | ||
169 | windPlugin.Dispose(); | ||
170 | } | ||
171 | |||
172 | m_availableWindPlugins.Clear(); | ||
173 | |||
96 | // Remove our hooks | 174 | // Remove our hooks |
97 | m_scene.EventManager.OnFrame -= WindUpdate; | 175 | m_scene.EventManager.OnFrame -= WindUpdate; |
98 | // m_scene.EventManager.OnNewClient -= SunToClient; | 176 | m_scene.EventManager.OnMakeRootAgent -= OnAgentEnteredRegion; |
99 | m_scene.EventManager.OnMakeChildAgent -= MakeChildAgent; | ||
100 | m_scene.EventManager.OnAvatarEnteringNewParcel -= AvatarEnteringParcel; | ||
101 | m_scene.EventManager.OnClientClosed -= ClientLoggedOut; | ||
102 | } | 177 | } |
103 | } | 178 | } |
104 | 179 | ||
@@ -112,144 +187,279 @@ namespace OpenSim.Region.CoreModules | |||
112 | get { return false; } | 187 | get { return false; } |
113 | } | 188 | } |
114 | 189 | ||
115 | /// <summary> | ||
116 | /// Retrieve the wind speed at the given region coordinate. This | ||
117 | /// implimentation ignores Z. | ||
118 | /// </summary> | ||
119 | /// <param name="x">0...255</param> | ||
120 | /// <param name="y">0...255</param> | ||
121 | /// <returns></returns> | ||
122 | public Vector3 WindSpeed(int x, int y, int z) | ||
123 | { | ||
124 | Vector3 windVector = new Vector3(0.0f, 0.0f, 0.0f); | ||
125 | |||
126 | x /= 16; | ||
127 | y /= 16; | ||
128 | if (x < 0) x = 0; | ||
129 | if (x > 15) x = 15; | ||
130 | if (y < 0) y = 0; | ||
131 | if (y > 15) y = 15; | ||
132 | 190 | ||
133 | if (windSpeeds != null) | 191 | #endregion |
192 | |||
193 | #region Console Commands | ||
194 | private void ValidateConsole() | ||
195 | { | ||
196 | if (m_scene.ConsoleScene() == null) | ||
134 | { | 197 | { |
135 | windVector.X = windSpeeds[y * 16 + x].X; | 198 | // FIXME: If console region is root then this will be printed by every module. Currently, there is no |
136 | windVector.Y = windSpeeds[y * 16 + x].Y; | 199 | // way to prevent this, short of making the entire module shared (which is complete overkill). |
200 | // One possibility is to return a bool to signal whether the module has completely handled the command | ||
201 | m_log.InfoFormat("[WIND]: Please change to a specific region in order to set Sun parameters."); | ||
202 | return; | ||
137 | } | 203 | } |
138 | 204 | ||
205 | if (m_scene.ConsoleScene() != m_scene) | ||
206 | { | ||
207 | m_log.InfoFormat("[WIND]: Console Scene is not my scene."); | ||
208 | return; | ||
209 | } | ||
210 | } | ||
139 | 211 | ||
140 | return windVector; | 212 | /// <summary> |
213 | /// Base console command handler, only used if a person specifies the base command with now options | ||
214 | /// </summary> | ||
215 | private void HandleConsoleCommand(string module, string[] cmdparams) | ||
216 | { | ||
217 | ValidateConsole(); | ||
218 | m_log.Info("[WIND] The wind command can be used to change the currently active wind model plugin and update the parameters for wind plugins."); | ||
141 | } | 219 | } |
142 | 220 | ||
143 | public void WindToClient(IClientAPI client) | 221 | /// <summary> |
222 | /// Called to change the active wind model plugin | ||
223 | /// </summary> | ||
224 | private void HandleConsoleBaseCommand(string module, string[] cmdparams) | ||
144 | { | 225 | { |
145 | if (m_ready) | 226 | ValidateConsole(); |
227 | |||
228 | if( (cmdparams.Length != 4) | ||
229 | || !cmdparams[1].Equals("base") | ||
230 | ) | ||
146 | { | 231 | { |
147 | //if (!sunFixed) | 232 | m_log.Info("[WIND] Invalid parameters to change parameters for Wind module base, usage: wind base <parameter> <value>"); |
148 | //GenWindPos(); // Generate shared values once | 233 | return; |
149 | client.SendWindData(windSpeeds); | ||
150 | } | 234 | } |
235 | |||
236 | switch (cmdparams[2]) | ||
237 | { | ||
238 | case "wind_update_rate": | ||
239 | int newRate = 1; | ||
240 | |||
241 | if (int.TryParse(cmdparams[3], out newRate)) | ||
242 | { | ||
243 | m_frameUpdateRate = newRate; | ||
244 | } | ||
245 | else | ||
246 | { | ||
247 | m_log.InfoFormat("[WIND] Invalid value {0} specified for {1}", cmdparams[3], cmdparams[2]); | ||
248 | return; | ||
249 | } | ||
250 | |||
251 | break; | ||
252 | case "wind_plugin": | ||
253 | string desiredPlugin = cmdparams[3]; | ||
254 | |||
255 | if (desiredPlugin.Equals(m_activeWindPlugin.Name)) | ||
256 | { | ||
257 | m_log.InfoFormat("[WIND] Wind model plugin {0} is already active", cmdparams[3]); | ||
258 | return; | ||
259 | } | ||
260 | |||
261 | if (m_availableWindPlugins.ContainsKey(desiredPlugin)) | ||
262 | { | ||
263 | m_activeWindPlugin = m_availableWindPlugins[cmdparams[3]]; | ||
264 | m_log.InfoFormat("[WIND] {0} wind model plugin now active", m_activeWindPlugin.Name); | ||
265 | } | ||
266 | else | ||
267 | { | ||
268 | m_log.InfoFormat("[WIND] Could not find wind model plugin {0}", desiredPlugin); | ||
269 | } | ||
270 | break; | ||
271 | } | ||
272 | |||
151 | } | 273 | } |
152 | 274 | ||
153 | public void WindUpdate() | 275 | /// <summary> |
276 | /// Called to change plugin parameters. | ||
277 | /// </summary> | ||
278 | private void HandleConsoleParamCommand(string module, string[] cmdparams) | ||
154 | { | 279 | { |
155 | if (((m_frame++ % m_frame_mod) != 0) || !m_ready) | 280 | ValidateConsole(); |
281 | |||
282 | // wind <plugin> <param> [value] | ||
283 | if ((cmdparams.Length != 4) | ||
284 | && (cmdparams.Length != 3)) | ||
156 | { | 285 | { |
286 | m_log.Info("[WIND] Usage: wind <plugin> <param> [value]"); | ||
157 | return; | 287 | return; |
158 | } | 288 | } |
159 | //m_log.Debug("[WIND]:Regenerating..."); | ||
160 | GenWindPos(); // Generate shared values once | ||
161 | 289 | ||
162 | //int spotxp = 0; | 290 | string plugin = cmdparams[1]; |
163 | //int spotyp = 0; | 291 | string param = cmdparams[2]; |
164 | //int spotxm = 0; | 292 | float value = 0f; |
165 | //int spotym = 0; | 293 | if (cmdparams.Length == 4) |
166 | List<ScenePresence> avatars = m_scene.GetAvatars(); | ||
167 | foreach (ScenePresence avatar in avatars) | ||
168 | { | 294 | { |
169 | if (!avatar.IsChildAgent) | 295 | if (!float.TryParse(cmdparams[3], out value)) |
170 | { | 296 | { |
171 | avatar.ControllingClient.SendWindData(windSpeeds); | 297 | m_log.InfoFormat("[WIND] Invalid value {0}", cmdparams[3]); |
172 | } | 298 | } |
173 | } | ||
174 | 299 | ||
175 | // set estate settings for region access to sun position | 300 | try |
176 | //m_scene.RegionInfo.RegionSettings.SunVector = Position; | 301 | { |
177 | //m_scene.RegionInfo.EstateSettings.sunHour = GetLindenEstateHourFromCurrentTime(); | 302 | WindParamSet(plugin, param, value); |
178 | } | 303 | } |
179 | 304 | catch (Exception e) | |
180 | public void ForceWindUpdateToAllClients() | 305 | { |
181 | { | 306 | m_log.InfoFormat("[WIND] {0}", e.Message); |
182 | GenWindPos(); // Generate shared values once | 307 | } |
183 | 308 | } | |
184 | List<ScenePresence> avatars = m_scene.GetAvatars(); | 309 | else |
185 | foreach (ScenePresence avatar in avatars) | ||
186 | { | 310 | { |
187 | if (!avatar.IsChildAgent) | 311 | try |
188 | avatar.ControllingClient.SendWindData(windSpeeds); | 312 | { |
313 | value = WindParamGet(plugin, param); | ||
314 | m_log.InfoFormat("[WIND] {0} : {1}", param, value); | ||
315 | } | ||
316 | catch (Exception e) | ||
317 | { | ||
318 | m_log.InfoFormat("[WIND] {0}", e.Message); | ||
319 | } | ||
189 | } | 320 | } |
190 | 321 | ||
191 | // set estate settings for region access to sun position | ||
192 | //m_scene.RegionInfo.RegionSettings.SunVector = Position; | ||
193 | //m_scene.RegionInfo.RegionSettings.SunPosition = GetLindenEstateHourFromCurrentTime(); | ||
194 | } | 322 | } |
323 | #endregion | ||
324 | |||
325 | |||
326 | #region IWindModule Methods | ||
327 | |||
195 | /// <summary> | 328 | /// <summary> |
196 | /// Calculate the sun's orbital position and its velocity. | 329 | /// Retrieve the wind speed at the given region coordinate. This |
330 | /// implimentation ignores Z. | ||
197 | /// </summary> | 331 | /// </summary> |
332 | /// <param name="x">0...255</param> | ||
333 | /// <param name="y">0...255</param> | ||
334 | public Vector3 WindSpeed(int x, int y, int z) | ||
335 | { | ||
336 | if (m_activeWindPlugin != null) | ||
337 | { | ||
338 | return m_activeWindPlugin.WindSpeed(x, y, z); | ||
339 | } | ||
340 | else | ||
341 | { | ||
342 | return new Vector3(0.0f, 0.0f, 0.0f); | ||
343 | } | ||
344 | } | ||
198 | 345 | ||
199 | private void GenWindPos() | 346 | public void WindParamSet(string plugin, string param, float value) |
200 | { | 347 | { |
201 | for (int y = 0; y < 16; y++) | 348 | if (m_availableWindPlugins.ContainsKey(plugin)) |
202 | { | 349 | { |
203 | for (int x = 0; x < 16; x++) | 350 | IWindModelPlugin windPlugin = m_availableWindPlugins[plugin]; |
204 | { | 351 | windPlugin.WindParamSet(param, value); |
205 | windSpeeds[y * 16 + x].X = (float)(m_rndnums.NextDouble() * 2d - 1d); // -1 to 1 | 352 | m_log.InfoFormat("[WIND] {0} set to {1}", param, value); |
206 | windSpeeds[y * 16 + x].Y = (float)(m_rndnums.NextDouble() * 2d - 1d); // -1 to 1 | 353 | } |
207 | windSpeeds[y * 16 + x].X *= m_strength; | 354 | else |
208 | windSpeeds[y * 16 + x].Y *= m_strength; | 355 | { |
209 | } | 356 | throw new Exception(String.Format("Could not find plugin {0}", plugin)); |
210 | } | 357 | } |
358 | |||
211 | } | 359 | } |
212 | 360 | ||
213 | private void ClientLoggedOut(UUID AgentId) | 361 | public float WindParamGet(string plugin, string param) |
214 | { | 362 | { |
215 | lock (m_rootAgents) | 363 | if (m_availableWindPlugins.ContainsKey(plugin)) |
216 | { | 364 | { |
217 | if (m_rootAgents.ContainsKey(AgentId)) | 365 | IWindModelPlugin windPlugin = m_availableWindPlugins[plugin]; |
218 | { | 366 | return windPlugin.WindParamGet(param); |
219 | m_rootAgents.Remove(AgentId); | 367 | } |
220 | } | 368 | else |
369 | { | ||
370 | throw new Exception(String.Format("Could not find plugin {0}", plugin)); | ||
221 | } | 371 | } |
222 | } | 372 | } |
223 | 373 | ||
224 | private void AvatarEnteringParcel(ScenePresence avatar, int localLandID, UUID regionID) | 374 | public string WindActiveModelPluginName |
225 | { | 375 | { |
226 | lock (m_rootAgents) | 376 | get |
227 | { | 377 | { |
228 | if (m_rootAgents.ContainsKey(avatar.UUID)) | 378 | if (m_activeWindPlugin != null) |
229 | { | 379 | { |
230 | m_rootAgents[avatar.UUID] = avatar.RegionHandle; | 380 | return m_activeWindPlugin.Name; |
231 | } | 381 | } |
232 | else | 382 | else |
233 | { | 383 | { |
234 | m_rootAgents.Add(avatar.UUID, avatar.RegionHandle); | 384 | return String.Empty; |
235 | WindToClient(avatar.ControllingClient); | ||
236 | } | 385 | } |
237 | } | 386 | } |
238 | //m_log.Info("[FRIEND]: " + avatar.Name + " status:" + (!avatar.IsChildAgent).ToString()); | ||
239 | } | 387 | } |
240 | 388 | ||
241 | private void MakeChildAgent(ScenePresence avatar) | 389 | #endregion |
390 | |||
391 | /// <summary> | ||
392 | /// Called on each frame update. Updates the wind model and clients as necessary. | ||
393 | /// </summary> | ||
394 | public void WindUpdate() | ||
395 | { | ||
396 | if (((m_frame++ % m_frameUpdateRate) != 0) || !m_ready) | ||
397 | { | ||
398 | return; | ||
399 | } | ||
400 | |||
401 | GenWindPos(); | ||
402 | |||
403 | SendWindAllClients(); | ||
404 | } | ||
405 | |||
406 | public void OnAgentEnteredRegion(ScenePresence avatar) | ||
407 | { | ||
408 | if (m_ready) | ||
409 | { | ||
410 | if (m_activeWindPlugin != null) | ||
411 | { | ||
412 | // Ask wind plugin to generate a LL wind array to be cached locally | ||
413 | // Try not to update this too often, as it may involve array copies | ||
414 | if (m_frame >= (m_frameLastUpdateClientArray + m_frameUpdateRate)) | ||
415 | { | ||
416 | windSpeeds = m_activeWindPlugin.WindLLClientArray(); | ||
417 | m_frameLastUpdateClientArray = m_frame; | ||
418 | } | ||
419 | } | ||
420 | |||
421 | avatar.ControllingClient.SendWindData(windSpeeds); | ||
422 | } | ||
423 | } | ||
424 | |||
425 | private void SendWindAllClients() | ||
242 | { | 426 | { |
243 | lock (m_rootAgents) | 427 | if (m_ready) |
244 | { | 428 | { |
245 | if (m_rootAgents.ContainsKey(avatar.UUID)) | 429 | List<ScenePresence> avatars = m_scene.GetAvatars(); |
430 | |||
431 | if (avatars.Count > 0) | ||
246 | { | 432 | { |
247 | if (m_rootAgents[avatar.UUID] == avatar.RegionHandle) | 433 | // Ask wind plugin to generate a LL wind array to be cached locally |
434 | // Try not to update this too often, as it may involve array copies | ||
435 | if (m_frame >= (m_frameLastUpdateClientArray + m_frameUpdateRate)) | ||
436 | { | ||
437 | windSpeeds = m_activeWindPlugin.WindLLClientArray(); | ||
438 | m_frameLastUpdateClientArray = m_frame; | ||
439 | } | ||
440 | |||
441 | foreach (ScenePresence avatar in avatars) | ||
248 | { | 442 | { |
249 | m_rootAgents.Remove(avatar.UUID); | 443 | if (!avatar.IsChildAgent) |
444 | avatar.ControllingClient.SendWindData(windSpeeds); | ||
250 | } | 445 | } |
251 | } | 446 | } |
252 | } | 447 | } |
253 | } | 448 | } |
449 | /// <summary> | ||
450 | /// Calculate the sun's orbital position and its velocity. | ||
451 | /// </summary> | ||
452 | |||
453 | private void GenWindPos() | ||
454 | { | ||
455 | if( m_activeWindPlugin != null ) | ||
456 | { | ||
457 | // Tell Wind Plugin to update it's wind data | ||
458 | m_activeWindPlugin.WindUpdate(m_frame); | ||
459 | } | ||
460 | } | ||
461 | |||
462 | |||
463 | |||
254 | } | 464 | } |
255 | } | 465 | } |