diff --git a/OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs b/OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs index c7d50274f9..3e9c3269c7 100644 --- a/OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs +++ b/OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs @@ -33,57 +33,182 @@ using OpenMetaverse; using log4net; using Nini.Config; using OpenSim.Framework; +using OpenSim.Region.CoreModules.Framework.InterfaceCommander; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; +using System.Xml; +using System.Xml.Serialization; +using System.IO; + namespace OpenSim.Region.OptionalModules.World.TreePopulator { /// - /// Version 2.01 - Very hacky compared to the original. Will fix original and release as 0.3 later. + /// Version 2.02 - Still hacky /// - public class TreePopulatorModule : IRegionModule + public class TreePopulatorModule : IRegionModule, ICommandableModule, IVegetationModule { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private readonly Commander m_commander = new Commander("tree"); private Scene m_scene; - public double m_tree_density = 50.0; // Aim for this many per region - public double m_tree_updates = 1000.0; // MS between updates + [XmlRootAttribute(ElementName = "Copse", IsNullable = false)] + public class Copse + { + public string m_name; + public Boolean m_frozen; + public Tree m_tree_type; + public int m_tree_quantity; + public float m_treeline_low; + public float m_treeline_high; + public Vector3 m_seed_point; + public double m_range; + public Vector3 m_initial_scale; + public Vector3 m_maximum_scale; + public Vector3 m_rate; + + [XmlIgnore] + public Boolean m_planted; + [XmlIgnore] + public List m_trees; + + public Copse() + { + } + + public Copse(string fileName, Boolean planted) + { + Copse cp = (Copse)DeserializeObject(fileName); + + this.m_name = cp.m_name; + this.m_frozen = cp.m_frozen; + this.m_tree_quantity = cp.m_tree_quantity; + this.m_treeline_high = cp.m_treeline_high; + this.m_treeline_low = cp.m_treeline_low; + this.m_range = cp.m_range; + this.m_tree_type = cp.m_tree_type; + this.m_seed_point = cp.m_seed_point; + this.m_initial_scale = cp.m_initial_scale; + this.m_maximum_scale = cp.m_maximum_scale; + this.m_initial_scale = cp.m_initial_scale; + this.m_rate = cp.m_rate; + this.m_planted = planted; + this.m_trees = new List(); + } + + public Copse(string copsedef) + { + char[] delimiterChars = {':', ';'}; + string[] field = copsedef.Split(delimiterChars); + + this.m_name = field[1].Trim(); + this.m_frozen = (copsedef[0] == 'F'); + this.m_tree_quantity = int.Parse(field[2]); + this.m_treeline_high = float.Parse(field[3]); + this.m_treeline_low = float.Parse(field[4]); + this.m_range = double.Parse(field[5]); + this.m_tree_type = (Tree) Enum.Parse(typeof(Tree),field[6]); + this.m_seed_point = Vector3.Parse(field[7]); + this.m_initial_scale = Vector3.Parse(field[8]); + this.m_maximum_scale = Vector3.Parse(field[9]); + this.m_rate = Vector3.Parse(field[10]); + this.m_planted = true; + this.m_trees = new List(); + } + + public Copse(string name, int quantity, float high, float low, double range, Vector3 point, Tree type, Vector3 scale, Vector3 max_scale, Vector3 rate, List trees) + { + this.m_name = name; + this.m_frozen = false; + this.m_tree_quantity = quantity; + this.m_treeline_high = high; + this.m_treeline_low = low; + this.m_range = range; + this.m_tree_type = type; + this.m_seed_point = point; + this.m_initial_scale = scale; + this.m_maximum_scale = max_scale; + this.m_rate = rate; + this.m_planted = false; + this.m_trees = trees; + } + + public override string ToString() + { + string frozen = (this.m_frozen ? "F" : "A"); + + 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};", + frozen, + this.m_name, + this.m_tree_quantity, + this.m_treeline_high, + this.m_treeline_low, + this.m_range, + this.m_tree_type, + this.m_seed_point.ToString(), + this.m_initial_scale.ToString(), + this.m_maximum_scale.ToString(), + this.m_rate.ToString()); + } + } + + private List m_copse; + + private double m_update_ms = 1000.0; // msec between updates private bool m_active_trees = false; - private List m_trees; + Timer CalculateTrees; + #region ICommandableModule Members + + public ICommander CommandInterface + { + get { return m_commander; } + } + + #endregion + #region IRegionModule Members public void Initialise(Scene scene, IConfigSource config) { + m_scene = scene; m_scene.RegisterModuleInterface(this); + m_scene.EventManager.OnPluginConsole += EventManager_OnPluginConsole; - m_scene.AddCommand( - this, "tree plant", "tree plant", "Start populating trees", HandleTreeConsoleCommand); - - m_scene.AddCommand( - this, "tree active", "tree active ", "Change activity state for trees module", HandleTreeConsoleCommand); - + // ini file settings try { - m_tree_density = config.Configs["Trees"].GetDouble("tree_density", m_tree_density); m_active_trees = config.Configs["Trees"].GetBoolean("active_trees", m_active_trees); } catch (Exception) { + m_log.Debug("[TREES]: ini failure for active_trees - using default"); } - m_trees = new List(); + try + { + m_update_ms = config.Configs["Trees"].GetDouble("update_rate", m_update_ms); + } + catch (Exception) + { + m_log.Debug("[TREES]: ini failure for update_rate - using default"); + } - if (m_active_trees) - activeizeTreeze(true); + InstallCommands(); m_log.Debug("[TREES]: Initialised tree module"); } public void PostInitialise() { + ReloadCopse(); + if (m_copse.Count > 0) + m_log.Info("[TREES]: Copse load complete"); + + if (m_active_trees) + activeizeTreeze(true); } public void Close() @@ -102,61 +227,397 @@ namespace OpenSim.Region.OptionalModules.World.TreePopulator #endregion - /// - /// Handle a tree command from the console. - /// - /// - /// - public void HandleTreeConsoleCommand(string module, string[] cmdparams) - { - if (m_scene.ConsoleScene() != null && m_scene.ConsoleScene() != m_scene) - return; + //-------------------------------------------------------------- - if (cmdparams[1] == "active") + #region ICommandableModule Members + + private void HandleTreeActive(Object[] args) + { + if ((Boolean)args[0] && !m_active_trees) { - if (cmdparams.Length <= 2) - { - if (m_active_trees) - m_log.InfoFormat("[TREES]: Trees are currently active"); - else - m_log.InfoFormat("[TREES]: Trees are currently not active"); - } - else if (cmdparams[2] == "true" && !m_active_trees) - { - m_log.InfoFormat("[TREES]: Activating Trees"); - m_active_trees = true; - activeizeTreeze(m_active_trees); - } - else if (cmdparams[2] == "false" && m_active_trees) - { - m_log.InfoFormat("[TREES]: Trees no longer active, for now..."); - m_active_trees = false; - activeizeTreeze(m_active_trees); - } - else - { - m_log.InfoFormat("[TREES]: When setting the tree module active via the console, you must specify true or false"); - } + m_log.InfoFormat("[TREES]: Activating Trees"); + m_active_trees = true; + activeizeTreeze(m_active_trees); } - else if (cmdparams[1] == "plant") + else if (!(Boolean)args[0] && m_active_trees) { - m_log.InfoFormat("[TREES]: New tree planting"); - UUID uuid = m_scene.RegionInfo.EstateSettings.EstateOwner; - if (uuid == UUID.Zero) - uuid = m_scene.RegionInfo.MasterAvatarAssignedUUID; - CreateTree(uuid, new Vector3(128.0f, 128.0f, 0.0f)); + m_log.InfoFormat("[TREES]: Trees module is no longer active"); + m_active_trees = false; + activeizeTreeze(m_active_trees); } else { - m_log.InfoFormat("[TREES]: Unknown command"); + m_log.InfoFormat("[TREES]: Trees module is already in the required state"); } } + private void HandleTreeFreeze(Object[] args) + { + string copsename = ((string)args[0]).Trim(); + Boolean freezeState = (Boolean) args[1]; + + foreach (Copse cp in m_copse) + { + if (cp.m_name == copsename && (!cp.m_frozen && freezeState || cp.m_frozen && !freezeState)) + { + cp.m_frozen = freezeState; + foreach (UUID tree in cp.m_trees) + { + SceneObjectPart sop = ((SceneObjectGroup)m_scene.Entities[tree]).RootPart; + sop.Name = (freezeState ? sop.Name.Replace("ATPM", "FTPM") : sop.Name.Replace("FTPM", "ATPM")); + sop.ParentGroup.HasGroupChanged = true; + } + + m_log.InfoFormat("[TREES]: Activity for copse {0} is frozen {1}", copsename, freezeState); + return; + } + else if (cp.m_name == copsename && (cp.m_frozen && freezeState || !cp.m_frozen && !freezeState)) + { + m_log.InfoFormat("[TREES]: Copse {0} is already in the requested freeze state", copsename); + return; + } + } + m_log.InfoFormat("[TREES]: Copse {0} was not found - command failed", copsename); + } + + private void HandleTreeLoad(Object[] args) + { + Copse copse; + + m_log.InfoFormat("[TREES]: Loading copse definition...."); + + copse = new Copse(((string)args[0]), false); + foreach (Copse cp in m_copse) + { + if (cp.m_name == copse.m_name) + { + m_log.InfoFormat("[TREES]: Copse: {0} is already defined - command failed", copse.m_name); + return; + } + } + + m_copse.Add(copse); + m_log.InfoFormat("[TREES]: Loaded copse: {0}", copse.ToString()); + } + + private void HandleTreePlant(Object[] args) + { + string copsename = ((string)args[0]).Trim(); + + m_log.InfoFormat("[TREES]: New tree planting for copse {0}", copsename); + UUID uuid = m_scene.RegionInfo.EstateSettings.EstateOwner; + if (uuid == UUID.Zero) + uuid = m_scene.RegionInfo.MasterAvatarAssignedUUID; + + foreach (Copse copse in m_copse) + { + if (copse.m_name == copsename) + { + if (!copse.m_planted) + { + // The first tree for a copse is created here + CreateTree(uuid, copse, copse.m_seed_point); + copse.m_planted = true; + return; + } + else + { + m_log.InfoFormat("[TREES]: Copse {0} has already been planted", copsename); + } + } + } + m_log.InfoFormat("[TREES]: Copse {0} not found for planting", copsename); + } + + private void HandleTreeRate(Object[] args) + { + m_update_ms = (double)args[0]; + if (m_update_ms >= 1000.0) + { + if (m_active_trees) + { + activeizeTreeze(false); + activeizeTreeze(true); + } + m_log.InfoFormat("[TREES]: Update rate set to {0} mSec", m_update_ms); + } + else + { + m_log.InfoFormat("[TREES]: minimum rate is 1000.0 mSec - command failed"); + } + } + + private void HandleTreeReload(Object[] args) + { + if (m_active_trees) + { + CalculateTrees.Stop(); + } + + ReloadCopse(); + + if (m_active_trees) + { + CalculateTrees.Start(); + } + } + + private void HandleTreeRemove(Object[] args) + { + string copsename = ((string)args[0]).Trim(); + Copse copseIdentity = null; + + foreach (Copse cp in m_copse) + { + if (cp.m_name == copsename) + { + copseIdentity = cp; + } + } + + if (copseIdentity != null) + { + foreach (UUID tree in copseIdentity.m_trees) + { + if (m_scene.Entities.ContainsKey(tree)) + { + SceneObjectPart selectedTree = ((SceneObjectGroup)m_scene.Entities[tree]).RootPart; + + + m_scene.DeleteSceneObject(selectedTree.ParentGroup, false); + m_scene.ForEachClient(delegate(IClientAPI controller) + { + controller.SendKillObject(m_scene.RegionInfo.RegionHandle, + selectedTree.LocalId); + }); + } + else + { + m_log.DebugFormat("[TREES]: Tree not in scene {0}", tree); + } + } + copseIdentity.m_trees = new List(); + m_copse.Remove(copseIdentity); + m_log.InfoFormat("[TREES]: Copse {0} has been removed", copsename); + } + else + { + m_log.InfoFormat("[TREES]: Copse {0} was not found - command failed", copsename); + } + } + + private void HandleTreeStatistics(Object[] args) + { + m_log.InfoFormat("[TREES]: Activity State: {0}; Update Rate: {1}", m_active_trees, m_update_ms); + foreach (Copse cp in m_copse) + { + m_log.InfoFormat("[TREES]: Copse {0}; {1} trees; frozen {2}", cp.m_name, cp.m_trees.Count, cp.m_frozen); + } + } + + private void InstallCommands() + { + Command treeActiveCommand = + new Command("active", CommandIntentions.COMMAND_HAZARDOUS, HandleTreeActive, "Change activity state for the trees module"); + treeActiveCommand.AddArgument("activeTF", "The required activity state", "Boolean"); + + Command treeFreezeCommand = + new Command("freeze", CommandIntentions.COMMAND_HAZARDOUS, HandleTreeFreeze, "Freeze/Unfreeze activity for a defined copse"); + treeFreezeCommand.AddArgument("copse", "The required copse", "String"); + treeFreezeCommand.AddArgument("freezeTF", "The required freeze state", "Boolean"); + + Command treeLoadCommand = + new Command("load", CommandIntentions.COMMAND_HAZARDOUS, HandleTreeLoad, "Load a copse definition from an xml file"); + treeLoadCommand.AddArgument("filename", "The (xml) file you wish to load", "String"); + + Command treePlantCommand = + new Command("plant", CommandIntentions.COMMAND_HAZARDOUS, HandleTreePlant, "Start the planting on a copse"); + treePlantCommand.AddArgument("copse", "The required copse", "String"); + + Command treeRateCommand = + new Command("rate", CommandIntentions.COMMAND_HAZARDOUS, HandleTreeRate, "Reset the tree update rate (mSec)"); + treeRateCommand.AddArgument("updateRate", "The required update rate (minimum 1000.0)", "Double"); + + Command treeReloadCommand = + new Command("reload", CommandIntentions.COMMAND_HAZARDOUS, HandleTreeReload, "Reload copse definitions from the in-scene trees"); + + Command treeRemoveCommand = + new Command("remove", CommandIntentions.COMMAND_HAZARDOUS, HandleTreeRemove, "Remove a copse definition and all its in-scene trees"); + treeRemoveCommand.AddArgument("copse", "The required copse", "String"); + + Command treeStatisticsCommand = + new Command("statistics", CommandIntentions.COMMAND_STATISTICAL, HandleTreeStatistics, "Log statistics about the trees"); + + m_commander.RegisterCommand("active", treeActiveCommand); + m_commander.RegisterCommand("freeze", treeFreezeCommand); + m_commander.RegisterCommand("load", treeLoadCommand); + m_commander.RegisterCommand("plant", treePlantCommand); + m_commander.RegisterCommand("rate", treeRateCommand); + m_commander.RegisterCommand("reload", treeReloadCommand); + m_commander.RegisterCommand("remove", treeRemoveCommand); + m_commander.RegisterCommand("statistics", treeStatisticsCommand); + + m_scene.RegisterModuleCommander(m_commander); + } + + /// + /// Processes commandline input. Do not call directly. + /// + /// Commandline arguments + private void EventManager_OnPluginConsole(string[] args) + { + if (args[0] == "tree") + { + if (args.Length == 1) + { + m_commander.ProcessConsoleCommand("help", new string[0]); + return; + } + + string[] tmpArgs = new string[args.Length - 2]; + int i; + for (i = 2; i < args.Length; i++) + { + tmpArgs[i - 2] = args[i]; + } + + m_commander.ProcessConsoleCommand(args[1], tmpArgs); + } + } + #endregion + + #region IVegetationModule Members + + public SceneObjectGroup AddTree( + UUID uuid, UUID groupID, Vector3 scale, Quaternion rotation, Vector3 position, Tree treeType, bool newTree) + { + PrimitiveBaseShape treeShape = new PrimitiveBaseShape(); + treeShape.PathCurve = 16; + treeShape.PathEnd = 49900; + treeShape.PCode = newTree ? (byte)PCode.NewTree : (byte)PCode.Tree; + treeShape.Scale = scale; + treeShape.State = (byte)treeType; + + return m_scene.AddNewPrim(uuid, groupID, position, rotation, treeShape); + } + + #endregion + + #region IEntityCreator Members + + protected static readonly PCode[] creationCapabilities = new PCode[] { PCode.NewTree, PCode.Tree }; + public PCode[] CreationCapabilities { get { return creationCapabilities; } } + + public SceneObjectGroup CreateEntity( + UUID ownerID, UUID groupID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) + { + if (Array.IndexOf(creationCapabilities, (PCode)shape.PCode) < 0) + { + m_log.DebugFormat("[VEGETATION]: PCode {0} not handled by {1}", shape.PCode, Name); + return null; + } + + SceneObjectGroup sceneObject = new SceneObjectGroup(ownerID, pos, rot, shape); + SceneObjectPart rootPart = sceneObject.GetChildPart(sceneObject.UUID); + + rootPart.AddFlag(PrimFlags.Phantom); + + m_scene.AddNewSceneObject(sceneObject, true); + sceneObject.SetGroup(groupID, null); + + return sceneObject; + } + + #endregion + + //-------------------------------------------------------------- + + #region Tree Utilities + static public void SerializeObject(string fileName, Object obj) + { + try + { + XmlSerializer xs = new XmlSerializer(typeof(Copse)); + + using (XmlTextWriter writer = new XmlTextWriter(fileName, System.Text.Encoding.UTF8)) + { + writer.Formatting = Formatting.Indented; + xs.Serialize(writer, obj); + } + } + catch (SystemException ex) + { + throw new ApplicationException("Unexpected failure in Tree serialization", ex); + } + } + + static public object DeserializeObject(string fileName) + { + try + { + XmlSerializer xs = new XmlSerializer(typeof(Copse)); + + using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read)) + return xs.Deserialize(fs); + } + catch (SystemException ex) + { + throw new ApplicationException("Unexpected failure in Tree de-serialization", ex); + } + } + + private void ReloadCopse() + { + m_copse = new List(); + + List objs = m_scene.GetEntities(); + + foreach (EntityBase obj in objs) + { + if (obj is SceneObjectGroup) + { + SceneObjectGroup grp = (SceneObjectGroup)obj; + + if (grp.Name.Length > 5 && (grp.Name.Substring(0, 5) == "ATPM:" || grp.Name.Substring(0, 5) == "FTPM:")) + { + // Create a new copse definition or add uuid to an existing definition + try + { + Boolean copsefound = false; + Copse copse = new Copse(grp.Name); + + foreach (Copse cp in m_copse) + { + if (cp.m_name == copse.m_name) + { + copsefound = true; + cp.m_trees.Add(grp.UUID); + //m_log.DebugFormat("[TREES]: Found tree {0}", grp.UUID); + } + } + + if (!copsefound) + { + m_log.InfoFormat("[TREES]: Found copse {0}", grp.Name); + m_copse.Add(copse); + copse.m_trees.Add(grp.UUID); + } + } + catch + { + m_log.InfoFormat("[TREES]: Ill formed copse definition {0} - ignoring", grp.Name); + } + } + } + } + } + #endregion + private void activeizeTreeze(bool activeYN) { if (activeYN) { - CalculateTrees = new Timer(m_tree_updates); + CalculateTrees = new Timer(m_update_ms); CalculateTrees.Elapsed += CalculateTrees_Elapsed; CalculateTrees.Start(); } @@ -168,143 +629,156 @@ namespace OpenSim.Region.OptionalModules.World.TreePopulator private void growTrees() { - foreach (UUID tree in m_trees) + foreach (Copse copse in m_copse) { - if (m_scene.Entities.ContainsKey(tree)) + if (!copse.m_frozen) { - SceneObjectPart s_tree = ((SceneObjectGroup) m_scene.Entities[tree]).RootPart; + foreach (UUID tree in copse.m_trees) + { + if (m_scene.Entities.ContainsKey(tree)) + { + SceneObjectPart s_tree = ((SceneObjectGroup)m_scene.Entities[tree]).RootPart; - // 100 seconds to grow 1m - s_tree.Scale += new Vector3(0.1f, 0.1f, 0.1f); - s_tree.SendFullUpdateToAllClients(); - //s_tree.ScheduleTerseUpdate(); - } - else - { - m_trees.Remove(tree); + 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) + { + s_tree.Scale += copse.m_rate; + s_tree.ParentGroup.HasGroupChanged = true; + s_tree.ScheduleFullUpdate(); + } + } + else + { + m_log.DebugFormat("[TREES]: Tree not in scene {0}", tree); + } + } } } } private void seedTrees() { - foreach (UUID tree in m_trees) + foreach (Copse copse in m_copse) { - if (m_scene.Entities.ContainsKey(tree)) + if (!copse.m_frozen) { - SceneObjectPart s_tree = ((SceneObjectGroup) m_scene.Entities[tree]).RootPart; - - if (s_tree.Scale.X > 0.5) + foreach (UUID tree in copse.m_trees) { - if (Util.RandomClass.NextDouble() > 0.75) + if (m_scene.Entities.ContainsKey(tree)) { - SpawnChild(s_tree); + SceneObjectPart s_tree = ((SceneObjectGroup)m_scene.Entities[tree]).RootPart; + + if (copse.m_trees.Count < copse.m_tree_quantity) + { + // Tree has grown enough to seed if it has grown by at least 25% of seeded to full grown height + if (s_tree.Scale.Z > copse.m_initial_scale.Z + (copse.m_maximum_scale.Z - copse.m_initial_scale.Z) / 4.0) + { + if (Util.RandomClass.NextDouble() > 0.75) + { + SpawnChild(copse, s_tree); + } + } + } + } + else + { + m_log.DebugFormat("[TREES]: Tree not in scene {0}", tree); } } } - else - { - m_trees.Remove(tree); - } } } private void killTrees() { - foreach (UUID tree in m_trees) + foreach (Copse copse in m_copse) { - double killLikelyhood = 0.0; - - if (m_scene.Entities.ContainsKey(tree)) + if (!copse.m_frozen && copse.m_trees.Count >= copse.m_tree_quantity) { - SceneObjectPart selectedTree = ((SceneObjectGroup) m_scene.Entities[tree]).RootPart; - double selectedTreeScale = Math.Sqrt(Math.Pow(selectedTree.Scale.X, 2) + - Math.Pow(selectedTree.Scale.Y, 2) + - Math.Pow(selectedTree.Scale.Z, 2)); - - foreach (UUID picktree in m_trees) + foreach (UUID tree in copse.m_trees) { - if (picktree != tree) + double killLikelyhood = 0.0; + + if (m_scene.Entities.ContainsKey(tree)) { - SceneObjectPart pickedTree = ((SceneObjectGroup) m_scene.Entities[picktree]).RootPart; + SceneObjectPart selectedTree = ((SceneObjectGroup)m_scene.Entities[tree]).RootPart; + double selectedTreeScale = Math.Sqrt(Math.Pow(selectedTree.Scale.X, 2) + + Math.Pow(selectedTree.Scale.Y, 2) + + Math.Pow(selectedTree.Scale.Z, 2)); - double pickedTreeScale = Math.Sqrt(Math.Pow(pickedTree.Scale.X, 2) + - Math.Pow(pickedTree.Scale.Y, 2) + - Math.Pow(pickedTree.Scale.Z, 2)); + foreach (UUID picktree in copse.m_trees) + { + if (picktree != tree) + { + SceneObjectPart pickedTree = ((SceneObjectGroup)m_scene.Entities[picktree]).RootPart; - double pickedTreeDistance = Math.Sqrt(Math.Pow(Math.Abs(pickedTree.AbsolutePosition.X - selectedTree.AbsolutePosition.X), 2) + - Math.Pow(Math.Abs(pickedTree.AbsolutePosition.Y - selectedTree.AbsolutePosition.Y), 2) + - Math.Pow(Math.Abs(pickedTree.AbsolutePosition.Z - selectedTree.AbsolutePosition.Z), 2)); + double pickedTreeScale = Math.Sqrt(Math.Pow(pickedTree.Scale.X, 2) + + Math.Pow(pickedTree.Scale.Y, 2) + + Math.Pow(pickedTree.Scale.Z, 2)); - killLikelyhood += (selectedTreeScale / (pickedTreeScale * pickedTreeDistance)) * 0.1; + double pickedTreeDistance = Vector3.Distance(pickedTree.AbsolutePosition, selectedTree.AbsolutePosition); + + killLikelyhood += (selectedTreeScale / (pickedTreeScale * pickedTreeDistance)) * 0.1; + } + } + + if (Util.RandomClass.NextDouble() < killLikelyhood) + { + + m_scene.DeleteSceneObject(selectedTree.ParentGroup, false); + copse.m_trees.Remove(selectedTree.ParentGroup.UUID); + + m_scene.ForEachClient(delegate(IClientAPI controller) + { + controller.SendKillObject(m_scene.RegionInfo.RegionHandle, + selectedTree.LocalId); + }); + + break; + } + } + else + { + m_log.DebugFormat("[TREES]: Tree not in scene {0}", tree); } } - - if (Util.RandomClass.NextDouble() < killLikelyhood) - { - m_scene.DeleteSceneObject(selectedTree.ParentGroup, false); - m_trees.Remove(selectedTree.ParentGroup.UUID); - - m_scene.ForEachClient(delegate(IClientAPI controller) - { - controller.SendKillObject(m_scene.RegionInfo.RegionHandle, - selectedTree.LocalId); - }); - - break; - } - selectedTree.SetText(killLikelyhood.ToString(), new Vector3(1.0f, 1.0f, 1.0f), 1.0); - } - else - { - m_trees.Remove(tree); } } } - private void SpawnChild(SceneObjectPart s_tree) + private void SpawnChild(Copse copse, SceneObjectPart s_tree) { Vector3 position = new Vector3(); - position.X = s_tree.AbsolutePosition.X + (1 * (-1 * Util.RandomClass.Next(1))); - if (position.X > 255) - position.X = 255; - if (position.X < 0) - position.X = 0; - position.Y = s_tree.AbsolutePosition.Y + (1 * (-1 * Util.RandomClass.Next(1))); - if (position.Y > 255) - position.Y = 255; - if (position.Y < 0) - position.Y = 0; - double randX = ((Util.RandomClass.NextDouble() * 2.0) - 1.0) * (s_tree.Scale.X * 3); double randY = ((Util.RandomClass.NextDouble() * 2.0) - 1.0) * (s_tree.Scale.X * 3); - position.X += (float) randX; - position.Y += (float) randY; + position.X = s_tree.AbsolutePosition.X + (float)randX; + position.Y = s_tree.AbsolutePosition.Y + (float)randY; - UUID uuid = m_scene.RegionInfo.EstateSettings.EstateOwner; - if (uuid == UUID.Zero) - uuid = m_scene.RegionInfo.MasterAvatarAssignedUUID; + if (position.X <= 255 && position.X >= 0 && + position.Y <= 255 && position.Y >= 0 && + Util.GetDistanceTo(position, copse.m_seed_point) <= copse.m_range) + { + UUID uuid = m_scene.RegionInfo.EstateSettings.EstateOwner; + if (uuid == UUID.Zero) + uuid = m_scene.RegionInfo.MasterAvatarAssignedUUID; - CreateTree(uuid, position); + CreateTree(uuid, copse, position); + } } - private void CreateTree(UUID uuid, Vector3 position) + private void CreateTree(UUID uuid, Copse copse, Vector3 position) { - position.Z = (float) m_scene.Heightmap[(int) position.X, (int) position.Y]; - IVegetationModule module = m_scene.RequestModuleInterface(); - - if (null == module) - return; - - SceneObjectGroup tree - = module.AddTree( - uuid, UUID.Zero, new Vector3(0.1f, 0.1f, 0.1f), Quaternion.Identity, position, Tree.Cypress1, false); - - m_trees.Add(tree.UUID); - tree.SendGroupFullUpdate(); + position.Z = (float)m_scene.Heightmap[(int)position.X, (int)position.Y]; + if (position.Z >= copse.m_treeline_low && position.Z <= copse.m_treeline_high) + { + SceneObjectGroup tree = AddTree(uuid, UUID.Zero, copse.m_initial_scale, Quaternion.Identity, position, copse.m_tree_type, false); + + tree.Name = copse.ToString(); + copse.m_trees.Add(tree.UUID); + tree.SendGroupFullUpdate(); + } } private void CalculateTrees_Elapsed(object sender, ElapsedEventArgs e) @@ -315,3 +789,4 @@ namespace OpenSim.Region.OptionalModules.World.TreePopulator } } } +