Initial commit

I wish I could figure out how to have PlexVie be out of the LibOMV tree but its just not working die to a DLL not found exception about libopenjpeg. (Yes the dll is in the bin folder)
This will do for now
This commit is contained in:
Blake Bourque
2015-06-18 22:15:24 -04:00
commit 0bb2dff347
382 changed files with 273704 additions and 0 deletions
+33
View File
@@ -0,0 +1,33 @@
using System;
using OpenMetaverse;
namespace PlexView
{
public class PlexView
{
public PlexView (string[] args)
{
GridClient client = new GridClient();
client.Settings.LOGIN_SERVER = "http://login.osgrid.org/";
if (client.Network.Login("", "", "", "FirstBot", "1.0"))
{
// Yay we made it! let's print out the message of the day
Console.WriteLine("You have successfully logged into Second Life!\n The Message of the day is {0}\nPress any Key to Logout",
client.Network.LoginMessage);
Console.ReadLine(); // Wait for user to press a key before we continue
client.Network.Logout(); // Lets logout since we're done here
}
else
{
// tell the user why the login failed
Console.WriteLine("We were unable to login to Second Life, The Login Server said: {0}",
client.Network.LoginMessage);
}
Console.WriteLine("Press Any Key to Exit");
Console.ReadLine(); // Wait for user to press a key before we exit
}
}
}
@@ -0,0 +1,39 @@
<?xml version="1.0" ?>
<project name="PlexView" default="build">
<target name="build">
<echo message="Build Directory is ${build.dir}" />
<mkdir dir="${build.dir}" />
<csc target="exe" debug="${build.debug}" unsafe="True" warnaserror="False" define="TRACE" nostdlib="False" main="" output="${build.dir}/${project::get-name()}.exe">
<resources prefix="PlexView" dynamicprefix="true" >
</resources>
<sources failonempty="true">
<include name="PlexView.cs" />
<include name="Program.cs" />
<include name="Properties/AssemblyInfo.cs" />
</sources>
<references basedir="${project::get-base-directory()}">
<lib>
<include name="${project::get-base-directory()}" />
<include name="${build.dir}" />
</lib>
<include name="System.dll" />
<include name="${build.dir}/OpenMetaverse.dll" />
<include name="${build.dir}/OpenMetaverseTypes.dll" />
<include name="${build.dir}/OpenMetaverse.Utilities.dll" />
<include name="${build.dir}/OpenMetaverse.StructuredData.dll" />
</references>
<nowarn>
<warning number="1591" />
<warning number="1574" />
<warning number="0419" />
<warning number="0618" />
</nowarn>
</csc>
</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>
+31
View File
@@ -0,0 +1,31 @@
<Project name="PlexView" description="" standardNamespace="PlexView" newfilesearch="None" enableviewstate="True" fileversion="2.0" language="C#" clr-version="Net_2_0" ctype="DotNetProject">
<Configurations active="Debug">
<Configuration name="Release" ctype="DotNetProjectConfiguration">
<Output directory="./../../../bin/" assembly="PlexView" executeScript="" executeBeforeBuild="" executeAfterBuild="" executeBeforeBuildArguments="" executeAfterBuildArguments="" />
<Build debugmode="True" target="Exe" />
<Execution runwithwarnings="True" consolepause="True" runtime="MsNet" clr-version="Net_2_0" />
<CodeGeneration compiler="Csc" warninglevel="4" nowarn="1591,1574,0419,0618" includedebuginformation="False" optimize="True" unsafecodeallowed="True" generateoverflowchecks="False" mainclass="" target="Exe" definesymbols="TRACE" generatexmldocumentation="False" win32Icon="" ctype="CSharpCompilerParameters" />
</Configuration>
<Configuration name="Debug" ctype="DotNetProjectConfiguration">
<Output directory="./../../../bin/" assembly="PlexView" executeScript="" executeBeforeBuild="" executeAfterBuild="" executeBeforeBuildArguments="" executeAfterBuildArguments="" />
<Build debugmode="True" target="Exe" />
<Execution runwithwarnings="True" consolepause="True" runtime="MsNet" clr-version="Net_2_0" />
<CodeGeneration compiler="Csc" warninglevel="4" nowarn="1591,1574,0419,0618" includedebuginformation="True" optimize="False" unsafecodeallowed="True" generateoverflowchecks="False" mainclass="" target="Exe" definesymbols="TRACE;DEBUG" generatexmldocumentation="False" win32Icon="" ctype="CSharpCompilerParameters" />
</Configuration>
</Configurations>
<DeploymentInformation target="" script="" strategy="File">
<excludeFiles />
</DeploymentInformation>
<Contents>
<File name="./PlexView.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
<File name="./Program.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
<File name="./Properties/AssemblyInfo.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
</Contents>
<References>
<ProjectReference type="Gac" localcopy="False" refto="System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<ProjectReference type="Project" localcopy="False" refto="OpenMetaverse" />
<ProjectReference type="Project" localcopy="False" refto="OpenMetaverseTypes" />
<ProjectReference type="Project" localcopy="False" refto="OpenMetaverse.Utilities" />
<ProjectReference type="Project" localcopy="False" refto="OpenMetaverse.StructuredData" />
</References>
</Project>
+13
View File
@@ -0,0 +1,13 @@
using System;
namespace PlexView
{
public class Program
{
public static void Main (string[] args)
{
new PlexView(args);
}
}
}
@@ -0,0 +1,33 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("PlexView")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("PlexView")]
[assembly: AssemblyCopyright("Copyright © 2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("83715687-9058-4d2a-8090-d8726dd5cd74")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>
<log4net>
<appender name="FileAppender" type="log4net.Appender.FileAppender">
<file value="PlexView.log.txt" />
<appendToFile value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level - %message%newline" />
</layout>
</appender>
<logger name="OpenMetaverse">
<level value="DEBUG" />
<appender-ref ref="FileAppender" />
</logger>
</log4net>
</configuration>
+111
View File
@@ -0,0 +1,111 @@
using System;
using System.Collections.Specialized;
using System.Text.RegularExpressions;
namespace CommandLine.Utility
{
/// <summary>
/// Arguments class
/// </summary>
public class Arguments
{
// Variables
private StringDictionary Parameters;
// Constructor
public Arguments(string[] Args)
{
Parameters = new StringDictionary();
Regex Splitter = new Regex(@"^-{1,2}|=",
RegexOptions.IgnoreCase | RegexOptions.Compiled);
Regex Remover = new Regex(@"^['""]?(.*?)['""]?$",
RegexOptions.IgnoreCase | RegexOptions.Compiled);
string Parameter = null;
string[] Parts;
// Valid parameters forms:
// {-,/,--}param{ ,=,:}((",')value(",'))
// Examples:
// -param1 value1 --param2
// /param4=happy -param5 '--=nice=--'
foreach (string Txt in Args)
{
// Look for new parameters (-,/ or --) and a
// possible enclosed value (=,:)
Parts = Splitter.Split(Txt, 3);
switch (Parts.Length)
{
// Found a value (for the last parameter
// found (space separator))
case 1:
if (Parameter != null)
{
if (!Parameters.ContainsKey(Parameter))
{
Parts[0] =
Remover.Replace(Parts[0], "$1");
Parameters.Add(Parameter, Parts[0]);
}
Parameter = null;
}
// else Error: no parameter waiting for a value (skipped)
break;
// Found just a parameter
case 2:
// The last parameter is still waiting.
// With no value, set it to true.
if (Parameter != null)
{
if (!Parameters.ContainsKey(Parameter))
Parameters.Add(Parameter, "true");
}
Parameter = Parts[1];
break;
// Parameter with enclosed value
case 3:
// The last parameter is still waiting.
// With no value, set it to true.
if (Parameter != null)
{
if (!Parameters.ContainsKey(Parameter))
Parameters.Add(Parameter, "true");
}
Parameter = Parts[1];
// Remove possible enclosing characters (",')
if (!Parameters.ContainsKey(Parameter))
{
Parts[2] = Remover.Replace(Parts[2], "$1");
Parameters.Add(Parameter, Parts[2]);
}
Parameter = null;
break;
}
}
// In case a parameter is still waiting
if (Parameter != null)
{
if (!Parameters.ContainsKey(Parameter))
Parameters.Add(Parameter, "true");
}
}
// Retrieve a parameter value if it exists
// (overriding C# indexer property)
public string this[string Param]
{
get
{
return (Parameters[Param]);
}
}
}
}
@@ -0,0 +1,387 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Xml;
using System.Threading;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace OpenMetaverse.TestClient
{
public class LoginDetails
{
public string FirstName;
public string LastName;
public string Password;
public string StartLocation;
public bool GroupCommands;
public string MasterName;
public UUID MasterKey;
public string URI;
}
public class StartPosition
{
public string sim;
public int x;
public int y;
public int z;
public StartPosition()
{
this.sim = null;
this.x = 0;
this.y = 0;
this.z = 0;
}
}
public sealed class ClientManager
{
const string VERSION = "1.0.0";
class Singleton { internal static readonly ClientManager Instance = new ClientManager(); }
public static ClientManager Instance { get { return Singleton.Instance; } }
public Dictionary<UUID, TestClient> Clients = new Dictionary<UUID, TestClient>();
public Dictionary<Simulator, Dictionary<uint, Primitive>> SimPrims = new Dictionary<Simulator, Dictionary<uint, Primitive>>();
public bool Running = true;
public bool GetTextures = false;
public volatile int PendingLogins = 0;
public string onlyAvatar = String.Empty;
ClientManager()
{
}
public void Start(List<LoginDetails> accounts, bool getTextures)
{
GetTextures = getTextures;
foreach (LoginDetails account in accounts)
Login(account);
}
public TestClient Login(string[] args)
{
if (args.Length < 3)
{
Console.WriteLine("Usage: login firstname lastname password [simname] [login server url]");
return null;
}
LoginDetails account = new LoginDetails();
account.FirstName = args[0];
account.LastName = args[1];
account.Password = args[2];
if (args.Length > 3)
{
// If it looks like a full starting position was specified, parse it
if (args[3].StartsWith("http"))
{
account.URI = args[3];
}
else
{
if (args[3].IndexOf('/') >= 0)
{
char sep = '/';
string[] startbits = args[3].Split(sep);
try
{
account.StartLocation = NetworkManager.StartLocation(startbits[0], Int32.Parse(startbits[1]),
Int32.Parse(startbits[2]), Int32.Parse(startbits[3]));
}
catch (FormatException) { }
}
// Otherwise, use the center of the named region
if (account.StartLocation == null)
account.StartLocation = NetworkManager.StartLocation(args[3], 128, 128, 40);
}
}
if (args.Length > 4)
if (args[4].StartsWith("http"))
account.URI = args[4];
if (string.IsNullOrEmpty(account.URI))
account.URI = Program.LoginURI;
Logger.Log("Using login URI " + account.URI, Helpers.LogLevel.Info);
return Login(account);
}
public TestClient Login(LoginDetails account)
{
// Check if this client is already logged in
foreach (TestClient c in Clients.Values)
{
if (c.Self.FirstName == account.FirstName && c.Self.LastName == account.LastName)
{
Logout(c);
break;
}
}
++PendingLogins;
TestClient client = new TestClient(this);
client.Network.LoginProgress +=
delegate(object sender, LoginProgressEventArgs e)
{
Logger.Log(String.Format("Login {0}: {1}", e.Status, e.Message), Helpers.LogLevel.Info, client);
if (e.Status == LoginStatus.Success)
{
Clients[client.Self.AgentID] = client;
if (client.MasterKey == UUID.Zero)
{
UUID query = UUID.Zero;
EventHandler<DirPeopleReplyEventArgs> peopleDirCallback =
delegate(object sender2, DirPeopleReplyEventArgs dpe)
{
if (dpe.QueryID == query)
{
if (dpe.MatchedPeople.Count != 1)
{
Logger.Log("Unable to resolve master key from " + client.MasterName, Helpers.LogLevel.Warning);
}
else
{
client.MasterKey = dpe.MatchedPeople[0].AgentID;
Logger.Log("Master key resolved to " + client.MasterKey, Helpers.LogLevel.Info);
}
}
};
client.Directory.DirPeopleReply += peopleDirCallback;
query = client.Directory.StartPeopleSearch(client.MasterName, 0);
}
Logger.Log("Logged in " + client.ToString(), Helpers.LogLevel.Info);
--PendingLogins;
}
else if (e.Status == LoginStatus.Failed)
{
Logger.Log("Failed to login " + account.FirstName + " " + account.LastName + ": " +
client.Network.LoginMessage, Helpers.LogLevel.Warning);
--PendingLogins;
}
};
// Optimize the throttle
client.Throttle.Wind = 0;
client.Throttle.Cloud = 0;
client.Throttle.Land = 1000000;
client.Throttle.Task = 1000000;
client.GroupCommands = account.GroupCommands;
client.MasterName = account.MasterName;
client.MasterKey = account.MasterKey;
client.AllowObjectMaster = client.MasterKey != UUID.Zero; // Require UUID for object master.
LoginParams loginParams = client.Network.DefaultLoginParams(
account.FirstName, account.LastName, account.Password, "TestClient", VERSION);
if (!String.IsNullOrEmpty(account.StartLocation))
loginParams.Start = account.StartLocation;
if (!String.IsNullOrEmpty(account.URI))
loginParams.URI = account.URI;
client.Network.BeginLogin(loginParams);
return client;
}
/// <summary>
///
/// </summary>
public void Run(bool noGUI)
{
if (noGUI)
{
while (Running)
{
Thread.Sleep(2 * 1000);
}
}
else {
Console.WriteLine("Type quit to exit. Type help for a command list.");
while (Running)
{
PrintPrompt();
string input = Console.ReadLine();
DoCommandAll(input, UUID.Zero);
}
}
foreach (GridClient client in Clients.Values)
{
if (client.Network.Connected)
client.Network.Logout();
}
}
private void PrintPrompt()
{
int online = 0;
foreach (GridClient client in Clients.Values)
{
if (client.Network.Connected) online++;
}
Console.Write(online + " avatars online> ");
}
/// <summary>
///
/// </summary>
/// <param name="cmd"></param>
/// <param name="fromAgentID"></param>
/// <param name="imSessionID"></param>
public void DoCommandAll(string cmd, UUID fromAgentID)
{
string[] tokens = cmd.Trim().Split(new char[] { ' ', '\t' });
if (tokens.Length == 0)
return;
string firstToken = tokens[0].ToLower();
if (String.IsNullOrEmpty(firstToken))
return;
// Allow for comments when cmdline begins with ';' or '#'
if (firstToken[0] == ';' || firstToken[0] == '#')
return;
if ('@' == firstToken[0]) {
onlyAvatar = String.Empty;
if (tokens.Length == 3) {
bool found = false;
onlyAvatar = tokens[1]+" "+tokens[2];
foreach (TestClient client in Clients.Values) {
if ((client.ToString() == onlyAvatar) && (client.Network.Connected)) {
found = true;
break;
}
}
if (found) {
Logger.Log("Commanding only "+onlyAvatar+" now", Helpers.LogLevel.Info);
} else {
Logger.Log("Commanding nobody now. Avatar "+onlyAvatar+" is offline", Helpers.LogLevel.Info);
}
} else {
Logger.Log("Commanding all avatars now", Helpers.LogLevel.Info);
}
return;
}
string[] args = new string[tokens.Length - 1];
if (args.Length > 0)
Array.Copy(tokens, 1, args, 0, args.Length);
if (firstToken == "login")
{
Login(args);
}
else if (firstToken == "quit")
{
Quit();
Logger.Log("All clients logged out and program finished running.", Helpers.LogLevel.Info);
}
else if (firstToken == "help")
{
if (Clients.Count > 0)
{
foreach (TestClient client in Clients.Values)
{
Console.WriteLine(client.Commands["help"].Execute(args, UUID.Zero));
break;
}
}
else
{
Console.WriteLine("You must login at least one bot to use the help command");
}
}
else if (firstToken == "script")
{
// No reason to pass this to all bots, and we also want to allow it when there are no bots
ScriptCommand command = new ScriptCommand(null);
Logger.Log(command.Execute(args, UUID.Zero), Helpers.LogLevel.Info);
}
else if (firstToken == "waitforlogin")
{
// Special exception to allow this to run before any bots have logged in
if (ClientManager.Instance.PendingLogins > 0)
{
WaitForLoginCommand command = new WaitForLoginCommand(null);
Logger.Log(command.Execute(args, UUID.Zero), Helpers.LogLevel.Info);
}
else
{
Logger.Log("No pending logins", Helpers.LogLevel.Info);
}
}
else
{
// Make an immutable copy of the Clients dictionary to safely iterate over
Dictionary<UUID, TestClient> clientsCopy = new Dictionary<UUID, TestClient>(Clients);
int completed = 0;
foreach (TestClient client in clientsCopy.Values)
{
ThreadPool.QueueUserWorkItem((WaitCallback)
delegate(object state)
{
TestClient testClient = (TestClient)state;
if ((String.Empty == onlyAvatar) || (testClient.ToString() == onlyAvatar)) {
if (testClient.Commands.ContainsKey(firstToken)) {
string result;
try {
result = testClient.Commands[firstToken].Execute(args, fromAgentID);
Logger.Log(result, Helpers.LogLevel.Info, testClient);
} catch(Exception e) {
Logger.Log(String.Format("{0} raised exception {1}", firstToken, e),
Helpers.LogLevel.Error,
testClient);
}
} else
Logger.Log("Unknown command " + firstToken, Helpers.LogLevel.Warning);
}
++completed;
},
client);
}
while (completed < clientsCopy.Count)
Thread.Sleep(50);
}
}
/// <summary>
///
/// </summary>
/// <param name="client"></param>
public void Logout(TestClient client)
{
Clients.Remove(client.Self.AgentID);
client.Network.Logout();
}
/// <summary>
///
/// </summary>
public void Quit()
{
Running = false;
// TODO: It would be really nice if we could figure out a way to abort the ReadLine here in so that Run() will exit.
}
}
}
+61
View File
@@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using System.Text;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace OpenMetaverse.TestClient
{
public enum CommandCategory : int
{
Parcel,
Appearance,
Movement,
Simulator,
Communication,
Inventory,
Objects,
Voice,
TestClient,
Friends,
Groups,
Other,
Unknown,
Search
}
public abstract class Command : IComparable
{
public string Name;
public string Description;
public CommandCategory Category;
public TestClient Client;
public abstract string Execute(string[] args, UUID fromAgentID);
/// <summary>
/// When set to true, think will be called.
/// </summary>
public bool Active;
/// <summary>
/// Called twice per second, when Command.Active is set to true.
/// </summary>
public virtual void Think()
{
}
public int CompareTo(object obj)
{
if (obj is Command)
{
Command c2 = (Command)obj;
return Category.CompareTo(c2.Category);
}
else
throw new ArgumentException("Object is not of type Command.");
}
}
}
@@ -0,0 +1,84 @@
using System;
using System.Collections.Generic;
using System.Text;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace OpenMetaverse.TestClient
{
public class BotsCommand : Command
{
private Dictionary<UUID, bool> m_AgentList = new Dictionary<UUID, bool>();
public BotsCommand(TestClient testClient)
{
Name = "bots";
Description = "detects avatars that appear to be bots.";
Category = CommandCategory.Other;
testClient.Avatars.ViewerEffect += new EventHandler<ViewerEffectEventArgs>(Avatars_ViewerEffect);
testClient.Avatars.ViewerEffectLookAt += new EventHandler<ViewerEffectLookAtEventArgs>(Avatars_ViewerEffectLookAt);
testClient.Avatars.ViewerEffectPointAt += new EventHandler<ViewerEffectPointAtEventArgs>(Avatars_ViewerEffectPointAt);
}
private void Avatars_ViewerEffectPointAt(object sender, ViewerEffectPointAtEventArgs e)
{
lock (m_AgentList)
{
if (m_AgentList.ContainsKey(e.SourceID))
m_AgentList[e.SourceID] = true;
else
m_AgentList.Add(e.SourceID, true);
}
}
private void Avatars_ViewerEffectLookAt(object sender, ViewerEffectLookAtEventArgs e)
{
lock (m_AgentList)
{
if (m_AgentList.ContainsKey(e.SourceID))
m_AgentList[e.SourceID] = true;
else
m_AgentList.Add(e.SourceID, true);
}
}
private void Avatars_ViewerEffect(object sender, ViewerEffectEventArgs e)
{
lock (m_AgentList)
{
if (m_AgentList.ContainsKey(e.SourceID))
m_AgentList[e.SourceID] = true;
else
m_AgentList.Add(e.SourceID, true);
}
}
public override string Execute(string[] args, UUID fromAgentID)
{
StringBuilder result = new StringBuilder();
lock (Client.Network.Simulators)
{
for (int i = 0; i < Client.Network.Simulators.Count; i++)
{
Client.Network.Simulators[i].ObjectsAvatars.ForEach(
delegate(Avatar av)
{
lock (m_AgentList)
{
if (!m_AgentList.ContainsKey(av.ID))
{
result.AppendLine();
result.AppendFormat("{0} (Group: {1}, Location: {2}, UUID: {3} LocalID: {4}) Is Probably a bot",
av.Name, av.GroupName, av.Position, av.ID, av.LocalID);
}
}
}
);
}
}
return result.ToString();
}
}
}
@@ -0,0 +1,159 @@
using System;
using System.Collections.Generic;
using System.Threading;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace OpenMetaverse.TestClient
{
public class CloneProfileCommand : Command
{
Avatar.AvatarProperties Properties;
Avatar.Interests Interests;
List<UUID> Groups = new List<UUID>();
bool ReceivedProperties = false;
bool ReceivedInterests = false;
bool ReceivedGroups = false;
ManualResetEvent ReceivedProfileEvent = new ManualResetEvent(false);
public CloneProfileCommand(TestClient testClient)
{
testClient.Avatars.AvatarInterestsReply += new EventHandler<AvatarInterestsReplyEventArgs>(Avatars_AvatarInterestsReply);
testClient.Avatars.AvatarPropertiesReply += new EventHandler<AvatarPropertiesReplyEventArgs>(Avatars_AvatarPropertiesReply);
testClient.Avatars.AvatarGroupsReply += new EventHandler<AvatarGroupsReplyEventArgs>(Avatars_AvatarGroupsReply);
testClient.Groups.GroupJoinedReply += new EventHandler<GroupOperationEventArgs>(Groups_OnGroupJoined);
testClient.Avatars.AvatarPicksReply += new EventHandler<AvatarPicksReplyEventArgs>(Avatars_AvatarPicksReply);
testClient.Avatars.PickInfoReply += new EventHandler<PickInfoReplyEventArgs>(Avatars_PickInfoReply);
Name = "cloneprofile";
Description = "Clones another avatars profile as closely as possible. WARNING: This command will " +
"destroy your existing profile! Usage: cloneprofile [targetuuid]";
Category = CommandCategory.Other;
}
public override string Execute(string[] args, UUID fromAgentID)
{
if (args.Length != 1)
return Description;
UUID targetID;
ReceivedProperties = false;
ReceivedInterests = false;
ReceivedGroups = false;
try
{
targetID = new UUID(args[0]);
}
catch (Exception)
{
return Description;
}
// Request all of the packets that make up an avatar profile
Client.Avatars.RequestAvatarProperties(targetID);
//Request all of the avatars pics
Client.Avatars.RequestAvatarPicks(Client.Self.AgentID);
Client.Avatars.RequestAvatarPicks(targetID);
// Wait for all the packets to arrive
ReceivedProfileEvent.Reset();
ReceivedProfileEvent.WaitOne(5000, false);
// Check if everything showed up
if (!ReceivedInterests || !ReceivedProperties || !ReceivedGroups)
return "Failed to retrieve a complete profile for that UUID";
// Synchronize our profile
Client.Self.UpdateInterests(Interests);
Client.Self.UpdateProfile(Properties);
// TODO: Leave all the groups we're currently a member of? This could
// break TestClient connectivity that might be relying on group authentication
// Attempt to join all the groups
foreach (UUID groupID in Groups)
{
Client.Groups.RequestJoinGroup(groupID);
}
return "Synchronized our profile to the profile of " + targetID.ToString();
}
void Groups_OnGroupJoined(object sender, GroupOperationEventArgs e)
{
Console.WriteLine(Client.ToString() + (e.Success ? " joined " : " failed to join ") +
e.GroupID.ToString());
if (e.Success)
{
Console.WriteLine(Client.ToString() + " setting " + e.GroupID.ToString() +
" as the active group");
Client.Groups.ActivateGroup(e.GroupID);
}
}
void Avatars_PickInfoReply(object sender, PickInfoReplyEventArgs e)
{
Client.Self.PickInfoUpdate(e.PickID, e.Pick.TopPick, e.Pick.ParcelID, e.Pick.Name, e.Pick.PosGlobal, e.Pick.SnapshotID, e.Pick.Desc);
}
void Avatars_AvatarPicksReply(object sender, AvatarPicksReplyEventArgs e)
{
foreach (KeyValuePair<UUID, string> kvp in e.Picks)
{
if (e.AvatarID == Client.Self.AgentID)
{
Client.Self.PickDelete(kvp.Key);
}
else
{
Client.Avatars.RequestPickInfo(e.AvatarID, kvp.Key);
}
}
}
void Avatars_AvatarGroupsReply(object sender, AvatarGroupsReplyEventArgs e)
{
lock (ReceivedProfileEvent)
{
foreach (AvatarGroup group in e.Groups)
{
Groups.Add(group.GroupID);
}
ReceivedGroups = true;
if (ReceivedInterests && ReceivedProperties && ReceivedGroups)
ReceivedProfileEvent.Set();
}
}
void Avatars_AvatarPropertiesReply(object sender, AvatarPropertiesReplyEventArgs e)
{
lock (ReceivedProfileEvent)
{
Properties = e.Properties;
ReceivedProperties = true;
if (ReceivedInterests && ReceivedProperties && ReceivedGroups)
ReceivedProfileEvent.Set();
}
}
void Avatars_AvatarInterestsReply(object sender, AvatarInterestsReplyEventArgs e)
{
lock (ReceivedProfileEvent)
{
Interests = e.Interests;
ReceivedInterests = true;
if (ReceivedInterests && ReceivedProperties && ReceivedGroups)
ReceivedProfileEvent.Set();
}
}
}
}
@@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using System.Text;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace OpenMetaverse.TestClient
{
/// <summary>
/// Sends a packet of type GenericMessage to the simulator.
/// </summary>
public class GenericMessageCommand : Command
{
public GenericMessageCommand(TestClient testClient)
{
Name = "sendgeneric";
Description = "send a generic UDP message to the simulator.";
Category = CommandCategory.Other;
}
public override string Execute(string[] args, UUID fromAgentID)
{
UUID target;
if (args.Length < 1)
return "Usage: sendgeneric method_name [value1 value2 ...]";
string methodName = args[0];
GenericMessagePacket gmp = new GenericMessagePacket();
gmp.AgentData.AgentID = Client.Self.AgentID;
gmp.AgentData.SessionID = Client.Self.SessionID;
gmp.AgentData.TransactionID = UUID.Zero;
gmp.MethodData.Method = Utils.StringToBytes(methodName);
gmp.MethodData.Invoice = UUID.Zero;
gmp.ParamList = new GenericMessagePacket.ParamListBlock[args.Length - 1];
StringBuilder sb = new StringBuilder();
for (int i = 1; i < args.Length; i++)
{
GenericMessagePacket.ParamListBlock paramBlock = new GenericMessagePacket.ParamListBlock();
paramBlock.Parameter = Utils.StringToBytes(args[i]);
gmp.ParamList[i - 1] = paramBlock;
sb.AppendFormat(" {0}", args[i]);
}
Client.Network.SendPacket(gmp);
return string.Format("Sent generic message with method {0}, params{1}", methodName, sb);
}
}
}
@@ -0,0 +1,82 @@
using System;
using System.Text;
using System.Reflection;
using System.Collections.Generic;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace OpenMetaverse.TestClient
{
public class PlayAnimationCommand : Command
{
private Dictionary<UUID, string> m_BuiltInAnimations = new Dictionary<UUID, string>(Animations.ToDictionary());
public PlayAnimationCommand(TestClient testClient)
{
Name = "play";
Description = "Attempts to play an animation";
Category = CommandCategory.Appearance;
}
private string Usage()
{
String usage = "Usage:\n" +
"\tplay list - list the built in animations\n" +
"\tplay show - show any currently playing animations\n" +
"\tplay UUID - play an animation asset\n" +
"\tplay ANIMATION - where ANIMATION is one of the values returned from \"play list\"\n";
return usage;
}
public override string Execute(string[] args, UUID fromAgentID)
{
StringBuilder result = new StringBuilder();
if (args.Length != 1)
return Usage();
UUID animationID;
string arg = args[0].Trim();
if (UUID.TryParse(args[0], out animationID))
{
Client.Self.AnimationStart(animationID, true);
}
else if (arg.ToLower().Equals("list"))
{
foreach (string key in m_BuiltInAnimations.Values)
{
result.AppendLine(key);
}
}
else if (arg.ToLower().Equals("show"))
{
Client.Self.SignaledAnimations.ForEach(delegate(KeyValuePair<UUID, int> kvp) {
if (m_BuiltInAnimations.ContainsKey(kvp.Key))
{
result.AppendFormat("The {0} System Animation is being played, sequence is {1}", m_BuiltInAnimations[kvp.Key], kvp.Value);
}
else
{
result.AppendFormat("The {0} Asset Animation is being played, sequence is {0}", kvp.Key, kvp.Value);
}
});
}
else if (m_BuiltInAnimations.ContainsValue(args[0].Trim().ToUpper()))
{
foreach (var kvp in m_BuiltInAnimations)
{
if (kvp.Value.Equals(arg.ToUpper()))
{
Client.Self.AnimationStart(kvp.Key, true);
break;
}
}
}
else
{
return Usage();
}
return result.ToString();
}
}
}
@@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using System.Text;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace OpenMetaverse.TestClient
{
public class TouchCommand: Command
{
public TouchCommand(TestClient testClient)
{
Name = "touch";
Description = "Attempt to touch a prim with specified UUID";
Category = CommandCategory.Objects;
}
public override string Execute(string[] args, UUID fromAgentID)
{
UUID target;
if (args.Length != 1)
return "Usage: touch UUID";
if (UUID.TryParse(args[0], out target))
{
Primitive targetPrim = Client.Network.CurrentSim.ObjectsPrimitives.Find(
delegate(Primitive prim)
{
return prim.ID == target;
}
);
if (targetPrim != null)
{
Client.Self.Touch(targetPrim.LocalID);
return "Touched prim " + targetPrim.LocalID;
}
}
return "Couldn't find a prim to touch with UUID " + args[0];
}
}
}
@@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using System.Text;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace OpenMetaverse.TestClient
{
public class WhoCommand: Command
{
public WhoCommand(TestClient testClient)
{
Name = "who";
Description = "Lists seen avatars.";
Category = CommandCategory.Other;
}
public override string Execute(string[] args, UUID fromAgentID)
{
StringBuilder result = new StringBuilder();
lock (Client.Network.Simulators)
{
for (int i = 0; i < Client.Network.Simulators.Count; i++)
{
Client.Network.Simulators[i].ObjectsAvatars.ForEach(
delegate(Avatar av)
{
result.AppendLine();
result.AppendFormat("{0} (Group: {1}, Location: {2}, UUID: {3} LocalID: {4})",
av.Name, av.GroupName, av.Position, av.ID, av.LocalID);
}
);
}
}
return result.ToString();
}
}
}
@@ -0,0 +1,25 @@
using System;
using System.Threading;
using OpenMetaverse;
namespace OpenMetaverse.TestClient
{
/// <summary>
/// Set avatars current appearance to appearance last stored on simulator
/// </summary>
public class AppearanceCommand : Command
{
public AppearanceCommand(TestClient testClient)
{
Name = "appearance";
Description = "Set your current appearance to your last saved appearance. Usage: appearance [rebake]";
Category = CommandCategory.Appearance;
}
public override string Execute(string[] args, UUID fromAgentID)
{
Client.Appearance.RequestSetAppearance((args.Length > 0 && args[0].Equals("rebake")));
return "Appearance sequence started";
}
}
}
@@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using OpenMetaverse;
namespace OpenMetaverse.TestClient
{
public class AttachmentsCommand : Command
{
public AttachmentsCommand(TestClient testClient)
{
Client = testClient;
Name = "attachments";
Description = "Prints a list of the currently known agent attachments";
Category = CommandCategory.Appearance;
}
public override string Execute(string[] args, UUID fromAgentID)
{
List<Primitive> attachments = Client.Network.CurrentSim.ObjectsPrimitives.FindAll(
delegate(Primitive prim) { return prim.ParentID == Client.Self.LocalID; }
);
for (int i = 0; i < attachments.Count; i++)
{
Primitive prim = attachments[i];
AttachmentPoint point = StateToAttachmentPoint(prim.PrimData.State);
// TODO: Fetch properties for the objects with missing property sets so we can show names
Logger.Log(String.Format("[Attachment @ {0}] LocalID: {1} UUID: {2} Offset: {3}",
point, prim.LocalID, prim.ID, prim.Position), Helpers.LogLevel.Info, Client);
}
return "Found " + attachments.Count + " attachments";
}
public static AttachmentPoint StateToAttachmentPoint(uint state)
{
const uint ATTACHMENT_MASK = 0xF0;
uint fixedState = (((byte)state & ATTACHMENT_MASK) >> 4) | (((byte)state & ~ATTACHMENT_MASK) << 4);
return (AttachmentPoint)fixedState;
}
}
}
@@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
using System.Text;
using OpenMetaverse;
namespace OpenMetaverse.TestClient.Commands.Appearance
{
public class AvatarInfoCommand : Command
{
public AvatarInfoCommand(TestClient testClient)
{
Name = "avatarinfo";
Description = "Print out information on a nearby avatar. Usage: avatarinfo [firstname] [lastname]";
Category = CommandCategory.Appearance;
}
public override string Execute(string[] args, UUID fromAgentID)
{
if (args.Length != 2)
return "Usage: avatarinfo [firstname] [lastname]";
string targetName = String.Format("{0} {1}", args[0], args[1]);
Avatar foundAv = Client.Network.CurrentSim.ObjectsAvatars.Find(
delegate(Avatar avatar) { return (avatar.Name == targetName); }
);
if (foundAv != null)
{
StringBuilder output = new StringBuilder();
output.AppendFormat("{0} ({1})", targetName, foundAv.ID);
output.AppendLine();
for (int i = 0; i < foundAv.Textures.FaceTextures.Length; i++)
{
if (foundAv.Textures.FaceTextures[i] != null)
{
Primitive.TextureEntryFace face = foundAv.Textures.FaceTextures[i];
AvatarTextureIndex type = (AvatarTextureIndex)i;
output.AppendFormat("{0}: {1}", type, face.TextureID);
output.AppendLine();
}
}
return output.ToString();
}
else
{
return "No nearby avatar with the name " + targetName;
}
}
}
}
@@ -0,0 +1,82 @@
using System;
using System.Collections.Generic;
using System.Threading;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace OpenMetaverse.TestClient
{
public class CloneCommand : Command
{
uint SerialNum = 2;
public CloneCommand(TestClient testClient)
{
Name = "clone";
Description = "Clone the appearance of a nearby avatar. Usage: clone [name]";
Category = CommandCategory.Appearance;
}
public override string Execute(string[] args, UUID fromAgentID)
{
string targetName = String.Empty;
List<DirectoryManager.AgentSearchData> matches;
for (int ct = 0; ct < args.Length; ct++)
targetName = targetName + args[ct] + " ";
targetName = targetName.TrimEnd();
if (targetName.Length == 0)
return "Usage: clone [name]";
if (Client.Directory.PeopleSearch(DirectoryManager.DirFindFlags.People, targetName, 0, 1000 * 10,
out matches) && matches.Count > 0)
{
UUID target = matches[0].AgentID;
targetName += String.Format(" ({0})", target);
if (Client.Appearances.ContainsKey(target))
{
#region AvatarAppearance to AgentSetAppearance
AvatarAppearancePacket appearance = Client.Appearances[target];
AgentSetAppearancePacket set = new AgentSetAppearancePacket();
set.AgentData.AgentID = Client.Self.AgentID;
set.AgentData.SessionID = Client.Self.SessionID;
set.AgentData.SerialNum = SerialNum++;
set.AgentData.Size = new Vector3(2f, 2f, 2f); // HACK
set.WearableData = new AgentSetAppearancePacket.WearableDataBlock[0];
set.VisualParam = new AgentSetAppearancePacket.VisualParamBlock[appearance.VisualParam.Length];
for (int i = 0; i < appearance.VisualParam.Length; i++)
{
set.VisualParam[i] = new AgentSetAppearancePacket.VisualParamBlock();
set.VisualParam[i].ParamValue = appearance.VisualParam[i].ParamValue;
}
set.ObjectData.TextureEntry = appearance.ObjectData.TextureEntry;
#endregion AvatarAppearance to AgentSetAppearance
// Detach everything we are currently wearing
Client.Appearance.AddAttachments(new List<InventoryItem>(), true);
// Send the new appearance packet
Client.Network.SendPacket(set);
return "Cloned " + targetName;
}
else
{
return "Don't know the appearance of avatar " + targetName;
}
}
else
{
return "Couldn't find avatar " + targetName;
}
}
}
}
@@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using OpenMetaverse;
namespace OpenMetaverse.TestClient
{
public class WearCommand : Command
{
public WearCommand(TestClient testClient)
{
Client = testClient;
Name = "wear";
Description = "Wear an outfit folder from inventory. Usage: wear [outfit name]";
Category = CommandCategory.Appearance;
}
public override string Execute(string[] args, UUID fromAgentID)
{
if (args.Length < 1)
return "Usage: wear [outfit name] eg: 'wear Clothing/My Outfit";
string target = String.Empty;
for (int ct = 0; ct < args.Length; ct++)
{
target += args[ct] + " ";
}
target = target.TrimEnd();
UUID folder = Client.Inventory.FindObjectByPath(Client.Inventory.Store.RootFolder.UUID, Client.Self.AgentID, target, 20 * 1000);
if (folder == UUID.Zero)
{
return "Outfit path " + target + " not found";
}
List<InventoryBase> contents = Client.Inventory.FolderContents(folder, Client.Self.AgentID, true, true, InventorySortOrder.ByName, 20 * 1000);
List<InventoryItem> items = new List<InventoryItem>();
if (contents == null)
{
return "Failed to get contents of " + target;
}
foreach (InventoryBase item in contents)
{
if (item is InventoryItem)
items.Add((InventoryItem)item);
}
Client.Appearance.ReplaceOutfit(items);
return "Starting to change outfit to " + target;
}
}
}
@@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using System.Text;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace OpenMetaverse.TestClient
{
public class EchoMasterCommand: Command
{
public EchoMasterCommand(TestClient testClient)
{
Name = "echoMaster";
Description = "Repeat everything that master says.";
Category = CommandCategory.Communication;
}
public override string Execute(string[] args, UUID fromAgentID)
{
if (!Active)
{
Active = true;
Client.Self.ChatFromSimulator += Self_ChatFromSimulator;
return "Echoing is now on.";
}
else
{
Active = false;
Client.Self.ChatFromSimulator -= Self_ChatFromSimulator;
return "Echoing is now off.";
}
}
void Self_ChatFromSimulator(object sender, ChatEventArgs e)
{
if (e.Message.Length > 0 && (Client.MasterKey == e.SourceID || (Client.MasterName == e.FromName && !Client.AllowObjectMaster)))
Client.Self.Chat(e.Message, 0, ChatType.Normal);
}
}
}
@@ -0,0 +1,72 @@
using System;
using System.Collections.Generic;
using System.Threading;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace OpenMetaverse.TestClient
{
public class ImCommand : Command
{
string ToAvatarName = String.Empty;
ManualResetEvent NameSearchEvent = new ManualResetEvent(false);
Dictionary<string, UUID> Name2Key = new Dictionary<string, UUID>();
public ImCommand(TestClient testClient)
{
testClient.Avatars.AvatarPickerReply += Avatars_AvatarPickerReply;
Name = "im";
Description = "Instant message someone. Usage: im [firstname] [lastname] [message]";
Category = CommandCategory.Communication;
}
public override string Execute(string[] args, UUID fromAgentID)
{
if (args.Length < 3)
return "Usage: im [firstname] [lastname] [message]";
ToAvatarName = args[0] + " " + args[1];
// Build the message
string message = String.Empty;
for (int ct = 2; ct < args.Length; ct++)
message += args[ct] + " ";
message = message.TrimEnd();
if (message.Length > 1023) message = message.Remove(1023);
if (!Name2Key.ContainsKey(ToAvatarName.ToLower()))
{
// Send the Query
Client.Avatars.RequestAvatarNameSearch(ToAvatarName, UUID.Random());
NameSearchEvent.WaitOne(6000, false);
}
if (Name2Key.ContainsKey(ToAvatarName.ToLower()))
{
UUID id = Name2Key[ToAvatarName.ToLower()];
Client.Self.InstantMessage(id, message);
return "Instant Messaged " + id.ToString() + " with message: " + message;
}
else
{
return "Name lookup for " + ToAvatarName + " failed";
}
}
void Avatars_AvatarPickerReply(object sender, AvatarPickerReplyEventArgs e)
{
foreach (KeyValuePair<UUID, string> kvp in e.Avatars)
{
if (kvp.Value.ToLower() == ToAvatarName.ToLower())
{
Name2Key[ToAvatarName.ToLower()] = kvp.Key;
NameSearchEvent.Set();
return;
}
}
}
}
}
@@ -0,0 +1,86 @@
using System;
using System.Collections.Generic;
using System.Threading;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace OpenMetaverse.TestClient
{
public class ImGroupCommand : Command
{
UUID ToGroupID = UUID.Zero;
ManualResetEvent WaitForSessionStart = new ManualResetEvent(false);
public ImGroupCommand(TestClient testClient)
{
Name = "imgroup";
Description = "Send an instant message to a group. Usage: imgroup [group_uuid] [message]";
Category = CommandCategory.Communication;
}
public override string Execute(string[] args, UUID fromAgentID)
{
if (args.Length < 2)
return "Usage: imgroup [group_uuid] [message]";
if (UUID.TryParse(args[0], out ToGroupID))
{
string message = String.Empty;
for (int ct = 1; ct < args.Length; ct++)
message += args[ct] + " ";
message = message.TrimEnd();
if (message.Length > 1023)
{
message = message.Remove(1023);
Console.WriteLine("Message truncated at 1024 characters");
}
Client.Self.GroupChatJoined += Self_GroupChatJoined;
if (!Client.Self.GroupChatSessions.ContainsKey(ToGroupID))
{
WaitForSessionStart.Reset();
Client.Self.RequestJoinGroupChat(ToGroupID);
}
else
{
WaitForSessionStart.Set();
}
if (WaitForSessionStart.WaitOne(20000, false))
{
Client.Self.InstantMessageGroup(ToGroupID, message);
}
else
{
return "Timeout waiting for group session start";
}
Client.Self.GroupChatJoined -= Self_GroupChatJoined;
return "Instant Messaged group " + ToGroupID.ToString() + " with message: " + message;
}
else
{
return "failed to instant message group";
}
}
void Self_GroupChatJoined(object sender, GroupChatJoinedEventArgs e)
{
if (e.Success)
{
Console.WriteLine("Joined {0} Group Chat Success!", e.SessionName);
WaitForSessionStart.Set();
}
else
{
Console.WriteLine("Join Group Chat failed :(");
}
}
}
}
@@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Text;
using OpenMetaverse;
namespace OpenMetaverse.TestClient
{
public class SayCommand: Command
{
public SayCommand(TestClient testClient)
{
Name = "say";
Description = "Say something. (usage: say (optional channel) whatever)";
Category = CommandCategory.Communication;
}
public override string Execute(string[] args, UUID fromAgentID)
{
int channel = 0;
int startIndex = 0;
if (args.Length < 1)
{
return "usage: say (optional channel) whatever";
}
else if (args.Length > 1)
{
if (Int32.TryParse(args[0], out channel))
startIndex = 1;
}
String message = String.Empty;
for (int i = startIndex; i < args.Length; i++)
{
// Append a space before the next arg
if( i > 0 )
message += " ";
message += args[i];
}
Client.Self.Chat(message, channel, ChatType.Normal);
return "Said " + message.ToString();
}
}
}
@@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using System.Text;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace OpenMetaverse.TestClient
{
public class ShoutCommand : Command
{
public ShoutCommand(TestClient testClient)
{
Name = "shout";
Description = "Shout something.";
Category = CommandCategory.Communication;
}
public override string Execute(string[] args, UUID fromAgentID)
{
int channel = 0;
int startIndex = 0;
string message = String.Empty;
if (args.Length < 1)
{
return "usage: shout (optional channel) whatever";
}
else if (args.Length > 1)
{
try
{
channel = Convert.ToInt32(args[0]);
startIndex = 1;
}
catch (FormatException)
{
channel = 0;
}
}
for (int i = startIndex; i < args.Length; i++)
{
// Append a space before the next arg
if( i > 0 )
message += " ";
message += args[i];
}
Client.Self.Chat(message, channel, ChatType.Shout);
return "Shouted " + message;
}
}
}
@@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using System.Text;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace OpenMetaverse.TestClient
{
public class WhisperCommand : Command
{
public WhisperCommand(TestClient testClient)
{
Name = "whisper";
Description = "Whisper something.";
Category = CommandCategory.Communication;
}
public override string Execute(string[] args, UUID fromAgentID)
{
int channel = 0;
int startIndex = 0;
string message = String.Empty;
if (args.Length < 1)
{
return "usage: whisper (optional channel) whatever";
}
else if (args.Length > 1)
{
try
{
channel = Convert.ToInt32(args[0]);
startIndex = 1;
}
catch (FormatException)
{
channel = 0;
}
}
for (int i = startIndex; i < args.Length; i++)
{
// Append a space before the next arg
if( i > 0 )
message += " ";
message += args[i];
}
Client.Self.Chat(message, channel, ChatType.Whisper);
return "Whispered " + message;
}
}
}
@@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace OpenMetaverse.TestClient.Commands
{
class key2nameCommand : Command
{
System.Threading.AutoResetEvent waitQuery = new System.Threading.AutoResetEvent(false);
StringBuilder result = new StringBuilder();
public key2nameCommand(TestClient testClient)
{
Name = "key2name";
Description = "resolve a UUID to an avatar or group name. Usage: key2name UUID";
Category = CommandCategory.Search;
}
public override string Execute(string[] args, UUID fromAgentID)
{
if (args.Length < 1)
return "Usage: key2name UUID";
UUID key;
if(!UUID.TryParse(args[0].Trim(), out key))
{
return "UUID " + args[0].Trim() + " appears to be invalid";
}
result.Remove(0, result.Length);
waitQuery.Reset();
Client.Avatars.UUIDNameReply += Avatars_OnAvatarNames;
Client.Groups.GroupProfile += Groups_OnGroupProfile;
Client.Avatars.RequestAvatarName(key);
Client.Groups.RequestGroupProfile(key);
if (!waitQuery.WaitOne(10000, false))
{
result.AppendLine("Timeout waiting for reply, this could mean the Key is not an avatar or a group");
}
Client.Avatars.UUIDNameReply -= Avatars_OnAvatarNames;
Client.Groups.GroupProfile -= Groups_OnGroupProfile;
return result.ToString();
}
void Groups_OnGroupProfile(object sender, GroupProfileEventArgs e)
{
result.AppendLine("Group: " + e.Group.Name + " " + e.Group.ID);
waitQuery.Set();
}
void Avatars_OnAvatarNames(object sender, UUIDNameReplyEventArgs e)
{
foreach (KeyValuePair<UUID, string> kvp in e.Names)
result.AppendLine("Avatar: " + kvp.Value + " " + kvp.Key);
waitQuery.Set();
}
}
}
@@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace OpenMetaverse.TestClient.Commands
{
class SearchClassifiedsCommand : Command
{
System.Threading.AutoResetEvent waitQuery = new System.Threading.AutoResetEvent(false);
public SearchClassifiedsCommand(TestClient testClient)
{
Name = "searchclassifieds";
Description = "Searches Classified Ads. Usage: searchclassifieds [search text]";
Category = CommandCategory.Search;
}
public override string Execute(string[] args, UUID fromAgentID)
{
if (args.Length < 1)
return "Usage: searchclassifieds [search text]";
string searchText = string.Empty;
for (int i = 0; i < args.Length; i++)
searchText += args[i] + " ";
searchText = searchText.TrimEnd();
waitQuery.Reset();
StringBuilder result = new StringBuilder();
EventHandler<DirClassifiedsReplyEventArgs> callback = delegate(object sender, DirClassifiedsReplyEventArgs e)
{
result.AppendFormat("Your search string '{0}' returned {1} classified ads" + System.Environment.NewLine,
searchText, e.Classifieds.Count);
foreach (DirectoryManager.Classified ad in e.Classifieds)
{
result.AppendLine(ad.ToString());
}
// classifieds are sent 16 ads at a time
if (e.Classifieds.Count < 16)
{
waitQuery.Set();
}
};
Client.Directory.DirClassifiedsReply += callback;
UUID searchID = Client.Directory.StartClassifiedSearch(searchText, DirectoryManager.ClassifiedCategories.Any, DirectoryManager.ClassifiedQueryFlags.Mature | DirectoryManager.ClassifiedQueryFlags.PG);
if (!waitQuery.WaitOne(20000, false) && Client.Network.Connected)
{
result.AppendLine("Timeout waiting for simulator to respond to query.");
}
Client.Directory.DirClassifiedsReply -= callback;
return result.ToString();
}
}
}
@@ -0,0 +1,68 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace OpenMetaverse.TestClient.Commands
{
class SearchEventsCommand : Command
{
System.Threading.AutoResetEvent waitQuery = new System.Threading.AutoResetEvent(false);
int resultCount;
public SearchEventsCommand(TestClient testClient)
{
Name = "searchevents";
Description = "Searches Events list. Usage: searchevents [search text]";
Category = CommandCategory.Search;
}
public override string Execute(string[] args, UUID fromAgentID)
{
// process command line arguments
if (args.Length < 1)
return "Usage: searchevents [search text]";
string searchText = string.Empty;
for (int i = 0; i < args.Length; i++)
searchText += args[i] + " ";
searchText = searchText.TrimEnd();
waitQuery.Reset();
Client.Directory.DirEventsReply += Directory_DirEvents;
// send the request to the directory manager
Client.Directory.StartEventsSearch(searchText, 0);
string result;
if (waitQuery.WaitOne(20000, false) && Client.Network.Connected)
{
result = "Your query '" + searchText + "' matched " + resultCount + " Events. ";
}
else
{
result = "Timeout waiting for simulator to respond.";
}
Client.Directory.DirEventsReply -= Directory_DirEvents;
return result;
}
void Directory_DirEvents(object sender, DirEventsReplyEventArgs e)
{
if (e.MatchedEvents[0].ID == 0 && e.MatchedEvents.Count == 1)
{
Console.WriteLine("No Results matched your search string");
}
else
{
foreach (DirectoryManager.EventsSearchData ev in e.MatchedEvents)
{
Console.WriteLine("Event ID: {0} Event Name: {1} Event Date: {2}", ev.ID, ev.Name, ev.Date);
}
}
resultCount = e.MatchedEvents.Count;
waitQuery.Set();
}
}
}
@@ -0,0 +1,68 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace OpenMetaverse.TestClient.Commands
{
class SearchGroupsCommand : Command
{
System.Threading.AutoResetEvent waitQuery = new System.Threading.AutoResetEvent(false);
int resultCount = 0;
public SearchGroupsCommand(TestClient testClient)
{
Name = "searchgroups";
Description = "Searches groups. Usage: searchgroups [search text]";
Category = CommandCategory.Groups;
}
public override string Execute(string[] args, UUID fromAgentID)
{
// process command line arguments
if (args.Length < 1)
return "Usage: searchgroups [search text]";
string searchText = string.Empty;
for (int i = 0; i < args.Length; i++)
searchText += args[i] + " ";
searchText = searchText.TrimEnd();
waitQuery.Reset();
Client.Directory.DirGroupsReply += Directory_DirGroups;
// send the request to the directory manager
Client.Directory.StartGroupSearch(searchText, 0);
string result;
if (waitQuery.WaitOne(20000, false) && Client.Network.Connected)
{
result = "Your query '" + searchText + "' matched " + resultCount + " Groups. ";
}
else
{
result = "Timeout waiting for simulator to respond.";
}
Client.Directory.DirGroupsReply -= Directory_DirGroups;
return result;
}
void Directory_DirGroups(object sender, DirGroupsReplyEventArgs e)
{
if (e.MatchedGroups.Count > 0)
{
foreach (DirectoryManager.GroupSearchData group in e.MatchedGroups)
{
Console.WriteLine("Group {1} ({0}) has {2} members", group.GroupID, group.GroupName, group.Members);
}
}
else
{
Console.WriteLine("Didn't find any groups that matched your query :(");
}
waitQuery.Set();
}
}
}
@@ -0,0 +1,125 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace OpenMetaverse.TestClient.Commands
{
/// <summary>
///
/// </summary>
public class SearchLandCommand : Command
{
private System.Threading.AutoResetEvent waitQuery = new System.Threading.AutoResetEvent(false);
private StringBuilder result = new StringBuilder();
/// <summary>
/// Construct a new instance of the SearchLandCommand
/// </summary>
/// <param name="testClient"></param>
public SearchLandCommand(TestClient testClient)
{
Name = "searchland";
Description = "Searches for land for sale. for usage information type: searchland";
Category = CommandCategory.Search;
}
/// <summary>
/// Show commandusage
/// </summary>
/// <returns>A string containing the parameter usage instructions</returns>
public string ShowUsage()
{
return "Usage: searchland [type] [max price] [min size]\n" +
"\twhere [type] is one of: mainland, auction, estate, all\n" +
"\tif [max price] or [min size] are 0 that parameter will be ignored\n\n" +
"example: \"searchland mainland 0 512\" // shows the lowest priced mainland that is larger than 512/m2\n\n";
}
/// <summary>
///
/// </summary>
/// <param name="args"></param>
/// <param name="fromAgentID"></param>
/// <returns></returns>
public override string Execute(string[] args, UUID fromAgentID)
{
// process command line arguments
if (args.Length < 3)
return ShowUsage();
string searchType = args[0].Trim().ToLower();
int maxPrice;
int minSize;
DirectoryManager.SearchTypeFlags searchTypeFlags = DirectoryManager.SearchTypeFlags.Any;
if (searchType.StartsWith("au"))
searchTypeFlags = DirectoryManager.SearchTypeFlags.Auction;
else if (searchType.StartsWith("m"))
searchTypeFlags = DirectoryManager.SearchTypeFlags.Mainland;
else if (searchType.StartsWith("e"))
searchTypeFlags = DirectoryManager.SearchTypeFlags.Estate;
else if (searchType.StartsWith("al"))
searchTypeFlags = DirectoryManager.SearchTypeFlags.Any;
else
return ShowUsage();
// initialize some default flags we'll use in the search
DirectoryManager.DirFindFlags queryFlags = DirectoryManager.DirFindFlags.SortAsc | DirectoryManager.DirFindFlags.PerMeterSort
| DirectoryManager.DirFindFlags.IncludeAdult | DirectoryManager.DirFindFlags.IncludePG | DirectoryManager.DirFindFlags.IncludeMature;
// validate the parameters passed
if (int.TryParse(args[1], out maxPrice) && int.TryParse(args[2], out minSize))
{
// if the [max price] parameter is greater than 0, we'll enable the flag to limit by price
if (maxPrice > 0)
queryFlags |= DirectoryManager.DirFindFlags.LimitByPrice;
// if the [min size] parameter is greater than 0, we'll enable the flag to limit by area
if (minSize > 0)
queryFlags |= DirectoryManager.DirFindFlags.LimitByArea;
}
else
{
return ShowUsage();
}
//waitQuery.Reset();
// subscribe to the event that returns the search results
Client.Directory.DirLandReply += Directory_DirLand;
// send the request to the directory manager
Client.Directory.StartLandSearch(queryFlags, searchTypeFlags, maxPrice, minSize, 0);
if (!waitQuery.WaitOne(20000, false) && Client.Network.Connected)
{
result.AppendLine("Timeout waiting for simulator to respond.");
}
// unsubscribe to the event that returns the search results
Client.Directory.DirLandReply -= Directory_DirLand;
// return the results
return result.ToString();
}
/// <summary>
/// Process the search reply
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Directory_DirLand(object sender, DirLandReplyEventArgs e)
{
foreach (DirectoryManager.DirectoryParcel searchResult in e.DirParcels)
{
// add the results to the StringBuilder object that contains the results
result.AppendLine(searchResult.ToString());
}
result.AppendFormat("{0} results" + System.Environment.NewLine, e.DirParcels.Count);
// let the calling method know we have data
waitQuery.Set();
}
}
}
@@ -0,0 +1,69 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace OpenMetaverse.TestClient.Commands
{
class SearchPeopleCommand : Command
{
System.Threading.AutoResetEvent waitQuery = new System.Threading.AutoResetEvent(false);
int resultCount = 0;
public SearchPeopleCommand(TestClient testClient)
{
Name = "searchpeople";
Description = "Searches for other avatars. Usage: searchpeople [search text]";
Category = CommandCategory.Search;
}
public override string Execute(string[] args, UUID fromAgentID)
{
// process command line arguments
if (args.Length < 1)
return "Usage: searchpeople [search text]";
string searchText = string.Empty;
for (int i = 0; i < args.Length; i++)
searchText += args[i] + " ";
searchText = searchText.TrimEnd();
waitQuery.Reset();
Client.Directory.DirPeopleReply += Directory_DirPeople;
// send the request to the directory manager
Client.Directory.StartPeopleSearch(searchText, 0);
string result;
if (waitQuery.WaitOne(20000, false) && Client.Network.Connected)
{
result = "Your query '" + searchText + "' matched " + resultCount + " People. ";
}
else
{
result = "Timeout waiting for simulator to respond.";
}
Client.Directory.DirPeopleReply -= Directory_DirPeople;
return result;
}
void Directory_DirPeople(object sender, DirPeopleReplyEventArgs e)
{
if (e.MatchedPeople.Count > 0)
{
foreach (DirectoryManager.AgentSearchData agent in e.MatchedPeople)
{
Console.WriteLine("{0} {1} ({2})", agent.FirstName, agent.LastName, agent.AgentID);
}
}
else
{
Console.WriteLine("Didn't find any people that matched your query :(");
}
waitQuery.Set();
}
}
}
@@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace OpenMetaverse.TestClient.Commands
{
class SearchPlacesCommand : Command
{
System.Threading.AutoResetEvent waitQuery = new System.Threading.AutoResetEvent(false);
public SearchPlacesCommand(TestClient testClient)
{
Name = "searchplaces";
Description = "Searches Places. Usage: searchplaces [search text]";
Category = CommandCategory.Search;
}
public override string Execute(string[] args, UUID fromAgentID)
{
if (args.Length < 1)
return "Usage: searchplaces [search text]";
string searchText = string.Empty;
for (int i = 0; i < args.Length; i++)
searchText += args[i] + " ";
searchText = searchText.TrimEnd();
waitQuery.Reset();
StringBuilder result = new StringBuilder();
EventHandler<PlacesReplyEventArgs> callback = delegate(object sender, PlacesReplyEventArgs e)
{
result.AppendFormat("Your search string '{0}' returned {1} results" + System.Environment.NewLine,
searchText, e.MatchedPlaces.Count);
foreach (DirectoryManager.PlacesSearchData place in e.MatchedPlaces)
{
result.AppendLine(place.ToString());
}
waitQuery.Set();
};
Client.Directory.PlacesReply += callback;
Client.Directory.StartPlacesSearch(searchText);
if (!waitQuery.WaitOne(20000, false) && Client.Network.Connected)
{
result.AppendLine("Timeout waiting for simulator to respond to query.");
}
Client.Directory.PlacesReply -= callback;
return result.ToString();
}
}
}
@@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace OpenMetaverse.TestClient.Commands
{
class ShowEventDetailsCommand : Command
{
public ShowEventDetailsCommand(TestClient testClient)
{
Name = "showevent";
Description = "Shows an Events details. Usage: showevent [eventID]";
Category = CommandCategory.Other;
}
public override string Execute(string[] args, UUID fromAgentID)
{
if (args.Length < 1)
return "Usage: showevent [eventID] (use searchevents to get ID)";
Client.Directory.EventInfoReply += Directory_EventDetails;
uint eventID;
if (UInt32.TryParse(args[0], out eventID))
{
Client.Directory.EventInfoRequest(eventID);
return "Sent query for Event " + eventID;
}
else
{
return "Usage: showevent [eventID] (use searchevents to get ID)";
}
}
void Directory_EventDetails(object sender, EventInfoReplyEventArgs e)
{
float x, y;
Helpers.GlobalPosToRegionHandle((float)e.MatchedEvent.GlobalPos.X, (float)e.MatchedEvent.GlobalPos.Y, out x, out y);
StringBuilder sb = new StringBuilder("secondlife://" + e.MatchedEvent.SimName + "/" + x + "/" + y + "/0" + System.Environment.NewLine);
sb.AppendLine(e.MatchedEvent.ToString());
//sb.AppendFormat(" Name: {0} ({1})" + System.Environment.NewLine, e.MatchedEvent.Name, e.MatchedEvent.ID);
//sb.AppendFormat(" Location: {0}/{1}/{2}" + System.Environment.NewLine, e.MatchedEvent.SimName, x, y);
//sb.AppendFormat(" Date: {0}" + System.Environment.NewLine, e.MatchedEvent.Date);
//sb.AppendFormat("Description: {0}" + System.Environment.NewLine, e.MatchedEvent.Desc);
Console.WriteLine(sb.ToString());
Client.Directory.EventInfoReply -= Directory_EventDetails;
}
}
}
@@ -0,0 +1,106 @@
using System;
using System.IO;
using System.Collections.Generic;
using System.Threading;
using OpenMetaverse;
namespace OpenMetaverse.TestClient
{
/// <summary>
/// Request the raw terrain file from the simulator, save it as a file.
///
/// Can only be used by the Estate Owner
/// </summary>
public class DownloadTerrainCommand : Command
{
/// <summary>
/// Create a Synchronization event object
/// </summary>
private static AutoResetEvent xferTimeout = new AutoResetEvent(false);
/// <summary>A string we use to report the result of the request with.</summary>
private static System.Text.StringBuilder result = new System.Text.StringBuilder();
private static string fileName;
/// <summary>
/// Download a simulators raw terrain data and save it to a file
/// </summary>
/// <param name="testClient"></param>
public DownloadTerrainCommand(TestClient testClient)
{
Name = "downloadterrain";
Description = "Download the RAW terrain file for this estate. Usage: downloadterrain [timeout]";
Category = CommandCategory.Simulator;
}
/// <summary>
/// Execute the application
/// </summary>
/// <param name="args">arguments passed to this module</param>
/// <param name="fromAgentID">The ID of the avatar sending the request</param>
/// <returns></returns>
public override string Execute(string[] args, UUID fromAgentID)
{
int timeout = 120000; // default the timeout to 2 minutes
fileName = Client.Network.CurrentSim.Name + ".raw";
if (args.Length > 0 && int.TryParse(args[0], out timeout) != true)
return "Usage: downloadterrain [timeout]";
// Create a delegate which will be fired when the simulator receives our download request
// Starts the actual transfer request
EventHandler<InitiateDownloadEventArgs> initiateDownloadDelegate =
delegate(object sender, InitiateDownloadEventArgs e)
{
Client.Assets.RequestAssetXfer(e.SimFileName, false, false, UUID.Zero, AssetType.Unknown, false);
};
// Subscribe to the event that will tell us the status of the download
Client.Assets.XferReceived += new EventHandler<XferReceivedEventArgs>(Assets_XferReceived);
// subscribe to the event which tells us when the simulator has received our request
Client.Assets.InitiateDownload += initiateDownloadDelegate;
// configure request to tell the simulator to send us the file
List<string> parameters = new List<string>();
parameters.Add("download filename");
parameters.Add(fileName);
// send the request
Client.Estate.EstateOwnerMessage("terrain", parameters);
// wait for (timeout) seconds for the request to complete (defaults 2 minutes)
if (!xferTimeout.WaitOne(timeout, false))
{
result.Append("Timeout while waiting for terrain data");
}
// unsubscribe from events
Client.Assets.InitiateDownload -= initiateDownloadDelegate;
Client.Assets.XferReceived -= new EventHandler<XferReceivedEventArgs>(Assets_XferReceived);
// return the result
return result.ToString();
}
/// <summary>
/// Handle the reply to the OnXferReceived event
/// </summary>
private void Assets_XferReceived(object sender, XferReceivedEventArgs e)
{
if (e.Xfer.Success)
{
// set the result message
result.AppendFormat("Terrain file {0} ({1} bytes) downloaded successfully, written to {2}", e.Xfer.Filename, e.Xfer.Size, fileName);
// write the file to disk
FileStream stream = new FileStream(fileName, FileMode.Create);
BinaryWriter w = new BinaryWriter(stream);
w.Write(e.Xfer.AssetData);
w.Close();
// tell the application we've gotten the file
xferTimeout.Set();
}
}
}
}
@@ -0,0 +1,78 @@
using System;
using System.IO;
using System.Collections.Generic;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace OpenMetaverse.TestClient
{
public class UploadRawTerrainCommand : Command
{
System.Threading.AutoResetEvent WaitForUploadComplete = new System.Threading.AutoResetEvent(false);
public UploadRawTerrainCommand(TestClient testClient)
{
Name = "uploadterrain";
Description = "Upload a raw terrain file to a simulator. usage: uploadterrain filename";
Category = CommandCategory.Simulator;
}
public override string Execute(string[] args, UUID fromAgentID)
{
string fileName = String.Empty;
if (args.Length != 1)
return "Usage: uploadterrain filename";
fileName = args[0];
if (!System.IO.File.Exists(fileName))
{
return String.Format("File {0} Does not exist", fileName);
}
// Setup callbacks for upload request reply and progress indicator
// so we can detect when the upload is complete
Client.Assets.UploadProgress += new EventHandler<AssetUploadEventArgs>(Assets_UploadProgress);
byte[] fileData = File.ReadAllBytes(fileName);
Client.Estate.UploadTerrain(fileData, fileName);
// Wait for upload to complete. Upload request is fired in callback from first request
if (!WaitForUploadComplete.WaitOne(120000, false))
{
Cleanup();
return "Timeout waiting for terrain file upload";
}
else
{
Cleanup();
return "Terrain raw file uploaded and applied";
}
}
/// <summary>
/// Unregister previously subscribed event handlers
/// </summary>
private void Cleanup()
{
Client.Assets.UploadProgress -= new EventHandler<AssetUploadEventArgs>(Assets_UploadProgress);
}
void Assets_UploadProgress(object sender, AssetUploadEventArgs e)
{
if (e.Upload.Transferred == e.Upload.Size)
{
WaitForUploadComplete.Set();
}
else
{
//Console.WriteLine("Progress: {0}/{1} {2}/{3} {4}", upload.XferID, upload.ID, upload.Transferred, upload.Size, upload.Success);
Console.Write(".");
}
}
}
}
@@ -0,0 +1,63 @@
using System;
using System.Collections.Generic;
using System.Threading;
using OpenMetaverse;
using OpenMetaverse.Packets;
using System.Text;
// the Namespace used for all TestClient commands
namespace OpenMetaverse.TestClient
{
/// <summary>
/// Shows a list of friends
/// </summary>
public class FriendsCommand : Command
{
/// <summary>
/// Constructor for FriendsCommand class
/// </summary>
/// <param name="testClient">A reference to the TestClient object</param>
public FriendsCommand(TestClient testClient)
{
// The name of the command
Name = "friends";
// A short description of the command with usage instructions
Description = "List avatar friends. Usage: friends";
Category = CommandCategory.Friends;
}
/// <summary>
/// Get a list of current friends
/// </summary>
/// <param name="args">optional testClient command arguments</param>
/// <param name="fromAgentID">The <seealso cref="OpenMetaverse.UUID"/>
/// of the agent making the request</param>
/// <returns></returns>
public override string Execute(string[] args, UUID fromAgentID)
{
// initialize a StringBuilder object used to return the results
StringBuilder sb = new StringBuilder();
// Only iterate the Friends dictionary if we actually have friends!
if (Client.Friends.FriendList.Count > 0)
{
// iterate over the InternalDictionary using a delegate to populate
// our StringBuilder output string
sb.AppendFormat("has {0} friends:", Client.Friends.FriendList.Count).AppendLine();
Client.Friends.FriendList.ForEach(delegate(FriendInfo friend)
{
// append the name of the friend to our output
sb.AppendFormat("{0}, {1}", friend.UUID, friend.Name).AppendLine();
});
}
else
{
// we have no friends :(
sb.AppendLine("No Friends");
}
// return the result
return sb.ToString();
}
}
}
@@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
using System.Threading;
using OpenMetaverse;
using OpenMetaverse.Packets;
using System.Text;
namespace OpenMetaverse.TestClient
{
public class MapFriendCommand : Command
{
ManualResetEvent WaitforFriend = new ManualResetEvent(false);
public MapFriendCommand(TestClient testClient)
{
Name = "mapfriend";
Description = "Show a friends location. Usage: mapfriend UUID";
Category = CommandCategory.Friends;
}
public override string Execute(string[] args, UUID fromAgentID)
{
if (args.Length != 1)
return Description;
UUID targetID;
if (!UUID.TryParse(args[0], out targetID))
return Description;
StringBuilder sb = new StringBuilder();
EventHandler<FriendFoundReplyEventArgs> del = delegate(object sender, FriendFoundReplyEventArgs e)
{
if (!e.RegionHandle.Equals(0))
sb.AppendFormat("Found Friend {0} in {1} at {2}/{3}", e.AgentID, e.RegionHandle, e.Location.X, e.Location.Y);
else
sb.AppendFormat("Found Friend {0}, But they appear to be offline", e.AgentID);
WaitforFriend.Set();
};
Client.Friends.FriendFoundReply += del;
WaitforFriend.Reset();
Client.Friends.MapFriend(targetID);
if (!WaitforFriend.WaitOne(10000, false))
{
sb.AppendFormat("Timeout waiting for reply, Do you have mapping rights on {0}?", targetID);
}
Client.Friends.FriendFoundReply -= del;
return sb.ToString();
}
}
}
@@ -0,0 +1,70 @@
using System;
using System.Collections.Generic;
using System.Threading;
using OpenMetaverse;
using OpenMetaverse.Packets;
using System.Text;
namespace OpenMetaverse.TestClient
{
/// <summary>
/// Changes Avatars currently active group
/// </summary>
public class ActivateGroupCommand : Command
{
private ManualResetEvent GroupsEvent = new ManualResetEvent(false);
string activeGroup;
public ActivateGroupCommand(TestClient testClient)
{
Name = "activategroup";
Description = "Set a group as active. Usage: activategroup GroupName";
Category = CommandCategory.Groups;
}
public override string Execute(string[] args, UUID fromAgentID)
{
if (args.Length < 1)
return Description;
activeGroup = string.Empty;
string groupName = String.Empty;
for (int i = 0; i < args.Length; i++)
groupName += args[i] + " ";
groupName = groupName.Trim();
UUID groupUUID = Client.GroupName2UUID(groupName);
if (UUID.Zero != groupUUID) {
EventHandler<PacketReceivedEventArgs> pcallback = AgentDataUpdateHandler;
Client.Network.RegisterCallback(PacketType.AgentDataUpdate, pcallback);
Console.WriteLine("setting " + groupName + " as active group");
Client.Groups.ActivateGroup(groupUUID);
GroupsEvent.WaitOne(30000, false);
Client.Network.UnregisterCallback(PacketType.AgentDataUpdate, pcallback);
GroupsEvent.Reset();
/* A.Biondi
* TODO: Handle titles choosing.
*/
if (String.IsNullOrEmpty(activeGroup))
return Client.ToString() + " failed to activate the group " + groupName;
return "Active group is now " + activeGroup;
}
return Client.ToString() + " doesn't seem to be member of the group " + groupName;
}
private void AgentDataUpdateHandler(object sender, PacketReceivedEventArgs e)
{
AgentDataUpdatePacket p = (AgentDataUpdatePacket)e.Packet;
if (p.AgentData.AgentID == Client.Self.AgentID)
{
activeGroup = Utils.BytesToString(p.AgentData.GroupName) + " ( " + Utils.BytesToString(p.AgentData.GroupTitle) + " )";
GroupsEvent.Set();
}
}
}
}
@@ -0,0 +1,66 @@
using System;
using System.Collections.Generic;
using System.Threading;
using OpenMetaverse;
using OpenMetaverse.Packets;
using System.Text;
namespace OpenMetaverse.TestClient
{
/// <summary>
/// dumps group members to console
/// </summary>
public class GroupMembersCommand : Command
{
private ManualResetEvent GroupsEvent = new ManualResetEvent(false);
private string GroupName;
private UUID GroupUUID;
private UUID GroupRequestID;
public GroupMembersCommand(TestClient testClient)
{
Name = "groupmembers";
Description = "Dump group members to console. Usage: groupmembers GroupName";
Category = CommandCategory.Groups;
}
public override string Execute(string[] args, UUID fromAgentID)
{
if (args.Length < 1)
return Description;
GroupName = String.Empty;
for (int i = 0; i < args.Length; i++)
GroupName += args[i] + " ";
GroupName = GroupName.Trim();
GroupUUID = Client.GroupName2UUID(GroupName);
if (UUID.Zero != GroupUUID) {
Client.Groups.GroupMembersReply += GroupMembersHandler;
GroupRequestID = Client.Groups.RequestGroupMembers(GroupUUID);
GroupsEvent.WaitOne(30000, false);
GroupsEvent.Reset();
Client.Groups.GroupMembersReply -= GroupMembersHandler;
return Client.ToString() + " got group members";
}
return Client.ToString() + " doesn't seem to be member of the group " + GroupName;
}
private void GroupMembersHandler(object sender, GroupMembersReplyEventArgs e)
{
if (e.RequestID == GroupRequestID) {
StringBuilder sb = new StringBuilder();
sb.AppendLine();
sb.AppendFormat("GroupMembers: RequestID {0}", e.RequestID).AppendLine();
sb.AppendFormat("GroupMembers: GroupUUID {0}", GroupUUID).AppendLine();
sb.AppendFormat("GroupMembers: GroupName {0}", GroupName).AppendLine();
if (e.Members.Count > 0)
foreach (KeyValuePair<UUID, GroupMember> member in e.Members)
sb.AppendFormat("GroupMembers: MemberUUID {0}", member.Key.ToString()).AppendLine();
sb.AppendFormat("GroupMembers: MemberCount {0}", e.Members.Count).AppendLine();
Console.WriteLine(sb.ToString());
GroupsEvent.Set();
}
}
}
}
@@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using System.Threading;
using OpenMetaverse;
using OpenMetaverse.Packets;
using System.Text;
namespace OpenMetaverse.TestClient
{
/// <summary>
/// dumps group roles to console
/// </summary>
public class GroupRolesCommand : Command
{
private ManualResetEvent GroupsEvent = new ManualResetEvent(false);
private string GroupName;
private UUID GroupUUID;
private UUID GroupRequestID;
public GroupRolesCommand(TestClient testClient)
{
Name = "grouproles";
Description = "Dump group roles to console. Usage: grouproles GroupName";
Category = CommandCategory.Groups;
}
public override string Execute(string[] args, UUID fromAgentID)
{
if (args.Length < 1)
return Description;
GroupName = String.Empty;
for (int i = 0; i < args.Length; i++)
GroupName += args[i] + " ";
GroupName = GroupName.Trim();
GroupUUID = Client.GroupName2UUID(GroupName);
if (UUID.Zero != GroupUUID) {
Client.Groups.GroupRoleDataReply += Groups_GroupRoles;
GroupRequestID = Client.Groups.RequestGroupRoles(GroupUUID);
GroupsEvent.WaitOne(30000, false);
GroupsEvent.Reset();
Client.Groups.GroupRoleDataReply += Groups_GroupRoles;
return Client.ToString() + " got group roles";
}
return Client.ToString() + " doesn't seem to have any roles in the group " + GroupName;
}
void Groups_GroupRoles(object sender, GroupRolesDataReplyEventArgs e)
{
if (e.RequestID == GroupRequestID)
{
StringBuilder sb = new StringBuilder();
sb.AppendLine();
sb.AppendFormat("GroupRole: RequestID {0}", e.RequestID).AppendLine();
sb.AppendFormat("GroupRole: GroupUUID {0}", GroupUUID).AppendLine();
sb.AppendFormat("GroupRole: GroupName {0}", GroupName).AppendLine();
if (e.Roles.Count > 0)
foreach (KeyValuePair<UUID, GroupRole> role in e.Roles)
sb.AppendFormat("GroupRole: Role {0} {1}|{2}", role.Value.ID, role.Value.Name, role.Value.Title).AppendLine();
sb.AppendFormat("GroupRole: RoleCount {0}", e.Roles.Count).AppendLine();
Console.WriteLine(sb.ToString());
GroupsEvent.Set();
}
}
}
}
@@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.Threading;
using OpenMetaverse;
using OpenMetaverse.Packets;
using System.Text;
namespace OpenMetaverse.TestClient
{
public class GroupsCommand : Command
{
public GroupsCommand(TestClient testClient)
{
Name = "groups";
Description = "List avatar groups. Usage: groups";
Category = CommandCategory.Groups;
}
public override string Execute(string[] args, UUID fromAgentID)
{
Client.ReloadGroupsCache();
return getGroupsString();
}
string getGroupsString()
{
if (null == Client.GroupsCache)
return "Groups cache failed.";
if (0 == Client.GroupsCache.Count)
return "No groups";
StringBuilder sb = new StringBuilder();
sb.AppendLine("got "+Client.GroupsCache.Count +" groups:");
foreach (Group group in Client.GroupsCache.Values)
{
sb.AppendLine(group.ID + ", " + group.Name);
}
return sb.ToString();
}
}
}
@@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using System.Threading;
using OpenMetaverse;
using OpenMetaverse.Packets;
using System.Text;
namespace OpenMetaverse.TestClient
{
public class InviteGroupCommand : Command
{
public InviteGroupCommand(TestClient testClient)
{
Name = "invitegroup";
Description = "invite an avatar into a group. Usage: invitegroup AvatarUUID GroupUUID RoleUUID*";
Category = CommandCategory.Groups;
}
public override string Execute(string[] args, UUID fromAgentID)
{
if (args.Length < 2)
return Description;
UUID avatar = UUID.Zero;
UUID group = UUID.Zero;
UUID role = UUID.Zero;
List<UUID> roles = new List<UUID>();
if (!UUID.TryParse(args[0], out avatar))
return "parse error avatar UUID";
if (!UUID.TryParse(args[1], out group))
return "parse error group UUID";
if (2 == args.Length)
roles.Add(UUID.Zero);
else
for (int i = 2; i < args.Length; i++)
if (UUID.TryParse(args[i], out role))
roles.Add(role);
Client.Groups.Invite(group, roles, avatar);
return "invited "+avatar+" to "+group;
}
}
}
@@ -0,0 +1,155 @@
using System;
using System.Collections.Generic;
using System.Threading;
using OpenMetaverse;
using OpenMetaverse.Packets;
using System.Text;
namespace OpenMetaverse.TestClient
{
public class JoinGroupCommand : Command
{
ManualResetEvent GetGroupsSearchEvent = new ManualResetEvent(false);
private UUID queryID = UUID.Zero;
private UUID resolvedGroupID;
private string groupName;
private string resolvedGroupName;
private bool joinedGroup;
public JoinGroupCommand(TestClient testClient)
{
Name = "joingroup";
Description = "join a group. Usage: joingroup GroupName | joingroup UUID GroupId";
Category = CommandCategory.Groups;
}
public override string Execute(string[] args, UUID fromAgentID)
{
if (args.Length < 1)
return Description;
groupName = String.Empty;
resolvedGroupID = UUID.Zero;
resolvedGroupName = String.Empty;
if (args[0].ToLower() == "uuid")
{
if (args.Length < 2)
return Description;
if (!UUID.TryParse((resolvedGroupName = groupName = args[1]), out resolvedGroupID))
return resolvedGroupName + " doesn't seem a valid UUID";
}
else
{
for (int i = 0; i < args.Length; i++)
groupName += args[i] + " ";
groupName = groupName.Trim();
Client.Directory.DirGroupsReply += Directory_DirGroups;
queryID = Client.Directory.StartGroupSearch(groupName, 0);
GetGroupsSearchEvent.WaitOne(60000, false);
Client.Directory.DirGroupsReply -= Directory_DirGroups;
GetGroupsSearchEvent.Reset();
}
if (resolvedGroupID == UUID.Zero)
{
if (string.IsNullOrEmpty(resolvedGroupName))
return "Unable to obtain UUID for group " + groupName;
else
return resolvedGroupName;
}
Client.Groups.GroupJoinedReply += Groups_OnGroupJoined;
Client.Groups.RequestJoinGroup(resolvedGroupID);
/* A.Biondi
* TODO: implement the pay to join procedure.
*/
GetGroupsSearchEvent.WaitOne(60000, false);
Client.Groups.GroupJoinedReply -= Groups_GroupJoined;
GetGroupsSearchEvent.Reset();
Client.ReloadGroupsCache();
if (joinedGroup)
return "Joined the group " + resolvedGroupName;
return "Unable to join the group " + resolvedGroupName;
}
void Groups_GroupJoined(object sender, GroupOperationEventArgs e)
{
throw new NotImplementedException();
}
void Directory_DirGroups(object sender, DirGroupsReplyEventArgs e)
{
if (queryID == e.QueryID)
{
queryID = UUID.Zero;
if (e.MatchedGroups.Count < 1)
{
Console.WriteLine("ERROR: Got an empty reply");
}
else
{
if (e.MatchedGroups.Count > 1)
{
/* A.Biondi
* The Group search doesn't work as someone could expect...
* It'll give back to you a long list of groups even if the
* searchText (groupName) matches esactly one of the groups
* names present on the server, so we need to check each result.
* UUIDs of the matching groups are written on the console.
*/
Console.WriteLine("Matching groups are:\n");
foreach (DirectoryManager.GroupSearchData groupRetrieved in e.MatchedGroups)
{
Console.WriteLine(groupRetrieved.GroupName + "\t\t\t(" +
Name + " UUID " + groupRetrieved.GroupID.ToString() + ")");
if (groupRetrieved.GroupName.ToLower() == groupName.ToLower())
{
resolvedGroupID = groupRetrieved.GroupID;
resolvedGroupName = groupRetrieved.GroupName;
break;
}
}
if (string.IsNullOrEmpty(resolvedGroupName))
resolvedGroupName = "Ambiguous name. Found " + e.MatchedGroups.Count.ToString() + " groups (UUIDs on console)";
}
}
GetGroupsSearchEvent.Set();
}
}
void Groups_OnGroupJoined(object sender, GroupOperationEventArgs e)
{
Console.WriteLine(Client.ToString() + (e.Success ? " joined " : " failed to join ") + e.GroupID.ToString());
/* A.Biondi
* This code is not necessary because it is yet present in the
* GroupCommand.cs as well. So the new group will be activated by
* the mentioned command. If the GroupCommand.cs would change,
* just uncomment the following two lines.
if (success)
{
Console.WriteLine(Client.ToString() + " setting " + groupID.ToString() + " as the active group");
Client.Groups.ActivateGroup(groupID);
}
*/
joinedGroup = e.Success;
GetGroupsSearchEvent.Set();
}
}
}
@@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using System.Threading;
using OpenMetaverse;
using OpenMetaverse.Packets;
using System.Text;
namespace OpenMetaverse.TestClient
{
public class LeaveGroupCommand : Command
{
ManualResetEvent GroupsEvent = new ManualResetEvent(false);
private bool leftGroup;
public LeaveGroupCommand(TestClient testClient)
{
Name = "leavegroup";
Description = "Leave a group. Usage: leavegroup GroupName";
Category = CommandCategory.Groups;
}
public override string Execute(string[] args, UUID fromAgentID)
{
if (args.Length < 1)
return Description;
string groupName = String.Empty;
for (int i = 0; i < args.Length; i++)
groupName += args[i] + " ";
groupName = groupName.Trim();
UUID groupUUID = Client.GroupName2UUID(groupName);
if (UUID.Zero != groupUUID) {
Client.Groups.GroupLeaveReply += Groups_GroupLeft;
Client.Groups.LeaveGroup(groupUUID);
GroupsEvent.WaitOne(30000, false);
Client.Groups.GroupLeaveReply -= Groups_GroupLeft;
GroupsEvent.Reset();
Client.ReloadGroupsCache();
if (leftGroup)
return Client.ToString() + " has left the group " + groupName;
return "failed to leave the group " + groupName;
}
return Client.ToString() + " doesn't seem to be member of the group " + groupName;
}
void Groups_GroupLeft(object sender, GroupOperationEventArgs e)
{
Console.WriteLine(Client.ToString() + (e.Success ? " has left group " : " failed to left group ") + e.GroupID.ToString());
leftGroup = e.Success;
GroupsEvent.Set();
}
}
}
@@ -0,0 +1,354 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading;
using System.ComponentModel;
using System.Xml;
using System.Xml.Serialization;
using OpenMetaverse;
using OpenMetaverse.Packets;
using OpenMetaverse.TestClient;
using OpenMetaverse.Assets;
namespace OpenMetaverse.TestClient
{
public class QueuedDownloadInfo
{
public UUID AssetID;
public UUID ItemID;
public UUID TaskID;
public UUID OwnerID;
public AssetType Type;
public string FileName;
public DateTime WhenRequested;
public bool IsRequested;
public QueuedDownloadInfo(string file, UUID asset, UUID item, UUID task, UUID owner, AssetType type)
{
FileName = file;
AssetID = asset;
ItemID = item;
TaskID = task;
OwnerID = owner;
Type = type;
WhenRequested = DateTime.Now;
IsRequested = false;
}
}
public class BackupCommand : Command
{
/// <summary>Maximum number of transfer requests to send to the server</summary>
private const int MAX_TRANSFERS = 10;
// all items here, fed by the inventory walking thread
private Queue<QueuedDownloadInfo> PendingDownloads = new Queue<QueuedDownloadInfo>();
// items sent to the server here
private List<QueuedDownloadInfo> CurrentDownloads = new List<QueuedDownloadInfo>(MAX_TRANSFERS);
// background workers
private BackgroundWorker BackupWorker;
private BackgroundWorker QueueWorker;
// some stats
private int TextItemsFound;
private int TextItemsTransferred;
private int TextItemErrors;
#region Properties
/// <summary>
/// true if either of the background threads is running
/// </summary>
private bool BackgroundBackupRunning
{
get { return InventoryWalkerRunning || QueueRunnerRunning; }
}
/// <summary>
/// true if the thread walking inventory is running
/// </summary>
private bool InventoryWalkerRunning
{
get { return BackupWorker != null; }
}
/// <summary>
/// true if the thread feeding the queue to the server is running
/// </summary>
private bool QueueRunnerRunning
{
get { return QueueWorker != null; }
}
/// <summary>
/// returns a string summarizing activity
/// </summary>
/// <returns></returns>
private string BackgroundBackupStatus
{
get
{
StringBuilder sbResult = new StringBuilder();
sbResult.AppendFormat("{0} is {1} running.", Name, BoolToNot(BackgroundBackupRunning));
if (TextItemErrors != 0 || TextItemsFound != 0 || TextItemsTransferred != 0)
{
sbResult.AppendFormat("\r\n{0} : Inventory walker ( {1} running ) has found {2} items.",
Name, BoolToNot(InventoryWalkerRunning), TextItemsFound);
sbResult.AppendFormat("\r\n{0} : Server Transfers ( {1} running ) has transferred {2} items with {3} errors.",
Name, BoolToNot(QueueRunnerRunning), TextItemsTransferred, TextItemErrors);
sbResult.AppendFormat("\r\n{0} : {1} items in Queue, {2} items requested from server.",
Name, PendingDownloads.Count, CurrentDownloads.Count);
}
return sbResult.ToString();
}
}
#endregion Properties
public BackupCommand(TestClient testClient)
{
Name = "backuptext";
Description = "Backup inventory to a folder on your hard drive. Usage: " + Name + " [to <directory>] | [abort] | [status]";
}
public override string Execute(string[] args, UUID fromAgentID)
{
if (args.Length == 1 && args[0] == "status")
{
return BackgroundBackupStatus;
}
else if (args.Length == 1 && args[0] == "abort")
{
if (!BackgroundBackupRunning)
return BackgroundBackupStatus;
BackupWorker.CancelAsync();
QueueWorker.CancelAsync();
Thread.Sleep(500);
// check status
return BackgroundBackupStatus;
}
else if (args.Length != 2)
{
return "Usage: " + Name + " [to <directory>] | [abort] | [status]";
}
else if (BackgroundBackupRunning)
{
return BackgroundBackupStatus;
}
QueueWorker = new BackgroundWorker();
QueueWorker.WorkerSupportsCancellation = true;
QueueWorker.DoWork += new DoWorkEventHandler(bwQueueRunner_DoWork);
QueueWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bwQueueRunner_RunWorkerCompleted);
QueueWorker.RunWorkerAsync();
BackupWorker = new BackgroundWorker();
BackupWorker.WorkerSupportsCancellation = true;
BackupWorker.DoWork += new DoWorkEventHandler(bwBackup_DoWork);
BackupWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bwBackup_RunWorkerCompleted);
BackupWorker.RunWorkerAsync(args);
return "Started background operations.";
}
void bwQueueRunner_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
QueueWorker = null;
Console.WriteLine(BackgroundBackupStatus);
}
void bwQueueRunner_DoWork(object sender, DoWorkEventArgs e)
{
TextItemErrors = TextItemsTransferred = 0;
while (QueueWorker.CancellationPending == false)
{
// have any timed out?
if (CurrentDownloads.Count > 0)
{
foreach (QueuedDownloadInfo qdi in CurrentDownloads)
{
if ((qdi.WhenRequested + TimeSpan.FromSeconds(60)) < DateTime.Now)
{
Logger.DebugLog(Name + ": timeout on asset " + qdi.AssetID.ToString(), Client);
// submit request again
Client.Assets.RequestInventoryAsset(
qdi.AssetID, qdi.ItemID, qdi.TaskID, qdi.OwnerID, qdi.Type, true, Assets_OnAssetReceived);
qdi.WhenRequested = DateTime.Now;
qdi.IsRequested = true;
}
}
}
if (PendingDownloads.Count != 0)
{
// room in the server queue?
if (CurrentDownloads.Count < MAX_TRANSFERS)
{
// yes
QueuedDownloadInfo qdi = PendingDownloads.Dequeue();
qdi.WhenRequested = DateTime.Now;
qdi.IsRequested = true;
Client.Assets.RequestInventoryAsset(
qdi.AssetID, qdi.ItemID, qdi.TaskID, qdi.OwnerID, qdi.Type, true, Assets_OnAssetReceived);
lock (CurrentDownloads) CurrentDownloads.Add(qdi);
}
}
if (CurrentDownloads.Count == 0 && PendingDownloads.Count == 0 && BackupWorker == null)
{
Logger.DebugLog(Name + ": both transfer queues empty AND inventory walking thread is done", Client);
return;
}
Thread.Sleep(100);
}
}
void bwBackup_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Console.WriteLine(Name + ": Inventory walking thread done.");
BackupWorker = null;
}
private void bwBackup_DoWork(object sender, DoWorkEventArgs e)
{
string[] args;
TextItemsFound = 0;
args = (string[])e.Argument;
lock (CurrentDownloads) CurrentDownloads.Clear();
// FIXME:
//Client.Inventory.RequestFolderContents(Client.Inventory.Store.RootFolder.UUID, Client.Self.AgentID,
// true, true, false, InventorySortOrder.ByName);
DirectoryInfo di = new DirectoryInfo(args[1]);
// recurse on the root folder into the entire inventory
BackupFolder(Client.Inventory.Store.RootNode, di.FullName);
}
/// <summary>
/// BackupFolder - recurse through the inventory nodes sending scripts and notecards to the transfer queue
/// </summary>
/// <param name="folder">The current leaf in the inventory tree</param>
/// <param name="sPathSoFar">path so far, in the form @"c:\here" -- this needs to be "clean" for the current filesystem</param>
private void BackupFolder(InventoryNode folder, string sPathSoFar)
{
// FIXME:
//Client.Inventory.RequestFolderContents(folder.Data.UUID, Client.Self.AgentID, true, true, false,
// InventorySortOrder.ByName);
// first scan this folder for text
foreach (InventoryNode iNode in folder.Nodes.Values)
{
if (BackupWorker.CancellationPending)
return;
if (iNode.Data is OpenMetaverse.InventoryItem)
{
InventoryItem ii = iNode.Data as InventoryItem;
if (ii.AssetType == AssetType.LSLText || ii.AssetType == AssetType.Notecard)
{
// check permissions on scripts
if (ii.AssetType == AssetType.LSLText)
{
if ((ii.Permissions.OwnerMask & PermissionMask.Modify) == PermissionMask.None)
{
// skip this one
continue;
}
}
string sExtension = (ii.AssetType == AssetType.LSLText) ? ".lsl" : ".txt";
// make the output file
string sPath = sPathSoFar + @"\" + MakeValid(ii.Name.Trim()) + sExtension;
// create the new qdi
QueuedDownloadInfo qdi = new QueuedDownloadInfo(sPath, ii.AssetUUID, iNode.Data.UUID, UUID.Zero,
Client.Self.AgentID, ii.AssetType);
// add it to the queue
lock (PendingDownloads)
{
TextItemsFound++;
PendingDownloads.Enqueue(qdi);
}
}
}
}
// now run any subfolders
foreach (InventoryNode i in folder.Nodes.Values)
{
if (BackupWorker.CancellationPending)
return;
else if (i.Data is OpenMetaverse.InventoryFolder)
BackupFolder(i, sPathSoFar + @"\" + MakeValid(i.Data.Name.Trim()));
}
}
private string MakeValid(string path)
{
// FIXME: We need to strip illegal characters out
return path.Trim().Replace('"', '\'');
}
private void Assets_OnAssetReceived(AssetDownload asset, Asset blah)
{
lock (CurrentDownloads)
{
// see if we have this in our transfer list
QueuedDownloadInfo r = CurrentDownloads.Find(delegate(QueuedDownloadInfo q)
{
return q.AssetID == asset.AssetID;
});
if (r != null && r.AssetID == asset.AssetID)
{
if (asset.Success)
{
// create the directory to put this in
Directory.CreateDirectory(Path.GetDirectoryName(r.FileName));
// write out the file
File.WriteAllBytes(r.FileName, asset.AssetData);
Logger.DebugLog(Name + " Wrote: " + r.FileName, Client);
TextItemsTransferred++;
}
else
{
TextItemErrors++;
Console.WriteLine("{0}: Download of asset {1} ({2}) failed with status {3}", Name, r.FileName,
r.AssetID.ToString(), asset.Status.ToString());
}
// remove the entry
CurrentDownloads.Remove(r);
}
}
}
/// <summary>
/// returns blank or "not" if false
/// </summary>
/// <param name="b"></param>
/// <returns></returns>
private static string BoolToNot(bool b)
{
return b ? String.Empty : "not";
}
}
}
@@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace OpenMetaverse.TestClient
{
public class BalanceCommand: Command
{
public BalanceCommand(TestClient testClient)
{
Name = "balance";
Description = "Shows the amount of L$.";
Category = CommandCategory.Other;
}
public override string Execute(string[] args, UUID fromAgentID)
{
System.Threading.AutoResetEvent waitBalance = new System.Threading.AutoResetEvent(false);
EventHandler<BalanceEventArgs> del = delegate(object sender, BalanceEventArgs e) { waitBalance.Set(); };
Client.Self.MoneyBalance += del;
Client.Self.RequestBalance();
String result = "Timeout waiting for balance reply";
if (waitBalance.WaitOne(10000, false))
{
result = Client.ToString() + " has L$: " + Client.Self.Balance;
}
Client.Self.MoneyBalance -= del;
return result;
}
}
}
@@ -0,0 +1,84 @@
using System;
using System.Collections.Generic;
using System.Text;
using OpenMetaverse;
namespace OpenMetaverse.TestClient.Commands.Inventory.Shell
{
public class ChangeDirectoryCommand : Command
{
private OpenMetaverse.Inventory Inventory;
public ChangeDirectoryCommand(TestClient client)
{
Name = "cd";
Description = "Changes the current working inventory folder.";
Category = CommandCategory.Inventory;
}
public override string Execute(string[] args, UUID fromAgentID)
{
Inventory = Client.Inventory.Store;
if (args.Length > 1)
return "Usage: cd [path-to-folder]";
string pathStr = "";
string[] path = null;
if (args.Length == 0)
{
path = new string[] { "" };
// cd without any arguments doesn't do anything.
}
else if (args.Length == 1)
{
pathStr = args[0];
path = pathStr.Split(new char[] { '/' });
// Use '/' as a path seperator.
}
InventoryFolder currentFolder = Client.CurrentDirectory;
if (pathStr.StartsWith("/"))
currentFolder = Inventory.RootFolder;
if (currentFolder == null) // We need this to be set to something.
return "Error: Client not logged in.";
// Traverse the path, looking for the
for (int i = 0; i < path.Length; ++i)
{
string nextName = path[i];
if (string.IsNullOrEmpty(nextName) || nextName == ".")
continue; // Ignore '.' and blanks, stay in the current directory.
if (nextName == ".." && currentFolder != Inventory.RootFolder)
{
// If we encounter .., move to the parent folder.
currentFolder = Inventory[currentFolder.ParentUUID] as InventoryFolder;
}
else
{
List<InventoryBase> currentContents = Inventory.GetContents(currentFolder);
// Try and find an InventoryBase with the corresponding name.
bool found = false;
foreach (InventoryBase item in currentContents)
{
// Allow lookup by UUID as well as name:
if (item.Name == nextName || item.UUID.ToString() == nextName)
{
found = true;
if (item is InventoryFolder)
{
currentFolder = item as InventoryFolder;
}
else
{
return item.Name + " is not a folder.";
}
}
}
if (!found)
return nextName + " not found in " + currentFolder.Name;
}
}
Client.CurrentDirectory = currentFolder;
return "Current folder: " + currentFolder.Name;
}
}
}
@@ -0,0 +1,193 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading;
using OpenMetaverse;
using OpenMetaverse.Assets;
namespace OpenMetaverse.TestClient
{
public class CreateNotecardCommand : Command
{
const int NOTECARD_CREATE_TIMEOUT = 1000 * 10;
const int NOTECARD_FETCH_TIMEOUT = 1000 * 10;
const int INVENTORY_FETCH_TIMEOUT = 1000 * 10;
public CreateNotecardCommand(TestClient testClient)
{
Name = "createnotecard";
Description = "Creates a notecard from a local text file and optionally embed an inventory item. Usage: createnotecard filename.txt [itemid]";
Category = CommandCategory.Inventory;
}
public override string Execute(string[] args, UUID fromAgentID)
{
UUID embedItemID = UUID.Zero, notecardItemID = UUID.Zero, notecardAssetID = UUID.Zero;
string filename, fileData;
bool success = false, finalUploadSuccess = false;
string message = String.Empty;
AutoResetEvent notecardEvent = new AutoResetEvent(false);
if (args.Length == 1)
{
filename = args[0];
}
else if (args.Length == 2)
{
filename = args[0];
UUID.TryParse(args[1], out embedItemID);
}
else
{
return "Usage: createnotecard filename.txt";
}
if (!File.Exists(filename))
return "File \"" + filename + "\" does not exist";
try { fileData = File.ReadAllText(filename); }
catch (Exception ex) { return "Failed to open " + filename + ": " + ex.Message; }
#region Notecard asset data
AssetNotecard notecard = new AssetNotecard();
notecard.BodyText = fileData;
// Item embedding
if (embedItemID != UUID.Zero)
{
// Try to fetch the inventory item
InventoryItem item = FetchItem(embedItemID);
if (item != null)
{
notecard.EmbeddedItems = new List<InventoryItem> { item };
notecard.BodyText += (char)0xdbc0 + (char)0xdc00;
}
else
{
return "Failed to fetch inventory item " + embedItemID;
}
}
notecard.Encode();
#endregion Notecard asset data
Client.Inventory.RequestCreateItem(Client.Inventory.FindFolderForType(AssetType.Notecard),
filename, filename + " created by OpenMetaverse TestClient " + DateTime.Now, AssetType.Notecard,
UUID.Random(), InventoryType.Notecard, PermissionMask.All,
delegate(bool createSuccess, InventoryItem item)
{
if (createSuccess)
{
#region Upload an empty notecard asset first
AutoResetEvent emptyNoteEvent = new AutoResetEvent(false);
AssetNotecard empty = new AssetNotecard();
empty.BodyText = "\n";
empty.Encode();
Client.Inventory.RequestUploadNotecardAsset(empty.AssetData, item.UUID,
delegate(bool uploadSuccess, string status, UUID itemID, UUID assetID)
{
notecardItemID = itemID;
notecardAssetID = assetID;
success = uploadSuccess;
message = status ?? "Unknown error uploading notecard asset";
emptyNoteEvent.Set();
});
emptyNoteEvent.WaitOne(NOTECARD_CREATE_TIMEOUT, false);
#endregion Upload an empty notecard asset first
if (success)
{
// Upload the actual notecard asset
Client.Inventory.RequestUploadNotecardAsset(notecard.AssetData, item.UUID,
delegate(bool uploadSuccess, string status, UUID itemID, UUID assetID)
{
notecardItemID = itemID;
notecardAssetID = assetID;
finalUploadSuccess = uploadSuccess;
message = status ?? "Unknown error uploading notecard asset";
notecardEvent.Set();
});
}
else
{
notecardEvent.Set();
}
}
else
{
message = "Notecard item creation failed";
notecardEvent.Set();
}
}
);
notecardEvent.WaitOne(NOTECARD_CREATE_TIMEOUT, false);
if (finalUploadSuccess)
{
Logger.Log("Notecard successfully created, ItemID " + notecardItemID + " AssetID " + notecardAssetID, Helpers.LogLevel.Info);
return DownloadNotecard(notecardItemID, notecardAssetID);
}
else
return "Notecard creation failed: " + message;
}
private InventoryItem FetchItem(UUID itemID)
{
InventoryItem fetchItem = null;
AutoResetEvent fetchItemEvent = new AutoResetEvent(false);
EventHandler<ItemReceivedEventArgs> itemReceivedCallback =
delegate(object sender, ItemReceivedEventArgs e)
{
if (e.Item.UUID == itemID)
{
fetchItem = e.Item;
fetchItemEvent.Set();
}
};
Client.Inventory.ItemReceived += itemReceivedCallback;
Client.Inventory.RequestFetchInventory(itemID, Client.Self.AgentID);
fetchItemEvent.WaitOne(INVENTORY_FETCH_TIMEOUT, false);
Client.Inventory.ItemReceived -= itemReceivedCallback;
return fetchItem;
}
private string DownloadNotecard(UUID itemID, UUID assetID)
{
AutoResetEvent assetDownloadEvent = new AutoResetEvent(false);
byte[] notecardData = null;
string error = "Timeout";
Client.Assets.RequestInventoryAsset(assetID, itemID, UUID.Zero, Client.Self.AgentID, AssetType.Notecard, true,
delegate(AssetDownload transfer, Asset asset)
{
if (transfer.Success)
notecardData = transfer.AssetData;
else
error = transfer.Status.ToString();
assetDownloadEvent.Set();
}
);
assetDownloadEvent.WaitOne(NOTECARD_FETCH_TIMEOUT, false);
if (notecardData != null)
return Encoding.UTF8.GetString(notecardData);
else
return "Error downloading notecard asset: " + error;
}
}
}
@@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading;
using System.Xml;
using System.Xml.Serialization;
using OpenMetaverse;
namespace OpenMetaverse.TestClient
{
/// <summary>
/// Inventory Example, Moves a folder to the Trash folder
/// </summary>
public class DeleteFolderCommand : Command
{
public DeleteFolderCommand(TestClient testClient)
{
Name = "deleteFolder";
Description = "Moves a folder to the Trash Folder";
Category = CommandCategory.Inventory;
}
public override string Execute(string[] args, UUID fromAgentID)
{
// parse the command line
string target = String.Empty;
for (int ct = 0; ct < args.Length; ct++)
target = target + args[ct] + " ";
target = target.TrimEnd();
// initialize results list
List<InventoryBase> found = new List<InventoryBase>();
// find the folder
found = Client.Inventory.LocalFind(Client.Inventory.Store.RootFolder.UUID, target.Split('/'), 0, true);
if (found.Count.Equals(1))
{
// move the folder to the trash folder
Client.Inventory.MoveFolder(found[0].UUID, Client.Inventory.FindFolderForType(AssetType.TrashFolder));
return String.Format("Moved folder {0} to Trash", found[0].Name);
}
return String.Empty;
}
}
}
@@ -0,0 +1,84 @@
using System;
using System.IO;
using System.Threading;
using OpenMetaverse;
using OpenMetaverse.Assets;
namespace OpenMetaverse.TestClient
{
public class DownloadCommand : Command
{
UUID AssetID;
AssetType assetType;
AutoResetEvent DownloadHandle = new AutoResetEvent(false);
bool Success;
string usage = "Usage: download [uuid] [assetType]";
public DownloadCommand(TestClient testClient)
{
Name = "download";
Description = "Downloads the specified asset. Usage: download [uuid] [assetType]";
Category = CommandCategory.Inventory;
}
public override string Execute(string[] args, UUID fromAgentID)
{
if (args.Length != 2)
return usage;
Success = false;
AssetID = UUID.Zero;
assetType = AssetType.Unknown;
DownloadHandle.Reset();
if (!UUID.TryParse(args[0], out AssetID))
return usage;
try {
assetType = (AssetType)Enum.Parse(typeof(AssetType), args[1], true);
} catch (ArgumentException) {
return usage;
}
if (!Enum.IsDefined(typeof(AssetType), assetType))
return usage;
// Start the asset download
Client.Assets.RequestAsset(AssetID, assetType, true, Assets_OnAssetReceived);
if (DownloadHandle.WaitOne(120 * 1000, false))
{
if (Success)
return String.Format("Saved {0}.{1}", AssetID, assetType.ToString().ToLower());
else
return String.Format("Failed to download asset {0}, perhaps {1} is the incorrect asset type?",
AssetID, assetType);
}
else
{
return "Timed out waiting for texture download";
}
}
private void Assets_OnAssetReceived(AssetDownload transfer, Asset asset)
{
if (transfer.AssetID == AssetID)
{
if (transfer.Success)
{
try
{
File.WriteAllBytes(String.Format("{0}.{1}", AssetID,
assetType.ToString().ToLower()), asset.AssetData);
Success = true;
}
catch (Exception ex)
{
Logger.Log(ex.Message, Helpers.LogLevel.Error, ex);
}
}
DownloadHandle.Set();
}
}
}
}
@@ -0,0 +1,118 @@
using System;
using System.Text;
using System.IO;
using System.Collections.Generic;
using OpenMetaverse;
using OpenMetaverse.Imaging;
using OpenMetaverse.Assets;
namespace OpenMetaverse.TestClient
{
public class DumpOutfitCommand : Command
{
List<UUID> OutfitAssets = new List<UUID>();
public DumpOutfitCommand(TestClient testClient)
{
Name = "dumpoutfit";
Description = "Dumps all of the textures from an avatars outfit to the hard drive. Usage: dumpoutfit [avatar-uuid]";
Category = CommandCategory.Inventory;
}
public override string Execute(string[] args, UUID fromAgentID)
{
if (args.Length != 1)
return "Usage: dumpoutfit [avatar-uuid]";
UUID target;
if (!UUID.TryParse(args[0], out target))
return "Usage: dumpoutfit [avatar-uuid]";
lock (Client.Network.Simulators)
{
for (int i = 0; i < Client.Network.Simulators.Count; i++)
{
Avatar targetAv = Client.Network.Simulators[i].ObjectsAvatars.Find(
delegate(Avatar avatar)
{
return avatar.ID == target;
}
);
if (targetAv != null)
{
StringBuilder output = new StringBuilder("Downloading ");
lock (OutfitAssets) OutfitAssets.Clear();
for (int j = 0; j < targetAv.Textures.FaceTextures.Length; j++)
{
Primitive.TextureEntryFace face = targetAv.Textures.FaceTextures[j];
if (face != null)
{
ImageType type = ImageType.Normal;
switch ((AvatarTextureIndex)j)
{
case AvatarTextureIndex.HeadBaked:
case AvatarTextureIndex.EyesBaked:
case AvatarTextureIndex.UpperBaked:
case AvatarTextureIndex.LowerBaked:
case AvatarTextureIndex.SkirtBaked:
type = ImageType.Baked;
break;
}
OutfitAssets.Add(face.TextureID);
Client.Assets.RequestImage(face.TextureID, type, Assets_OnImageReceived);
output.Append(((AvatarTextureIndex)j).ToString());
output.Append(" ");
}
}
return output.ToString();
}
}
}
return "Couldn't find avatar " + target.ToString();
}
private void Assets_OnImageReceived(TextureRequestState state, AssetTexture assetTexture)
{
lock (OutfitAssets)
{
if (OutfitAssets.Contains(assetTexture.AssetID))
{
if (state == TextureRequestState.Finished)
{
try
{
File.WriteAllBytes(assetTexture.AssetID + ".jp2", assetTexture.AssetData);
Console.WriteLine("Wrote JPEG2000 image " + assetTexture.AssetID + ".jp2");
ManagedImage imgData;
OpenJPEG.DecodeToImage(assetTexture.AssetData, out imgData);
byte[] tgaFile = imgData.ExportTGA();
File.WriteAllBytes(assetTexture.AssetID + ".tga", tgaFile);
Console.WriteLine("Wrote TGA image " + assetTexture.AssetID + ".tga");
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
else
{
Console.WriteLine("Failed to download image " + assetTexture.AssetID);
}
OutfitAssets.Remove(assetTexture.AssetID);
}
}
}
}
}
@@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace OpenMetaverse.TestClient
{
public class EmptyLostAndCommand : Command
{
/// <summary>
/// TestClient command to download and display a notecard asset
/// </summary>
/// <param name="testClient"></param>
public EmptyLostAndCommand(TestClient testClient)
{
Name = "emptylostandfound";
Description = "Empty inventory Lost And Found folder";
Category = CommandCategory.Inventory;
}
/// <summary>
/// Exectute the command
/// </summary>
/// <param name="args"></param>
/// <param name="fromAgentID"></param>
/// <returns></returns>
public override string Execute(string[] args, UUID fromAgentID)
{
Client.Inventory.EmptyLostAndFound();
return "Lost And Found Emptied";
}
}
}
@@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace OpenMetaverse.TestClient
{
public class EmptyTrashCommand : Command
{
/// <summary>
/// TestClient command to download and display a notecard asset
/// </summary>
/// <param name="testClient"></param>
public EmptyTrashCommand(TestClient testClient)
{
Name = "emptytrash";
Description = "Empty inventory Trash folder";
Category = CommandCategory.Inventory;
}
/// <summary>
/// Exectute the command
/// </summary>
/// <param name="args"></param>
/// <param name="fromAgentID"></param>
/// <returns></returns>
public override string Execute(string[] args, UUID fromAgentID)
{
Client.Inventory.EmptyTrash();
return "Trash Emptied";
}
}
}
@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Text;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace OpenMetaverse.TestClient
{
public class GiveAllCommand: Command
{
public GiveAllCommand(TestClient testClient)
{
Name = "giveAll";
Description = "Gives you all it's money.";
Category = CommandCategory.Other;
}
public override string Execute(string[] args, UUID fromAgentID)
{
if (fromAgentID == UUID.Zero)
return "Unable to send money to console. This command only works when IMed.";
int amount = Client.Self.Balance;
Client.Self.GiveAvatarMoney(fromAgentID, Client.Self.Balance, "TestClient.GiveAll");
return "Gave $" + amount + " to " + fromAgentID;
}
}
}
@@ -0,0 +1,65 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace OpenMetaverse.TestClient.Commands.Inventory.Shell
{
class GiveItemCommand : Command
{
private InventoryManager Manager;
private OpenMetaverse.Inventory Inventory;
public GiveItemCommand(TestClient client)
{
Name = "give";
Description = "Gives items from the current working directory to an avatar.";
Category = CommandCategory.Inventory;
}
public override string Execute(string[] args, UUID fromAgentID)
{
if (args.Length < 2)
{
return "Usage: give <agent uuid> itemname";
}
UUID dest;
if (!UUID.TryParse(args[0], out dest))
{
return "First argument expected agent UUID.";
}
Manager = Client.Inventory;
Inventory = Manager.Store;
string ret = "";
string nl = "\n";
string target = String.Empty;
for (int ct = 0; ct < args.Length; ct++)
target = target + args[ct] + " ";
target = target.TrimEnd();
string inventoryName = target;
// WARNING: Uses local copy of inventory contents, need to download them first.
List<InventoryBase> contents = Inventory.GetContents(Client.CurrentDirectory);
bool found = false;
foreach (InventoryBase b in contents)
{
if (inventoryName == b.Name || inventoryName == b.UUID.ToString())
{
found = true;
if (b is InventoryItem)
{
InventoryItem item = b as InventoryItem;
Manager.GiveItem(item.UUID, item.Name, item.AssetType, dest, true);
ret += "Gave " + item.Name + " (" + item.AssetType + ")" + nl;
}
else
{
ret += "Unable to give folder " + b.Name + nl;
}
}
}
if (!found)
ret += "No inventory item named " + inventoryName + " found." + nl;
return ret;
}
}
}
@@ -0,0 +1,57 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading;
using System.Xml;
using System.Xml.Serialization;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace OpenMetaverse.TestClient
{
public class InventoryCommand : Command
{
private Inventory Inventory;
private InventoryManager Manager;
public InventoryCommand(TestClient testClient)
{
Name = "i";
Description = "Prints out inventory.";
Category = CommandCategory.Inventory;
}
public override string Execute(string[] args, UUID fromAgentID)
{
Manager = Client.Inventory;
Inventory = Manager.Store;
StringBuilder result = new StringBuilder();
InventoryFolder rootFolder = Inventory.RootFolder;
PrintFolder(rootFolder, result, 0);
return result.ToString();
}
void PrintFolder(InventoryFolder f, StringBuilder result, int indent)
{
List<InventoryBase> contents = Manager.FolderContents(f.UUID, Client.Self.AgentID,
true, true, InventorySortOrder.ByName, 3000);
if (contents != null)
{
foreach (InventoryBase i in contents)
{
result.AppendFormat("{0}{1} ({2})\n", new String(' ', indent * 2), i.Name, i.UUID);
if (i is InventoryFolder)
{
InventoryFolder folder = (InventoryFolder)i;
PrintFolder(folder, result, indent + 1);
}
}
}
}
}
}
@@ -0,0 +1,99 @@
using System;
using System.Collections.Generic;
using System.Text;
using OpenMetaverse;
namespace OpenMetaverse.TestClient.Commands.Inventory.Shell
{
public class ListContentsCommand : Command
{
private InventoryManager Manager;
private OpenMetaverse.Inventory Inventory;
public ListContentsCommand(TestClient client)
{
Name = "ls";
Description = "Lists the contents of the current working inventory folder.";
Category = CommandCategory.Inventory;
}
public override string Execute(string[] args, UUID fromAgentID)
{
if (args.Length > 1)
return "Usage: ls [-l]";
bool longDisplay = false;
if (args.Length > 0 && args[0] == "-l")
longDisplay = true;
Manager = Client.Inventory;
Inventory = Manager.Store;
// WARNING: Uses local copy of inventory contents, need to download them first.
List<InventoryBase> contents = Inventory.GetContents(Client.CurrentDirectory);
string displayString = "";
string nl = "\n"; // New line character
// Pretty simple, just print out the contents.
foreach (InventoryBase b in contents)
{
if (longDisplay)
{
// Generate a nicely formatted description of the item.
// It kinda looks like the output of the unix ls.
// starts with 'd' if the inventory is a folder, '-' if not.
// 9 character permissions string
// UUID of object
// Name of object
if (b is InventoryFolder)
{
InventoryFolder folder = b as InventoryFolder;
displayString += "d--------- ";
displayString += folder.UUID;
displayString += " " + folder.Name;
}
else if (b is InventoryItem)
{
InventoryItem item = b as InventoryItem;
displayString += "-";
displayString += PermMaskString(item.Permissions.OwnerMask);
displayString += PermMaskString(item.Permissions.GroupMask);
displayString += PermMaskString(item.Permissions.EveryoneMask);
displayString += " " + item.UUID;
displayString += " " + item.Name;
displayString += nl;
displayString += " AssetID: " + item.AssetUUID;
}
}
else
{
displayString += b.Name;
}
displayString += nl;
}
return displayString;
}
/// <summary>
/// Returns a 3-character summary of the PermissionMask
/// CMT if the mask allows copy, mod and transfer
/// -MT if it disallows copy
/// --T if it only allows transfer
/// --- if it disallows everything
/// </summary>
/// <param name="mask"></param>
/// <returns></returns>
private static string PermMaskString(PermissionMask mask)
{
string str = "";
if (((uint)mask | (uint)PermissionMask.Copy) == (uint)PermissionMask.Copy)
str += "C";
else
str += "-";
if (((uint)mask | (uint)PermissionMask.Modify) == (uint)PermissionMask.Modify)
str += "M";
else
str += "-";
if (((uint)mask | (uint)PermissionMask.Transfer) == (uint)PermissionMask.Transfer)
str += "T";
else
str += "-";
return str;
}
}
}
@@ -0,0 +1,60 @@
using System;
using System.Collections.Generic;
using OpenMetaverse;
namespace OpenMetaverse.TestClient
{
public class ObjectInventoryCommand : Command
{
public ObjectInventoryCommand(TestClient testClient)
{
Name = "objectinventory";
Description = "Retrieves a listing of items inside an object (task inventory). Usage: objectinventory [objectID]";
Category = CommandCategory.Inventory;
}
public override string Execute(string[] args, UUID fromAgentID)
{
if (args.Length != 1)
return "Usage: objectinventory [objectID]";
uint objectLocalID;
UUID objectID;
if (!UUID.TryParse(args[0], out objectID))
return "Usage: objectinventory [objectID]";
Primitive found = Client.Network.CurrentSim.ObjectsPrimitives.Find(delegate(Primitive prim) { return prim.ID == objectID; });
if (found != null)
objectLocalID = found.LocalID;
else
return "Couldn't find prim " + objectID.ToString();
List<InventoryBase> items = Client.Inventory.GetTaskInventory(objectID, objectLocalID, 1000 * 30);
if (items != null)
{
string result = String.Empty;
for (int i = 0; i < items.Count; i++)
{
if (items[i] is InventoryFolder)
{
result += String.Format("[Folder] Name: {0}", items[i].Name) + Environment.NewLine;
}
else
{
InventoryItem item = (InventoryItem)items[i];
result += String.Format("[Item] Name: {0} Desc: {1} Type: {2}", item.Name, item.Description,
item.AssetType) + Environment.NewLine;
}
}
return result;
}
else
{
return "Failed to download task inventory for " + objectLocalID;
}
}
}
}
@@ -0,0 +1,38 @@
using System;
using System.IO;
using OpenMetaverse;
namespace OpenMetaverse.TestClient
{
public class ScriptCommand : Command
{
public ScriptCommand(TestClient testClient)
{
Name = "script";
Description = "Reads TestClient commands from a file. One command per line, arguments separated by spaces. Usage: script [filename]";
Category = CommandCategory.TestClient;
}
public override string Execute(string[] args, UUID fromAgentID)
{
if (args.Length != 1)
return "Usage: script [filename]";
// Load the file
string[] lines;
try { lines = File.ReadAllLines(args[0]); }
catch (Exception e) { return e.Message; }
// Execute all of the commands
for (int i = 0; i < lines.Length; i++)
{
string line = lines[i].Trim();
if (line.Length > 0)
ClientManager.Instance.DoCommandAll(line, UUID.Zero);
}
return "Finished executing " + lines.Length + " commands";
}
}
}
@@ -0,0 +1,134 @@
using System;
using System.Collections.Generic;
using System.Threading;
using OpenMetaverse;
namespace OpenMetaverse.TestClient
{
public class TaskRunningCommand : Command
{
public TaskRunningCommand(TestClient testClient)
{
Name = "taskrunning";
Description = "Retrieves or set IsRunning flag on items inside an object (task inventory). Usage: taskrunning objectID [[scriptName] true|false]";
Category = CommandCategory.Inventory;
}
public override string Execute(string[] args, UUID fromAgentID)
{
if (args.Length != 1)
return "Usage: taskrunning objectID [[scriptName] true|false]";
uint objectLocalID;
UUID objectID;
if (!UUID.TryParse(args[0], out objectID))
return "Usage: taskrunning objectID [[scriptName] true|false]";
Primitive found = Client.Network.CurrentSim.ObjectsPrimitives.Find(delegate(Primitive prim) { return prim.ID == objectID; });
if (found != null)
objectLocalID = found.LocalID;
else
return String.Format("Couldn't find prim {0}", objectID);
List<InventoryBase> items = Client.Inventory.GetTaskInventory(objectID, objectLocalID, 1000 * 30);
//bool wantSet = false;
bool setTaskTo = false;
if (items != null)
{
string result = String.Empty;
string matching = String.Empty;
bool setAny = false;
if (args.Length > 1)
{
matching = args[1];
string tf;
if (args.Length > 2)
{
tf = args[2];
}
else
{
tf = matching.ToLower();
}
if (tf == "true")
{
setAny = true;
setTaskTo = true;
}
else if (tf == "false")
{
setAny = true;
setTaskTo = false;
}
}
bool wasRunning = false;
EventHandler<ScriptRunningReplyEventArgs> callback;
using (AutoResetEvent OnScriptRunningReset = new AutoResetEvent(false))
{
callback = ((object sender, ScriptRunningReplyEventArgs e) =>
{
if (e.ObjectID == objectID)
{
result += String.Format(" IsMono: {0} IsRunning: {1}", e.IsMono, e.IsRunning);
wasRunning = e.IsRunning;
OnScriptRunningReset.Set();
}
});
Client.Inventory.ScriptRunningReply += callback;
for (int i = 0; i < items.Count; i++)
{
if (items[i] is InventoryFolder)
{
// this shouldn't happen this year
result += String.Format("[Folder] Name: {0}", items[i].Name) + Environment.NewLine;
}
else
{
InventoryItem item = (InventoryItem)items[i];
AssetType assetType = item.AssetType;
result += String.Format("[Item] Name: {0} Desc: {1} Type: {2}", item.Name, item.Description,
assetType);
if (assetType == AssetType.LSLBytecode || assetType == AssetType.LSLText)
{
OnScriptRunningReset.Reset();
Client.Inventory.RequestGetScriptRunning(objectID, item.UUID);
if (!OnScriptRunningReset.WaitOne(10000, true))
{
result += " (no script info)";
}
if (setAny && item.Name.Contains(matching))
{
if (wasRunning != setTaskTo)
{
OnScriptRunningReset.Reset();
result += " Setting " + setTaskTo + " => ";
Client.Inventory.RequestSetScriptRunning(objectID, item.UUID, setTaskTo);
if (!OnScriptRunningReset.WaitOne(10000, true))
{
result += " (was not set)";
}
}
}
}
result += Environment.NewLine;
}
}
}
Client.Inventory.ScriptRunningReply -= callback;
return result;
}
else
{
return "Failed to download task inventory for " + objectLocalID;
}
}
}
}
@@ -0,0 +1,51 @@
using System;
using System.Collections.Generic;
using System.Text;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace OpenMetaverse.TestClient
{
public class TreeCommand: Command
{
public TreeCommand(TestClient testClient)
{
Name = "tree";
Description = "Rez a tree.";
Category = CommandCategory.Objects;
}
public override string Execute(string[] args, UUID fromAgentID)
{
if (args.Length == 1)
{
try
{
string treeName = args[0].Trim(new char[] { ' ' });
Tree tree = (Tree)Enum.Parse(typeof(Tree), treeName);
Vector3 treePosition = Client.Self.SimPosition;
treePosition.Z += 3.0f;
Client.Objects.AddTree(Client.Network.CurrentSim, new Vector3(0.5f, 0.5f, 0.5f),
Quaternion.Identity, treePosition, tree, Client.GroupID, false);
return "Attempted to rez a " + treeName + " tree";
}
catch (Exception)
{
return "Type !tree for usage";
}
}
string usage = "Usage: !tree [";
foreach (string value in Enum.GetNames(typeof(Tree)))
{
usage += value + ",";
}
usage = usage.TrimEnd(new char[] { ',' });
usage += "]";
return usage;
}
}
}
@@ -0,0 +1,161 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Drawing;
using OpenMetaverse;
using OpenMetaverse.Http;
using OpenMetaverse.Imaging;
namespace OpenMetaverse.TestClient
{
public class UploadImageCommand : Command
{
AutoResetEvent UploadCompleteEvent = new AutoResetEvent(false);
UUID TextureID = UUID.Zero;
DateTime start;
public UploadImageCommand(TestClient testClient)
{
Name = "uploadimage";
Description = "Upload an image to your inventory. Usage: uploadimage [inventoryname] [timeout] [filename]";
Category = CommandCategory.Inventory;
}
public override string Execute(string[] args, UUID fromAgentID)
{
string inventoryName;
uint timeout;
string fileName;
if (args.Length != 3)
return "Usage: uploadimage [inventoryname] [timeout] [filename]";
TextureID = UUID.Zero;
inventoryName = args[0];
fileName = args[2];
if (!UInt32.TryParse(args[1], out timeout))
return "Usage: uploadimage [inventoryname] [timeout] [filename]";
Console.WriteLine("Loading image " + fileName);
byte[] jpeg2k = LoadImage(fileName);
if (jpeg2k == null)
return "Failed to compress image to JPEG2000";
Console.WriteLine("Finished compressing image to JPEG2000, uploading...");
start = DateTime.Now;
DoUpload(jpeg2k, inventoryName);
if (UploadCompleteEvent.WaitOne((int)timeout, false))
{
return String.Format("Texture upload {0}: {1}", (TextureID != UUID.Zero) ? "succeeded" : "failed",
TextureID);
}
else
{
return "Texture upload timed out";
}
}
private void DoUpload(byte[] UploadData, string FileName)
{
if (UploadData != null)
{
string name = System.IO.Path.GetFileNameWithoutExtension(FileName);
Client.Inventory.RequestCreateItemFromAsset(UploadData, name, "Uploaded with TestClient",
AssetType.Texture, InventoryType.Texture, Client.Inventory.FindFolderForType(AssetType.Texture),
delegate(bool success, string status, UUID itemID, UUID assetID)
{
Console.WriteLine(String.Format(
"RequestCreateItemFromAsset() returned: Success={0}, Status={1}, ItemID={2}, AssetID={3}",
success, status, itemID, assetID));
TextureID = assetID;
Console.WriteLine(String.Format("Upload took {0}", DateTime.Now.Subtract(start)));
UploadCompleteEvent.Set();
}
);
}
}
private byte[] LoadImage(string fileName)
{
byte[] UploadData;
string lowfilename = fileName.ToLower();
Bitmap bitmap = null;
try
{
if (lowfilename.EndsWith(".jp2") || lowfilename.EndsWith(".j2c"))
{
Image image;
ManagedImage managedImage;
// Upload JPEG2000 images untouched
UploadData = System.IO.File.ReadAllBytes(fileName);
OpenJPEG.DecodeToImage(UploadData, out managedImage, out image);
bitmap = (Bitmap)image;
}
else
{
if (lowfilename.EndsWith(".tga"))
bitmap = LoadTGAClass.LoadTGA(fileName);
else
bitmap = (Bitmap)System.Drawing.Image.FromFile(fileName);
int oldwidth = bitmap.Width;
int oldheight = bitmap.Height;
if (!IsPowerOfTwo((uint)oldwidth) || !IsPowerOfTwo((uint)oldheight))
{
Bitmap resized = new Bitmap(256, 256, bitmap.PixelFormat);
Graphics graphics = Graphics.FromImage(resized);
graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
graphics.InterpolationMode =
System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
graphics.DrawImage(bitmap, 0, 0, 256, 256);
bitmap.Dispose();
bitmap = resized;
oldwidth = 256;
oldheight = 256;
}
// Handle resizing to prevent excessively large images
if (oldwidth > 1024 || oldheight > 1024)
{
int newwidth = (oldwidth > 1024) ? 1024 : oldwidth;
int newheight = (oldheight > 1024) ? 1024 : oldheight;
Bitmap resized = new Bitmap(newwidth, newheight, bitmap.PixelFormat);
Graphics graphics = Graphics.FromImage(resized);
graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
graphics.InterpolationMode =
System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
graphics.DrawImage(bitmap, 0, 0, newwidth, newheight);
bitmap.Dispose();
bitmap = resized;
}
UploadData = OpenJPEG.EncodeFromImage(bitmap, false);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString() + " SL Image Upload ");
return null;
}
return UploadData;
}
private static bool IsPowerOfTwo(uint n)
{
return (n & (n - 1)) == 0 && n != 0;
}
}
}
@@ -0,0 +1,89 @@
using System;
using System.IO;
using System.Collections.Generic;
namespace OpenMetaverse.TestClient
{
/// <summary>
/// Example of how to put a new script in your inventory
/// </summary>
public class UploadScriptCommand : Command
{
/// <summary>
/// The default constructor for TestClient commands
/// </summary>
/// <param name="testClient"></param>
public UploadScriptCommand(TestClient testClient)
{
Name = "uploadscript";
Description = "Upload a local .lsl file file into your inventory.";
Category = CommandCategory.Inventory;
}
/// <summary>
/// The default override for TestClient commands
/// </summary>
/// <param name="args"></param>
/// <param name="fromAgentID"></param>
/// <returns></returns>
public override string Execute(string[] args, UUID fromAgentID)
{
if (args.Length < 1)
return "Usage: uploadscript filename.lsl";
string file = String.Empty;
for (int ct = 0; ct < args.Length; ct++)
file = String.Format("{0}{1} ", file, args[ct]);
file = file.TrimEnd();
if (!File.Exists(file))
return String.Format("Filename '{0}' does not exist", file);
string ret = String.Format("Filename: {0}", file);
try
{
using (StreamReader reader = new StreamReader(file))
{
string body = reader.ReadToEnd();
string desc = String.Format("{0} created by OpenMetaverse TestClient {1}", file, DateTime.Now);
// create the asset
Client.Inventory.RequestCreateItem(Client.Inventory.FindFolderForType(AssetType.LSLText), file, desc, AssetType.LSLText, UUID.Random(), InventoryType.LSL, PermissionMask.All,
delegate(bool success, InventoryItem item)
{
if (success)
// upload the asset
Client.Inventory.RequestUpdateScriptAgentInventory(EncodeScript(body), item.UUID, true, new InventoryManager.ScriptUpdatedCallback(delegate(bool uploadSuccess, string uploadStatus, bool compileSuccess, List<string> compileMessages, UUID itemid, UUID assetid)
{
if (uploadSuccess)
ret += String.Format(" Script successfully uploaded, ItemID {0} AssetID {1}", itemid, assetid);
if (compileSuccess)
ret += " compilation successful";
}));
});
}
return ret;
}
catch (System.Exception e)
{
Logger.Log(e.ToString(), Helpers.LogLevel.Error, Client);
return String.Format("Error creating script for {0}", ret);
}
}
/// <summary>
/// Encodes the script text for uploading
/// </summary>
/// <param name="body"></param>
public static byte[] EncodeScript(string body)
{
// Assume this is a string, add 1 for the null terminator ?
byte[] stringBytes = System.Text.Encoding.UTF8.GetBytes(body);
byte[] assetData = new byte[stringBytes.Length]; //+ 1];
Array.Copy(stringBytes, 0, assetData, 0, stringBytes.Length);
return assetData;
}
}
}
@@ -0,0 +1,78 @@
using System;
using System.Collections.Generic;
using OpenMetaverse;
using OpenMetaverse.Packets;
using OpenMetaverse.Assets;
namespace OpenMetaverse.TestClient
{
public class ViewNotecardCommand : Command
{
/// <summary>
/// TestClient command to download and display a notecard asset
/// </summary>
/// <param name="testClient"></param>
public ViewNotecardCommand(TestClient testClient)
{
Name = "viewnote";
Description = "Downloads and displays a notecard asset";
Category = CommandCategory.Inventory;
}
/// <summary>
/// Exectute the command
/// </summary>
/// <param name="args"></param>
/// <param name="fromAgentID"></param>
/// <returns></returns>
public override string Execute(string[] args, UUID fromAgentID)
{
if (args.Length < 1)
{
return "Usage: viewnote [notecard asset uuid]";
}
UUID note;
if (!UUID.TryParse(args[0], out note))
{
return "First argument expected agent UUID.";
}
System.Threading.AutoResetEvent waitEvent = new System.Threading.AutoResetEvent(false);
System.Text.StringBuilder result = new System.Text.StringBuilder();
// verify asset is loaded in store
if (Client.Inventory.Store.Contains(note))
{
// retrieve asset from store
InventoryItem ii = (InventoryItem)Client.Inventory.Store[note];
// make request for asset
Client.Assets.RequestInventoryAsset(ii, true,
delegate(AssetDownload transfer, Asset asset)
{
if (transfer.Success)
{
result.AppendFormat("Raw Notecard Data: " + System.Environment.NewLine + " {0}", Utils.BytesToString(asset.AssetData));
waitEvent.Set();
}
}
);
// wait for reply or timeout
if (!waitEvent.WaitOne(10000, false))
{
result.Append("Timeout waiting for notecard to download.");
}
}
else
{
result.Append("Cannot find asset in inventory store, use 'i' to populate store");
}
// return results
return result.ToString();
}
}
}
@@ -0,0 +1,78 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading;
using OpenMetaverse;
using OpenMetaverse.StructuredData;
namespace OpenMetaverse.TestClient
{
public class XferCommand : Command
{
const int FETCH_ASSET_TIMEOUT = 1000 * 10;
public XferCommand(TestClient testClient)
{
Name = "xfer";
Description = "Downloads the specified asset using the Xfer system. Usage: xfer [uuid]";
}
public override string Execute(string[] args, UUID fromAgentID)
{
UUID assetID;
if (args.Length != 1 || !UUID.TryParse(args[0], out assetID))
return "Usage: xfer [uuid]";
string filename;
byte[] assetData = RequestXfer(assetID, AssetType.Object, out filename);
if (assetData != null)
{
try
{
File.WriteAllBytes(filename, assetData);
return "Saved asset " + filename;
}
catch (Exception ex)
{
return "Failed to save asset " + filename + ": " + ex.Message;
}
}
else
{
return "Failed to xfer asset " + assetID;
}
}
byte[] RequestXfer(UUID assetID, AssetType type, out string filename)
{
AutoResetEvent xferEvent = new AutoResetEvent(false);
ulong xferID = 0;
byte[] data = null;
EventHandler<XferReceivedEventArgs> xferCallback =
delegate(object sender, XferReceivedEventArgs e)
{
if (e.Xfer.XferID == xferID)
{
if (e.Xfer.Success)
data = e.Xfer.AssetData;
xferEvent.Set();
}
};
Client.Assets.XferReceived += xferCallback;
filename = assetID + ".asset";
xferID = Client.Assets.RequestAssetXfer(filename, false, true, assetID, type, false);
xferEvent.WaitOne(FETCH_ASSET_TIMEOUT, false);
Client.Assets.XferReceived -= xferCallback;
return data;
}
}
}
@@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using System.Text;
using OpenMetaverse;
namespace OpenMetaverse.TestClient
{
/// <summary>
/// Display a list of all agent locations in a specified region
/// </summary>
public class AgentLocationsCommand : Command
{
public AgentLocationsCommand(TestClient testClient)
{
Name = "agentlocations";
Description = "Downloads all of the agent locations in a specified region. Usage: agentlocations [regionhandle]";
Category = CommandCategory.Simulator;
}
public override string Execute(string[] args, UUID fromAgentID)
{
ulong regionHandle;
if (args.Length == 0)
regionHandle = Client.Network.CurrentSim.Handle;
else if (!(args.Length == 1 && UInt64.TryParse(args[0], out regionHandle)))
return "Usage: agentlocations [regionhandle]";
List<MapItem> items = Client.Grid.MapItems(regionHandle, GridItemType.AgentLocations,
GridLayerType.Objects, 1000 * 20);
if (items != null)
{
StringBuilder ret = new StringBuilder();
ret.AppendLine("Agent locations:");
for (int i = 0; i < items.Count; i++)
{
MapAgentLocation location = (MapAgentLocation)items[i];
ret.AppendLine(String.Format("{0} avatar(s) at {1},{2}", location.AvatarCount, location.LocalX,
location.LocalY));
}
return ret.ToString();
}
else
{
return "Failed to fetch agent locations";
}
}
}
}
@@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using System.Text;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace OpenMetaverse.TestClient
{
public class FindSimCommand : Command
{
public FindSimCommand(TestClient testClient)
{
Name = "findsim";
Description = "Searches for a simulator and returns information about it. Usage: findsim [Simulator Name]";
}
public override string Execute(string[] args, UUID fromAgentID)
{
if (args.Length < 1)
return "Usage: findsim [Simulator Name]";
// Build the simulator name from the args list
string simName = string.Empty;
for (int i = 0; i < args.Length; i++)
simName += args[i] + " ";
simName = simName.TrimEnd().ToLower();
//if (!GridDataCached[Client])
//{
// Client.Grid.RequestAllSims(GridManager.MapLayerType.Objects);
// System.Threading.Thread.Sleep(5000);
// GridDataCached[Client] = true;
//}
GridRegion region;
if (Client.Grid.GetGridRegion(simName, GridLayerType.Objects, out region))
return String.Format("{0}: handle={1} ({2},{3})", region.Name, region.RegionHandle, region.X, region.Y);
else
return "Lookup of " + simName + " failed";
}
}
}
@@ -0,0 +1,30 @@
using System;
using OpenMetaverse;
namespace OpenMetaverse.TestClient
{
public class GridLayerCommand : Command
{
public GridLayerCommand(TestClient testClient)
{
Name = "gridlayer";
Description = "Downloads all of the layer chunks for the grid object map";
Category = CommandCategory.Simulator;
testClient.Grid.GridLayer += Grid_GridLayer;
}
void Grid_GridLayer(object sender, GridLayerEventArgs e)
{
Console.WriteLine(String.Format("Layer({0}) Bottom: {1} Left: {2} Top: {3} Right: {4}",
e.Layer.ImageID.ToString(), e.Layer.Bottom, e.Layer.Left, e.Layer.Top, e.Layer.Right));
}
public override string Execute(string[] args, UUID fromAgentID)
{
Client.Grid.RequestMapLayer(GridLayerType.Objects);
return "Sent.";
}
}
}
@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Text;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace OpenMetaverse.TestClient
{
public class GridMapCommand : Command
{
public GridMapCommand(TestClient testClient)
{
Name = "gridmap";
Description = "Downloads all visible information about the grid map";
Category = CommandCategory.Simulator;
}
public override string Execute(string[] args, UUID fromAgentID)
{
//if (args.Length < 1)
// return "";
Client.Grid.RequestMainlandSims(GridLayerType.Objects);
return "Sent.";
}
}
}
@@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using OpenMetaverse;
namespace OpenMetaverse.TestClient
{
public class ParcelDetailsCommand : Command
{
public ParcelDetailsCommand(TestClient testClient)
{
Name = "parceldetails";
Description = "Displays parcel details from the ParcelTracker dictionary. Usage: parceldetails parcelID";
Category = CommandCategory.Parcel;
}
public override string Execute(string[] args, UUID fromAgentID)
{
if (args.Length < 1)
return "Usage: parceldetails parcelID (use parcelinfo to get ID)";
int parcelID;
Parcel parcel;
// test argument that is is a valid integer, then verify we have that parcel data stored in the dictionary
if (Int32.TryParse(args[0], out parcelID) && Client.Network.CurrentSim.Parcels.TryGetValue(parcelID, out parcel))
{
// this request will update the parcels dictionary
Client.Parcels.RequestParcelProperties(Client.Network.CurrentSim, parcelID, 0);
// Use reflection to dynamically get the fields from the Parcel struct
Type t = parcel.GetType();
System.Reflection.FieldInfo[] fields = t.GetFields(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
StringBuilder sb = new StringBuilder();
foreach (System.Reflection.FieldInfo field in fields)
{
sb.AppendFormat("{0} = {1}" + System.Environment.NewLine, field.Name, field.GetValue(parcel));
}
return sb.ToString();
}
else
{
return String.Format("Unable to find Parcel {0} in Parcels Dictionary, Did you run parcelinfo to populate the dictionary first?", args[0]);
}
}
}
}
@@ -0,0 +1,64 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using OpenMetaverse;
namespace OpenMetaverse.TestClient
{
public class ParcelInfoCommand : Command
{
private AutoResetEvent ParcelsDownloaded = new AutoResetEvent(false);
public ParcelInfoCommand(TestClient testClient)
{
Name = "parcelinfo";
Description = "Prints out info about all the parcels in this simulator";
Category = CommandCategory.Parcel;
testClient.Network.Disconnected += Network_OnDisconnected;
}
public override string Execute(string[] args, UUID fromAgentID)
{
StringBuilder sb = new StringBuilder();
string result;
EventHandler<SimParcelsDownloadedEventArgs> del = delegate(object sender, SimParcelsDownloadedEventArgs e)
{
ParcelsDownloaded.Set();
};
ParcelsDownloaded.Reset();
Client.Parcels.SimParcelsDownloaded += del;
Client.Parcels.RequestAllSimParcels(Client.Network.CurrentSim);
if (Client.Network.CurrentSim.IsParcelMapFull())
ParcelsDownloaded.Set();
if (ParcelsDownloaded.WaitOne(30000, false) && Client.Network.Connected)
{
sb.AppendFormat("Downloaded {0} Parcels in {1} " + System.Environment.NewLine,
Client.Network.CurrentSim.Parcels.Count, Client.Network.CurrentSim.Name);
Client.Network.CurrentSim.Parcels.ForEach(delegate(Parcel parcel)
{
sb.AppendFormat("Parcel[{0}]: Name: \"{1}\", Description: \"{2}\" ACLBlacklist Count: {3}, ACLWhiteList Count: {5} Traffic: {4}" + System.Environment.NewLine,
parcel.LocalID, parcel.Name, parcel.Desc, parcel.AccessBlackList.Count, parcel.Dwell, parcel.AccessWhiteList.Count);
});
result = sb.ToString();
}
else
result = "Failed to retrieve information on all the simulator parcels";
Client.Parcels.SimParcelsDownloaded -= del;
return result;
}
void Network_OnDisconnected(object sender, DisconnectedEventArgs e)
{
ParcelsDownloaded.Set();
}
}
}
@@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using OpenMetaverse;
namespace OpenMetaverse.TestClient
{
public class ParcelPrimOwnersCommand : Command
{
public ParcelPrimOwnersCommand(TestClient testClient)
{
Name = "primowners";
Description = "Displays a list of prim owners and prim counts on a parcel. Usage: primowners parcelID";
Category = CommandCategory.Parcel;
}
public override string Execute(string[] args, UUID fromAgentID)
{
if (args.Length < 1)
return "Usage: primowners parcelID (use parcelinfo to get ID)";
int parcelID;
Parcel parcel;
StringBuilder result = new StringBuilder();
// test argument that is is a valid integer, then verify we have that parcel data stored in the dictionary
if (Int32.TryParse(args[0], out parcelID) && Client.Network.CurrentSim.Parcels.TryGetValue(parcelID, out parcel))
{
AutoResetEvent wait = new AutoResetEvent(false);
EventHandler<ParcelObjectOwnersReplyEventArgs> callback = delegate(object sender, ParcelObjectOwnersReplyEventArgs e)
{
for (int i = 0; i < e.PrimOwners.Count; i++)
{
result.AppendFormat("Owner: {0} Count: {1}" + System.Environment.NewLine, e.PrimOwners[i].OwnerID, e.PrimOwners[i].Count);
wait.Set();
}
};
Client.Parcels.ParcelObjectOwnersReply += callback;
Client.Parcels.RequestObjectOwners(Client.Network.CurrentSim, parcelID);
if (!wait.WaitOne(10000, false))
{
result.AppendLine("Timed out waiting for packet.");
}
Client.Parcels.ParcelObjectOwnersReply -= callback;
return result.ToString();
}
else
{
return String.Format("Unable to find Parcel {0} in Parcels Dictionary, Did you run parcelinfo to populate the dictionary first?", args[0]);
}
}
}
}
@@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using OpenMetaverse;
namespace OpenMetaverse.TestClient
{
public class ParcelSelectObjectsCommand : Command
{
public ParcelSelectObjectsCommand(TestClient testClient)
{
Name = "selectobjects";
Description = "Displays a list of prim localIDs on a given parcel with a specific owner. Usage: selectobjects parcelID OwnerUUID";
Category = CommandCategory.Parcel;
}
public override string Execute(string[] args, UUID fromAgentID)
{
if (args.Length < 2)
return "Usage: selectobjects parcelID OwnerUUID (use parcelinfo to get ID, use parcelprimowners to get ownerUUID)";
int parcelID;
UUID ownerUUID;
int counter = 0;
StringBuilder result = new StringBuilder();
// test argument that is is a valid integer, then verify we have that parcel data stored in the dictionary
if (Int32.TryParse(args[0], out parcelID)
&& UUID.TryParse(args[1], out ownerUUID))
{
AutoResetEvent wait = new AutoResetEvent(false);
EventHandler<ForceSelectObjectsReplyEventArgs> callback = delegate(object sender, ForceSelectObjectsReplyEventArgs e)
{
for (int i = 0; i < e.ObjectIDs.Count; i++)
{
result.Append(e.ObjectIDs[i].ToString() + " ");
counter++;
}
if (e.ObjectIDs.Count < 251)
wait.Set();
};
Client.Parcels.ForceSelectObjectsReply += callback;
Client.Parcels.RequestSelectObjects(parcelID, (ObjectReturnType)16, ownerUUID);
Client.Parcels.RequestObjectOwners(Client.Network.CurrentSim, parcelID);
if (!wait.WaitOne(30000, false))
{
result.AppendLine("Timed out waiting for packet.");
}
Client.Parcels.ForceSelectObjectsReply -= callback;
result.AppendLine("Found a total of " + counter + " Objects");
return result.ToString();
}
else
{
return String.Format("Unable to find Parcel {0} in Parcels Dictionary, Did you run parcelinfo to populate the dictionary first?", args[0]);
}
}
}
}
@@ -0,0 +1,28 @@
using System;
using OpenMetaverse;
namespace OpenMetaverse.TestClient
{
public class WindCommand : Command
{
public WindCommand(TestClient testClient)
{
Name = "wind";
Description = "Displays current wind data";
Category = CommandCategory.Simulator;
}
public override string Execute(string[] args, UUID fromAgentID)
{
// Get the agent's current "patch" position, where each patch of
// wind data is a 16x16m square
Vector3 agentPos = Client.Self.SimPosition;
int xPos = (int)Utils.Clamp(agentPos.X, 0.0f, 255.0f) / 16;
int yPos = (int)Utils.Clamp(agentPos.Y, 0.0f, 255.0f) / 16;
Vector2 windSpeed = Client.Network.CurrentSim.WindSpeeds[yPos * 16 + xPos];
return "Local wind speed is " + windSpeed.ToString();
}
}
}
@@ -0,0 +1,53 @@
using System;
namespace OpenMetaverse.TestClient.Commands.Movement
{
class BackCommand : Command
{
public BackCommand(TestClient client)
{
Name = "back";
Description = "Sends the move back command to the server for a single packet or a given number of seconds. Usage: back [seconds]";
Category = CommandCategory.Movement;
}
public override string Execute(string[] args, UUID fromAgentID)
{
if (args.Length > 1)
return "Usage: back [seconds]";
if (args.Length == 0)
{
Client.Self.Movement.SendManualUpdate(AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG, Client.Self.Movement.Camera.Position,
Client.Self.Movement.Camera.AtAxis, Client.Self.Movement.Camera.LeftAxis, Client.Self.Movement.Camera.UpAxis,
Client.Self.Movement.BodyRotation, Client.Self.Movement.HeadRotation, Client.Self.Movement.Camera.Far, AgentFlags.None,
AgentState.None, true);
}
else
{
// Parse the number of seconds
int duration;
if (!Int32.TryParse(args[0], out duration))
return "Usage: back [seconds]";
// Convert to milliseconds
duration *= 1000;
int start = Environment.TickCount;
Client.Self.Movement.AtNeg = true;
while (Environment.TickCount - start < duration)
{
// The movement timer will do this automatically, but we do it here as an example
// and to make sure updates are being sent out fast enough
Client.Self.Movement.SendUpdate(false);
System.Threading.Thread.Sleep(100);
}
Client.Self.Movement.AtNeg = false;
}
return "Moved backward";
}
}
}
@@ -0,0 +1,34 @@
using System;
using OpenMetaverse;
namespace OpenMetaverse.TestClient
{
public class CrouchCommand : Command
{
public CrouchCommand(TestClient testClient)
{
Name = "crouch";
Description = "Starts or stops crouching. Usage: crouch [start/stop]";
Category = CommandCategory.Movement;
}
public override string Execute(string[] args, UUID fromAgentID)
{
bool start = true;
if (args.Length == 1 && args[0].ToLower() == "stop")
start = false;
if (start)
{
Client.Self.Crouch(true);
return "Started crouching";
}
else
{
Client.Self.Crouch(false);
return "Stopped crouching";
}
}
}
}
@@ -0,0 +1,34 @@
using System;
using OpenMetaverse;
namespace OpenMetaverse.TestClient
{
public class FlyCommand : Command
{
public FlyCommand(TestClient testClient)
{
Name = "fly";
Description = "Starts or stops flying. Usage: fly [start/stop]";
Category = CommandCategory.Movement;
}
public override string Execute(string[] args, UUID fromAgentID)
{
bool start = true;
if (args.Length == 1 && args[0].ToLower() == "stop")
start = false;
if (start)
{
Client.Self.Fly(true);
return "Started flying";
}
else
{
Client.Self.Fly(false);
return "Stopped flying";
}
}
}
}
@@ -0,0 +1,164 @@
using System;
namespace OpenMetaverse.TestClient.Commands.Movement
{
class FlyToCommand : Command
{
Vector3 myPos = new Vector3();
Vector2 myPos0 = new Vector2();
Vector3 target = new Vector3();
Vector2 target0 = new Vector2();
float diff, olddiff, saveolddiff;
int startTime = 0;
int duration = 10000;
bool running = false;
public FlyToCommand(TestClient Client)
{
Name = "FlyTo";
Description = "Fly the avatar toward the specified position for a maximum of seconds. Usage: FlyTo x y z [seconds]";
Category = CommandCategory.Movement;
}
public override string Execute(string[] args, UUID fromAgentID)
{
if (args.Length > 4 || args.Length < 3)
return "Usage: FlyTo x y z [seconds]";
if (!float.TryParse(args[0], out target.X) ||
!float.TryParse(args[1], out target.Y) ||
!float.TryParse(args[2], out target.Z))
{
return "Usage: FlyTo x y z [seconds]";
}
if (running)
return "Already in progress, wait for the previous FlyTo to finish";
running = true;
// Subscribe to terse update events while this command is running
Client.Objects.TerseObjectUpdate += Objects_OnObjectUpdated;
target0.X = target.X;
target0.Y = target.Y;
if (args.Length == 4 && Int32.TryParse(args[3], out duration))
duration *= 1000;
startTime = Environment.TickCount;
Client.Self.Movement.Fly = true;
Client.Self.Movement.AtPos = true;
Client.Self.Movement.AtNeg = false;
ZMovement();
Client.Self.Movement.TurnToward(target);
return string.Format("flying to {0} in {1} seconds", target.ToString(), duration / 1000);
}
private void Objects_OnObjectUpdated(object sender, TerseObjectUpdateEventArgs e)
{
if (startTime == 0) return;
if (e.Update.LocalID == Client.Self.LocalID)
{
XYMovement();
ZMovement();
if (Client.Self.Movement.AtPos || Client.Self.Movement.AtNeg)
{
Client.Self.Movement.TurnToward(target);
Debug("Flyxy ");
}
else if (Client.Self.Movement.UpPos || Client.Self.Movement.UpNeg)
{
Client.Self.Movement.TurnToward(target);
//Client.Self.Movement.SendUpdate(false);
Debug("Fly z ");
}
else if (Vector3.Distance(target, Client.Self.SimPosition) <= 2.0)
{
EndFlyto();
Debug("At Target");
}
}
if (Environment.TickCount - startTime > duration)
{
EndFlyto();
Debug("End Flyto");
}
}
private bool XYMovement()
{
bool res = false;
myPos = Client.Self.SimPosition;
myPos0.X = myPos.X;
myPos0.Y = myPos.Y;
diff = Vector2.Distance(target0, myPos0);
Vector2 vvel = new Vector2(Client.Self.Velocity.X, Client.Self.Velocity.Y);
float vel = vvel.Length();
if (diff >= 10.0)
{
Client.Self.Movement.AtPos = true;
res = true;
}
else if (diff >= 2 && vel < 5)
{
Client.Self.Movement.AtPos = true;
}
else
{
Client.Self.Movement.AtPos = false;
Client.Self.Movement.AtNeg = false;
}
saveolddiff = olddiff;
olddiff = diff;
return res;
}
private void ZMovement()
{
Client.Self.Movement.UpPos = false;
Client.Self.Movement.UpNeg = false;
float diffz = (target.Z - Client.Self.SimPosition.Z);
if (diffz >= 20.0)
Client.Self.Movement.UpPos = true;
else if (diffz <= -20.0)
Client.Self.Movement.UpNeg = true;
else if (diffz >= +5.0 && Client.Self.Velocity.Z < +4.0)
Client.Self.Movement.UpPos = true;
else if (diffz <= -5.0 && Client.Self.Velocity.Z > -4.0)
Client.Self.Movement.UpNeg = true;
else if (diffz >= +2.0 && Client.Self.Velocity.Z < +1.0)
Client.Self.Movement.UpPos = true;
else if (diffz <= -2.0 && Client.Self.Velocity.Z > -1.0)
Client.Self.Movement.UpNeg = true;
}
private void EndFlyto()
{
// Unsubscribe from terse update events
Client.Objects.TerseObjectUpdate -= Objects_OnObjectUpdated;
startTime = 0;
Client.Self.Movement.AtPos = false;
Client.Self.Movement.AtNeg = false;
Client.Self.Movement.UpPos = false;
Client.Self.Movement.UpNeg = false;
Client.Self.Movement.SendUpdate(false);
running = false;
}
[System.Diagnostics.Conditional("DEBUG")]
private void Debug(string x)
{
Console.WriteLine(x + " {0,3:##0} {1,3:##0} {2,3:##0} diff {3,5:##0.0} olddiff {4,5:##0.0} At:{5,5} {6,5} Up:{7,5} {8,5} v: {9} w: {10}",
myPos.X, myPos.Y, myPos.Z, diff, saveolddiff,
Client.Self.Movement.AtPos, Client.Self.Movement.AtNeg, Client.Self.Movement.UpPos, Client.Self.Movement.UpNeg,
Client.Self.Velocity.ToString(), Client.Self.AngularVelocity.ToString());
}
}
}
@@ -0,0 +1,142 @@
using System;
using System.Collections.Generic;
using System.Text;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace OpenMetaverse.TestClient
{
public class FollowCommand: Command
{
const float DISTANCE_BUFFER = 3.0f;
uint targetLocalID = 0;
public FollowCommand(TestClient testClient)
{
Name = "follow";
Description = "Follow another avatar. Usage: follow [FirstName LastName]/off.";
Category = CommandCategory.Movement;
testClient.Network.RegisterCallback(PacketType.AlertMessage, AlertMessageHandler);
}
public override string Execute(string[] args, UUID fromAgentID)
{
// Construct the target name from the passed arguments
string target = String.Empty;
for (int ct = 0; ct < args.Length; ct++)
target = target + args[ct] + " ";
target = target.TrimEnd();
if (target.Length == 0 || target == "off")
{
Active = false;
targetLocalID = 0;
Client.Self.AutoPilotCancel();
return "Following is off";
}
else
{
if (Follow(target))
return "Following " + target;
else
return "Unable to follow " + target + ". Client may not be able to see that avatar.";
}
}
bool Follow(string name)
{
lock (Client.Network.Simulators)
{
for (int i = 0; i < Client.Network.Simulators.Count; i++)
{
Avatar target = Client.Network.Simulators[i].ObjectsAvatars.Find(
delegate(Avatar avatar)
{
return avatar.Name == name;
}
);
if (target != null)
{
targetLocalID = target.LocalID;
Active = true;
return true;
}
}
}
if (Active)
{
Client.Self.AutoPilotCancel();
Active = false;
}
return false;
}
public override void Think()
{
if (Active)
{
// Find the target position
lock (Client.Network.Simulators)
{
for (int i = 0; i < Client.Network.Simulators.Count; i++)
{
Avatar targetAv;
if (Client.Network.Simulators[i].ObjectsAvatars.TryGetValue(targetLocalID, out targetAv))
{
float distance = 0.0f;
if (Client.Network.Simulators[i] == Client.Network.CurrentSim)
{
distance = Vector3.Distance(targetAv.Position, Client.Self.SimPosition);
}
else
{
// FIXME: Calculate global distances
}
if (distance > DISTANCE_BUFFER)
{
uint regionX, regionY;
Utils.LongToUInts(Client.Network.Simulators[i].Handle, out regionX, out regionY);
double xTarget = (double)targetAv.Position.X + (double)regionX;
double yTarget = (double)targetAv.Position.Y + (double)regionY;
double zTarget = targetAv.Position.Z - 2f;
Logger.DebugLog(String.Format("[Autopilot] {0} meters away from the target, starting autopilot to <{1},{2},{3}>",
distance, xTarget, yTarget, zTarget), Client);
Client.Self.AutoPilot(xTarget, yTarget, zTarget);
}
else
{
// We are in range of the target and moving, stop moving
Client.Self.AutoPilotCancel();
}
}
}
}
}
base.Think();
}
private void AlertMessageHandler(object sender, PacketReceivedEventArgs e)
{
Packet packet = e.Packet;
AlertMessagePacket alert = (AlertMessagePacket)packet;
string message = Utils.BytesToString(alert.AlertData.Message);
if (message.Contains("Autopilot cancel"))
{
Logger.Log("FollowCommand: " + message, Helpers.LogLevel.Info, Client);
}
}
}
}
@@ -0,0 +1,53 @@
using System;
namespace OpenMetaverse.TestClient.Commands.Movement
{
class ForwardCommand : Command
{
public ForwardCommand(TestClient client)
{
Name = "forward";
Description = "Sends the move forward command to the server for a single packet or a given number of seconds. Usage: forward [seconds]";
Category = CommandCategory.Movement;
}
public override string Execute(string[] args, UUID fromAgentID)
{
if (args.Length > 1)
return "Usage: forward [seconds]";
if (args.Length == 0)
{
Client.Self.Movement.SendManualUpdate(AgentManager.ControlFlags.AGENT_CONTROL_AT_POS, Client.Self.Movement.Camera.Position,
Client.Self.Movement.Camera.AtAxis, Client.Self.Movement.Camera.LeftAxis, Client.Self.Movement.Camera.UpAxis,
Client.Self.Movement.BodyRotation, Client.Self.Movement.HeadRotation, Client.Self.Movement.Camera.Far, AgentFlags.None,
AgentState.None, true);
}
else
{
// Parse the number of seconds
int duration;
if (!Int32.TryParse(args[0], out duration))
return "Usage: forward [seconds]";
// Convert to milliseconds
duration *= 1000;
int start = Environment.TickCount;
Client.Self.Movement.AtPos = true;
while (Environment.TickCount - start < duration)
{
// The movement timer will do this automatically, but we do it here as an example
// and to make sure updates are being sent out fast enough
Client.Self.Movement.SendUpdate(false);
System.Threading.Thread.Sleep(100);
}
Client.Self.Movement.AtPos = false;
}
return "Moved forward";
}
}
}
@@ -0,0 +1,24 @@
using System;
using OpenMetaverse;
namespace OpenMetaverse.TestClient
{
public class GoHomeCommand : Command
{
public GoHomeCommand(TestClient testClient)
{
Name = "gohome";
Description = "Teleports home";
Category = CommandCategory.Movement;
}
public override string Execute(string[] args, UUID fromAgentID)
{
if ( Client.Self.GoHome() ) {
return "Teleport Home Succesful";
} else {
return "Teleport Home Failed";
}
}
}
}
@@ -0,0 +1,51 @@
using System;
using System.Collections.Generic;
using System.Text;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace OpenMetaverse.TestClient
{
public class GotoCommand: Command
{
public GotoCommand(TestClient testClient)
{
Name = "goto";
Description = "Teleport to a location (e.g. \"goto Hooper/100/100/30\")";
Category = CommandCategory.Movement;
}
public override string Execute(string[] args, UUID fromAgentID)
{
if (args.Length < 1)
return "Usage: goto sim/x/y/z";
string destination = String.Empty;
// Handle multi-word sim names by combining the arguments
foreach (string arg in args)
{
destination += arg + " ";
}
destination = destination.Trim();
string[] tokens = destination.Split(new char[] { '/' });
if (tokens.Length != 4)
return "Usage: goto sim/x/y/z";
string sim = tokens[0];
float x, y, z;
if (!float.TryParse(tokens[1], out x) ||
!float.TryParse(tokens[2], out y) ||
!float.TryParse(tokens[3], out z))
{
return "Usage: goto sim/x/y/z";
}
if (Client.Self.Teleport(sim, new Vector3(x, y, z)))
return "Teleported to " + Client.Network.CurrentSim;
else
return "Teleport failed: " + Client.Self.TeleportMessage;
}
}
}
@@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using System.Text;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace OpenMetaverse.TestClient
{
public class GotoLandmarkCommand : Command
{
public GotoLandmarkCommand(TestClient testClient)
{
Name = "goto_landmark";
Description = "Teleports to a Landmark. Usage: goto_landmark [UUID]";
Category = CommandCategory.Movement;
}
public override string Execute(string[] args, UUID fromAgentID)
{
if (args.Length < 1)
{
return "Usage: goto_landmark [UUID]";
}
UUID landmark = new UUID();
if (!UUID.TryParse(args[0], out landmark))
{
return "Invalid LLUID";
}
else
{
Console.WriteLine("Teleporting to " + landmark.ToString());
}
if (Client.Self.Teleport(landmark))
{
return "Teleport Succesful";
}
else
{
return "Teleport Failed";
}
}
}
}
@@ -0,0 +1,21 @@
using System;
using OpenMetaverse;
namespace OpenMetaverse.TestClient
{
public class JumpCommand: Command
{
public JumpCommand(TestClient testClient)
{
Name = "jump";
Description = "Jumps or flies up";
Category = CommandCategory.Movement;
}
public override string Execute(string[] args, UUID fromAgentID)
{
Client.Self.Jump(true);
return "Jumped";
}
}
}
@@ -0,0 +1,53 @@
using System;
namespace OpenMetaverse.TestClient.Commands.Movement
{
class LeftCommand : Command
{
public LeftCommand(TestClient client)
{
Name = "left";
Description = "Sends the move left command to the server for a single packet or a given number of seconds. Usage: left [seconds]";
Category = CommandCategory.Movement;
}
public override string Execute(string[] args, UUID fromAgentID)
{
if (args.Length > 1)
return "Usage: left [seconds]";
if (args.Length == 0)
{
Client.Self.Movement.SendManualUpdate(AgentManager.ControlFlags.AGENT_CONTROL_LEFT_POS, Client.Self.Movement.Camera.Position,
Client.Self.Movement.Camera.AtAxis, Client.Self.Movement.Camera.LeftAxis, Client.Self.Movement.Camera.UpAxis,
Client.Self.Movement.BodyRotation, Client.Self.Movement.HeadRotation, Client.Self.Movement.Camera.Far, AgentFlags.None,
AgentState.None, true);
}
else
{
// Parse the number of seconds
int duration;
if (!Int32.TryParse(args[0], out duration))
return "Usage: left [seconds]";
// Convert to milliseconds
duration *= 1000;
int start = Environment.TickCount;
Client.Self.Movement.LeftPos = true;
while (Environment.TickCount - start < duration)
{
// The movement timer will do this automatically, but we do it here as an example
// and to make sure updates are being sent out fast enough
Client.Self.Movement.SendUpdate(false);
System.Threading.Thread.Sleep(100);
}
Client.Self.Movement.LeftPos = false;
}
return "Moved left";
}
}
}
@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Text;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace OpenMetaverse.TestClient
{
public class LocationCommand: Command
{
public LocationCommand(TestClient testClient)
{
Name = "location";
Description = "Show current location of avatar.";
Category = CommandCategory.Movement;
}
public override string Execute(string[] args, UUID fromAgentID)
{
return "CurrentSim: '" + Client.Network.CurrentSim.ToString() + "' Position: " +
Client.Self.SimPosition.ToString();
}
}
}
@@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace OpenMetaverse.TestClient.Commands.Movement
{
class MovetoCommand : Command
{
public MovetoCommand(TestClient client)
{
Name = "moveto";
Description = "Moves the avatar to the specified global position using simulator autopilot. Usage: moveto x y z";
Category = CommandCategory.Movement;
}
public override string Execute(string[] args, UUID fromAgentID)
{
if (args.Length != 3)
return "Usage: moveto x y z";
uint regionX, regionY;
Utils.LongToUInts(Client.Network.CurrentSim.Handle, out regionX, out regionY);
double x, y, z;
if (!Double.TryParse(args[0], out x) ||
!Double.TryParse(args[1], out y) ||
!Double.TryParse(args[2], out z))
{
return "Usage: moveto x y z";
}
// Convert the local coordinates to global ones by adding the region handle parts to x and y
x += (double)regionX;
y += (double)regionY;
Client.Self.AutoPilot(x, y, z);
return String.Format("Attempting to move to <{0},{1},{2}>", x, y, z);
}
}
}
@@ -0,0 +1,53 @@
using System;
namespace OpenMetaverse.TestClient.Commands.Movement
{
class RightCommand : Command
{
public RightCommand(TestClient client)
{
Name = "right";
Description = "Sends the move right command to the server for a single packet or a given number of seconds. Usage: right [seconds]";
Category = CommandCategory.Movement;
}
public override string Execute(string[] args, UUID fromAgentID)
{
if (args.Length > 1)
return "Usage: right [seconds]";
if (args.Length == 0)
{
Client.Self.Movement.SendManualUpdate(AgentManager.ControlFlags.AGENT_CONTROL_LEFT_NEG, Client.Self.Movement.Camera.Position,
Client.Self.Movement.Camera.AtAxis, Client.Self.Movement.Camera.LeftAxis, Client.Self.Movement.Camera.UpAxis,
Client.Self.Movement.BodyRotation, Client.Self.Movement.HeadRotation, Client.Self.Movement.Camera.Far, AgentFlags.None,
AgentState.None, true);
}
else
{
// Parse the number of seconds
int duration;
if (!Int32.TryParse(args[0], out duration))
return "Usage: right [seconds]";
// Convert to milliseconds
duration *= 1000;
int start = Environment.TickCount;
Client.Self.Movement.LeftNeg = true;
while (Environment.TickCount - start < duration)
{
// The movement timer will do this automatically, but we do it here as an example
// and to make sure updates are being sent out fast enough
Client.Self.Movement.SendUpdate(false);
System.Threading.Thread.Sleep(100);
}
Client.Self.Movement.LeftNeg = false;
}
return "Moved right";
}
}
}
@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Text;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace OpenMetaverse.TestClient
{
public class SetHomeCommand : Command
{
public SetHomeCommand(TestClient testClient)
{
Name = "sethome";
Description = "Sets home to the current location.";
Category = CommandCategory.Movement;
}
public override string Execute(string[] args, UUID fromAgentID)
{
Client.Self.SetHome();
return "Home Set";
}
}
}
@@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.Text;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace OpenMetaverse.TestClient
{
public class SitCommand: Command
{
public SitCommand(TestClient testClient)
{
Name = "sit";
Description = "Attempt to sit on the closest prim";
Category = CommandCategory.Movement;
}
public override string Execute(string[] args, UUID fromAgentID)
{
Primitive closest = null;
double closestDistance = Double.MaxValue;
Client.Network.CurrentSim.ObjectsPrimitives.ForEach(
delegate(Primitive prim)
{
float distance = Vector3.Distance(Client.Self.SimPosition, prim.Position);
if (closest == null || distance < closestDistance)
{
closest = prim;
closestDistance = distance;
}
}
);
if (closest != null)
{
Client.Self.RequestSit(closest.ID, Vector3.Zero);
Client.Self.Sit();
return "Sat on " + closest.ID + " (" + closest.LocalID + "). Distance: " + closestDistance;
}
else
{
return "Couldn't find a nearby prim to sit on";
}
}
}
}
@@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;
using System.Text;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace OpenMetaverse.TestClient
{
public class SitOnCommand : Command
{
public SitOnCommand(TestClient testClient)
{
Name = "siton";
Description = "Attempt to sit on a particular prim, with specified UUID";
Category = CommandCategory.Movement;
}
public override string Execute(string[] args, UUID fromAgentID)
{
if (args.Length != 1)
return "Usage: siton UUID";
UUID target;
if (UUID.TryParse(args[0], out target))
{
Primitive targetPrim = Client.Network.CurrentSim.ObjectsPrimitives.Find(
delegate(Primitive prim)
{
return prim.ID == target;
}
);
if (targetPrim != null)
{
Client.Self.RequestSit(targetPrim.ID, Vector3.Zero);
Client.Self.Sit();
return "Requested to sit on prim " + targetPrim.ID.ToString() +
" (" + targetPrim.LocalID + ")";
}
}
return "Couldn't find a prim to sit on with UUID " + args[0];
}
}
}
@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Text;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace OpenMetaverse.TestClient
{
public class StandCommand: Command
{
public StandCommand(TestClient testClient)
{
Name = "stand";
Description = "Stand";
Category = CommandCategory.Movement;
}
public override string Execute(string[] args, UUID fromAgentID)
{
Client.Self.Stand();
return "Standing up.";
}
}
}
@@ -0,0 +1,58 @@
/*
* Copyright (c) 2006-2014, openmetaverse.org
* All rights reserved.
*
* - 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.
* - Neither the name of the openmetaverse.org 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR 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;
namespace OpenMetaverse.TestClient.Commands.Movement
{
class TurnToCommand : Command
{
public TurnToCommand(TestClient client)
{
Name = "turnto";
Description = "Turns the avatar looking to a specified point. Usage: turnto x y z";
Category = CommandCategory.Movement;
}
public override string Execute(string[] args, UUID fromAgentID)
{
if (args.Length != 3)
return "Usage: turnto x y z";
double x, y, z;
if (!Double.TryParse(args[0], out x) ||
!Double.TryParse(args[1], out y) ||
!Double.TryParse(args[2], out z))
{
return "Usage: turnto x y z";
}
Vector3 newDirection;
newDirection.X = (float)x;
newDirection.Y = (float)y;
newDirection.Z = (float)z;
Client.Self.Movement.TurnToward(newDirection);
Client.Self.Movement.SendUpdate(false);
return "Turned to ";
}
}
}
@@ -0,0 +1,170 @@
using System;
using System.Collections.Generic;
using System.Threading;
namespace OpenMetaverse.TestClient
{
public class ChangePermsCommand : Command
{
AutoResetEvent GotPermissionsEvent = new AutoResetEvent(false);
Dictionary<UUID, Primitive> Objects = new Dictionary<UUID, Primitive>();
PermissionMask Perms = PermissionMask.None;
private bool PermsSent;
private int PermCount;
public ChangePermsCommand(TestClient testClient)
{
testClient.Objects.ObjectProperties += new EventHandler<ObjectPropertiesEventArgs>(Objects_OnObjectProperties);
Name = "changeperms";
Description = "Recursively changes all of the permissions for child and task inventory objects. Usage prim-uuid [copy] [mod] [xfer]";
Category = CommandCategory.Objects;
}
public override string Execute(string[] args, UUID fromAgentID)
{
UUID rootID;
Primitive rootPrim;
List<Primitive> childPrims;
List<uint> localIDs = new List<uint>();
// Reset class-wide variables
PermsSent = false;
Objects.Clear();
Perms = PermissionMask.None;
PermCount = 0;
if (args.Length < 1 || args.Length > 4)
return "Usage prim-uuid [copy] [mod] [xfer]";
if (!UUID.TryParse(args[0], out rootID))
return "Usage prim-uuid [copy] [mod] [xfer]";
for (int i = 1; i < args.Length; i++)
{
switch (args[i].ToLower())
{
case "copy":
Perms |= PermissionMask.Copy;
break;
case "mod":
Perms |= PermissionMask.Modify;
break;
case "xfer":
Perms |= PermissionMask.Transfer;
break;
default:
return "Usage prim-uuid [copy] [mod] [xfer]";
}
}
Logger.DebugLog("Using PermissionMask: " + Perms.ToString(), Client);
// Find the requested prim
rootPrim = Client.Network.CurrentSim.ObjectsPrimitives.Find(delegate(Primitive prim) { return prim.ID == rootID; });
if (rootPrim == null)
return "Cannot find requested prim " + rootID.ToString();
else
Logger.DebugLog("Found requested prim " + rootPrim.ID.ToString(), Client);
if (rootPrim.ParentID != 0)
{
// This is not actually a root prim, find the root
if (!Client.Network.CurrentSim.ObjectsPrimitives.TryGetValue(rootPrim.ParentID, out rootPrim))
return "Cannot find root prim for requested object";
else
Logger.DebugLog("Set root prim to " + rootPrim.ID.ToString(), Client);
}
// Find all of the child objects linked to this root
childPrims = Client.Network.CurrentSim.ObjectsPrimitives.FindAll(delegate(Primitive prim) { return prim.ParentID == rootPrim.LocalID; });
// Build a dictionary of primitives for referencing later
Objects[rootPrim.ID] = rootPrim;
for (int i = 0; i < childPrims.Count; i++)
Objects[childPrims[i].ID] = childPrims[i];
// Build a list of all the localIDs to set permissions for
localIDs.Add(rootPrim.LocalID);
for (int i = 0; i < childPrims.Count; i++)
localIDs.Add(childPrims[i].LocalID);
// Go through each of the three main permissions and enable or disable them
#region Set Linkset Permissions
PermCount = 0;
if ((Perms & PermissionMask.Modify) == PermissionMask.Modify)
Client.Objects.SetPermissions(Client.Network.CurrentSim, localIDs, PermissionWho.NextOwner, PermissionMask.Modify, true);
else
Client.Objects.SetPermissions(Client.Network.CurrentSim, localIDs, PermissionWho.NextOwner, PermissionMask.Modify, false);
PermsSent = true;
if (!GotPermissionsEvent.WaitOne(1000 * 30, false))
return "Failed to set the modify bit, permissions in an unknown state";
PermCount = 0;
if ((Perms & PermissionMask.Copy) == PermissionMask.Copy)
Client.Objects.SetPermissions(Client.Network.CurrentSim, localIDs, PermissionWho.NextOwner, PermissionMask.Copy, true);
else
Client.Objects.SetPermissions(Client.Network.CurrentSim, localIDs, PermissionWho.NextOwner, PermissionMask.Copy, false);
PermsSent = true;
if (!GotPermissionsEvent.WaitOne(1000 * 30, false))
return "Failed to set the copy bit, permissions in an unknown state";
PermCount = 0;
if ((Perms & PermissionMask.Transfer) == PermissionMask.Transfer)
Client.Objects.SetPermissions(Client.Network.CurrentSim, localIDs, PermissionWho.NextOwner, PermissionMask.Transfer, true);
else
Client.Objects.SetPermissions(Client.Network.CurrentSim, localIDs, PermissionWho.NextOwner, PermissionMask.Transfer, false);
PermsSent = true;
if (!GotPermissionsEvent.WaitOne(1000 * 30, false))
return "Failed to set the transfer bit, permissions in an unknown state";
#endregion Set Linkset Permissions
// Check each prim for task inventory and set permissions on the task inventory
int taskItems = 0;
foreach (Primitive prim in Objects.Values)
{
if ((prim.Flags & PrimFlags.InventoryEmpty) == 0)
{
List<InventoryBase> items = Client.Inventory.GetTaskInventory(prim.ID, prim.LocalID, 1000 * 30);
if (items != null)
{
for (int i = 0; i < items.Count; i++)
{
if (!(items[i] is InventoryFolder))
{
InventoryItem item = (InventoryItem)items[i];
item.Permissions.NextOwnerMask = Perms;
Client.Inventory.UpdateTaskInventory(prim.LocalID, item);
++taskItems;
}
}
}
}
}
return "Set permissions to " + Perms.ToString() + " on " + localIDs.Count + " objects and " + taskItems + " inventory items";
}
void Objects_OnObjectProperties(object sender, ObjectPropertiesEventArgs e)
{
if (PermsSent)
{
if (Objects.ContainsKey(e.Properties.ObjectID))
{
// FIXME: Confirm the current operation against properties.Permissions.NextOwnerMask
++PermCount;
if (PermCount >= Objects.Count)
GotPermissionsEvent.Set();
}
}
}
}
}
@@ -0,0 +1,47 @@
using System;
using OpenMetaverse;
namespace OpenMetaverse.TestClient
{
public class DeRezCommand : Command
{
public DeRezCommand(TestClient testClient)
{
Name = "derez";
Description = "De-Rezes a specified prim. " + "Usage: derez [prim-uuid]";
Category = CommandCategory.Objects;
}
public override string Execute(string[] args, UUID fromAgentID)
{
UUID primID;
if (args.Length != 1)
return "Usage: derez [prim-uuid]";
if (UUID.TryParse(args[0], out primID))
{
Primitive target = Client.Network.CurrentSim.ObjectsPrimitives.Find(
delegate(Primitive prim) { return prim.ID == primID; }
);
if (target != null)
{
uint objectLocalID = target.LocalID;
Client.Inventory.RequestDeRezToInventory(objectLocalID, DeRezDestination.AgentInventoryTake,
Client.Inventory.FindFolderForType(AssetType.TrashFolder),
UUID.Random());
return "removing " + target;
}
else
{
return "Could not find prim " + primID.ToString();
}
}
else
{
return "Usage: derez [prim-uuid]";
}
}
}
}
@@ -0,0 +1,90 @@
using System;
using System.IO;
using System.Threading;
using OpenMetaverse;
using OpenMetaverse.Assets;
namespace OpenMetaverse.TestClient
{
public class DownloadTextureCommand : Command
{
UUID TextureID;
AutoResetEvent DownloadHandle = new AutoResetEvent(false);
AssetTexture Asset;
TextureRequestState resultState;
public DownloadTextureCommand(TestClient testClient)
{
Name = "downloadtexture";
Description = "Downloads the specified texture. " +
"Usage: downloadtexture [texture-uuid] [discardlevel]";
Category = CommandCategory.Inventory;
}
public override string Execute(string[] args, UUID fromAgentID)
{
if (args.Length != 1 && args.Length != 2)
return "Usage: downloadtexture [texture-uuid] [discardlevel]";
TextureID = UUID.Zero;
DownloadHandle.Reset();
Asset = null;
if (UUID.TryParse(args[0], out TextureID))
{
int discardLevel = 0;
if (args.Length > 1)
{
if (!Int32.TryParse(args[1], out discardLevel))
return "Usage: downloadtexture [texture-uuid] [discardlevel]";
}
Client.Assets.RequestImage(TextureID, ImageType.Normal, Assets_OnImageReceived);
if (DownloadHandle.WaitOne(120 * 1000, false))
{
if (resultState == TextureRequestState.Finished)
{
if (Asset != null && Asset.Decode())
{
try { File.WriteAllBytes(Asset.AssetID + ".jp2", Asset.AssetData); }
catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); }
return String.Format("Saved {0}.jp2 ({1}x{2})", Asset.AssetID, Asset.Image.Width, Asset.Image.Height);
}
else
{
return "Failed to decode texture " + TextureID.ToString();
}
}
else if (resultState == TextureRequestState.NotFound)
{
return "Simulator reported texture not found: " + TextureID.ToString();
}
else
{
return "Download failed for texture " + TextureID + " " + resultState;
}
}
else
{
return "Timed out waiting for texture download";
}
}
else
{
return "Usage: downloadtexture [texture-uuid]";
}
}
private void Assets_OnImageReceived(TextureRequestState state, AssetTexture asset)
{
resultState = state;
Asset = asset;
DownloadHandle.Set();
}
}
}
@@ -0,0 +1,243 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using OpenMetaverse;
using OpenMetaverse.StructuredData;
using OpenMetaverse.Assets;
namespace OpenMetaverse.TestClient
{
public class ExportCommand : Command
{
List<UUID> Textures = new List<UUID>();
AutoResetEvent GotPermissionsEvent = new AutoResetEvent(false);
Primitive.ObjectProperties Properties;
bool GotPermissions = false;
UUID SelectedObject = UUID.Zero;
Dictionary<UUID, Primitive> PrimsWaiting = new Dictionary<UUID, Primitive>();
AutoResetEvent AllPropertiesReceived = new AutoResetEvent(false);
public ExportCommand(TestClient testClient)
{
testClient.Objects.ObjectPropertiesFamily += new EventHandler<ObjectPropertiesFamilyEventArgs>(Objects_OnObjectPropertiesFamily);
testClient.Objects.ObjectProperties += new EventHandler<ObjectPropertiesEventArgs>(Objects_OnObjectProperties);
testClient.Avatars.ViewerEffectPointAt += new EventHandler<ViewerEffectPointAtEventArgs>(Avatars_ViewerEffectPointAt);
Name = "export";
Description = "Exports an object to an xml file. Usage: export uuid outputfile.xml";
Category = CommandCategory.Objects;
}
void Avatars_ViewerEffectPointAt(object sender, ViewerEffectPointAtEventArgs e)
{
if (e.SourceID == Client.MasterKey)
{
//Client.DebugLog("Master is now selecting " + targetID.ToString());
SelectedObject = e.TargetID;
}
}
public override string Execute(string[] args, UUID fromAgentID)
{
if (args.Length != 2 && !(args.Length == 1 && SelectedObject != UUID.Zero))
return "Usage: export uuid outputfile.xml";
UUID id;
uint localid;
string file;
if (args.Length == 2)
{
file = args[1];
if (!UUID.TryParse(args[0], out id))
return "Usage: export uuid outputfile.xml";
}
else
{
file = args[0];
id = SelectedObject;
}
Primitive exportPrim;
exportPrim = Client.Network.CurrentSim.ObjectsPrimitives.Find(
delegate(Primitive prim) { return prim.ID == id; }
);
if (exportPrim != null)
{
if (exportPrim.ParentID != 0)
localid = exportPrim.ParentID;
else
localid = exportPrim.LocalID;
// Check for export permission first
Client.Objects.RequestObjectPropertiesFamily(Client.Network.CurrentSim, id);
GotPermissionsEvent.WaitOne(1000 * 10, false);
if (!GotPermissions)
{
return "Couldn't fetch permissions for the requested object, try again";
}
else
{
GotPermissions = false;
if (Properties.OwnerID != Client.Self.AgentID &&
Properties.OwnerID != Client.MasterKey &&
Client.Self.AgentID != Client.Self.AgentID)
{
return "That object is owned by " + Properties.OwnerID + ", we don't have permission " +
"to export it";
}
}
List<Primitive> prims = Client.Network.CurrentSim.ObjectsPrimitives.FindAll(
delegate(Primitive prim)
{
return (prim.LocalID == localid || prim.ParentID == localid);
}
);
bool complete = RequestObjectProperties(prims, 250);
if (!complete)
{
Logger.Log("Warning: Unable to retrieve full properties for:", Helpers.LogLevel.Warning, Client);
foreach (UUID uuid in PrimsWaiting.Keys)
Logger.Log(uuid.ToString(), Helpers.LogLevel.Warning, Client);
}
string output = OSDParser.SerializeLLSDXmlString(Helpers.PrimListToOSD(prims));
try { File.WriteAllText(file, output); }
catch (Exception e) { return e.Message; }
Logger.Log("Exported " + prims.Count + " prims to " + file, Helpers.LogLevel.Info, Client);
// Create a list of all of the textures to download
List<ImageRequest> textureRequests = new List<ImageRequest>();
lock (Textures)
{
for (int i = 0; i < prims.Count; i++)
{
Primitive prim = prims[i];
if (prim.Textures.DefaultTexture.TextureID != Primitive.TextureEntry.WHITE_TEXTURE &&
!Textures.Contains(prim.Textures.DefaultTexture.TextureID))
{
Textures.Add(prim.Textures.DefaultTexture.TextureID);
}
for (int j = 0; j < prim.Textures.FaceTextures.Length; j++)
{
if (prim.Textures.FaceTextures[j] != null &&
prim.Textures.FaceTextures[j].TextureID != Primitive.TextureEntry.WHITE_TEXTURE &&
!Textures.Contains(prim.Textures.FaceTextures[j].TextureID))
{
Textures.Add(prim.Textures.FaceTextures[j].TextureID);
}
}
if (prim.Sculpt != null && prim.Sculpt.SculptTexture != UUID.Zero && !Textures.Contains(prim.Sculpt.SculptTexture))
{
Textures.Add(prim.Sculpt.SculptTexture);
}
}
// Create a request list from all of the images
for (int i = 0; i < Textures.Count; i++)
textureRequests.Add(new ImageRequest(Textures[i], ImageType.Normal, 1013000.0f, 0));
}
// Download all of the textures in the export list
foreach (ImageRequest request in textureRequests)
{
Client.Assets.RequestImage(request.ImageID, request.Type, Assets_OnImageReceived);
}
return "XML exported, began downloading " + Textures.Count + " textures";
}
else
{
return "Couldn't find UUID " + id.ToString() + " in the " +
Client.Network.CurrentSim.ObjectsPrimitives.Count +
"objects currently indexed in the current simulator";
}
}
private bool RequestObjectProperties(List<Primitive> objects, int msPerRequest)
{
// Create an array of the local IDs of all the prims we are requesting properties for
uint[] localids = new uint[objects.Count];
lock (PrimsWaiting)
{
PrimsWaiting.Clear();
for (int i = 0; i < objects.Count; ++i)
{
localids[i] = objects[i].LocalID;
PrimsWaiting.Add(objects[i].ID, objects[i]);
}
}
Client.Objects.SelectObjects(Client.Network.CurrentSim, localids);
return AllPropertiesReceived.WaitOne(2000 + msPerRequest * objects.Count, false);
}
private void Assets_OnImageReceived(TextureRequestState state, AssetTexture asset)
{
if (state == TextureRequestState.Finished && Textures.Contains(asset.AssetID))
{
lock (Textures)
Textures.Remove(asset.AssetID);
if (state == TextureRequestState.Finished)
{
try { File.WriteAllBytes(asset.AssetID + ".jp2", asset.AssetData); }
catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client); }
if (asset.Decode())
{
try { File.WriteAllBytes(asset.AssetID + ".tga", asset.Image.ExportTGA()); }
catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client); }
}
else
{
Logger.Log("Failed to decode image " + asset.AssetID, Helpers.LogLevel.Error, Client);
}
Logger.Log("Finished downloading image " + asset.AssetID, Helpers.LogLevel.Info, Client);
}
else
{
Logger.Log("Failed to download image " + asset.AssetID + ":" + state, Helpers.LogLevel.Warning, Client);
}
}
}
void Objects_OnObjectPropertiesFamily(object sender, ObjectPropertiesFamilyEventArgs e)
{
Properties = new Primitive.ObjectProperties();
Properties.SetFamilyProperties(e.Properties);
GotPermissions = true;
GotPermissionsEvent.Set();
}
void Objects_OnObjectProperties(object sender, ObjectPropertiesEventArgs e)
{
lock (PrimsWaiting)
{
PrimsWaiting.Remove(e.Properties.ObjectID);
if (PrimsWaiting.Count == 0)
AllPropertiesReceived.Set();
}
}
}
}
@@ -0,0 +1,128 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using OpenMetaverse;
namespace OpenMetaverse.TestClient
{
public class ExportParticlesCommand : Command
{
public ExportParticlesCommand(TestClient testClient)
{
Name = "exportparticles";
Description = "Reverse engineers a prim with a particle system to an LSL script. Usage: exportscript [prim-uuid]";
Category = CommandCategory.Objects;
}
public override string Execute(string[] args, UUID fromAgentID)
{
if (args.Length != 1)
return "Usage: exportparticles [prim-uuid]";
UUID id;
if (!UUID.TryParse(args[0], out id))
return "Usage: exportparticles [prim-uuid]";
lock (Client.Network.Simulators)
{
for (int i = 0; i < Client.Network.Simulators.Count; i++)
{
Primitive exportPrim = Client.Network.Simulators[i].ObjectsPrimitives.Find(
delegate(Primitive prim)
{
return prim.ID == id;
}
);
if (exportPrim != null)
{
if (exportPrim.ParticleSys.CRC != 0)
{
StringBuilder lsl = new StringBuilder();
#region Particle System to LSL
lsl.Append("default" + Environment.NewLine);
lsl.Append("{" + Environment.NewLine);
lsl.Append(" state_entry()" + Environment.NewLine);
lsl.Append(" {" + Environment.NewLine);
lsl.Append(" llParticleSystem([" + Environment.NewLine);
lsl.Append(" PSYS_PART_FLAGS, 0");
if ((exportPrim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.InterpColor) != 0)
lsl.Append(" | PSYS_PART_INTERP_COLOR_MASK");
if ((exportPrim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.InterpScale) != 0)
lsl.Append(" | PSYS_PART_INTERP_SCALE_MASK");
if ((exportPrim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.Bounce) != 0)
lsl.Append(" | PSYS_PART_BOUNCE_MASK");
if ((exportPrim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.Wind) != 0)
lsl.Append(" | PSYS_PART_WIND_MASK");
if ((exportPrim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.FollowSrc) != 0)
lsl.Append(" | PSYS_PART_FOLLOW_SRC_MASK");
if ((exportPrim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.FollowVelocity) != 0)
lsl.Append(" | PSYS_PART_FOLLOW_VELOCITY_MASK");
if ((exportPrim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.TargetPos) != 0)
lsl.Append(" | PSYS_PART_TARGET_POS_MASK");
if ((exportPrim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.TargetLinear) != 0)
lsl.Append(" | PSYS_PART_TARGET_LINEAR_MASK");
if ((exportPrim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.Emissive) != 0)
lsl.Append(" | PSYS_PART_EMISSIVE_MASK");
lsl.Append(","); lsl.Append(Environment.NewLine);
lsl.Append(" PSYS_SRC_PATTERN, 0");
if ((exportPrim.ParticleSys.Pattern & Primitive.ParticleSystem.SourcePattern.Drop) != 0)
lsl.Append(" | PSYS_SRC_PATTERN_DROP");
if ((exportPrim.ParticleSys.Pattern & Primitive.ParticleSystem.SourcePattern.Explode) != 0)
lsl.Append(" | PSYS_SRC_PATTERN_EXPLODE");
if ((exportPrim.ParticleSys.Pattern & Primitive.ParticleSystem.SourcePattern.Angle) != 0)
lsl.Append(" | PSYS_SRC_PATTERN_ANGLE");
if ((exportPrim.ParticleSys.Pattern & Primitive.ParticleSystem.SourcePattern.AngleCone) != 0)
lsl.Append(" | PSYS_SRC_PATTERN_ANGLE_CONE");
if ((exportPrim.ParticleSys.Pattern & Primitive.ParticleSystem.SourcePattern.AngleConeEmpty) != 0)
lsl.Append(" | PSYS_SRC_PATTERN_ANGLE_CONE_EMPTY");
lsl.Append("," + Environment.NewLine);
lsl.Append(" PSYS_PART_START_ALPHA, " + String.Format("{0:0.00000}", exportPrim.ParticleSys.PartStartColor.A) + "," + Environment.NewLine);
lsl.Append(" PSYS_PART_END_ALPHA, " + String.Format("{0:0.00000}", exportPrim.ParticleSys.PartEndColor.A) + "," + Environment.NewLine);
lsl.Append(" PSYS_PART_START_COLOR, " + exportPrim.ParticleSys.PartStartColor.ToRGBString() + "," + Environment.NewLine);
lsl.Append(" PSYS_PART_END_COLOR, " + exportPrim.ParticleSys.PartEndColor.ToRGBString() + "," + Environment.NewLine);
lsl.Append(" PSYS_PART_START_SCALE, <" + String.Format("{0:0.00000}", exportPrim.ParticleSys.PartStartScaleX) + ", " + String.Format("{0:0.00000}", exportPrim.ParticleSys.PartStartScaleY) + ", 0>, " + Environment.NewLine);
lsl.Append(" PSYS_PART_END_SCALE, <" + String.Format("{0:0.00000}", exportPrim.ParticleSys.PartEndScaleX) + ", " + String.Format("{0:0.00000}", exportPrim.ParticleSys.PartEndScaleY) + ", 0>, " + Environment.NewLine);
lsl.Append(" PSYS_PART_MAX_AGE, " + String.Format("{0:0.00000}", exportPrim.ParticleSys.PartMaxAge) + "," + Environment.NewLine);
lsl.Append(" PSYS_SRC_MAX_AGE, " + String.Format("{0:0.00000}", exportPrim.ParticleSys.MaxAge) + "," + Environment.NewLine);
lsl.Append(" PSYS_SRC_ACCEL, " + exportPrim.ParticleSys.PartAcceleration.ToString() + "," + Environment.NewLine);
lsl.Append(" PSYS_SRC_BURST_PART_COUNT, " + String.Format("{0:0}", exportPrim.ParticleSys.BurstPartCount) + "," + Environment.NewLine);
lsl.Append(" PSYS_SRC_BURST_RADIUS, " + String.Format("{0:0.00000}", exportPrim.ParticleSys.BurstRadius) + "," + Environment.NewLine);
lsl.Append(" PSYS_SRC_BURST_RATE, " + String.Format("{0:0.00000}", exportPrim.ParticleSys.BurstRate) + "," + Environment.NewLine);
lsl.Append(" PSYS_SRC_BURST_SPEED_MIN, " + String.Format("{0:0.00000}", exportPrim.ParticleSys.BurstSpeedMin) + "," + Environment.NewLine);
lsl.Append(" PSYS_SRC_BURST_SPEED_MAX, " + String.Format("{0:0.00000}", exportPrim.ParticleSys.BurstSpeedMax) + "," + Environment.NewLine);
lsl.Append(" PSYS_SRC_INNERANGLE, " + String.Format("{0:0.00000}", exportPrim.ParticleSys.InnerAngle) + "," + Environment.NewLine);
lsl.Append(" PSYS_SRC_OUTERANGLE, " + String.Format("{0:0.00000}", exportPrim.ParticleSys.OuterAngle) + "," + Environment.NewLine);
lsl.Append(" PSYS_SRC_OMEGA, " + exportPrim.ParticleSys.AngularVelocity.ToString() + "," + Environment.NewLine);
lsl.Append(" PSYS_SRC_TEXTURE, (key)\"" + exportPrim.ParticleSys.Texture.ToString() + "\"," + Environment.NewLine);
lsl.Append(" PSYS_SRC_TARGET_KEY, (key)\"" + exportPrim.ParticleSys.Target.ToString() + "\"" + Environment.NewLine);
lsl.Append(" ]);" + Environment.NewLine);
lsl.Append(" }" + Environment.NewLine);
lsl.Append("}" + Environment.NewLine);
#endregion Particle System to LSL
return lsl.ToString();
}
else
{
return "Prim " + exportPrim.LocalID + " does not have a particle system";
}
}
}
}
return "Couldn't find prim " + id.ToString();
}
}
}
@@ -0,0 +1,102 @@
using System;
using System.Collections.Generic;
using System.Threading;
using OpenMetaverse;
namespace OpenMetaverse.TestClient
{
public class FindObjectsCommand : Command
{
Dictionary<UUID, Primitive> PrimsWaiting = new Dictionary<UUID, Primitive>();
AutoResetEvent AllPropertiesReceived = new AutoResetEvent(false);
public FindObjectsCommand(TestClient testClient)
{
testClient.Objects.ObjectProperties += new EventHandler<ObjectPropertiesEventArgs>(Objects_OnObjectProperties);
Name = "findobjects";
Description = "Finds all objects, which name contains search-string. " +
"Usage: findobjects [radius] <search-string>";
Category = CommandCategory.Objects;
}
public override string Execute(string[] args, UUID fromAgentID)
{
// *** parse arguments ***
if ((args.Length < 1) || (args.Length > 2))
return "Usage: findobjects [radius] <search-string>";
float radius = float.Parse(args[0]);
string searchString = (args.Length > 1) ? args[1] : String.Empty;
// *** get current location ***
Vector3 location = Client.Self.SimPosition;
// *** find all objects in radius ***
List<Primitive> prims = Client.Network.CurrentSim.ObjectsPrimitives.FindAll(
delegate(Primitive prim)
{
Vector3 pos = prim.Position;
return ((prim.ParentID == 0) && (pos != Vector3.Zero) && (Vector3.Distance(pos, location) < radius));
}
);
// *** request properties of these objects ***
bool complete = RequestObjectProperties(prims, 250);
foreach (Primitive p in prims)
{
string name = p.Properties != null ? p.Properties.Name : null;
if (String.IsNullOrEmpty(searchString) || ((name != null) && (name.Contains(searchString))))
Console.WriteLine(String.Format("Object '{0}': {1}", name, p.ID.ToString()));
}
if (!complete)
{
Console.WriteLine("Warning: Unable to retrieve full properties for:");
foreach (UUID uuid in PrimsWaiting.Keys)
Console.WriteLine(uuid);
}
return "Done searching";
}
private bool RequestObjectProperties(List<Primitive> objects, int msPerRequest)
{
// Create an array of the local IDs of all the prims we are requesting properties for
uint[] localids = new uint[objects.Count];
lock (PrimsWaiting)
{
PrimsWaiting.Clear();
for (int i = 0; i < objects.Count; ++i)
{
localids[i] = objects[i].LocalID;
PrimsWaiting.Add(objects[i].ID, objects[i]);
}
}
Client.Objects.SelectObjects(Client.Network.CurrentSim, localids);
return AllPropertiesReceived.WaitOne(2000 + msPerRequest * objects.Count, false);
}
void Objects_OnObjectProperties(object sender, ObjectPropertiesEventArgs e)
{
lock (PrimsWaiting)
{
Primitive prim;
if (PrimsWaiting.TryGetValue(e.Properties.ObjectID, out prim))
{
prim.Properties = e.Properties;
}
PrimsWaiting.Remove(e.Properties.ObjectID);
if (PrimsWaiting.Count == 0)
AllPropertiesReceived.Set();
}
}
}
}

Some files were not shown because too many files have changed in this diff Show More