Merge 15cc0a45f9
into cd72e7b701
commit
90e2661c35
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
28
README.md
28
README.md
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue