added ability to control flock from scripts.
parent
1c410fdb81
commit
e584d81e0c
|
@ -44,7 +44,6 @@ namespace Flocking
|
||||||
private Random m_rndnums = new Random (Environment.TickCount);
|
private Random m_rndnums = new Random (Environment.TickCount);
|
||||||
|
|
||||||
private BoidBehaviour m_behaviour;
|
private BoidBehaviour m_behaviour;
|
||||||
private FlowField m_flowField;
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -59,31 +58,31 @@ namespace Flocking
|
||||||
/// <param name='mf'>
|
/// <param name='mf'>
|
||||||
/// Mf. max force / acceleration this boid can extert
|
/// Mf. max force / acceleration this boid can extert
|
||||||
/// </param>
|
/// </param>
|
||||||
public Boid (string id, Vector3 size, BoidBehaviour behaviour, FlowField flowField)
|
public Boid (string id, Vector3 size, BoidBehaviour behaviour)
|
||||||
{
|
{
|
||||||
m_id = id;
|
m_id = id;
|
||||||
m_acc = Vector3.Zero;
|
m_acc = Vector3.Zero;
|
||||||
m_vel = new Vector3 (m_rndnums.Next (-1, 1), m_rndnums.Next (-1, 1), m_rndnums.Next (-1, 1));
|
m_vel = new Vector3 (m_rndnums.Next (-1, 1), m_rndnums.Next (-1, 1), m_rndnums.Next (-1, 1));
|
||||||
m_size = size;
|
m_size = size;
|
||||||
m_behaviour = behaviour;
|
m_behaviour = behaviour;
|
||||||
m_flowField = flowField;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector3 Location {
|
public Vector3 Location {
|
||||||
get { return m_loc;}
|
get { return m_loc; }
|
||||||
set { m_loc = value; }
|
set { m_loc = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector3 Velocity {
|
public Vector3 Velocity {
|
||||||
get { return m_vel;}
|
get { return m_vel; }
|
||||||
|
set { m_vel = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector3 Size {
|
public Vector3 Size {
|
||||||
get { return m_size;}
|
get { return m_size; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public String Id {
|
public String Id {
|
||||||
get {return m_id;}
|
get { return m_id; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -92,15 +91,14 @@ namespace Flocking
|
||||||
/// <param name='boids'>
|
/// <param name='boids'>
|
||||||
/// Boids. all the other chaps in the scene
|
/// Boids. all the other chaps in the scene
|
||||||
/// </param>
|
/// </param>
|
||||||
public void MoveInSceneRelativeToFlock (List<Boid> neighbours)
|
public void MoveInSceneRelativeToFlock (List<Boid> neighbours, FlowField field)
|
||||||
{
|
{
|
||||||
//List<Boid> neighbours = m_model.GetNeighbours(this);
|
|
||||||
// we would like to stay with our mates
|
// we would like to stay with our mates
|
||||||
Flock (neighbours);
|
Flock (neighbours);
|
||||||
|
|
||||||
// our first priority is to not hurt ourselves
|
// however, our first priority is to not hurt ourselves
|
||||||
// so adjust where we would like to go to avoid hitting things
|
// so adjust where we would like to go to avoid hitting things
|
||||||
AvoidObstacles ();
|
AvoidObstacles (field);
|
||||||
|
|
||||||
// then we want to avoid any threats
|
// then we want to avoid any threats
|
||||||
// this not implemented yet
|
// this not implemented yet
|
||||||
|
@ -127,7 +125,7 @@ namespace Flocking
|
||||||
Vector3 sep = Separate (neighbours); // Separation
|
Vector3 sep = Separate (neighbours); // Separation
|
||||||
Vector3 ali = Align (neighbours); // Alignment
|
Vector3 ali = Align (neighbours); // Alignment
|
||||||
Vector3 coh = Cohesion (neighbours); // Cohesion
|
Vector3 coh = Cohesion (neighbours); // Cohesion
|
||||||
Vector3 ori = Orientation();
|
Vector3 ori = Orientation(); // its tricky to fly directly up or down
|
||||||
|
|
||||||
// Arbitrarily weight these forces
|
// Arbitrarily weight these forces
|
||||||
sep *= m_behaviour.separationWeighting;
|
sep *= m_behaviour.separationWeighting;
|
||||||
|
@ -213,10 +211,23 @@ namespace Flocking
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// navigate away from whatever it is we are too close to
|
/// navigate away from whatever it is we are too close to
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void AvoidObstacles ()
|
void AvoidObstacles (FlowField field)
|
||||||
{
|
{
|
||||||
//look tolerance metres ahead
|
//look tolerance metres ahead
|
||||||
m_acc += m_flowField.AdjustVelocity( this, m_behaviour.tolerance );
|
//m_acc += field.AdjustVelocity( this, m_behaviour.lookaheadDistance );
|
||||||
|
Vector3 normVel = Vector3.Normalize (m_vel);
|
||||||
|
Vector3 inFront = m_loc + normVel * m_behaviour.LookaheadDistance;
|
||||||
|
|
||||||
|
Vector3 adjustedDestintation = field.FieldStrength (m_loc, m_size, inFront);
|
||||||
|
Vector3 newVel = Vector3.Normalize (adjustedDestintation - m_loc) * Vector3.Mag (m_vel);
|
||||||
|
|
||||||
|
float mOrigVel = Vector3.Mag(m_vel);
|
||||||
|
float mNewVel = Vector3.Mag(newVel);
|
||||||
|
if( mNewVel != 0f && mNewVel > mOrigVel ) {
|
||||||
|
newVel *= mOrigVel / mNewVel;
|
||||||
|
}
|
||||||
|
m_vel = newVel;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -243,6 +254,9 @@ namespace Flocking
|
||||||
tooCloseNeighbours.ForEach( delegate(Boid neighbour) {
|
tooCloseNeighbours.ForEach( delegate(Boid neighbour) {
|
||||||
// Calculate vector pointing away from neighbor
|
// Calculate vector pointing away from neighbor
|
||||||
Vector3 diff = m_loc - neighbour.Location;
|
Vector3 diff = m_loc - neighbour.Location;
|
||||||
|
if( diff == Vector3.Zero ) {
|
||||||
|
diff = new Vector3( (float)m_rndnums.NextDouble(), (float)m_rndnums.NextDouble(), (float)m_rndnums.NextDouble());
|
||||||
|
}
|
||||||
steer += Utils.GetNormalizedVector(diff) / (float)(Utils.GetDistanceTo (m_loc, neighbour.Location));
|
steer += Utils.GetNormalizedVector(diff) / (float)(Utils.GetDistanceTo (m_loc, neighbour.Location));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,29 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,247 @@
|
||||||
|
/*
|
||||||
|
* 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 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 FlockingCommandParser
|
||||||
|
{
|
||||||
|
private static readonly ILog m_log = LogManager.GetLogger (System.Reflection.MethodBase.GetCurrentMethod ().DeclaringType);
|
||||||
|
private IRegionModuleBase m_module;
|
||||||
|
private Scene m_scene;
|
||||||
|
private int m_chatChannel;
|
||||||
|
private UUID m_owner;
|
||||||
|
private Dictionary<string, BoidCmdDelegate> m_commandMap = new Dictionary<string, BoidCmdDelegate> ();
|
||||||
|
private Dictionary<string, BoidCmdDefn> m_syntaxMap = new Dictionary<string, BoidCmdDefn> ();
|
||||||
|
|
||||||
|
|
||||||
|
public FlockingCommandParser (IRegionModuleBase module, Scene scene, int channel)
|
||||||
|
{
|
||||||
|
m_module = module;
|
||||||
|
m_scene = scene;
|
||||||
|
m_chatChannel = channel;
|
||||||
|
|
||||||
|
// who do we respond to in send messages
|
||||||
|
m_owner = scene.RegionInfo.EstateSettings.EstateOwner;
|
||||||
|
|
||||||
|
// register our event handlers
|
||||||
|
m_scene.EventManager.OnChatFromClient += ProcessChatCommand; //listen for commands sent from the client
|
||||||
|
|
||||||
|
IScriptModuleComms commsMod = scene.RequestModuleInterface<IScriptModuleComms>();
|
||||||
|
commsMod.OnScriptCommand += ProcessScriptCommand;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Deregister ()
|
||||||
|
{
|
||||||
|
m_scene.EventManager.OnChatFromClient -= ProcessChatCommand;
|
||||||
|
IScriptModuleComms commsMod = m_scene.RequestModuleInterface<IScriptModuleComms>();
|
||||||
|
commsMod.OnScriptCommand -= ProcessScriptCommand;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddCommand (string cmd, string args, string help, CommandDelegate fn)
|
||||||
|
{
|
||||||
|
string argStr = "";
|
||||||
|
if (args.Trim ().Length > 0) {
|
||||||
|
argStr = " <" + args + "> ";
|
||||||
|
}
|
||||||
|
m_commandMap.Add (cmd, new BoidCmdDelegate (fn));
|
||||||
|
m_syntaxMap.Add (cmd, new BoidCmdDefn (cmd, args, help));
|
||||||
|
// register this command with the console
|
||||||
|
m_scene.AddCommand (m_module, "flock-" + cmd, "flock-" + cmd + argStr, help, fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#region handlers
|
||||||
|
|
||||||
|
public void ProcessScriptCommand (UUID scriptId, string reqId, string module, string input, string key)
|
||||||
|
{
|
||||||
|
if (m_module.Name != module) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string[] tokens = (input+"|<script>").Split ( new char[] { '|' }, StringSplitOptions.None);
|
||||||
|
|
||||||
|
string command = tokens [0];
|
||||||
|
m_log.Debug("Input was " + input + ", command is " + command);
|
||||||
|
BoidCmdDefn defn = null;
|
||||||
|
if (m_syntaxMap.TryGetValue (command, out defn)) {
|
||||||
|
if (CorrectSignature (tokens, defn)) {
|
||||||
|
|
||||||
|
// we got the signature of the command right
|
||||||
|
BoidCmdDelegate del = null;
|
||||||
|
if (m_commandMap.TryGetValue (command, out del)) {
|
||||||
|
m_log.Info("command ok - executing");
|
||||||
|
del (module, tokens);
|
||||||
|
} else {
|
||||||
|
// we don't understand this command
|
||||||
|
// shouldn't happen
|
||||||
|
m_log.ErrorFormat ("Unable to invoke command {0}", command);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
m_log.Error(" signature wrong for " + command);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
m_log.Error("no command for " + command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RespondToScript (UUID scriptId, int msgNum, string response)
|
||||||
|
{
|
||||||
|
IScriptModuleComms commsMod = m_scene.RequestModuleInterface<IScriptModuleComms>();
|
||||||
|
if( commsMod != null ) {
|
||||||
|
commsMod.DispatchReply (scriptId, msgNum, response, "");
|
||||||
|
} else {
|
||||||
|
Console.WriteLine("No script comms");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ProcessChatCommand (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_module.Name, args);
|
||||||
|
} else {
|
||||||
|
// we don't understand this command
|
||||||
|
// shouldn't happen
|
||||||
|
m_log.ErrorFormat ("Unable to invoke command {0}", args [0]);
|
||||||
|
RespondToChat (msg, "Unable to invoke command " + args [0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// we recognise the command, but we got the call wrong
|
||||||
|
RespondToChat (msg, "wrong syntax: " + defn.GetSyntax ());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// this is not a command we recognise
|
||||||
|
RespondToChat (msg, args [0] + " is not a valid command for osboids");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RespondToChat (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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
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 ShowResponse (string response, string [] cmd)
|
||||||
|
{
|
||||||
|
bool inWorld = IsInWorldCmd (cmd);
|
||||||
|
if (inWorld) {
|
||||||
|
ScenePresence owner = m_scene.GetScenePresence(m_owner);
|
||||||
|
SendMessage(owner, response);
|
||||||
|
} else {
|
||||||
|
MainConsole.Instance.Output (response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsInWorldCmd (string [] args)
|
||||||
|
{
|
||||||
|
bool retVal = false;
|
||||||
|
|
||||||
|
if (args.Length > 0 && args [args.Length - 1].Equals ("<ui>")) {
|
||||||
|
retVal = true;
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@ namespace Flocking
|
||||||
private Random m_rnd = new Random(Environment.TickCount);
|
private Random m_rnd = new Random(Environment.TickCount);
|
||||||
private int m_flockSize;
|
private int m_flockSize;
|
||||||
private Vector3 m_boidSize;
|
private Vector3 m_boidSize;
|
||||||
|
private Vector3 m_startPos;
|
||||||
|
|
||||||
public int Size {
|
public int Size {
|
||||||
get {return m_flockSize;}
|
get {return m_flockSize;}
|
||||||
|
@ -51,21 +52,17 @@ namespace Flocking
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public FlockingModel( BoidBehaviour behaviour ) {
|
public FlockingModel( BoidBehaviour behaviour, Vector3 startPos ) {
|
||||||
m_behaviour = behaviour;
|
m_behaviour = behaviour;
|
||||||
|
m_startPos = startPos;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddBoid (string name)
|
void AddBoid (string name)
|
||||||
{
|
{
|
||||||
Boid boid = new Boid (name, m_boidSize, m_behaviour, m_flowField);
|
Boid boid = new Boid (name, m_boidSize, m_behaviour);
|
||||||
|
|
||||||
// find an initial random location for this Boid
|
boid.Location = m_startPos;
|
||||||
// somewhere not within an obstacle
|
boid.Velocity = Vector3.UnitX;
|
||||||
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(boid, 5f);
|
|
||||||
m_flock.Add (boid);
|
m_flock.Add (boid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,6 +74,7 @@ namespace Flocking
|
||||||
m_boidSize = boidSize;
|
m_boidSize = boidSize;
|
||||||
for (int i = 0; i < m_flockSize; i++) {
|
for (int i = 0; i < m_flockSize; i++) {
|
||||||
AddBoid ("boid"+i );
|
AddBoid ("boid"+i );
|
||||||
|
UpdateFlockPos();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,7 +89,7 @@ namespace Flocking
|
||||||
public List<Boid> UpdateFlockPos ()
|
public List<Boid> UpdateFlockPos ()
|
||||||
{
|
{
|
||||||
m_flock.ForEach( delegate(Boid boid) {
|
m_flock.ForEach( delegate(Boid boid) {
|
||||||
boid.MoveInSceneRelativeToFlock(GetNeighbours(boid));
|
boid.MoveInSceneRelativeToFlock(GetNeighbours(boid), m_flowField);
|
||||||
} );
|
} );
|
||||||
|
|
||||||
return m_flock;
|
return m_flock;
|
||||||
|
|
|
@ -36,6 +36,8 @@ using OpenSim.Region.Framework.Interfaces;
|
||||||
using OpenSim.Region.Framework.Scenes;
|
using OpenSim.Region.Framework.Scenes;
|
||||||
using OpenSim.Framework;
|
using OpenSim.Framework;
|
||||||
using OpenSim.Framework.Console;
|
using OpenSim.Framework.Console;
|
||||||
|
using OpenSim.Services.Interfaces;
|
||||||
|
|
||||||
|
|
||||||
namespace Flocking
|
namespace Flocking
|
||||||
{
|
{
|
||||||
|
@ -49,12 +51,12 @@ namespace Flocking
|
||||||
private FlockingModel m_model;
|
private FlockingModel m_model;
|
||||||
private FlockingView m_view;
|
private FlockingView m_view;
|
||||||
private bool m_enabled = false;
|
private bool m_enabled = false;
|
||||||
private bool m_ready = false;
|
private bool m_active = false;
|
||||||
private uint m_frame = 0;
|
private uint m_frame = 0;
|
||||||
private int m_frameUpdateRate = 1;
|
private int m_frameUpdateRate = 1;
|
||||||
private int m_chatChannel = 118;
|
private int m_chatChannel = 118;
|
||||||
private string m_boidPrim;
|
private string m_boidPrim = "boid-prim";
|
||||||
private ChatCommandParser m_chatCommandParser;
|
private FlockingCommandParser m_commandParser;
|
||||||
private BoidBehaviour m_behaviour;
|
private BoidBehaviour m_behaviour;
|
||||||
private int m_flockSize = 100;
|
private int m_flockSize = 100;
|
||||||
|
|
||||||
|
@ -95,42 +97,26 @@ namespace Flocking
|
||||||
//m_log.Info ("ADDING FLOCKING");
|
//m_log.Info ("ADDING FLOCKING");
|
||||||
m_scene = scene;
|
m_scene = scene;
|
||||||
if (m_enabled) {
|
if (m_enabled) {
|
||||||
//register commands
|
|
||||||
m_chatCommandParser = new ChatCommandParser(this, scene, m_chatChannel);
|
|
||||||
RegisterCommands ();
|
|
||||||
|
|
||||||
//register handlers
|
//register handlers
|
||||||
m_scene.EventManager.OnFrame += FlockUpdate;
|
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_behaviour);
|
|
||||||
|
|
||||||
m_view = new FlockingView (m_scene);
|
|
||||||
m_view.BoidPrim = m_boidPrim;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RegionLoaded (Scene scene)
|
public void RegionLoaded (Scene scene)
|
||||||
{
|
{
|
||||||
if (m_enabled) {
|
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);
|
|
||||||
|
|
||||||
//ask the view how big the boid is
|
|
||||||
Vector3 scale = m_view.GetBoidSize();
|
|
||||||
// m_log.Error( m_boidPrim + " = " + scale.ToString());
|
|
||||||
|
|
||||||
// Generate initial flock values
|
|
||||||
m_model.Initialise (m_flockSize, scale, field);
|
|
||||||
|
|
||||||
// who is the owner for the flock in this region
|
// who is the owner for the flock in this region
|
||||||
m_owner = m_scene.RegionInfo.EstateSettings.EstateOwner;
|
m_owner = scene.RegionInfo.EstateSettings.EstateOwner;
|
||||||
m_view.PostInitialize (m_owner);
|
|
||||||
|
|
||||||
// Mark Module Ready for duty
|
//register command handler
|
||||||
m_ready = true;
|
m_commandParser = new FlockingCommandParser(this, scene, m_chatChannel);
|
||||||
|
RegisterCommands ();
|
||||||
|
|
||||||
|
// init view
|
||||||
|
m_view = new FlockingView (scene);
|
||||||
|
m_view.PostInitialize (m_owner);
|
||||||
|
m_view.BoidPrim = m_boidPrim;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,7 +124,7 @@ namespace Flocking
|
||||||
{
|
{
|
||||||
if (m_enabled) {
|
if (m_enabled) {
|
||||||
m_scene.EventManager.OnFrame -= FlockUpdate;
|
m_scene.EventManager.OnFrame -= FlockUpdate;
|
||||||
m_scene.EventManager.OnChatFromClient -= m_chatCommandParser.SimChatSent;
|
m_commandParser.Deregister();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,7 +142,7 @@ namespace Flocking
|
||||||
|
|
||||||
public void FlockUpdate ()
|
public void FlockUpdate ()
|
||||||
{
|
{
|
||||||
if (((m_frame++ % m_frameUpdateRate) != 0) || !m_ready || !m_enabled) {
|
if (((m_frame++ % m_frameUpdateRate) != 0) || !m_active || !m_enabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// work out where everyone has moved to
|
// work out where everyone has moved to
|
||||||
|
@ -169,27 +155,37 @@ namespace Flocking
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
private void BuildFlowField(Vector3 centre, int width, int depth, int height) {
|
||||||
|
m_log.Info("building flow field");
|
||||||
|
//build a flow field based on the scene
|
||||||
|
FlowField field = new FlowField(m_scene, centre, width, depth, height);
|
||||||
|
m_log.Info("built");
|
||||||
|
//ask the view how big the boid prim is
|
||||||
|
Vector3 scale = m_view.GetBoidSize();
|
||||||
|
|
||||||
|
Vector3 startPos = m_scene.GetSceneObjectPart(m_view.BoidPrim).ParentGroup.AbsolutePosition;
|
||||||
|
// init model
|
||||||
|
m_log.Info("creating model");
|
||||||
|
m_model = new FlockingModel (m_behaviour, startPos );
|
||||||
|
// Generate initial flock values
|
||||||
|
m_model.Initialise (m_flockSize, scale, field);
|
||||||
|
m_log.Info("done");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
#region Command Handling
|
#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 ()
|
private void RegisterCommands ()
|
||||||
{
|
{
|
||||||
AddCommand ("stop", "", "Stop all Flocking", HandleStopCmd);
|
m_commandParser.AddCommand ("stop", "", "Stop all Flocking", HandleStopCmd);
|
||||||
AddCommand ("start", "", "Start Flocking", HandleStartCmd);
|
m_commandParser.AddCommand ("start", "", "Start Flocking", HandleStartCmd);
|
||||||
AddCommand ("size", "num", "Adjust the size of the flock ", HandleSetSizeCmd);
|
m_commandParser.AddCommand ("size", "num", "Adjust the size of the flock ", HandleSetSizeCmd);
|
||||||
AddCommand ("stats", "", "show flocking stats", HandleShowStatsCmd);
|
m_commandParser.AddCommand ("stats", "", "show flocking stats", HandleShowStatsCmd);
|
||||||
AddCommand ("prim", "name", "set the prim used for each boid to that passed in", HandleSetPrimCmd);
|
m_commandParser.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);
|
m_commandParser.AddCommand ("framerate", "num", "[debugging] only update boids every <num> frames", HandleSetFrameRateCmd);
|
||||||
AddCommand ("set", "name, value", "change the flock dynamics", HandleSetParameterCmd);
|
m_commandParser.AddCommand ("set", "name, value", "change the flock behaviour properties", HandleSetParameterCmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool ShouldHandleCmd ()
|
private bool ShouldHandleCmd ()
|
||||||
|
@ -197,26 +193,6 @@ namespace Flocking
|
||||||
return m_scene.ConsoleScene () == m_scene;
|
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)
|
public void HandleSetParameterCmd(string module, string[] args)
|
||||||
{
|
{
|
||||||
if (ShouldHandleCmd ()) {
|
if (ShouldHandleCmd ()) {
|
||||||
|
@ -226,9 +202,8 @@ namespace Flocking
|
||||||
if( m_behaviour.IsValidParameter( name ) ) {
|
if( m_behaviour.IsValidParameter( name ) ) {
|
||||||
m_behaviour.SetParameter(name, newVal);
|
m_behaviour.SetParameter(name, newVal);
|
||||||
} else {
|
} else {
|
||||||
bool inWorld = IsInWorldCmd( ref args);
|
m_commandParser.ShowResponse( name + "is not a valid flock parameter", args );
|
||||||
ShowResponse( name + "is not a valid flock parameter", inWorld );
|
m_commandParser.ShowResponse( "valid parameters are: " + m_behaviour.GetList(), args);
|
||||||
ShowResponse( "valid parameters are: " + m_behaviour.GetList(), inWorld);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -237,7 +212,7 @@ namespace Flocking
|
||||||
{
|
{
|
||||||
if (ShouldHandleCmd ()) {
|
if (ShouldHandleCmd ()) {
|
||||||
m_log.Info ("stop the flocking capability");
|
m_log.Info ("stop the flocking capability");
|
||||||
m_enabled = false;
|
m_active = false;
|
||||||
m_view.Clear ();
|
m_view.Clear ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -254,7 +229,8 @@ namespace Flocking
|
||||||
{
|
{
|
||||||
if (ShouldHandleCmd ()) {
|
if (ShouldHandleCmd ()) {
|
||||||
m_log.Info ("start the flocking capability");
|
m_log.Info ("start the flocking capability");
|
||||||
m_enabled = true;
|
BuildFlowField(new Vector3(128f, 128f, 128f), 200, 200, 200);
|
||||||
|
m_active = true;
|
||||||
FlockUpdate ();
|
FlockUpdate ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -273,9 +249,8 @@ namespace Flocking
|
||||||
public void HandleShowStatsCmd (string module, string[] args)
|
public void HandleShowStatsCmd (string module, string[] args)
|
||||||
{
|
{
|
||||||
if (ShouldHandleCmd ()) {
|
if (ShouldHandleCmd ()) {
|
||||||
bool inWorld = IsInWorldCmd (ref args);
|
|
||||||
string str = m_model.ToString();
|
string str = m_model.ToString();
|
||||||
ShowResponse (str, inWorld);
|
m_commandParser.ShowResponse (str, args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,8 +54,9 @@ namespace Flocking
|
||||||
m_owner = owner;
|
m_owner = owner;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String BoidPrim {
|
public string BoidPrim {
|
||||||
set{ m_boidPrim = value;}
|
get{ return m_boidPrim; }
|
||||||
|
set{ m_boidPrim = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector3 GetBoidSize ()
|
public Vector3 GetBoidSize ()
|
||||||
|
|
|
@ -1,3 +1,29 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
using OpenMetaverse;
|
using OpenMetaverse;
|
||||||
using OpenSim.Region.Framework.Scenes;
|
using OpenSim.Region.Framework.Scenes;
|
||||||
|
@ -16,7 +42,7 @@ namespace Flocking
|
||||||
private float m_endZ;
|
private float m_endZ;
|
||||||
private UUID TERRAIN = UUID.Random ();
|
private UUID TERRAIN = UUID.Random ();
|
||||||
private UUID EDGE = UUID.Random ();
|
private UUID EDGE = UUID.Random ();
|
||||||
private UUID[,,] m_field = new UUID[256, 256, 256]; // field of the object at this position
|
private UUID[,,] m_field = new UUID[256, 256, 256]; // field of objects at this position
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="Flocking.FlowField"/> class.
|
/// Initializes a new instance of the <see cref="Flocking.FlowField"/> class.
|
||||||
|
@ -93,95 +119,119 @@ namespace Flocking
|
||||||
float fmaxX, fminX, fmaxY, fminY, fmaxZ, fminZ;
|
float fmaxX, fminX, fmaxY, fminY, fmaxZ, fminZ;
|
||||||
int maxX, minX, maxY, minY, maxZ, minZ;
|
int maxX, minX, maxY, minY, maxZ, minZ;
|
||||||
sog.GetAxisAlignedBoundingBoxRaw (out fminX, out fmaxX, out fminY, out fmaxY, out fminZ, out fmaxZ);
|
sog.GetAxisAlignedBoundingBoxRaw (out fminX, out fmaxX, out fminY, out fmaxY, out fminZ, out fmaxZ);
|
||||||
|
Vector3 pos = sog.AbsolutePosition;
|
||||||
|
|
||||||
minX = Convert.ToInt32 (fminX);
|
minX = Convert.ToInt32 (fminX + pos.X);
|
||||||
maxX = Convert.ToInt32 (fmaxX);
|
maxX = Convert.ToInt32 (fmaxX + pos.X);
|
||||||
minY = Convert.ToInt32 (fminY);
|
minY = Convert.ToInt32 (fminY + pos.Y);
|
||||||
maxY = Convert.ToInt32 (fmaxX);
|
maxY = Convert.ToInt32 (fmaxX + pos.Y);
|
||||||
minZ = Convert.ToInt32 (fminZ);
|
minZ = Convert.ToInt32 (fminZ + pos.Z);
|
||||||
maxZ = Convert.ToInt32 (fmaxZ);
|
maxZ = Convert.ToInt32 (fmaxZ + pos.Z);
|
||||||
|
|
||||||
for (int x = minX; x < maxX; x++) {
|
for (int x = minX; x < maxX; x++) {
|
||||||
for (int y = minY; y < maxY; y++) {
|
for (int y = minY; y < maxY; y++) {
|
||||||
for (int z = minZ; z < maxZ; z++) {
|
for (int z = minZ; z < maxZ; z++) {
|
||||||
|
if( inBounds(x,y,z) ) {
|
||||||
m_field [x, y, z] = sog.UUID;
|
m_field [x, y, z] = sog.UUID;
|
||||||
|
} else {
|
||||||
|
Console.WriteLine(sog.Name + " OOB at " + sog.AbsolutePosition + " -> " + x + " " + y + " " + z);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool inBounds (int x, int y, int z)
|
||||||
|
{
|
||||||
|
return x >= 0 && x < 256 && y >= 0 && y < 256 && z >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if false
|
||||||
public Vector3 AdjustVelocity (Boid boid, float lookAheadDist)
|
public Vector3 AdjustVelocity (Boid boid, float lookAheadDist)
|
||||||
{
|
{
|
||||||
Vector3 normVel = Vector3.Normalize (boid.Velocity);
|
Vector3 normVel = Vector3.Normalize (boid.Velocity);
|
||||||
Vector3 loc = boid.Location;
|
Vector3 loc = boid.Location;
|
||||||
Vector3 inFront = loc + normVel * lookAheadDist;
|
Vector3 inFront = loc + normVel * lookAheadDist;
|
||||||
|
|
||||||
Vector3 adjustedDestintation = inFront + FieldStrength (loc, boid.Size, inFront);
|
Vector3 adjustedDestintation = FieldStrength (loc, boid.Size, inFront);
|
||||||
Vector3 newVel = Vector3.Normalize (adjustedDestintation - loc) * Vector3.Mag (boid.Velocity);
|
Vector3 newVel = Vector3.Normalize (adjustedDestintation - loc) * Vector3.Mag (boid.Velocity);
|
||||||
|
|
||||||
|
float mOrigVel = Vector3.Mag(boid.Velocity);
|
||||||
|
float mNewVel = Vector3.Mag(newVel);
|
||||||
|
if( mNewVel != 0f && mNewVel > mOrigVel ) {
|
||||||
|
newVel *= mOrigVel / mNewVel;
|
||||||
|
}
|
||||||
return newVel;
|
return newVel;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
public Vector3 FieldStrength (Vector3 current, Vector3 size, Vector3 inFront)
|
public Vector3 FieldStrength (Vector3 currentPos, Vector3 size, Vector3 targetPos)
|
||||||
{
|
{
|
||||||
Vector3 retVal = Vector3.Zero;
|
|
||||||
float length = size.X/2;
|
float length = size.X/2;
|
||||||
float width = size.Y/2;
|
float width = size.Y/2;
|
||||||
float height = size.Z/2;
|
float height = size.Z/2;
|
||||||
|
|
||||||
//keep us in bounds
|
//keep us in bounds
|
||||||
if (inFront.X > m_endX)
|
targetPos.X = Math.Min( targetPos.X, m_endX - length );
|
||||||
retVal.X -= inFront.X - m_endX - length;
|
targetPos.X = Math.Max(targetPos.X, m_startX + length);
|
||||||
if (inFront.Y > m_endY)
|
targetPos.Y = Math.Min( targetPos.Y, m_endY - width );
|
||||||
retVal.Y -= inFront.Y - m_endY - width;
|
targetPos.Y = Math.Max(targetPos.Y, m_startY + width);
|
||||||
if (inFront.Z > m_endZ)
|
targetPos.Z = Math.Min( targetPos.Z, m_endZ - height );
|
||||||
retVal.Z -= inFront.Z - m_endZ - height;
|
targetPos.Z = Math.Max(targetPos.Z, m_startZ + height);
|
||||||
if (inFront.X < m_startX)
|
|
||||||
retVal.X += m_startX - inFront.X + length;
|
int count = 0;
|
||||||
if (inFront.Y < m_startY)
|
|
||||||
retVal.Y += m_startY - inFront.Y + width;
|
|
||||||
if (inFront.Z < m_startZ)
|
|
||||||
retVal.Z += m_startZ - inFront.Z + height;
|
|
||||||
|
|
||||||
//now get the field strength at the inbounds position
|
//now get the field strength at the inbounds position
|
||||||
UUID collider = LookUp (inFront + retVal);
|
UUID collider = LookUp (targetPos);
|
||||||
while (collider != UUID.Zero) {
|
while (collider != UUID.Zero && count < 100) {
|
||||||
|
count++;
|
||||||
if (collider == TERRAIN) {
|
if (collider == TERRAIN) {
|
||||||
// ground height at current and dest averaged
|
// ground height at currentPos and dest averaged
|
||||||
float h1 = m_scene.GetGroundHeight (current.X, current.Y);
|
float h1 = m_scene.GetGroundHeight (currentPos.X, currentPos.Y);
|
||||||
float h2 = m_scene.GetGroundHeight (inFront.X, inFront.Y);
|
float h2 = m_scene.GetGroundHeight (targetPos.X, targetPos.Y);
|
||||||
float h = (h1 + h2) / 2;
|
float h = (h1 + h2) / 2;
|
||||||
retVal.Z += h;
|
targetPos.Z = h + height;
|
||||||
} else if (collider == EDGE) {
|
} else if (collider == EDGE) {
|
||||||
// we ain't ever going to hit these
|
//keep us in bounds
|
||||||
|
targetPos.X = Math.Min( targetPos.X, m_endX - length );
|
||||||
|
targetPos.X = Math.Max(targetPos.X, m_startX + length);
|
||||||
|
targetPos.Y = Math.Min( targetPos.Y, m_endY - width );
|
||||||
|
targetPos.Y = Math.Max(targetPos.Y, m_startY + width);
|
||||||
|
targetPos.Z = Math.Min( targetPos.Z, m_endZ - height );
|
||||||
|
targetPos.Z = Math.Max(targetPos.Z, m_startZ + height);
|
||||||
} else {
|
} else {
|
||||||
//we have hit a SOG
|
//we have hit a SOG
|
||||||
SceneObjectGroup sog = m_scene.GetSceneObjectPart (collider).ParentGroup;
|
SceneObjectGroup sog = m_scene.GetSceneObjectPart(collider).ParentGroup;
|
||||||
if (sog == null) {
|
if (sog == null) {
|
||||||
Console.WriteLine (collider);
|
Console.WriteLine (collider);
|
||||||
} else {
|
} else {
|
||||||
float sogMinX, sogMinY, sogMinZ, sogMaxX, sogMaxY, sogMaxZ;
|
float sogMinX, sogMinY, sogMinZ, sogMaxX, sogMaxY, sogMaxZ;
|
||||||
sog.GetAxisAlignedBoundingBoxRaw (out sogMinX, out sogMaxX, out sogMinY, out sogMaxY, out sogMinZ, out sogMaxZ);
|
sog.GetAxisAlignedBoundingBoxRaw (out sogMinX, out sogMaxX, out sogMinY, out sogMaxY, out sogMinZ, out sogMaxZ);
|
||||||
|
Vector3 pos = sog.AbsolutePosition;
|
||||||
//keep us out of the sog
|
//keep us out of the sog
|
||||||
if (inFront.X > sogMinX)
|
// adjust up/down first if necessary
|
||||||
retVal.X -= inFront.X - sogMinX - length;
|
// then turn left or right
|
||||||
if (inFront.Y > sogMinY)
|
if (targetPos.Z > sogMinZ + pos.Z)
|
||||||
retVal.Y -= inFront.Y - sogMinY - width;
|
targetPos.Z = (sogMinZ + pos.Z) - height;
|
||||||
if (inFront.Z > sogMinZ)
|
if (targetPos.Z < sogMaxZ + pos.Z)
|
||||||
retVal.Z -= inFront.Z - sogMinZ - height;
|
targetPos.Z = (sogMaxZ + pos.Z) + height;
|
||||||
if (inFront.X < sogMaxX)
|
if (targetPos.X > sogMinX + pos.X)
|
||||||
retVal.X += sogMaxX - inFront.X + length;
|
targetPos.X = (sogMinX + pos.X) - length;
|
||||||
if (inFront.Y < sogMaxY)
|
if (targetPos.Y > sogMinY + pos.Y)
|
||||||
retVal.Y += sogMaxY - inFront.Y + width;
|
targetPos.Y = (sogMinY + pos.Y) - width;
|
||||||
if (inFront.Z < sogMaxZ)
|
if (targetPos.X < sogMaxX + pos.X)
|
||||||
retVal.Z += sogMaxZ - inFront.Z + height;
|
targetPos.X = (sogMaxX + pos.X) + length;
|
||||||
|
if (targetPos.Y < sogMaxY + pos.Y)
|
||||||
|
targetPos.Y = (sogMaxY + pos.Y) + width;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
collider = LookUp (inFront + retVal);
|
|
||||||
//inFront += retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
return retVal;
|
// we what is at the new target position
|
||||||
|
collider = LookUp (targetPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
return targetPos;
|
||||||
}
|
}
|
||||||
|
|
||||||
public UUID LookUp (Vector3 loc)
|
public UUID LookUp (Vector3 loc)
|
||||||
|
|
Loading…
Reference in New Issue