diff --git a/Module/BirdsModule/FlockingModel.cs b/Module/BirdsModule/FlockingModel.cs index 77bf813..9a9f458 100644 --- a/Module/BirdsModule/FlockingModel.cs +++ b/Module/BirdsModule/FlockingModel.cs @@ -40,7 +40,8 @@ namespace Flocking private float m_neighbourDistance; private float m_desiredSeparation; private float m_tolerance; - private float m_border; + private float m_border; + private string m_name; private Random m_rnd = new Random(Environment.TickCount); @@ -50,13 +51,14 @@ namespace Flocking if( value < m_flock.Count ) { m_flock.RemoveRange( 0, m_flock.Count - value ); } else while( value > m_flock.Count ) { - AddBird( "Bird"+m_flock.Count); + AddBird(m_name + m_flock.Count); } } } - public FlockingModel( float maxSpeed, float maxForce, float neighbourDistance, float desiredSeparation, float tolerance, float border) { - m_maxSpeed = maxSpeed; + public FlockingModel(string moduleName, float maxSpeed, float maxForce, float neighbourDistance, float desiredSeparation, float tolerance, float border) { + m_name = moduleName; + m_maxSpeed = maxSpeed; m_maxForce = maxForce; m_neighbourDistance = neighbourDistance; m_desiredSeparation = desiredSeparation; diff --git a/Module/BirdsModule/FlockingModule.cs b/Module/BirdsModule/FlockingModule.cs index 023dfc7..59c990f 100644 --- a/Module/BirdsModule/FlockingModule.cs +++ b/Module/BirdsModule/FlockingModule.cs @@ -42,7 +42,7 @@ using OpenSim.Framework.Console; using Mono.Addins; [assembly: Addin("OpenSimBirds", "0.2")] -[assembly: AddinDependency("OpenSim", "0.5")] +[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)] namespace Flocking { @@ -54,6 +54,7 @@ namespace Flocking public string m_name = "OpenSimBirds"; private Scene m_scene; + private ICommandConsole m_console; private FlockingModel m_model; private FlockingView m_view; private bool m_enabled = false; @@ -91,25 +92,11 @@ namespace Flocking public void AddRegion (Scene scene) { m_log.InfoFormat("[{0}]: Adding region '{1}' to this module", m_name, scene.RegionInfo.RegionName); - - string moduleConfigFile = Path.Combine(Util.configDir(), "../addon-modules/" + m_name + "/config/" + m_name + ".ini"); - m_log.InfoFormat("[{0}]: Loading from config file {1}", m_name, moduleConfigFile); - try - { - m_config = new IniConfigSource(moduleConfigFile); - } - catch (Exception) - { - m_log.InfoFormat("[{0}]: No module config file '{1}' was found! Tide in this region is set to Disabled", m_name, moduleConfigFile); - m_enabled = false; - m_config = null; - return; - } IConfig cnf = m_config.Configs[scene.RegionInfo.RegionName]; if (cnf == null) { - m_log.InfoFormat("[{0}]: No region section [{1}] found in config file {2}. Tide in this region is set to Disabled", m_name, scene.RegionInfo.RegionName, moduleConfigFile); + m_log.InfoFormat("[{0}]: No region section [{1}] found in configuration. Birds in this region are set to Disabled", m_name, scene.RegionInfo.RegionName); m_enabled = false; return; } @@ -128,45 +115,38 @@ namespace Flocking m_tolerance = cnf.GetFloat("BirdsTolerance", 5f); m_borderSize = cnf.GetFloat("BirdsRegionBorderSize", 5f); m_maxHeight = cnf.GetInt("BirdsMaxHeight", 256); + m_frameUpdateRate = cnf.GetInt("BirdsUpdateEveryNFrames", 1); + + m_log.InfoFormat("[{0}] Enabled on channel {1} with Flock Size {2}", m_name, m_chatChannel, m_flockSize); - m_log.InfoFormat("[{0}] Enabled on channel {1} with Flock Size {2}", m_name, m_chatChannel, m_flockSize); - m_scene = scene; + m_console = MainConsole.Instance; //register commands with the scene RegisterCommands(); //register handlers - scene.EventManager.OnFrame += FlockUpdate; - scene.EventManager.OnChatFromClient += SimChatSent; //listen for commands sent from the client + m_scene.EventManager.OnFrame += FlockUpdate; + m_scene.EventManager.OnChatFromClient += SimChatSent; //listen for commands sent from the client // init module - m_model = new FlockingModel(m_maxSpeed, m_maxForce, m_neighbourDistance, m_desiredSeparation, m_tolerance, m_borderSize); - m_view = new FlockingView(scene); + m_model = new FlockingModel(m_name, m_maxSpeed, m_maxForce, m_neighbourDistance, m_desiredSeparation, m_tolerance, m_borderSize); + m_view = new FlockingView(m_name, m_scene); m_view.BirdPrim = m_birdPrim; m_frame = 0; + FlockInitialise(); + } } public void RegionLoaded (Scene scene) { - if (m_enabled) { - - //make a flow map for this scene - FlowMap flowMap = new FlowMap(scene, m_maxHeight, m_borderSize); - flowMap.Initialise(); - - // Generate initial flock values - m_model.Initialise (m_flockSize, flowMap); - - // who is the owner for the flock in this region - m_owner = scene.RegionInfo.EstateSettings.EstateOwner; - m_view.PostInitialize (m_owner); - - // Mark Module Ready for duty + //m_scene = scene; + if (m_enabled) { + // Mark Module Ready for duty m_ready = true; - } + } } public void RemoveRegion (Scene scene) @@ -190,10 +170,28 @@ namespace Flocking } #endregion - - #region EventHandlers - - public void FlockUpdate () + + #region Helpers + + public void FlockInitialise() + { + //make a flow map for this scene + FlowMap flowMap = new FlowMap(m_scene, m_maxHeight, m_borderSize); + flowMap.Initialise(); + + // Generate initial flock values + m_model.Initialise(m_flockSize, flowMap); + + // who is the owner for the flock in this region + m_owner = m_scene.RegionInfo.EstateSettings.EstateOwner; + m_view.PostInitialize(m_owner); + } + + #endregion + + #region EventHandlers + + public void FlockUpdate () { if (((m_frame++ % m_frameUpdateRate) != 0) || !m_ready || !m_enabled) { return; @@ -247,13 +245,17 @@ namespace Flocking if (args.Trim ().Length > 0) { argStr = " <" + args + "> "; } - m_scene.AddCommand (this, "flock-" + cmd, "flock-" + cmd + argStr, help, fn); - } + m_log.InfoFormat("[{0}]: Adding command {1} - {2} to region '{3}'", m_name, "birds-" + cmd + argStr, help, m_scene.RegionInfo.RegionName); + //m_scene.AddCommand (this, "birds-" + cmd, "birds-" + cmd + argStr, help, fn); + m_console.Commands.AddCommand(m_name, false, "birds-" + cmd, "birds-" + cmd + argStr, help, fn); + } private void RegisterCommands () { - AddCommand ("stop", "", "Stop all Flocking", HandleStopCmd); - AddCommand ("start", "", "Start Flocking", HandleStartCmd); + AddCommand ("stop", "", "Stop Birds Flocking", HandleStopCmd); + AddCommand ("start", "", "Start Birds Flocking", HandleStartCmd); + AddCommand ("enable", "", "Enable Birds Flocking", HandleEnableCmd); + AddCommand ("disable", "", "Disable Birds Flocking", HandleDisableCmd); AddCommand ("size", "num", "Adjust the size of the flock ", HandleSetSizeCmd); AddCommand ("stats", "", "show flocking stats", HandleShowStatsCmd); AddCommand ("prim", "name", "set the prim used for each bird to that passed in", HandleSetPrimCmd); @@ -262,7 +264,14 @@ namespace Flocking private bool ShouldHandleCmd () { - return m_scene.ConsoleScene () == m_scene; + if (!(m_console.ConsoleScene == null || m_console.ConsoleScene == m_scene)) + { + m_log.InfoFormat("[{0}]: Command Ignored!", m_name); + return false; + } else { + m_log.InfoFormat("[{0}]: Command Executed!", m_name); + return true; + } } private bool IsInWorldCmd (ref string [] args) @@ -286,16 +295,47 @@ namespace Flocking MainConsole.Instance.Output (response); } } + + public void HandleDisableCmd(string module, string[] args) + { + if (m_ready && ShouldHandleCmd ()) { + m_log.InfoFormat("[{0}]: Bird flocking is disabled.", m_name); + m_enabled = false; + m_ready = false; + m_view.Clear(); + } + } + + public void HandleEnableCmd(string module, string[] args) + { + if (!m_ready && ShouldHandleCmd()) + { + m_log.InfoFormat("[{0}]: Bird flocking is enabled.", m_name); + FlockInitialise(); + m_enabled = true; + m_ready = true; + } + } public void HandleStopCmd (string module, string[] args) { - if (ShouldHandleCmd ()) { - m_log.Info ("stop the flocking capability"); + if (m_enabled && m_ready && ShouldHandleCmd()) + { + m_log.InfoFormat("[{0}]: Bird flocking is stopped.", m_name); m_enabled = false; - m_view.Clear (); } } + public void HandleStartCmd(string module, string[] args) + { + if (!m_enabled && m_ready && ShouldHandleCmd()) + { + m_log.InfoFormat("[{0}]: Bird flocking is started.", m_name); + m_enabled = true; + FlockUpdate(); + } + } + void HandleSetFrameRateCmd (string module, string[] args) { if (ShouldHandleCmd ()) { @@ -304,15 +344,6 @@ namespace Flocking } } - public void HandleStartCmd (string module, string[] args) - { - if (ShouldHandleCmd ()) { - m_log.Info ("start the flocking capability"); - m_enabled = true; - FlockUpdate (); - } - } - public void HandleSetSizeCmd (string module, string[] args) { if (ShouldHandleCmd ()) { diff --git a/Module/BirdsModule/FlockingView.cs b/Module/BirdsModule/FlockingView.cs index 7cccd4d..fd0656c 100644 --- a/Module/BirdsModule/FlockingView.cs +++ b/Module/BirdsModule/FlockingView.cs @@ -29,21 +29,25 @@ using System; using System.Collections.Generic; using OpenMetaverse; using OpenSim.Framework; -using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Scenes; +using log4net; namespace Flocking { public class FlockingView - { - private Scene m_scene; - private UUID m_owner; + { + private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + private Scene m_scene; + private UUID m_owner; + private String m_name; private String m_birdPrim; private Dictionary m_sogMap = new Dictionary (); - public FlockingView (Scene scene) - { - m_scene = scene; + public FlockingView (String moduleName, Scene scene) + { + m_name = moduleName; + m_scene = scene; } public void PostInitialize (UUID owner) @@ -59,7 +63,8 @@ namespace Flocking { //trash everything we have foreach (string name in m_sogMap.Keys) - { + { + m_log.InfoFormat("[{0}]: Removing prim {1} from region {2}", m_name, name, m_scene.RegionInfo.RegionName); RemoveSOGFromScene(name); } m_sogMap.Clear(); @@ -77,18 +82,32 @@ namespace Flocking SceneObjectPart existing = m_scene.GetSceneObjectPart (bird.Id); - SceneObjectGroup sog; + SceneObjectGroup sog; + SceneObjectPart rootPart; + if (existing == null) { SceneObjectGroup group = findByName (m_birdPrim); - sog = CopyPrim (group, bird.Id); - m_sogMap [bird.Id] = sog; + sog = CopyPrim (group, bird.Id); + rootPart = sog.RootPart; + //set prim to phantom + sog.UpdatePrimFlags(rootPart.LocalId, false, false, true, false); + m_sogMap [bird.Id] = sog; + m_log.InfoFormat("[{0}]: Adding prim {1} from region {2}", m_name, bird.Id, m_scene.RegionInfo.RegionName); m_scene.AddNewSceneObject (sog, false); } else { - sog = existing.ParentGroup; + sog = existing.ParentGroup; + rootPart = sog.RootPart; + //set prim to phantom + sog.UpdatePrimFlags(rootPart.LocalId, false, false, true, false); } Quaternion rotation = CalcRotationToEndpoint (sog, sog.AbsolutePosition, bird.Location); - sog.UpdateGroupRotationPR( bird.Location, rotation); + sog.UpdateGroupRotationPR( bird.Location, rotation); + + // Fire script on_rez + sog.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 1); + rootPart.ParentGroup.ResumeScripts(); + rootPart.ScheduleFullUpdate(); } private static Quaternion CalcRotationToEndpoint (SceneObjectGroup copy, Vector3 sv, Vector3 ev) @@ -106,7 +125,7 @@ namespace Flocking private SceneObjectGroup CopyPrim (SceneObjectGroup prim, string name) { - SceneObjectGroup copy = prim.Copy (true); + SceneObjectGroup copy = prim.Copy (true); copy.Name = name; copy.DetachFromBackup (); return copy; @@ -133,9 +152,9 @@ namespace Flocking private SceneObjectGroup MakeDefaultPrim (string name) { PrimitiveBaseShape shape = PrimitiveBaseShape.CreateSphere (); - shape.Scale = new Vector3 (0.5f, 0.5f, 0.5f); + shape.Scale = new Vector3 (0.5f, 0.5f, 0.5f); - SceneObjectGroup prim = new SceneObjectGroup(m_owner, new Vector3((float)m_scene.RegionInfo.RegionSizeX / 2, (float)m_scene.RegionInfo.RegionSizeY / 2, 25f), shape); + SceneObjectGroup prim = new SceneObjectGroup(m_owner, new Vector3((float)m_scene.RegionInfo.RegionSizeX / 2, (float)m_scene.RegionInfo.RegionSizeY / 2, 25f), shape); prim.Name = name; prim.DetachFromBackup (); m_scene.AddNewSceneObject (prim, false); diff --git a/README.md b/README.md index fc530e9..dbd33a9 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,6 @@ -INonSharedRegion Module - ability to control flocks of prims within an OpenSim scene +INonSharedRegion Module - ability to control flocks of prims within an OpenSim scene. + +***This module is currently broken, removing prims from the scene on disable does not work**** To build from source @@ -6,7 +8,8 @@ To build from source Add OpenSimBirds source tree under opensim/addon-modules ./runprebuild.sh against opensim root to build this module into the solution -then xbuild, or build within Visual Studio / Monodevelop to produce the binaries +then xbuild, or build within Visual Studio / Monodevelop to produce the binaries. +Remember you need an .ini file in bin/addon-modules/OpenSimBirds/config/ OpenSimBirds has no external dependencies other than the dlls currently included in opensim. The project generates a single dll - OpenSimBirds.Modules.dll which is copied into opensim/bin as part of the build step @@ -19,12 +22,13 @@ If you are running multiple regions on one simulator you can have different Bird settings per region in the configuration file, in the exact same way you can customize per Region setting in Regions.ini -The configuration file for this module is in: +The configuration file for this module should be placed in: -addon-modules/OpenSimBirds/config/OpenSimBirds.ini +bin/addon-modules/OpenSimBirds/config/OpenSimBirds.ini -and follows the same format as a Regions.ini file, where you specify setting for -each region using the [Region Name] section heading. +and follows the similar format as a Regions.ini file, where you specify setting for +each region using the [Region Name] section heading. There is an example .ini file +provided which should be edited and copied to the correct place above. Here is an example config: @@ -76,22 +80,10 @@ throw the constituent parts of a 200 linked prim dragon. Tests show that <= 500 single prims can be flocked effectively - depending on system and network However maybe <= 300 simple linksets can perform as well. -I intend to allow inventory items and UUIDs to represent the birds - this is not written yet however. - Please Note -This module is currently only tested against opensim master. If it is found to work against a stable release, -then that behaviour ought to be considered as a bug - which I will attempt to fix in the next git push. - - - -Next Steps - -I want to improve the ability of the birds to avoid obstacles within the scene. Current avoidance is pretty basic, and -only functions correctly about fifty percent of the time. Need to improve this without increasing computational cost. - - +This module is currently only tested against opensim master. Licence: all files released under a BSD licence If you have any question please contact Jak Daniels, jak@ateb.co.uk diff --git a/config/OpenSimBirds.ini b/config/OpenSimBirds.ini deleted file mode 100644 index 121c393..0000000 --- a/config/OpenSimBirds.ini +++ /dev/null @@ -1,16 +0,0 @@ -;; Set the Birds settings per named region - -[Test Region 1] - - BirdsEnabled = True ;set to false to disable the module in this region - BirdsFlockSize = 100 ;the number of birds to flock - BirdsMaxSpeed = 3 ;how far each bird can travel per update - BirdsMaxForce = 0.25 ;the maximum acceleration allowed to the current velocity of the bird - BirdsNeighbourDistance = 25 ;max distance for other birds to be considered in the same flock as us - BirdsDesiredSeparation = 20 ;how far away from other birds we would like to stay - BirdsTolerance = 5 ;how close to the edges of things can we get without being worried - BirdsBorderSize = 5 ;how close to the edge of a region can we get? - BirdsMaxHeight = 256 ;how high are we allowed to flock - BirdsPrim = seagull01 ;By default the module will create a flock of plain wooden spheres, - ;however this can be overridden to the name of an existing prim that - ;needs to already exist in the scene - i.e. be rezzed in the region.