fixes for stable

stable0711
Jon Cundill 2011-07-21 22:30:45 +01:00
parent 9aa909ba74
commit c2ecfbaf7c
21 changed files with 0 additions and 1777 deletions

View File

@ -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

View File

@ -1,4 +0,0 @@
The following people have contributed to the development of the osboids module
* Jon Cundill - initial implementation

Binary file not shown.

Binary file not shown.

View File

@ -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;
}
}
}

View File

@ -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
);
}
}
}

View File

@ -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;
}
}
}

View File

@ -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>

View File

@ -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>

View File

@ -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;
}
}
}

View File

@ -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
}
}

View File

@ -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);
}
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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>

0
README Normal file → Executable file
View File

View File

@ -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

View File

@ -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>