OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
TreePopulatorModule.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 System.Timers;
32 using OpenMetaverse;
33 using log4net;
34 using Mono.Addins;
35 using Nini.Config;
36 using OpenSim.Framework;
37 using OpenSim.Region.CoreModules.Framework.InterfaceCommander;
38 using OpenSim.Region.Framework.Interfaces;
39 using OpenSim.Region.Framework.Scenes;
40 
41 using System.Xml;
42 using System.Xml.Serialization;
43 using System.IO;
44 
45 namespace OpenSim.Region.OptionalModules.World.TreePopulator
46 {
50  [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "TreePopulatorModule")]
52  {
53  private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
54  private readonly Commander m_commander = new Commander("tree");
55  private Scene m_scene;
56 
57  [XmlRootAttribute(ElementName = "Copse", IsNullable = false)]
58  public class Copse
59  {
60  public string m_name;
61  public Boolean m_frozen;
62  public Tree m_tree_type;
63  public int m_tree_quantity;
64  public float m_treeline_low;
65  public float m_treeline_high;
66  public Vector3 m_seed_point;
67  public double m_range;
68  public Vector3 m_initial_scale;
69  public Vector3 m_maximum_scale;
70  public Vector3 m_rate;
71 
72  [XmlIgnore]
74  [XmlIgnore]
75  public List<UUID> m_trees;
76 
77  public Copse()
78  {
79  }
80 
81  public Copse(string fileName, Boolean planted)
82  {
83  Copse cp = (Copse)DeserializeObject(fileName);
84 
85  this.m_name = cp.m_name;
86  this.m_frozen = cp.m_frozen;
87  this.m_tree_quantity = cp.m_tree_quantity;
88  this.m_treeline_high = cp.m_treeline_high;
89  this.m_treeline_low = cp.m_treeline_low;
90  this.m_range = cp.m_range;
91  this.m_tree_type = cp.m_tree_type;
92  this.m_seed_point = cp.m_seed_point;
93  this.m_initial_scale = cp.m_initial_scale;
94  this.m_maximum_scale = cp.m_maximum_scale;
95  this.m_initial_scale = cp.m_initial_scale;
96  this.m_rate = cp.m_rate;
97  this.m_planted = planted;
98  this.m_trees = new List<UUID>();
99  }
100 
101  public Copse(string copsedef)
102  {
103  char[] delimiterChars = {':', ';'};
104  string[] field = copsedef.Split(delimiterChars);
105 
106  this.m_name = field[1].Trim();
107  this.m_frozen = (copsedef[0] == 'F');
108  this.m_tree_quantity = int.Parse(field[2]);
109  this.m_treeline_high = float.Parse(field[3], Culture.NumberFormatInfo);
110  this.m_treeline_low = float.Parse(field[4], Culture.NumberFormatInfo);
111  this.m_range = double.Parse(field[5], Culture.NumberFormatInfo);
112  this.m_tree_type = (Tree) Enum.Parse(typeof(Tree),field[6]);
113  this.m_seed_point = Vector3.Parse(field[7]);
114  this.m_initial_scale = Vector3.Parse(field[8]);
115  this.m_maximum_scale = Vector3.Parse(field[9]);
116  this.m_rate = Vector3.Parse(field[10]);
117  this.m_planted = true;
118  this.m_trees = new List<UUID>();
119  }
120 
121  public Copse(string name, int quantity, float high, float low, double range, Vector3 point, Tree type, Vector3 scale, Vector3 max_scale, Vector3 rate, List<UUID> trees)
122  {
123  this.m_name = name;
124  this.m_frozen = false;
125  this.m_tree_quantity = quantity;
126  this.m_treeline_high = high;
127  this.m_treeline_low = low;
128  this.m_range = range;
129  this.m_tree_type = type;
130  this.m_seed_point = point;
131  this.m_initial_scale = scale;
132  this.m_maximum_scale = max_scale;
133  this.m_rate = rate;
134  this.m_planted = false;
135  this.m_trees = trees;
136  }
137 
138  public override string ToString()
139  {
140  string frozen = (this.m_frozen ? "F" : "A");
141 
142  return string.Format("{0}TPM: {1}; {2}; {3:0.0}; {4:0.0}; {5:0.0}; {6}; {7:0.0}; {8:0.0}; {9:0.0}; {10:0.00};",
143  frozen,
144  this.m_name,
145  this.m_tree_quantity,
146  this.m_treeline_high,
147  this.m_treeline_low,
148  this.m_range,
149  this.m_tree_type,
150  this.m_seed_point.ToString(),
151  this.m_initial_scale.ToString(),
152  this.m_maximum_scale.ToString(),
153  this.m_rate.ToString());
154  }
155  }
156 
157  private List<Copse> m_copse;
158 
159  private double m_update_ms = 1000.0; // msec between updates
160  private bool m_active_trees = false;
161 
162  Timer CalculateTrees;
163 
164  #region ICommandableModule Members
165 
166  public ICommander CommandInterface
167  {
168  get { return m_commander; }
169  }
170 
171  #endregion
172 
173  #region Region Module interface
174 
175  public void Initialise(IConfigSource config)
176  {
177 
178  // ini file settings
179  try
180  {
181  m_active_trees = config.Configs["Trees"].GetBoolean("active_trees", m_active_trees);
182  }
183  catch (Exception)
184  {
185  m_log.Debug("[TREES]: ini failure for active_trees - using default");
186  }
187 
188  try
189  {
190  m_update_ms = config.Configs["Trees"].GetDouble("update_rate", m_update_ms);
191  }
192  catch (Exception)
193  {
194  m_log.Debug("[TREES]: ini failure for update_rate - using default");
195  }
196 
197  InstallCommands();
198 
199  m_log.Debug("[TREES]: Initialised tree module");
200  }
201 
202  public void AddRegion(Scene scene)
203  {
204  m_scene = scene;
205  m_scene.RegisterModuleCommander(m_commander);
206  m_scene.EventManager.OnPluginConsole += EventManager_OnPluginConsole;
207 
208  }
209 
210  public void RemoveRegion(Scene scene)
211  {
212  }
213 
214  public void RegionLoaded(Scene scene)
215  {
216  ReloadCopse();
217  if (m_copse.Count > 0)
218  m_log.Info("[TREES]: Copse load complete");
219 
220  if (m_active_trees)
221  activeizeTreeze(true);
222  }
223 
224  public void Close()
225  {
226  }
227 
228  public string Name
229  {
230  get { return "TreePopulatorModule"; }
231  }
232 
233  public Type ReplaceableInterface
234  {
235  get { return null; }
236  }
237 
238 
239  #endregion
240 
241  //--------------------------------------------------------------
242 
243  #region ICommandableModule Members
244 
245  private void HandleTreeActive(Object[] args)
246  {
247  if ((Boolean)args[0] && !m_active_trees)
248  {
249  m_log.InfoFormat("[TREES]: Activating Trees");
250  m_active_trees = true;
251  activeizeTreeze(m_active_trees);
252  }
253  else if (!(Boolean)args[0] && m_active_trees)
254  {
255  m_log.InfoFormat("[TREES]: Trees module is no longer active");
256  m_active_trees = false;
257  activeizeTreeze(m_active_trees);
258  }
259  else
260  {
261  m_log.InfoFormat("[TREES]: Trees module is already in the required state");
262  }
263  }
264 
265  private void HandleTreeFreeze(Object[] args)
266  {
267  string copsename = ((string)args[0]).Trim();
268  Boolean freezeState = (Boolean) args[1];
269 
270  foreach (Copse cp in m_copse)
271  {
272  if (cp.m_name == copsename && (!cp.m_frozen && freezeState || cp.m_frozen && !freezeState))
273  {
274  cp.m_frozen = freezeState;
275  foreach (UUID tree in cp.m_trees)
276  {
277  SceneObjectPart sop = ((SceneObjectGroup)m_scene.Entities[tree]).RootPart;
278  sop.Name = (freezeState ? sop.Name.Replace("ATPM", "FTPM") : sop.Name.Replace("FTPM", "ATPM"));
279  sop.ParentGroup.HasGroupChanged = true;
280  }
281 
282  m_log.InfoFormat("[TREES]: Activity for copse {0} is frozen {1}", copsename, freezeState);
283  return;
284  }
285  else if (cp.m_name == copsename && (cp.m_frozen && freezeState || !cp.m_frozen && !freezeState))
286  {
287  m_log.InfoFormat("[TREES]: Copse {0} is already in the requested freeze state", copsename);
288  return;
289  }
290  }
291  m_log.InfoFormat("[TREES]: Copse {0} was not found - command failed", copsename);
292  }
293 
294  private void HandleTreeLoad(Object[] args)
295  {
296  Copse copse;
297 
298  m_log.InfoFormat("[TREES]: Loading copse definition....");
299 
300  copse = new Copse(((string)args[0]), false);
301  foreach (Copse cp in m_copse)
302  {
303  if (cp.m_name == copse.m_name)
304  {
305  m_log.InfoFormat("[TREES]: Copse: {0} is already defined - command failed", copse.m_name);
306  return;
307  }
308  }
309 
310  m_copse.Add(copse);
311  m_log.InfoFormat("[TREES]: Loaded copse: {0}", copse.ToString());
312  }
313 
314  private void HandleTreePlant(Object[] args)
315  {
316  string copsename = ((string)args[0]).Trim();
317 
318  m_log.InfoFormat("[TREES]: New tree planting for copse {0}", copsename);
319  UUID uuid = m_scene.RegionInfo.EstateSettings.EstateOwner;
320 
321  foreach (Copse copse in m_copse)
322  {
323  if (copse.m_name == copsename)
324  {
325  if (!copse.m_planted)
326  {
327  // The first tree for a copse is created here
328  CreateTree(uuid, copse, copse.m_seed_point);
329  copse.m_planted = true;
330  return;
331  }
332  else
333  {
334  m_log.InfoFormat("[TREES]: Copse {0} has already been planted", copsename);
335  }
336  }
337  }
338  m_log.InfoFormat("[TREES]: Copse {0} not found for planting", copsename);
339  }
340 
341  private void HandleTreeRate(Object[] args)
342  {
343  m_update_ms = (double)args[0];
344  if (m_update_ms >= 1000.0)
345  {
346  if (m_active_trees)
347  {
348  activeizeTreeze(false);
349  activeizeTreeze(true);
350  }
351  m_log.InfoFormat("[TREES]: Update rate set to {0} mSec", m_update_ms);
352  }
353  else
354  {
355  m_log.InfoFormat("[TREES]: minimum rate is 1000.0 mSec - command failed");
356  }
357  }
358 
359  private void HandleTreeReload(Object[] args)
360  {
361  if (m_active_trees)
362  {
363  CalculateTrees.Stop();
364  }
365 
366  ReloadCopse();
367 
368  if (m_active_trees)
369  {
370  CalculateTrees.Start();
371  }
372  }
373 
374  private void HandleTreeRemove(Object[] args)
375  {
376  string copsename = ((string)args[0]).Trim();
377  Copse copseIdentity = null;
378 
379  foreach (Copse cp in m_copse)
380  {
381  if (cp.m_name == copsename)
382  {
383  copseIdentity = cp;
384  }
385  }
386 
387  if (copseIdentity != null)
388  {
389  foreach (UUID tree in copseIdentity.m_trees)
390  {
391  if (m_scene.Entities.ContainsKey(tree))
392  {
393  SceneObjectPart selectedTree = ((SceneObjectGroup)m_scene.Entities[tree]).RootPart;
394  // Delete tree and alert clients (not silent)
395  m_scene.DeleteSceneObject(selectedTree.ParentGroup, false);
396  }
397  else
398  {
399  m_log.DebugFormat("[TREES]: Tree not in scene {0}", tree);
400  }
401  }
402  copseIdentity.m_trees = new List<UUID>();
403  m_copse.Remove(copseIdentity);
404  m_log.InfoFormat("[TREES]: Copse {0} has been removed", copsename);
405  }
406  else
407  {
408  m_log.InfoFormat("[TREES]: Copse {0} was not found - command failed", copsename);
409  }
410  }
411 
412  private void HandleTreeStatistics(Object[] args)
413  {
414  m_log.InfoFormat("[TREES]: Activity State: {0}; Update Rate: {1}", m_active_trees, m_update_ms);
415  foreach (Copse cp in m_copse)
416  {
417  m_log.InfoFormat("[TREES]: Copse {0}; {1} trees; frozen {2}", cp.m_name, cp.m_trees.Count, cp.m_frozen);
418  }
419  }
420 
421  private void InstallCommands()
422  {
423  Command treeActiveCommand =
424  new Command("active", CommandIntentions.COMMAND_HAZARDOUS, HandleTreeActive, "Change activity state for the trees module");
425  treeActiveCommand.AddArgument("activeTF", "The required activity state", "Boolean");
426 
427  Command treeFreezeCommand =
428  new Command("freeze", CommandIntentions.COMMAND_HAZARDOUS, HandleTreeFreeze, "Freeze/Unfreeze activity for a defined copse");
429  treeFreezeCommand.AddArgument("copse", "The required copse", "String");
430  treeFreezeCommand.AddArgument("freezeTF", "The required freeze state", "Boolean");
431 
432  Command treeLoadCommand =
433  new Command("load", CommandIntentions.COMMAND_HAZARDOUS, HandleTreeLoad, "Load a copse definition from an xml file");
434  treeLoadCommand.AddArgument("filename", "The (xml) file you wish to load", "String");
435 
436  Command treePlantCommand =
437  new Command("plant", CommandIntentions.COMMAND_HAZARDOUS, HandleTreePlant, "Start the planting on a copse");
438  treePlantCommand.AddArgument("copse", "The required copse", "String");
439 
440  Command treeRateCommand =
441  new Command("rate", CommandIntentions.COMMAND_HAZARDOUS, HandleTreeRate, "Reset the tree update rate (mSec)");
442  treeRateCommand.AddArgument("updateRate", "The required update rate (minimum 1000.0)", "Double");
443 
444  Command treeReloadCommand =
445  new Command("reload", CommandIntentions.COMMAND_HAZARDOUS, HandleTreeReload, "Reload copse definitions from the in-scene trees");
446 
447  Command treeRemoveCommand =
448  new Command("remove", CommandIntentions.COMMAND_HAZARDOUS, HandleTreeRemove, "Remove a copse definition and all its in-scene trees");
449  treeRemoveCommand.AddArgument("copse", "The required copse", "String");
450 
451  Command treeStatisticsCommand =
452  new Command("statistics", CommandIntentions.COMMAND_STATISTICAL, HandleTreeStatistics, "Log statistics about the trees");
453 
454  m_commander.RegisterCommand("active", treeActiveCommand);
455  m_commander.RegisterCommand("freeze", treeFreezeCommand);
456  m_commander.RegisterCommand("load", treeLoadCommand);
457  m_commander.RegisterCommand("plant", treePlantCommand);
458  m_commander.RegisterCommand("rate", treeRateCommand);
459  m_commander.RegisterCommand("reload", treeReloadCommand);
460  m_commander.RegisterCommand("remove", treeRemoveCommand);
461  m_commander.RegisterCommand("statistics", treeStatisticsCommand);
462  }
463 
468  private void EventManager_OnPluginConsole(string[] args)
469  {
470  if (args[0] == "tree")
471  {
472  if (args.Length == 1)
473  {
474  m_commander.ProcessConsoleCommand("help", new string[0]);
475  return;
476  }
477 
478  string[] tmpArgs = new string[args.Length - 2];
479  int i;
480  for (i = 2; i < args.Length; i++)
481  {
482  tmpArgs[i - 2] = args[i];
483  }
484 
485  m_commander.ProcessConsoleCommand(args[1], tmpArgs);
486  }
487  }
488  #endregion
489 
490  #region IVegetationModule Members
491 
493  UUID uuid, UUID groupID, Vector3 scale, Quaternion rotation, Vector3 position, Tree treeType, bool newTree)
494  {
495  PrimitiveBaseShape treeShape = new PrimitiveBaseShape();
496  treeShape.PathCurve = 16;
497  treeShape.PathEnd = 49900;
498  treeShape.PCode = newTree ? (byte)PCode.NewTree : (byte)PCode.Tree;
499  treeShape.Scale = scale;
500  treeShape.State = (byte)treeType;
501 
502  return m_scene.AddNewPrim(uuid, groupID, position, rotation, treeShape);
503  }
504 
505  #endregion
506 
507  #region IEntityCreator Members
508 
509  protected static readonly PCode[] creationCapabilities = new PCode[] { PCode.NewTree, PCode.Tree };
510  public PCode[] CreationCapabilities { get { return creationCapabilities; } }
511 
513  UUID ownerID, UUID groupID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
514  {
515  if (Array.IndexOf(creationCapabilities, (PCode)shape.PCode) < 0)
516  {
517  m_log.DebugFormat("[VEGETATION]: PCode {0} not handled by {1}", shape.PCode, Name);
518  return null;
519  }
520 
521  SceneObjectGroup sceneObject = new SceneObjectGroup(ownerID, pos, rot, shape);
522  SceneObjectPart rootPart = sceneObject.GetPart(sceneObject.UUID);
523 
524  rootPart.AddFlag(PrimFlags.Phantom);
525 
526  m_scene.AddNewSceneObject(sceneObject, true);
527  sceneObject.SetGroup(groupID, null);
528 
529  return sceneObject;
530  }
531 
532  #endregion
533 
534  //--------------------------------------------------------------
535 
536  #region Tree Utilities
537  static public void SerializeObject(string fileName, Object obj)
538  {
539  try
540  {
541  XmlSerializer xs = new XmlSerializer(typeof(Copse));
542 
543  using (XmlTextWriter writer = new XmlTextWriter(fileName, Util.UTF8))
544  {
545  writer.Formatting = Formatting.Indented;
546  xs.Serialize(writer, obj);
547  }
548  }
549  catch (SystemException ex)
550  {
551  throw new ApplicationException("Unexpected failure in Tree serialization", ex);
552  }
553  }
554 
555  static public object DeserializeObject(string fileName)
556  {
557  try
558  {
559  XmlSerializer xs = new XmlSerializer(typeof(Copse));
560 
561  using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read))
562  return xs.Deserialize(fs);
563  }
564  catch (SystemException ex)
565  {
566  throw new ApplicationException("Unexpected failure in Tree de-serialization", ex);
567  }
568  }
569 
570  private void ReloadCopse()
571  {
572  m_copse = new List<Copse>();
573 
574  EntityBase[] objs = m_scene.GetEntities();
575  foreach (EntityBase obj in objs)
576  {
577  if (obj is SceneObjectGroup)
578  {
579  SceneObjectGroup grp = (SceneObjectGroup)obj;
580 
581  if (grp.Name.Length > 5 && (grp.Name.Substring(0, 5) == "ATPM:" || grp.Name.Substring(0, 5) == "FTPM:"))
582  {
583  // Create a new copse definition or add uuid to an existing definition
584  try
585  {
586  Boolean copsefound = false;
587  Copse copse = new Copse(grp.Name);
588 
589  foreach (Copse cp in m_copse)
590  {
591  if (cp.m_name == copse.m_name)
592  {
593  copsefound = true;
594  cp.m_trees.Add(grp.UUID);
595  //m_log.DebugFormat("[TREES]: Found tree {0}", grp.UUID);
596  }
597  }
598 
599  if (!copsefound)
600  {
601  m_log.InfoFormat("[TREES]: Found copse {0}", grp.Name);
602  m_copse.Add(copse);
603  copse.m_trees.Add(grp.UUID);
604  }
605  }
606  catch
607  {
608  m_log.InfoFormat("[TREES]: Ill formed copse definition {0} - ignoring", grp.Name);
609  }
610  }
611  }
612  }
613  }
614  #endregion
615 
616  private void activeizeTreeze(bool activeYN)
617  {
618  if (activeYN)
619  {
620  CalculateTrees = new Timer(m_update_ms);
621  CalculateTrees.Elapsed += CalculateTrees_Elapsed;
622  CalculateTrees.Start();
623  }
624  else
625  {
626  CalculateTrees.Stop();
627  }
628  }
629 
630  private void growTrees()
631  {
632  foreach (Copse copse in m_copse)
633  {
634  if (!copse.m_frozen)
635  {
636  foreach (UUID tree in copse.m_trees)
637  {
638  if (m_scene.Entities.ContainsKey(tree))
639  {
640  SceneObjectPart s_tree = ((SceneObjectGroup)m_scene.Entities[tree]).RootPart;
641 
642  if (s_tree.Scale.X < copse.m_maximum_scale.X && s_tree.Scale.Y < copse.m_maximum_scale.Y && s_tree.Scale.Z < copse.m_maximum_scale.Z)
643  {
644  s_tree.Scale += copse.m_rate;
645  s_tree.ParentGroup.HasGroupChanged = true;
646  s_tree.ScheduleFullUpdate();
647  }
648  }
649  else
650  {
651  m_log.DebugFormat("[TREES]: Tree not in scene {0}", tree);
652  }
653  }
654  }
655  }
656  }
657 
658  private void seedTrees()
659  {
660  foreach (Copse copse in m_copse)
661  {
662  if (!copse.m_frozen)
663  {
664  foreach (UUID tree in copse.m_trees)
665  {
666  if (m_scene.Entities.ContainsKey(tree))
667  {
668  SceneObjectPart s_tree = ((SceneObjectGroup)m_scene.Entities[tree]).RootPart;
669 
670  if (copse.m_trees.Count < copse.m_tree_quantity)
671  {
672  // Tree has grown enough to seed if it has grown by at least 25% of seeded to full grown height
673  if (s_tree.Scale.Z > copse.m_initial_scale.Z + (copse.m_maximum_scale.Z - copse.m_initial_scale.Z) / 4.0)
674  {
675  if (Util.RandomClass.NextDouble() > 0.75)
676  {
677  SpawnChild(copse, s_tree);
678  }
679  }
680  }
681  }
682  else
683  {
684  m_log.DebugFormat("[TREES]: Tree not in scene {0}", tree);
685  }
686  }
687  }
688  }
689  }
690 
691  private void killTrees()
692  {
693  foreach (Copse copse in m_copse)
694  {
695  if (!copse.m_frozen && copse.m_trees.Count >= copse.m_tree_quantity)
696  {
697  foreach (UUID tree in copse.m_trees)
698  {
699  double killLikelyhood = 0.0;
700 
701  if (m_scene.Entities.ContainsKey(tree))
702  {
703  SceneObjectPart selectedTree = ((SceneObjectGroup)m_scene.Entities[tree]).RootPart;
704  double selectedTreeScale = Math.Sqrt(Math.Pow(selectedTree.Scale.X, 2) +
705  Math.Pow(selectedTree.Scale.Y, 2) +
706  Math.Pow(selectedTree.Scale.Z, 2));
707 
708  foreach (UUID picktree in copse.m_trees)
709  {
710  if (picktree != tree)
711  {
712  SceneObjectPart pickedTree = ((SceneObjectGroup)m_scene.Entities[picktree]).RootPart;
713 
714  double pickedTreeScale = Math.Sqrt(Math.Pow(pickedTree.Scale.X, 2) +
715  Math.Pow(pickedTree.Scale.Y, 2) +
716  Math.Pow(pickedTree.Scale.Z, 2));
717 
718  double pickedTreeDistance = Vector3.Distance(pickedTree.AbsolutePosition, selectedTree.AbsolutePosition);
719 
720  killLikelyhood += (selectedTreeScale / (pickedTreeScale * pickedTreeDistance)) * 0.1;
721  }
722  }
723 
724  if (Util.RandomClass.NextDouble() < killLikelyhood)
725  {
726  // Delete tree and alert clients (not silent)
727  m_scene.DeleteSceneObject(selectedTree.ParentGroup, false);
728  copse.m_trees.Remove(selectedTree.ParentGroup.UUID);
729  break;
730  }
731  }
732  else
733  {
734  m_log.DebugFormat("[TREES]: Tree not in scene {0}", tree);
735  }
736  }
737  }
738  }
739  }
740 
741  private void SpawnChild(Copse copse, SceneObjectPart s_tree)
742  {
743  Vector3 position = new Vector3();
744 
745  double randX = ((Util.RandomClass.NextDouble() * 2.0) - 1.0) * (s_tree.Scale.X * 3);
746  double randY = ((Util.RandomClass.NextDouble() * 2.0) - 1.0) * (s_tree.Scale.X * 3);
747 
748  position.X = s_tree.AbsolutePosition.X + (float)randX;
749  position.Y = s_tree.AbsolutePosition.Y + (float)randY;
750 
751  if (position.X <= (m_scene.RegionInfo.RegionSizeX - 1) && position.X >= 0 &&
752  position.Y <= (m_scene.RegionInfo.RegionSizeY - 1) && position.Y >= 0 &&
753  Util.GetDistanceTo(position, copse.m_seed_point) <= copse.m_range)
754  {
755  UUID uuid = m_scene.RegionInfo.EstateSettings.EstateOwner;
756 
757  CreateTree(uuid, copse, position);
758  }
759  }
760 
761  private void CreateTree(UUID uuid, Copse copse, Vector3 position)
762  {
763 
764  position.Z = (float)m_scene.Heightmap[(int)position.X, (int)position.Y];
765  if (position.Z >= copse.m_treeline_low && position.Z <= copse.m_treeline_high)
766  {
767  SceneObjectGroup tree = AddTree(uuid, UUID.Zero, copse.m_initial_scale, Quaternion.Identity, position, copse.m_tree_type, false);
768 
769  tree.Name = copse.ToString();
770  copse.m_trees.Add(tree.UUID);
771  tree.SendGroupFullUpdate();
772  }
773  }
774 
775  private void CalculateTrees_Elapsed(object sender, ElapsedEventArgs e)
776  {
777  growTrees();
778  seedTrees();
779  killTrees();
780  }
781  }
782 }
783 
Copse(string name, int quantity, float high, float low, double range, Vector3 point, Tree type, Vector3 scale, Vector3 max_scale, Vector3 rate, List< UUID > trees)
A scene object group is conceptually an object in the scene. The object is constituted of SceneObject...
void Initialise(IConfigSource config)
This is called to initialize the region module. For shared modules, this is called exactly once...
SceneObjectGroup AddTree(UUID uuid, UUID groupID, Vector3 scale, Quaternion rotation, Vector3 position, Tree treeType, bool newTree)
Add a new tree to the scene. Used by other modules.
void AddRegion(Scene scene)
This is called whenever a Scene is added. For shared modules, this can happen several times...
A single function call encapsulated in a class which enforces arguments when passing around as Object...
Definition: Command.cs:39
System.Timers.Timer Timer
void Close()
This is the inverse to Initialise. After a Close(), this instance won't be usable anymore...
Vector3 Scale
Change the scale of this part.
SceneObjectGroup CreateEntity(UUID ownerID, UUID groupID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
Create an entity
OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion rotation
Definition: ICM_Api.cs:32
A class to enable modules to register console and script commands, which enforces typing and valid in...
Definition: Commander.cs:41
void RegionLoaded(Scene scene)
This will be called once for every scene loaded. In a shared module this will be multiple times in on...
Interactive OpenSim region server
Definition: OpenSim.cs:55
void RemoveRegion(Scene scene)
This is called whenever a Scene is removed. For shared modules, this can happen several times...
override string Name
The name of an object grouping is always the same as its root part