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:
111
Programs/examples/TestClient/Arguments.cs
Normal file
111
Programs/examples/TestClient/Arguments.cs
Normal 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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
332
Programs/examples/TestClient/ClientManager.cs
Normal file
332
Programs/examples/TestClient/ClientManager.cs
Normal 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.
|
||||
}
|
||||
}
|
||||
}
|
||||
29
Programs/examples/TestClient/Command.cs
Normal file
29
Programs/examples/TestClient/Command.cs
Normal 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()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
130
Programs/examples/TestClient/Commands/CloneProfileCommand.cs
Normal file
130
Programs/examples/TestClient/Commands/CloneProfileCommand.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 :(");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
39
Programs/examples/TestClient/Commands/DetectBotCommand.cs
Normal file
39
Programs/examples/TestClient/Commands/DetectBotCommand.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
26
Programs/examples/TestClient/Commands/GoHome.cs
Normal file
26
Programs/examples/TestClient/Commands/GoHome.cs
Normal 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";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
37
Programs/examples/TestClient/Commands/GotoLandmark.cs
Normal file
37
Programs/examples/TestClient/Commands/GotoLandmark.cs
Normal 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";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
147
Programs/examples/TestClient/Commands/Groups/JoinGroupCommand.cs
Normal file
147
Programs/examples/TestClient/Commands/Groups/JoinGroupCommand.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
358
Programs/examples/TestClient/Commands/Inventory/BackupCommand.cs
Normal file
358
Programs/examples/TestClient/Commands/Inventory/BackupCommand.cs
Normal 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";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
43
Programs/examples/TestClient/Commands/Land/FindSimCommand.cs
Normal file
43
Programs/examples/TestClient/Commands/Land/FindSimCommand.cs
Normal 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";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
27
Programs/examples/TestClient/Commands/Land/GridMapCommand.cs
Normal file
27
Programs/examples/TestClient/Commands/Land/GridMapCommand.cs
Normal 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.";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
33
Programs/examples/TestClient/Commands/Movement/FlyCommand.cs
Normal file
33
Programs/examples/TestClient/Commands/Movement/FlyCommand.cs
Normal 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";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
156
Programs/examples/TestClient/Commands/Movement/FollowCommand.cs
Normal file
156
Programs/examples/TestClient/Commands/Movement/FollowCommand.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
23
Programs/examples/TestClient/Commands/Movement/SetHome.cs
Normal file
23
Programs/examples/TestClient/Commands/Movement/SetHome.cs
Normal 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";
|
||||
}
|
||||
}
|
||||
}
|
||||
48
Programs/examples/TestClient/Commands/Movement/SitCommand.cs
Normal file
48
Programs/examples/TestClient/Commands/Movement/SitCommand.cs
Normal 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";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
236
Programs/examples/TestClient/Commands/Prims/ExportCommand.cs
Normal file
236
Programs/examples/TestClient/Commands/Prims/ExportCommand.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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]";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
236
Programs/examples/TestClient/Commands/Prims/ImportCommand.cs
Normal file
236
Programs/examples/TestClient/Commands/Prims/ImportCommand.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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]";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
}
|
||||
61
Programs/examples/TestClient/Commands/SearchEventsCommand.cs
Normal file
61
Programs/examples/TestClient/Commands/SearchEventsCommand.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
47
Programs/examples/TestClient/Commands/Stats/StatsCommand.cs
Normal file
47
Programs/examples/TestClient/Commands/Stats/StatsCommand.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
25
Programs/examples/TestClient/Commands/Stats/UptimeCommand.cs
Normal file
25
Programs/examples/TestClient/Commands/Stats/UptimeCommand.cs
Normal 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) + ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
52
Programs/examples/TestClient/Commands/System/DebugCommand.cs
Normal file
52
Programs/examples/TestClient/Commands/System/DebugCommand.cs
Normal 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";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
29
Programs/examples/TestClient/Commands/System/HelpCommand.cs
Normal file
29
Programs/examples/TestClient/Commands/System/HelpCommand.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
28
Programs/examples/TestClient/Commands/System/LoadCommand.cs
Normal file
28
Programs/examples/TestClient/Commands/System/LoadCommand.cs
Normal 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.";
|
||||
}
|
||||
}
|
||||
}
|
||||
34
Programs/examples/TestClient/Commands/System/LoginCommand.cs
Normal file
34
Programs/examples/TestClient/Commands/System/LoginCommand.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
}
|
||||
22
Programs/examples/TestClient/Commands/System/MD5Command.cs
Normal file
22
Programs/examples/TestClient/Commands/System/MD5Command.cs
Normal 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]";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
}
|
||||
24
Programs/examples/TestClient/Commands/System/QuitCommand.cs
Normal file
24
Programs/examples/TestClient/Commands/System/QuitCommand.cs
Normal 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";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
43
Programs/examples/TestClient/Commands/TouchCommand.cs
Normal file
43
Programs/examples/TestClient/Commands/TouchCommand.cs
Normal 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];
|
||||
}
|
||||
}
|
||||
}
|
||||
50
Programs/examples/TestClient/Commands/TreeCommand.cs
Normal file
50
Programs/examples/TestClient/Commands/TreeCommand.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
40
Programs/examples/TestClient/Commands/WhoCommand.cs
Normal file
40
Programs/examples/TestClient/Commands/WhoCommand.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
88
Programs/examples/TestClient/Parsing.cs
Normal file
88
Programs/examples/TestClient/Parsing.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
155
Programs/examples/TestClient/Program.cs
Normal file
155
Programs/examples/TestClient/Program.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
33
Programs/examples/TestClient/Properties/AssemblyInfo.cs
Normal file
33
Programs/examples/TestClient/Properties/AssemblyInfo.cs
Normal 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")]
|
||||
126
Programs/examples/TestClient/TestClient.build
Normal file
126
Programs/examples/TestClient/TestClient.build
Normal 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>
|
||||
263
Programs/examples/TestClient/TestClient.cs
Normal file
263
Programs/examples/TestClient/TestClient.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
159
Programs/examples/TestClient/TestClient.csproj
Normal file
159
Programs/examples/TestClient/TestClient.csproj
Normal 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>
|
||||
Reference in New Issue
Block a user