aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/OptionalModules/World/TreePopulator
diff options
context:
space:
mode:
authorCharles Krinke2009-06-14 16:32:50 +0000
committerCharles Krinke2009-06-14 16:32:50 +0000
commit8d24168befd3bcecbdd19cdea091233eb113dfc7 (patch)
tree9027511fbca390c0b89947abff9b87f65e05ce5d /OpenSim/Region/OptionalModules/World/TreePopulator
parentBug fix in remote neighbour connector. (diff)
downloadopensim-SC_OLD-8d24168befd3bcecbdd19cdea091233eb113dfc7.zip
opensim-SC_OLD-8d24168befd3bcecbdd19cdea091233eb113dfc7.tar.gz
opensim-SC_OLD-8d24168befd3bcecbdd19cdea091233eb113dfc7.tar.bz2
opensim-SC_OLD-8d24168befd3bcecbdd19cdea091233eb113dfc7.tar.xz
Thank you kindly, M1sha, for a patch that improves the treePopulator module:
(a) Implements the ICommandableModule interface to clean up the user interface (b) Uses a specification for a 'copse' (collected group of trees) which permits via an xml file: Tree type; Tree Line (high and low), Seed point; Radius of Copse; Number of required trees; Initial size of seeded tree; maximum size of seeded tree; growth rate; freeze growth state (c) Multiple Copse may be defined for a region (d) Growth on individual copse may be frozen or restarted, or all growth disabled/enabled (e) Copse definitions are persistant, they are reloaded from the trees present on a region restart (f) All trees in a copse may be removed and the copse definition deleted in one command
Diffstat (limited to 'OpenSim/Region/OptionalModules/World/TreePopulator')
-rw-r--r--OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs749
1 files changed, 612 insertions, 137 deletions
diff --git a/OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs b/OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs
index c7d5027..3e9c326 100644
--- a/OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs
+++ b/OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs
@@ -33,57 +33,182 @@ using OpenMetaverse;
33using log4net; 33using log4net;
34using Nini.Config; 34using Nini.Config;
35using OpenSim.Framework; 35using OpenSim.Framework;
36using OpenSim.Region.CoreModules.Framework.InterfaceCommander;
36using OpenSim.Region.Framework.Interfaces; 37using OpenSim.Region.Framework.Interfaces;
37using OpenSim.Region.Framework.Scenes; 38using OpenSim.Region.Framework.Scenes;
38 39
40using System.Xml;
41using System.Xml.Serialization;
42using System.IO;
43
39namespace OpenSim.Region.OptionalModules.World.TreePopulator 44namespace OpenSim.Region.OptionalModules.World.TreePopulator
40{ 45{
41 /// <summary> 46 /// <summary>
42 /// Version 2.01 - Very hacky compared to the original. Will fix original and release as 0.3 later. 47 /// Version 2.02 - Still hacky
43 /// </summary> 48 /// </summary>
44 public class TreePopulatorModule : IRegionModule 49 public class TreePopulatorModule : IRegionModule, ICommandableModule, IVegetationModule
45 { 50 {
46 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 51 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
52 private readonly Commander m_commander = new Commander("tree");
47 private Scene m_scene; 53 private Scene m_scene;
48 54
49 public double m_tree_density = 50.0; // Aim for this many per region 55 [XmlRootAttribute(ElementName = "Copse", IsNullable = false)]
50 public double m_tree_updates = 1000.0; // MS between updates 56 public class Copse
57 {
58 public string m_name;
59 public Boolean m_frozen;
60 public Tree m_tree_type;
61 public int m_tree_quantity;
62 public float m_treeline_low;
63 public float m_treeline_high;
64 public Vector3 m_seed_point;
65 public double m_range;
66 public Vector3 m_initial_scale;
67 public Vector3 m_maximum_scale;
68 public Vector3 m_rate;
69
70 [XmlIgnore]
71 public Boolean m_planted;
72 [XmlIgnore]
73 public List<UUID> m_trees;
74
75 public Copse()
76 {
77 }
78
79 public Copse(string fileName, Boolean planted)
80 {
81 Copse cp = (Copse)DeserializeObject(fileName);
82
83 this.m_name = cp.m_name;
84 this.m_frozen = cp.m_frozen;
85 this.m_tree_quantity = cp.m_tree_quantity;
86 this.m_treeline_high = cp.m_treeline_high;
87 this.m_treeline_low = cp.m_treeline_low;
88 this.m_range = cp.m_range;
89 this.m_tree_type = cp.m_tree_type;
90 this.m_seed_point = cp.m_seed_point;
91 this.m_initial_scale = cp.m_initial_scale;
92 this.m_maximum_scale = cp.m_maximum_scale;
93 this.m_initial_scale = cp.m_initial_scale;
94 this.m_rate = cp.m_rate;
95 this.m_planted = planted;
96 this.m_trees = new List<UUID>();
97 }
98
99 public Copse(string copsedef)
100 {
101 char[] delimiterChars = {':', ';'};
102 string[] field = copsedef.Split(delimiterChars);
103
104 this.m_name = field[1].Trim();
105 this.m_frozen = (copsedef[0] == 'F');
106 this.m_tree_quantity = int.Parse(field[2]);
107 this.m_treeline_high = float.Parse(field[3]);
108 this.m_treeline_low = float.Parse(field[4]);
109 this.m_range = double.Parse(field[5]);
110 this.m_tree_type = (Tree) Enum.Parse(typeof(Tree),field[6]);
111 this.m_seed_point = Vector3.Parse(field[7]);
112 this.m_initial_scale = Vector3.Parse(field[8]);
113 this.m_maximum_scale = Vector3.Parse(field[9]);
114 this.m_rate = Vector3.Parse(field[10]);
115 this.m_planted = true;
116 this.m_trees = new List<UUID>();
117 }
118
119 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)
120 {
121 this.m_name = name;
122 this.m_frozen = false;
123 this.m_tree_quantity = quantity;
124 this.m_treeline_high = high;
125 this.m_treeline_low = low;
126 this.m_range = range;
127 this.m_tree_type = type;
128 this.m_seed_point = point;
129 this.m_initial_scale = scale;
130 this.m_maximum_scale = max_scale;
131 this.m_rate = rate;
132 this.m_planted = false;
133 this.m_trees = trees;
134 }
135
136 public override string ToString()
137 {
138 string frozen = (this.m_frozen ? "F" : "A");
139
140 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};",
141 frozen,
142 this.m_name,
143 this.m_tree_quantity,
144 this.m_treeline_high,
145 this.m_treeline_low,
146 this.m_range,
147 this.m_tree_type,
148 this.m_seed_point.ToString(),
149 this.m_initial_scale.ToString(),
150 this.m_maximum_scale.ToString(),
151 this.m_rate.ToString());
152 }
153 }
154
155 private List<Copse> m_copse;
156
157 private double m_update_ms = 1000.0; // msec between updates
51 private bool m_active_trees = false; 158 private bool m_active_trees = false;
52 private List<UUID> m_trees; 159
53 Timer CalculateTrees; 160 Timer CalculateTrees;
54 161
162 #region ICommandableModule Members
163
164 public ICommander CommandInterface
165 {
166 get { return m_commander; }
167 }
168
169 #endregion
170
55 #region IRegionModule Members 171 #region IRegionModule Members
56 172
57 public void Initialise(Scene scene, IConfigSource config) 173 public void Initialise(Scene scene, IConfigSource config)
58 { 174 {
175
59 m_scene = scene; 176 m_scene = scene;
60 m_scene.RegisterModuleInterface<IRegionModule>(this); 177 m_scene.RegisterModuleInterface<IRegionModule>(this);
178 m_scene.EventManager.OnPluginConsole += EventManager_OnPluginConsole;
61 179
62 m_scene.AddCommand( 180 // ini file settings
63 this, "tree plant", "tree plant", "Start populating trees", HandleTreeConsoleCommand);
64
65 m_scene.AddCommand(
66 this, "tree active", "tree active <boolean>", "Change activity state for trees module", HandleTreeConsoleCommand);
67
68 try 181 try
69 { 182 {
70 m_tree_density = config.Configs["Trees"].GetDouble("tree_density", m_tree_density);
71 m_active_trees = config.Configs["Trees"].GetBoolean("active_trees", m_active_trees); 183 m_active_trees = config.Configs["Trees"].GetBoolean("active_trees", m_active_trees);
72 } 184 }
73 catch (Exception) 185 catch (Exception)
74 { 186 {
187 m_log.Debug("[TREES]: ini failure for active_trees - using default");
75 } 188 }
76 189
77 m_trees = new List<UUID>(); 190 try
191 {
192 m_update_ms = config.Configs["Trees"].GetDouble("update_rate", m_update_ms);
193 }
194 catch (Exception)
195 {
196 m_log.Debug("[TREES]: ini failure for update_rate - using default");
197 }
78 198
79 if (m_active_trees) 199 InstallCommands();
80 activeizeTreeze(true);
81 200
82 m_log.Debug("[TREES]: Initialised tree module"); 201 m_log.Debug("[TREES]: Initialised tree module");
83 } 202 }
84 203
85 public void PostInitialise() 204 public void PostInitialise()
86 { 205 {
206 ReloadCopse();
207 if (m_copse.Count > 0)
208 m_log.Info("[TREES]: Copse load complete");
209
210 if (m_active_trees)
211 activeizeTreeze(true);
87 } 212 }
88 213
89 public void Close() 214 public void Close()
@@ -102,61 +227,397 @@ namespace OpenSim.Region.OptionalModules.World.TreePopulator
102 227
103 #endregion 228 #endregion
104 229
105 /// <summary> 230 //--------------------------------------------------------------
106 /// Handle a tree command from the console. 231
107 /// </summary> 232 #region ICommandableModule Members
108 /// <param name="module"></param> 233
109 /// <param name="cmdparams"></param> 234 private void HandleTreeActive(Object[] args)
110 public void HandleTreeConsoleCommand(string module, string[] cmdparams)
111 { 235 {
112 if (m_scene.ConsoleScene() != null && m_scene.ConsoleScene() != m_scene) 236 if ((Boolean)args[0] && !m_active_trees)
113 return; 237 {
238 m_log.InfoFormat("[TREES]: Activating Trees");
239 m_active_trees = true;
240 activeizeTreeze(m_active_trees);
241 }
242 else if (!(Boolean)args[0] && m_active_trees)
243 {
244 m_log.InfoFormat("[TREES]: Trees module is no longer active");
245 m_active_trees = false;
246 activeizeTreeze(m_active_trees);
247 }
248 else
249 {
250 m_log.InfoFormat("[TREES]: Trees module is already in the required state");
251 }
252 }
114 253
115 if (cmdparams[1] == "active") 254 private void HandleTreeFreeze(Object[] args)
255 {
256 string copsename = ((string)args[0]).Trim();
257 Boolean freezeState = (Boolean) args[1];
258
259 foreach (Copse cp in m_copse)
116 { 260 {
117 if (cmdparams.Length <= 2) 261 if (cp.m_name == copsename && (!cp.m_frozen && freezeState || cp.m_frozen && !freezeState))
118 { 262 {
119 if (m_active_trees) 263 cp.m_frozen = freezeState;
120 m_log.InfoFormat("[TREES]: Trees are currently active"); 264 foreach (UUID tree in cp.m_trees)
121 else 265 {
122 m_log.InfoFormat("[TREES]: Trees are currently not active"); 266 SceneObjectPart sop = ((SceneObjectGroup)m_scene.Entities[tree]).RootPart;
267 sop.Name = (freezeState ? sop.Name.Replace("ATPM", "FTPM") : sop.Name.Replace("FTPM", "ATPM"));
268 sop.ParentGroup.HasGroupChanged = true;
269 }
270
271 m_log.InfoFormat("[TREES]: Activity for copse {0} is frozen {1}", copsename, freezeState);
272 return;
123 } 273 }
124 else if (cmdparams[2] == "true" && !m_active_trees) 274 else if (cp.m_name == copsename && (cp.m_frozen && freezeState || !cp.m_frozen && !freezeState))
125 { 275 {
126 m_log.InfoFormat("[TREES]: Activating Trees"); 276 m_log.InfoFormat("[TREES]: Copse {0} is already in the requested freeze state", copsename);
127 m_active_trees = true; 277 return;
128 activeizeTreeze(m_active_trees);
129 } 278 }
130 else if (cmdparams[2] == "false" && m_active_trees) 279 }
280 m_log.InfoFormat("[TREES]: Copse {0} was not found - command failed", copsename);
281 }
282
283 private void HandleTreeLoad(Object[] args)
284 {
285 Copse copse;
286
287 m_log.InfoFormat("[TREES]: Loading copse definition....");
288
289 copse = new Copse(((string)args[0]), false);
290 foreach (Copse cp in m_copse)
291 {
292 if (cp.m_name == copse.m_name)
131 { 293 {
132 m_log.InfoFormat("[TREES]: Trees no longer active, for now..."); 294 m_log.InfoFormat("[TREES]: Copse: {0} is already defined - command failed", copse.m_name);
133 m_active_trees = false; 295 return;
134 activeizeTreeze(m_active_trees);
135 } 296 }
136 else 297 }
298
299 m_copse.Add(copse);
300 m_log.InfoFormat("[TREES]: Loaded copse: {0}", copse.ToString());
301 }
302
303 private void HandleTreePlant(Object[] args)
304 {
305 string copsename = ((string)args[0]).Trim();
306
307 m_log.InfoFormat("[TREES]: New tree planting for copse {0}", copsename);
308 UUID uuid = m_scene.RegionInfo.EstateSettings.EstateOwner;
309 if (uuid == UUID.Zero)
310 uuid = m_scene.RegionInfo.MasterAvatarAssignedUUID;
311
312 foreach (Copse copse in m_copse)
313 {
314 if (copse.m_name == copsename)
137 { 315 {
138 m_log.InfoFormat("[TREES]: When setting the tree module active via the console, you must specify true or false"); 316 if (!copse.m_planted)
317 {
318 // The first tree for a copse is created here
319 CreateTree(uuid, copse, copse.m_seed_point);
320 copse.m_planted = true;
321 return;
322 }
323 else
324 {
325 m_log.InfoFormat("[TREES]: Copse {0} has already been planted", copsename);
326 }
139 } 327 }
140 } 328 }
141 else if (cmdparams[1] == "plant") 329 m_log.InfoFormat("[TREES]: Copse {0} not found for planting", copsename);
330 }
331
332 private void HandleTreeRate(Object[] args)
333 {
334 m_update_ms = (double)args[0];
335 if (m_update_ms >= 1000.0)
142 { 336 {
143 m_log.InfoFormat("[TREES]: New tree planting"); 337 if (m_active_trees)
144 UUID uuid = m_scene.RegionInfo.EstateSettings.EstateOwner; 338 {
145 if (uuid == UUID.Zero) 339 activeizeTreeze(false);
146 uuid = m_scene.RegionInfo.MasterAvatarAssignedUUID; 340 activeizeTreeze(true);
147 CreateTree(uuid, new Vector3(128.0f, 128.0f, 0.0f)); 341 }
342 m_log.InfoFormat("[TREES]: Update rate set to {0} mSec", m_update_ms);
148 } 343 }
149 else 344 else
150 { 345 {
151 m_log.InfoFormat("[TREES]: Unknown command"); 346 m_log.InfoFormat("[TREES]: minimum rate is 1000.0 mSec - command failed");
152 } 347 }
153 } 348 }
154 349
350 private void HandleTreeReload(Object[] args)
351 {
352 if (m_active_trees)
353 {
354 CalculateTrees.Stop();
355 }
356
357 ReloadCopse();
358
359 if (m_active_trees)
360 {
361 CalculateTrees.Start();
362 }
363 }
364
365 private void HandleTreeRemove(Object[] args)
366 {
367 string copsename = ((string)args[0]).Trim();
368 Copse copseIdentity = null;
369
370 foreach (Copse cp in m_copse)
371 {
372 if (cp.m_name == copsename)
373 {
374 copseIdentity = cp;
375 }
376 }
377
378 if (copseIdentity != null)
379 {
380 foreach (UUID tree in copseIdentity.m_trees)
381 {
382 if (m_scene.Entities.ContainsKey(tree))
383 {
384 SceneObjectPart selectedTree = ((SceneObjectGroup)m_scene.Entities[tree]).RootPart;
385
386
387 m_scene.DeleteSceneObject(selectedTree.ParentGroup, false);
388 m_scene.ForEachClient(delegate(IClientAPI controller)
389 {
390 controller.SendKillObject(m_scene.RegionInfo.RegionHandle,
391 selectedTree.LocalId);
392 });
393 }
394 else
395 {
396 m_log.DebugFormat("[TREES]: Tree not in scene {0}", tree);
397 }
398 }
399 copseIdentity.m_trees = new List<UUID>();
400 m_copse.Remove(copseIdentity);
401 m_log.InfoFormat("[TREES]: Copse {0} has been removed", copsename);
402 }
403 else
404 {
405 m_log.InfoFormat("[TREES]: Copse {0} was not found - command failed", copsename);
406 }
407 }
408
409 private void HandleTreeStatistics(Object[] args)
410 {
411 m_log.InfoFormat("[TREES]: Activity State: {0}; Update Rate: {1}", m_active_trees, m_update_ms);
412 foreach (Copse cp in m_copse)
413 {
414 m_log.InfoFormat("[TREES]: Copse {0}; {1} trees; frozen {2}", cp.m_name, cp.m_trees.Count, cp.m_frozen);
415 }
416 }
417
418 private void InstallCommands()
419 {
420 Command treeActiveCommand =
421 new Command("active", CommandIntentions.COMMAND_HAZARDOUS, HandleTreeActive, "Change activity state for the trees module");
422 treeActiveCommand.AddArgument("activeTF", "The required activity state", "Boolean");
423
424 Command treeFreezeCommand =
425 new Command("freeze", CommandIntentions.COMMAND_HAZARDOUS, HandleTreeFreeze, "Freeze/Unfreeze activity for a defined copse");
426 treeFreezeCommand.AddArgument("copse", "The required copse", "String");
427 treeFreezeCommand.AddArgument("freezeTF", "The required freeze state", "Boolean");
428
429 Command treeLoadCommand =
430 new Command("load", CommandIntentions.COMMAND_HAZARDOUS, HandleTreeLoad, "Load a copse definition from an xml file");
431 treeLoadCommand.AddArgument("filename", "The (xml) file you wish to load", "String");
432
433 Command treePlantCommand =
434 new Command("plant", CommandIntentions.COMMAND_HAZARDOUS, HandleTreePlant, "Start the planting on a copse");
435 treePlantCommand.AddArgument("copse", "The required copse", "String");
436
437 Command treeRateCommand =
438 new Command("rate", CommandIntentions.COMMAND_HAZARDOUS, HandleTreeRate, "Reset the tree update rate (mSec)");
439 treeRateCommand.AddArgument("updateRate", "The required update rate (minimum 1000.0)", "Double");
440
441 Command treeReloadCommand =
442 new Command("reload", CommandIntentions.COMMAND_HAZARDOUS, HandleTreeReload, "Reload copse definitions from the in-scene trees");
443
444 Command treeRemoveCommand =
445 new Command("remove", CommandIntentions.COMMAND_HAZARDOUS, HandleTreeRemove, "Remove a copse definition and all its in-scene trees");
446 treeRemoveCommand.AddArgument("copse", "The required copse", "String");
447
448 Command treeStatisticsCommand =
449 new Command("statistics", CommandIntentions.COMMAND_STATISTICAL, HandleTreeStatistics, "Log statistics about the trees");
450
451 m_commander.RegisterCommand("active", treeActiveCommand);
452 m_commander.RegisterCommand("freeze", treeFreezeCommand);
453 m_commander.RegisterCommand("load", treeLoadCommand);
454 m_commander.RegisterCommand("plant", treePlantCommand);
455 m_commander.RegisterCommand("rate", treeRateCommand);
456 m_commander.RegisterCommand("reload", treeReloadCommand);
457 m_commander.RegisterCommand("remove", treeRemoveCommand);
458 m_commander.RegisterCommand("statistics", treeStatisticsCommand);
459
460 m_scene.RegisterModuleCommander(m_commander);
461 }
462
463 /// <summary>
464 /// Processes commandline input. Do not call directly.
465 /// </summary>
466 /// <param name="args">Commandline arguments</param>
467 private void EventManager_OnPluginConsole(string[] args)
468 {
469 if (args[0] == "tree")
470 {
471 if (args.Length == 1)
472 {
473 m_commander.ProcessConsoleCommand("help", new string[0]);
474 return;
475 }
476
477 string[] tmpArgs = new string[args.Length - 2];
478 int i;
479 for (i = 2; i < args.Length; i++)
480 {
481 tmpArgs[i - 2] = args[i];
482 }
483
484 m_commander.ProcessConsoleCommand(args[1], tmpArgs);
485 }
486 }
487 #endregion
488
489 #region IVegetationModule Members
490
491 public SceneObjectGroup AddTree(
492 UUID uuid, UUID groupID, Vector3 scale, Quaternion rotation, Vector3 position, Tree treeType, bool newTree)
493 {
494 PrimitiveBaseShape treeShape = new PrimitiveBaseShape();
495 treeShape.PathCurve = 16;
496 treeShape.PathEnd = 49900;
497 treeShape.PCode = newTree ? (byte)PCode.NewTree : (byte)PCode.Tree;
498 treeShape.Scale = scale;
499 treeShape.State = (byte)treeType;
500
501 return m_scene.AddNewPrim(uuid, groupID, position, rotation, treeShape);
502 }
503
504 #endregion
505
506 #region IEntityCreator Members
507
508 protected static readonly PCode[] creationCapabilities = new PCode[] { PCode.NewTree, PCode.Tree };
509 public PCode[] CreationCapabilities { get { return creationCapabilities; } }
510
511 public SceneObjectGroup CreateEntity(
512 UUID ownerID, UUID groupID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
513 {
514 if (Array.IndexOf(creationCapabilities, (PCode)shape.PCode) < 0)
515 {
516 m_log.DebugFormat("[VEGETATION]: PCode {0} not handled by {1}", shape.PCode, Name);
517 return null;
518 }
519
520 SceneObjectGroup sceneObject = new SceneObjectGroup(ownerID, pos, rot, shape);
521 SceneObjectPart rootPart = sceneObject.GetChildPart(sceneObject.UUID);
522
523 rootPart.AddFlag(PrimFlags.Phantom);
524
525 m_scene.AddNewSceneObject(sceneObject, true);
526 sceneObject.SetGroup(groupID, null);
527
528 return sceneObject;
529 }
530
531 #endregion
532
533 //--------------------------------------------------------------
534
535 #region Tree Utilities
536 static public void SerializeObject(string fileName, Object obj)
537 {
538 try
539 {
540 XmlSerializer xs = new XmlSerializer(typeof(Copse));
541
542 using (XmlTextWriter writer = new XmlTextWriter(fileName, System.Text.Encoding.UTF8))
543 {
544 writer.Formatting = Formatting.Indented;
545 xs.Serialize(writer, obj);
546 }
547 }
548 catch (SystemException ex)
549 {
550 throw new ApplicationException("Unexpected failure in Tree serialization", ex);
551 }
552 }
553
554 static public object DeserializeObject(string fileName)
555 {
556 try
557 {
558 XmlSerializer xs = new XmlSerializer(typeof(Copse));
559
560 using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read))
561 return xs.Deserialize(fs);
562 }
563 catch (SystemException ex)
564 {
565 throw new ApplicationException("Unexpected failure in Tree de-serialization", ex);
566 }
567 }
568
569 private void ReloadCopse()
570 {
571 m_copse = new List<Copse>();
572
573 List<EntityBase> objs = m_scene.GetEntities();
574
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
155 private void activeizeTreeze(bool activeYN) 616 private void activeizeTreeze(bool activeYN)
156 { 617 {
157 if (activeYN) 618 if (activeYN)
158 { 619 {
159 CalculateTrees = new Timer(m_tree_updates); 620 CalculateTrees = new Timer(m_update_ms);
160 CalculateTrees.Elapsed += CalculateTrees_Elapsed; 621 CalculateTrees.Elapsed += CalculateTrees_Elapsed;
161 CalculateTrees.Start(); 622 CalculateTrees.Start();
162 } 623 }
@@ -168,143 +629,156 @@ namespace OpenSim.Region.OptionalModules.World.TreePopulator
168 629
169 private void growTrees() 630 private void growTrees()
170 { 631 {
171 foreach (UUID tree in m_trees) 632 foreach (Copse copse in m_copse)
172 { 633 {
173 if (m_scene.Entities.ContainsKey(tree)) 634 if (!copse.m_frozen)
174 {
175 SceneObjectPart s_tree = ((SceneObjectGroup) m_scene.Entities[tree]).RootPart;
176
177 // 100 seconds to grow 1m
178 s_tree.Scale += new Vector3(0.1f, 0.1f, 0.1f);
179 s_tree.SendFullUpdateToAllClients();
180 //s_tree.ScheduleTerseUpdate();
181 }
182 else
183 { 635 {
184 m_trees.Remove(tree); 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 }
185 } 654 }
186 } 655 }
187 } 656 }
188 657
189 private void seedTrees() 658 private void seedTrees()
190 { 659 {
191 foreach (UUID tree in m_trees) 660 foreach (Copse copse in m_copse)
192 { 661 {
193 if (m_scene.Entities.ContainsKey(tree)) 662 if (!copse.m_frozen)
194 { 663 {
195 SceneObjectPart s_tree = ((SceneObjectGroup) m_scene.Entities[tree]).RootPart; 664 foreach (UUID tree in copse.m_trees)
196
197 if (s_tree.Scale.X > 0.5)
198 { 665 {
199 if (Util.RandomClass.NextDouble() > 0.75) 666 if (m_scene.Entities.ContainsKey(tree))
200 { 667 {
201 SpawnChild(s_tree); 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);
202 } 685 }
203 } 686 }
204 } 687 }
205 else
206 {
207 m_trees.Remove(tree);
208 }
209 } 688 }
210 } 689 }
211 690
212 private void killTrees() 691 private void killTrees()
213 { 692 {
214 foreach (UUID tree in m_trees) 693 foreach (Copse copse in m_copse)
215 { 694 {
216 double killLikelyhood = 0.0; 695 if (!copse.m_frozen && copse.m_trees.Count >= copse.m_tree_quantity)
217
218 if (m_scene.Entities.ContainsKey(tree))
219 { 696 {
220 SceneObjectPart selectedTree = ((SceneObjectGroup) m_scene.Entities[tree]).RootPart; 697 foreach (UUID tree in copse.m_trees)
221 double selectedTreeScale = Math.Sqrt(Math.Pow(selectedTree.Scale.X, 2) +
222 Math.Pow(selectedTree.Scale.Y, 2) +
223 Math.Pow(selectedTree.Scale.Z, 2));
224
225 foreach (UUID picktree in m_trees)
226 { 698 {
227 if (picktree != tree) 699 double killLikelyhood = 0.0;
700
701 if (m_scene.Entities.ContainsKey(tree))
228 { 702 {
229 SceneObjectPart pickedTree = ((SceneObjectGroup) m_scene.Entities[picktree]).RootPart; 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));
230 707
231 double pickedTreeScale = Math.Sqrt(Math.Pow(pickedTree.Scale.X, 2) + 708 foreach (UUID picktree in copse.m_trees)
232 Math.Pow(pickedTree.Scale.Y, 2) + 709 {
233 Math.Pow(pickedTree.Scale.Z, 2)); 710 if (picktree != tree)
711 {
712 SceneObjectPart pickedTree = ((SceneObjectGroup)m_scene.Entities[picktree]).RootPart;
234 713
235 double pickedTreeDistance = Math.Sqrt(Math.Pow(Math.Abs(pickedTree.AbsolutePosition.X - selectedTree.AbsolutePosition.X), 2) + 714 double pickedTreeScale = Math.Sqrt(Math.Pow(pickedTree.Scale.X, 2) +
236 Math.Pow(Math.Abs(pickedTree.AbsolutePosition.Y - selectedTree.AbsolutePosition.Y), 2) + 715 Math.Pow(pickedTree.Scale.Y, 2) +
237 Math.Pow(Math.Abs(pickedTree.AbsolutePosition.Z - selectedTree.AbsolutePosition.Z), 2)); 716 Math.Pow(pickedTree.Scale.Z, 2));
238 717
239 killLikelyhood += (selectedTreeScale / (pickedTreeScale * pickedTreeDistance)) * 0.1; 718 double pickedTreeDistance = Vector3.Distance(pickedTree.AbsolutePosition, selectedTree.AbsolutePosition);
240 }
241 }
242 719
243 if (Util.RandomClass.NextDouble() < killLikelyhood) 720 killLikelyhood += (selectedTreeScale / (pickedTreeScale * pickedTreeDistance)) * 0.1;
244 { 721 }
245 m_scene.DeleteSceneObject(selectedTree.ParentGroup, false); 722 }
246 m_trees.Remove(selectedTree.ParentGroup.UUID);
247 723
248 m_scene.ForEachClient(delegate(IClientAPI controller) 724 if (Util.RandomClass.NextDouble() < killLikelyhood)
249 { 725 {
250 controller.SendKillObject(m_scene.RegionInfo.RegionHandle,
251 selectedTree.LocalId);
252 });
253 726
254 break; 727 m_scene.DeleteSceneObject(selectedTree.ParentGroup, false);
728 copse.m_trees.Remove(selectedTree.ParentGroup.UUID);
729
730 m_scene.ForEachClient(delegate(IClientAPI controller)
731 {
732 controller.SendKillObject(m_scene.RegionInfo.RegionHandle,
733 selectedTree.LocalId);
734 });
735
736 break;
737 }
738 }
739 else
740 {
741 m_log.DebugFormat("[TREES]: Tree not in scene {0}", tree);
742 }
255 } 743 }
256 selectedTree.SetText(killLikelyhood.ToString(), new Vector3(1.0f, 1.0f, 1.0f), 1.0);
257 }
258 else
259 {
260 m_trees.Remove(tree);
261 } 744 }
262 } 745 }
263 } 746 }
264 747
265 private void SpawnChild(SceneObjectPart s_tree) 748 private void SpawnChild(Copse copse, SceneObjectPart s_tree)
266 { 749 {
267 Vector3 position = new Vector3(); 750 Vector3 position = new Vector3();
268 751
269 position.X = s_tree.AbsolutePosition.X + (1 * (-1 * Util.RandomClass.Next(1)));
270 if (position.X > 255)
271 position.X = 255;
272 if (position.X < 0)
273 position.X = 0;
274 position.Y = s_tree.AbsolutePosition.Y + (1 * (-1 * Util.RandomClass.Next(1)));
275 if (position.Y > 255)
276 position.Y = 255;
277 if (position.Y < 0)
278 position.Y = 0;
279
280 double randX = ((Util.RandomClass.NextDouble() * 2.0) - 1.0) * (s_tree.Scale.X * 3); 752 double randX = ((Util.RandomClass.NextDouble() * 2.0) - 1.0) * (s_tree.Scale.X * 3);
281 double randY = ((Util.RandomClass.NextDouble() * 2.0) - 1.0) * (s_tree.Scale.X * 3); 753 double randY = ((Util.RandomClass.NextDouble() * 2.0) - 1.0) * (s_tree.Scale.X * 3);
282 754
283 position.X += (float) randX; 755 position.X = s_tree.AbsolutePosition.X + (float)randX;
284 position.Y += (float) randY; 756 position.Y = s_tree.AbsolutePosition.Y + (float)randY;
285 757
286 UUID uuid = m_scene.RegionInfo.EstateSettings.EstateOwner; 758 if (position.X <= 255 && position.X >= 0 &&
287 if (uuid == UUID.Zero) 759 position.Y <= 255 && position.Y >= 0 &&
288 uuid = m_scene.RegionInfo.MasterAvatarAssignedUUID; 760 Util.GetDistanceTo(position, copse.m_seed_point) <= copse.m_range)
761 {
762 UUID uuid = m_scene.RegionInfo.EstateSettings.EstateOwner;
763 if (uuid == UUID.Zero)
764 uuid = m_scene.RegionInfo.MasterAvatarAssignedUUID;
289 765
290 CreateTree(uuid, position); 766 CreateTree(uuid, copse, position);
767 }
291 } 768 }
292 769
293 private void CreateTree(UUID uuid, Vector3 position) 770 private void CreateTree(UUID uuid, Copse copse, Vector3 position)
294 { 771 {
295 position.Z = (float) m_scene.Heightmap[(int) position.X, (int) position.Y];
296 772
297 IVegetationModule module = m_scene.RequestModuleInterface<IVegetationModule>(); 773 position.Z = (float)m_scene.Heightmap[(int)position.X, (int)position.Y];
298 774 if (position.Z >= copse.m_treeline_low && position.Z <= copse.m_treeline_high)
299 if (null == module) 775 {
300 return; 776 SceneObjectGroup tree = AddTree(uuid, UUID.Zero, copse.m_initial_scale, Quaternion.Identity, position, copse.m_tree_type, false);
301 777
302 SceneObjectGroup tree 778 tree.Name = copse.ToString();
303 = module.AddTree( 779 copse.m_trees.Add(tree.UUID);
304 uuid, UUID.Zero, new Vector3(0.1f, 0.1f, 0.1f), Quaternion.Identity, position, Tree.Cypress1, false); 780 tree.SendGroupFullUpdate();
305 781 }
306 m_trees.Add(tree.UUID);
307 tree.SendGroupFullUpdate();
308 } 782 }
309 783
310 private void CalculateTrees_Elapsed(object sender, ElapsedEventArgs e) 784 private void CalculateTrees_Elapsed(object sender, ElapsedEventArgs e)
@@ -315,3 +789,4 @@ namespace OpenSim.Region.OptionalModules.World.TreePopulator
315 } 789 }
316 } 790 }
317} 791}
792