fixes for stable
parent
9aa909ba74
commit
c2ecfbaf7c
14
CHANGES.txt
14
CHANGES.txt
|
@ -1,14 +0,0 @@
|
||||||
|
|
||||||
08/07/2011 - Initial pre alpha release
|
|
||||||
Basic Flocking algos implemented
|
|
||||||
Border avoidance not so good
|
|
||||||
No configuration capabilities
|
|
||||||
|
|
||||||
09/07/2011
|
|
||||||
Fixed Boid rotation, boid now orients with direction of travel
|
|
||||||
added command handlers for both console and inworld chat channel
|
|
||||||
added commands for setting size of flock, prim to use for boid
|
|
||||||
added commands to start and stop the boids flocking
|
|
||||||
|
|
||||||
13/07/2011
|
|
||||||
added more documentation
|
|
|
@ -1,4 +0,0 @@
|
||||||
The following people have contributed to the development of the osboids module
|
|
||||||
|
|
||||||
* Jon Cundill - initial implementation
|
|
||||||
|
|
BIN
Flocking.dll
BIN
Flocking.dll
Binary file not shown.
BIN
Flocking.dll.mdb
BIN
Flocking.dll.mdb
Binary file not shown.
313
Flocking/Boid.cs
313
Flocking/Boid.cs
|
@ -1,313 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) Contributors, https://github.com/jonc/osboids
|
|
||||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
* * Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* * Neither the name of the OpenSimulator Project nor the
|
|
||||||
* names of its contributors may be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
|
||||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using log4net;
|
|
||||||
using OpenMetaverse;
|
|
||||||
using Utils = OpenSim.Framework.Util;
|
|
||||||
|
|
||||||
namespace Flocking
|
|
||||||
{
|
|
||||||
public class Boid
|
|
||||||
{
|
|
||||||
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 FlowField m_flowField;
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="Flocking.Boid"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name='l'>
|
|
||||||
/// L. the initial position of this boid
|
|
||||||
/// </param>
|
|
||||||
/// <param name='ms'>
|
|
||||||
/// Ms. max speed this boid can attain
|
|
||||||
/// </param>
|
|
||||||
/// <param name='mf'>
|
|
||||||
/// Mf. max force / acceleration this boid can extert
|
|
||||||
/// </param>
|
|
||||||
public Boid (string id, FlockingModel model, FlowField flowField)
|
|
||||||
{
|
|
||||||
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_flowField = flowField;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 boid in the scene relative to the rest of the flock.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name='boids'>
|
|
||||||
/// Boids. all the other chaps in the scene
|
|
||||||
/// </param>
|
|
||||||
public void MoveInSceneRelativeToFlock ()
|
|
||||||
{
|
|
||||||
List<Boid> neighbours = m_model.GetNeighbours(this);
|
|
||||||
// we would like to stay with our mates
|
|
||||||
Flock (neighbours);
|
|
||||||
|
|
||||||
// our first priority is to not hurt ourselves
|
|
||||||
// so adjust where we would like to go to avoid hitting things
|
|
||||||
AvoidObstacles ();
|
|
||||||
|
|
||||||
// then we want to avoid any threats
|
|
||||||
// this not implemented yet
|
|
||||||
|
|
||||||
|
|
||||||
// ok so we worked our where we want to go, so ...
|
|
||||||
UpdatePositionInScene ();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Move within our local 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<Boid> neighbours)
|
|
||||||
{
|
|
||||||
|
|
||||||
// calc the force vectors on this boid
|
|
||||||
Vector3 sep = Separate (neighbours); // Separation
|
|
||||||
Vector3 ali = Align (neighbours); // Alignment
|
|
||||||
Vector3 coh = Cohesion (neighbours); // Cohesion
|
|
||||||
|
|
||||||
// Arbitrarily weight these forces
|
|
||||||
sep *= m_model.SeparationWeighting;
|
|
||||||
ali *= m_model.AlignmentWeighting;
|
|
||||||
coh *= m_model.CohesionWeighting;
|
|
||||||
|
|
||||||
// Add the force vectors to the current acceleration of the boid
|
|
||||||
m_acc += sep;
|
|
||||||
m_acc += ali;
|
|
||||||
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
|
|
||||||
m_vel += m_acc;
|
|
||||||
// Limit speed
|
|
||||||
m_vel = Util.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 = Vector3.Zero; // The steering vector
|
|
||||||
Vector3 desired = target - m_loc; // A vector pointing from the location to the target
|
|
||||||
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 (distance > 0) {
|
|
||||||
// Normalize desired
|
|
||||||
desired.Normalize ();
|
|
||||||
// Two options for desired vector magnitude (1 -- based on distance, 2 -- maxspeed)
|
|
||||||
if ((slowdown) && (distance < m_model.LookaheadDistance )) {
|
|
||||||
desired *= (m_model.MaxSpeed * (distance / m_model.LookaheadDistance)); // This damping is somewhat arbitrary
|
|
||||||
} else {
|
|
||||||
desired *= m_model.MaxSpeed;
|
|
||||||
}
|
|
||||||
// Steering = Desired minus Velocity
|
|
||||||
steer = desired - m_vel;
|
|
||||||
//steer.limit(maxforce); // Limit to maximum steering force
|
|
||||||
steer = Util.Limit (steer, m_model.MaxForce);
|
|
||||||
}
|
|
||||||
return steer;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// navigate away from whatever it is we are too close to
|
|
||||||
/// </summary>
|
|
||||||
void AvoidObstacles ()
|
|
||||||
{
|
|
||||||
//look tolerance metres ahead
|
|
||||||
m_acc += m_flowField.AdjustVelocity( m_loc, m_vel, m_model.Tolerance );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Separate ourselves from the specified boids.
|
|
||||||
/// keeps us a respectable distance from our closest neighbours whilst still
|
|
||||||
/// being part of our local flock
|
|
||||||
/// </summary>
|
|
||||||
/// <param name='neighbours'>
|
|
||||||
/// Boids. all the boids in the scene
|
|
||||||
/// </param>
|
|
||||||
Vector3 Separate (List<Boid> neighbours)
|
|
||||||
{
|
|
||||||
// For every boid in the system, check if it's too close
|
|
||||||
float desired = m_model.DesiredSeparation;
|
|
||||||
//who are we too close to at the moment
|
|
||||||
List<Boid> tooCloseNeighbours = neighbours.FindAll( delegate(Boid neighbour) {
|
|
||||||
// Is the distance is less than an arbitrary amount
|
|
||||||
return Utils.GetDistanceTo (m_loc, neighbour.Location) < desired;
|
|
||||||
});
|
|
||||||
|
|
||||||
// move a bit away from them
|
|
||||||
Vector3 steer = Vector3.Zero;
|
|
||||||
tooCloseNeighbours.ForEach( delegate(Boid neighbour) {
|
|
||||||
// Calculate vector pointing away from neighbor
|
|
||||||
Vector3 diff = m_loc - neighbour.Location;
|
|
||||||
steer += Utils.GetNormalizedVector(diff) / (float)Utils.GetDistanceTo (m_loc, neighbour.Location);
|
|
||||||
});
|
|
||||||
|
|
||||||
if( steer.Length () > 0 ) {
|
|
||||||
// Average -- divide by how many
|
|
||||||
steer /= (float)tooCloseNeighbours.Count;
|
|
||||||
// Implement Reynolds: Steering = Desired - Velocity
|
|
||||||
steer.Normalize ();
|
|
||||||
steer *= m_model.MaxSpeed;
|
|
||||||
steer -= m_vel;
|
|
||||||
//don't go too fast;
|
|
||||||
steer = Util.Limit (steer, m_model.MaxForce);
|
|
||||||
}
|
|
||||||
return steer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Align our boid within the flock.
|
|
||||||
/// For every nearby boid in the system, calculate the average velocity
|
|
||||||
/// and move us towards that - this keeps us moving with the flock.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name='boids'>
|
|
||||||
/// Boids. all the boids in the scene - we only really care about those in the neighbourdist
|
|
||||||
/// </param>
|
|
||||||
Vector3 Align (List<Boid> boids)
|
|
||||||
{
|
|
||||||
Vector3 steer = Vector3.Zero;
|
|
||||||
|
|
||||||
boids.ForEach( delegate( Boid other ) {
|
|
||||||
steer += other.Velocity;
|
|
||||||
});
|
|
||||||
|
|
||||||
int count = boids.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 = Util.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 boids, calculate our steering vector towards that location
|
|
||||||
/// </summary>
|
|
||||||
/// <param name='neighbours'>
|
|
||||||
/// Boids. the boids in the scene
|
|
||||||
/// </param>
|
|
||||||
Vector3 Cohesion (List<Boid> neighbours)
|
|
||||||
{
|
|
||||||
|
|
||||||
Vector3 sum = Vector3.Zero; // Start with empty vector to accumulate all locations
|
|
||||||
|
|
||||||
neighbours.ForEach( delegate(Boid other) {
|
|
||||||
sum += other.Location; // Add location
|
|
||||||
});
|
|
||||||
|
|
||||||
int count = neighbours.Count;
|
|
||||||
if (count > 0) {
|
|
||||||
sum /= (float)count;
|
|
||||||
return Steer (sum, false); // Steer towards the location
|
|
||||||
}
|
|
||||||
return sum;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,127 +0,0 @@
|
||||||
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
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,81 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Flocking
|
|
||||||
{
|
|
||||||
public class FlockParameters
|
|
||||||
{
|
|
||||||
// public int flockSize;
|
|
||||||
public float maxSpeed;
|
|
||||||
public float maxForce;
|
|
||||||
public float neighbourDistance;
|
|
||||||
public float desiredSeparation;
|
|
||||||
public float tolerance;
|
|
||||||
public float separationWeighting;
|
|
||||||
public float alignmentWeighting;
|
|
||||||
public float cohesionWeighting;
|
|
||||||
public float lookaheadDistance;
|
|
||||||
private Dictionary<string, string> m_paramDescriptions = new Dictionary<string, string> ();
|
|
||||||
|
|
||||||
public FlockParameters() {
|
|
||||||
m_paramDescriptions.Add("max-speed", "max distance boid will travel per frame");
|
|
||||||
m_paramDescriptions.Add("max-force", "max acceleration od decelleration boid can exert");
|
|
||||||
m_paramDescriptions.Add("neighbour-distance", "boid will consider other boids within this distance as part of local flock");
|
|
||||||
m_paramDescriptions.Add("desired-separation", "closest distance to other boids that our boid would like to get");
|
|
||||||
m_paramDescriptions.Add("tolerance", "how close to the edges of objects or the scene should our boid get");
|
|
||||||
m_paramDescriptions.Add("separation-weighting", "factor by which closeness to other boids should be favoured when updating position in flock");
|
|
||||||
m_paramDescriptions.Add("alignment-weighting", "factor by which alignment with other boids should be favoured when updating position in flock");
|
|
||||||
m_paramDescriptions.Add("cohesion-weighting", "factor by which keeping within the local flock should be favoured when updating position in flock");
|
|
||||||
m_paramDescriptions.Add("lookahead-distance", "how far in front should the boid look for edges and boundaries");
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsValidParameter (string name)
|
|
||||||
{
|
|
||||||
return m_paramDescriptions.ContainsKey (name);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetParameter (string name, string newVal)
|
|
||||||
{
|
|
||||||
switch (name) {
|
|
||||||
case "max-speed":
|
|
||||||
maxSpeed = Convert.ToSingle(newVal);
|
|
||||||
break;
|
|
||||||
case "max-force":
|
|
||||||
maxForce = Convert.ToSingle(newVal);
|
|
||||||
break;
|
|
||||||
case "neighbour-distance":
|
|
||||||
neighbourDistance = Convert.ToSingle(newVal);
|
|
||||||
break;
|
|
||||||
case "desired-separation":
|
|
||||||
desiredSeparation = Convert.ToSingle(newVal);
|
|
||||||
break;
|
|
||||||
case "tolerance":
|
|
||||||
tolerance = Convert.ToSingle(newVal);
|
|
||||||
break;
|
|
||||||
case "separation-weighting":
|
|
||||||
separationWeighting = Convert.ToSingle(newVal);
|
|
||||||
break;
|
|
||||||
case "alignment-weighting":
|
|
||||||
alignmentWeighting = Convert.ToSingle(newVal);
|
|
||||||
break;
|
|
||||||
case "cohesion-weighting":
|
|
||||||
cohesionWeighting = Convert.ToSingle(newVal);
|
|
||||||
break;
|
|
||||||
case "lookahead-distance":
|
|
||||||
lookaheadDistance = Convert.ToSingle(newVal);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string GetList ()
|
|
||||||
{
|
|
||||||
string retVal = Environment.NewLine;
|
|
||||||
foreach (string name in m_paramDescriptions.Keys) {
|
|
||||||
retVal += name + " - " + m_paramDescriptions [name] + Environment.NewLine;
|
|
||||||
}
|
|
||||||
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<PropertyGroup>
|
|
||||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
|
||||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
|
||||||
<ReferencePath>/Users/jon/osim/opensim/bin/</ReferencePath>
|
|
||||||
<LastOpenVersion>9.0.21022</LastOpenVersion>
|
|
||||||
<ProjectView>ProjectFiles</ProjectView>
|
|
||||||
<ProjectTrust>0</ProjectTrust>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition = " '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' " />
|
|
||||||
<PropertyGroup Condition = " '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " />
|
|
||||||
</Project>
|
|
|
@ -1,66 +0,0 @@
|
||||||
<?xml version="1.0" ?>
|
|
||||||
<project name="Flocking" default="build">
|
|
||||||
<target name="build">
|
|
||||||
<echo message="Build Directory is ${project::get-base-directory()}/${build.dir}" />
|
|
||||||
<mkdir dir="${project::get-base-directory()}/${build.dir}" />
|
|
||||||
<copy todir="${project::get-base-directory()}/${build.dir}" flatten="true">
|
|
||||||
<fileset basedir="${project::get-base-directory()}">
|
|
||||||
</fileset>
|
|
||||||
</copy>
|
|
||||||
<copy todir="${project::get-base-directory()}/${build.dir}">
|
|
||||||
<fileset basedir=".">
|
|
||||||
</fileset>
|
|
||||||
</copy>
|
|
||||||
<csc target="library" debug="${build.debug}" platform="${build.platform}" unsafe="False" warnaserror="False" define="TRACE;DEBUG" nostdlib="False" main="" output="${project::get-base-directory()}/${build.dir}/${project::get-name()}.dll" noconfig="true">
|
|
||||||
<resources prefix="Flocking" dynamicprefix="true" >
|
|
||||||
<include name="Resources/Flocking.addin.xml" />
|
|
||||||
</resources>
|
|
||||||
<sources failonempty="true">
|
|
||||||
<include name="Boid.cs" />
|
|
||||||
<include name="FlockingModel.cs" />
|
|
||||||
<include name="FlockingModule.cs" />
|
|
||||||
<include name="FlockingView.cs" />
|
|
||||||
<include name="FlowField.cs" />
|
|
||||||
<include name="FlowFieldTest.cs" />
|
|
||||||
<include name="FlowMap.cs" />
|
|
||||||
<include name="Util.cs" />
|
|
||||||
<include name="VectorTest.cs" />
|
|
||||||
</sources>
|
|
||||||
<references basedir="${project::get-base-directory()}">
|
|
||||||
<lib>
|
|
||||||
<include name="${project::get-base-directory()}" />
|
|
||||||
<include name="${project::get-base-directory()}/../../../bin" />
|
|
||||||
</lib>
|
|
||||||
<include name="../../../bin/log4net.dll"/>
|
|
||||||
<include name="../../../bin/Nini.dll"/>
|
|
||||||
<include name="../../../bin/nunit.framework.dll"/>
|
|
||||||
<include name="../../../bin/OpenMetaverse.dll"/>
|
|
||||||
<include name="../../../bin/OpenMetaverseTypes.dll"/>
|
|
||||||
<include name="../../../bin/OpenSim.Framework.dll"/>
|
|
||||||
<include name="../../../bin/OpenSim.Framework.Communications.dll"/>
|
|
||||||
<include name="../../../bin/OpenSim.Framework.Console.dll"/>
|
|
||||||
<include name="../../../bin/OpenSim.Region.Framework.dll"/>
|
|
||||||
<include name="../../../bin/OpenSim.Tests.Common.dll"/>
|
|
||||||
<include name="System.dll" />
|
|
||||||
<include name="System.Drawing.dll" />
|
|
||||||
<include name="System.Xml.dll" />
|
|
||||||
</references>
|
|
||||||
</csc>
|
|
||||||
<echo message="Copying from [${project::get-base-directory()}/${build.dir}/] to [${project::get-base-directory()}/../../../bin/" />
|
|
||||||
<mkdir dir="${project::get-base-directory()}/../../../bin/"/>
|
|
||||||
<copy todir="${project::get-base-directory()}/../../../bin/">
|
|
||||||
<fileset basedir="${project::get-base-directory()}/${build.dir}/" >
|
|
||||||
<include name="*.dll"/>
|
|
||||||
<include name="*.exe"/>
|
|
||||||
<include name="*.mdb" if='${build.debug}'/>
|
|
||||||
<include name="*.pdb" if='${build.debug}'/>
|
|
||||||
</fileset>
|
|
||||||
</copy>
|
|
||||||
</target>
|
|
||||||
<target name="clean">
|
|
||||||
<delete dir="${bin.dir}" failonerror="false" />
|
|
||||||
<delete dir="${obj.dir}" failonerror="false" />
|
|
||||||
</target>
|
|
||||||
<target name="doc" description="Creates documentation.">
|
|
||||||
</target>
|
|
||||||
</project>
|
|
|
@ -1,135 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) Contributors, https://github.com/jonc/osboids
|
|
||||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
* * Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* * Neither the name of the OpenSimulator Project nor the
|
|
||||||
* names of its contributors may be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
|
||||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using OpenMetaverse;
|
|
||||||
using Utils = OpenSim.Framework.Util;
|
|
||||||
|
|
||||||
namespace Flocking
|
|
||||||
{
|
|
||||||
public class FlockingModel
|
|
||||||
{
|
|
||||||
private List<Boid> m_flock = new List<Boid>();
|
|
||||||
private FlowField m_flowField;
|
|
||||||
private FlockParameters m_parameters;
|
|
||||||
private Random m_rnd = new Random(Environment.TickCount);
|
|
||||||
private int m_size;
|
|
||||||
|
|
||||||
public int Size {
|
|
||||||
get {return m_size;}
|
|
||||||
set {
|
|
||||||
if( value < m_flock.Count ) {
|
|
||||||
m_flock.RemoveRange( 0, m_flock.Count - value );
|
|
||||||
} else while( value > m_flock.Count ) {
|
|
||||||
AddBoid( "boid"+m_flock.Count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public FlockingModel( FlockParameters parameters ) {
|
|
||||||
m_parameters = parameters;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AddBoid (string name)
|
|
||||||
{
|
|
||||||
Boid boid = new Boid (name, this, m_flowField);
|
|
||||||
|
|
||||||
// find an initial random location for this Boid
|
|
||||||
// somewhere not within an obstacle
|
|
||||||
int xInit = m_rnd.Next(Util.SCENE_SIZE);
|
|
||||||
int yInit = m_rnd.Next(Util.SCENE_SIZE);
|
|
||||||
int zInit = m_rnd.Next(Util.SCENE_SIZE);
|
|
||||||
Vector3 location = new Vector3 (Convert.ToSingle(xInit), Convert.ToSingle(yInit), Convert.ToSingle(zInit));
|
|
||||||
boid.Location = location + m_flowField.AdjustVelocity(location, Vector3.UnitZ, 5f);
|
|
||||||
m_flock.Add (boid);
|
|
||||||
}
|
|
||||||
|
|
||||||
public float MaxSpeed {
|
|
||||||
get {return m_parameters.maxSpeed;}
|
|
||||||
}
|
|
||||||
|
|
||||||
public float MaxForce {
|
|
||||||
get {return m_parameters.maxForce;}
|
|
||||||
}
|
|
||||||
|
|
||||||
public float NeighbourDistance {
|
|
||||||
get {return m_parameters.neighbourDistance;}
|
|
||||||
}
|
|
||||||
|
|
||||||
public float DesiredSeparation {
|
|
||||||
get {return m_parameters.desiredSeparation;}
|
|
||||||
}
|
|
||||||
|
|
||||||
public float Tolerance {
|
|
||||||
get {return m_parameters.tolerance;}
|
|
||||||
}
|
|
||||||
|
|
||||||
public float SeparationWeighting {
|
|
||||||
get{ return m_parameters.separationWeighting; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public float AlignmentWeighting {
|
|
||||||
get{ return m_parameters.alignmentWeighting; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public float CohesionWeighting {
|
|
||||||
get{ return m_parameters.cohesionWeighting; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public float LookaheadDistance {
|
|
||||||
get { return m_parameters.lookaheadDistance; }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void Initialise (int size, FlowField flowField)
|
|
||||||
{
|
|
||||||
m_flowField = flowField;
|
|
||||||
m_size = size;
|
|
||||||
for (int i = 0; i < m_size; 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_parameters.neighbourDistance);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public List<Boid> UpdateFlockPos ()
|
|
||||||
{
|
|
||||||
m_flock.ForEach( delegate(Boid boid) {
|
|
||||||
boid.MoveInSceneRelativeToFlock();
|
|
||||||
} );
|
|
||||||
|
|
||||||
return m_flock;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,308 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) Contributors, https://github.com/jonc/osboids
|
|
||||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
* * Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* * Neither the name of the OpenSimulator Project nor the
|
|
||||||
* names of its contributors may be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
|
||||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
using System;
|
|
||||||
using System.Timers;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using OpenMetaverse;
|
|
||||||
using System.IO;
|
|
||||||
using Nini.Config;
|
|
||||||
using System.Threading;
|
|
||||||
using log4net;
|
|
||||||
using OpenSim.Region.Framework.Interfaces;
|
|
||||||
using OpenSim.Region.Framework.Scenes;
|
|
||||||
using OpenSim.Framework;
|
|
||||||
using OpenSim.Framework.Console;
|
|
||||||
|
|
||||||
namespace Flocking
|
|
||||||
{
|
|
||||||
public class FlockingModule : INonSharedRegionModule
|
|
||||||
{
|
|
||||||
|
|
||||||
private static readonly ILog m_log = LogManager.GetLogger (System.Reflection.MethodBase.GetCurrentMethod ().DeclaringType);
|
|
||||||
static object m_sync = new object();
|
|
||||||
|
|
||||||
private Scene m_scene;
|
|
||||||
private FlockingModel m_model;
|
|
||||||
private FlockingView m_view;
|
|
||||||
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_boidPrim;
|
|
||||||
private ChatCommandParser m_chatCommandParser;
|
|
||||||
private FlockParameters m_parameters;
|
|
||||||
private int m_flockSize = 100;
|
|
||||||
|
|
||||||
private UUID m_owner;
|
|
||||||
|
|
||||||
#region IRegionModule Members
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public void Initialise (IConfigSource source)
|
|
||||||
{
|
|
||||||
//check if we are in the ini files
|
|
||||||
//if so get some physical constants out of them and pass into the model
|
|
||||||
IConfig config = source.Configs ["Boids"];
|
|
||||||
if (config != null) {
|
|
||||||
m_chatChannel = config.GetInt ("chat-channel", 118);
|
|
||||||
m_boidPrim = config.GetString ("boid-prim", "boidPrim");
|
|
||||||
|
|
||||||
m_parameters = new FlockParameters();
|
|
||||||
m_flockSize = config.GetInt ("flock-size", 100);
|
|
||||||
m_parameters.maxSpeed = config.GetFloat("max-speed", 3f);
|
|
||||||
m_parameters.maxForce = config.GetFloat("max-force", 0.25f);
|
|
||||||
m_parameters.neighbourDistance = config.GetFloat("neighbour-dist", 25f);
|
|
||||||
m_parameters.desiredSeparation = config.GetFloat("desired-separation", 20f);
|
|
||||||
m_parameters.tolerance = config.GetFloat("tolerance", 5f);
|
|
||||||
m_parameters.separationWeighting = config.GetFloat("separation-weighting", 1.5f);
|
|
||||||
m_parameters.alignmentWeighting = config.GetFloat("alignment-weighting", 1f);
|
|
||||||
m_parameters.cohesionWeighting = config.GetFloat("cohesion-weighting", 1f);
|
|
||||||
m_parameters.lookaheadDistance = config.GetFloat("lookahead-dist", 100f);
|
|
||||||
|
|
||||||
// we're in the config - so turn on this module
|
|
||||||
m_enabled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddRegion (Scene scene)
|
|
||||||
{
|
|
||||||
//m_log.Info ("ADDING FLOCKING");
|
|
||||||
m_scene = scene;
|
|
||||||
if (m_enabled) {
|
|
||||||
//register commands
|
|
||||||
m_chatCommandParser = new ChatCommandParser(this, scene, m_chatChannel);
|
|
||||||
RegisterCommands ();
|
|
||||||
|
|
||||||
//register handlers
|
|
||||||
m_scene.EventManager.OnFrame += FlockUpdate;
|
|
||||||
m_scene.EventManager.OnChatFromClient += m_chatCommandParser.SimChatSent; //listen for commands sent from the client
|
|
||||||
|
|
||||||
// init module
|
|
||||||
m_model = new FlockingModel (m_parameters);
|
|
||||||
|
|
||||||
m_view = new FlockingView (m_scene);
|
|
||||||
m_view.BoidPrim = m_boidPrim;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RegionLoaded (Scene scene)
|
|
||||||
{
|
|
||||||
if (m_enabled) {
|
|
||||||
|
|
||||||
//build a proper flow field based on the scene
|
|
||||||
FlowField field = new FlowField(scene, new Vector3(128f, 128f, 128f), 200, 200, 200);
|
|
||||||
|
|
||||||
// Generate initial flock values
|
|
||||||
m_model.Initialise (m_flockSize, field);
|
|
||||||
|
|
||||||
// who is the owner for the flock in this region
|
|
||||||
m_owner = m_scene.RegionInfo.EstateSettings.EstateOwner;
|
|
||||||
m_view.PostInitialize (m_owner);
|
|
||||||
|
|
||||||
// Mark Module Ready for duty
|
|
||||||
m_ready = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveRegion (Scene scene)
|
|
||||||
{
|
|
||||||
if (m_enabled) {
|
|
||||||
m_scene.EventManager.OnFrame -= FlockUpdate;
|
|
||||||
m_scene.EventManager.OnChatFromClient -= m_chatCommandParser.SimChatSent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Name {
|
|
||||||
get { return "FlockingModule"; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsSharedModule {
|
|
||||||
get { return false; }
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region EventHandlers
|
|
||||||
|
|
||||||
public void FlockUpdate ()
|
|
||||||
{
|
|
||||||
if (((m_frame++ % m_frameUpdateRate) != 0) || !m_ready || !m_enabled) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// work out where everyone has moved to
|
|
||||||
// and tell the scene to render the new positions
|
|
||||||
lock( m_sync ) {
|
|
||||||
List<Boid > boids = m_model.UpdateFlockPos ();
|
|
||||||
m_view.Render (boids);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#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_scene.AddCommand (this, "flock-" + cmd, "flock-" + cmd + argStr, help, fn);
|
|
||||||
m_chatCommandParser.AddCommand(cmd, args, help, fn);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RegisterCommands ()
|
|
||||||
{
|
|
||||||
AddCommand ("stop", "", "Stop all Flocking", HandleStopCmd);
|
|
||||||
AddCommand ("start", "", "Start Flocking", HandleStartCmd);
|
|
||||||
AddCommand ("size", "num", "Adjust the size of the flock ", HandleSetSizeCmd);
|
|
||||||
AddCommand ("stats", "", "show flocking stats", HandleShowStatsCmd);
|
|
||||||
AddCommand ("prim", "name", "set the prim used for each boid to that passed in", HandleSetPrimCmd);
|
|
||||||
AddCommand ("framerate", "num", "[debugging] only update boids every <num> frames", HandleSetFrameRateCmd);
|
|
||||||
AddCommand ("set", "name, value", "change the flock dynamics", HandleSetParameterCmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool ShouldHandleCmd ()
|
|
||||||
{
|
|
||||||
return m_scene.ConsoleScene () == m_scene;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool IsInWorldCmd (ref string [] args)
|
|
||||||
{
|
|
||||||
bool retVal = false;
|
|
||||||
|
|
||||||
if (args.Length > 0 && args [args.Length - 1].Equals ("<ui>")) {
|
|
||||||
retVal = true;
|
|
||||||
}
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ShowResponse (string response, bool inWorld)
|
|
||||||
{
|
|
||||||
if (inWorld) {
|
|
||||||
ScenePresence owner = m_scene.GetScenePresence(m_owner);
|
|
||||||
m_chatCommandParser.SendMessage(owner, response);
|
|
||||||
} else {
|
|
||||||
MainConsole.Instance.Output (response);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void HandleSetParameterCmd(string module, string[] args)
|
|
||||||
{
|
|
||||||
if (ShouldHandleCmd ()) {
|
|
||||||
string name = args[1];
|
|
||||||
string newVal = args[2];
|
|
||||||
|
|
||||||
if( m_parameters.IsValidParameter( name ) ) {
|
|
||||||
m_parameters.SetParameter(name, newVal);
|
|
||||||
} else {
|
|
||||||
bool inWorld = IsInWorldCmd( ref args);
|
|
||||||
ShowResponse( name + "is not a valid flock parameter", inWorld );
|
|
||||||
ShowResponse( "valid parameters are: " + m_parameters.GetList(), inWorld);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void HandleStopCmd (string module, string[] args)
|
|
||||||
{
|
|
||||||
if (ShouldHandleCmd ()) {
|
|
||||||
m_log.Info ("stop the flocking capability");
|
|
||||||
m_enabled = false;
|
|
||||||
m_view.Clear ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void HandleSetFrameRateCmd (string module, string[] args)
|
|
||||||
{
|
|
||||||
if (ShouldHandleCmd ()) {
|
|
||||||
int frameRate = Convert.ToInt32( args[1] );
|
|
||||||
m_frameUpdateRate = frameRate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void HandleStartCmd (string module, string[] args)
|
|
||||||
{
|
|
||||||
if (ShouldHandleCmd ()) {
|
|
||||||
m_log.Info ("start the flocking capability");
|
|
||||||
m_enabled = true;
|
|
||||||
FlockUpdate ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void HandleSetSizeCmd (string module, string[] args)
|
|
||||||
{
|
|
||||||
if (ShouldHandleCmd ()) {
|
|
||||||
lock( m_sync ) {
|
|
||||||
int newSize = Convert.ToInt32(args[1]);
|
|
||||||
m_model.Size = newSize;
|
|
||||||
m_view.Clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void HandleShowStatsCmd (string module, string[] args)
|
|
||||||
{
|
|
||||||
if (ShouldHandleCmd ()) {
|
|
||||||
bool inWorld = IsInWorldCmd (ref args);
|
|
||||||
string str = "Num Boids = " + m_model.Size;
|
|
||||||
ShowResponse (str, inWorld);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void HandleSetPrimCmd (string module, string[] args)
|
|
||||||
{
|
|
||||||
if (ShouldHandleCmd ()) {
|
|
||||||
string primName = args[1];
|
|
||||||
lock(m_sync) {
|
|
||||||
m_view.BoidPrim = primName;
|
|
||||||
m_view.Clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#region IRegionModuleBase Members
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public void Close ()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public Type ReplaceableInterface {
|
|
||||||
get { return null; }
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,154 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) Contributors, https://github.com/jonc/osboids
|
|
||||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
* * Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* * Neither the name of the OpenSimulator Project nor the
|
|
||||||
* names of its contributors may be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
|
||||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using OpenMetaverse;
|
|
||||||
using OpenSim.Framework;
|
|
||||||
using OpenSim.Region.Framework.Scenes;
|
|
||||||
|
|
||||||
namespace Flocking
|
|
||||||
{
|
|
||||||
public class FlockingView
|
|
||||||
{
|
|
||||||
private Scene m_scene;
|
|
||||||
private UUID m_owner;
|
|
||||||
private String m_boidPrim;
|
|
||||||
|
|
||||||
private Dictionary<string, SceneObjectGroup> m_sogMap = new Dictionary<string, SceneObjectGroup> ();
|
|
||||||
|
|
||||||
public FlockingView (Scene scene)
|
|
||||||
{
|
|
||||||
m_scene = scene;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PostInitialize (UUID owner)
|
|
||||||
{
|
|
||||||
m_owner = owner;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String BoidPrim {
|
|
||||||
set{ m_boidPrim = value;}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Clear ()
|
|
||||||
{
|
|
||||||
//trash everything we have
|
|
||||||
List<string> current = new List<string> (m_sogMap.Keys);
|
|
||||||
current.ForEach (delegate(string name) {
|
|
||||||
RemoveSOGFromScene(name);
|
|
||||||
});
|
|
||||||
m_sogMap.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Render (List<Boid> boids)
|
|
||||||
{
|
|
||||||
boids.ForEach(delegate( Boid boid ) {
|
|
||||||
DrawBoid (boid);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DrawBoid (Boid boid)
|
|
||||||
{
|
|
||||||
SceneObjectPart existing = m_scene.GetSceneObjectPart (boid.Id);
|
|
||||||
|
|
||||||
SceneObjectGroup sog;
|
|
||||||
if (existing == null) {
|
|
||||||
SceneObjectGroup group = findByName (m_boidPrim);
|
|
||||||
sog = CopyPrim (group, boid.Id);
|
|
||||||
m_sogMap [boid.Id] = sog;
|
|
||||||
m_scene.AddNewSceneObject (sog, false);
|
|
||||||
} else {
|
|
||||||
sog = existing.ParentGroup;
|
|
||||||
}
|
|
||||||
|
|
||||||
Quaternion rotation = CalcRotationToEndpoint (sog, boid.Location);
|
|
||||||
sog.UpdateGroupRotationPR( boid.Location, rotation);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Quaternion CalcRotationToEndpoint (SceneObjectGroup sog, Vector3 ev)
|
|
||||||
{
|
|
||||||
//llSetRot(llRotBetween(<1,0,0>,llVecNorm(targetPosition - llGetPos())));
|
|
||||||
// boid wil fly x forwards and Z up
|
|
||||||
Vector3 sv = sog.AbsolutePosition;
|
|
||||||
|
|
||||||
Vector3 currDirVec = Vector3.UnitX;
|
|
||||||
Vector3 desiredDirVec = Vector3.Subtract (ev, sv);
|
|
||||||
desiredDirVec.Normalize ();
|
|
||||||
|
|
||||||
Quaternion rot = Vector3.RotationBetween (currDirVec, desiredDirVec);
|
|
||||||
|
|
||||||
//TODO: if we turn upside down, flip us over by rotating along Y
|
|
||||||
|
|
||||||
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 = (SceneObjectGroup)m_scene.Entities.Find (delegate( EntityBase e ) {
|
|
||||||
return (e.Name == name) && (e is SceneObjectGroup);
|
|
||||||
});
|
|
||||||
|
|
||||||
// can't find it so make a default one
|
|
||||||
if (retVal == null) {
|
|
||||||
retVal = MakeDefaultPrim (name);
|
|
||||||
}
|
|
||||||
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 (128f, 128f, 25f), shape);
|
|
||||||
prim.Name = name;
|
|
||||||
prim.DetachFromBackup ();
|
|
||||||
m_scene.AddNewSceneObject (prim, false);
|
|
||||||
|
|
||||||
return prim;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RemoveSOGFromScene(string sogName)
|
|
||||||
{
|
|
||||||
SceneObjectGroup sog = m_sogMap[sogName];
|
|
||||||
m_scene.DeleteSceneObject(sog, false);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,106 +0,0 @@
|
||||||
using System;
|
|
||||||
using OpenMetaverse;
|
|
||||||
using OpenSim.Region.Framework.Scenes;
|
|
||||||
|
|
||||||
namespace Flocking
|
|
||||||
{
|
|
||||||
public class FlowField
|
|
||||||
{
|
|
||||||
private const int BUFFER = 5;
|
|
||||||
private Scene m_scene;
|
|
||||||
private float m_startX;
|
|
||||||
private float m_startY;
|
|
||||||
private float m_startZ;
|
|
||||||
private float m_endX;
|
|
||||||
private float m_endY;
|
|
||||||
private float m_endZ;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="Flocking.FlowField"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name='scene'>
|
|
||||||
/// Scene.
|
|
||||||
/// </param>
|
|
||||||
/// <param name='centre'>
|
|
||||||
/// Centre.
|
|
||||||
/// </param>
|
|
||||||
/// <param name='width'>
|
|
||||||
/// Width.
|
|
||||||
/// </param>
|
|
||||||
/// <param name='depth'>
|
|
||||||
/// Depth.
|
|
||||||
/// </param>
|
|
||||||
/// <param name='height'>
|
|
||||||
/// Height.
|
|
||||||
/// </param>
|
|
||||||
///
|
|
||||||
public FlowField (Scene scene, Vector3 centre, int width, int depth, int height)
|
|
||||||
{
|
|
||||||
m_scene = scene;
|
|
||||||
|
|
||||||
m_startX = Math.Max( BUFFER, centre.X - width/2f);
|
|
||||||
m_startY = Math.Max( BUFFER, centre.Y - depth/2f);
|
|
||||||
m_startZ = Math.Max( BUFFER, centre.Z - height/2f);
|
|
||||||
m_endX = Math.Min( Util.SCENE_SIZE - BUFFER, centre.X + width/2f);
|
|
||||||
m_endY = Math.Min( Util.SCENE_SIZE - BUFFER, centre.Y + depth/2f);
|
|
||||||
m_endZ = Math.Min( Util.SCENE_SIZE - BUFFER, centre.Z + height/2f);
|
|
||||||
|
|
||||||
// build the flow field over the given bounds
|
|
||||||
Initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// build a flow field on the scene at the specified centre
|
|
||||||
/// position in the scene and of extent given by width, depth and height.
|
|
||||||
/// </summary>
|
|
||||||
public void Initialize() {
|
|
||||||
foreach( SceneObjectGroup sog in m_scene.Entities.GetAllByType<SceneObjectGroup>() ) {
|
|
||||||
float offsetHeight;
|
|
||||||
Vector3 size = sog.GetAxisAlignedBoundingBox( out offsetHeight );
|
|
||||||
Vector3 pos = sog.AbsolutePosition;
|
|
||||||
|
|
||||||
// color in the flow field with the strength at this pos due to
|
|
||||||
// this sog
|
|
||||||
for( int x = 0; x < size.X; x++ ) {
|
|
||||||
for( int y = 0; y < size.Y; y++ ) {
|
|
||||||
for( int z = 0; z < size.Z; z++ ) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vector3 AdjustVelocity (Vector3 loc, Vector3 vel, float lookAheadDist)
|
|
||||||
{
|
|
||||||
Vector3 normVel = Vector3.Normalize(vel);
|
|
||||||
Vector3 inFront = loc + normVel * lookAheadDist;
|
|
||||||
Vector3 adjustedDestintation = inFront + FieldStrength(inFront);
|
|
||||||
Vector3 newVel = Vector3.Normalize(adjustedDestintation - loc) * Vector3.Mag(vel);
|
|
||||||
return newVel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vector3 FieldStrength (Vector3 inFront)
|
|
||||||
{
|
|
||||||
Vector3 retVal = Vector3.Zero;
|
|
||||||
|
|
||||||
//keep us in bounds
|
|
||||||
if( inFront.X > m_endX ) retVal.X -= inFront.X - m_endX;
|
|
||||||
if( inFront.Y > m_endY ) retVal.Y -= inFront.Y - m_endY;
|
|
||||||
if( inFront.Z > m_endZ ) retVal.Z -= inFront.Z - m_endZ;
|
|
||||||
if( inFront.X < m_startX ) retVal.X += m_startX - inFront.X;
|
|
||||||
if( inFront.Y < m_startY ) retVal.Y += m_startY - inFront.Y;
|
|
||||||
if( inFront.Z < m_startZ ) retVal.Z += m_startZ - inFront.Z;
|
|
||||||
|
|
||||||
//now get the field strength at the inbounds position
|
|
||||||
Vector3 strength = LookUp( inFront + retVal);
|
|
||||||
|
|
||||||
return retVal + strength;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vector3 LookUp (Vector3 par1)
|
|
||||||
{
|
|
||||||
return Vector3.Zero;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,118 +0,0 @@
|
||||||
using System;
|
|
||||||
using NUnit.Framework;
|
|
||||||
using OpenMetaverse;
|
|
||||||
using OpenSim.Framework;
|
|
||||||
using OpenSim.Region.Framework.Scenes;
|
|
||||||
using OpenSim.Tests.Common;
|
|
||||||
using OpenSim.Tests.Common.Mock;
|
|
||||||
|
|
||||||
|
|
||||||
namespace Flocking
|
|
||||||
{
|
|
||||||
[TestFixture()]
|
|
||||||
public class FlowFieldTest
|
|
||||||
{
|
|
||||||
[Test()]
|
|
||||||
public void TestEmptyFlowField ()
|
|
||||||
{
|
|
||||||
Scene scene = SceneSetupHelpers.SetupScene();
|
|
||||||
|
|
||||||
Vector3 centre = new Vector3 (100f, 100f, 100f);
|
|
||||||
FlowField field = new FlowField(scene, centre, 50, 50, 50);
|
|
||||||
Vector3 strength = field.FieldStrength (centre);
|
|
||||||
Assert.That( strength == Vector3.Zero);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test()]
|
|
||||||
public void TestWeCanMoveFreely ()
|
|
||||||
{
|
|
||||||
Scene scene = SceneSetupHelpers.SetupScene();
|
|
||||||
|
|
||||||
Vector3 centre = new Vector3 (100f, 100f, 100f);
|
|
||||||
FlowField field = new FlowField(scene, centre, 50, 50, 50);
|
|
||||||
Vector3 pos = new Vector3(100f, 100f,100f);
|
|
||||||
Vector3 velocity = new Vector3(20f, 0f, 0f);
|
|
||||||
Vector3 newVel = field.AdjustVelocity (pos, velocity, 10);
|
|
||||||
Console.WriteLine( newVel );
|
|
||||||
Assert.That(newVel == velocity);
|
|
||||||
Vector3 newPos = pos+newVel;
|
|
||||||
Assert.That( newPos.X < 150f);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test()]
|
|
||||||
public void TestWeDontFallOfTheEdge ()
|
|
||||||
{
|
|
||||||
Scene scene = SceneSetupHelpers.SetupScene();
|
|
||||||
|
|
||||||
Vector3 centre = new Vector3 (100f, 100f, 100f);
|
|
||||||
FlowField field = new FlowField(scene, centre, 50, 50, 50);
|
|
||||||
|
|
||||||
Vector3 pos = new Vector3(140f, 100f,100f);
|
|
||||||
Vector3 velocity = new Vector3(20f, 0f, 0f);
|
|
||||||
Vector3 newVel = field.AdjustVelocity (pos, velocity, 10);
|
|
||||||
Console.WriteLine( newVel );
|
|
||||||
Vector3 newPos = pos+newVel;
|
|
||||||
Assert.That( newPos.X < 150f);
|
|
||||||
Assert.That(velocity != newVel);
|
|
||||||
|
|
||||||
pos = new Vector3(60f, 100f, 100f);
|
|
||||||
velocity = new Vector3(-20f, 0f, 0f);
|
|
||||||
newVel = field.AdjustVelocity(pos, velocity, 10);
|
|
||||||
newPos = pos+newVel;
|
|
||||||
Assert.That( newPos.X > 50f );
|
|
||||||
Assert.That(velocity != newVel);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test()]
|
|
||||||
public void TestWeCanCopeWithCorners ()
|
|
||||||
{
|
|
||||||
Scene scene = SceneSetupHelpers.SetupScene();
|
|
||||||
|
|
||||||
Vector3 centre = new Vector3 (100f, 100f, 100f);
|
|
||||||
FlowField field = new FlowField(scene, centre, 50, 50, 50);
|
|
||||||
Vector3 pos = new Vector3(140f, 140f,140f);
|
|
||||||
Vector3 velocity = new Vector3(20f, 20f, 20f); // going to hit the corner
|
|
||||||
Vector3 newVel = field.AdjustVelocity (pos, velocity, 10);
|
|
||||||
Console.WriteLine( newVel );
|
|
||||||
Vector3 newPos = pos+newVel;
|
|
||||||
Assert.That( newPos.X < 150f);
|
|
||||||
Assert.That( newPos.Y < 150f);
|
|
||||||
Assert.That( newPos.Z < 150f);
|
|
||||||
Assert.That(velocity != newVel);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test()]
|
|
||||||
[Ignore()]
|
|
||||||
public void TestNonEmptyFlowField ()
|
|
||||||
{
|
|
||||||
Scene scene = SceneSetupHelpers.SetupScene();
|
|
||||||
Vector3 centre = new Vector3 (100f, 100f, 100f);
|
|
||||||
SceneObjectGroup sceneObjectGroup = AddSog (centre, new Vector3(10f,10f,10f));
|
|
||||||
scene.AddNewSceneObject(sceneObjectGroup, false);
|
|
||||||
|
|
||||||
FlowField field = new FlowField(scene, centre, 50, 50, 50);
|
|
||||||
Vector3 strength = field.FieldStrength (centre);
|
|
||||||
Assert.That( strength != Vector3.Zero);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SceneObjectGroup AddSog (Vector3 position, Vector3 size)
|
|
||||||
{
|
|
||||||
UUID ownerId = new UUID("00000000-0000-0000-0000-000000000010");
|
|
||||||
string part1Name = "part1";
|
|
||||||
UUID part1Id = new UUID("00000000-0000-0000-0000-000000000001");
|
|
||||||
string part2Name = "part2";
|
|
||||||
UUID part2Id = new UUID("00000000-0000-0000-0000-000000000002");
|
|
||||||
|
|
||||||
SceneObjectPart part1
|
|
||||||
= new SceneObjectPart(ownerId, PrimitiveBaseShape.Default, position, Quaternion.Identity, Vector3.Zero)
|
|
||||||
{ Name = part1Name, UUID = part1Id };
|
|
||||||
part1.Scale =size;
|
|
||||||
SceneObjectGroup so = new SceneObjectGroup(part1);
|
|
||||||
|
|
||||||
return so;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,185 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) Contributors, https://github.com/jonc/osboids
|
|
||||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
* * Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* * Neither the name of the OpenSimulator Project nor the
|
|
||||||
* names of its contributors may be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
|
||||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using OpenMetaverse;
|
|
||||||
using OpenSim.Region.Framework.Scenes;
|
|
||||||
|
|
||||||
namespace Flocking
|
|
||||||
{
|
|
||||||
public class FlowMap
|
|
||||||
{
|
|
||||||
private Scene m_scene;
|
|
||||||
private float[,,] m_flowMap = new float[256,256,256];
|
|
||||||
|
|
||||||
public FlowMap (Scene scene)
|
|
||||||
{
|
|
||||||
m_scene = scene;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int LengthX {
|
|
||||||
get {return 256;}
|
|
||||||
}
|
|
||||||
public int LengthY {
|
|
||||||
get {return 256;}
|
|
||||||
}
|
|
||||||
public int LengthZ {
|
|
||||||
get {return 256;}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Initialise() {
|
|
||||||
//fill in the boundaries
|
|
||||||
for( int x = 0; x < 256; x++ ) {
|
|
||||||
for( int y = 0; y < 256; y++ ) {
|
|
||||||
m_flowMap[x,y,0] = 100f;
|
|
||||||
m_flowMap[x,y,255] = 100f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for( int x = 0; x < 256; x++ ) {
|
|
||||||
for( int z = 0; z < 256; z++ ) {
|
|
||||||
m_flowMap[x,0,z] = 100f;
|
|
||||||
m_flowMap[x,255,z] = 100f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for( int y = 0; y < 256; y++ ) {
|
|
||||||
for( int z = 0; z < 256; z++ ) {
|
|
||||||
m_flowMap[0,y,z] = 100f;
|
|
||||||
m_flowMap[255,y,z] = 100f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//fill in the terrain
|
|
||||||
for( int x = 0; x < 256; x++ ) {
|
|
||||||
for( int y = 0; y < 256; 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 < 5f ||
|
|
||||||
targetPos.X > 250f ||
|
|
||||||
targetPos.Y < 5f ||
|
|
||||||
targetPos.Y > 250f ||
|
|
||||||
targetPos.Z < 5f ||
|
|
||||||
targetPos.Z > 250f ) {
|
|
||||||
|
|
||||||
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;
|
|
||||||
} else if( x < 0 || y < 0 || z < 0 ) {
|
|
||||||
retVal = true;
|
|
||||||
} else if (m_flowMap[x,y,z] > 50f) {
|
|
||||||
retVal = true;
|
|
||||||
}
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,54 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) Contributors, https://github.com/jonc/osboids
|
|
||||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
* * Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* * Neither the name of the OpenSimulator Project nor the
|
|
||||||
* names of its contributors may be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
|
||||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
using System;
|
|
||||||
using OpenMetaverse;
|
|
||||||
|
|
||||||
namespace Flocking
|
|
||||||
{
|
|
||||||
|
|
||||||
public class Util
|
|
||||||
{
|
|
||||||
public const int SCENE_SIZE = 256;
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
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;
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
<Addin id="Flocking" version="0.1">
|
|
||||||
<Runtime>
|
|
||||||
<Import assembly="Flocking.dll"/>
|
|
||||||
</Runtime>
|
|
||||||
|
|
||||||
<Dependencies>
|
|
||||||
<Addin id="OpenSim" version="0.5" />
|
|
||||||
</Dependencies>
|
|
||||||
|
|
||||||
<Extension path = "/OpenSim/RegionModules">
|
|
||||||
<RegionModule id="Flocking" type="Flocking.FlockingModule" />
|
|
||||||
</Extension>
|
|
||||||
</Addin>
|
|
28
TODO.txt
28
TODO.txt
|
@ -1,28 +0,0 @@
|
||||||
|
|
||||||
|
|
||||||
TODO:
|
|
||||||
|
|
||||||
[done] Expose Settings to ini Files
|
|
||||||
|
|
||||||
[done] Write in world Chat controller to allow maintenance of flocking in world.
|
|
||||||
|
|
||||||
[done - but basic] Handle Borders Correctly
|
|
||||||
|
|
||||||
[done - but basic] Handle Collision Avoidance
|
|
||||||
|
|
||||||
Replace above with a proper flow field implementation
|
|
||||||
|
|
||||||
Handle Wander
|
|
||||||
|
|
||||||
Handle Perching
|
|
||||||
|
|
||||||
Handle Predator Avoidance
|
|
||||||
|
|
||||||
|
|
||||||
Optimise it all...
|
|
||||||
|
|
||||||
Look at maintaining flocks across sim boundaries.
|
|
||||||
|
|
||||||
Look at exposing flocking as a service to scripts
|
|
||||||
|
|
||||||
|
|
36
prebuild.xml
36
prebuild.xml
|
@ -1,36 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8" ?>
|
|
||||||
<!-- Core osboids Project -->
|
|
||||||
|
|
||||||
<Project frameworkVersion="v3_5" name="Flocking" path="addon-modules/osboids/Flocking/" type="Library">
|
|
||||||
<Configuration name="Debug">
|
|
||||||
<Options>
|
|
||||||
<OutputPath>../../../bin/</OutputPath>
|
|
||||||
</Options>
|
|
||||||
</Configuration>
|
|
||||||
<Configuration name="Release">
|
|
||||||
<Options>
|
|
||||||
<OutputPath>../../../bin/</OutputPath>
|
|
||||||
</Options>
|
|
||||||
</Configuration>
|
|
||||||
|
|
||||||
<ReferencePath>../../../bin/</ReferencePath>
|
|
||||||
<Reference name="log4net" path="../../../bin/" />
|
|
||||||
<Reference name="System"/>
|
|
||||||
<Reference name="System.Drawing" />
|
|
||||||
<Reference name="System.Xml"/>
|
|
||||||
<Reference name="Nini" path="../../../bin/" />
|
|
||||||
<Reference name="nunit.framework" path="../../../bin/" />
|
|
||||||
<Reference name="OpenSim.Framework" path="../../../bin/" />
|
|
||||||
<Reference name="OpenSim.Tests.Common" path="../../../bin/" />
|
|
||||||
<Reference name="OpenSim.Framework.Communications" path="../../../bin/" />
|
|
||||||
<Reference name="OpenSim.Region.Framework" path="../../../bin/" />
|
|
||||||
<Reference name="OpenSim.Framework.Console" path="../../../bin/" />
|
|
||||||
<Reference name="OpenMetaverseTypes" path="../../../bin/" />
|
|
||||||
<Reference name="OpenMetaverse" path="../../../bin/" />
|
|
||||||
<Files>
|
|
||||||
<Match pattern="*.cs" recurse="true"/>
|
|
||||||
<Match pattern="*.addin.xml" path="Resources" buildAction="EmbeddedResource" recurse="true"/>
|
|
||||||
|
|
||||||
</Files>
|
|
||||||
</Project>
|
|
||||||
|
|
Loading…
Reference in New Issue