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

View File

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

View File

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

View File

@ -43,8 +43,10 @@ using OpenSim.Framework.Console;
using Mono.Addins;
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: AddinDescription("OpenSimBirds module.")]
[assembly: AddinAuthor("Jak Daniels")]
namespace Flocking
{
@ -58,31 +60,31 @@ namespace Flocking
private string m_regionConfigDir = "";
private Scene m_scene;
private ICommandConsole m_console;
private FlockingModel m_model;
private FlockingView m_view;
private bool m_startup = true;
private bool m_enabled = false;
private bool m_ready = false;
private uint m_frame = 0;
private int m_frameUpdateRate = 1;
private int m_chatChannel = 118;
private string m_birdPrim;
private int m_flockSize = 50;
private FlockingModel m_model;
private FlockingView m_view;
private bool m_enabled = false;
private bool m_startup = false;
private bool m_ready = false;
private uint m_frame = 0;
private int m_frameUpdateRate = 1;
private int m_chatChannel = 118;
private string m_birdPrim;
private int m_flockSize = 50;
private int m_maxFlockSize = 100;
private float m_maxSpeed;
private float m_maxForce;
private float m_neighbourDistance;
private float m_desiredSeparation;
private float m_tolerance;
private float m_maxSpeed;
private float m_maxForce;
private float m_neighbourDistance;
private float m_desiredSeparation;
private float m_tolerance;
private float m_borderSize;
private int m_maxHeight;
private Vector3 m_shoutPos = new Vector3(128f, 128f, 30f);
private Vector3 m_shoutPos = new Vector3(128f, 128f, 30f);
static object m_sync = new object();
private List<UUID> m_allowedControllers = new List<UUID>();
public IConfigSource m_config;
private UUID m_owner;
private UUID m_owner;
#endregion
#region IRegionModuleBase implementation
@ -92,28 +94,28 @@ namespace Flocking
public bool IsSharedModule { get { return false; } }
public void Initialise (IConfigSource source)
{
{
m_config = source;
}
}
public void AddRegion (Scene scene)
{
public void AddRegion (Scene scene)
{
IConfig cnf;
m_log.InfoFormat("[{0}]: Adding region {1} to this module", m_name, scene.RegionInfo.RegionName);
cnf = m_config.Configs["Startup"];
m_regionConfigDir = cnf.GetString("regionload_regionsdir", Path.Combine(Util.configDir(), "bin/Regions/"));
cnf = m_config.Configs[scene.RegionInfo.RegionName];
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(m_regionConfigDir, "Regions.ini");
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);
cnf = m_config.Configs[scene.RegionInfo.RegionName];
}
@ -124,18 +126,23 @@ namespace Flocking
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_enabled = false;
return;
m_log.InfoFormat("[{0}]: No region section [{1}] found in configuration {2}.", m_name, scene.RegionInfo.RegionName, moduleConfigFile);
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_enabled = cnf.GetBoolean("BirdsEnabled", false);
m_startup = cnf.GetBoolean("BirdsShowOnStartup", false);
m_chatChannel = cnf.GetInt("BirdsChatChannel", 118);
m_birdPrim = cnf.GetString("BirdsPrim", "birdPrim");
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}] 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;
//register commands with the scene
@ -205,19 +212,18 @@ namespace Flocking
m_shoutPos = new Vector3(scene.RegionInfo.RegionSizeX / 2f, scene.RegionInfo.RegionSizeY / 2f, 30f);
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)
{
if (m_startup)
public void RegionLoaded (Scene scene)
{
if (m_enabled)
{
// Mark Module Ready for duty
m_ready = true;
}
}
m_ready = true;
}
}
public void PrimsLoaded(Scene scene)
{
@ -225,22 +231,22 @@ namespace Flocking
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);
if (m_startup) {
if (m_enabled) {
m_view.Clear();
scene.EventManager.OnFrame -= FlockUpdate;
scene.EventManager.OnChatFromClient -= SimChatSent;
scene.EventManager.OnFrame -= FlockUpdate;
scene.EventManager.OnChatFromClient -= SimChatSent;
scene.EventManager.OnChatFromWorld -= SimChatSent;
scene.EventManager.OnPrimsLoaded -= PrimsLoaded;
m_ready = false;
}
}
}
public void Close()
{
if (m_startup)
if (m_enabled)
{
m_scene.EventManager.OnFrame -= FlockUpdate;
m_scene.EventManager.OnChatFromClient -= SimChatSent;
@ -250,7 +256,7 @@ namespace Flocking
}
}
#endregion
#endregion
#region Helpers
@ -292,25 +298,25 @@ namespace Flocking
#region EventHandlers
public void FlockUpdate ()
{
if (!m_ready || !m_enabled || ((m_frame++ % m_frameUpdateRate) != 0))
{
if (!m_ready || !m_startup || ((m_frame++ % m_frameUpdateRate) != 0))
{
return;
}
//m_log.InfoFormat("update my birds");
// work out where everyone has moved to
// and tell the scene to render the new positions
lock( m_sync ) {
List<Bird > birds = m_model.UpdateFlockPos ();
m_view.Render (birds);
}
}
protected void SimChatSent (Object x, OSChatMessage msg)
{
if (msg.Channel != m_chatChannel) return; // not for us
return;
}
//m_log.InfoFormat("update my birds");
// work out where everyone has moved to
// and tell the scene to render the new positions
lock( m_sync ) {
List<Bird > birds = m_model.UpdateFlockPos ();
m_view.Render (birds);
}
}
protected void SimChatSent (Object x, OSChatMessage msg)
{
if (msg.Channel != m_chatChannel) return; // not for us
if (m_allowedControllers.Count > 0)
{
bool reject = true;
@ -325,27 +331,27 @@ namespace Flocking
if (reject) return; //not for us
}
// try and parse a valid cmd from this msg
string cmd = msg.Message; //.ToLower ();
//stick ui in the args so we know to respond in world
//bit of a hack - but lets us use CommandDelegate inWorld
string[] args = (cmd + " <ui>").Split (" ".ToCharArray ());
if (cmd.StartsWith ("stop")) {
HandleStopCmd (m_name, args);
} else if (cmd.StartsWith ("start")) {
HandleStartCmd (m_name, args);
// try and parse a valid cmd from this msg
string cmd = msg.Message; //.ToLower ();
//stick ui in the args so we know to respond in world
//bit of a hack - but lets us use CommandDelegate inWorld
string[] args = (cmd + " <ui>").Split (" ".ToCharArray ());
if (cmd.StartsWith ("stop")) {
HandleStopCmd (m_name, args);
} else if (cmd.StartsWith ("start")) {
HandleStartCmd (m_name, args);
} else if (cmd.StartsWith("enable")) {
HandleEnableCmd(m_name, args);
} else if (cmd.StartsWith("disable")) {
HandleDisableCmd(m_name, args);
} else if (cmd.StartsWith ("size")) {
HandleSetSizeCmd (m_name, args);
} else if (cmd.StartsWith ("stats")) {
HandleShowStatsCmd (m_name, args);
} else if (cmd.StartsWith ("prim")) {
HandleSetPrimCmd (m_name, args);
} else if (cmd.StartsWith ("size")) {
HandleSetSizeCmd (m_name, args);
} else if (cmd.StartsWith ("stats")) {
HandleShowStatsCmd (m_name, args);
} else if (cmd.StartsWith ("prim")) {
HandleSetPrimCmd (m_name, args);
} else if (cmd.StartsWith("speed")) {
HandleSetMaxSpeedCmd(m_name, args);
} else if (cmd.StartsWith("force")) {
@ -356,36 +362,35 @@ namespace Flocking
HandleSetDesiredSeparationCmd(m_name, args);
} else if (cmd.StartsWith("tolerance")) {
HandleSetToleranceCmd(m_name, args);
} else if (cmd.StartsWith ("framerate")) {
HandleSetFrameRateCmd (m_name, args);
}
}
} else if (cmd.StartsWith ("framerate")) {
HandleSetFrameRateCmd (m_name, args);
}
}
#endregion
#region Command Handling
private void AddCommand (string cmd, string args, string help, CommandDelegate fn)
{
string argStr = "";
if (args.Trim ().Length > 0) {
argStr = " <" + args + "> ";
}
#endregion
#region Command Handling
private void AddCommand (string cmd, string args, string help, CommandDelegate fn)
{
string argStr = "";
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_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 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 ("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);
private void RegisterCommands ()
{
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("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("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("separation", "num", "How far away from other birds we would like to stay", HandleSetDesiredSeparationCmd);
@ -400,7 +405,6 @@ namespace Flocking
if (comms != null)
{
comms.RegisterScriptInvocation(this, "birdsGetStats");
}
}
@ -408,36 +412,37 @@ namespace Flocking
{
return ""; //currently a placeholder
}
private bool ShouldHandleCmd ()
{
private bool ShouldHandleCmd ()
{
if (!(m_console.ConsoleScene == null || m_console.ConsoleScene == m_scene)) {
return false;
}
return true;
}
private bool IsInWorldCmd (ref string [] args)
{
if (args.Length > 0 && args [args.Length - 1].Equals ("<ui>")) {
}
private bool IsInWorldCmd (ref string [] args)
{
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);
return true;
}
return true;
}
return false;
}
private void ShowResponse (string response, bool inWorld)
{
if (inWorld) {
//IClientAPI ownerAPI = null;
//if (m_scene.TryGetClient (m_owner, out ownerAPI)) {
// ownerAPI.SendBlueBoxMessage (m_owner, "Birds", response);
//}
}
private void ShowResponse (string response, bool inWorld)
{
if (inWorld) {
//IClientAPI ownerAPI = null;
//if (m_scene.TryGetClient (m_owner, out ownerAPI)) {
// ownerAPI.SendBlueBoxMessage (m_owner, "Birds", response);
//}
SendSimChat(response, m_chatChannel);
} else {
MainConsole.Instance.Output (response);
}
}
} else {
if (m_ready)
MainConsole.Instance.Output (response);
}
}
private void SendSimChat(string msg, int channel)
{
@ -448,7 +453,7 @@ namespace Flocking
{
if (m_ready && ShouldHandleCmd ()) {
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_view.Clear();
}
@ -459,60 +464,59 @@ namespace Flocking
if (m_ready && ShouldHandleCmd())
{
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;
}
}
public void HandleStopCmd (string module, string[] args)
{
if (m_enabled && m_ready && ShouldHandleCmd())
public void HandleStopCmd (string module, string[] args)
{
if (m_startup && m_ready && ShouldHandleCmd())
{
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)
{
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_enabled = true;
m_startup = true;
FlockUpdate();
}
}
void HandleSetFrameRateCmd (string module, string[] args)
{
void HandleSetFrameRateCmd (string module, string[] args)
{
if (m_ready && ShouldHandleCmd())
{
int frameRate = Convert.ToInt32( args[1] );
m_frameUpdateRate = frameRate;
int frameRate = Convert.ToInt32( args[1] );
m_frameUpdateRate = frameRate;
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())
{
lock( m_sync ) {
int newSize = Convert.ToInt32(args[1]);
lock( m_sync ) {
int newSize = Convert.ToInt32(args[1]);
if (newSize > m_maxFlockSize) newSize = m_maxFlockSize;
m_view.Clear();
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);
}
}
}
public void HandleShowStatsCmd (string module, string[] args)
{
}
}
}
public void HandleShowStatsCmd (string module, string[] args)
{
if (m_ready && ShouldHandleCmd())
{
bool inWorld = IsInWorldCmd (ref args);
bool inWorld = IsInWorldCmd (ref args);
int i;
int s=m_model.Size;
UUID primUuid;
@ -523,8 +527,8 @@ namespace Flocking
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_ready ? "True" : "False"), inWorld);
ShowResponse("birds-enabled = " + (m_enabled ? "True" : "False"), inWorld);
ShowResponse("birds-startup = " + (m_ready ? "True" : "False"), inWorld);
ShowResponse("birds-prim = " + m_view.BirdPrim, inWorld);
ShowResponse("birds-framerate = " + m_frameUpdateRate, 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);
}
}
}
public void HandleSetPrimCmd (string module, string[] args)
{
}
}
public void HandleSetPrimCmd (string module, string[] args)
{
if (m_ready && ShouldHandleCmd())
{
string primName = args[1];
lock(m_sync) {
m_view.BirdPrim = primName;
string primName = args[1];
lock(m_sync) {
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_view.Clear();
}
}
}
m_view.Clear();
}
}
}
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
{
public class FlockingView
{
public class FlockingView
{
private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private Scene m_scene;
private UUID m_owner;
private UUID m_owner;
private String m_name;
private String m_birdPrim;
private Dictionary<string, SceneObjectGroup> m_sogMap = new Dictionary<string, SceneObjectGroup> ();
public FlockingView (String moduleName, Scene scene)
{
m_name = moduleName;
m_scene = scene;
}
public void PostInitialize (UUID owner)
{
m_owner = owner;
}
public String BirdPrim {
get { return m_birdPrim; }
set{ m_birdPrim = value;}
}
private String m_birdPrim;
public void Clear ()
{
private Dictionary<string, SceneObjectGroup> m_sogMap = new Dictionary<string, SceneObjectGroup> ();
public FlockingView (String moduleName, Scene scene)
{
m_name = moduleName;
m_scene = scene;
}
public void PostInitialize (UUID owner)
{
m_owner = owner;
}
public String BirdPrim {
get { return m_birdPrim; }
set{ m_birdPrim = value;}
}
public void Clear ()
{
//trash everything we have
foreach (string name in m_sogMap.Keys)
{
@ -71,103 +71,103 @@ namespace Flocking
}
m_sogMap.Clear();
m_scene.ForceClientUpdate();
}
}
public void Render(List<Bird> birds)
{
foreach (Bird bird in birds) {
DrawBird (bird);
}
}
private void DrawBird (Bird bird)
{
SceneObjectPart existing = m_scene.GetSceneObjectPart (bird.Id);
{
foreach (Bird bird in birds) {
DrawBird (bird);
}
}
private void DrawBird (Bird bird)
{
SceneObjectPart existing = m_scene.GetSceneObjectPart (bird.Id);
SceneObjectGroup sog;
SceneObjectGroup sog;
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);
SceneObjectGroup group = findByName (m_birdPrim);
sog = CopyPrim (group, bird.Id);
sog = CopyPrim (group, bird.Id);
rootPart = sog.RootPart;
rootPart.AddFlag(PrimFlags.Temporary);
rootPart.AddFlag(PrimFlags.Phantom);
//set prim to phantom
//sog.UpdatePrimFlags(rootPart.LocalId, false, false, true, false);
m_sogMap [bird.Id] = sog;
m_scene.AddNewSceneObject (sog, false);
m_sogMap [bird.Id] = sog;
m_scene.AddNewSceneObject (sog, false);
// Fire script on_rez
sog.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 1);
rootPart.ParentGroup.ResumeScripts();
rootPart.ScheduleFullUpdate();
sog.DetachFromBackup();
} else {
sog = existing.ParentGroup;
} else {
sog = existing.ParentGroup;
m_sogMap[bird.Id] = sog;
//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);
}
private static Quaternion CalcRotationToEndpoint (SceneObjectGroup copy, Vector3 sv, Vector3 ev)
{
//llSetRot(llRotBetween(<1,0,0>,llVecNorm(targetPosition - llGetPos())));
// bird wil fly x forwards and Z up
Vector3 currDirVec = Vector3.UnitX;
Vector3 desiredDirVec = Vector3.Subtract (ev, sv);
desiredDirVec.Normalize ();
}
Quaternion rot = Vector3.RotationBetween (currDirVec, desiredDirVec);
return rot;
}
private SceneObjectGroup CopyPrim (SceneObjectGroup prim, string name)
{
SceneObjectGroup copy = prim.Copy (true);
copy.Name = name;
copy.DetachFromBackup ();
return copy;
}
private SceneObjectGroup findByName (string name)
{
SceneObjectGroup retVal = null;
foreach (EntityBase e in m_scene.GetEntities()) {
if (e.Name == name) {
retVal = (SceneObjectGroup)e;
break;
}
}
// can't find it so make a default one
if (retVal == null) {
Quaternion rotation = CalcRotationToEndpoint (sog, sog.AbsolutePosition, bird.Location);
sog.UpdateGroupRotationPR( bird.Location, rotation);
}
private static Quaternion CalcRotationToEndpoint (SceneObjectGroup copy, Vector3 sv, Vector3 ev)
{
//llSetRot(llRotBetween(<1,0,0>,llVecNorm(targetPosition - llGetPos())));
// bird wil fly x forwards and Z up
Vector3 currDirVec = Vector3.UnitX;
Vector3 desiredDirVec = Vector3.Subtract (ev, sv);
desiredDirVec.Normalize ();
Quaternion rot = Vector3.RotationBetween (currDirVec, desiredDirVec);
return rot;
}
private SceneObjectGroup CopyPrim (SceneObjectGroup prim, string name)
{
SceneObjectGroup copy = prim.Copy (true);
copy.Name = name;
copy.DetachFromBackup ();
return copy;
}
private SceneObjectGroup findByName (string name)
{
SceneObjectGroup retVal = null;
foreach (EntityBase e in m_scene.GetEntities()) {
if (e.Name == name) {
retVal = (SceneObjectGroup)e;
break;
}
}
// can't find it so make a default one
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);
retVal = MakeDefaultPrim (name);
}
retVal = MakeDefaultPrim (name);
}
return retVal;
}
return retVal;
}
private SceneObjectGroup MakeDefaultPrim (string name)
{
PrimitiveBaseShape shape = PrimitiveBaseShape.CreateSphere ();
shape.Scale = new Vector3 (0.5f, 0.5f, 0.5f);
private SceneObjectGroup MakeDefaultPrim (string name)
{
PrimitiveBaseShape shape = PrimitiveBaseShape.CreateSphere ();
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);
prim.Name = name;
prim.DetachFromBackup ();
m_scene.AddNewSceneObject (prim, false);
prim.Name = name;
prim.DetachFromBackup ();
m_scene.AddNewSceneObject (prim, false);
return prim;
}
return prim;
}
}
}
}

View File

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

View File

@ -25,13 +25,13 @@ Configuration:
If you have the module added to or compiled with your OpenSim build then it will run a instance of itself once per region.
By default it will configure itself to some sensible defaults and will sit quietly in the background waiting for commands
from the console, or from in-world. It will not enable itself (i.e. rez some birds) until commanded to do so, or
configured to do so in the .ini file. It is possible to completely stop the module from doing anything (including
from the console, or from in-world. It will not enable itself (i.e. rez some birds) until commanded to do so, or
configured to do so in the .ini file. It is possible to completely stop the module from doing anything (including
listening for commands), but you must have a particular setting in the .ini file for that region (see below) - in other
words, you must have a config for it!
To become active, the module needs to be enabled in the ini file or commanded to do so from inworld or the console.
Otherwise it does nothing on startup except listen for commands. If you are running multiple regions on one simulator you
Otherwise it does nothing on startup except listen for commands. If you are running multiple regions on one simulator you
can have different Birds settings per region in the configuration file, in the exact same way you can customize per Region
setting in Regions.ini
@ -59,9 +59,9 @@ Here is an example config:
;; Set the Birds settings per named region
[Test Region 1]
BirdsModuleStartup = 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
BirdsModuleEnabled = True ;this is the default and determines whether the module does anything
BirdsShowOnStartup = True ;set to false to disable the birds from appearing in this region
BirdsFlockSize = 50 ;the number of birds to flock
BirdsMaxFlockSize = 100 ;the maximum flock size that can be created (keeps things sane)
BirdsMaxSpeed = 3 ;how far each bird can travel per update
@ -72,9 +72,9 @@ Here is an example config:
BirdsBorderSize = 5 ;how close to the edge of a region can we get?
BirdsMaxHeight = 256 ;how high are we allowed to flock
BirdsUpdateEveryNFrames = 1 ;update bird positions every N simulator frames
BirdsPrim = SeaGull1 ;By default the module will create a flock of plain wooden spheres,
BirdsPrim = SeaGull1 ;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.
;needs to already exist in the scene - i.e. be rezzed in the region.
;who is allowed to send commands via chat or script: list of UUIDs or ESTATE_OWNER or ESTATE_MANAGER
;or everyone if not specified
@ -94,7 +94,7 @@ Runtime Commands:
The following commands, which can be issued on the Console or via in-world chat or scripted chat on the BirdsChatChannel
to control the birds at runtime:
birds-stop or /118 stop ;stop all birds flocking
birds-stop or /118 stop ;stop all birds flocking
birds-start or /118 start ;start all birds flocking
birds-enable or /118 enable ;enable the flocking simulation if disabled and rez new birds
birds-disable or /118 disable ;stop all birds and remove them from the scene
@ -122,8 +122,8 @@ Security:
By default anyone can send commands to the module from within a script or via the in-world chat on the 'BirdsChatChannel' channel.
You should use a high negative value for channel if you want to allow script access, but not in-world chat. Further you can restrict
which users are allowed to control the module using the 'BirdsAllowedControllers' setting. This is a comma separated list of user UUIDs,
but it may also contain one of the pre-defined constants ESTATE_OWNER (evaluates to the UUID of the estate owner) and ESTATE_MANAGER
(evaluates to a list of estate manager UUIDS).
but it may also contain one of the pre-defined constants ESTATE_OWNER (evaluates to the UUID of the estate owner) and ESTATE_MANAGER
(evaluates to a list of estate manager UUIDS).
* For commands sent from in-world chat, it is the UUID of the avatar sending the command that is checked against the list.
* For commands sent from a script it is the UUID of the owner of the prim in which the script resides that is checked against the list.
@ -134,7 +134,7 @@ Any currently rezzed in-scene-object can be used as the bird prim. However fps i
complexity of the entity to use. It is easier to throw a single prim (or sculpty) around the scene than it is to
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
Tests show that <= 500 single prims can be flocked effectively - depending on system and network
However maybe <= 300 simple linksets can perform as well.
Network Traffic:
@ -186,9 +186,9 @@ is an example output:
In the above example, there is one avatar sitting on bird-prim18. For more than one avatar the UUID list will be separated by spaces.
Please Note:
Please Note:
This module is currently only tested against opensim master.
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