OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
WindModule.cs
Go to the documentation of this file.
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 OpenSim.Framework;
36 using OpenSim.Region.Framework.Interfaces;
37 using OpenSim.Region.Framework.Scenes;
38 
39 using OpenSim.Region.CoreModules.World.Wind;
40 
41 namespace OpenSim.Region.CoreModules
42 {
43  [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "WindModule")]
44  public class WindModule : IWindModule
45  {
46  private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
47 
48  private uint m_frame = 0;
49  private uint m_frameLastUpdateClientArray = 0;
50  private int m_frameUpdateRate = 150;
51  //private Random m_rndnums = new Random(Environment.TickCount);
52  private Scene m_scene = null;
53  private bool m_ready = false;
54 
55  private bool m_enabled = false;
56  private IConfig m_windConfig;
57  private IWindModelPlugin m_activeWindPlugin = null;
58  private string m_dWindPluginName = "SimpleRandomWind";
59  private Dictionary<string, IWindModelPlugin> m_availableWindPlugins = new Dictionary<string, IWindModelPlugin>();
60 
61  // Simplified windSpeeds based on the fact that the client protocal tracks at a resolution of 16m
62  private Vector2[] windSpeeds = new Vector2[16 * 16];
63 
64  #region INonSharedRegionModule Methods
65 
66  public void Initialise(IConfigSource config)
67  {
68  m_windConfig = config.Configs["Wind"];
69 // string desiredWindPlugin = m_dWindPluginName;
70 
71  if (m_windConfig != null)
72  {
73  m_enabled = m_windConfig.GetBoolean("enabled", true);
74 
75  m_frameUpdateRate = m_windConfig.GetInt("wind_update_rate", 150);
76 
77  // Determine which wind model plugin is desired
78  if (m_windConfig.Contains("wind_plugin"))
79  {
80  m_dWindPluginName = m_windConfig.GetString("wind_plugin", m_dWindPluginName);
81  }
82  }
83 
84  if (m_enabled)
85  {
86  m_log.InfoFormat("[WIND] Enabled with an update rate of {0} frames.", m_frameUpdateRate);
87 
88  }
89 
90  }
91 
92  public void AddRegion(Scene scene)
93  {
94  if (!m_enabled)
95  return;
96 
97  m_scene = scene;
98  m_frame = 0;
99 
100  // Register all the Wind Model Plug-ins
101  foreach (IWindModelPlugin windPlugin in AddinManager.GetExtensionObjects("/OpenSim/WindModule", false))
102  {
103  m_log.InfoFormat("[WIND] Found Plugin: {0}", windPlugin.Name);
104  m_availableWindPlugins.Add(windPlugin.Name, windPlugin);
105  }
106 
107  // Check for desired plugin
108  if (m_availableWindPlugins.ContainsKey(m_dWindPluginName))
109  {
110  m_activeWindPlugin = m_availableWindPlugins[m_dWindPluginName];
111 
112  m_log.InfoFormat("[WIND] {0} plugin found, initializing.", m_dWindPluginName);
113 
114  if (m_windConfig != null)
115  {
116  m_activeWindPlugin.Initialise();
117  m_activeWindPlugin.WindConfig(m_scene, m_windConfig);
118  }
119  }
120 
121 
122  // if the plug-in wasn't found, default to no wind.
123  if (m_activeWindPlugin == null)
124  {
125  m_log.ErrorFormat("[WIND] Could not find specified wind plug-in: {0}", m_dWindPluginName);
126  m_log.ErrorFormat("[WIND] Defaulting to no wind.");
127  }
128 
129  // This one puts an entry in the main help screen
130  // m_scene.AddCommand("Regions", this, "wind", "wind", "Usage: wind <plugin> <param> [value] - Get or Update Wind paramaters", null);
131 
132  // This one enables the ability to type just the base command without any parameters
133  // m_scene.AddCommand("Regions", this, "wind", "", "", HandleConsoleCommand);
134 
135  // Get a list of the parameters for each plugin
136  foreach (IWindModelPlugin windPlugin in m_availableWindPlugins.Values)
137  {
138  // m_scene.AddCommand("Regions", this, String.Format("wind base wind_plugin {0}", windPlugin.Name), String.Format("{0} - {1}", windPlugin.Name, windPlugin.Description), "", HandleConsoleBaseCommand);
139  m_scene.AddCommand(
140  "Regions",
141  this,
142  "wind base wind_update_rate",
143  "wind base wind_update_rate [<value>]",
144  "Get or set the wind update rate.",
145  "",
146  HandleConsoleBaseCommand);
147 
148  foreach (KeyValuePair<string, string> kvp in windPlugin.WindParams())
149  {
150  string windCommand = String.Format("wind {0} {1}", windPlugin.Name, kvp.Key);
151  m_scene.AddCommand("Regions", this, windCommand, string.Format("{0} [<value>]", windCommand), kvp.Value, "", HandleConsoleParamCommand);
152  }
153  }
154 
155  // Register event handlers for when Avatars enter the region, and frame ticks
156  m_scene.EventManager.OnFrame += WindUpdate;
157  m_scene.EventManager.OnMakeRootAgent += OnAgentEnteredRegion;
158 
159  // Register the wind module
160  m_scene.RegisterModuleInterface<IWindModule>(this);
161 
162  // Generate initial wind values
163  GenWindPos();
164 
165  // Mark Module Ready for duty
166  m_ready = true;
167  }
168 
169  public void RemoveRegion(Scene scene)
170  {
171  if (!m_enabled)
172  return;
173 
174  m_ready = false;
175 
176  // REVIEW: If a region module is closed, is there a possibility that it'll re-open/initialize ??
177  m_activeWindPlugin = null;
178  foreach (IWindModelPlugin windPlugin in m_availableWindPlugins.Values)
179  {
180  windPlugin.Dispose();
181  }
182 
183  m_availableWindPlugins.Clear();
184 
185  // Remove our hooks
186  m_scene.EventManager.OnFrame -= WindUpdate;
187  m_scene.EventManager.OnMakeRootAgent -= OnAgentEnteredRegion;
188 
189  }
190 
191  public void Close()
192  {
193  }
194 
195  public string Name
196  {
197  get { return "WindModule"; }
198  }
199 
200  public Type ReplaceableInterface
201  {
202  get { return null; }
203  }
204 
205  public void RegionLoaded(Scene scene)
206  {
207  }
208 
209  #endregion
210 
211  #region Console Commands
212  private void ValidateConsole()
213  {
214  if (m_scene.ConsoleScene() == null)
215  {
216  // FIXME: If console region is root then this will be printed by every module. Currently, there is no
217  // way to prevent this, short of making the entire module shared (which is complete overkill).
218  // One possibility is to return a bool to signal whether the module has completely handled the command
219  MainConsole.Instance.Output("Please change to a specific region in order to set Sun parameters.");
220  return;
221  }
222 
223  if (m_scene.ConsoleScene() != m_scene)
224  {
225  MainConsole.Instance.Output("Console Scene is not my scene.");
226  return;
227  }
228  }
229 
233  private void HandleConsoleCommand(string module, string[] cmdparams)
234  {
235  ValidateConsole();
236 
237  MainConsole.Instance.Output(
238  "The wind command can be used to change the currently active wind model plugin and update the parameters for wind plugins.");
239  }
240 
244  private void HandleConsoleBaseCommand(string module, string[] cmdparams)
245  {
246  ValidateConsole();
247 
248  if ((cmdparams.Length != 4)
249  || !cmdparams[1].Equals("base"))
250  {
251  MainConsole.Instance.Output(
252  "Invalid parameters to change parameters for Wind module base, usage: wind base <parameter> <value>");
253 
254  return;
255  }
256 
257  switch (cmdparams[2])
258  {
259  case "wind_update_rate":
260  int newRate = 1;
261 
262  if (int.TryParse(cmdparams[3], out newRate))
263  {
264  m_frameUpdateRate = newRate;
265  }
266  else
267  {
268  MainConsole.Instance.OutputFormat(
269  "Invalid value {0} specified for {1}", cmdparams[3], cmdparams[2]);
270 
271  return;
272  }
273 
274  break;
275  case "wind_plugin":
276  string desiredPlugin = cmdparams[3];
277 
278  if (desiredPlugin.Equals(m_activeWindPlugin.Name))
279  {
280  MainConsole.Instance.OutputFormat("Wind model plugin {0} is already active", cmdparams[3]);
281 
282  return;
283  }
284 
285  if (m_availableWindPlugins.ContainsKey(desiredPlugin))
286  {
287  m_activeWindPlugin = m_availableWindPlugins[cmdparams[3]];
288 
289  MainConsole.Instance.OutputFormat("{0} wind model plugin now active", m_activeWindPlugin.Name);
290  }
291  else
292  {
293  MainConsole.Instance.OutputFormat("Could not find wind model plugin {0}", desiredPlugin);
294  }
295  break;
296  }
297  }
298 
302  private void HandleConsoleParamCommand(string module, string[] cmdparams)
303  {
304  ValidateConsole();
305 
306  // wind <plugin> <param> [value]
307  if ((cmdparams.Length != 4)
308  && (cmdparams.Length != 3))
309  {
310  MainConsole.Instance.Output("Usage: wind <plugin> <param> [value]");
311  return;
312  }
313 
314  string plugin = cmdparams[1];
315  string param = cmdparams[2];
316  float value = 0f;
317  if (cmdparams.Length == 4)
318  {
319  if (!float.TryParse(cmdparams[3], out value))
320  {
321  MainConsole.Instance.OutputFormat("Invalid value {0}", cmdparams[3]);
322  }
323 
324  try
325  {
326  WindParamSet(plugin, param, value);
327  MainConsole.Instance.OutputFormat("{0} set to {1}", param, value);
328  }
329  catch (Exception e)
330  {
331  MainConsole.Instance.OutputFormat("{0}", e.Message);
332  }
333  }
334  else
335  {
336  try
337  {
338  value = WindParamGet(plugin, param);
339  MainConsole.Instance.OutputFormat("{0} : {1}", param, value);
340  }
341  catch (Exception e)
342  {
343  MainConsole.Instance.OutputFormat("{0}", e.Message);
344  }
345  }
346 
347  }
348  #endregion
349 
350 
351  #region IWindModule Methods
352 
359  public Vector3 WindSpeed(int x, int y, int z)
360  {
361  if (m_activeWindPlugin != null)
362  {
363  return m_activeWindPlugin.WindSpeed(x, y, z);
364  }
365  else
366  {
367  return new Vector3(0.0f, 0.0f, 0.0f);
368  }
369  }
370 
371  public void WindParamSet(string plugin, string param, float value)
372  {
373  if (m_availableWindPlugins.ContainsKey(plugin))
374  {
375  IWindModelPlugin windPlugin = m_availableWindPlugins[plugin];
376  windPlugin.WindParamSet(param, value);
377  }
378  else
379  {
380  throw new Exception(String.Format("Could not find plugin {0}", plugin));
381  }
382  }
383 
384  public float WindParamGet(string plugin, string param)
385  {
386  if (m_availableWindPlugins.ContainsKey(plugin))
387  {
388  IWindModelPlugin windPlugin = m_availableWindPlugins[plugin];
389  return windPlugin.WindParamGet(param);
390  }
391  else
392  {
393  throw new Exception(String.Format("Could not find plugin {0}", plugin));
394  }
395  }
396 
397  public string WindActiveModelPluginName
398  {
399  get
400  {
401  if (m_activeWindPlugin != null)
402  {
403  return m_activeWindPlugin.Name;
404  }
405  else
406  {
407  return String.Empty;
408  }
409  }
410  }
411 
412  #endregion
413 
417  public void WindUpdate()
418  {
419  if (((m_frame++ % m_frameUpdateRate) != 0) || !m_ready)
420  {
421  return;
422  }
423 
424  GenWindPos();
425 
426  SendWindAllClients();
427  }
428 
430  {
431  if (m_ready)
432  {
433  if (m_activeWindPlugin != null)
434  {
435  // Ask wind plugin to generate a LL wind array to be cached locally
436  // Try not to update this too often, as it may involve array copies
437  if (m_frame >= (m_frameLastUpdateClientArray + m_frameUpdateRate))
438  {
439  windSpeeds = m_activeWindPlugin.WindLLClientArray();
440  m_frameLastUpdateClientArray = m_frame;
441  }
442  }
443 
444  avatar.ControllingClient.SendWindData(windSpeeds);
445  }
446  }
447 
448  private void SendWindAllClients()
449  {
450  if (m_ready)
451  {
452  if (m_scene.GetRootAgentCount() > 0)
453  {
454  // Ask wind plugin to generate a LL wind array to be cached locally
455  // Try not to update this too often, as it may involve array copies
456  if (m_frame >= (m_frameLastUpdateClientArray + m_frameUpdateRate))
457  {
458  windSpeeds = m_activeWindPlugin.WindLLClientArray();
459  m_frameLastUpdateClientArray = m_frame;
460  }
461 
462  m_scene.ForEachRootClient(delegate(IClientAPI client)
463  {
464  client.SendWindData(windSpeeds);
465  });
466  }
467  }
468  }
472 
473  private void GenWindPos()
474  {
475  if (m_activeWindPlugin != null)
476  {
477  // Tell Wind Plugin to update it's wind data
478  m_activeWindPlugin.WindUpdate(m_frame);
479  }
480  }
481  }
482 }
void AddRegion(Scene scene)
This is called whenever a Scene is added. For shared modules, this can happen several times...
Definition: WindModule.cs:92
void WindParamSet(string plugin, string param, float value)
Set Wind Plugin Parameter
Definition: WindModule.cs:371
void WindUpdate()
Called on each frame update. Updates the wind model and clients as necessary.
Definition: WindModule.cs:417
void RemoveRegion(Scene scene)
This is called whenever a Scene is removed. For shared modules, this can happen several times...
Definition: WindModule.cs:169
void Initialise(IConfigSource config)
This is called to initialize the region module. For shared modules, this is called exactly once...
Definition: WindModule.cs:66
Dictionary< string, string > WindParams()
Retrieve a list of parameter/description pairs.
void RegionLoaded(Scene scene)
This will be called once for every scene loaded. In a shared module this will be multiple times in on...
Definition: WindModule.cs:205
float WindParamGet(string plugin, string param)
Get Wind Plugin Parameter
Definition: WindModule.cs:384
void Close()
This is the inverse to Initialise. After a Close(), this instance won't be usable anymore...
Definition: WindModule.cs:191
Vector3 WindSpeed(int x, int y, int z)
Retrieve the wind speed at the given region coordinate. This implimentation ignores Z...
Definition: WindModule.cs:359
void OnAgentEnteredRegion(ScenePresence avatar)
Definition: WindModule.cs:429