Moving examples, mapgenerator, and VisualParamGenerator to Programs folder (SVN is seriously ruined still, don't check out yet)

git-svn-id: http://libopenmetaverse.googlecode.com/svn/trunk@1961 52acb1d6-8a22-11de-b505-999d5b087335
This commit is contained in:
John Hurliman
2008-07-22 23:21:49 +00:00
parent ef71c02528
commit f2dde3daae
153 changed files with 0 additions and 0 deletions

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

View File

@@ -0,0 +1,332 @@
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 LLUUID 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 class ClientManager
{
public Dictionary<LLUUID, GridClient> Clients = new Dictionary<LLUUID, GridClient>();
public Dictionary<Simulator, Dictionary<uint, Primitive>> SimPrims = new Dictionary<Simulator, Dictionary<uint, Primitive>>();
public bool Running = true;
string version = "1.0.0";
/// <summary>
///
/// </summary>
/// <param name="accounts"></param>
public ClientManager(List<LoginDetails> accounts)
{
foreach (LoginDetails account in accounts)
Login(account);
}
public ClientManager(List<LoginDetails> accounts, string s)
{
char sep = '/';
string[] startbits = s.Split(sep);
foreach (LoginDetails account in accounts)
{
account.StartLocation = NetworkManager.StartLocation(startbits[0], Int32.Parse(startbits[1]),
Int32.Parse(startbits[2]), Int32.Parse(startbits[3]));
Login(account);
}
}
/// <summary>
///
/// </summary>
/// <param name="account"></param>
/// <returns></returns>
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;
}
}
TestClient client = new TestClient(this);
// 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;
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;
if (client.Network.Login(loginParams))
{
if (account.MasterKey == LLUUID.Zero && !String.IsNullOrEmpty(account.MasterName))
{
// To prevent security issues, we must resolve the specified master name to a key.
ManualResetEvent keyResolution = new ManualResetEvent(false);
List<DirectoryManager.AgentSearchData> masterMatches = new List<DirectoryManager.AgentSearchData>();
// Set up the callback that handles the search results:
DirectoryManager.DirPeopleReplyCallback callback =
delegate (LLUUID queryID, List<DirectoryManager.AgentSearchData> matches) {
// This may be called several times with additional search results.
if (matches.Count > 0)
{
lock (masterMatches)
{
masterMatches.AddRange(matches);
}
}
else
{
// No results to show.
keyResolution.Set();
}
};
// Find master's key from name
Console.WriteLine("Resolving {0}'s UUID", account.MasterName);
client.Directory.OnDirPeopleReply += callback;
client.Directory.StartPeopleSearch(DirectoryManager.DirFindFlags.People, account.MasterName, 0);
keyResolution.WaitOne(TimeSpan.FromSeconds(30), false);
client.Directory.OnDirPeopleReply -= callback;
LLUUID masterKey = LLUUID.Zero;
string masterName = account.MasterName;
lock (masterMatches) {
if (masterMatches.Count == 1) {
masterKey = masterMatches[0].AgentID;
masterName = masterMatches[0].FirstName + " " + masterMatches[0].LastName;
} else if (masterMatches.Count > 0) {
// Print out numbered list of masters:
Console.WriteLine("Possible masters:");
for (int i = 0; i < masterMatches.Count; ++i)
{
Console.WriteLine("{0}: {1}", i, masterMatches[i].FirstName + " " + masterMatches[i].LastName);
}
Console.Write("Ambiguous master, choose one: ");
// Read number from the console:
string read = null;
do
{
read = Console.ReadLine();
int choice = 0;
if (int.TryParse(read, out choice))
{
if (choice == -1)
{
break;
}
else if (choice < masterMatches.Count)
{
masterKey = masterMatches[choice].AgentID;
masterName = masterMatches[choice].FirstName + " " + masterMatches[choice].LastName;
break;
}
else
{
Console.WriteLine("Please type a number from the above list, -1 to cancel.");
}
}
else
{
Console.WriteLine("You didn't type a number.");
Console.WriteLine("Please type a number from the above list, -1 to cancel.");
}
} while (read != null); // Do it until the user selects a master.
}
}
if (masterKey != LLUUID.Zero)
{
Console.WriteLine("\"{0}\" resolved to {1} ({2})", account.MasterName, masterName, masterKey);
account.MasterName = masterName;
account.MasterKey = masterKey;
}
else
{
Console.WriteLine("Unable to obtain UUID for \"{0}\". No master will be used. Try specifying a key with --masterkey.", account.MasterName);
}
}
client.MasterKey = account.MasterKey;
Clients[client.Self.AgentID] = client;
Console.WriteLine("Logged in " + client.ToString());
}
else
{
Console.WriteLine("Failed to login " + account.FirstName + " " + account.LastName + ": " +
client.Network.LoginMessage);
}
return client;
}
/// <summary>
///
/// </summary>
/// <param name="args"></param>
/// <returns></returns>
public TestClient Login(string[] args)
{
LoginDetails account = new LoginDetails();
account.FirstName = args[0];
account.LastName = args[1];
account.Password = args[2];
if (args.Length == 4)
{
account.StartLocation = NetworkManager.StartLocation(args[3], 128, 128, 40);
}
return Login(account);
}
/// <summary>
///
/// </summary>
public void Run()
{
Console.WriteLine("Type quit to exit. Type help for a command list.");
while (Running)
{
PrintPrompt();
string input = Console.ReadLine();
DoCommandAll(input, LLUUID.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, LLUUID fromAgentID)
{
string[] tokens = cmd.Trim().Split(new char[] { ' ', '\t' });
string firstToken = tokens[0].ToLower();
if (tokens.Length == 0)
return;
if (firstToken == "login")
{
// Special login case: Only call it once, and allow it with
// no logged in avatars
string[] args = new string[tokens.Length - 1];
Array.Copy(tokens, 1, args, 0, args.Length);
Login(args);
}
else if (firstToken == "quit")
{
Quit();
Console.WriteLine("All clients logged out and program finished running.");
}
else
{
// make a copy of the clients list so that it can be iterated without fear of being changed during iteration
Dictionary<LLUUID, GridClient> clientsCopy = new Dictionary<LLUUID, GridClient>(Clients);
foreach (TestClient client in clientsCopy.Values)
client.DoCommand(cmd, fromAgentID);
}
}
/// <summary>
///
/// </summary>
/// <param name="client"></param>
public void Logout(TestClient client)
{
Clients.Remove(client.Self.AgentID);
client.Network.Logout();
}
/// <summary>
///
/// </summary>
public void LogoutAll()
{
// make a copy of the clients list so that it can be iterated without fear of being changed during iteration
Dictionary<LLUUID, GridClient> clientsCopy = new Dictionary<LLUUID, GridClient>(Clients);
foreach (TestClient client in clientsCopy.Values)
Logout(client);
}
/// <summary>
///
/// </summary>
public void Quit()
{
LogoutAll();
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.
}
}
}

View File

@@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Text;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace OpenMetaverse.TestClient
{
public abstract class Command
{
public string Name;
public string Description;
public TestClient Client;
public abstract string Execute(string[] args, LLUUID 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()
{
}
}
}

View File

@@ -0,0 +1,45 @@
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";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
bool success = false;
// Register a handler for the appearance event
AutoResetEvent appearanceEvent = new AutoResetEvent(false);
AppearanceManager.AppearanceUpdatedCallback callback =
delegate(LLObject.TextureEntry te) { appearanceEvent.Set(); };
Client.Appearance.OnAppearanceUpdated += callback;
// Start the appearance setting process (with baking enabled or disabled)
Client.Appearance.SetPreviousAppearance(!(args.Length > 0 && args[0].Equals("nobake")));
// Wait for the process to complete or time out
if (appearanceEvent.WaitOne(1000 * 120, false))
success = true;
// Unregister the handler
Client.Appearance.OnAppearanceUpdated -= callback;
// Return success or failure message
if (success)
return "Successfully set appearance";
else
return "Timed out while setting appearance";
}
}
}

View File

@@ -0,0 +1,35 @@
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";
}
public override string Execute(string[] args, LLUUID 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 = Helpers.StateToAttachmentPoint(prim.Data.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";
}
}
}

View File

@@ -0,0 +1,54 @@
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]";
}
public override string Execute(string[] args, LLUUID 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)
{
LLObject.TextureEntryFace face = foundAv.Textures.FaceTextures[i];
AppearanceManager.TextureIndex type = (AppearanceManager.TextureIndex)i;
output.AppendFormat("{0}: {1}", type, face.TextureID);
output.AppendLine();
}
}
return output.ToString();
}
else
{
return "No nearby avatar with the name " + targetName;
}
}
}
}

View File

@@ -0,0 +1,81 @@
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]";
}
public override string Execute(string[] args, LLUUID 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)
{
LLUUID 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 LLVector3(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<InventoryBase>(), 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;
}
}
}
}

View File

@@ -0,0 +1,45 @@
using System;
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] [nobake]";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
if (args.Length < 1)
return "Usage: wear [outfit name] eg: 'wear /My Outfit/Dance Party";
string target = String.Empty;
bool bake = true;
for (int ct = 0; ct < args.Length; ct++)
{
if (args[ct].Equals("nobake"))
bake = false;
else
target = target + args[ct] + " ";
}
target = target.TrimEnd();
try
{
Client.Appearance.WearOutfit(target.Split('/'), bake);
}
catch (InvalidOutfitException ex)
{
return "Invalid outfit (" + ex.Message + ")";
}
return String.Empty;
}
}
}

View File

@@ -0,0 +1,130 @@
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<LLUUID> Groups = new List<LLUUID>();
bool ReceivedProperties = false;
bool ReceivedInterests = false;
bool ReceivedGroups = false;
ManualResetEvent ReceivedProfileEvent = new ManualResetEvent(false);
public CloneProfileCommand(TestClient testClient)
{
testClient.Avatars.OnAvatarInterests += new AvatarManager.AvatarInterestsCallback(Avatars_OnAvatarInterests);
testClient.Avatars.OnAvatarProperties += new AvatarManager.AvatarPropertiesCallback(Avatars_OnAvatarProperties);
testClient.Avatars.OnAvatarGroups += new AvatarManager.AvatarGroupsCallback(Avatars_OnAvatarGroups);
testClient.Groups.OnGroupJoined += new GroupManager.GroupJoinedCallback(Groups_OnGroupJoined);
Name = "cloneprofile";
Description = "Clones another avatars profile as closely as possible. WARNING: This command will " +
"destroy your existing profile! Usage: cloneprofile [targetuuid]";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
if (args.Length != 1)
return Description;
LLUUID targetID;
ReceivedProperties = false;
ReceivedInterests = false;
ReceivedGroups = false;
try
{
targetID = new LLUUID(args[0]);
}
catch (Exception)
{
return Description;
}
// Request all of the packets that make up an avatar profile
Client.Avatars.RequestAvatarProperties(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 (LLUUID groupID in Groups)
{
Client.Groups.RequestJoinGroup(groupID);
}
return "Synchronized our profile to the profile of " + targetID.ToString();
}
void Avatars_OnAvatarProperties(LLUUID avatarID, Avatar.AvatarProperties properties)
{
lock (ReceivedProfileEvent)
{
Properties = properties;
ReceivedProperties = true;
if (ReceivedInterests && ReceivedProperties && ReceivedGroups)
ReceivedProfileEvent.Set();
}
}
void Avatars_OnAvatarInterests(LLUUID avatarID, Avatar.Interests interests)
{
lock (ReceivedProfileEvent)
{
Interests = interests;
ReceivedInterests = true;
if (ReceivedInterests && ReceivedProperties && ReceivedGroups)
ReceivedProfileEvent.Set();
}
}
void Avatars_OnAvatarGroups(LLUUID avatarID, List<AvatarGroup> groups)
{
lock (ReceivedProfileEvent)
{
foreach (AvatarGroup group in groups)
{
Groups.Add(group.GroupID);
}
ReceivedGroups = true;
if (ReceivedInterests && ReceivedProperties && ReceivedGroups)
ReceivedProfileEvent.Set();
}
}
void Groups_OnGroupJoined(LLUUID groupID, bool success)
{
Console.WriteLine(Client.ToString() + (success ? " joined " : " failed to join ") +
groupID.ToString());
if (success)
{
Console.WriteLine(Client.ToString() + " setting " + groupID.ToString() +
" as the active group");
Client.Groups.ActivateGroup(groupID);
}
}
}
}

View File

@@ -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.";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
if (!Active)
{
Active = true;
Client.Self.OnChat += new AgentManager.ChatCallback(Self_OnChat);
return "Echoing is now on.";
}
else
{
Active = false;
Client.Self.OnChat -= new AgentManager.ChatCallback(Self_OnChat);
return "Echoing is now off.";
}
}
void Self_OnChat(string message, ChatAudibleLevel audible, ChatType type,
ChatSourceType sourcetype, string fromName, LLUUID id, LLUUID ownerid, LLVector3 position)
{
if (message.Length > 0 && Client.MasterKey == id)
Client.Self.Chat(message, 0, ChatType.Normal);
}
}
}

View File

@@ -0,0 +1,71 @@
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, LLUUID> Name2Key = new Dictionary<string, LLUUID>();
public ImCommand(TestClient testClient)
{
testClient.Avatars.OnAvatarNameSearch += new AvatarManager.AvatarNameSearchCallback(Avatars_OnAvatarNameSearch);
Name = "im";
Description = "Instant message someone. Usage: im [firstname] [lastname] [message]";
}
public override string Execute(string[] args, LLUUID 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, LLUUID.Random());
NameSearchEvent.WaitOne(6000, false);
}
if (Name2Key.ContainsKey(ToAvatarName.ToLower()))
{
LLUUID 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_OnAvatarNameSearch(LLUUID queryID, Dictionary<LLUUID, string> avatars)
{
foreach (KeyValuePair<LLUUID, string> kvp in avatars)
{
if (kvp.Value.ToLower() == ToAvatarName.ToLower())
{
Name2Key[ToAvatarName.ToLower()] = kvp.Key;
NameSearchEvent.Set();
return;
}
}
}
}
}

View File

@@ -0,0 +1,77 @@
using System;
using System.Collections.Generic;
using System.Threading;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace OpenMetaverse.TestClient
{
public class ImGroupCommand : Command
{
LLUUID ToGroupID = LLUUID.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]";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
if (args.Length < 2)
return "Usage: imgroup [group_uuid] [message]";
if (LLUUID.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);
Client.Self.OnGroupChatJoin += new AgentManager.GroupChatJoined(Self_OnGroupChatJoin);
if (!Client.Self.GroupChatSessions.ContainsKey(ToGroupID))
{
WaitForSessionStart.Reset();
Client.Self.RequestJoinGroupChat(ToGroupID);
}
else
{
WaitForSessionStart.Set();
}
if (WaitForSessionStart.WaitOne(10000, false))
{
Client.Self.InstantMessageGroup(ToGroupID, message);
}
else
{
return "Timeout waiting for group session start";
}
Client.Self.OnGroupChatJoin -= new AgentManager.GroupChatJoined(Self_OnGroupChatJoin);
return "Instant Messaged group " + ToGroupID.ToString() + " with message: " + message;
}
else
{
return "failed to instant message group";
}
}
void Self_OnGroupChatJoin(LLUUID groupChatSessionID, LLUUID tmpSessionID, bool success)
{
if (success)
{
Console.WriteLine("Join Group Chat Success!");
WaitForSessionStart.Set();
}
else
{
Console.WriteLine("Join Group Chat failed :(");
}
}
}
}

View File

@@ -0,0 +1,44 @@
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)";
}
public override string Execute(string[] args, LLUUID 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;
}
StringBuilder message = new StringBuilder();
for (int i = startIndex; i < args.Length; i++)
{
message.Append(args[i]);
if (i != args.Length - 1) message.Append(" ");
}
Client.Self.Chat(message.ToString(), channel, ChatType.Normal);
return "Said " + message.ToString();
}
}
}

View File

@@ -0,0 +1,49 @@
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.";
}
public override string Execute(string[] args, LLUUID 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++)
{
message += args[i] + " ";
}
Client.Self.Chat(message, channel, ChatType.Shout);
return "Shouted " + message;
}
}
}

View File

@@ -0,0 +1,51 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Speech.Synthesis;
using libsecondlife;
using libsecondlife.Packets;
using libsecondlife.AssetSystem;
// Since this requires .Net 3.0 I've left it out of the project by default.
// To use this: include it in the project and add a reference to the System.Speech.dll
namespace libsecondlife.TestClient
{
public class TtsCommand : Command
{
SpeechSynthesizer _speechSynthesizer;
public TtsCommand(TestClient testClient)
{
Name = "tts";
Description = "Text To Speech. When activated, client will echo all recieved chat messages out thru the computer's speakers.";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
if (!Active)
{
if (_speechSynthesizer == null)
_speechSynthesizer = new SpeechSynthesizer();
Active = true;
Client.Self.OnChat += new MainAvatar.ChatCallback(Self_OnChat);
return "TTS is now on.";
}
else
{
Active = false;
Client.Self.OnChat -= new MainAvatar.ChatCallback(Self_OnChat);
return "TTS is now off.";
}
}
void Self_OnChat(string message, byte audible, byte type, byte sourcetype, string fromName, LLUUID id, LLUUID ownerid, LLVector3 position)
{
if (message.Length > 0)
{
_speechSynthesizer.SpeakAsync(message);
}
}
}
}

View File

@@ -0,0 +1,49 @@
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.";
}
public override string Execute(string[] args, LLUUID 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++)
{
message += args[i] + " ";
}
Client.Self.Chat(message, channel, ChatType.Whisper);
return "Whispered " + message;
}
}
}

View File

@@ -0,0 +1,39 @@
using System;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace OpenMetaverse.TestClient
{
public class DetectBotCommand : Command
{
public DetectBotCommand(TestClient testClient)
{
Name = "detectbot";
Description = "Runs in the background, reporting any potential bots";
testClient.Avatars.OnAvatarAppearance += new AvatarManager.AvatarAppearanceCallback(Avatars_OnAvatarAppearance);
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
return "This command is always running";
}
void Avatars_OnAvatarAppearance(LLUUID avatarID, bool isTrial, LLObject.TextureEntryFace defaultTexture, LLObject.TextureEntryFace[] faceTextures, System.Collections.Generic.List<byte> visualParams)
{
if (IsNullOrZero(faceTextures[(int)AppearanceManager.TextureIndex.EyesBaked]) &&
IsNullOrZero(faceTextures[(int)AppearanceManager.TextureIndex.HeadBaked]) &&
IsNullOrZero(faceTextures[(int)AppearanceManager.TextureIndex.LowerBaked]) &&
IsNullOrZero(faceTextures[(int)AppearanceManager.TextureIndex.SkirtBaked]) &&
IsNullOrZero(faceTextures[(int)AppearanceManager.TextureIndex.UpperBaked]))
{
Console.WriteLine("Avatar " + avatarID.ToString() + " may be a bot");
}
}
private bool IsNullOrZero(LLObject.TextureEntryFace face)
{
return (face == null || face.TextureID == LLUUID.Zero);
}
}
}

View File

@@ -0,0 +1,61 @@
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";
}
/// <summary>
/// Get a list of current friends
/// </summary>
/// <param name="args">optional testClient command arguments</param>
/// <param name="fromAgentID">The <seealso cref="OpenMetaverse.LLUUID"/>
/// of the agent making the request</param>
/// <returns></returns>
public override string Execute(string[] args, LLUUID 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
Client.Friends.FriendList.ForEach(delegate(FriendInfo friend)
{
// append the name of the friend to our output
sb.AppendLine(friend.Name);
});
}
else
{
// we have no friends :(
sb.AppendLine("No Friends");
}
// return the result
return sb.ToString();
}
}
}

View File

@@ -0,0 +1,53 @@
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";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
if (args.Length != 1)
return Description;
LLUUID targetID;
if (!LLUUID.TryParse(args[0], out targetID))
return Description;
StringBuilder sb = new StringBuilder();
FriendsManager.FriendFoundEvent del =
delegate(LLUUID agentID, ulong regionHandle, LLVector3 location)
{
if (!regionHandle.Equals(0))
sb.AppendFormat("Found Friend {0} in {1} at {2}/{3}", agentID, regionHandle, location.X, location.Y);
else
sb.AppendFormat("Found Friend {0}, But they appear to be offline", agentID);
WaitforFriend.Set();
};
Client.Friends.OnFriendFound += 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.OnFriendFound -= del;
return sb.ToString();
}
}
}

View File

@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Text;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace OpenMetaverse.TestClient
{
public class GoHomeCommand : Command
{
public GoHomeCommand(TestClient testClient)
{
Name = "gohome";
Description = "Teleports home";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
if ( Client.Self.GoHome() ) {
return "Teleport Home Succesful";
} else {
return "Teleport Home Failed";
}
}
}
}

View File

@@ -0,0 +1,37 @@
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]";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
if (args.Length < 1)
{
return "Usage: goto_landmark [UUID]";
}
LLUUID landmark = new LLUUID();
if ( ! LLUUID.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";
}
}
}
}

View File

@@ -0,0 +1,92 @@
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
{
ManualResetEvent GroupsEvent = new ManualResetEvent(false);
Dictionary<LLUUID, Group> groups = new Dictionary<LLUUID, Group>();
string activeGroup;
public ActivateGroupCommand(TestClient testClient)
{
Name = "activategroup";
Description = "Set a group as active. Usage: activategroup GroupName";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
if (args.Length < 1)
return Description;
groups.Clear();
activeGroup = string.Empty;
string groupName = String.Empty;
for (int i = 0; i < args.Length; i++)
groupName += args[i] + " ";
groupName = groupName.Trim();
GroupManager.CurrentGroupsCallback callback = new GroupManager.CurrentGroupsCallback(Groups_OnCurrentGroups);
Client.Groups.OnCurrentGroups += callback;
Client.Groups.RequestCurrentGroups();
GroupsEvent.WaitOne(30000, false);
Client.Groups.OnCurrentGroups -= callback;
GroupsEvent.Reset();
if (groups.Count > 0)
{
foreach (Group currentGroup in groups.Values)
if (currentGroup.Name.ToLower() == groupName.ToLower())
{
NetworkManager.PacketCallback pcallback = new NetworkManager.PacketCallback(AgentDataUpdateHandler);
Client.Network.RegisterCallback(PacketType.AgentDataUpdate, pcallback);
Console.WriteLine("setting " + currentGroup.Name + " as active group");
Client.Groups.ActivateGroup(currentGroup.ID);
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;
}
return Client.ToString() + " doesn't seem member of any group";
}
void Groups_OnCurrentGroups(Dictionary<LLUUID, Group> cGroups)
{
groups = cGroups;
GroupsEvent.Set();
}
private void AgentDataUpdateHandler(Packet packet, Simulator sim)
{
AgentDataUpdatePacket p = (AgentDataUpdatePacket)packet;
if (p.AgentData.AgentID == Client.Self.AgentID)
{
activeGroup = Helpers.FieldToUTF8String(p.AgentData.GroupName) + " ( " + Helpers.FieldToUTF8String(p.AgentData.GroupTitle) + " )";
GroupsEvent.Set();
}
}
}
}

View File

@@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using System.Threading;
using OpenMetaverse;
using OpenMetaverse.Packets;
using System.Text;
namespace OpenMetaverse.TestClient
{
public class GroupsCommand : Command
{
ManualResetEvent GetCurrentGroupsEvent = new ManualResetEvent(false);
Dictionary<LLUUID, Group> groups = new Dictionary<LLUUID, Group>();
public GroupsCommand(TestClient testClient)
{
testClient.Groups.OnCurrentGroups += new GroupManager.CurrentGroupsCallback(Groups_OnCurrentGroups);
Name = "groups";
Description = "List avatar groups. Usage: groups";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
if (groups.Count == 0)
{
Client.Groups.RequestCurrentGroups();
GetCurrentGroupsEvent.WaitOne(10000, false);
}
if (groups.Count > 0)
{
return getGroupsString();
}
else
{
return "No groups";
}
}
void Groups_OnCurrentGroups(Dictionary<LLUUID, Group> pGroups)
{
groups = pGroups;
GetCurrentGroupsEvent.Set();
}
string getGroupsString()
{
StringBuilder sb = new StringBuilder();
foreach (Group group in groups.Values)
{
sb.AppendLine(group.Name + " " + group.ID);
}
return sb.ToString();
}
}
}

View File

@@ -0,0 +1,147 @@
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 LLUUID queryID = LLUUID.Zero;
private LLUUID 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";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
if (args.Length < 1)
return Description;
groupName = String.Empty;
resolvedGroupID = LLUUID.Zero;
resolvedGroupName = String.Empty;
if (args[0].ToLower() == "uuid")
{
if (args.Length < 2)
return Description;
if (!LLUUID.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();
DirectoryManager.DirGroupsReplyCallback callback = new DirectoryManager.DirGroupsReplyCallback(Directory_OnDirGroupsReply);
Client.Directory.OnDirGroupsReply += callback;
queryID = Client.Directory.StartGroupSearch(DirectoryManager.DirFindFlags.Groups, groupName, 0);
GetGroupsSearchEvent.WaitOne(60000, false);
Client.Directory.OnDirGroupsReply -= callback;
GetGroupsSearchEvent.Reset();
}
if (resolvedGroupID == LLUUID.Zero)
{
if (string.IsNullOrEmpty(resolvedGroupName))
return "Unable to obtain UUID for group " + groupName;
else
return resolvedGroupName;
}
GroupManager.GroupJoinedCallback gcallback = new GroupManager.GroupJoinedCallback(Groups_OnGroupJoined);
Client.Groups.OnGroupJoined += gcallback;
Client.Groups.RequestJoinGroup(resolvedGroupID);
/* A.Biondi
* TODO: implement the pay to join procedure.
*/
GetGroupsSearchEvent.WaitOne(60000, false);
Client.Groups.OnGroupJoined -= gcallback;
GetGroupsSearchEvent.Reset();
if (joinedGroup)
return "Joined the group " + resolvedGroupName;
return "Unable to join the group " + resolvedGroupName;
}
void Groups_OnGroupJoined(LLUUID groupID, bool success)
{
Console.WriteLine(Client.ToString() + (success ? " joined " : " failed to join ") + 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 = success;
GetGroupsSearchEvent.Set();
}
void Directory_OnDirGroupsReply(LLUUID queryid, List<DirectoryManager.GroupSearchData> matchedGroups)
{
if (queryID == queryid)
{
queryID = LLUUID.Zero;
if (matchedGroups.Count < 1)
{
Console.WriteLine("ERROR: Got an empty reply");
}
else
{
if (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 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 " + matchedGroups.Count.ToString() + " groups (UUIDs on console)";
}
}
GetGroupsSearchEvent.Set();
}
}
}
}

View File

@@ -0,0 +1,89 @@
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);
Dictionary<LLUUID, Group> groups = new Dictionary<LLUUID, Group>();
private bool leftGroup;
public LeaveGroupCommand(TestClient testClient)
{
Name = "leavegroup";
Description = "Leave a group. Usage: leavegroup GroupName";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
if (args.Length < 1)
return Description;
groups.Clear();
string groupName = String.Empty;
for (int i = 0; i < args.Length; i++)
groupName += args[i] + " ";
groupName = groupName.Trim();
GroupManager.CurrentGroupsCallback callback = new GroupManager.CurrentGroupsCallback(Groups_OnCurrentGroups);
Client.Groups.OnCurrentGroups += callback;
Client.Groups.RequestCurrentGroups();
GroupsEvent.WaitOne(30000, false);
Client.Groups.OnCurrentGroups -= callback;
GroupsEvent.Reset();
if (groups.Count > 0)
{
foreach (Group currentGroup in groups.Values)
if (currentGroup.Name.ToLower() == groupName.ToLower())
{
GroupManager.GroupLeftCallback lcallback = new GroupManager.GroupLeftCallback(Groups_OnGroupLeft);
Client.Groups.OnGroupLeft += lcallback;
Client.Groups.LeaveGroup(currentGroup.ID);
/* A.Biondi
* TODO: modify GroupsCommand.cs
* GroupsCommand.cs doesn't refresh the groups list until a new
* CurrentGroupsCallback occurs, so if you'd issue the command
* 'Groups' right after have left a group, it'll display still yet
* the group you just left (unless you have 0 groups, because it
* would force the refresh with Client.Groups.RequestCurrentGroups).
*/
GroupsEvent.WaitOne(30000, false);
Client.Groups.OnGroupLeft -= lcallback;
GroupsEvent.Reset();
if (leftGroup)
return Client.ToString() + " has left the group " + groupName;
return "failed to left the group " + groupName;
}
return Client.ToString() + " doesn't seem to be member of the group " + groupName;
}
return Client.ToString() + " doesn't seem member of any group";
}
void Groups_OnCurrentGroups(Dictionary<LLUUID, Group> cGroups)
{
groups = cGroups;
GroupsEvent.Set();
}
void Groups_OnGroupLeft(LLUUID groupID, bool success)
{
Console.WriteLine(Client.ToString() + (success ? " has left group " : " failed to left group ") + groupID.ToString());
leftGroup = success;
GroupsEvent.Set();
}
}
}

View File

@@ -0,0 +1,358 @@
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;
namespace OpenMetaverse.TestClient
{
public class QueuedDownloadInfo
{
public LLUUID TransferID;
public LLUUID AssetID;
public LLUUID ItemID;
public LLUUID TaskID;
public LLUUID OwnerID;
public AssetType Type;
public string FileName;
public DateTime WhenRequested;
public bool IsRequested;
public QueuedDownloadInfo(string file, LLUUID asset, LLUUID item, LLUUID task, LLUUID owner, AssetType type)
{
FileName = file;
AssetID = asset;
ItemID = item;
TaskID = task;
OwnerID = owner;
Type = type;
TransferID = LLUUID.Zero;
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]";
testClient.Assets.OnAssetReceived += new AssetManager.AssetReceivedCallback(Assets_OnAssetReceived);
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
StringBuilder sbResult = new StringBuilder();
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
qdi.TransferID = Client.Assets.RequestInventoryAsset(
qdi.AssetID, qdi.ItemID, qdi.TaskID, qdi.OwnerID, qdi.Type, true);
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;
qdi.TransferID = Client.Assets.RequestInventoryAsset(
qdi.AssetID, qdi.ItemID, qdi.TaskID, qdi.OwnerID, qdi.Type, true);
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)
{
StringBuilder sbRequests = new StringBuilder();
// 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, LLUUID.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.TransferID == asset.ID;
});
if (r != null && r.TransferID == asset.ID)
{
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";
}
}
}

View File

@@ -0,0 +1,32 @@
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$.";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
System.Threading.AutoResetEvent waitBalance = new System.Threading.AutoResetEvent(false);
AgentManager.BalanceCallback del = delegate(int balance) { waitBalance.Set(); };
Client.Self.OnBalanceUpdated += 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.OnBalanceUpdated -= del;
return result;
}
}
}

View File

@@ -0,0 +1,85 @@
using System;
using System.Collections.Generic;
using System.Text;
using OpenMetaverse;
namespace OpenMetaverse.TestClient.Commands.Inventory.Shell
{
public class ChangeDirectoryCommand : Command
{
private InventoryManager Manager;
private OpenMetaverse.Inventory Inventory;
public ChangeDirectoryCommand(TestClient client)
{
Name = "cd";
Description = "Changes the current working inventory folder.";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
Manager = Client.Inventory;
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;
}
}
}

View File

@@ -0,0 +1,85 @@
using System;
using System.Collections.Generic;
using System.IO;
using OpenMetaverse;
namespace OpenMetaverse.TestClient
{
public class CreateNotecardCommand : Command
{
public CreateNotecardCommand(TestClient testClient)
{
Name = "createnotecard";
Description = "Creates a notecard from a local text file.";
}
void OnNoteUpdate(bool success, string status, LLUUID itemID, LLUUID assetID)
{
if (success)
Console.WriteLine("Notecard successfully uploaded, ItemID {0} AssetID {1}", itemID, assetID);
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
if(args.Length < 1)
return "Usage: createnotecard filename.txt";
string file = String.Empty;
for (int ct = 0; ct < args.Length; ct++)
file = file + args[ct] + " ";
file = file.TrimEnd();
Console.WriteLine("Filename: {0}", file);
if (!File.Exists(file))
return String.Format("Filename '{0}' does not exist", file);
System.IO.StreamReader reader = new StreamReader(file);
string body = reader.ReadToEnd();
// FIXME: Upload the notecard asset first. When that completes, call RequestCreateItem
try
{
string desc = String.Format("{0} created by OpenMetaverse TestClient {1}", file, DateTime.Now);
// create the asset
Client.Inventory.RequestCreateItem(Client.Inventory.FindFolderForType(AssetType.Notecard),
file, desc, AssetType.Notecard, LLUUID.Random(), InventoryType.Notecard, PermissionMask.All,
delegate(bool success, InventoryItem item) {
if(success) // upload the asset
Client.Inventory.RequestUploadNotecardAsset(CreateNotecardAsset(body), item.UUID, new InventoryManager.NotecardUploadedAssetCallback(OnNoteUpdate));
}
);
return "Done";
}
catch (System.Exception e)
{
Logger.Log(e.ToString(), Helpers.LogLevel.Error, Client);
return "Error creating notecard.";
}
}
/// <summary>
/// </summary>
/// <param name="body"></param>
public static byte[] CreateNotecardAsset(string body)
{
// Format the string body into Linden text
string lindenText = "Linden text version 1\n";
lindenText += "{\n";
lindenText += "LLEmbeddedItems version 1\n";
lindenText += "{\n";
lindenText += "count 0\n";
lindenText += "}\n";
lindenText += "Text length " + body.Length + "\n";
lindenText += body;
lindenText += "}\n";
// Assume this is a string, add 1 for the null terminator
byte[] stringBytes = System.Text.Encoding.UTF8.GetBytes(lindenText);
byte[] assetData = new byte[stringBytes.Length]; //+ 1];
Array.Copy(stringBytes, 0, assetData, 0, stringBytes.Length);
return assetData;
}
}
}

View File

@@ -0,0 +1,51 @@
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";
}
public override string Execute(string[] args, LLUUID 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>();
try
{
// 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);
}
}
catch (InvalidOutfitException ex)
{
return "Folder Not Found: (" + ex.Message + ")";
}
return string.Empty;
}
}
}

View File

@@ -0,0 +1,124 @@
using System;
using System.Text;
using System.IO;
using System.Collections.Generic;
using OpenMetaverse;
using OpenMetaverse.Imaging;
namespace OpenMetaverse.TestClient
{
public class DumpOutfitCommand : Command
{
List<LLUUID> OutfitAssets = new List<LLUUID>();
AssetManager.ImageReceivedCallback ImageReceivedHandler;
public DumpOutfitCommand(TestClient testClient)
{
Name = "dumpoutfit";
Description = "Dumps all of the textures from an avatars outfit to the hard drive. Usage: dumpoutfit [avatar-uuid]";
ImageReceivedHandler = new AssetManager.ImageReceivedCallback(Assets_OnImageReceived);
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
if (args.Length != 1)
return "Usage: dumpoutfit [avatar-uuid]";
LLUUID target;
if (!LLUUID.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;
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();
Client.Assets.OnImageReceived += ImageReceivedHandler;
for (int j = 0; j < targetAv.Textures.FaceTextures.Length; j++)
{
LLObject.TextureEntryFace face = targetAv.Textures.FaceTextures[j];
if (face != null)
{
ImageType type = ImageType.Normal;
switch ((AppearanceManager.TextureIndex)j)
{
case AppearanceManager.TextureIndex.HeadBaked:
case AppearanceManager.TextureIndex.EyesBaked:
case AppearanceManager.TextureIndex.UpperBaked:
case AppearanceManager.TextureIndex.LowerBaked:
case AppearanceManager.TextureIndex.SkirtBaked:
type = ImageType.Baked;
break;
}
OutfitAssets.Add(face.TextureID);
Client.Assets.RequestImage(face.TextureID, type, 100000.0f, 0);
output.Append(((AppearanceManager.TextureIndex)j).ToString());
output.Append(" ");
}
}
return output.ToString();
}
}
}
return "Couldn't find avatar " + target.ToString();
}
private void Assets_OnImageReceived(ImageDownload image, AssetTexture assetTexture)
{
lock (OutfitAssets)
{
if (OutfitAssets.Contains(image.ID))
{
if (image.Success)
{
try
{
File.WriteAllBytes(image.ID.ToString() + ".jp2", image.AssetData);
Console.WriteLine("Wrote JPEG2000 image " + image.ID.ToString() + ".jp2");
ManagedImage imgData;
OpenJPEG.DecodeToImage(image.AssetData, out imgData);
byte[] tgaFile = imgData.ExportTGA();
File.WriteAllBytes(image.ID.ToString() + ".tga", tgaFile);
Console.WriteLine("Wrote TGA image " + image.ID.ToString() + ".tga");
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
else
{
Console.WriteLine("Failed to download image " + image.ID.ToString());
}
OutfitAssets.Remove(image.ID);
if (OutfitAssets.Count == 0)
Client.Assets.OnImageReceived -= ImageReceivedHandler;
}
}
}
}
}

View File

@@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using System.IO;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace OpenMetaverse.TestClient
{
public class ExportOutfitCommand : Command
{
public ExportOutfitCommand(TestClient testClient)
{
Name = "exportoutfit";
Description = "Exports an avatars outfit to an xml file. Usage: exportoutfit [avataruuid] outputfile.xml";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
LLUUID id;
string path;
if (args.Length == 1)
{
id = Client.Self.AgentID;
path = args[0];
}
else if (args.Length == 2)
{
if (!LLUUID.TryParse(args[0], out id))
return "Usage: exportoutfit [avataruuid] outputfile.xml";
path = args[1];
}
else
return "Usage: exportoutfit [avataruuid] outputfile.xml";
lock (Client.Appearances)
{
if (Client.Appearances.ContainsKey(id))
{
try
{
File.WriteAllText(path, Packet.ToXmlString(Client.Appearances[id]));
}
catch (Exception e)
{
return e.ToString();
}
return "Exported appearance for avatar " + id.ToString() + " to " + args[1];
}
else
{
return "Couldn't find an appearance for avatar " + id.ToString();
}
}
}
}
}

View File

@@ -0,0 +1,27 @@
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.";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
if (fromAgentID == LLUUID.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;
}
}
}

View File

@@ -0,0 +1,59 @@
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.";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
if (args.Length < 2)
{
return "Usage: give <agent uuid> <item1> [item2] [item3] [...]";
}
LLUUID dest;
if (!LLUUID.TryParse(args[0], out dest))
{
return "First argument expected agent UUID.";
}
Manager = Client.Inventory;
Inventory = Manager.Store;
string ret = "";
string nl = "\n";
for (int i = 1; i < args.Length; ++i)
{
string inventoryName = args[i];
// 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 + nl;
}
else
{
ret += "Unable to give folder " + b.Name + nl;
}
}
}
if (!found)
ret += "No inventory item named " + inventoryName + " found." + nl;
}
return ret;
}
}
}

View File

@@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using System.IO;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace OpenMetaverse.TestClient
{
public class ImportOutfitCommand : Command
{
//private uint SerialNum = 1;
public ImportOutfitCommand(TestClient testClient)
{
Name = "importoutfit";
Description = "Imports an appearance from an xml file. Usage: importoutfit inputfile.xml";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
if (args.Length != 1)
return "Usage: importoutfit inputfile.xml";
return "LLSD packet import is under construction";
//try
//{
// Packet packet = Packet.FromXmlString((File.ReadAllText(args[0])));
// if (packet.Type != PacketType.AvatarAppearance)
// return "Deserialized a " + packet.Type + " packet instead of an AvatarAppearance packet";
// AvatarAppearancePacket appearance = (AvatarAppearancePacket)packet;
// AgentSetAppearancePacket set = new AgentSetAppearancePacket();
// set.AgentData.AgentID = Client.Self.AgentID;
// set.AgentData.SessionID = Client.Self.SessionID;
// set.AgentData.SerialNum = SerialNum++;
// // HACK: Weak hack to calculate size
// float AV_Height_Range = 2.025506f - 1.50856f;
// float AV_Height = 1.50856f + (((float)appearance.VisualParam[25].ParamValue / 255.0f) * AV_Height_Range);
// set.AgentData.Size = new LLVector3(0.45f, 0.6f, AV_Height);
// set.ObjectData.TextureEntry = appearance.ObjectData.TextureEntry;
// set.VisualParam = new AgentSetAppearancePacket.VisualParamBlock[appearance.VisualParam.Length];
// int i = 0;
// foreach (AvatarAppearancePacket.VisualParamBlock block in appearance.VisualParam)
// {
// set.VisualParam[i] = new AgentSetAppearancePacket.VisualParamBlock();
// set.VisualParam[i].ParamValue = block.ParamValue;
// i++;
// }
// set.WearableData = new AgentSetAppearancePacket.WearableDataBlock[0];
// Client.Network.SendPacket(set);
//}
//catch (Exception)
//{
// return "Failed to import the appearance XML file, maybe it doesn't exist or is in the wrong format?";
//}
//return "Imported " + args[0] + " and sent an AgentSetAppearance packet";
}
}
}

View File

@@ -0,0 +1,50 @@
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.";
}
public override string Execute(string[] args, LLUUID 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)
{
foreach (InventoryBase i in Manager.FolderContents(f.UUID, Client.Self.AgentID, true, true, InventorySortOrder.ByName, 3000))
{
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);
}
}
}
}
}

View File

@@ -0,0 +1,95 @@
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.";
}
public override string Execute(string[] args, LLUUID 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;
}
}
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;
}
}
}

View File

@@ -0,0 +1,59 @@
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]";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
if (args.Length != 1)
return "Usage: objectinventory [objectID]";
uint objectLocalID;
LLUUID objectID;
if (!LLUUID.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;
}
}
}
}

View File

@@ -0,0 +1,167 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Drawing;
using OpenMetaverse;
using OpenMetaverse.Capabilities;
using OpenMetaverse.Imaging;
namespace OpenMetaverse.TestClient
{
public class UploadImageCommand : Command
{
AutoResetEvent UploadCompleteEvent = new AutoResetEvent(false);
LLUUID TextureID = LLUUID.Zero;
DateTime start;
public UploadImageCommand(TestClient testClient)
{
Name = "uploadimage";
Description = "Upload an image to your inventory. Usage: uploadimage [inventoryname] [timeout] [filename]";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
string inventoryName;
uint timeout;
string fileName;
if (args.Length != 3)
return "Usage: uploadimage [inventoryname] [timeout] [filename]";
TextureID = LLUUID.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 != LLUUID.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(CapsClient client, long bytesReceived, long bytesSent, long totalBytesToReceive, long totalBytesToSend)
{
if (bytesSent > 0)
Console.WriteLine(String.Format("Texture upload: {0} / {1}", bytesSent, totalBytesToSend));
},
delegate(bool success, string status, LLUUID itemID, LLUUID 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;
}
}
}

View File

@@ -0,0 +1,52 @@
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]";
}
public override string Execute(string[] args, LLUUID 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<GridItem> 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++)
{
GridAgentLocation location = (GridAgentLocation)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";
}
}
}
}

View File

@@ -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, LLUUID 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";
}
}
}

View File

@@ -0,0 +1,29 @@
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";
testClient.Grid.OnGridLayer += new GridManager.GridLayerCallback(Grid_OnGridLayer);
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
Client.Grid.RequestMapLayer(GridLayerType.Objects);
return "Sent.";
}
private void Grid_OnGridLayer(GridLayer layer)
{
Console.WriteLine(String.Format("Layer({0}) Bottom: {1} Left: {2} Top: {3} Right: {4}",
layer.ImageID.ToString(), layer.Bottom, layer.Left, layer.Top, layer.Right));
}
}
}

View File

@@ -0,0 +1,27 @@
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";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
//if (args.Length < 1)
// return "";
Client.Grid.RequestMainlandSims(GridLayerType.Objects);
return "Sent.";
}
}
}

View File

@@ -0,0 +1,48 @@
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";
}
public override string Execute(string[] args, LLUUID 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.PropertiesRequest(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]);
}
}
}
}

View File

@@ -0,0 +1,64 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using OpenMetaverse;
using OpenMetaverse.Utilities;
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";
testClient.Network.OnDisconnected += new NetworkManager.DisconnectedCallback(Network_OnDisconnected);
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
StringBuilder sb = new StringBuilder();
string result;
ParcelManager.SimParcelsDownloaded del = delegate(Simulator simulator, InternalDictionary<int, Parcel> simParcels, int[,] parcelMap)
{
ParcelsDownloaded.Set();
};
ParcelsDownloaded.Reset();
Client.Parcels.OnSimParcelsDownloaded += del;
Client.Parcels.RequestAllSimParcels(Client.Network.CurrentSim);
if (Client.Network.CurrentSim.IsParcelMapFull())
ParcelsDownloaded.Set();
if (ParcelsDownloaded.WaitOne(20000, 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}\" ACL Count: {3} Traffic: {4}" + System.Environment.NewLine,
parcel.LocalID, parcel.Name, parcel.Desc, parcel.AccessList.Count, parcel.Dwell);
});
result = sb.ToString();
}
else
result = "Failed to retrieve information on all the simulator parcels";
Client.Parcels.OnSimParcelsDownloaded -= del;
return result;
}
void Network_OnDisconnected(NetworkManager.DisconnectType reason, string message)
{
ParcelsDownloaded.Set();
}
}
}

View File

@@ -0,0 +1,33 @@
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]";
}
public override string Execute(string[] args, LLUUID 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";
}
}
}
}

View File

@@ -0,0 +1,33 @@
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]";
}
public override string Execute(string[] args, LLUUID 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";
}
}
}
}

View File

@@ -0,0 +1,156 @@
using System;
using System.Collections.Generic;
using System.Text;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace OpenMetaverse.TestClient
{
public class FollowCommand: Command
{
public FollowCommand(TestClient testClient)
{
Name = "follow";
Description = "Follow another avatar. (usage: follow [FirstName LastName]) If no target is set then will follow master.";
testClient.Network.RegisterCallback(PacketType.AlertMessage, new NetworkManager.PacketCallback(AlertMessageHandler));
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
string target = String.Empty;
for (int ct = 0; ct < args.Length; ct++)
target = target + args[ct] + " ";
target = target.TrimEnd();
if (target.Length > 0)
{
if (Follow(target))
return "Following " + target;
else
return "Unable to follow " + target + ". Client may not be able to see that avatar.";
}
else
{
if (Follow(Client.MasterKey))
return "Following " + Client.MasterKey;
else
return "No target specified and no master not found. usage: follow [FirstName LastName])";
}
}
const float DISTANCE_BUFFER = 3.0f;
uint targetLocalID = 0;
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;
}
}
}
Active = false;
return false;
}
bool Follow(LLUUID id)
{
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.ID == id;
}
);
if (target != null)
{
targetLocalID = target.LocalID;
Active = true;
return true;
}
}
}
Active = false;
return false;
}
public override void Think()
{
// 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 = LLVector3.Dist(targetAv.Position, Client.Self.SimPosition);
}
else
{
// FIXME: Calculate global distances
}
if (distance > DISTANCE_BUFFER)
{
uint regionX, regionY;
Helpers.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(Packet packet, Simulator simulator)
{
AlertMessagePacket alert = (AlertMessagePacket)packet;
string message = Helpers.FieldToUTF8String(alert.AlertData.Message);
if (message.Contains("Autopilot cancel"))
{
Logger.Log("Server cancelled the autopilot", Helpers.LogLevel.Info, Client);
}
}
}
}

View File

@@ -0,0 +1,50 @@
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\")";
}
public override string Execute(string[] args, LLUUID 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 LLVector3(x, y, z)))
return "Teleported to " + Client.Network.CurrentSim;
else
return "Teleport failed: " + Client.Self.TeleportMessage;
}
}
}

View File

@@ -0,0 +1,20 @@
using System;
using OpenMetaverse;
namespace OpenMetaverse.TestClient
{
public class JumpCommand: Command
{
public JumpCommand(TestClient testClient)
{
Name = "jump";
Description = "Jumps or flies up";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
Client.Self.Jump();
return "Jumped";
}
}
}

View File

@@ -0,0 +1,23 @@
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 the location.";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
return "CurrentSim: '" + Client.Network.CurrentSim.ToString() + "' Position: " +
Client.Self.SimPosition.ToString();
}
}
}

View File

@@ -0,0 +1,40 @@
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";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
if (args.Length != 3)
return "Usage: moveto x y z";
uint regionX, regionY;
Helpers.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);
}
}
}

View File

@@ -0,0 +1,23 @@
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.";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
Client.Self.SetHome();
return "Home Set";
}
}
}

View File

@@ -0,0 +1,48 @@
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";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
Primitive closest = null;
double closestDistance = Double.MaxValue;
Client.Network.CurrentSim.ObjectsPrimitives.ForEach(
delegate(Primitive prim)
{
float distance = LLVector3.Dist(Client.Self.SimPosition, prim.Position);
if (closest == null || distance < closestDistance)
{
closest = prim;
closestDistance = distance;
}
}
);
if (closest != null)
{
Client.Self.RequestSit(closest.ID, LLVector3.Zero);
Client.Self.Sit();
return "Sat on " + closest.ID + " (" + closest.LocalID + "). Distance: " + closestDistance;
}
else
{
return "Couldn't find a nearby prim to sit on";
}
}
}
}

View File

@@ -0,0 +1,45 @@
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";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
if (args.Length != 1)
return "Usage: siton UUID";
LLUUID target;
if (LLUUID.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, LLVector3.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];
}
}
}

View File

@@ -0,0 +1,23 @@
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";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
Client.Self.Stand();
return "Standing up.";
}
}
}

View File

@@ -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);
LLUUID SelectedObject = LLUUID.Zero;
Dictionary<LLUUID, Primitive> Objects = new Dictionary<LLUUID, Primitive>();
PermissionMask Perms = PermissionMask.None;
bool PermsSent = false;
int PermCount = 0;
public ChangePermsCommand(TestClient testClient)
{
testClient.Objects.OnObjectProperties += new ObjectManager.ObjectPropertiesCallback(Objects_OnObjectProperties);
Name = "changeperms";
Description = "Recursively changes all of the permissions for child and task inventory objects. Usage prim-uuid [copy] [mod] [xfer]";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
LLUUID 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 (!LLUUID.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 & LLObject.ObjectFlags.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(Simulator simulator, LLObject.ObjectProperties properties)
{
if (PermsSent)
{
if (Objects.ContainsKey(properties.ObjectID))
{
// FIXME: Confirm the current operation against properties.Permissions.NextOwnerMask
++PermCount;
if (PermCount >= Objects.Count)
GotPermissionsEvent.Set();
}
}
}
}
}

View File

@@ -0,0 +1,87 @@
using System;
using System.IO;
using System.Threading;
using OpenMetaverse;
namespace OpenMetaverse.TestClient
{
public class DownloadTextureCommand : Command
{
LLUUID TextureID;
AutoResetEvent DownloadHandle = new AutoResetEvent(false);
ImageDownload Image;
AssetTexture Asset;
public DownloadTextureCommand(TestClient testClient)
{
Name = "downloadtexture";
Description = "Downloads the specified texture. " +
"Usage: downloadtexture [texture-uuid]";
testClient.Assets.OnImageReceiveProgress += new AssetManager.ImageReceiveProgressCallback(Assets_OnImageReceiveProgress);
testClient.Assets.OnImageReceived += new AssetManager.ImageReceivedCallback(Assets_OnImageReceived);
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
if (args.Length != 1)
return "Usage: downloadtexture [texture-uuid]";
TextureID = LLUUID.Zero;
DownloadHandle.Reset();
Image = null;
Asset = null;
if (LLUUID.TryParse(args[0], out TextureID))
{
Client.Assets.RequestImage(TextureID, ImageType.Normal);
if (DownloadHandle.WaitOne(120 * 1000, false))
{
if (Image != null && Image.Success)
{
if (Asset != null && Asset.Decode())
{
try { File.WriteAllBytes(Image.ID.ToString() + ".jp2", Asset.AssetData); }
catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); }
return String.Format("Saved {0}.jp2 ({1}x{2})", Image.ID, Asset.Image.Width, Asset.Image.Height);
}
else
{
return "Failed to decode texture " + TextureID.ToString();
}
}
else if (Image != null && Image.NotFound)
{
return "Simulator reported texture not found: " + TextureID.ToString();
}
else
{
return "Download failed for texture " + TextureID.ToString();
}
}
else
{
return "Timed out waiting for texture download";
}
}
else
{
return "Usage: downloadtexture [texture-uuid]";
}
}
private void Assets_OnImageReceived(ImageDownload image, AssetTexture asset)
{
Image = image;
Asset = asset;
DownloadHandle.Set();
}
private void Assets_OnImageReceiveProgress(LLUUID image, int recieved, int total)
{
Console.WriteLine(String.Format("Texture {0}: Received {1} / {2}", image, recieved, total));
}
}
}

View File

@@ -0,0 +1,236 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using OpenMetaverse;
using OpenMetaverse.StructuredData;
namespace OpenMetaverse.TestClient
{
public class ExportCommand : Command
{
List<LLUUID> Textures = new List<LLUUID>();
AutoResetEvent GotPermissionsEvent = new AutoResetEvent(false);
LLObject.ObjectPropertiesFamily Properties;
bool GotPermissions = false;
LLUUID SelectedObject = LLUUID.Zero;
Dictionary<LLUUID, Primitive> PrimsWaiting = new Dictionary<LLUUID, Primitive>();
AutoResetEvent AllPropertiesReceived = new AutoResetEvent(false);
public ExportCommand(TestClient testClient)
{
testClient.Objects.OnObjectPropertiesFamily += new ObjectManager.ObjectPropertiesFamilyCallback(Objects_OnObjectPropertiesFamily);
testClient.Objects.OnObjectProperties += new ObjectManager.ObjectPropertiesCallback(Objects_OnObjectProperties);
testClient.Assets.OnImageReceived += new AssetManager.ImageReceivedCallback(Assets_OnImageReceived);
testClient.Avatars.OnPointAt += new AvatarManager.PointAtCallback(Avatars_OnPointAt);
Name = "export";
Description = "Exports an object to an xml file. Usage: export uuid outputfile.xml";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
if (args.Length != 2 && !(args.Length == 1 && SelectedObject != LLUUID.Zero))
return "Usage: export uuid outputfile.xml";
LLUUID id;
uint localid;
string file;
if (args.Length == 2)
{
file = args[1];
if (!LLUUID.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 (LLUUID uuid in PrimsWaiting.Keys)
Logger.Log(uuid.ToString(), Helpers.LogLevel.Warning, Client);
}
string output = LLSDParser.SerializeXmlString(Helpers.PrimListToLLSD(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 != LLObject.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 != LLObject.TextureEntry.WHITE_TEXTURE &&
!Textures.Contains(prim.Textures.FaceTextures[j].TextureID))
{
Textures.Add(prim.Textures.FaceTextures[j].TextureID);
}
}
if (prim.Sculpt.SculptTexture != LLUUID.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
Client.Assets.RequestImages(textureRequests);
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(ImageDownload image, AssetTexture asset)
{
if (Textures.Contains(image.ID))
{
lock (Textures)
Textures.Remove(image.ID);
if (image.Success)
{
try { File.WriteAllBytes(image.ID.ToString() + ".jp2", asset.AssetData); }
catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client); }
if (asset.Decode())
{
try { File.WriteAllBytes(image.ID.ToString() + ".tga", asset.Image.ExportTGA()); }
catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client); }
}
else
{
Logger.Log("Failed to decode image " + image.ID.ToString(), Helpers.LogLevel.Error, Client);
}
Logger.Log("Finished downloading image " + image.ID.ToString(), Helpers.LogLevel.Info, Client);
}
else
{
Logger.Log("Failed to download image " + image.ID.ToString(), Helpers.LogLevel.Warning, Client);
}
}
}
void Avatars_OnPointAt(LLUUID sourceID, LLUUID targetID, LLVector3d targetPos,
PointAtType pointType, float duration, LLUUID id)
{
if (sourceID == Client.MasterKey)
{
//Client.DebugLog("Master is now selecting " + targetID.ToString());
SelectedObject = targetID;
}
}
void Objects_OnObjectPropertiesFamily(Simulator simulator, LLObject.ObjectPropertiesFamily properties)
{
Properties = properties;
GotPermissions = true;
GotPermissionsEvent.Set();
}
void Objects_OnObjectProperties(Simulator simulator, LLObject.ObjectProperties properties)
{
lock (PrimsWaiting)
{
PrimsWaiting.Remove(properties.ObjectID);
if (PrimsWaiting.Count == 0)
AllPropertiesReceived.Set();
}
}
}
}

View File

@@ -0,0 +1,127 @@
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]";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
if (args.Length != 1)
return "Usage: exportparticles [prim-uuid]";
LLUUID id;
if (!LLUUID.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.ToStringRGB() + "," + Environment.NewLine);
lsl.Append(" PSYS_PART_END_COLOR, " + exportPrim.ParticleSys.PartEndColor.ToStringRGB() + "," + 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();
}
}
}

View File

@@ -0,0 +1,94 @@
using System;
using System.Collections.Generic;
using System.Threading;
using OpenMetaverse;
namespace OpenMetaverse.TestClient
{
public class FindObjectsCommand : Command
{
Dictionary<LLUUID, Primitive> PrimsWaiting = new Dictionary<LLUUID, Primitive>();
AutoResetEvent AllPropertiesReceived = new AutoResetEvent(false);
public FindObjectsCommand(TestClient testClient)
{
testClient.Objects.OnObjectProperties += new ObjectManager.ObjectPropertiesCallback(Objects_OnObjectProperties);
Name = "findobjects";
Description = "Finds all objects, which name contains search-string. " +
"Usage: findobjects [radius] <search-string>";
}
public override string Execute(string[] args, LLUUID 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] : "";
// *** get current location ***
LLVector3 location = Client.Self.SimPosition;
// *** find all objects in radius ***
List<Primitive> prims = Client.Network.CurrentSim.ObjectsPrimitives.FindAll(
delegate(Primitive prim) {
LLVector3 pos = prim.Position;
return ((prim.ParentID == 0) && (pos != LLVector3.Zero) && (LLVector3.Dist(pos, location) < radius));
}
);
// *** request properties of these objects ***
bool complete = RequestObjectProperties(prims, 250);
foreach (Primitive p in prims) {
string name = p.Properties.Name;
if ((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 (LLUUID 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(Simulator simulator, LLObject.ObjectProperties properties)
{
lock (PrimsWaiting) {
Primitive prim;
if (PrimsWaiting.TryGetValue(properties.ObjectID, out prim)) {
prim.Properties = properties;
}
PrimsWaiting.Remove(properties.ObjectID);
if (PrimsWaiting.Count == 0)
AllPropertiesReceived.Set();
}
}
}
}

View File

@@ -0,0 +1,49 @@
using System;
using OpenMetaverse;
namespace OpenMetaverse.TestClient
{
public class FindTextureCommand : Command
{
public FindTextureCommand(TestClient testClient)
{
Name = "findtexture";
Description = "Checks if a specified texture is currently visible on a specified face. " +
"Usage: findtexture [face-index] [texture-uuid]";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
int faceIndex;
LLUUID textureID;
if (args.Length != 2)
return "Usage: findtexture [face-index] [texture-uuid]";
if (Int32.TryParse(args[0], out faceIndex) &&
LLUUID.TryParse(args[1], out textureID))
{
Client.Network.CurrentSim.ObjectsPrimitives.ForEach(
delegate(Primitive prim)
{
if (prim.Textures != null && prim.Textures.FaceTextures[faceIndex] != null)
{
if (prim.Textures.FaceTextures[faceIndex].TextureID == textureID)
{
Logger.Log(String.Format("Primitive {0} ({1}) has face index {2} set to {3}",
prim.ID.ToString(), prim.LocalID, faceIndex, textureID.ToString()),
Helpers.LogLevel.Info, Client);
}
}
}
);
return "Done searching";
}
else
{
return "Usage: findtexture [face-index] [texture-uuid]";
}
}
}
}

View File

@@ -0,0 +1,236 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.IO;
using OpenMetaverse;
using OpenMetaverse.StructuredData;
namespace OpenMetaverse.TestClient
{
public class ImportCommand : Command
{
private enum ImporterState
{
RezzingParent,
RezzingChildren,
Linking,
Idle
}
private class Linkset
{
public Primitive RootPrim;
public List<Primitive> Children = new List<Primitive>();
public Linkset()
{
RootPrim = new Primitive();
}
public Linkset(Primitive rootPrim)
{
RootPrim = rootPrim;
}
}
Primitive currentPrim;
LLVector3 currentPosition;
AutoResetEvent primDone = new AutoResetEvent(false);
List<Primitive> primsCreated;
List<uint> linkQueue;
uint rootLocalID;
ImporterState state = ImporterState.Idle;
public ImportCommand(TestClient testClient)
{
Name = "import";
Description = "Import prims from an exported xml file. Usage: import inputfile.xml [usegroup]";
testClient.Objects.OnNewPrim += new ObjectManager.NewPrimCallback(Objects_OnNewPrim);
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
if (args.Length < 1)
return "Usage: import inputfile.xml [usegroup]";
string filename = args[0];
LLUUID GroupID = (args.Length > 1) ? Client.GroupID : LLUUID.Zero;
string xml;
List<Primitive> prims;
try { xml = File.ReadAllText(filename); }
catch (Exception e) { return e.Message; }
try { prims = Helpers.LLSDToPrimList(LLSDParser.DeserializeXml(xml)); }
catch (Exception e) { return "Failed to deserialize " + filename + ": " + e.Message; }
// Build an organized structure from the imported prims
Dictionary<uint, Linkset> linksets = new Dictionary<uint, Linkset>();
for (int i = 0; i < prims.Count; i++)
{
Primitive prim = prims[i];
if (prim.ParentID == 0)
{
if (linksets.ContainsKey(prim.LocalID))
linksets[prim.LocalID].RootPrim = prim;
else
linksets[prim.LocalID] = new Linkset(prim);
}
else
{
if (!linksets.ContainsKey(prim.ParentID))
linksets[prim.ParentID] = new Linkset();
linksets[prim.ParentID].Children.Add(prim);
}
}
primsCreated = new List<Primitive>();
Console.WriteLine("Importing " + linksets.Count + " structures.");
foreach (Linkset linkset in linksets.Values)
{
if (linkset.RootPrim.LocalID != 0)
{
state = ImporterState.RezzingParent;
currentPrim = linkset.RootPrim;
// HACK: Import the structure just above our head
// We need a more elaborate solution for importing with relative or absolute offsets
linkset.RootPrim.Position = Client.Self.SimPosition;
linkset.RootPrim.Position.Z += 3.0f;
currentPosition = linkset.RootPrim.Position;
// Rez the root prim with no rotation
LLQuaternion rootRotation = linkset.RootPrim.Rotation;
linkset.RootPrim.Rotation = LLQuaternion.Identity;
Client.Objects.AddPrim(Client.Network.CurrentSim, linkset.RootPrim.Data, GroupID,
linkset.RootPrim.Position, linkset.RootPrim.Scale, linkset.RootPrim.Rotation);
if (!primDone.WaitOne(10000, false))
return "Rez failed, timed out while creating the root prim.";
Client.Objects.SetPosition(Client.Network.CurrentSim, primsCreated[primsCreated.Count - 1].LocalID, linkset.RootPrim.Position);
state = ImporterState.RezzingChildren;
// Rez the child prims
foreach (Primitive prim in linkset.Children)
{
currentPrim = prim;
currentPosition = prim.Position + linkset.RootPrim.Position;
Client.Objects.AddPrim(Client.Network.CurrentSim, prim.Data, GroupID, currentPosition,
prim.Scale, prim.Rotation);
if (!primDone.WaitOne(10000, false))
return "Rez failed, timed out while creating child prim.";
Client.Objects.SetPosition(Client.Network.CurrentSim, primsCreated[primsCreated.Count - 1].LocalID, currentPosition);
}
// Create a list of the local IDs of the newly created prims
List<uint> primIDs = new List<uint>(primsCreated.Count);
primIDs.Add(rootLocalID); // Root prim is first in list.
if (linkset.Children.Count != 0)
{
// Add the rest of the prims to the list of local IDs
foreach (Primitive prim in primsCreated)
{
if (prim.LocalID != rootLocalID)
primIDs.Add(prim.LocalID);
}
linkQueue = new List<uint>(primIDs.Count);
linkQueue.AddRange(primIDs);
// Link and set the permissions + rotation
state = ImporterState.Linking;
Client.Objects.LinkPrims(Client.Network.CurrentSim, linkQueue);
if (primDone.WaitOne(1000 * linkset.Children.Count, false))
Client.Objects.SetRotation(Client.Network.CurrentSim, rootLocalID, rootRotation);
else
Console.WriteLine("Warning: Failed to link {0} prims", linkQueue.Count);
}
else
{
Client.Objects.SetRotation(Client.Network.CurrentSim, rootLocalID, rootRotation);
}
// Set permissions on newly created prims
Client.Objects.SetPermissions(Client.Network.CurrentSim, primIDs,
PermissionWho.Everyone | PermissionWho.Group | PermissionWho.NextOwner,
PermissionMask.All, true);
state = ImporterState.Idle;
}
else
{
// Skip linksets with a missing root prim
Console.WriteLine("WARNING: Skipping a linkset with a missing root prim");
}
// Reset everything for the next linkset
primsCreated.Clear();
}
return "Import complete.";
}
void Objects_OnNewPrim(Simulator simulator, Primitive prim, ulong regionHandle, ushort timeDilation)
{
if ((prim.Flags & LLObject.ObjectFlags.CreateSelected) == 0)
return; // We received an update for an object we didn't create
switch (state)
{
case ImporterState.RezzingParent:
rootLocalID = prim.LocalID;
goto case ImporterState.RezzingChildren;
case ImporterState.RezzingChildren:
if (!primsCreated.Contains(prim))
{
Console.WriteLine("Setting properties for " + prim.LocalID);
// TODO: Is there a way to set all of this at once, and update more ObjectProperties stuff?
Client.Objects.SetPosition(simulator, prim.LocalID, currentPosition);
Client.Objects.SetTextures(simulator, prim.LocalID, currentPrim.Textures);
if (currentPrim.Light.Intensity > 0) {
Client.Objects.SetLight(simulator, prim.LocalID, currentPrim.Light);
}
Client.Objects.SetFlexible(simulator, prim.LocalID, currentPrim.Flexible);
if (currentPrim.Sculpt.SculptTexture != LLUUID.Zero) {
Client.Objects.SetSculpt(simulator, prim.LocalID, currentPrim.Sculpt);
}
if (!String.IsNullOrEmpty(currentPrim.Properties.Name))
Client.Objects.SetName(simulator, prim.LocalID, currentPrim.Properties.Name);
if (!String.IsNullOrEmpty(currentPrim.Properties.Description))
Client.Objects.SetDescription(simulator, prim.LocalID, currentPrim.Properties.Description);
primsCreated.Add(prim);
primDone.Set();
}
break;
case ImporterState.Linking:
lock (linkQueue)
{
int index = linkQueue.IndexOf(prim.LocalID);
if (index != -1)
{
linkQueue.RemoveAt(index);
if (linkQueue.Count == 0)
primDone.Set();
}
}
break;
}
}
}
}

View File

@@ -0,0 +1,36 @@
using System;
using OpenMetaverse;
namespace OpenMetaverse.TestClient
{
public class PrimCountCommand: Command
{
public PrimCountCommand(TestClient testClient)
{
Name = "primcount";
Description = "Shows the number of objects currently being tracked.";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
int count = 0;
lock (Client.Network.Simulators)
{
for (int i = 0; i < Client.Network.Simulators.Count; i++)
{
int avcount = Client.Network.Simulators[i].ObjectsAvatars.Count;
int primcount = Client.Network.Simulators[i].ObjectsPrimitives.Count;
Console.WriteLine("{0} (Avatars: {1} Primitives: {2})",
Client.Network.Simulators[i].Name, avcount, primcount);
count += avcount;
count += primcount;
}
}
return "Tracking a total of " + count + " objects";
}
}
}

View File

@@ -0,0 +1,69 @@
using System;
using OpenMetaverse;
namespace OpenMetaverse.TestClient
{
public class PrimInfoCommand : Command
{
public PrimInfoCommand(TestClient testClient)
{
Name = "priminfo";
Description = "Dumps information about a specified prim. " + "Usage: priminfo [prim-uuid]";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
LLUUID primID;
if (args.Length != 1)
return "Usage: priminfo [prim-uuid]";
if (LLUUID.TryParse(args[0], out primID))
{
Primitive target = Client.Network.CurrentSim.ObjectsPrimitives.Find(
delegate(Primitive prim) { return prim.ID == primID; }
);
if (target != null)
{
Logger.Log("Light: " + target.Light.ToString(), Helpers.LogLevel.Info, Client);
if (target.ParticleSys.CRC != 0)
Logger.Log("Particles: " + target.ParticleSys.ToString(), Helpers.LogLevel.Info, Client);
Logger.Log("TextureEntry:", Helpers.LogLevel.Info, Client);
if (target.Textures != null)
{
Logger.Log(String.Format("Default texure: {0}",
target.Textures.DefaultTexture.TextureID.ToString()),
Helpers.LogLevel.Info);
for (int i = 0; i < target.Textures.FaceTextures.Length; i++)
{
if (target.Textures.FaceTextures[i] != null)
{
Logger.Log(String.Format("Face {0}: {1}", i,
target.Textures.FaceTextures[i].TextureID.ToString()),
Helpers.LogLevel.Info, Client);
}
}
}
else
{
Logger.Log("null", Helpers.LogLevel.Info, Client);
}
return "Done.";
}
else
{
return "Could not find prim " + primID.ToString();
}
}
else
{
return "Usage: priminfo [prim-uuid]";
}
}
}
}

View File

@@ -0,0 +1,66 @@
using System;
using System.Text.RegularExpressions;
using OpenMetaverse;
namespace OpenMetaverse.TestClient
{
public class PrimRegexCommand : Command
{
public PrimRegexCommand(TestClient testClient)
{
Name = "primregex";
Description = "Find prim by text predicat. " +
"Usage: primregex [text predicat] (eg findprim .away.)";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
if (args.Length < 1)
return "Usage: primregex [text predicat]";
try
{
// Build the predicat from the args list
string predicatPrim = string.Empty;
for (int i = 0; i < args.Length; i++)
predicatPrim += args[i] + " ";
predicatPrim = predicatPrim.TrimEnd();
// Build Regex
Regex regexPrimName = new Regex(predicatPrim.ToLower());
// Print result
Logger.Log(string.Format("Searching prim for [{0}] ({1} prims loaded in simulator)\n", predicatPrim,
Client.Network.CurrentSim.ObjectsPrimitives.Count), Helpers.LogLevel.Info, Client);
Client.Network.CurrentSim.ObjectsPrimitives.ForEach(
delegate(Primitive prim)
{
if (prim.Text != null && regexPrimName.IsMatch(prim.Text.ToLower()))
{
Logger.Log(string.Format("\nNAME={0}\nID = {1}\nFLAGS = {2}\nTEXT = '{3}'\nDESC='{4}", prim.PropertiesFamily.Name,
prim.ID, prim.Flags.ToString(), prim.Text, prim.PropertiesFamily.Description), Helpers.LogLevel.Info, Client);
}
else if (prim.PropertiesFamily.Name != null && regexPrimName.IsMatch(prim.PropertiesFamily.Name.ToLower()))
{
Logger.Log(string.Format("\nNAME={0}\nID = {1}\nFLAGS = {2}\nTEXT = '{3}'\nDESC='{4}", prim.PropertiesFamily.Name,
prim.ID, prim.Flags.ToString(), prim.Text, prim.PropertiesFamily.Description), Helpers.LogLevel.Info, Client);
}
else if (prim.PropertiesFamily.Description != null && regexPrimName.IsMatch(prim.PropertiesFamily.Description.ToLower()))
{
Logger.Log(string.Format("\nNAME={0}\nID = {1}\nFLAGS = {2}\nTEXT = '{3}'\nDESC='{4}", prim.PropertiesFamily.Name,
prim.ID, prim.Flags.ToString(), prim.Text, prim.PropertiesFamily.Description), Helpers.LogLevel.Info, Client);
}
}
);
}
catch (System.Exception e)
{
Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e);
return "Error searching";
}
return "Done searching";
}
}
}

View File

@@ -0,0 +1,61 @@
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]";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
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.OnEventsReply += new DirectoryManager.EventReplyCallback(Directory_OnEventsReply);
Client.Directory.StartEventsSearch(searchText, true, "u", 0, DirectoryManager.EventCategories.All, LLUUID.Random());
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.OnEventsReply -= new DirectoryManager.EventReplyCallback(Directory_OnEventsReply);
return result;
}
void Directory_OnEventsReply(LLUUID queryID, List<DirectoryManager.EventsSearchData> matchedEvents)
{
if (matchedEvents[0].ID == 0 && matchedEvents.Count == 1)
{
Console.WriteLine("No Results matched your search string");
}
else
{
foreach (DirectoryManager.EventsSearchData ev in matchedEvents)
{
Console.WriteLine("Event ID: {0} Event Name: {1} Event Date: {2}", ev.ID, ev.Name, ev.Date);
}
}
resultCount = matchedEvents.Count;
waitQuery.Set();
}
}
}

View File

@@ -0,0 +1,46 @@
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]";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
if (args.Length < 1)
return "Usage: showevent [eventID] (use searchevents to get ID)";
Client.Directory.OnEventInfo += new DirectoryManager.EventInfoCallback(Directory_OnEventInfo);
uint eventID;
if (UInt32.TryParse(args[0], out eventID))
{
Client.Directory.EventInfoRequest(eventID);
return "Query Sent";
}
else
{
return "Usage: showevent [eventID] (use searchevents to get ID)";
}
}
void Directory_OnEventInfo(DirectoryManager.EventInfo matchedEvent)
{
float x,y;
Helpers.GlobalPosToRegionHandle((float)matchedEvent.GlobalPos.X, (float)matchedEvent.GlobalPos.Y, out x, out y);
StringBuilder sb = new StringBuilder();
sb.AppendFormat(" Name: {0} ({1})" + System.Environment.NewLine, matchedEvent.Name, matchedEvent.ID);
sb.AppendFormat(" Location: {0}/{1}/{2}" + System.Environment.NewLine, matchedEvent.SimName, x, y);
sb.AppendFormat(" Date: {0}" + System.Environment.NewLine, matchedEvent.Date);
sb.AppendFormat("Description: {0}" + System.Environment.NewLine, matchedEvent.Desc);
Console.WriteLine(sb.ToString());
}
}
}

View File

@@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Text;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace OpenMetaverse.TestClient
{
public class DilationCommand : Command
{
public DilationCommand(TestClient testClient)
{
Name = "dilation";
Description = "Shows time dilation for current sim.";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
return "Dilation is " + Client.Network.CurrentSim.Stats.Dilation.ToString();
}
}
}

View File

@@ -0,0 +1,50 @@
using System;
using System.Text;
using OpenMetaverse;
namespace OpenMetaverse.TestClient
{
public class RegionInfoCommand : Command
{
public RegionInfoCommand(TestClient testClient)
{
Name = "regioninfo";
Description = "Prints out info about all the current region";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
StringBuilder output = new StringBuilder();
output.AppendLine(Client.Network.CurrentSim.ToString());
output.Append("UUID: ");
output.AppendLine(Client.Network.CurrentSim.ID.ToString());
uint x, y;
Helpers.LongToUInts(Client.Network.CurrentSim.Handle, out x, out y);
output.AppendLine(String.Format("Handle: {0} (X: {1} Y: {2})", Client.Network.CurrentSim.Handle, x, y));
output.Append("Access: ");
output.AppendLine(Client.Network.CurrentSim.Access.ToString());
output.Append("Flags: ");
output.AppendLine(Client.Network.CurrentSim.Flags.ToString());
output.Append("TerrainBase0: ");
output.AppendLine(Client.Network.CurrentSim.TerrainBase0.ToString());
output.Append("TerrainBase1: ");
output.AppendLine(Client.Network.CurrentSim.TerrainBase1.ToString());
output.Append("TerrainBase2: ");
output.AppendLine(Client.Network.CurrentSim.TerrainBase2.ToString());
output.Append("TerrainBase3: ");
output.AppendLine(Client.Network.CurrentSim.TerrainBase3.ToString());
output.Append("TerrainDetail0: ");
output.AppendLine(Client.Network.CurrentSim.TerrainDetail0.ToString());
output.Append("TerrainDetail1: ");
output.AppendLine(Client.Network.CurrentSim.TerrainDetail1.ToString());
output.Append("TerrainDetail2: ");
output.AppendLine(Client.Network.CurrentSim.TerrainDetail2.ToString());
output.Append("TerrainDetail3: ");
output.AppendLine(Client.Network.CurrentSim.TerrainDetail3.ToString());
output.Append("Water Height: ");
output.AppendLine(Client.Network.CurrentSim.WaterHeight.ToString());
return output.ToString();
}
}
}

View File

@@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Text;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace OpenMetaverse.TestClient
{
public class StatsCommand : Command
{
public StatsCommand(TestClient testClient)
{
Name = "stats";
Description = "Provide connection figures and statistics";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
StringBuilder output = new StringBuilder();
lock (Client.Network.Simulators)
{
for (int i = 0; i < Client.Network.Simulators.Count; i++)
{
Simulator sim = Client.Network.Simulators[i];
output.AppendLine(String.Format(
"[{0}] Dilation: {1} InBPS: {2} OutBPS: {3} ResentOut: {4} ResentIn: {5}",
sim.ToString(), sim.Stats.Dilation, sim.Stats.IncomingBPS, sim.Stats.OutgoingBPS,
sim.Stats.ResentPackets, sim.Stats.ReceivedResends));
}
}
Simulator csim = Client.Network.CurrentSim;
output.Append("Packets in the queue: " + Client.Network.InboxCount);
output.AppendLine(String.Format("FPS : {0} PhysicsFPS : {1} AgentUpdates : {2} Objects : {3} Scripted Objects : {4}",
csim.Stats.FPS, csim.Stats.PhysicsFPS, csim.Stats.AgentUpdates, csim.Stats.Objects, csim.Stats.ScriptedObjects));
output.AppendLine(String.Format("Frame Time : {0} Net Time : {1} Image Time : {2} Physics Time : {3} Script Time : {4} Other Time : {5}",
csim.Stats.FrameTime, csim.Stats.NetTime, csim.Stats.ImageTime, csim.Stats.PhysicsTime, csim.Stats.ScriptTime, csim.Stats.OtherTime));
output.AppendLine(String.Format("Agents : {0} Child Agents : {1} Active Scripts : {2}",
csim.Stats.Agents, csim.Stats.ChildAgents, csim.Stats.ActiveScripts));
return output.ToString();
}
}
}

View File

@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Text;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace OpenMetaverse.TestClient
{
public class UptimeCommand : Command
{
public DateTime Created = DateTime.Now;
public UptimeCommand(TestClient testClient)
{
Name = "uptime";
Description = "Shows the login name, login time and length of time logged on.";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
string name = Client.ToString();
return "I am " + name + ", Up Since: " + Created + " (" + (DateTime.Now - Created) + ")";
}
}
}

View File

@@ -0,0 +1,52 @@
using System;
using System.Collections.Generic;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace OpenMetaverse.TestClient
{
public class DebugCommand : Command
{
public DebugCommand(TestClient testClient)
{
Name = "debug";
Description = "Turn debug messages on or off. Usage: debug [level] where level is one of None, Debug, Error, Info, Warn";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
if (args.Length != 1)
return "Usage: debug [level] where level is one of None, Debug, Error, Info, Warn";
if (args[0].ToLower() == "debug")
{
Settings.LOG_LEVEL = Helpers.LogLevel.Debug;
return "Logging is set to Debug";
}
else if (args[0].ToLower() == "none")
{
Settings.LOG_LEVEL = Helpers.LogLevel.None;
return "Logging is set to None";
}
else if (args[0].ToLower() == "warn")
{
Settings.LOG_LEVEL = Helpers.LogLevel.Warning;
return "Logging is set to level Warning";
}
else if (args[0].ToLower() == "info")
{
Settings.LOG_LEVEL = Helpers.LogLevel.Info;
return "Logging is set to level Info";
}
else if (args[0].ToLower() == "error")
{
Settings.LOG_LEVEL = Helpers.LogLevel.Error;
return "Logging is set to level Error";
}
else
{
return "Usage: debug [level] where level is one of None, Debug, Error, Info, Warn";
}
}
}
}

View File

@@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Text;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace OpenMetaverse.TestClient
{
public class HelpCommand: Command
{
public HelpCommand(TestClient testClient)
{
Name = "help";
Description = "Lists available commands.";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
StringBuilder result = new StringBuilder();
result.AppendFormat("\n\nHELP\nClient accept teleport lures from master and group members.\n");
foreach (Command c in Client.Commands.Values)
{
result.AppendFormat(" * {0} - {1}\n", c.Name, c.Description);
}
return result.ToString();
}
}
}

View File

@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace OpenMetaverse.TestClient
{
public class LoadCommand: Command
{
public LoadCommand(TestClient testClient)
{
Name = "load";
Description = "Loads commands from a dll. (Usage: load AssemblyNameWithoutExtension)";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
if (args.Length < 1)
return "Usage: load AssemblyNameWithoutExtension";
string filename = AppDomain.CurrentDomain.BaseDirectory + args[0] + ".dll";
Client.RegisterAllCommands(Assembly.LoadFile(filename));
return "Assembly " + filename + " loaded.";
}
}
}

View File

@@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace OpenMetaverse.TestClient
{
public class LoginCommand : Command
{
public LoginCommand(TestClient testClient)
{
Name = "login";
Description = "Logs in another avatar";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
if (args.Length != 3 && args.Length != 4)
return "usage: login firstname lastname password [simname]";
GridClient newClient = Client.ClientManager.Login(args);
if (newClient.Network.Connected)
{
return "Logged in " + newClient.ToString();
}
else
{
return "Failed to login: " + newClient.Network.LoginMessage;
}
}
}
}

View File

@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Text;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace OpenMetaverse.TestClient
{
public class LogoutCommand : Command
{
public LogoutCommand(TestClient testClient)
{
Name = "logout";
Description = "Log this avatar out";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
string name = Client.ToString();
Client.ClientManager.Logout(Client);
return "Logged " + name + " out";
}
}
}

View File

@@ -0,0 +1,22 @@
using System;
using OpenMetaverse;
namespace OpenMetaverse.TestClient
{
public class MD5Command : Command
{
public MD5Command(TestClient testClient)
{
Name = "md5";
Description = "Creates an MD5 hash from a given password. Usage: md5 [password]";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
if (args.Length == 1)
return Helpers.MD5(args[0]);
else
return "Usage: md5 [password]";
}
}
}

View File

@@ -0,0 +1,22 @@
using System;
using OpenMetaverse;
namespace OpenMetaverse.TestClient
{
public class PacketLogCommand : Command
{
public PacketLogCommand(TestClient testClient)
{
Name = "packetlog";
Description = "Logs a given number of packets to an xml file. Usage: packetlog 10 tenpackets.xml";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
if (args.Length != 2)
return "Usage: packetlog 10 tenpackets.xml";
return "This function is currently unimplemented";
}
}
}

View File

@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Text;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace OpenMetaverse.TestClient
{
public class QuitCommand: Command
{
public QuitCommand(TestClient testClient)
{
Name = "quit";
Description = "Log all avatars out and shut down";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
Client.ClientManager.LogoutAll();
Client.ClientManager.Running = false;
return "All avatars logged out";
}
}
}

View File

@@ -0,0 +1,68 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace OpenMetaverse.TestClient
{
public class SetMasterCommand: Command
{
public DateTime Created = DateTime.Now;
private LLUUID resolvedMasterKey = LLUUID.Zero;
private ManualResetEvent keyResolution = new ManualResetEvent(false);
private LLUUID query = LLUUID.Zero;
public SetMasterCommand(TestClient testClient)
{
Name = "setmaster";
Description = "Sets the user name of the master user. The master user can IM to run commands. Usage: setmaster [name]";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
string masterName = String.Empty;
for (int ct = 0; ct < args.Length;ct++)
masterName = masterName + args[ct] + " ";
masterName = masterName.TrimEnd();
if (masterName.Length == 0)
return "Usage: setmaster [name]";
DirectoryManager.DirPeopleReplyCallback callback = new DirectoryManager.DirPeopleReplyCallback(KeyResolvHandler);
Client.Directory.OnDirPeopleReply += callback;
query = Client.Directory.StartPeopleSearch(DirectoryManager.DirFindFlags.People, masterName, 0);
if (keyResolution.WaitOne(TimeSpan.FromMinutes(1), false))
{
Client.MasterKey = resolvedMasterKey;
keyResolution.Reset();
Client.Directory.OnDirPeopleReply -= callback;
}
else
{
keyResolution.Reset();
Client.Directory.OnDirPeopleReply -= callback;
return "Unable to obtain UUID for \"" + masterName + "\". Master unchanged.";
}
// Send an Online-only IM to the new master
Client.Self.InstantMessage(
Client.MasterKey, "You are now my master. IM me with \"help\" for a command list.");
return String.Format("Master set to {0} ({1})", masterName, Client.MasterKey.ToString());
}
private void KeyResolvHandler(LLUUID queryid, List<DirectoryManager.AgentSearchData> matches)
{
if (query != queryid)
return;
resolvedMasterKey = matches[0].AgentID;
keyResolution.Set();
query = LLUUID.Zero;
}
}
}

View File

@@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;
using System.Text;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace OpenMetaverse.TestClient
{
public class SetMasterKeyCommand : Command
{
public DateTime Created = DateTime.Now;
public SetMasterKeyCommand(TestClient testClient)
{
Name = "setMasterKey";
Description = "Sets the key of the master user. The master user can IM to run commands.";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
Client.MasterKey = LLUUID.Parse(args[0]);
lock (Client.Network.Simulators)
{
for (int i = 0; i < Client.Network.Simulators.Count; i++)
{
Avatar master = Client.Network.Simulators[i].ObjectsAvatars.Find(
delegate(Avatar avatar)
{
return avatar.ID == Client.MasterKey;
}
);
if (master != null)
{
Client.Self.InstantMessage(master.ID,
"You are now my master. IM me with \"help\" for a command list.");
break;
}
}
}
return "Master set to " + Client.MasterKey.ToString();
}
}
}

View File

@@ -0,0 +1,76 @@
using System;
using OpenMetaverse;
namespace OpenMetaverse.TestClient
{
public class ShowEffectsCommand : Command
{
bool ShowEffects = false;
public ShowEffectsCommand(TestClient testClient)
{
Name = "showeffects";
Description = "Prints out information for every viewer effect that is received. Usage: showeffects [on/off]";
testClient.Avatars.OnEffect += new AvatarManager.EffectCallback(Avatars_OnEffect);
testClient.Avatars.OnLookAt += new AvatarManager.LookAtCallback(Avatars_OnLookAt);
testClient.Avatars.OnPointAt += new AvatarManager.PointAtCallback(Avatars_OnPointAt);
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
if (args.Length == 0)
{
ShowEffects = true;
return "Viewer effects will be shown on the console";
}
else if (args.Length == 1)
{
if (args[0] == "on")
{
ShowEffects = true;
return "Viewer effects will be shown on the console";
}
else
{
ShowEffects = false;
return "Viewer effects will not be shown";
}
}
else
{
return "Usage: showeffects [on/off]";
}
}
private void Avatars_OnPointAt(LLUUID sourceID, LLUUID targetID, LLVector3d targetPos,
PointAtType pointType, float duration, LLUUID id)
{
if (ShowEffects)
Console.WriteLine(
"ViewerEffect [PointAt]: SourceID: {0} TargetID: {1} TargetPos: {2} Type: {3} Duration: {4} ID: {5}",
sourceID.ToString(), targetID.ToString(), targetPos, pointType, duration,
id.ToString());
}
private void Avatars_OnLookAt(LLUUID sourceID, LLUUID targetID, LLVector3d targetPos,
LookAtType lookType, float duration, LLUUID id)
{
if (ShowEffects)
Console.WriteLine(
"ViewerEffect [LookAt]: SourceID: {0} TargetID: {1} TargetPos: {2} Type: {3} Duration: {4} ID: {5}",
sourceID.ToString(), targetID.ToString(), targetPos, lookType, duration,
id.ToString());
}
private void Avatars_OnEffect(EffectType type, LLUUID sourceID, LLUUID targetID,
LLVector3d targetPos, float duration, LLUUID id)
{
if (ShowEffects)
Console.WriteLine(
"ViewerEffect [{0}]: SourceID: {1} TargetID: {2} TargetPos: {3} Duration: {4} ID: {5}",
type, sourceID.ToString(), targetID.ToString(), targetPos, duration,
id.ToString());
}
}
}

View File

@@ -0,0 +1,43 @@
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";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
LLUUID target;
if (args.Length != 1)
return "Usage: touch UUID";
if (LLUUID.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];
}
}
}

View File

@@ -0,0 +1,50 @@
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.";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
if (args.Length == 1)
{
try
{
string treeName = args[0].Trim(new char[] { ' ' });
Tree tree = (Tree)Enum.Parse(typeof(Tree), treeName);
LLVector3 treePosition = Client.Self.SimPosition;
treePosition.Z += 3.0f;
Client.Objects.AddTree(Client.Network.CurrentSim, new LLVector3(0.5f, 0.5f, 0.5f),
LLQuaternion.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;
}
}
}

View File

@@ -0,0 +1,68 @@
using System;
using System.Collections.Generic;
using System.Threading;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace OpenMetaverse.TestClient
{
public class ParcelVoiceInfoCommand : Command
{
private AutoResetEvent ParcelVoiceInfoEvent = new AutoResetEvent(false);
private string VoiceRegionName = null;
private int VoiceLocalID = -1;
private string VoiceChannelURI = null;
public ParcelVoiceInfoCommand(TestClient testClient)
{
Name = "voiceparcel";
Description = "obtain parcel voice info. Usage: voiceparcel";
Client = testClient;
}
private bool registered = false;
private bool IsVoiceManagerRunning()
{
if (null == Client.VoiceManager) return false;
if (!registered)
{
Client.VoiceManager.OnParcelVoiceInfo += Voice_OnParcelVoiceInfo;
registered = true;
}
return true;
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
if (!IsVoiceManagerRunning())
return String.Format("VoiceManager not running for {0}", fromAgentID);
if (!Client.VoiceManager.RequestParcelVoiceInfo())
{
return "RequestParcelVoiceInfo failed. Not available for the current grid?";
}
ParcelVoiceInfoEvent.WaitOne(30 * 1000, false);
if (String.IsNullOrEmpty(VoiceRegionName) && -1 == VoiceLocalID)
{
return String.Format("Parcel Voice Info request for {0} failed.", Client.Self.Name);
}
return String.Format("Parcel Voice Info request for {0}: region name \"{1}\", parcel local id {2}, channel URI {3}",
Client.Self.Name, VoiceRegionName, VoiceLocalID, VoiceChannelURI);
}
void Voice_OnParcelVoiceInfo(string regionName, int localID, string channelURI)
{
VoiceRegionName = regionName;
VoiceLocalID = localID;
VoiceChannelURI = channelURI;
ParcelVoiceInfoEvent.Set();
}
}
}

View File

@@ -0,0 +1,66 @@
using System;
using System.Collections.Generic;
using System.Threading;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace OpenMetaverse.TestClient
{
public class VoiceAccountCommand : Command
{
private AutoResetEvent ProvisionEvent = new AutoResetEvent(false);
private string VoiceAccount = null;
private string VoicePassword = null;
public VoiceAccountCommand(TestClient testClient)
{
Name = "voiceaccount";
Description = "obtain voice account info. Usage: voiceaccount";
Client = testClient;
}
private bool registered = false;
private bool IsVoiceManagerRunning()
{
if (null == Client.VoiceManager) return false;
if (!registered)
{
Client.VoiceManager.OnProvisionAccount += Voice_OnProvisionAccount;
registered = true;
}
return true;
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
if (!IsVoiceManagerRunning())
return String.Format("VoiceManager not running for {0}", Client.Self.Name);
if (!Client.VoiceManager.RequestProvisionAccount())
{
return "RequestProvisionAccount failed. Not available for the current grid?";
}
ProvisionEvent.WaitOne(30 * 1000, false);
if (String.IsNullOrEmpty(VoiceAccount) && String.IsNullOrEmpty(VoicePassword))
{
return String.Format("Voice account information lookup for {0} failed.", Client.Self.Name);
}
return String.Format("Voice Account for {0}: user \"{1}\", password \"{2}\"",
Client.Self.Name, VoiceAccount, VoicePassword);
}
void Voice_OnProvisionAccount(string username, string password)
{
VoiceAccount = username;
VoicePassword = password;
ProvisionEvent.Set();
}
}
}

View File

@@ -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.";
}
public override string Execute(string[] args, LLUUID 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}/{3}, UUID: {4})", av.Name,
av.GroupName, (av.CurrentSim != null ? av.CurrentSim.Name : String.Empty),
av.Position, av.ID.ToString());
}
);
}
}
return result.ToString();
}
}
}

View File

@@ -0,0 +1,88 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace OpenMetaverse.TestClient
{
class Parsing
{
public static string[] ParseArguments(string str)
{
List<string> list = new List<string>();
string current = String.Empty;
string trimmed = null;
bool withinQuote = false;
bool escaped = false;
foreach (char c in str)
{
if (c == '"')
{
if (escaped)
{
current += '"';
escaped = false;
}
else
{
current += '"';
withinQuote = !withinQuote;
}
}
else if (c == ' ' || c == '\t')
{
if (escaped || withinQuote)
{
current += c;
escaped = false;
}
else
{
trimmed = current.Trim();
if (trimmed.StartsWith("\"") && trimmed.EndsWith("\""))
{
trimmed = trimmed.Remove(0, 1);
trimmed = trimmed.Remove(trimmed.Length - 1);
trimmed = trimmed.Trim();
}
if (trimmed.Length > 0)
list.Add(trimmed);
current = String.Empty;
}
}
else if (c == '\\')
{
if (escaped)
{
current += '\\';
escaped = false;
}
else
{
escaped = true;
}
}
else
{
if (escaped)
throw new FormatException(c.ToString() + " is not an escapable character.");
current += c;
}
}
trimmed = current.Trim();
if (trimmed.StartsWith("\"") && trimmed.EndsWith("\""))
{
trimmed = trimmed.Remove(0, 1);
trimmed = trimmed.Remove(trimmed.Length - 1);
trimmed = trimmed.Trim();
}
if (trimmed.Length > 0)
list.Add(trimmed);
return list.ToArray();
}
}
}

View File

@@ -0,0 +1,155 @@
using System;
using System.Collections.Generic;
using System.IO;
using CommandLine.Utility;
namespace OpenMetaverse.TestClient
{
public class CommandLineArgumentsException : Exception
{
}
public class Program
{
private static void Usage()
{
Console.WriteLine("Usage: " + Environment.NewLine +
"TestClient.exe --first firstname --last lastname --pass password --contact \"youremail\" [--startpos \"sim/x/y/z\"] [--master \"master name\"] [--masterkey \"master uuid\"] --loginuri=\"uri\"");
}
static void Main(string[] args)
{
Arguments arguments = new Arguments(args);
ClientManager manager;
List<LoginDetails> accounts = new List<LoginDetails>();
LoginDetails account;
bool groupCommands = false;
string masterName = String.Empty;
LLUUID masterKey = LLUUID.Zero;
string file = String.Empty;
string loginuri = String.Empty;
try
{
if (arguments["groupcommands"] != null)
{
groupCommands = true;
}
if (arguments["masterkey"] != null)
{
masterKey = LLUUID.Parse(arguments["masterkey"]);
}
if (arguments["master"] != null)
{
masterName = arguments["master"];
}
if (arguments["loginuri"] != null)
{
loginuri = arguments["loginuri"];
}
if (arguments["file"] != null)
{
file = arguments["file"];
if (!File.Exists(file))
{
Console.WriteLine("File {0} Does not exist", file);
return;
}
// Loading names from a file
try
{
using (StreamReader reader = new StreamReader(file))
{
string line;
int lineNumber = 0;
while ((line = reader.ReadLine()) != null)
{
lineNumber++;
string[] tokens = line.Trim().Split(new char[] { ' ', ',' });
if (tokens.Length >= 3)
{
account = new LoginDetails();
account.FirstName = tokens[0];
account.LastName = tokens[1];
account.Password = tokens[2];
accounts.Add(account);
// Leaving this out until we have per-account masters (if that
// is desirable). For now the command-line option can
// specify the single master that TestClient supports
//if (tokens.Length == 5)
//{
// master = tokens[3] + " " + tokens[4];
//}
}
else
{
Console.WriteLine("Invalid data on line " + lineNumber +
", must be in the format of: FirstName LastName Password");
}
}
}
}
catch (Exception e)
{
Console.WriteLine("Error reading from " + args[1]);
Console.WriteLine(e.ToString());
return;
}
}
else if (arguments["first"] != null && arguments["last"] != null && arguments["pass"] != null)
{
// Taking a single login off the command-line
account = new LoginDetails();
account.FirstName = arguments["first"];
account.LastName = arguments["last"];
account.Password = arguments["pass"];
accounts.Add(account);
}
else
{
throw new CommandLineArgumentsException();
}
}
catch (CommandLineArgumentsException)
{
Usage();
return;
}
foreach (LoginDetails a in accounts)
{
a.GroupCommands = groupCommands;
a.MasterName = masterName;
a.MasterKey = masterKey;
a.URI = loginuri;
}
// Login the accounts and run the input loop
if (arguments["startpos"] != null)
{
manager = new ClientManager(accounts, arguments["startpos"]);
}
else
{
manager = new ClientManager(accounts);
}
manager.Run();
}
}
}

View File

@@ -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("TestClient")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("TestClient")]
[assembly: AssemblyCopyright("Copyright © 2006")]
[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("0563f706-7fa9-42f6-bf23-c6acd1175964")]
// 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")]

View File

@@ -0,0 +1,126 @@
<?xml version="1.0"?>
<project
name="libsecondlife"
default="build">
<!-- global framework settings -->
<property
name="target.framework"
value="${framework::get-target-framework()}" />
<property
name="assembly.dir"
value="${framework::get-assembly-directory(target.framework)}" />
<!-- global project settings -->
<xmlpeek
file="../../../libsecondlife.build"
xpath="/project/property[@name = 'project.version']/@value"
property="project.version" />
<property
name="build.number"
value="${math::abs(math::floor(timespan::get-total-days(datetime::now()
- datetime::parse('01/01/2002'))))}" />
<property
name="assembly"
value="TestClient"/>
<property
name="bin_dir"
value="../../../bin" />
<!-- default configuration -->
<property
name="project.config"
value="debug" /> <!-- debug|release -->
<!-- named configurations -->
<target
name="init"
description="Initializes build properties">
<call target="${project.config}" />
</target>
<target
name="debug"
description="configures a debug build">
<property
name="build.debug"
value="true" />
<property
name="package.name"
value="${project::get-name()}-${project.version}-${project.config}" />
<property
name="assembly.configuration"
value="${framework::get-target-framework()}.${platform::get-name()} [${project.config}]" />
</target>
<target
name="release"
description="configures a release build">
<property
name="project.config"
value="release" />
<property
name="build.debug"
value="false" />
<property
name="package.name"
value="${project::get-name()}-${project.version}" />
<property
name="assembly.configuration"
value="${framework::get-target-framework()}.${platform::get-name()}" />
</target>
<!-- build tasks -->
<target
name="build"
depends="init"
description="Builds the binaries for the current configuration">
<echo message="Build Directory is ${bin_dir}/" />
<mkdir
dir="${bin_dir}"
failonerror="false" />
<csc
target="exe"
debug="${build.debug}"
output="${bin_dir}/${assembly}.exe">
<sources failonempty="true">
<include name="*.cs" />
<include name="Commands/**.cs" />
<exclude name="Commands/Communication/TtsCommand.cs" />
</sources>
<references basedir="${bin_dir}/">
<include name="libsecondlife.dll"/>
<include name="openjpegnet.dll"/>
<include name="System.Drawing.dll" />
</references>
</csc>
</target>
<target
name="build-dll"
description="Builds libsecondlife dll">
<nant
buildfile="../../libsecondlife-cs/libsecondlife.build"
target="${project.config} build"/>
</target>
<target
name="clean"
depends="init"
description="Deletes the current configuration">
<delete failonerror="false">
<fileset basedir="${bin_dir}/">
<include name="${assembly}.exe" />
<include name="${assembly}.pdb" />
<include name="**/${assembly}.*.resources" />
</fileset>
</delete>
</target>
<target
name="*"
description="Handles unknown targets">
<echo message="skip" />
</target>
</project>

View File

@@ -0,0 +1,263 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Xml;
using OpenMetaverse;
using OpenMetaverse.Packets;
using OpenMetaverse.Utilities;
namespace OpenMetaverse.TestClient
{
public class TestClient : GridClient
{
public LLUUID GroupID = LLUUID.Zero;
public Dictionary<LLUUID, GroupMember> GroupMembers;
public Dictionary<LLUUID, AvatarAppearancePacket> Appearances = new Dictionary<LLUUID, AvatarAppearancePacket>();
public Dictionary<string, Command> Commands = new Dictionary<string,Command>();
public bool Running = true;
public bool GroupCommands = false;
public string MasterName = String.Empty;
public LLUUID MasterKey = LLUUID.Zero;
public ClientManager ClientManager;
public VoiceManager VoiceManager;
// Shell-like inventory commands need to be aware of the 'current' inventory folder.
public InventoryFolder CurrentDirectory = null;
private LLQuaternion bodyRotation = LLQuaternion.Identity;
private LLVector3 forward = new LLVector3(0, 0.9999f, 0);
private LLVector3 left = new LLVector3(0.9999f, 0, 0);
private LLVector3 up = new LLVector3(0, 0, 0.9999f);
private System.Timers.Timer updateTimer;
/// <summary>
///
/// </summary>
public TestClient(ClientManager manager)
{
ClientManager = manager;
updateTimer = new System.Timers.Timer(500);
updateTimer.Elapsed += new System.Timers.ElapsedEventHandler(updateTimer_Elapsed);
RegisterAllCommands(Assembly.GetExecutingAssembly());
Settings.LOG_LEVEL = Helpers.LogLevel.Debug;
Settings.LOG_RESENDS = false;
Settings.STORE_LAND_PATCHES = true;
Settings.ALWAYS_DECODE_OBJECTS = true;
Settings.ALWAYS_REQUEST_OBJECTS = true;
Settings.SEND_AGENT_UPDATES = true;
Settings.USE_TEXTURE_CACHE = true;
Network.RegisterCallback(PacketType.AgentDataUpdate, new NetworkManager.PacketCallback(AgentDataUpdateHandler));
Network.OnLogin += new NetworkManager.LoginCallback(LoginHandler);
Self.OnInstantMessage += new AgentManager.InstantMessageCallback(Self_OnInstantMessage);
Groups.OnGroupMembers += new GroupManager.GroupMembersCallback(GroupMembersHandler);
Inventory.OnObjectOffered += new InventoryManager.ObjectOfferedCallback(Inventory_OnInventoryObjectReceived);
Network.RegisterCallback(PacketType.AvatarAppearance, new NetworkManager.PacketCallback(AvatarAppearanceHandler));
Network.RegisterCallback(PacketType.AlertMessage, new NetworkManager.PacketCallback(AlertMessageHandler));
VoiceManager = new VoiceManager(this);
updateTimer.Start();
}
/// <summary>
/// Initialize everything that needs to be initialized once we're logged in.
/// </summary>
/// <param name="login">The status of the login</param>
/// <param name="message">Error message on failure, MOTD on success.</param>
public void LoginHandler(LoginStatus login, string message)
{
if (login == LoginStatus.Success)
{
// Start in the inventory root folder.
CurrentDirectory = Inventory.Store.RootFolder;
}
}
public void RegisterAllCommands(Assembly assembly)
{
foreach (Type t in assembly.GetTypes())
{
try
{
if (t.IsSubclassOf(typeof(Command)))
{
ConstructorInfo info = t.GetConstructor(new Type[] { typeof(TestClient) });
Command command = (Command)info.Invoke(new object[] { this });
RegisterCommand(command);
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
public void RegisterCommand(Command command)
{
command.Client = this;
if (!Commands.ContainsKey(command.Name.ToLower()))
{
Commands.Add(command.Name.ToLower(), command);
}
}
//breaks up large responses to deal with the max IM size
private void SendResponseIM(GridClient client, LLUUID fromAgentID, string data)
{
for ( int i = 0 ; i < data.Length ; i += 1024 ) {
int y;
if ((i + 1023) > data.Length)
{
y = data.Length - i;
}
else
{
y = 1023;
}
string message = data.Substring(i, y);
client.Self.InstantMessage(fromAgentID, message);
}
}
public void DoCommand(string cmd, LLUUID fromAgentID)
{
string[] tokens;
try { tokens = Parsing.ParseArguments(cmd); }
catch (FormatException ex) { Console.WriteLine(ex.Message); return; }
if (tokens.Length == 0)
return;
string firstToken = tokens[0].ToLower();
// "all balance" will send the balance command to all currently logged in bots
if (firstToken == "all" && tokens.Length > 1)
{
cmd = String.Empty;
// Reserialize all of the arguments except for "all"
for (int i = 1; i < tokens.Length; i++)
{
cmd += tokens[i] + " ";
}
ClientManager.DoCommandAll(cmd, fromAgentID);
return;
}
if (Commands.ContainsKey(firstToken))
{
string[] args = new string[tokens.Length - 1];
Array.Copy(tokens, 1, args, 0, args.Length);
string response = Commands[firstToken].Execute(args, fromAgentID);
if (!String.IsNullOrEmpty(response))
{
Console.WriteLine(response);
if (fromAgentID != LLUUID.Zero && Network.Connected)
{
// IMs don't like \r\n line endings, clean them up first
response = response.Replace("\r", String.Empty);
SendResponseIM(this, fromAgentID, response);
}
}
}
}
private void updateTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
foreach (Command c in Commands.Values)
if (c.Active)
c.Think();
}
private void AgentDataUpdateHandler(Packet packet, Simulator sim)
{
AgentDataUpdatePacket p = (AgentDataUpdatePacket)packet;
if (p.AgentData.AgentID == sim.Client.Self.AgentID)
{
Console.WriteLine("Got the group ID for " + sim.Client.ToString() + ", requesting group members...");
GroupID = p.AgentData.ActiveGroupID;
sim.Client.Groups.RequestGroupMembers(GroupID);
}
}
private void GroupMembersHandler(Dictionary<LLUUID, GroupMember> members)
{
Console.WriteLine("Got " + members.Count + " group members.");
GroupMembers = members;
}
private void AvatarAppearanceHandler(Packet packet, Simulator simulator)
{
AvatarAppearancePacket appearance = (AvatarAppearancePacket)packet;
lock (Appearances) Appearances[appearance.Sender.ID] = appearance;
}
private void AlertMessageHandler(Packet packet, Simulator simulator)
{
AlertMessagePacket message = (AlertMessagePacket)packet;
Logger.Log("[AlertMessage] " + Helpers.FieldToUTF8String(message.AlertData.Message), Helpers.LogLevel.Info, this);
}
private void Self_OnInstantMessage(InstantMessage im, Simulator simulator)
{
bool groupIM = im.GroupIM && GroupMembers != null && GroupMembers.ContainsKey(im.FromAgentID) ? true : false;
if (im.FromAgentID == MasterKey || (GroupCommands && groupIM))
{
// Received an IM from someone that is authenticated
Console.WriteLine("<{0} ({1})> {2}: {3} (@{4}:{5})", im.GroupIM ? "GroupIM" : "IM", im.Dialog, im.FromAgentName, im.Message, im.RegionID, im.Position);
if (im.Dialog == InstantMessageDialog.RequestTeleport)
{
Console.WriteLine("Accepting teleport lure.");
Self.TeleportLureRespond(im.FromAgentID, true);
}
else if (
im.Dialog == InstantMessageDialog.MessageFromAgent ||
im.Dialog == InstantMessageDialog.MessageFromObject)
{
DoCommand(im.Message, im.FromAgentID);
}
}
else
{
// Received an IM from someone that is not the bot's master, ignore
Console.WriteLine("<{0} ({1})> {2} (not master): {3} (@{4}:{5})", im.GroupIM ? "GroupIM" : "IM", im.Dialog, im.FromAgentName, im.Message,
im.RegionID, im.Position);
return;
}
}
private bool Inventory_OnInventoryObjectReceived(InstantMessage offer, AssetType type,
LLUUID objectID, bool fromTask)
{
if (MasterKey != LLUUID.Zero)
{
if (offer.FromAgentID != MasterKey)
return false;
}
else if (GroupMembers != null && !GroupMembers.ContainsKey(offer.FromAgentID))
{
return false;
}
return true;
}
}
}

View File

@@ -0,0 +1,159 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.50727</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{B87682F6-B2D7-4C4D-A529-400C24FD4880}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>OpenMetaverse.TestClient</RootNamespace>
<AssemblyName>TestClient</AssemblyName>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\..\..\bin\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>..\..\..\bin\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release-docs|AnyCPU' ">
<OutputPath>..\..\..\bin\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<CodeAnalysisRuleAssemblies>C:\Program Files\Microsoft Visual Studio 8\Team Tools\Static Analysis Tools\FxCop\\rules</CodeAnalysisRuleAssemblies>
<CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
<CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
<ErrorReport>prompt</ErrorReport>
<DocumentationFile>..\..\..\bin\TestClient.XML</DocumentationFile>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Drawing" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Arguments.cs" />
<Compile Include="Command.cs" />
<Compile Include="ClientManager.cs" />
<Compile Include="Commands\Appearance\AppearanceCommand.cs" />
<Compile Include="Commands\Appearance\AttachmentsCommand.cs" />
<Compile Include="Commands\Appearance\AvatarInfoCommand.cs" />
<Compile Include="Commands\Appearance\CloneCommand.cs" />
<Compile Include="Commands\Appearance\WearCommand.cs" />
<Compile Include="Commands\CloneProfileCommand.cs" />
<Compile Include="Commands\Communication\EchoMasterCommand.cs" />
<Compile Include="Commands\Communication\IMCommand.cs" />
<Compile Include="Commands\Communication\IMGroupCommand.cs" />
<Compile Include="Commands\Communication\SayCommand.cs" />
<Compile Include="Commands\Communication\ShoutCommand.cs" />
<Compile Include="Commands\Communication\WhisperCommand.cs" />
<Compile Include="Commands\DetectBotCommand.cs" />
<Compile Include="Commands\Friends\FriendsCommand.cs" />
<Compile Include="Commands\Friends\MapFriendCommand.cs" />
<Compile Include="Commands\GoHome.cs" />
<Compile Include="Commands\GotoLandmark.cs" />
<Compile Include="Commands\Groups\ActivateGroupCommand.cs" />
<Compile Include="Commands\Groups\GroupsCommand.cs" />
<Compile Include="Commands\Groups\JoinGroupCommand.cs" />
<Compile Include="Commands\Groups\LeaveGroupCommand.cs" />
<Compile Include="Commands\Inventory\BackupCommand.cs" />
<Compile Include="Commands\Inventory\BalanceCommand.cs" />
<Compile Include="Commands\Inventory\ChangeDirectoryCommand.cs" />
<Compile Include="Commands\Inventory\DeleteFolderCommand.cs" />
<Compile Include="Commands\Inventory\DumpOutfitCommand.cs" />
<Compile Include="Commands\Inventory\ExportOutfitCommand.cs" />
<Compile Include="Commands\Inventory\GiveAllCommand.cs" />
<Compile Include="Commands\Inventory\GiveItemCommand.cs" />
<Compile Include="Commands\Inventory\ImportOutfitCommand.cs" />
<Compile Include="Commands\Inventory\InventoryCommand.cs" />
<Compile Include="Commands\Inventory\ListContentsCommand.cs" />
<Compile Include="Commands\Inventory\ObjectInventoryCommand.cs" />
<Compile Include="Commands\Inventory\CreateNotecardCommand.cs" />
<Compile Include="Commands\Inventory\UploadImageCommand.cs" />
<Compile Include="Commands\Land\ParcelDetailsCommand.cs" />
<Compile Include="Commands\Land\FindSimCommand.cs" />
<Compile Include="Commands\Land\AgentLocationsCommand.cs" />
<Compile Include="Commands\Land\GridLayerCommand.cs" />
<Compile Include="Commands\Land\GridMapCommand.cs" />
<Compile Include="Commands\Land\ParcelInfoCommand.cs" />
<Compile Include="Commands\Movement\CrouchCommand.cs" />
<Compile Include="Commands\Movement\FlyCommand.cs" />
<Compile Include="Commands\Movement\FollowCommand.cs" />
<Compile Include="Commands\Movement\GotoCommand.cs" />
<Compile Include="Commands\Movement\JumpCommand.cs" />
<Compile Include="Commands\Movement\LocationCommand.cs" />
<Compile Include="Commands\Movement\MoveToCommand.cs" />
<Compile Include="Commands\Movement\SetHome.cs" />
<Compile Include="Commands\Movement\SitCommand.cs" />
<Compile Include="Commands\Movement\SitOnCommand.cs" />
<Compile Include="Commands\Movement\StandCommand.cs" />
<Compile Include="Commands\Prims\ChangePermsCommand.cs" />
<Compile Include="Commands\Prims\DownloadTextureCommand.cs" />
<Compile Include="Commands\Prims\ExportCommand.cs" />
<Compile Include="Commands\Prims\ExportParticlesCommand.cs" />
<Compile Include="Commands\Prims\FindObjectsCommand.cs" />
<Compile Include="Commands\Prims\FindTextureCommand.cs" />
<Compile Include="Commands\Prims\ImportCommand.cs" />
<Compile Include="Commands\Prims\PrimCountCommand.cs" />
<Compile Include="Commands\Prims\PrimInfoCommand.cs" />
<Compile Include="Commands\Prims\PrimRegexCommand.cs" />
<Compile Include="Commands\SearchEventsCommand.cs" />
<Compile Include="Commands\ShowEventDetailsCommand.cs" />
<Compile Include="Commands\Stats\DilationCommand.cs" />
<Compile Include="Commands\Stats\RegionInfoCommand.cs" />
<Compile Include="Commands\Stats\StatsCommand.cs" />
<Compile Include="Commands\Stats\UptimeCommand.cs" />
<Compile Include="Commands\System\DebugCommand.cs" />
<Compile Include="Commands\System\HelpCommand.cs" />
<Compile Include="Commands\System\LoadCommand.cs" />
<Compile Include="Commands\System\LoginCommand.cs" />
<Compile Include="Commands\System\LogoutCommand.cs" />
<Compile Include="Commands\System\MD5Command.cs" />
<Compile Include="Commands\System\PacketLogCommand.cs" />
<Compile Include="Commands\System\QuitCommand.cs" />
<Compile Include="Commands\System\SetMasterCommand.cs" />
<Compile Include="Commands\System\SetMasterKeyCommand.cs" />
<Compile Include="Commands\System\ShowEffectsCommand.cs" />
<Compile Include="Commands\TouchCommand.cs" />
<Compile Include="Commands\TreeCommand.cs" />
<Compile Include="Commands\Voice\ParcelVoiceInfo.cs" />
<Compile Include="Commands\Voice\VoiceAcountCommand.cs" />
<Compile Include="Commands\WhoCommand.cs" />
<Compile Include="Parsing.cs" />
<Compile Include="Program.cs" />
<Compile Include="TestClient.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\OpenMetaverse.csproj">
<Project>{D9CDEDFB-8169-4B03-B57F-0DF638F044EC}</Project>
<Name>OpenMetaverse</Name>
</ProjectReference>
<ProjectReference Include="..\..\libsecondlife.Utilities\OpenMetaverse.Utilities.csproj">
<Project>{CE5E06C2-2428-416B-ADC1-F1FE16A0FB27}</Project>
<Name>OpenMetaverse.Utilities</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>