2011-07-08 17:57:07 +00:00
/ *
* Copyright ( c ) Contributors , https : //github.com/jonc/osboids
2014-12-24 16:29:19 +00:00
* https : //github.com/JakDaniels/OpenSimBirds
2011-07-08 17:57:07 +00:00
* 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 ;
2014-12-24 16:29:19 +00:00
using System.Net ;
using System.IO ;
using System.Text ;
2011-07-08 17:57:07 +00:00
using System.Collections.Generic ;
using OpenMetaverse ;
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 ;
2014-07-17 16:43:21 +00:00
using Mono.Addins ;
2014-12-24 16:29:19 +00:00
[assembly: Addin("OpenSimBirds", "0.2")]
2014-12-31 18:50:48 +00:00
[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)]
2011-07-08 17:57:07 +00:00
namespace Flocking
{
2014-12-24 16:29:19 +00:00
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "OpenSimBirds")]
2014-07-17 16:43:21 +00:00
public class FlockingModule : INonSharedRegionModule
{
#region Fields
private static readonly ILog m_log = LogManager . GetLogger ( System . Reflection . MethodBase . GetCurrentMethod ( ) . DeclaringType ) ;
2011-07-08 17:57:07 +00:00
2014-12-24 16:29:19 +00:00
public string m_name = "OpenSimBirds" ;
2014-07-17 16:43:21 +00:00
private Scene m_scene ;
2014-12-31 18:50:48 +00:00
private ICommandConsole m_console ;
2011-07-08 17:57:07 +00:00
private FlockingModel m_model ;
private FlockingView m_view ;
private bool m_enabled = false ;
private bool m_ready = false ;
private uint m_frame = 0 ;
2011-07-09 11:35:13 +00:00
private int m_frameUpdateRate = 1 ;
2011-07-09 10:11:19 +00:00
private int m_chatChannel = 118 ;
2014-12-24 16:29:19 +00:00
private string m_birdPrim ;
2015-01-02 15:45:17 +00:00
private int m_flockSize = 50 ;
private int m_maxFlockSize = 100 ;
2011-07-10 23:08:26 +00:00
private float m_maxSpeed ;
private float m_maxForce ;
private float m_neighbourDistance ;
private float m_desiredSeparation ;
private float m_tolerance ;
2014-07-17 16:43:21 +00:00
private float m_borderSize ;
private int m_maxHeight ;
2014-12-24 16:29:19 +00:00
static object m_sync = new object ( ) ;
public IConfigSource m_config ;
2011-07-10 23:08:26 +00:00
2011-07-09 10:11:19 +00:00
private UUID m_owner ;
2014-07-17 16:43:21 +00:00
# endregion
2011-07-08 17:57:07 +00:00
2014-07-17 16:43:21 +00:00
#region IRegionModuleBase implementation
2011-07-08 17:57:07 +00:00
2014-12-24 16:29:19 +00:00
public string Name { get { return m_name ; } }
public Type ReplaceableInterface { get { return null ; } }
public bool IsSharedModule { get { return false ; } }
2014-07-17 16:43:21 +00:00
public void Initialise ( IConfigSource source )
2011-07-08 17:57:07 +00:00
{
2014-12-24 16:29:19 +00:00
m_config = source ;
}
2014-07-17 16:43:21 +00:00
2014-12-24 16:29:19 +00:00
public void AddRegion ( Scene scene )
{
m_log . InfoFormat ( "[{0}]: Adding region '{1}' to this module" , m_name , scene . RegionInfo . RegionName ) ;
IConfig cnf = m_config . Configs [ scene . RegionInfo . RegionName ] ;
2011-07-08 17:57:07 +00:00
2014-12-24 16:29:19 +00:00
if ( cnf = = null )
{
2014-12-31 18:50:48 +00:00
m_log . InfoFormat ( "[{0}]: No region section [{1}] found in configuration. Birds in this region are set to Disabled" , m_name , scene . RegionInfo . RegionName ) ;
2014-12-24 16:29:19 +00:00
m_enabled = false ;
return ;
}
m_enabled = cnf . GetBoolean ( "BirdsEnabled" , false ) ;
2014-07-17 16:43:21 +00:00
if ( m_enabled )
{
2014-12-24 16:29:19 +00:00
m_chatChannel = cnf . GetInt ( "BirdsChatChannel" , 118 ) ;
m_birdPrim = cnf . GetString ( "BirdsPrim" , "birdPrim" ) ;
2015-01-02 15:45:17 +00:00
m_flockSize = cnf . GetInt ( "BirdsFlockSize" , 50 ) ;
m_maxFlockSize = cnf . GetInt ( "BirdsMaxFlockSize" , 100 ) ;
2014-12-24 16:29:19 +00:00
m_maxSpeed = cnf . GetFloat ( "BirdsMaxSpeed" , 3f ) ;
m_maxForce = cnf . GetFloat ( "BirdsMaxForce" , 0.25f ) ;
m_neighbourDistance = cnf . GetFloat ( "BirdsNeighbourDistance" , 25f ) ;
m_desiredSeparation = cnf . GetFloat ( "BirdsDesiredSeparation" , 20f ) ;
m_tolerance = cnf . GetFloat ( "BirdsTolerance" , 5f ) ;
m_borderSize = cnf . GetFloat ( "BirdsRegionBorderSize" , 5f ) ;
m_maxHeight = cnf . GetInt ( "BirdsMaxHeight" , 256 ) ;
2014-12-31 18:50:48 +00:00
m_frameUpdateRate = cnf . GetInt ( "BirdsUpdateEveryNFrames" , 1 ) ;
m_log . InfoFormat ( "[{0}] Enabled on channel {1} with Flock Size {2}" , m_name , m_chatChannel , m_flockSize ) ;
2014-12-24 16:29:19 +00:00
2014-12-24 16:50:47 +00:00
m_scene = scene ;
2014-12-31 18:50:48 +00:00
m_console = MainConsole . Instance ;
2014-12-24 16:29:19 +00:00
2014-12-24 16:50:47 +00:00
//register commands with the scene
2014-07-17 16:43:21 +00:00
RegisterCommands ( ) ;
2011-07-08 17:57:07 +00:00
2014-07-17 16:43:21 +00:00
//register handlers
2014-12-31 18:50:48 +00:00
m_scene . EventManager . OnFrame + = FlockUpdate ;
m_scene . EventManager . OnChatFromClient + = SimChatSent ; //listen for commands sent from the client
2014-07-17 16:43:21 +00:00
// init module
2014-12-31 18:50:48 +00:00
m_model = new FlockingModel ( m_name , m_maxSpeed , m_maxForce , m_neighbourDistance , m_desiredSeparation , m_tolerance , m_borderSize ) ;
m_view = new FlockingView ( m_name , m_scene ) ;
2014-12-24 16:29:19 +00:00
m_view . BirdPrim = m_birdPrim ;
m_frame = 0 ;
2014-12-24 16:50:47 +00:00
2014-12-31 18:50:48 +00:00
FlockInitialise ( ) ;
2014-07-17 16:43:21 +00:00
}
2011-07-08 17:57:07 +00:00
}
public void RegionLoaded ( Scene scene )
{
2014-12-31 18:50:48 +00:00
//m_scene = scene;
if ( m_enabled ) {
// Mark Module Ready for duty
2011-07-09 11:35:13 +00:00
m_ready = true ;
2014-12-31 18:50:48 +00:00
}
2011-07-08 17:57:07 +00:00
}
public void RemoveRegion ( Scene scene )
{
2014-12-24 16:29:19 +00:00
m_log . InfoFormat ( "[{0}]: Removing region '{1}' from this module" , m_name , scene . RegionInfo . RegionName ) ;
2015-01-02 13:32:46 +00:00
if ( m_enabled ) {
m_view . Clear ( ) ;
2014-07-17 16:43:21 +00:00
m_ready = false ;
scene . EventManager . OnFrame - = FlockUpdate ;
scene . EventManager . OnChatFromClient - = SimChatSent ;
2011-07-08 17:57:07 +00:00
}
}
2014-07-17 16:43:21 +00:00
public void Close ( )
{
if ( m_enabled )
{
m_ready = false ;
m_scene . EventManager . OnFrame - = FlockUpdate ;
m_scene . EventManager . OnChatFromClient - = SimChatSent ;
}
}
2011-07-08 17:57:07 +00:00
# endregion
2014-12-31 18:50:48 +00:00
#region Helpers
public void FlockInitialise ( )
{
//make a flow map for this scene
FlowMap flowMap = new FlowMap ( m_scene , m_maxHeight , m_borderSize ) ;
flowMap . Initialise ( ) ;
// Generate initial flock values
m_model . Initialise ( m_flockSize , flowMap ) ;
// who is the owner for the flock in this region
m_owner = m_scene . RegionInfo . EstateSettings . EstateOwner ;
m_view . PostInitialize ( m_owner ) ;
}
# endregion
#region EventHandlers
public void FlockUpdate ( )
2011-07-09 11:35:13 +00:00
{
if ( ( ( m_frame + + % m_frameUpdateRate ) ! = 0 ) | | ! m_ready | | ! m_enabled ) {
return ;
}
2011-07-08 17:57:07 +00:00
2014-12-24 16:29:19 +00:00
//m_log.InfoFormat("update my birds");
2011-07-08 17:57:07 +00:00
// work out where everyone has moved to
// and tell the scene to render the new positions
2011-07-09 11:35:13 +00:00
lock ( m_sync ) {
2014-12-24 16:29:19 +00:00
List < Bird > birds = m_model . UpdateFlockPos ( ) ;
m_view . Render ( birds ) ;
2011-07-09 11:35:13 +00:00
}
}
2011-07-09 10:11:19 +00:00
protected void SimChatSent ( Object x , OSChatMessage msg )
{
2015-01-02 13:32:46 +00:00
if ( msg . Channel ! = m_chatChannel )
2011-07-09 10:11:19 +00:00
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
2011-07-10 15:37:00 +00:00
//bit of a hack - but lets us use CommandDelegate inWorld
2011-07-09 11:35:13 +00:00
string [ ] args = ( cmd + " <ui>" ) . Split ( " " . ToCharArray ( ) ) ;
2011-07-09 10:11:19 +00:00
if ( cmd . StartsWith ( "stop" ) ) {
2014-12-31 21:12:20 +00:00
HandleStopCmd ( m_name , args ) ;
2011-07-09 11:35:13 +00:00
} else if ( cmd . StartsWith ( "start" ) ) {
2014-12-31 21:12:20 +00:00
HandleStartCmd ( m_name , args ) ;
} else if ( cmd . StartsWith ( "enable" ) ) {
HandleEnableCmd ( m_name , args ) ;
} else if ( cmd . StartsWith ( "disable" ) ) {
HandleDisableCmd ( m_name , args ) ;
2011-07-09 11:35:13 +00:00
} else if ( cmd . StartsWith ( "size" ) ) {
2014-12-31 21:12:20 +00:00
HandleSetSizeCmd ( m_name , args ) ;
2011-07-09 11:35:13 +00:00
} else if ( cmd . StartsWith ( "stats" ) ) {
2014-12-31 21:12:20 +00:00
HandleShowStatsCmd ( m_name , args ) ;
2011-07-09 11:35:13 +00:00
} else if ( cmd . StartsWith ( "prim" ) ) {
2014-12-31 21:12:20 +00:00
HandleSetPrimCmd ( m_name , args ) ;
2011-07-09 12:38:04 +00:00
} else if ( cmd . StartsWith ( "framerate" ) ) {
2014-12-31 21:12:20 +00:00
HandleSetFrameRateCmd ( m_name , args ) ;
2011-07-09 10:11:19 +00:00
}
}
2011-07-08 17:57:07 +00:00
# endregion
2011-07-09 10:11:19 +00:00
#region Command Handling
private void AddCommand ( string cmd , string args , string help , CommandDelegate fn )
{
string argStr = "" ;
2011-07-09 11:35:13 +00:00
if ( args . Trim ( ) . Length > 0 ) {
2011-07-09 10:11:19 +00:00
argStr = " <" + args + "> " ;
}
2014-12-31 18:50:48 +00:00
m_log . InfoFormat ( "[{0}]: Adding command {1} - {2} to region '{3}'" , m_name , "birds-" + cmd + argStr , help , m_scene . RegionInfo . RegionName ) ;
//m_scene.AddCommand (this, "birds-" + cmd, "birds-" + cmd + argStr, help, fn);
m_console . Commands . AddCommand ( m_name , false , "birds-" + cmd , "birds-" + cmd + argStr , help , fn ) ;
}
2011-07-08 17:57:07 +00:00
2011-07-09 11:35:13 +00:00
private void RegisterCommands ( )
{
2014-12-31 18:50:48 +00:00
AddCommand ( "stop" , "" , "Stop Birds Flocking" , HandleStopCmd ) ;
AddCommand ( "start" , "" , "Start Birds Flocking" , HandleStartCmd ) ;
AddCommand ( "enable" , "" , "Enable Birds Flocking" , HandleEnableCmd ) ;
AddCommand ( "disable" , "" , "Disable Birds Flocking" , HandleDisableCmd ) ;
2011-07-09 10:11:19 +00:00
AddCommand ( "size" , "num" , "Adjust the size of the flock " , HandleSetSizeCmd ) ;
AddCommand ( "stats" , "" , "show flocking stats" , HandleShowStatsCmd ) ;
2014-12-24 16:29:19 +00:00
AddCommand ( "prim" , "name" , "set the prim used for each bird to that passed in" , HandleSetPrimCmd ) ;
AddCommand ( "framerate" , "num" , "[debugging] only update birds every <num> frames" , HandleSetFrameRateCmd ) ;
2011-07-09 10:11:19 +00:00
}
2011-07-09 11:35:13 +00:00
private bool ShouldHandleCmd ( )
{
2014-12-31 21:12:20 +00:00
if ( ! ( m_console . ConsoleScene = = null | | m_console . ConsoleScene = = m_scene ) ) {
2014-12-31 18:50:48 +00:00
return false ;
}
2014-12-31 21:12:20 +00:00
return true ;
}
2011-07-09 10:11:19 +00:00
2011-07-09 11:35:13 +00:00
private bool IsInWorldCmd ( ref string [ ] args )
{
2014-12-31 21:12:20 +00:00
if ( args . Length > 0 & & args [ args . Length - 1 ] . Equals ( "<ui>" ) ) {
m_log . InfoFormat ( "[{0}]: Inworld command detected in region {1}" , m_name , m_scene . RegionInfo . RegionName ) ;
return true ;
}
return false ;
2011-07-09 10:11:19 +00:00
}
2011-07-09 11:35:13 +00:00
private void ShowResponse ( string response , bool inWorld )
{
if ( inWorld ) {
IClientAPI ownerAPI = null ;
if ( m_scene . TryGetClient ( m_owner , out ownerAPI ) ) {
2014-12-24 16:29:19 +00:00
ownerAPI . SendBlueBoxMessage ( m_owner , "Birds" , response ) ;
2011-07-09 10:11:19 +00:00
}
2011-07-09 11:35:13 +00:00
} else {
MainConsole . Instance . Output ( response ) ;
}
2011-07-09 10:11:19 +00:00
}
2014-12-31 18:50:48 +00:00
public void HandleDisableCmd ( string module , string [ ] args )
{
2015-01-02 13:32:46 +00:00
if ( m_ready & & ShouldHandleCmd ( ) ) {
m_log . InfoFormat ( "[{0}]: Bird flocking is disabled in region {1}." , m_name , m_scene . RegionInfo . RegionName ) ;
2014-12-31 18:50:48 +00:00
m_enabled = false ;
m_ready = false ;
m_view . Clear ( ) ;
}
}
public void HandleEnableCmd ( string module , string [ ] args )
{
if ( ! m_ready & & ShouldHandleCmd ( ) )
2015-01-02 13:32:46 +00:00
{
m_log . InfoFormat ( "[{0}]: Bird flocking is enabled in region {1}." , m_name , m_scene . RegionInfo . RegionName ) ;
2014-12-31 18:50:48 +00:00
m_enabled = true ;
m_ready = true ;
}
}
2011-07-09 10:11:19 +00:00
public void HandleStopCmd ( string module , string [ ] args )
{
2014-12-31 18:50:48 +00:00
if ( m_enabled & & m_ready & & ShouldHandleCmd ( ) )
2015-01-02 13:32:46 +00:00
{
m_log . InfoFormat ( "[{0}]: Bird flocking is stopped in region {1}." , m_name , m_scene . RegionInfo . RegionName ) ;
2011-07-09 10:11:19 +00:00
m_enabled = false ;
}
}
2014-12-31 18:50:48 +00:00
public void HandleStartCmd ( string module , string [ ] args )
{
if ( ! m_enabled & & m_ready & & ShouldHandleCmd ( ) )
2015-01-02 13:32:46 +00:00
{
m_log . InfoFormat ( "[{0}]: Bird flocking is started in region {1}." , m_name , m_scene . RegionInfo . RegionName ) ;
2014-12-31 18:50:48 +00:00
m_enabled = true ;
FlockUpdate ( ) ;
}
}
2011-07-09 12:38:04 +00:00
void HandleSetFrameRateCmd ( string module , string [ ] args )
{
if ( ShouldHandleCmd ( ) ) {
int frameRate = Convert . ToInt32 ( args [ 1 ] ) ;
2015-01-02 13:32:46 +00:00
m_frameUpdateRate = frameRate ;
m_log . InfoFormat ( "[{0}]: Bird updates set to every {1} frames in region {2}." , m_name , frameRate , m_scene . RegionInfo . RegionName ) ;
2011-07-09 12:38:04 +00:00
}
}
2011-07-09 10:11:19 +00:00
public void HandleSetSizeCmd ( string module , string [ ] args )
{
2011-07-09 11:35:13 +00:00
if ( ShouldHandleCmd ( ) ) {
lock ( m_sync ) {
2015-01-02 15:45:17 +00:00
int newSize = Convert . ToInt32 ( args [ 1 ] ) ;
if ( newSize > m_maxFlockSize ) newSize = m_maxFlockSize ;
2015-01-02 13:32:46 +00:00
m_model . Size = newSize ;
m_log . InfoFormat ( "[{0}]: Bird flock size is set to {1} in region {2}." , m_name , newSize , m_scene . RegionInfo . RegionName ) ;
2011-07-09 11:35:13 +00:00
m_view . Clear ( ) ;
}
2011-07-09 10:11:19 +00:00
}
}
public void HandleShowStatsCmd ( string module , string [ ] args )
{
2011-07-09 11:35:13 +00:00
if ( ShouldHandleCmd ( ) ) {
bool inWorld = IsInWorldCmd ( ref args ) ;
2014-12-24 16:29:19 +00:00
ShowResponse ( "Num Birds = " + m_model . Size , inWorld ) ;
2011-07-09 10:11:19 +00:00
}
}
public void HandleSetPrimCmd ( string module , string [ ] args )
{
2011-07-09 11:35:13 +00:00
if ( ShouldHandleCmd ( ) ) {
2011-07-09 12:27:58 +00:00
string primName = args [ 1 ] ;
lock ( m_sync ) {
2015-01-02 13:32:46 +00:00
m_view . BirdPrim = primName ;
m_log . InfoFormat ( "[{0}]: Bird prim is set to {1} in region {2}." , m_name , primName , m_scene . RegionInfo . RegionName ) ;
2011-07-09 12:27:58 +00:00
m_view . Clear ( ) ;
}
2011-07-09 10:11:19 +00:00
}
}
2011-07-09 11:35:13 +00:00
2011-07-09 10:11:19 +00:00
# endregion
2011-07-08 17:57:07 +00:00
}
}