pull/1/merge
kcozens 2018-04-03 14:56:24 +00:00 committed by GitHub
commit 90e2661c35
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 849 additions and 847 deletions

View File

@ -31,343 +31,343 @@ using OpenMetaverse;
namespace Flocking namespace Flocking
{ {
public class Bird public class Bird
{ {
private static readonly ILog m_log = LogManager.GetLogger (System.Reflection.MethodBase.GetCurrentMethod ().DeclaringType); private static readonly ILog m_log = LogManager.GetLogger (System.Reflection.MethodBase.GetCurrentMethod ().DeclaringType);
private string m_id; private string m_id;
private Vector3 m_loc; private Vector3 m_loc;
private Vector3 m_vel; private Vector3 m_vel;
private Vector3 m_acc; private Vector3 m_acc;
private Random m_rndnums = new Random (Environment.TickCount); private Random m_rndnums = new Random (Environment.TickCount);
private FlockingModel m_model; private FlockingModel m_model;
private FlowMap m_flowMap; private FlowMap m_flowMap;
private int m_regionX; private int m_regionX;
private int m_regionY; private int m_regionY;
private int m_regionZ; private int m_regionZ;
private float m_regionBorder; private float m_regionBorder;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Flocking.Bird"/> class. /// Initializes a new instance of the <see cref="Flocking.Bird"/> class.
/// </summary> /// </summary>
/// <param name='l'> /// <param name='l'>
/// L. the initial position of this bird /// L. the initial position of this bird
/// </param> /// </param>
/// <param name='ms'> /// <param name='ms'>
/// Ms. max speed this bird can attain /// Ms. max speed this bird can attain
/// </param> /// </param>
/// <param name='mf'> /// <param name='mf'>
/// Mf. max force / acceleration this bird can extert /// Mf. max force / acceleration this bird can extert
/// </param> /// </param>
public Bird (string id, FlockingModel model, FlowMap flowMap) public Bird (string id, FlockingModel model, FlowMap flowMap)
{ {
m_id = id; m_id = id;
m_acc = Vector3.Zero; m_acc = Vector3.Zero;
m_vel = new Vector3 (m_rndnums.Next (-1, 1), m_rndnums.Next (-1, 1), m_rndnums.Next (-1, 1)); m_vel = new Vector3 (m_rndnums.Next (-1, 1), m_rndnums.Next (-1, 1), m_rndnums.Next (-1, 1));
m_model = model; m_model = model;
m_flowMap = flowMap; m_flowMap = flowMap;
m_regionX = m_flowMap.LengthX; m_regionX = m_flowMap.LengthX;
m_regionY = m_flowMap.LengthY; m_regionY = m_flowMap.LengthY;
m_regionZ = m_flowMap.LengthZ; m_regionZ = m_flowMap.LengthZ;
m_regionBorder = m_flowMap.Border; m_regionBorder = m_flowMap.Border;
} }
public Vector3 Location { public Vector3 Location {
get { return m_loc;} get { return m_loc;}
set { m_loc = value; } set { m_loc = value; }
} }
public Vector3 Velocity { public Vector3 Velocity {
get { return m_vel;} get { return m_vel;}
} }
public String Id { public String Id {
get {return m_id;} get {return m_id;}
} }
/// <summary> /// <summary>
/// Moves our bird in the scene relative to the rest of the flock. /// Moves our bird in the scene relative to the rest of the flock.
/// </summary> /// </summary>
/// <param name='birds'> /// <param name='birds'>
/// Birds. all the other chaps in the scene /// Birds. all the other chaps in the scene
/// </param> /// </param>
public void MoveInSceneRelativeToFlock (List<Bird> birds) public void MoveInSceneRelativeToFlock (List<Bird> birds)
{ {
// we would like to stay with our mates // we would like to stay with our mates
Flock (birds); Flock (birds);
// our first priority is to not hurt ourselves // our first priority is to not hurt ourselves
AvoidObstacles (); AvoidObstacles ();
// then we want to avoid any threats // then we want to avoid any threats
// this not implemented yet // this not implemented yet
// ok so we worked our where we want to go, so ... // ok so we worked our where we want to go, so ...
UpdatePositionInScene (); UpdatePositionInScene ();
} }
/// <summary> /// <summary>
/// Move within our flock /// Move within our flock
/// ///
/// We accumulate a new acceleration each time based on three rules /// We accumulate a new acceleration each time based on three rules
/// these are: /// these are:
/// our separation from our closest neighbours, /// our separation from our closest neighbours,
/// our desire to keep travelling within the local flock, /// our desire to keep travelling within the local flock,
/// our desire to move towards the flock centre /// our desire to move towards the flock centre
/// ///
/// </summary> /// </summary>
void Flock (List<Bird> birds) void Flock (List<Bird> birds)
{ {
// calc the force vectors on this bird // calc the force vectors on this bird
Vector3 sep = Separate (birds); // Separation Vector3 sep = Separate (birds); // Separation
Vector3 ali = Align (birds); // Alignment Vector3 ali = Align (birds); // Alignment
Vector3 coh = Cohesion (birds); // Cohesion Vector3 coh = Cohesion (birds); // Cohesion
// Arbitrarily weight these forces // Arbitrarily weight these forces
//TODO: expose these consts //TODO: expose these consts
sep *= 1.5f; //.mult(1.5); sep *= 1.5f; //.mult(1.5);
//ali.mult(1.0); //ali.mult(1.0);
ali *= 1.0f; ali *= 1.0f;
//coh.mult(1.0); //coh.mult(1.0);
coh *= 1.0f; coh *= 1.0f;
// Add the force vectors to the current acceleration of the bird // Add the force vectors to the current acceleration of the bird
//acc.add(sep); //acc.add(sep);
m_acc += sep; m_acc += sep;
//acc.add(ali); //acc.add(ali);
m_acc += ali; m_acc += ali;
//acc.add(coh); //acc.add(coh);
m_acc += coh; m_acc += coh;
} }
/// <summary> /// <summary>
/// Method to update our location within the scene. /// Method to update our location within the scene.
/// update our location in the world based on our /// update our location in the world based on our
/// current location, velocity and acceleration /// current location, velocity and acceleration
/// taking into account our max speed /// taking into account our max speed
/// ///
/// </summary> /// </summary>
void UpdatePositionInScene () void UpdatePositionInScene ()
{ {
// Update velocity // Update velocity
//vel.add(acc); //vel.add(acc);
m_vel += m_acc; m_vel += m_acc;
// Limit speed // Limit speed
//m_vel.limit(maxspeed); //m_vel.limit(maxspeed);
m_vel = BirdsUtil.Limit (m_vel, m_model.MaxSpeed); m_vel = BirdsUtil.Limit (m_vel, m_model.MaxSpeed);
m_loc += m_vel; m_loc += m_vel;
// Reset accelertion to 0 each cycle // Reset accelertion to 0 each cycle
m_acc *= 0.0f; m_acc *= 0.0f;
} }
/// <summary> /// <summary>
/// Seek the specified target. Move into that flock /// Seek the specified target. Move into that flock
/// Accelerate us towards where we want to go /// Accelerate us towards where we want to go
/// </summary> /// </summary>
/// <param name='target'> /// <param name='target'>
/// Target. the position within the flock we would like to achieve /// Target. the position within the flock we would like to achieve
/// </param> /// </param>
void Seek (Vector3 target) void Seek (Vector3 target)
{ {
m_acc += Steer (target, false); m_acc += Steer (target, false);
} }
/// <summary> /// <summary>
/// Arrive the specified target. Slow us down, as we are almost there /// Arrive the specified target. Slow us down, as we are almost there
/// </summary> /// </summary>
/// <param name='target'> /// <param name='target'>
/// Target. the flock we would like to think ourselves part of /// Target. the flock we would like to think ourselves part of
/// </param> /// </param>
void arrive (Vector3 target) void arrive (Vector3 target)
{ {
m_acc += Steer (target, true); m_acc += Steer (target, true);
} }
/// A method that calculates a steering vector towards a target /// A method that calculates a steering vector towards a target
/// Takes a second argument, if true, it slows down as it approaches the target /// Takes a second argument, if true, it slows down as it approaches the target
Vector3 Steer (Vector3 target, bool slowdown) Vector3 Steer (Vector3 target, bool slowdown)
{ {
Vector3 steer; // The steering vector Vector3 steer; // The steering vector
Vector3 desired = Vector3.Subtract(target, m_loc); // A vector pointing from the location to the target Vector3 desired = Vector3.Subtract(target, m_loc); // A vector pointing from the location to the target
float d = desired.Length (); // Distance from the target is the magnitude of the vector float d = desired.Length (); // Distance from the target is the magnitude of the vector
// If the distance is greater than 0, calc steering (otherwise return zero vector) // If the distance is greater than 0, calc steering (otherwise return zero vector)
if (d > 0) { if (d > 0) {
// Normalize desired // Normalize desired
desired.Normalize (); desired.Normalize ();
// Two options for desired vector magnitude (1 -- based on distance, 2 -- maxspeed) // Two options for desired vector magnitude (1 -- based on distance, 2 -- maxspeed)
if ((slowdown) && (d < 100.0f)) { if ((slowdown) && (d < 100.0f)) {
desired *= (m_model.MaxSpeed * (d / 100.0f)); // This damping is somewhat arbitrary desired *= (m_model.MaxSpeed * (d / 100.0f)); // This damping is somewhat arbitrary
} else { } else {
desired *= m_model.MaxSpeed; desired *= m_model.MaxSpeed;
} }
// Steering = Desired minus Velocity // Steering = Desired minus Velocity
//steer = target.sub(desired,m_vel); //steer = target.sub(desired,m_vel);
steer = Vector3.Subtract (desired, m_vel); steer = Vector3.Subtract (desired, m_vel);
//steer.limit(maxforce); // Limit to maximum steering force //steer.limit(maxforce); // Limit to maximum steering force
steer = BirdsUtil.Limit (steer, m_model.MaxForce); steer = BirdsUtil.Limit (steer, m_model.MaxForce);
} else { } else {
steer = Vector3.Zero; steer = Vector3.Zero;
} }
return steer; return steer;
} }
/// <summary> /// <summary>
/// Borders this instance. /// Borders this instance.
/// if we get too close wrap us around /// if we get too close wrap us around
/// CHANGE THIS to navigate away from whatever it is we are too close to /// CHANGE THIS to navigate away from whatever it is we are too close to
/// </summary> /// </summary>
void AvoidObstacles () void AvoidObstacles ()
{ {
//look tolerance metres ahead //look tolerance metres ahead
Vector3 normVel = Vector3.Normalize(m_vel); Vector3 normVel = Vector3.Normalize(m_vel);
Vector3 inFront = m_loc + Vector3.Multiply(normVel, m_model.Tolerance); Vector3 inFront = m_loc + Vector3.Multiply(normVel, m_model.Tolerance);
if( m_flowMap.WouldHitObstacle( m_loc, inFront ) ) { if( m_flowMap.WouldHitObstacle( m_loc, inFront ) ) {
AdjustVelocityToAvoidObstacles (); AdjustVelocityToAvoidObstacles ();
} }
} }
void AdjustVelocityToAvoidObstacles () void AdjustVelocityToAvoidObstacles ()
{ {
for( int i = 1; i < 5; i++ ) { for( int i = 1; i < 5; i++ ) {
Vector3 normVel = Vector3.Normalize(m_vel); Vector3 normVel = Vector3.Normalize(m_vel);
int xDelta = m_rndnums.Next (-i, i); int xDelta = m_rndnums.Next (-i, i);
int yDelta = m_rndnums.Next (-i, i); int yDelta = m_rndnums.Next (-i, i);
int zDelta = m_rndnums.Next (-i, i); int zDelta = m_rndnums.Next (-i, i);
normVel.X += xDelta; normVel.X += xDelta;
normVel.Y += yDelta; normVel.Y += yDelta;
normVel.Z += zDelta; normVel.Z += zDelta;
Vector3 inFront = m_loc + Vector3.Multiply(normVel, m_model.Tolerance); Vector3 inFront = m_loc + Vector3.Multiply(normVel, m_model.Tolerance);
if( !m_flowMap.WouldHitObstacle( m_loc, inFront ) ) { if( !m_flowMap.WouldHitObstacle( m_loc, inFront ) ) {
m_vel.X += xDelta; m_vel.X += xDelta;
m_vel.Y += yDelta; m_vel.Y += yDelta;
m_vel.Z += zDelta; m_vel.Z += zDelta;
//m_log.Info("avoided"); //m_log.Info("avoided");
return; return;
} }
} }
//m_log.Info("didn't avoid"); //m_log.Info("didn't avoid");
// try increaing our acceleration // try increaing our acceleration
// or try decreasing our acceleration // or try decreasing our acceleration
// or turn around - coz where we came from was OK // or turn around - coz where we came from was OK
if (m_loc.X < m_regionBorder || m_loc.X > m_regionX - m_regionBorder) if (m_loc.X < m_regionBorder || m_loc.X > m_regionX - m_regionBorder)
m_vel.X = -m_vel.X; m_vel.X = -m_vel.X;
if (m_loc.Y < m_regionBorder || m_loc.Y > m_regionY - m_regionBorder) if (m_loc.Y < m_regionBorder || m_loc.Y > m_regionY - m_regionBorder)
m_vel.Y = -m_vel.Y; m_vel.Y = -m_vel.Y;
if (m_loc.Z < 21 || m_loc.Z > m_regionZ ) if (m_loc.Z < 21 || m_loc.Z > m_regionZ )
m_vel.Z = -m_vel.Z; m_vel.Z = -m_vel.Z;
} }
/// <summary> /// <summary>
/// Separate ourselves from the specified birds. /// Separate ourselves from the specified birds.
/// keeps us a respectable distance from our closest neighbours whilst still /// keeps us a respectable distance from our closest neighbours whilst still
/// being part of our local flock /// being part of our local flock
/// </summary> /// </summary>
/// <param name='birds'> /// <param name='birds'>
/// Birds. all the birds in the scene /// Birds. all the birds in the scene
/// </param> /// </param>
Vector3 Separate (List<Bird> birds) Vector3 Separate (List<Bird> birds)
{ {
Vector3 steer = new Vector3 (0, 0, 0); Vector3 steer = new Vector3 (0, 0, 0);
int count = 0; int count = 0;
// For every bird in the system, check if it's too close // For every bird in the system, check if it's too close
foreach (Bird other in birds) { foreach (Bird other in birds) {
float d = Vector3.Distance (m_loc, other.Location); float d = Vector3.Distance (m_loc, other.Location);
// If the distance is greater than 0 and less than an arbitrary amount (0 when you are yourself) // If the distance is greater than 0 and less than an arbitrary amount (0 when you are yourself)
if ((d > 0) && (d < m_model.DesiredSeparation)) { if ((d > 0) && (d < m_model.DesiredSeparation)) {
// Calculate vector pointing away from neighbor // Calculate vector pointing away from neighbor
Vector3 diff = Vector3.Subtract (m_loc, other.Location); Vector3 diff = Vector3.Subtract (m_loc, other.Location);
diff.Normalize (); diff.Normalize ();
diff = Vector3.Divide (diff, d); diff = Vector3.Divide (diff, d);
steer = Vector3.Add (steer, diff); steer = Vector3.Add (steer, diff);
count++; // Keep track of how many count++; // Keep track of how many
} }
} }
// Average -- divide by how many // Average -- divide by how many
if (count > 0) { if (count > 0) {
steer /= (float)count; steer /= (float)count;
} }
// As long as the vector is greater than 0 // As long as the vector is greater than 0
if (steer.Length () > 0) { if (steer.Length () > 0) {
// Implement Reynolds: Steering = Desired - Velocity // Implement Reynolds: Steering = Desired - Velocity
steer.Normalize (); steer.Normalize ();
steer *= m_model.MaxSpeed; steer *= m_model.MaxSpeed;
steer -= m_vel; steer -= m_vel;
//steer.limit(maxforce); //steer.limit(maxforce);
steer = BirdsUtil.Limit (steer, m_model.MaxForce); steer = BirdsUtil.Limit (steer, m_model.MaxForce);
} }
return steer; return steer;
} }
/// <summary> /// <summary>
/// Align our bird within the flock. /// Align our bird within the flock.
/// For every nearby bird in the system, calculate the average velocity /// For every nearby bird in the system, calculate the average velocity
/// and move us towards that - this keeps us moving with the flock. /// and move us towards that - this keeps us moving with the flock.
/// </summary> /// </summary>
/// <param name='birds'> /// <param name='birds'>
/// Birds. all the birds in the scene - we only really care about those in the neighbourdist /// Birds. all the birds in the scene - we only really care about those in the neighbourdist
/// </param> /// </param>
Vector3 Align (List<Bird> birds) Vector3 Align (List<Bird> birds)
{ {
Vector3 steer = new Vector3 (0, 0, 0); Vector3 steer = new Vector3 (0, 0, 0);
int count = 0; int count = 0;
foreach (Bird other in birds) { foreach (Bird other in birds) {
float d = Vector3.Distance (m_loc, other.Location); float d = Vector3.Distance (m_loc, other.Location);
if ((d > 0) && (d < m_model.NeighbourDistance)) { if ((d > 0) && (d < m_model.NeighbourDistance)) {
steer += other.Velocity; steer += other.Velocity;
count++; count++;
} }
} }
if (count > 0) { if (count > 0) {
steer /= (float)count; steer /= (float)count;
} }
// As long as the vector is greater than 0 // As long as the vector is greater than 0
if (steer.Length () > 0) { if (steer.Length () > 0) {
// Implement Reynolds: Steering = Desired - Velocity // Implement Reynolds: Steering = Desired - Velocity
steer.Normalize (); steer.Normalize ();
steer *= m_model.MaxSpeed; steer *= m_model.MaxSpeed;
steer -= m_vel; steer -= m_vel;
//steer.limit(maxforce); //steer.limit(maxforce);
steer = BirdsUtil.Limit (steer, m_model.MaxForce); steer = BirdsUtil.Limit (steer, m_model.MaxForce);
} }
return steer; return steer;
} }
/// <summary> /// <summary>
/// MAintain the cohesion of our local flock /// MAintain the cohesion of our local flock
/// For the average location (i.e. center) of all nearby birds, calculate our steering vector towards that location /// For the average location (i.e. center) of all nearby birds, calculate our steering vector towards that location
/// </summary> /// </summary>
/// <param name='birds'> /// <param name='birds'>
/// Birds. the birds in the scene /// Birds. the birds in the scene
/// </param> /// </param>
Vector3 Cohesion (List<Bird> birds) Vector3 Cohesion (List<Bird> birds)
{ {
Vector3 sum = Vector3.Zero; // Start with empty vector to accumulate all locations Vector3 sum = Vector3.Zero; // Start with empty vector to accumulate all locations
int count = 0; int count = 0;
foreach (Bird other in birds) { foreach (Bird other in birds) {
float d = Vector3.Distance (m_loc, other.Location); float d = Vector3.Distance (m_loc, other.Location);
if ((d > 0) && (d < m_model.NeighbourDistance)) { if ((d > 0) && (d < m_model.NeighbourDistance)) {
sum += other.Location; // Add location sum += other.Location; // Add location
count++; count++;
} }
} }
if (count > 0) { if (count > 0) {
sum /= (float)count; sum /= (float)count;
return Steer (sum, false); // Steer towards the location return Steer (sum, false); // Steer towards the location
} }
return sum; return sum;
} }
} }
} }

View File

@ -30,23 +30,23 @@ using OpenMetaverse;
namespace Flocking namespace Flocking
{ {
public class BirdsUtil public class BirdsUtil
{ {
public static Vector3 Limit (Vector3 initial, float maxLen) public static Vector3 Limit (Vector3 initial, float maxLen)
{ {
float currLen = initial.Length (); float currLen = initial.Length ();
float ratio = 1.0f; float ratio = 1.0f;
if (currLen > maxLen) { if (currLen > maxLen) {
ratio = currLen / maxLen; ratio = currLen / maxLen;
} }
return initial /= ratio; return initial /= ratio;
} }
} }
} }

View File

@ -31,105 +31,105 @@ using OpenMetaverse;
namespace Flocking namespace Flocking
{ {
public class FlockingModel public class FlockingModel
{ {
private List<Bird> m_flock = new List<Bird>(); private List<Bird> m_flock = new List<Bird>();
private FlowMap m_flowMap; private FlowMap m_flowMap;
private float m_maxSpeed; private float m_maxSpeed;
private float m_maxForce; private float m_maxForce;
private float m_neighbourDistance; private float m_neighbourDistance;
private float m_desiredSeparation; private float m_desiredSeparation;
private float m_tolerance; private float m_tolerance;
private float m_border; private float m_border;
private string m_name; private string m_name;
private Random m_rnd = new Random(Environment.TickCount); private Random m_rnd = new Random(Environment.TickCount);
public int Size { public int Size {
get {return m_flock.Count;} get {return m_flock.Count;}
set { set {
//if( value < m_flock.Count ) { //if( value < m_flock.Count ) {
// m_flock.RemoveRange( 0, m_flock.Count - value ); // m_flock.RemoveRange( 0, m_flock.Count - value );
//} else //} else
m_flock = new List<Bird>(); m_flock = new List<Bird>();
while( value > m_flock.Count ) { while( value > m_flock.Count ) {
AddBird(m_name + m_flock.Count); AddBird(m_name + m_flock.Count);
} }
} }
} }
public FlockingModel(string moduleName, float maxSpeed, float maxForce, float neighbourDistance, float desiredSeparation, float tolerance, float border) { public FlockingModel(string moduleName, float maxSpeed, float maxForce, float neighbourDistance, float desiredSeparation, float tolerance, float border) {
m_name = moduleName; m_name = moduleName;
m_maxSpeed = maxSpeed; m_maxSpeed = maxSpeed;
m_maxForce = maxForce; m_maxForce = maxForce;
m_neighbourDistance = neighbourDistance; m_neighbourDistance = neighbourDistance;
m_desiredSeparation = desiredSeparation; m_desiredSeparation = desiredSeparation;
m_tolerance = tolerance; m_tolerance = tolerance;
m_border = border; m_border = border;
} }
void AddBird (string name) void AddBird (string name)
{ {
Bird Bird = new Bird (name, this, m_flowMap); Bird Bird = new Bird (name, this, m_flowMap);
// find an initial random location for this Bird // find an initial random location for this Bird
// somewhere not within an obstacle // somewhere not within an obstacle
int xInit = m_rnd.Next(m_flowMap.LengthX); int xInit = m_rnd.Next(m_flowMap.LengthX);
int yInit = m_rnd.Next(m_flowMap.LengthY); int yInit = m_rnd.Next(m_flowMap.LengthY);
int zInit = m_rnd.Next(m_flowMap.LengthZ); int zInit = m_rnd.Next(m_flowMap.LengthZ);
while( m_flowMap.IsWithinObstacle( xInit, yInit, zInit ) ){ while( m_flowMap.IsWithinObstacle( xInit, yInit, zInit ) ){
xInit = m_rnd.Next(m_flowMap.LengthX); xInit = m_rnd.Next(m_flowMap.LengthX);
yInit = m_rnd.Next(m_flowMap.LengthY); yInit = m_rnd.Next(m_flowMap.LengthY);
zInit = m_rnd.Next(m_flowMap.LengthZ); zInit = m_rnd.Next(m_flowMap.LengthZ);
} }
Bird.Location = new Vector3 (Convert.ToSingle(xInit), Convert.ToSingle(yInit), Convert.ToSingle(zInit)); Bird.Location = new Vector3 (Convert.ToSingle(xInit), Convert.ToSingle(yInit), Convert.ToSingle(zInit));
m_flock.Add (Bird); m_flock.Add (Bird);
} }
public float MaxSpeed { public float MaxSpeed {
get {return m_maxSpeed;} get {return m_maxSpeed;}
set { m_maxSpeed = value; } set { m_maxSpeed = value; }
} }
public float MaxForce { public float MaxForce {
get {return m_maxForce;} get {return m_maxForce;}
set { m_maxForce = value; } set { m_maxForce = value; }
} }
public float NeighbourDistance { public float NeighbourDistance {
get {return m_neighbourDistance;} get {return m_neighbourDistance;}
set { m_neighbourDistance = value; } set { m_neighbourDistance = value; }
} }
public float DesiredSeparation { public float DesiredSeparation {
get {return m_desiredSeparation;} get {return m_desiredSeparation;}
set { m_desiredSeparation = value; } set { m_desiredSeparation = value; }
} }
public float Tolerance { public float Tolerance {
get {return m_tolerance;} get {return m_tolerance;}
set { m_tolerance = value; } set { m_tolerance = value; }
} }
public void Initialise (int num, FlowMap flowMap) public void Initialise (int num, FlowMap flowMap)
{ {
m_flowMap = flowMap; m_flowMap = flowMap;
for (int i = 0; i < num; i++) { for (int i = 0; i < num; i++) {
AddBird (m_name + i ); AddBird (m_name + i );
} }
} }
public List<Bird> UpdateFlockPos () public List<Bird> UpdateFlockPos ()
{ {
foreach (Bird b in m_flock) { foreach (Bird b in m_flock) {
b.MoveInSceneRelativeToFlock(m_flock); // Passing the entire list of Birds to each Bird individually b.MoveInSceneRelativeToFlock(m_flock); // Passing the entire list of Birds to each Bird individually
} }
return m_flock; return m_flock;
} }
} }
} }

View File

@ -43,8 +43,10 @@ using OpenSim.Framework.Console;
using Mono.Addins; using Mono.Addins;
using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list; using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
[assembly: Addin("OpenSimBirds", "0.2")] [assembly: Addin("OpenSimBirds", OpenSim.VersionInfo.VersionNumber + "0.3")]
[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)] [assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)]
[assembly: AddinDescription("OpenSimBirds module.")]
[assembly: AddinAuthor("Jak Daniels")]
namespace Flocking namespace Flocking
{ {
@ -58,22 +60,22 @@ namespace Flocking
private string m_regionConfigDir = ""; private string m_regionConfigDir = "";
private Scene m_scene; private Scene m_scene;
private ICommandConsole m_console; private ICommandConsole m_console;
private FlockingModel m_model; private FlockingModel m_model;
private FlockingView m_view; private FlockingView m_view;
private bool m_startup = true; private bool m_enabled = false;
private bool m_enabled = false; private bool m_startup = false;
private bool m_ready = false; private bool m_ready = false;
private uint m_frame = 0; private uint m_frame = 0;
private int m_frameUpdateRate = 1; private int m_frameUpdateRate = 1;
private int m_chatChannel = 118; private int m_chatChannel = 118;
private string m_birdPrim; private string m_birdPrim;
private int m_flockSize = 50; private int m_flockSize = 50;
private int m_maxFlockSize = 100; private int m_maxFlockSize = 100;
private float m_maxSpeed; private float m_maxSpeed;
private float m_maxForce; private float m_maxForce;
private float m_neighbourDistance; private float m_neighbourDistance;
private float m_desiredSeparation; private float m_desiredSeparation;
private float m_tolerance; private float m_tolerance;
private float m_borderSize; private float m_borderSize;
private int m_maxHeight; private int m_maxHeight;
private Vector3 m_shoutPos = new Vector3(128f, 128f, 30f); private Vector3 m_shoutPos = new Vector3(128f, 128f, 30f);
@ -82,7 +84,7 @@ namespace Flocking
public IConfigSource m_config; public IConfigSource m_config;
private UUID m_owner; private UUID m_owner;
#endregion #endregion
#region IRegionModuleBase implementation #region IRegionModuleBase implementation
@ -92,12 +94,12 @@ namespace Flocking
public bool IsSharedModule { get { return false; } } public bool IsSharedModule { get { return false; } }
public void Initialise (IConfigSource source) public void Initialise (IConfigSource source)
{ {
m_config = source; m_config = source;
} }
public void AddRegion (Scene scene) public void AddRegion (Scene scene)
{ {
IConfig cnf; IConfig cnf;
m_log.InfoFormat("[{0}]: Adding region {1} to this module", m_name, scene.RegionInfo.RegionName); m_log.InfoFormat("[{0}]: Adding region {1} to this module", m_name, scene.RegionInfo.RegionName);
@ -108,12 +110,12 @@ namespace Flocking
if (cnf == null) if (cnf == null)
{ {
m_log.InfoFormat("[{0}]: No region section [{1}] found in addon-modules/{2}/config/*.ini configuration files.", m_name, scene.RegionInfo.RegionName, m_name); m_log.InfoFormat("[{0}]: No region section [{1}] found in {2} configuration file.", m_name, scene.RegionInfo.RegionName, m_regionConfigDir);
//string moduleConfigFile = Path.Combine(Util.configDir(),m_name + ".ini"); //string moduleConfigFile = Path.Combine(Util.configDir(),m_name + ".ini");
string moduleConfigFile = Path.Combine(m_regionConfigDir, "Regions.ini"); string moduleConfigFile = Path.Combine(m_regionConfigDir, "Regions.ini");
try try
{ {
m_log.InfoFormat("[{0}]: Checking {1} for [{2}] section containing valid config keys", m_name, moduleConfigFile, scene.RegionInfo.RegionName); m_log.InfoFormat("[{0}]: Checking {1} for [{2}] section", m_name, moduleConfigFile, scene.RegionInfo.RegionName);
m_config = new IniConfigSource(moduleConfigFile); m_config = new IniConfigSource(moduleConfigFile);
cnf = m_config.Configs[scene.RegionInfo.RegionName]; cnf = m_config.Configs[scene.RegionInfo.RegionName];
} }
@ -124,18 +126,23 @@ namespace Flocking
if (cnf == null) if (cnf == null)
{ {
m_log.InfoFormat("[{0}]: No region section [{1}] found in configuration {2}. Birds in this region are set to Disabled", m_name, scene.RegionInfo.RegionName, moduleConfigFile); m_log.InfoFormat("[{0}]: No region section [{1}] found in configuration {2}.", m_name, scene.RegionInfo.RegionName, moduleConfigFile);
m_enabled = false;
return; cnf = m_config.Configs[scene.RegionInfo.RegionName];
if (cnf == null)
{
m_log.InfoFormat("[{0}]: No region section [{1}] found in main configuration. Module is disabled.", m_name, scene.RegionInfo.RegionName);
return;
}
} }
} }
m_startup = cnf.GetBoolean("BirdsModuleStartup", true); m_enabled = cnf.GetBoolean("BirdsModuleEnabled", false);
if (m_startup) if (m_enabled)
{ {
m_scene = scene; m_scene = scene;
m_enabled = cnf.GetBoolean("BirdsEnabled", false); m_startup = cnf.GetBoolean("BirdsShowOnStartup", false);
m_chatChannel = cnf.GetInt("BirdsChatChannel", 118); m_chatChannel = cnf.GetInt("BirdsChatChannel", 118);
m_birdPrim = cnf.GetString("BirdsPrim", "birdPrim"); m_birdPrim = cnf.GetString("BirdsPrim", "birdPrim");
m_flockSize = cnf.GetInt("BirdsFlockSize", 20); m_flockSize = cnf.GetInt("BirdsFlockSize", 20);
@ -185,7 +192,7 @@ namespace Flocking
m_log.InfoFormat("[{0}] No command security was defined in the config. Any user may possibly configure this module from a script!", m_name); m_log.InfoFormat("[{0}] No command security was defined in the config. Any user may possibly configure this module from a script!", m_name);
} }
m_log.InfoFormat("[{0}] Module is {1} listening for commands on channel {2} with Flock Size {3}", m_name, m_enabled ? "enabled and" : "disabled, but still", m_chatChannel, m_flockSize); m_log.InfoFormat("[{0}] Module is {1} listening for commands on channel {2} with Flock Size {3}", m_name, m_startup ? "enabled and" : "disabled, but still", m_chatChannel, m_flockSize);
m_console = MainConsole.Instance; m_console = MainConsole.Instance;
//register commands with the scene //register commands with the scene
@ -205,19 +212,18 @@ namespace Flocking
m_shoutPos = new Vector3(scene.RegionInfo.RegionSizeX / 2f, scene.RegionInfo.RegionSizeY / 2f, 30f); m_shoutPos = new Vector3(scene.RegionInfo.RegionSizeX / 2f, scene.RegionInfo.RegionSizeY / 2f, 30f);
FlockInitialise(); FlockInitialise();
} }
else m_log.InfoFormat("[{0}] Module is disabled in Region {1}", m_name, scene.RegionInfo.RegionName); else m_log.InfoFormat("[{0}] Module is disabled in region {1}", m_name, scene.RegionInfo.RegionName);
} }
public void RegionLoaded (Scene scene) public void RegionLoaded (Scene scene)
{ {
if (m_startup) if (m_enabled)
{ {
// Mark Module Ready for duty // Mark Module Ready for duty
m_ready = true; m_ready = true;
} }
} }
public void PrimsLoaded(Scene scene) public void PrimsLoaded(Scene scene)
{ {
@ -225,22 +231,22 @@ namespace Flocking
ClearPersisted(); ClearPersisted();
} }
public void RemoveRegion (Scene scene) public void RemoveRegion (Scene scene)
{ {
m_log.InfoFormat("[{0}]: Removing region {1} from this module", m_name, scene.RegionInfo.RegionName); m_log.InfoFormat("[{0}]: Removing region {1} from this module", m_name, scene.RegionInfo.RegionName);
if (m_startup) { if (m_enabled) {
m_view.Clear(); m_view.Clear();
scene.EventManager.OnFrame -= FlockUpdate; scene.EventManager.OnFrame -= FlockUpdate;
scene.EventManager.OnChatFromClient -= SimChatSent; scene.EventManager.OnChatFromClient -= SimChatSent;
scene.EventManager.OnChatFromWorld -= SimChatSent; scene.EventManager.OnChatFromWorld -= SimChatSent;
scene.EventManager.OnPrimsLoaded -= PrimsLoaded; scene.EventManager.OnPrimsLoaded -= PrimsLoaded;
m_ready = false; m_ready = false;
} }
} }
public void Close() public void Close()
{ {
if (m_startup) if (m_enabled)
{ {
m_scene.EventManager.OnFrame -= FlockUpdate; m_scene.EventManager.OnFrame -= FlockUpdate;
m_scene.EventManager.OnChatFromClient -= SimChatSent; m_scene.EventManager.OnChatFromClient -= SimChatSent;
@ -250,7 +256,7 @@ namespace Flocking
} }
} }
#endregion #endregion
#region Helpers #region Helpers
@ -292,25 +298,25 @@ namespace Flocking
#region EventHandlers #region EventHandlers
public void FlockUpdate () public void FlockUpdate ()
{ {
if (!m_ready || !m_enabled || ((m_frame++ % m_frameUpdateRate) != 0)) if (!m_ready || !m_startup || ((m_frame++ % m_frameUpdateRate) != 0))
{ {
return; return;
} }
//m_log.InfoFormat("update my birds"); //m_log.InfoFormat("update my birds");
// work out where everyone has moved to // work out where everyone has moved to
// and tell the scene to render the new positions // and tell the scene to render the new positions
lock( m_sync ) { lock( m_sync ) {
List<Bird > birds = m_model.UpdateFlockPos (); List<Bird > birds = m_model.UpdateFlockPos ();
m_view.Render (birds); m_view.Render (birds);
} }
} }
protected void SimChatSent (Object x, OSChatMessage msg) protected void SimChatSent (Object x, OSChatMessage msg)
{ {
if (msg.Channel != m_chatChannel) return; // not for us if (msg.Channel != m_chatChannel) return; // not for us
if (m_allowedControllers.Count > 0) if (m_allowedControllers.Count > 0)
{ {
bool reject = true; bool reject = true;
@ -325,27 +331,27 @@ namespace Flocking
if (reject) return; //not for us if (reject) return; //not for us
} }
// try and parse a valid cmd from this msg // try and parse a valid cmd from this msg
string cmd = msg.Message; //.ToLower (); string cmd = msg.Message; //.ToLower ();
//stick ui in the args so we know to respond in world //stick ui in the args so we know to respond in world
//bit of a hack - but lets us use CommandDelegate inWorld //bit of a hack - but lets us use CommandDelegate inWorld
string[] args = (cmd + " <ui>").Split (" ".ToCharArray ()); string[] args = (cmd + " <ui>").Split (" ".ToCharArray ());
if (cmd.StartsWith ("stop")) { if (cmd.StartsWith ("stop")) {
HandleStopCmd (m_name, args); HandleStopCmd (m_name, args);
} else if (cmd.StartsWith ("start")) { } else if (cmd.StartsWith ("start")) {
HandleStartCmd (m_name, args); HandleStartCmd (m_name, args);
} else if (cmd.StartsWith("enable")) { } else if (cmd.StartsWith("enable")) {
HandleEnableCmd(m_name, args); HandleEnableCmd(m_name, args);
} else if (cmd.StartsWith("disable")) { } else if (cmd.StartsWith("disable")) {
HandleDisableCmd(m_name, args); HandleDisableCmd(m_name, args);
} else if (cmd.StartsWith ("size")) { } else if (cmd.StartsWith ("size")) {
HandleSetSizeCmd (m_name, args); HandleSetSizeCmd (m_name, args);
} else if (cmd.StartsWith ("stats")) { } else if (cmd.StartsWith ("stats")) {
HandleShowStatsCmd (m_name, args); HandleShowStatsCmd (m_name, args);
} else if (cmd.StartsWith ("prim")) { } else if (cmd.StartsWith ("prim")) {
HandleSetPrimCmd (m_name, args); HandleSetPrimCmd (m_name, args);
} else if (cmd.StartsWith("speed")) { } else if (cmd.StartsWith("speed")) {
HandleSetMaxSpeedCmd(m_name, args); HandleSetMaxSpeedCmd(m_name, args);
} else if (cmd.StartsWith("force")) { } else if (cmd.StartsWith("force")) {
@ -356,36 +362,35 @@ namespace Flocking
HandleSetDesiredSeparationCmd(m_name, args); HandleSetDesiredSeparationCmd(m_name, args);
} else if (cmd.StartsWith("tolerance")) { } else if (cmd.StartsWith("tolerance")) {
HandleSetToleranceCmd(m_name, args); HandleSetToleranceCmd(m_name, args);
} else if (cmd.StartsWith ("framerate")) { } else if (cmd.StartsWith ("framerate")) {
HandleSetFrameRateCmd (m_name, args); HandleSetFrameRateCmd (m_name, args);
} }
}
} #endregion
#endregion #region Command Handling
#region Command Handling private void AddCommand (string cmd, string args, string help, CommandDelegate fn)
{
private void AddCommand (string cmd, string args, string help, CommandDelegate fn) string argStr = "";
{ if (args.Trim ().Length > 0) {
string argStr = ""; argStr = " <" + args + "> ";
if (args.Trim ().Length > 0) { }
argStr = " <" + args + "> ";
}
m_log.InfoFormat("[{0}]: Adding console command {1} - {2} to region {3}", m_name, "birds-" + cmd + argStr, help, m_scene.RegionInfo.RegionName); m_log.InfoFormat("[{0}]: Adding console 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_scene.AddCommand (this, "birds-" + cmd, "birds-" + cmd + argStr, help, fn);
m_console.Commands.AddCommand(m_name, false, "birds-" + cmd, "birds-" + cmd + argStr, help, fn); m_console.Commands.AddCommand(m_name, false, "birds-" + cmd, "birds-" + cmd + argStr, help, fn);
} }
private void RegisterCommands () private void RegisterCommands ()
{ {
AddCommand ("stop", "", "Stop Birds Flocking", HandleStopCmd); AddCommand("stop", "", "Stop Birds Flocking", HandleStopCmd);
AddCommand ("start", "", "Start Birds Flocking", HandleStartCmd); AddCommand("start", "", "Start Birds Flocking", HandleStartCmd);
AddCommand ("enable", "", "Enable Birds Flocking", HandleEnableCmd); AddCommand("enable", "", "Enable Birds Flocking", HandleEnableCmd);
AddCommand ("disable", "", "Disable Birds Flocking", HandleDisableCmd); AddCommand("disable", "", "Disable Birds Flocking", HandleDisableCmd);
AddCommand ("size", "num", "Adjust the size of the flock ", HandleSetSizeCmd); AddCommand("size", "num", "Adjust the size of the flock ", HandleSetSizeCmd);
AddCommand ("prim", "name", "Set the prim used for each bird to that passed in", HandleSetPrimCmd); AddCommand("prim", "name", "Set the prim used for each bird to that passed in", HandleSetPrimCmd);
AddCommand ("speed", "num", "Set the maximum velocity each bird may achieve", HandleSetMaxSpeedCmd); AddCommand("speed", "num", "Set the maximum velocity each bird may achieve", HandleSetMaxSpeedCmd);
AddCommand("force", "num", "Set the maximum force each bird may accelerate", HandleSetMaxForceCmd); AddCommand("force", "num", "Set the maximum force each bird may accelerate", HandleSetMaxForceCmd);
AddCommand("distance", "num", "Set the maximum distance that other birds are to be considered in the same flock as us", HandleSetNeighbourDistanceCmd); AddCommand("distance", "num", "Set the maximum distance that other birds are to be considered in the same flock as us", HandleSetNeighbourDistanceCmd);
AddCommand("separation", "num", "How far away from other birds we would like to stay", HandleSetDesiredSeparationCmd); AddCommand("separation", "num", "How far away from other birds we would like to stay", HandleSetDesiredSeparationCmd);
@ -400,7 +405,6 @@ namespace Flocking
if (comms != null) if (comms != null)
{ {
comms.RegisterScriptInvocation(this, "birdsGetStats"); comms.RegisterScriptInvocation(this, "birdsGetStats");
} }
} }
@ -409,35 +413,36 @@ namespace Flocking
return ""; //currently a placeholder return ""; //currently a placeholder
} }
private bool ShouldHandleCmd () private bool ShouldHandleCmd ()
{ {
if (!(m_console.ConsoleScene == null || m_console.ConsoleScene == m_scene)) { if (!(m_console.ConsoleScene == null || m_console.ConsoleScene == m_scene)) {
return false; return false;
} }
return true; return true;
} }
private bool IsInWorldCmd (ref string [] args) private bool IsInWorldCmd (ref string [] args)
{ {
if (args.Length > 0 && args [args.Length - 1].Equals ("<ui>")) { if (args.Length > 0 && args [args.Length - 1].Equals ("<ui>")) {
m_log.InfoFormat("[{0}]: Inworld command detected in region {1}", m_name, m_scene.RegionInfo.RegionName); m_log.InfoFormat("[{0}]: Inworld command detected in region {1}", m_name, m_scene.RegionInfo.RegionName);
return true; return true;
} }
return false; return false;
} }
private void ShowResponse (string response, bool inWorld) private void ShowResponse (string response, bool inWorld)
{ {
if (inWorld) { if (inWorld) {
//IClientAPI ownerAPI = null; //IClientAPI ownerAPI = null;
//if (m_scene.TryGetClient (m_owner, out ownerAPI)) { //if (m_scene.TryGetClient (m_owner, out ownerAPI)) {
// ownerAPI.SendBlueBoxMessage (m_owner, "Birds", response); // ownerAPI.SendBlueBoxMessage (m_owner, "Birds", response);
//} //}
SendSimChat(response, m_chatChannel); SendSimChat(response, m_chatChannel);
} else { } else {
MainConsole.Instance.Output (response); if (m_ready)
} MainConsole.Instance.Output (response);
} }
}
private void SendSimChat(string msg, int channel) private void SendSimChat(string msg, int channel)
{ {
@ -448,7 +453,7 @@ namespace Flocking
{ {
if (m_ready && ShouldHandleCmd ()) { if (m_ready && ShouldHandleCmd ()) {
m_log.InfoFormat("[{0}]: Bird flocking is disabled in region {1}.", m_name, m_scene.RegionInfo.RegionName); m_log.InfoFormat("[{0}]: Bird flocking is disabled in region {1}.", m_name, m_scene.RegionInfo.RegionName);
m_enabled = false; m_startup = false;
//m_ready = false; //m_ready = false;
m_view.Clear(); m_view.Clear();
} }
@ -459,60 +464,59 @@ namespace Flocking
if (m_ready && ShouldHandleCmd()) if (m_ready && ShouldHandleCmd())
{ {
m_log.InfoFormat("[{0}]: Bird flocking is enabled in region {1}.", m_name, m_scene.RegionInfo.RegionName); m_log.InfoFormat("[{0}]: Bird flocking is enabled in region {1}.", m_name, m_scene.RegionInfo.RegionName);
m_enabled = true; m_startup = true;
//m_ready = true; //m_ready = true;
} }
} }
public void HandleStopCmd (string module, string[] args) public void HandleStopCmd (string module, string[] args)
{ {
if (m_enabled && m_ready && ShouldHandleCmd()) if (m_startup && m_ready && ShouldHandleCmd())
{ {
m_log.InfoFormat("[{0}]: Bird flocking is stopped in region {1}.", m_name, m_scene.RegionInfo.RegionName); m_log.InfoFormat("[{0}]: Bird flocking is stopped in region {1}.", m_name, m_scene.RegionInfo.RegionName);
m_enabled = false; m_startup = false;
} }
} }
public void HandleStartCmd(string module, string[] args) public void HandleStartCmd(string module, string[] args)
{ {
if (!m_enabled && m_ready && ShouldHandleCmd()) if (!m_startup && m_ready && ShouldHandleCmd())
{ {
m_log.InfoFormat("[{0}]: Bird flocking is started in region {1}.", m_name, m_scene.RegionInfo.RegionName); m_log.InfoFormat("[{0}]: Bird flocking is started in region {1}.", m_name, m_scene.RegionInfo.RegionName);
m_enabled = true; m_startup = true;
FlockUpdate(); FlockUpdate();
} }
} }
void HandleSetFrameRateCmd (string module, string[] args) void HandleSetFrameRateCmd (string module, string[] args)
{ {
if (m_ready && ShouldHandleCmd()) if (m_ready && ShouldHandleCmd())
{ {
int frameRate = Convert.ToInt32( args[1] ); int frameRate = Convert.ToInt32( args[1] );
m_frameUpdateRate = frameRate; m_frameUpdateRate = frameRate;
m_log.InfoFormat("[{0}]: Bird updates set to every {1} frames in region {2}.", m_name, frameRate, m_scene.RegionInfo.RegionName); m_log.InfoFormat("[{0}]: Bird updates set to every {1} frames in region {2}.", m_name, frameRate, m_scene.RegionInfo.RegionName);
} }
} }
public void HandleSetSizeCmd (string module, string[] args) public void HandleSetSizeCmd (string module, string[] args)
{ {
if (m_ready && ShouldHandleCmd()) if (m_ready && ShouldHandleCmd())
{ {
lock( m_sync ) { lock( m_sync ) {
int newSize = Convert.ToInt32(args[1]); int newSize = Convert.ToInt32(args[1]);
if (newSize > m_maxFlockSize) newSize = m_maxFlockSize; if (newSize > m_maxFlockSize) newSize = m_maxFlockSize;
m_view.Clear(); m_view.Clear();
m_model.Size = newSize; m_model.Size = newSize;
m_log.InfoFormat("[{0}]: Bird flock size is set to {1} in region {2}.", m_name, newSize, m_scene.RegionInfo.RegionName); m_log.InfoFormat("[{0}]: Bird flock size is set to {1} in region {2}.", m_name, newSize, m_scene.RegionInfo.RegionName);
}
}
}
} public void HandleShowStatsCmd (string module, string[] args)
} {
}
public void HandleShowStatsCmd (string module, string[] args)
{
if (m_ready && ShouldHandleCmd()) if (m_ready && ShouldHandleCmd())
{ {
bool inWorld = IsInWorldCmd (ref args); bool inWorld = IsInWorldCmd (ref args);
int i; int i;
int s=m_model.Size; int s=m_model.Size;
UUID primUuid; UUID primUuid;
@ -523,8 +527,8 @@ namespace Flocking
m_log.InfoFormat("[{0}]: Sending bird statistics to region {1}.", m_name, m_scene.RegionInfo.RegionName); m_log.InfoFormat("[{0}]: Sending bird statistics to region {1}.", m_name, m_scene.RegionInfo.RegionName);
} }
ShowResponse("birds-started = " + (m_enabled ? "True" : "False"), inWorld); ShowResponse("birds-enabled = " + (m_enabled ? "True" : "False"), inWorld);
ShowResponse("birds-enabled = " + (m_ready ? "True" : "False"), inWorld); ShowResponse("birds-startup = " + (m_ready ? "True" : "False"), inWorld);
ShowResponse("birds-prim = " + m_view.BirdPrim, inWorld); ShowResponse("birds-prim = " + m_view.BirdPrim, inWorld);
ShowResponse("birds-framerate = " + m_frameUpdateRate, inWorld); ShowResponse("birds-framerate = " + m_frameUpdateRate, inWorld);
ShowResponse("birds-maxsize = " + m_maxFlockSize, inWorld); ShowResponse("birds-maxsize = " + m_maxFlockSize, inWorld);
@ -560,21 +564,21 @@ namespace Flocking
ShowResponse("birds-prim" + i + " = " + m_name + i + " : " + primUuid.ToString() + " : " + avUuids.Trim(), inWorld); ShowResponse("birds-prim" + i + " = " + m_name + i + " : " + primUuid.ToString() + " : " + avUuids.Trim(), inWorld);
} }
} }
} }
public void HandleSetPrimCmd (string module, string[] args) public void HandleSetPrimCmd (string module, string[] args)
{ {
if (m_ready && ShouldHandleCmd()) if (m_ready && ShouldHandleCmd())
{ {
string primName = args[1]; string primName = args[1];
lock(m_sync) { lock(m_sync) {
m_view.BirdPrim = primName; m_view.BirdPrim = primName;
m_log.InfoFormat("[{0}]: Bird prim is set to {1} in region {2}.", m_name, primName, m_scene.RegionInfo.RegionName); m_log.InfoFormat("[{0}]: Bird prim is set to {1} in region {2}.", m_name, primName, m_scene.RegionInfo.RegionName);
m_view.Clear(); m_view.Clear();
} }
} }
} }
public void HandleSetMaxSpeedCmd(string module, string[] args) public void HandleSetMaxSpeedCmd(string module, string[] args)
{ {
@ -641,8 +645,6 @@ namespace Flocking
} }
} }
#endregion #endregion
}
}
} }

View File

@ -34,34 +34,34 @@ using log4net;
namespace Flocking namespace Flocking
{ {
public class FlockingView public class FlockingView
{ {
private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private Scene m_scene; private Scene m_scene;
private UUID m_owner; private UUID m_owner;
private String m_name; private String m_name;
private String m_birdPrim; private String m_birdPrim;
private Dictionary<string, SceneObjectGroup> m_sogMap = new Dictionary<string, SceneObjectGroup> (); private Dictionary<string, SceneObjectGroup> m_sogMap = new Dictionary<string, SceneObjectGroup> ();
public FlockingView (String moduleName, Scene scene) public FlockingView (String moduleName, Scene scene)
{ {
m_name = moduleName; m_name = moduleName;
m_scene = scene; m_scene = scene;
} }
public void PostInitialize (UUID owner) public void PostInitialize (UUID owner)
{ {
m_owner = owner; m_owner = owner;
} }
public String BirdPrim { public String BirdPrim {
get { return m_birdPrim; } get { return m_birdPrim; }
set{ m_birdPrim = value;} set{ m_birdPrim = value;}
} }
public void Clear () public void Clear ()
{ {
//trash everything we have //trash everything we have
foreach (string name in m_sogMap.Keys) foreach (string name in m_sogMap.Keys)
{ {
@ -71,103 +71,103 @@ namespace Flocking
} }
m_sogMap.Clear(); m_sogMap.Clear();
m_scene.ForceClientUpdate(); m_scene.ForceClientUpdate();
} }
public void Render(List<Bird> birds) public void Render(List<Bird> birds)
{ {
foreach (Bird bird in birds) { foreach (Bird bird in birds) {
DrawBird (bird); DrawBird (bird);
} }
} }
private void DrawBird (Bird bird) private void DrawBird (Bird bird)
{ {
SceneObjectPart existing = m_scene.GetSceneObjectPart (bird.Id); SceneObjectPart existing = m_scene.GetSceneObjectPart (bird.Id);
SceneObjectGroup sog; SceneObjectGroup sog;
SceneObjectPart rootPart; SceneObjectPart rootPart;
if (existing == null) { if (existing == null) {
m_log.InfoFormat("[{0}]: Adding prim {1} in region {2}", m_name, bird.Id, m_scene.RegionInfo.RegionName); m_log.InfoFormat("[{0}]: Adding prim {1} in region {2}", m_name, bird.Id, m_scene.RegionInfo.RegionName);
SceneObjectGroup group = findByName (m_birdPrim); SceneObjectGroup group = findByName (m_birdPrim);
sog = CopyPrim (group, bird.Id); sog = CopyPrim (group, bird.Id);
rootPart = sog.RootPart; rootPart = sog.RootPart;
rootPart.AddFlag(PrimFlags.Temporary); rootPart.AddFlag(PrimFlags.Temporary);
rootPart.AddFlag(PrimFlags.Phantom); rootPart.AddFlag(PrimFlags.Phantom);
//set prim to phantom //set prim to phantom
//sog.UpdatePrimFlags(rootPart.LocalId, false, false, true, false); //sog.UpdatePrimFlags(rootPart.LocalId, false, false, true, false);
m_sogMap [bird.Id] = sog; m_sogMap [bird.Id] = sog;
m_scene.AddNewSceneObject (sog, false); m_scene.AddNewSceneObject (sog, false);
// Fire script on_rez // Fire script on_rez
sog.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 1); sog.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 1);
rootPart.ParentGroup.ResumeScripts(); rootPart.ParentGroup.ResumeScripts();
rootPart.ScheduleFullUpdate(); rootPart.ScheduleFullUpdate();
sog.DetachFromBackup(); sog.DetachFromBackup();
} else { } else {
sog = existing.ParentGroup; sog = existing.ParentGroup;
m_sogMap[bird.Id] = sog; m_sogMap[bird.Id] = sog;
//rootPart = sog.RootPart; //rootPart = sog.RootPart;
//set prim to phantom //set prim to phantom
//sog.UpdatePrimFlags(rootPart.LocalId, false, false, true, false); //sog.UpdatePrimFlags(rootPart.LocalId, false, false, true, false);
} }
Quaternion rotation = CalcRotationToEndpoint (sog, sog.AbsolutePosition, bird.Location); Quaternion rotation = CalcRotationToEndpoint (sog, sog.AbsolutePosition, bird.Location);
sog.UpdateGroupRotationPR( bird.Location, rotation); sog.UpdateGroupRotationPR( bird.Location, rotation);
} }
private static Quaternion CalcRotationToEndpoint (SceneObjectGroup copy, Vector3 sv, Vector3 ev) private static Quaternion CalcRotationToEndpoint (SceneObjectGroup copy, Vector3 sv, Vector3 ev)
{ {
//llSetRot(llRotBetween(<1,0,0>,llVecNorm(targetPosition - llGetPos()))); //llSetRot(llRotBetween(<1,0,0>,llVecNorm(targetPosition - llGetPos())));
// bird wil fly x forwards and Z up // bird wil fly x forwards and Z up
Vector3 currDirVec = Vector3.UnitX; Vector3 currDirVec = Vector3.UnitX;
Vector3 desiredDirVec = Vector3.Subtract (ev, sv); Vector3 desiredDirVec = Vector3.Subtract (ev, sv);
desiredDirVec.Normalize (); desiredDirVec.Normalize ();
Quaternion rot = Vector3.RotationBetween (currDirVec, desiredDirVec); Quaternion rot = Vector3.RotationBetween (currDirVec, desiredDirVec);
return rot; return rot;
} }
private SceneObjectGroup CopyPrim (SceneObjectGroup prim, string name) private SceneObjectGroup CopyPrim (SceneObjectGroup prim, string name)
{ {
SceneObjectGroup copy = prim.Copy (true); SceneObjectGroup copy = prim.Copy (true);
copy.Name = name; copy.Name = name;
copy.DetachFromBackup (); copy.DetachFromBackup ();
return copy; return copy;
} }
private SceneObjectGroup findByName (string name) private SceneObjectGroup findByName (string name)
{ {
SceneObjectGroup retVal = null; SceneObjectGroup retVal = null;
foreach (EntityBase e in m_scene.GetEntities()) { foreach (EntityBase e in m_scene.GetEntities()) {
if (e.Name == name) { if (e.Name == name) {
retVal = (SceneObjectGroup)e; retVal = (SceneObjectGroup)e;
break; break;
} }
} }
// can't find it so make a default one // can't find it so make a default one
if (retVal == null) { if (retVal == null) {
m_log.InfoFormat("[{0}]: Prim named {1} was not found in region {2}. Making default wooden sphere.", m_name, name, m_scene.RegionInfo.RegionName); m_log.InfoFormat("[{0}]: Prim named {1} was not found in region {2}. Making default wooden sphere.", m_name, name, m_scene.RegionInfo.RegionName);
retVal = MakeDefaultPrim (name); retVal = MakeDefaultPrim (name);
} }
return retVal; return retVal;
} }
private SceneObjectGroup MakeDefaultPrim (string name) private SceneObjectGroup MakeDefaultPrim (string name)
{ {
PrimitiveBaseShape shape = PrimitiveBaseShape.CreateSphere (); 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.Name = name;
prim.DetachFromBackup (); prim.DetachFromBackup ();
m_scene.AddNewSceneObject (prim, false); m_scene.AddNewSceneObject (prim, false);
return prim; return prim;
} }
} }
} }

View File

@ -32,169 +32,169 @@ using OpenSim.Region.Framework.Scenes;
namespace Flocking namespace Flocking
{ {
public class FlowMap public class FlowMap
{ {
private Scene m_scene; private Scene m_scene;
private float[, ,] m_flowMap; private float[, ,] m_flowMap;
private uint regionX; private uint regionX;
private uint regionY; private uint regionY;
private uint regionZ; private uint regionZ;
private float regionBorder; private float regionBorder;
public FlowMap (Scene scene, int maxHeight, float borderSize) public FlowMap (Scene scene, int maxHeight, float borderSize)
{ {
m_scene = scene; m_scene = scene;
regionX = m_scene.RegionInfo.RegionSizeX; regionX = m_scene.RegionInfo.RegionSizeX;
regionY = m_scene.RegionInfo.RegionSizeY; regionY = m_scene.RegionInfo.RegionSizeY;
regionZ = (uint)maxHeight; regionZ = (uint)maxHeight;
regionBorder = borderSize; regionBorder = borderSize;
m_flowMap = new float[regionX, regionY, regionZ]; m_flowMap = new float[regionX, regionY, regionZ];
} }
public int LengthX { public int LengthX {
get {return (int)regionX;} get {return (int)regionX;}
} }
public int LengthY { public int LengthY {
get {return (int)regionY;} get {return (int)regionY;}
} }
public int LengthZ { public int LengthZ {
get {return (int)regionZ;} get {return (int)regionZ;}
} }
public int Border { public int Border {
get {return (int)regionBorder;} get {return (int)regionBorder;}
} }
public void Initialise() { public void Initialise() {
//fill in the boundaries //fill in the boundaries
for( int x = 0; x < regionX; x++ ) { for( int x = 0; x < regionX; x++ ) {
for( int y = 0; y < regionY; y++ ) { for( int y = 0; y < regionY; y++ ) {
m_flowMap[x,y,0] = 100f; m_flowMap[x,y,0] = 100f;
m_flowMap[x,y, regionZ-1] = 100f; m_flowMap[x,y, regionZ-1] = 100f;
} }
} }
for( int x = 0; x < regionX; x++ ) { for( int x = 0; x < regionX; x++ ) {
for( int z = 0; z < regionZ; z++ ) { for( int z = 0; z < regionZ; z++ ) {
m_flowMap[x,0,z] = 100f; m_flowMap[x,0,z] = 100f;
m_flowMap[x,regionY-1,z] = 100f; m_flowMap[x,regionY-1,z] = 100f;
} }
} }
for( int y = 0; y < regionY; y++ ) { for( int y = 0; y < regionY; y++ ) {
for( int z = 0; z < regionZ; z++ ) { for( int z = 0; z < regionZ; z++ ) {
m_flowMap[0,y,z] = 100f; m_flowMap[0,y,z] = 100f;
m_flowMap[regionX-1,y,z] = 100f; m_flowMap[regionX-1,y,z] = 100f;
} }
} }
//fill in the terrain //fill in the terrain
for( int x = 0; x < regionX; x++ ) { for( int x = 0; x < regionX; x++ ) {
for( int y = 0; y < regionY; y++ ) { for( int y = 0; y < regionY; y++ ) {
int zMax = Convert.ToInt32(m_scene.GetGroundHeight( x, y )); int zMax = Convert.ToInt32(m_scene.GetGroundHeight( x, y ));
for( int z = 1; z < zMax; z++ ) { for( int z = 1; z < zMax; z++ ) {
m_flowMap[x,y,z] = 100f; m_flowMap[x,y,z] = 100f;
} }
} }
} }
// fill in the things // fill in the things
foreach( EntityBase entity in m_scene.GetEntities() ) { foreach( EntityBase entity in m_scene.GetEntities() ) {
if( entity is SceneObjectGroup ) { if( entity is SceneObjectGroup ) {
SceneObjectGroup sog = (SceneObjectGroup)entity; SceneObjectGroup sog = (SceneObjectGroup)entity;
//todo: ignore phantom //todo: ignore phantom
float fmaxX, fminX, fmaxY, fminY, fmaxZ, fminZ; float fmaxX, fminX, fmaxY, fminY, fmaxZ, fminZ;
int maxX, minX, maxY, minY, maxZ, minZ; int maxX, minX, maxY, minY, maxZ, minZ;
sog.GetAxisAlignedBoundingBoxRaw( out fminX, out fmaxX, out fminY, out fmaxY, out fminZ, out fmaxZ ); sog.GetAxisAlignedBoundingBoxRaw( out fminX, out fmaxX, out fminY, out fmaxY, out fminZ, out fmaxZ );
minX = Convert.ToInt32(fminX); minX = Convert.ToInt32(fminX);
maxX = Convert.ToInt32(fmaxX); maxX = Convert.ToInt32(fmaxX);
minY = Convert.ToInt32(fminY); minY = Convert.ToInt32(fminY);
maxY = Convert.ToInt32(fmaxX); maxY = Convert.ToInt32(fmaxX);
minZ = Convert.ToInt32(fminZ); minZ = Convert.ToInt32(fminZ);
maxZ = Convert.ToInt32(fmaxZ); maxZ = Convert.ToInt32(fmaxZ);
for( int x = minX; x < maxX; x++ ) { for( int x = minX; x < maxX; x++ ) {
for( int y = minY; y < maxY; y++ ) { for( int y = minY; y < maxY; y++ ) {
for( int z = minZ; z < maxZ; z++ ) { for( int z = minZ; z < maxZ; z++ ) {
m_flowMap[x,y,z] = 100f; m_flowMap[x,y,z] = 100f;
} }
} }
} }
} }
} }
} }
public bool WouldHitObstacle (Vector3 currPos, Vector3 targetPos) public bool WouldHitObstacle (Vector3 currPos, Vector3 targetPos)
{ {
bool retVal = false; bool retVal = false;
//fail fast //fail fast
if( IsOutOfBounds(targetPos) ) { if( IsOutOfBounds(targetPos) ) {
retVal = true; retVal = true;
} else if( IsWithinObstacle(targetPos) ) { } else if( IsWithinObstacle(targetPos) ) {
retVal = true; retVal = true;
} else if( IntersectsObstacle (currPos, targetPos) ) { } else if( IntersectsObstacle (currPos, targetPos) ) {
retVal = true; retVal = true;
} }
return retVal; return retVal;
} }
public bool IsOutOfBounds(Vector3 targetPos) { public bool IsOutOfBounds(Vector3 targetPos) {
bool retVal = false; bool retVal = false;
if( targetPos.X < regionBorder || if( targetPos.X < regionBorder ||
targetPos.X > regionX - regionBorder || targetPos.X > regionX - regionBorder ||
targetPos.Y < regionBorder || targetPos.Y < regionBorder ||
targetPos.Y > regionY - regionBorder || targetPos.Y > regionY - regionBorder ||
targetPos.Z < regionBorder || targetPos.Z < regionBorder ||
targetPos.Z > regionZ - regionBorder ) { targetPos.Z > regionZ - regionBorder ) {
retVal = true; retVal = true;
} }
return retVal; return retVal;
} }
public bool IntersectsObstacle (Vector3 currPos, Vector3 targetPos) public bool IntersectsObstacle (Vector3 currPos, Vector3 targetPos)
{ {
bool retVal = false; bool retVal = false;
// Ray trace the Vector and fail as soon as we hit something // Ray trace the Vector and fail as soon as we hit something
Vector3 direction = targetPos - currPos; Vector3 direction = targetPos - currPos;
float length = direction.Length(); float length = direction.Length();
// check every metre // check every metre
for( float i = 1f; i < length; i += 1f ) { for( float i = 1f; i < length; i += 1f ) {
Vector3 rayPos = currPos + ( direction * i ); Vector3 rayPos = currPos + ( direction * i );
//give up if we go OOB on this ray //give up if we go OOB on this ray
if( IsOutOfBounds( rayPos ) ){ if( IsOutOfBounds( rayPos ) ){
retVal = true; retVal = true;
break; break;
} }
else if( IsWithinObstacle( rayPos ) ) { else if( IsWithinObstacle( rayPos ) ) {
retVal = true; retVal = true;
break; break;
} }
} }
return retVal; return retVal;
} }
public bool IsWithinObstacle( Vector3 targetPos ) { public bool IsWithinObstacle( Vector3 targetPos ) {
return IsWithinObstacle(Convert.ToInt32(targetPos.X), Convert.ToInt32(targetPos.Y),Convert.ToInt32(targetPos.Z)); return IsWithinObstacle(Convert.ToInt32(targetPos.X), Convert.ToInt32(targetPos.Y),Convert.ToInt32(targetPos.Z));
} }
public bool IsWithinObstacle( int x, int y, int z ) { public bool IsWithinObstacle( int x, int y, int z ) {
bool retVal = false; bool retVal = false;
if (x >= LengthX || y >= LengthY || z >= LengthZ) if (x >= LengthX || y >= LengthY || z >= LengthZ)
{ {
retVal = true; retVal = true;
} }
else if (x < 0 || y < 0 || z < 0) else if (x < 0 || y < 0 || z < 0)
{ {
retVal = true; retVal = true;
} else if (m_flowMap[x,y,z] > 50f) { } else if (m_flowMap[x,y,z] > 50f) {
retVal = true; retVal = true;
} }
return retVal; return retVal;
} }
} }
} }

View File

@ -60,8 +60,8 @@ Here is an example config:
[Test Region 1] [Test Region 1]
BirdsModuleStartup = True ;this is the default and determines whether the module does anything BirdsModuleEnabled = True ;this is the default and determines whether the module does anything
BirdsEnabled = True ;set to false to disable the birds from appearing in this region BirdsShowOnStartup = True ;set to false to disable the birds from appearing in this region
BirdsFlockSize = 50 ;the number of birds to flock BirdsFlockSize = 50 ;the number of birds to flock
BirdsMaxFlockSize = 100 ;the maximum flock size that can be created (keeps things sane) BirdsMaxFlockSize = 100 ;the maximum flock size that can be created (keeps things sane)
BirdsMaxSpeed = 3 ;how far each bird can travel per update BirdsMaxSpeed = 3 ;how far each bird can travel per update