fixed up in world command handling somewhat, added parser
parent
cdbac1c921
commit
c1109c1810
135
Flocking/Boid.cs
135
Flocking/Boid.cs
|
@ -28,6 +28,7 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using log4net;
|
using log4net;
|
||||||
using OpenMetaverse;
|
using OpenMetaverse;
|
||||||
|
using Utils = OpenSim.Framework.Util;
|
||||||
|
|
||||||
namespace Flocking
|
namespace Flocking
|
||||||
{
|
{
|
||||||
|
@ -74,7 +75,7 @@ namespace Flocking
|
||||||
public Vector3 Velocity {
|
public Vector3 Velocity {
|
||||||
get { return m_vel;}
|
get { return m_vel;}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String Id {
|
public String Id {
|
||||||
get {return m_id;}
|
get {return m_id;}
|
||||||
}
|
}
|
||||||
|
@ -85,10 +86,11 @@ namespace Flocking
|
||||||
/// <param name='boids'>
|
/// <param name='boids'>
|
||||||
/// Boids. all the other chaps in the scene
|
/// Boids. all the other chaps in the scene
|
||||||
/// </param>
|
/// </param>
|
||||||
public void MoveInSceneRelativeToFlock (List<Boid> boids)
|
public void MoveInSceneRelativeToFlock ()
|
||||||
{
|
{
|
||||||
|
List<Boid> neighbours = m_model.GetNeighbours(this);
|
||||||
// we would like to stay with our mates
|
// we would like to stay with our mates
|
||||||
Flock (boids);
|
Flock (neighbours);
|
||||||
|
|
||||||
// our first priority is to not hurt ourselves
|
// our first priority is to not hurt ourselves
|
||||||
// so adjust where we would like to go to avoid hitting things
|
// so adjust where we would like to go to avoid hitting things
|
||||||
|
@ -102,10 +104,9 @@ namespace Flocking
|
||||||
UpdatePositionInScene ();
|
UpdatePositionInScene ();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Move within our flock
|
/// Move within our local flock
|
||||||
///
|
|
||||||
/// We accumulate a new acceleration each time based on three rules
|
/// We accumulate a new acceleration each time based on three rules
|
||||||
/// these are:
|
/// these are:
|
||||||
/// our separation from our closest neighbours,
|
/// our separation from our closest neighbours,
|
||||||
|
@ -113,28 +114,22 @@ namespace Flocking
|
||||||
/// our desire to move towards the flock centre
|
/// our desire to move towards the flock centre
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void Flock (List<Boid> boids)
|
void Flock (List<Boid> neighbours)
|
||||||
{
|
{
|
||||||
|
|
||||||
// calc the force vectors on this boid
|
// calc the force vectors on this boid
|
||||||
Vector3 sep = Separate (boids); // Separation
|
Vector3 sep = Separate (neighbours); // Separation
|
||||||
Vector3 ali = Align (boids); // Alignment
|
Vector3 ali = Align (neighbours); // Alignment
|
||||||
Vector3 coh = Cohesion (boids); // Cohesion
|
Vector3 coh = Cohesion (neighbours); // Cohesion
|
||||||
|
|
||||||
// Arbitrarily weight these forces
|
// Arbitrarily weight these forces
|
||||||
//TODO: expose these consts
|
sep *= m_model.SeparationWeighting;
|
||||||
sep *= 1.5f; //.mult(1.5);
|
ali *= m_model.AlignmentWeighting;
|
||||||
//ali.mult(1.0);
|
coh *= m_model.CohesionWeighting;
|
||||||
ali *= 1.0f;
|
|
||||||
//coh.mult(1.0);
|
|
||||||
coh *= 1.0f;
|
|
||||||
|
|
||||||
// Add the force vectors to the current acceleration of the boid
|
// Add the force vectors to the current acceleration of the boid
|
||||||
//acc.add(sep);
|
|
||||||
m_acc += sep;
|
m_acc += sep;
|
||||||
//acc.add(ali);
|
|
||||||
m_acc += ali;
|
m_acc += ali;
|
||||||
//acc.add(coh);
|
|
||||||
m_acc += coh;
|
m_acc += coh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,10 +144,8 @@ namespace Flocking
|
||||||
void UpdatePositionInScene ()
|
void UpdatePositionInScene ()
|
||||||
{
|
{
|
||||||
// Update velocity
|
// Update velocity
|
||||||
//vel.add(acc);
|
|
||||||
m_vel += m_acc;
|
m_vel += m_acc;
|
||||||
// Limit speed
|
// Limit speed
|
||||||
//m_vel.limit(maxspeed);
|
|
||||||
m_vel = Util.Limit (m_vel, m_model.MaxSpeed);
|
m_vel = Util.Limit (m_vel, m_model.MaxSpeed);
|
||||||
m_loc += m_vel;
|
m_loc += m_vel;
|
||||||
// Reset accelertion to 0 each cycle
|
// Reset accelertion to 0 each cycle
|
||||||
|
@ -186,27 +179,24 @@ namespace Flocking
|
||||||
/// Takes a second argument, if true, it slows down as it approaches the target
|
/// Takes a second argument, if true, it slows down as it approaches the target
|
||||||
Vector3 Steer (Vector3 target, bool slowdown)
|
Vector3 Steer (Vector3 target, bool slowdown)
|
||||||
{
|
{
|
||||||
Vector3 steer; // The steering vector
|
Vector3 steer = Vector3.Zero; // The steering vector
|
||||||
Vector3 desired = Vector3.Subtract(target, m_loc); // A vector pointing from the location to the target
|
Vector3 desired = target - m_loc; // A vector pointing from the location to the target
|
||||||
float d = desired.Length (); // Distance from the target is the magnitude of the vector
|
float distance = desired.Length (); // Distance from the target is the magnitude of the vector
|
||||||
// If the distance is greater than 0, calc steering (otherwise return zero vector)
|
// If the distance is greater than 0, calc steering (otherwise return zero vector)
|
||||||
if (d > 0) {
|
if (distance > 0) {
|
||||||
// Normalize desired
|
// Normalize desired
|
||||||
desired.Normalize ();
|
desired.Normalize ();
|
||||||
// Two options for desired vector magnitude (1 -- based on distance, 2 -- maxspeed)
|
// Two options for desired vector magnitude (1 -- based on distance, 2 -- maxspeed)
|
||||||
if ((slowdown) && (d < 100.0f)) {
|
if ((slowdown) && (distance < m_model.LookaheadDistance )) {
|
||||||
desired *= (m_model.MaxSpeed * (d / 100.0f)); // This damping is somewhat arbitrary
|
desired *= (m_model.MaxSpeed * (distance / m_model.LookaheadDistance)); // This damping is somewhat arbitrary
|
||||||
} else {
|
} else {
|
||||||
desired *= m_model.MaxSpeed;
|
desired *= m_model.MaxSpeed;
|
||||||
}
|
}
|
||||||
// Steering = Desired minus Velocity
|
// Steering = Desired minus Velocity
|
||||||
//steer = target.sub(desired,m_vel);
|
steer = desired - m_vel;
|
||||||
steer = Vector3.Subtract (desired, m_vel);
|
|
||||||
//steer.limit(maxforce); // Limit to maximum steering force
|
//steer.limit(maxforce); // Limit to maximum steering force
|
||||||
steer = Util.Limit (steer, m_model.MaxForce);
|
steer = Util.Limit (steer, m_model.MaxForce);
|
||||||
} else {
|
}
|
||||||
steer = Vector3.Zero;
|
|
||||||
}
|
|
||||||
return steer;
|
return steer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,40 +216,37 @@ namespace Flocking
|
||||||
/// keeps us a respectable distance from our closest neighbours whilst still
|
/// keeps us a respectable distance from our closest neighbours whilst still
|
||||||
/// being part of our local flock
|
/// being part of our local flock
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name='boids'>
|
/// <param name='neighbours'>
|
||||||
/// Boids. all the boids in the scene
|
/// Boids. all the boids in the scene
|
||||||
/// </param>
|
/// </param>
|
||||||
Vector3 Separate (List<Boid> boids)
|
Vector3 Separate (List<Boid> neighbours)
|
||||||
{
|
{
|
||||||
Vector3 steer = new Vector3 (0, 0, 0);
|
|
||||||
int count = 0;
|
|
||||||
// For every boid in the system, check if it's too close
|
// For every boid in the system, check if it's too close
|
||||||
foreach (Boid other in boids) {
|
float desired = m_model.DesiredSeparation;
|
||||||
float d = Vector3.Distance (m_loc, other.Location);
|
//who are we too close to at the moment
|
||||||
// If the distance is greater than 0 and less than an arbitrary amount (0 when you are yourself)
|
List<Boid> tooCloseNeighbours = neighbours.FindAll( delegate(Boid neighbour) {
|
||||||
if ((d > 0) && (d < m_model.DesiredSeparation)) {
|
// Is the distance is less than an arbitrary amount
|
||||||
// Calculate vector pointing away from neighbor
|
return Utils.GetDistanceTo (m_loc, neighbour.Location) < desired;
|
||||||
Vector3 diff = Vector3.Subtract (m_loc, other.Location);
|
});
|
||||||
diff.Normalize ();
|
|
||||||
diff = Vector3.Divide (diff, d);
|
// move a bit away from them
|
||||||
steer = Vector3.Add (steer, diff);
|
Vector3 steer = Vector3.Zero;
|
||||||
count++; // Keep track of how many
|
tooCloseNeighbours.ForEach( delegate(Boid neighbour) {
|
||||||
}
|
// Calculate vector pointing away from neighbor
|
||||||
}
|
Vector3 diff = m_loc - neighbour.Location;
|
||||||
// Average -- divide by how many
|
steer += Utils.GetNormalizedVector(diff) / (float)Utils.GetDistanceTo (m_loc, neighbour.Location);
|
||||||
if (count > 0) {
|
});
|
||||||
steer /= (float)count;
|
|
||||||
}
|
if( steer.Length () > 0 ) {
|
||||||
|
// Average -- divide by how many
|
||||||
// As long as the vector is greater than 0
|
steer /= (float)tooCloseNeighbours.Count;
|
||||||
if (steer.Length () > 0) {
|
|
||||||
// Implement Reynolds: Steering = Desired - Velocity
|
// Implement Reynolds: Steering = Desired - Velocity
|
||||||
steer.Normalize ();
|
steer.Normalize ();
|
||||||
steer *= m_model.MaxSpeed;
|
steer *= m_model.MaxSpeed;
|
||||||
steer -= m_vel;
|
steer -= m_vel;
|
||||||
//steer.limit(maxforce);
|
//don't go too fast;
|
||||||
steer = Util.Limit (steer, m_model.MaxForce);
|
steer = Util.Limit (steer, m_model.MaxForce);
|
||||||
}
|
}
|
||||||
return steer;
|
return steer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -273,15 +260,14 @@ namespace Flocking
|
||||||
/// </param>
|
/// </param>
|
||||||
Vector3 Align (List<Boid> boids)
|
Vector3 Align (List<Boid> boids)
|
||||||
{
|
{
|
||||||
Vector3 steer = new Vector3 (0, 0, 0);
|
Vector3 steer = Vector3.Zero;
|
||||||
int count = 0;
|
|
||||||
foreach (Boid other in boids) {
|
boids.ForEach( delegate( Boid other ) {
|
||||||
float d = Vector3.Distance (m_loc, other.Location);
|
steer += other.Velocity;
|
||||||
if ((d > 0) && (d < m_model.NeighbourDistance)) {
|
});
|
||||||
steer += other.Velocity;
|
|
||||||
count++;
|
int count = boids.Count;
|
||||||
}
|
|
||||||
}
|
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
steer /= (float)count;
|
steer /= (float)count;
|
||||||
}
|
}
|
||||||
|
@ -303,22 +289,19 @@ namespace Flocking
|
||||||
/// MAintain the cohesion of our local flock
|
/// MAintain the cohesion of our local flock
|
||||||
/// For the average location (i.e. center) of all nearby boids, calculate our steering vector towards that location
|
/// For the average location (i.e. center) of all nearby boids, calculate our steering vector towards that location
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name='boids'>
|
/// <param name='neighbours'>
|
||||||
/// Boids. the boids in the scene
|
/// Boids. the boids in the scene
|
||||||
/// </param>
|
/// </param>
|
||||||
Vector3 Cohesion (List<Boid> boids)
|
Vector3 Cohesion (List<Boid> neighbours)
|
||||||
{
|
{
|
||||||
|
|
||||||
Vector3 sum = Vector3.Zero; // Start with empty vector to accumulate all locations
|
Vector3 sum = Vector3.Zero; // Start with empty vector to accumulate all locations
|
||||||
int count = 0;
|
|
||||||
|
|
||||||
foreach (Boid other in boids) {
|
neighbours.ForEach( delegate(Boid other) {
|
||||||
float d = Vector3.Distance (m_loc, other.Location);
|
sum += other.Location; // Add location
|
||||||
if ((d > 0) && (d < m_model.NeighbourDistance)) {
|
});
|
||||||
sum += other.Location; // Add location
|
|
||||||
count++;
|
int count = neighbours.Count;
|
||||||
}
|
|
||||||
}
|
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
sum /= (float)count;
|
sum /= (float)count;
|
||||||
return Steer (sum, false); // Steer towards the location
|
return Steer (sum, false); // Steer towards the location
|
||||||
|
|
|
@ -0,0 +1,127 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using log4net;
|
||||||
|
using OpenMetaverse;
|
||||||
|
using OpenSim.Framework;
|
||||||
|
using OpenSim.Region.Framework.Scenes;
|
||||||
|
using OpenSim.Framework.Console;
|
||||||
|
using OpenSim.Region.Framework.Interfaces;
|
||||||
|
|
||||||
|
namespace Flocking
|
||||||
|
{
|
||||||
|
public delegate void BoidCmdDelegate (string module,string[] args);
|
||||||
|
|
||||||
|
public class BoidCmdDefn
|
||||||
|
{
|
||||||
|
public string Help = "";
|
||||||
|
public string Args = "";
|
||||||
|
public int NumParams = 0;
|
||||||
|
string m_name;
|
||||||
|
|
||||||
|
public BoidCmdDefn (string name, string args, string help)
|
||||||
|
{
|
||||||
|
Help = help;
|
||||||
|
Args = args;
|
||||||
|
m_name = name;
|
||||||
|
|
||||||
|
if (args.Trim ().Length > 0) {
|
||||||
|
NumParams = args.Split (", ".ToCharArray ()).Length;
|
||||||
|
} else {
|
||||||
|
NumParams = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetSyntax ()
|
||||||
|
{
|
||||||
|
return m_name + " " + Args + " (" + Help + ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ChatCommandParser
|
||||||
|
{
|
||||||
|
private static readonly ILog m_log = LogManager.GetLogger (System.Reflection.MethodBase.GetCurrentMethod ().DeclaringType);
|
||||||
|
private string m_name;
|
||||||
|
private Scene m_scene;
|
||||||
|
private int m_chatChannel;
|
||||||
|
private Dictionary<string, BoidCmdDelegate> m_commandMap = new Dictionary<string, BoidCmdDelegate> ();
|
||||||
|
private Dictionary<string, BoidCmdDefn> m_syntaxMap = new Dictionary<string, BoidCmdDefn> ();
|
||||||
|
|
||||||
|
public ChatCommandParser (IRegionModuleBase module, Scene scene, int channel)
|
||||||
|
{
|
||||||
|
m_name = module.Name;
|
||||||
|
m_scene = scene;
|
||||||
|
m_chatChannel = channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddCommand (string cmd, string args, string help, CommandDelegate fn)
|
||||||
|
{
|
||||||
|
m_commandMap.Add (cmd, new BoidCmdDelegate (fn));
|
||||||
|
m_syntaxMap.Add (cmd, new BoidCmdDefn (cmd, args, help));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SimChatSent (Object x, OSChatMessage msg)
|
||||||
|
{
|
||||||
|
if (m_scene.ConsoleScene () != m_scene || msg.Channel != m_chatChannel)
|
||||||
|
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 ());
|
||||||
|
|
||||||
|
BoidCmdDefn defn = null;
|
||||||
|
if (m_syntaxMap.TryGetValue (args [0], out defn)) {
|
||||||
|
if (CorrectSignature (args, defn)) {
|
||||||
|
|
||||||
|
// we got the signature of the command right
|
||||||
|
BoidCmdDelegate del = null;
|
||||||
|
if (m_commandMap.TryGetValue (args [0], out del)) {
|
||||||
|
del (m_name, args);
|
||||||
|
} else {
|
||||||
|
// we don't understand this command
|
||||||
|
// shouldn't happen
|
||||||
|
m_log.ErrorFormat ("Unable to invoke command {0}", args [0]);
|
||||||
|
RespondToMessage (msg, "Unable to invoke command " + args [0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// we recognise the command, but we got the call wrong
|
||||||
|
RespondToMessage (msg, "wrong syntax: " + defn.GetSyntax ());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// this is not a command we recognise
|
||||||
|
RespondToMessage (msg, args [0] + " is not a valid command for osboids");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool CorrectSignature (string[] args, BoidCmdDefn defn)
|
||||||
|
{
|
||||||
|
// args contain cmd name at 0 and <ui> tagged in last pos
|
||||||
|
return args.Length - 2 == defn.NumParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RespondToMessage (OSChatMessage msg, string message)
|
||||||
|
{
|
||||||
|
m_log.Debug ("sending response -> " + message);
|
||||||
|
IClientAPI sender = msg.Sender;
|
||||||
|
sender.SendChatMessage (message, (byte)ChatTypeEnum.Say, msg.Position, "osboids", msg.SenderUUID, (byte)ChatSourceType.Agent, (byte)ChatAudibleLevel.Fully);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SendMessage (ScenePresence recipient, string message)
|
||||||
|
{
|
||||||
|
IClientAPI ownerAPI = recipient.ControllingClient;
|
||||||
|
ownerAPI.SendChatMessage (message,
|
||||||
|
(byte)ChatTypeEnum.Say,
|
||||||
|
recipient.AbsolutePosition,
|
||||||
|
"osboids",
|
||||||
|
recipient.UUID,
|
||||||
|
(byte)ChatSourceType.Agent,
|
||||||
|
(byte)ChatAudibleLevel.Fully
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
<include name="FlowFieldTest.cs" />
|
<include name="FlowFieldTest.cs" />
|
||||||
<include name="FlowMap.cs" />
|
<include name="FlowMap.cs" />
|
||||||
<include name="Util.cs" />
|
<include name="Util.cs" />
|
||||||
|
<include name="VectorTest.cs" />
|
||||||
</sources>
|
</sources>
|
||||||
<references basedir="${project::get-base-directory()}">
|
<references basedir="${project::get-base-directory()}">
|
||||||
<lib>
|
<lib>
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using OpenMetaverse;
|
using OpenMetaverse;
|
||||||
|
using Utils = OpenSim.Framework.Util;
|
||||||
|
|
||||||
namespace Flocking
|
namespace Flocking
|
||||||
{
|
{
|
||||||
|
@ -39,6 +40,11 @@ namespace Flocking
|
||||||
private float m_neighbourDistance;
|
private float m_neighbourDistance;
|
||||||
private float m_desiredSeparation;
|
private float m_desiredSeparation;
|
||||||
private float m_tolerance;
|
private float m_tolerance;
|
||||||
|
private float m_separationWeighting = 1.5f;
|
||||||
|
private float m_alignmentWeighting = 1f;
|
||||||
|
private float m_cohesionWeighting = 1f;
|
||||||
|
private float m_lookaheadDistance = 100f;
|
||||||
|
|
||||||
|
|
||||||
private Random m_rnd = new Random(Environment.TickCount);
|
private Random m_rnd = new Random(Environment.TickCount);
|
||||||
|
|
||||||
|
@ -95,6 +101,26 @@ namespace Flocking
|
||||||
get {return m_tolerance;}
|
get {return m_tolerance;}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public float SeparationWeighting {
|
||||||
|
get{ return m_separationWeighting; }
|
||||||
|
set{ m_separationWeighting = value;}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float AlignmentWeighting {
|
||||||
|
get{ return m_alignmentWeighting; }
|
||||||
|
set{ m_alignmentWeighting = value;}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float CohesionWeighting {
|
||||||
|
get{ return m_cohesionWeighting; }
|
||||||
|
set{ m_cohesionWeighting = value;}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float LookaheadDistance {
|
||||||
|
get { return m_lookaheadDistance; }
|
||||||
|
set { m_lookaheadDistance = value;}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public void Initialise (int num, FlowField flowField)
|
public void Initialise (int num, FlowField flowField)
|
||||||
{
|
{
|
||||||
|
@ -103,12 +129,19 @@ namespace Flocking
|
||||||
AddBoid ("boid"+i );
|
AddBoid ("boid"+i );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<Boid> GetNeighbours(Boid boid) {
|
||||||
|
return m_flock.FindAll(delegate(Boid other) {
|
||||||
|
return (boid != other) && (Utils.GetDistanceTo (boid.Location, other.Location) < m_neighbourDistance);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public List<Boid> UpdateFlockPos ()
|
public List<Boid> UpdateFlockPos ()
|
||||||
{
|
{
|
||||||
foreach (Boid b in m_flock) {
|
m_flock.ForEach( delegate(Boid boid) {
|
||||||
b.MoveInSceneRelativeToFlock(m_flock); // Passing the entire list of boids to each boid individually
|
boid.MoveInSceneRelativeToFlock();
|
||||||
}
|
} );
|
||||||
|
|
||||||
return m_flock;
|
return m_flock;
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,6 +60,11 @@ namespace Flocking
|
||||||
private float m_neighbourDistance;
|
private float m_neighbourDistance;
|
||||||
private float m_desiredSeparation;
|
private float m_desiredSeparation;
|
||||||
private float m_tolerance;
|
private float m_tolerance;
|
||||||
|
private float m_separationWeighting = 1.5f;
|
||||||
|
private float m_alignmentWeighting = 1f;
|
||||||
|
private float m_cohesionWeighting = 1f;
|
||||||
|
private float m_lookaheadDistance = 100f;
|
||||||
|
private ChatCommandParser m_chatCommandParser;
|
||||||
|
|
||||||
private UUID m_owner;
|
private UUID m_owner;
|
||||||
|
|
||||||
|
@ -81,6 +86,10 @@ namespace Flocking
|
||||||
m_neighbourDistance = config.GetFloat("neighbour-dist", 25f);
|
m_neighbourDistance = config.GetFloat("neighbour-dist", 25f);
|
||||||
m_desiredSeparation = config.GetFloat("desired-separation", 20f);
|
m_desiredSeparation = config.GetFloat("desired-separation", 20f);
|
||||||
m_tolerance = config.GetFloat("tolerance", 5f);
|
m_tolerance = config.GetFloat("tolerance", 5f);
|
||||||
|
m_separationWeighting = config.GetFloat("separation-weighting", 1.5f);
|
||||||
|
m_alignmentWeighting = config.GetFloat("alignment-weighting", 1f);
|
||||||
|
m_cohesionWeighting = config.GetFloat("cohesion-weighting", 1f);
|
||||||
|
m_lookaheadDistance = config.GetFloat("lookahead-dist",100f);
|
||||||
|
|
||||||
|
|
||||||
// we're in the config - so turn on this module
|
// we're in the config - so turn on this module
|
||||||
|
@ -94,27 +103,33 @@ namespace Flocking
|
||||||
m_scene = scene;
|
m_scene = scene;
|
||||||
if (m_enabled) {
|
if (m_enabled) {
|
||||||
//register commands
|
//register commands
|
||||||
|
m_chatCommandParser = new ChatCommandParser(this, scene, m_chatChannel);
|
||||||
RegisterCommands ();
|
RegisterCommands ();
|
||||||
|
|
||||||
//register handlers
|
//register handlers
|
||||||
m_scene.EventManager.OnFrame += FlockUpdate;
|
m_scene.EventManager.OnFrame += FlockUpdate;
|
||||||
m_scene.EventManager.OnChatFromClient += SimChatSent; //listen for commands sent from the client
|
m_scene.EventManager.OnChatFromClient += m_chatCommandParser.SimChatSent; //listen for commands sent from the client
|
||||||
|
|
||||||
// init module
|
// init module
|
||||||
m_model = new FlockingModel (m_maxSpeed, m_maxForce, m_neighbourDistance, m_desiredSeparation, m_tolerance);
|
m_model = new FlockingModel (m_maxSpeed, m_maxForce, m_neighbourDistance, m_desiredSeparation, m_tolerance);
|
||||||
|
m_model.SeparationWeighting = m_separationWeighting;
|
||||||
|
m_model.AlignmentWeighting = m_alignmentWeighting;
|
||||||
|
m_model.CohesionWeighting = m_cohesionWeighting;
|
||||||
|
m_model.LookaheadDistance = m_lookaheadDistance;
|
||||||
m_view = new FlockingView (m_scene);
|
m_view = new FlockingView (m_scene);
|
||||||
m_view.BoidPrim = m_boidPrim;
|
m_view.BoidPrim = m_boidPrim;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void chatCom (object sender, OSChatMessage chat)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public void RegionLoaded (Scene scene)
|
public void RegionLoaded (Scene scene)
|
||||||
{
|
{
|
||||||
if (m_enabled) {
|
if (m_enabled) {
|
||||||
|
|
||||||
//make a flow map for this scene
|
|
||||||
//FlowMap flowMap = new FlowMap(scene );
|
|
||||||
//flowMap.Initialise();
|
|
||||||
|
|
||||||
//build a proper flow field based on the scene
|
//build a proper flow field based on the scene
|
||||||
FlowField field = new FlowField(scene, new Vector3(128f, 128f, 128f), 200, 200, 200);
|
FlowField field = new FlowField(scene, new Vector3(128f, 128f, 128f), 200, 200, 200);
|
||||||
|
|
||||||
|
@ -134,7 +149,7 @@ namespace Flocking
|
||||||
{
|
{
|
||||||
if (m_enabled) {
|
if (m_enabled) {
|
||||||
m_scene.EventManager.OnFrame -= FlockUpdate;
|
m_scene.EventManager.OnFrame -= FlockUpdate;
|
||||||
m_scene.EventManager.OnChatFromClient -= SimChatSent;
|
m_scene.EventManager.OnChatFromClient -= m_chatCommandParser.SimChatSent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,9 +170,6 @@ namespace Flocking
|
||||||
if (((m_frame++ % m_frameUpdateRate) != 0) || !m_ready || !m_enabled) {
|
if (((m_frame++ % m_frameUpdateRate) != 0) || !m_ready || !m_enabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//m_log.InfoFormat("update my boids");
|
|
||||||
|
|
||||||
// work out where everyone has moved to
|
// work out where everyone has moved to
|
||||||
// and tell the scene to render the new positions
|
// and tell the scene to render the new positions
|
||||||
lock( m_sync ) {
|
lock( m_sync ) {
|
||||||
|
@ -166,34 +178,6 @@ namespace Flocking
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void SimChatSent (Object x, OSChatMessage msg)
|
|
||||||
{
|
|
||||||
if (m_scene.ConsoleScene () != m_scene || msg.Channel != m_chatChannel)
|
|
||||||
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 ("flock", args);
|
|
||||||
} else if (cmd.StartsWith ("start")) {
|
|
||||||
HandleStartCmd ("flock", args);
|
|
||||||
} else if (cmd.StartsWith ("size")) {
|
|
||||||
HandleSetSizeCmd ("flock", args);
|
|
||||||
} else if (cmd.StartsWith ("stats")) {
|
|
||||||
HandleShowStatsCmd ("flock", args);
|
|
||||||
} else if (cmd.StartsWith ("prim")) {
|
|
||||||
HandleSetPrimCmd ("flock", args);
|
|
||||||
} else if (cmd.StartsWith ("framerate")) {
|
|
||||||
HandleSetFrameRateCmd ("flock", args);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Command Handling
|
#region Command Handling
|
||||||
|
@ -205,6 +189,7 @@ namespace Flocking
|
||||||
argStr = " <" + args + "> ";
|
argStr = " <" + args + "> ";
|
||||||
}
|
}
|
||||||
m_scene.AddCommand (this, "flock-" + cmd, "flock-" + cmd + argStr, help, fn);
|
m_scene.AddCommand (this, "flock-" + cmd, "flock-" + cmd + argStr, help, fn);
|
||||||
|
m_chatCommandParser.AddCommand(cmd, args, help, fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RegisterCommands ()
|
private void RegisterCommands ()
|
||||||
|
@ -215,6 +200,7 @@ namespace Flocking
|
||||||
AddCommand ("stats", "", "show flocking stats", HandleShowStatsCmd);
|
AddCommand ("stats", "", "show flocking stats", HandleShowStatsCmd);
|
||||||
AddCommand ("prim", "name", "set the prim used for each boid to that passed in", HandleSetPrimCmd);
|
AddCommand ("prim", "name", "set the prim used for each boid to that passed in", HandleSetPrimCmd);
|
||||||
AddCommand ("framerate", "num", "[debugging] only update boids every <num> frames", HandleSetFrameRateCmd);
|
AddCommand ("framerate", "num", "[debugging] only update boids every <num> frames", HandleSetFrameRateCmd);
|
||||||
|
AddCommand ("set", "name, value", "change the flock dynamics", HandleSetParameterCmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool ShouldHandleCmd ()
|
private bool ShouldHandleCmd ()
|
||||||
|
@ -235,15 +221,19 @@ namespace Flocking
|
||||||
private void ShowResponse (string response, bool inWorld)
|
private void ShowResponse (string response, bool inWorld)
|
||||||
{
|
{
|
||||||
if (inWorld) {
|
if (inWorld) {
|
||||||
IClientAPI ownerAPI = null;
|
ScenePresence owner = m_scene.GetScenePresence(m_owner);
|
||||||
if (m_scene.TryGetClient (m_owner, out ownerAPI)) {
|
m_chatCommandParser.SendMessage(owner, response);
|
||||||
ownerAPI.SendBlueBoxMessage (m_owner, "osboids", response);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
MainConsole.Instance.Output (response);
|
MainConsole.Instance.Output (response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void HandleSetParameterCmd(string module, string[] args)
|
||||||
|
{
|
||||||
|
if (ShouldHandleCmd ()) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void HandleStopCmd (string module, string[] args)
|
public void HandleStopCmd (string module, string[] args)
|
||||||
{
|
{
|
||||||
if (ShouldHandleCmd ()) {
|
if (ShouldHandleCmd ()) {
|
||||||
|
|
|
@ -57,25 +57,24 @@ namespace Flocking
|
||||||
public void Clear ()
|
public void Clear ()
|
||||||
{
|
{
|
||||||
//trash everything we have
|
//trash everything we have
|
||||||
foreach (string name in m_sogMap.Keys)
|
List<string> current = new List<string> (m_sogMap.Keys);
|
||||||
{
|
current.ForEach (delegate(string name) {
|
||||||
RemoveSOGFromScene(name);
|
RemoveSOGFromScene(name);
|
||||||
}
|
});
|
||||||
m_sogMap.Clear();
|
m_sogMap.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Render (List<Boid> boids)
|
public void Render (List<Boid> boids)
|
||||||
{
|
{
|
||||||
foreach (Boid boid in boids) {
|
boids.ForEach(delegate( Boid boid ) {
|
||||||
DrawBoid (boid);
|
DrawBoid (boid);
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawBoid (Boid boid)
|
private void DrawBoid (Boid boid)
|
||||||
{
|
{
|
||||||
SceneObjectPart existing = m_scene.GetSceneObjectPart (boid.Id);
|
SceneObjectPart existing = m_scene.GetSceneObjectPart (boid.Id);
|
||||||
|
|
||||||
|
|
||||||
SceneObjectGroup sog;
|
SceneObjectGroup sog;
|
||||||
if (existing == null) {
|
if (existing == null) {
|
||||||
SceneObjectGroup group = findByName (m_boidPrim);
|
SceneObjectGroup group = findByName (m_boidPrim);
|
||||||
|
@ -86,20 +85,24 @@ namespace Flocking
|
||||||
sog = existing.ParentGroup;
|
sog = existing.ParentGroup;
|
||||||
}
|
}
|
||||||
|
|
||||||
Quaternion rotation = CalcRotationToEndpoint (sog, sog.AbsolutePosition, boid.Location);
|
Quaternion rotation = CalcRotationToEndpoint (sog, boid.Location);
|
||||||
sog.UpdateGroupRotationPR( boid.Location, rotation);
|
sog.UpdateGroupRotationPR( boid.Location, rotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Quaternion CalcRotationToEndpoint (SceneObjectGroup copy, Vector3 sv, Vector3 ev)
|
private static Quaternion CalcRotationToEndpoint (SceneObjectGroup sog, Vector3 ev)
|
||||||
{
|
{
|
||||||
//llSetRot(llRotBetween(<1,0,0>,llVecNorm(targetPosition - llGetPos())));
|
//llSetRot(llRotBetween(<1,0,0>,llVecNorm(targetPosition - llGetPos())));
|
||||||
// boid wil fly x forwards and Z up
|
// boid wil fly x forwards and Z up
|
||||||
|
Vector3 sv = sog.AbsolutePosition;
|
||||||
|
|
||||||
Vector3 currDirVec = Vector3.UnitX;
|
Vector3 currDirVec = Vector3.UnitX;
|
||||||
Vector3 desiredDirVec = Vector3.Subtract (ev, sv);
|
Vector3 desiredDirVec = Vector3.Subtract (ev, sv);
|
||||||
desiredDirVec.Normalize ();
|
desiredDirVec.Normalize ();
|
||||||
|
|
||||||
Quaternion rot = Vector3.RotationBetween (currDirVec, desiredDirVec);
|
Quaternion rot = Vector3.RotationBetween (currDirVec, desiredDirVec);
|
||||||
|
|
||||||
|
//TODO: if we turn upside down, flip us over by rotating along Y
|
||||||
|
|
||||||
return rot;
|
return rot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,13 +116,9 @@ namespace Flocking
|
||||||
|
|
||||||
private SceneObjectGroup findByName (string name)
|
private SceneObjectGroup findByName (string name)
|
||||||
{
|
{
|
||||||
SceneObjectGroup retVal = null;
|
SceneObjectGroup retVal = (SceneObjectGroup)m_scene.Entities.Find (delegate( EntityBase e ) {
|
||||||
foreach (EntityBase e in m_scene.GetEntities()) {
|
return (e.Name == name) && (e is SceneObjectGroup);
|
||||||
if (e.Name == name) {
|
});
|
||||||
retVal = (SceneObjectGroup)e;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// can't find it so make a default one
|
// can't find it so make a default one
|
||||||
if (retVal == null) {
|
if (retVal == null) {
|
||||||
|
|
|
@ -64,11 +64,9 @@ namespace Flocking
|
||||||
for( int x = 0; x < size.X; x++ ) {
|
for( int x = 0; x < size.X; x++ ) {
|
||||||
for( int y = 0; y < size.Y; y++ ) {
|
for( int y = 0; y < size.Y; y++ ) {
|
||||||
for( int z = 0; z < size.Z; z++ ) {
|
for( int z = 0; z < size.Z; z++ ) {
|
||||||
if( IsWithinFlowField(
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
using System;
|
||||||
|
using OpenMetaverse;
|
||||||
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
namespace Flocking
|
||||||
|
{
|
||||||
|
[TestFixture()]
|
||||||
|
public class VectorTest
|
||||||
|
{
|
||||||
|
[Test()]
|
||||||
|
public void TestCase ()
|
||||||
|
{
|
||||||
|
Vector3 [,] field = new Vector3[3,3];
|
||||||
|
Vector2 start = new Vector2(0f, 0f);
|
||||||
|
Assert.That( field[1,1].Z == 0 );
|
||||||
|
|
||||||
|
field[1,0] = Vector3.UnitZ;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue