* Importing Ming's mass test client
parent
dfb22716b9
commit
e93869c7a7
|
@ -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 /param3:"Test-:-work"
|
||||
// /param4=happy -param5 '--=nice=--'
|
||||
foreach (string Txt in Args)
|
||||
{
|
||||
// Look for new parameters (-,/ or --) and a
|
||||
// possible enclosed value (=,:)
|
||||
Parts = Splitter.Split(Txt, 3);
|
||||
|
||||
switch (Parts.Length)
|
||||
{
|
||||
// Found a value (for the last parameter
|
||||
// found (space separator))
|
||||
case 1:
|
||||
if (Parameter != null)
|
||||
{
|
||||
if (!Parameters.ContainsKey(Parameter))
|
||||
{
|
||||
Parts[0] =
|
||||
Remover.Replace(Parts[0], "$1");
|
||||
|
||||
Parameters.Add(Parameter, Parts[0]);
|
||||
}
|
||||
Parameter = null;
|
||||
}
|
||||
// else Error: no parameter waiting for a value (skipped)
|
||||
break;
|
||||
|
||||
// Found just a parameter
|
||||
case 2:
|
||||
// The last parameter is still waiting.
|
||||
// With no value, set it to true.
|
||||
if (Parameter != null)
|
||||
{
|
||||
if (!Parameters.ContainsKey(Parameter))
|
||||
Parameters.Add(Parameter, "true");
|
||||
}
|
||||
Parameter = Parts[1];
|
||||
break;
|
||||
|
||||
// Parameter with enclosed value
|
||||
case 3:
|
||||
// The last parameter is still waiting.
|
||||
// With no value, set it to true.
|
||||
if (Parameter != null)
|
||||
{
|
||||
if (!Parameters.ContainsKey(Parameter))
|
||||
Parameters.Add(Parameter, "true");
|
||||
}
|
||||
|
||||
Parameter = Parts[1];
|
||||
|
||||
// Remove possible enclosing characters (",')
|
||||
if (!Parameters.ContainsKey(Parameter))
|
||||
{
|
||||
Parts[2] = Remover.Replace(Parts[2], "$1");
|
||||
Parameters.Add(Parameter, Parts[2]);
|
||||
}
|
||||
|
||||
Parameter = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// In case a parameter is still waiting
|
||||
if (Parameter != null)
|
||||
{
|
||||
if (!Parameters.ContainsKey(Parameter))
|
||||
Parameters.Add(Parameter, "true");
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve a parameter value if it exists
|
||||
// (overriding C# indexer property)
|
||||
public string this[string Param]
|
||||
{
|
||||
get
|
||||
{
|
||||
return (Parameters[Param]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,323 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Xml;
|
||||
using System.Threading;
|
||||
using libsecondlife;
|
||||
using libsecondlife.Packets;
|
||||
using libsecondlife.AssetSystem;
|
||||
|
||||
namespace libsecondlife.TestClient
|
||||
{
|
||||
public class LoginDetails
|
||||
{
|
||||
public string FirstName;
|
||||
public string LastName;
|
||||
public string Password;
|
||||
public string StartLocation;
|
||||
public string MasterName;
|
||||
public LLUUID MasterKey;
|
||||
public string LoginURI;
|
||||
}
|
||||
|
||||
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, SecondLife> Clients = new Dictionary<LLUUID, SecondLife>();
|
||||
public Dictionary<Simulator, Dictionary<uint, Primitive>> SimPrims = new Dictionary<Simulator, Dictionary<uint, Primitive>>();
|
||||
|
||||
public bool Running = true;
|
||||
|
||||
string contactPerson = String.Empty;
|
||||
private LLUUID resolvedMasterKey = LLUUID.Zero;
|
||||
private ManualResetEvent keyResolution = new ManualResetEvent(false);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="accounts"></param>
|
||||
public ClientManager(List<LoginDetails> accounts, string c)
|
||||
{
|
||||
this.contactPerson = c;
|
||||
foreach (LoginDetails account in accounts)
|
||||
Login(account);
|
||||
}
|
||||
|
||||
public ClientManager(List<LoginDetails> accounts, string c, string s)
|
||||
{
|
||||
this.contactPerson = c;
|
||||
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.SimPrims = SimPrims;
|
||||
client.MasterName = account.MasterName;
|
||||
client.MasterKey = account.MasterKey;
|
||||
|
||||
libsecondlife.NetworkManager.LoginParams loginParams = new NetworkManager.LoginParams();
|
||||
loginParams.FirstName = account.FirstName;
|
||||
loginParams.LastName = account.LastName;
|
||||
loginParams.Password = account.Password;
|
||||
loginParams.UserAgent = "MassTestClient";
|
||||
loginParams.Start = account.StartLocation;
|
||||
loginParams.Author = contactPerson;
|
||||
loginParams.URI = account.LoginURI;
|
||||
|
||||
|
||||
if (!client.Network.Login(loginParams))
|
||||
{
|
||||
Console.WriteLine("Failed to login " + account.FirstName + " " + account.LastName + ": " +
|
||||
client.Network.LoginMessage);
|
||||
}
|
||||
|
||||
|
||||
if (client.Network.Connected)
|
||||
{
|
||||
if (account.MasterKey == LLUUID.Zero && !String.IsNullOrEmpty(account.MasterName))
|
||||
{
|
||||
Console.WriteLine("Resolving {0}'s UUID", account.MasterName);
|
||||
// Find master's key from name
|
||||
DirectoryManager.DirPeopleReplyCallback callback = new DirectoryManager.DirPeopleReplyCallback(KeyResolvHandler);
|
||||
client.Directory.OnDirPeopleReply += callback;
|
||||
client.Directory.StartPeopleSearch(DirectoryManager.DirFindFlags.People, account.MasterName, 0);
|
||||
if (keyResolution.WaitOne(TimeSpan.FromMinutes(1), false))
|
||||
{
|
||||
account.MasterKey = resolvedMasterKey;
|
||||
Console.WriteLine("\"{0}\" resolved to {1}", account.MasterName, account.MasterKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Unable to obtain UUID for \"{0}\". No master will be used. Try specifying a key with --masterkey.", account.MasterName);
|
||||
}
|
||||
client.Directory.OnDirPeopleReply -= callback;
|
||||
keyResolution.Reset();
|
||||
}
|
||||
|
||||
client.MasterKey = account.MasterKey;
|
||||
|
||||
Clients[client.Network.AgentID] = client;
|
||||
|
||||
Console.WriteLine("Logged in " + client.ToString());
|
||||
}
|
||||
|
||||
return client;
|
||||
}
|
||||
|
||||
private void KeyResolvHandler(LLUUID queryid, List<DirectoryManager.AgentSearchData> matches)
|
||||
{
|
||||
LLUUID master = matches[0].AgentID;
|
||||
if (matches.Count > 1)
|
||||
{
|
||||
Console.WriteLine("Possible masters:");
|
||||
for (int i = 0; i < matches.Count; ++i)
|
||||
{
|
||||
Console.WriteLine("{0}: {1}", i, matches[i].FirstName + " " + matches[i].LastName);
|
||||
}
|
||||
Console.Write("Ambiguous master, choose one:");
|
||||
string read = Console.ReadLine();
|
||||
while (read != null)
|
||||
{
|
||||
int choice = 0;
|
||||
if (int.TryParse(read, out choice))
|
||||
{
|
||||
master = matches[choice].AgentID;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Responce misunderstood.");
|
||||
Console.Write("Type the corresponding number:");
|
||||
}
|
||||
read = Console.ReadLine();
|
||||
}
|
||||
}
|
||||
resolvedMasterKey = master;
|
||||
keyResolution.Set();
|
||||
}
|
||||
|
||||
/// <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(List<string> massTestCommands)
|
||||
{
|
||||
Console.WriteLine("Type quit to exit. Type help for a command list.");
|
||||
|
||||
if (massTestCommands.Count == 0)
|
||||
{
|
||||
while (Running)
|
||||
{
|
||||
PrintPrompt();
|
||||
string input = Console.ReadLine();
|
||||
DoCommandAll(input, null, null);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int currentCommand = 0;
|
||||
while (Running)
|
||||
{
|
||||
DoCommandAll(massTestCommands[currentCommand], null, null);
|
||||
currentCommand++;
|
||||
if (massTestCommands.Count >= currentCommand)
|
||||
{
|
||||
currentCommand = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (SecondLife client in Clients.Values)
|
||||
{
|
||||
if (client.Network.Connected)
|
||||
client.Network.Logout();
|
||||
}
|
||||
}
|
||||
|
||||
private void PrintPrompt()
|
||||
{
|
||||
int online = 0;
|
||||
|
||||
foreach (SecondLife 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, LLUUID imSessionID)
|
||||
{
|
||||
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, SecondLife> clientsCopy = new Dictionary<LLUUID, SecondLife>(Clients);
|
||||
|
||||
foreach (TestClient client in clientsCopy.Values)
|
||||
client.DoCommand(cmd, fromAgentID, imSessionID);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
public void Logout(TestClient client)
|
||||
{
|
||||
Clients.Remove(client.Network.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, SecondLife> clientsCopy = new Dictionary<LLUUID, SecondLife>(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.
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using libsecondlife;
|
||||
using libsecondlife.Packets;
|
||||
|
||||
namespace libsecondlife.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,131 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using libsecondlife;
|
||||
using libsecondlife.Packets;
|
||||
|
||||
namespace libsecondlife.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.Self.OnJoinGroup += new MainAvatar.JoinGroupCallback(Self_OnJoinGroup);
|
||||
|
||||
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.ProfileInterests = Interests;
|
||||
Client.Self.ProfileProperties = Properties;
|
||||
Client.Self.SetAvatarInformation();
|
||||
|
||||
// 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.Self.RequestJoinGroup(groupID);
|
||||
}
|
||||
|
||||
return "Synchronized our profile to the profile of " + targetID.ToStringHyphenated();
|
||||
}
|
||||
|
||||
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, AvatarGroupsReplyPacket.GroupDataBlock[] groups)
|
||||
{
|
||||
lock (ReceivedProfileEvent)
|
||||
{
|
||||
foreach (AvatarGroupsReplyPacket.GroupDataBlock block in groups)
|
||||
{
|
||||
Groups.Add(block.GroupID);
|
||||
}
|
||||
|
||||
ReceivedGroups = true;
|
||||
|
||||
if (ReceivedInterests && ReceivedProperties && ReceivedGroups)
|
||||
ReceivedProfileEvent.Set();
|
||||
}
|
||||
}
|
||||
|
||||
void Self_OnJoinGroup(LLUUID groupID, bool success)
|
||||
{
|
||||
Console.WriteLine(Client.ToString() + (success ? " joined " : " failed to join ") +
|
||||
groupID.ToStringHyphenated());
|
||||
|
||||
if (success)
|
||||
{
|
||||
Console.WriteLine(Client.ToString() + " setting " + groupID.ToStringHyphenated() +
|
||||
" as the active group");
|
||||
Client.Self.ActivateGroup(groupID);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using libsecondlife;
|
||||
using libsecondlife.Packets;
|
||||
|
||||
namespace libsecondlife.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 MainAvatar.ChatCallback(Self_OnChat);
|
||||
return "Echoing is now on.";
|
||||
}
|
||||
else
|
||||
{
|
||||
Active = false;
|
||||
Client.Self.OnChat -= new MainAvatar.ChatCallback(Self_OnChat);
|
||||
return "Echoing is now off.";
|
||||
}
|
||||
}
|
||||
|
||||
void Self_OnChat(string message, MainAvatar.ChatAudibleLevel audible, MainAvatar.ChatType type,
|
||||
MainAvatar.ChatSourceType sourcetype, string fromName, LLUUID id, LLUUID ownerid, LLVector3 position)
|
||||
{
|
||||
if (message.Length > 0 && Client.MasterKey == id)
|
||||
{
|
||||
Client.Self.Chat(message, 0, MainAvatar.ChatType.Normal);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using libsecondlife;
|
||||
using libsecondlife.Packets;
|
||||
|
||||
namespace libsecondlife.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, id);
|
||||
return "Instant Messaged " + id.ToStringHyphenated() + " 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,44 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using libsecondlife;
|
||||
|
||||
namespace libsecondlife.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, MainAvatar.ChatType.Normal);
|
||||
|
||||
return "Said " + message.ToString();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using libsecondlife;
|
||||
using libsecondlife.Packets;
|
||||
|
||||
namespace libsecondlife.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, MainAvatar.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 libsecondlife;
|
||||
using libsecondlife.Packets;
|
||||
|
||||
namespace libsecondlife.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, MainAvatar.ChatType.Whisper);
|
||||
|
||||
return "Whispered " + message;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using libsecondlife;
|
||||
using libsecondlife.Packets;
|
||||
|
||||
namespace libsecondlife.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";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using libsecondlife;
|
||||
using libsecondlife.Packets;
|
||||
|
||||
namespace libsecondlife.TestClient
|
||||
{
|
||||
public class GotoLandmarkCommand : Command
|
||||
{
|
||||
public GotoLandmarkCommand(TestClient testClient)
|
||||
{
|
||||
Name = "goto_landmark";
|
||||
Description = "Teleports to a Landmark ";
|
||||
}
|
||||
|
||||
public override string Execute(string[] args, LLUUID fromAgentID)
|
||||
{
|
||||
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,29 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using libsecondlife;
|
||||
using libsecondlife.Packets;
|
||||
|
||||
namespace libsecondlife.TestClient
|
||||
{
|
||||
public class AppearanceCommand : Command
|
||||
{
|
||||
Utilities.Assets.AssetManager Assets;
|
||||
Utilities.Appearance.AppearanceManager Appearance;
|
||||
|
||||
public AppearanceCommand(TestClient testClient)
|
||||
{
|
||||
Name = "appearance";
|
||||
Description = "Set your current appearance to your last saved appearance";
|
||||
|
||||
Assets = new libsecondlife.Utilities.Assets.AssetManager(testClient);
|
||||
Appearance = new libsecondlife.Utilities.Appearance.AppearanceManager(testClient, Assets);
|
||||
}
|
||||
|
||||
public override string Execute(string[] args, LLUUID fromAgentID)
|
||||
{
|
||||
Appearance.SetPreviousAppearance();
|
||||
return "Done.";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using libsecondlife;
|
||||
using libsecondlife.Packets;
|
||||
|
||||
namespace libsecondlife.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)
|
||||
{
|
||||
return Client.ToString() + " has L$: " + Client.Self.Balance;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Xml;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
using libsecondlife;
|
||||
using libsecondlife.Packets;
|
||||
using libsecondlife.InventorySystem;
|
||||
|
||||
namespace libsecondlife.TestClient
|
||||
{
|
||||
public class DeleteFolderCommand : Command
|
||||
{
|
||||
public DeleteFolderCommand(TestClient testClient)
|
||||
{
|
||||
Name = "deleteFolder";
|
||||
Description = "Deletes a folder from inventory.";
|
||||
}
|
||||
|
||||
public override string Execute(string[] args, LLUUID fromAgentID)
|
||||
{
|
||||
return "Broken until someone fixes me";
|
||||
|
||||
//string target = String.Empty;
|
||||
//for (int ct = 0; ct < args.Length; ct++)
|
||||
// target = target + args[ct] + " ";
|
||||
//target = target.TrimEnd();
|
||||
|
||||
//Client.Inventory.DownloadInventory();
|
||||
//InventoryFolder folder = Client.Inventory.getFolder(target);
|
||||
//if (folder != null)
|
||||
//{
|
||||
// folder.Delete();
|
||||
// return "Folder " + target + " deleted.";
|
||||
//}
|
||||
|
||||
//return "Unable to find: " + target;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using libsecondlife;
|
||||
using libsecondlife.Utilities.Assets;
|
||||
using libsecondlife.Utilities.Appearance;
|
||||
|
||||
namespace libsecondlife.TestClient
|
||||
{
|
||||
public class DumpOutfitCommand : Command
|
||||
{
|
||||
libsecondlife.Utilities.Assets.AssetManager Assets;
|
||||
List<LLUUID> OutfitAssets = new List<LLUUID>();
|
||||
|
||||
public DumpOutfitCommand(TestClient testClient)
|
||||
{
|
||||
Name = "dumpoutfit";
|
||||
Description = "Dumps all of the textures from an avatars outfit to the hard drive. Usage: dumpoutfit [avatar-uuid]";
|
||||
|
||||
Assets = new AssetManager(testClient);
|
||||
Assets.OnImageReceived += 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.AvatarList)
|
||||
{
|
||||
foreach (Avatar avatar in Client.AvatarList.Values)
|
||||
{
|
||||
if (avatar.ID == target)
|
||||
{
|
||||
StringBuilder output = new StringBuilder("Downloading ");
|
||||
|
||||
lock (OutfitAssets) OutfitAssets.Clear();
|
||||
|
||||
foreach (KeyValuePair<uint, LLObject.TextureEntryFace> face in avatar.Textures.FaceTextures)
|
||||
{
|
||||
ImageType type = ImageType.Normal;
|
||||
|
||||
switch ((AppearanceManager.TextureIndex)face.Key)
|
||||
{
|
||||
case AppearanceManager.TextureIndex.HeadBaked:
|
||||
case AppearanceManager.TextureIndex.EyesBaked:
|
||||
case AppearanceManager.TextureIndex.UpperBaked:
|
||||
case AppearanceManager.TextureIndex.LowerBaked:
|
||||
case AppearanceManager.TextureIndex.SkirtBaked:
|
||||
type = ImageType.Baked;
|
||||
break;
|
||||
}
|
||||
|
||||
Assets.RequestImage(face.Value.TextureID, type, 100000.0f, 0);
|
||||
|
||||
output.Append(((AppearanceManager.TextureIndex)face.Key).ToString());
|
||||
output.Append(" ");
|
||||
}
|
||||
|
||||
return output.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "Couldn't find avatar " + target.ToStringHyphenated();
|
||||
}
|
||||
|
||||
private void Assets_OnImageReceived(ImageDownload image)
|
||||
{
|
||||
if (image.Success)
|
||||
{
|
||||
try
|
||||
{
|
||||
File.WriteAllBytes(image.ID.ToStringHyphenated() + ".jp2", image.AssetData);
|
||||
Console.WriteLine("Wrote JPEG2000 image " + image.ID.ToStringHyphenated() + ".jp2");
|
||||
|
||||
byte[] tgaFile = OpenJPEGNet.OpenJPEG.DecodeToTGA(image.AssetData);
|
||||
File.WriteAllBytes(image.ID.ToStringHyphenated() + ".tga", tgaFile);
|
||||
Console.WriteLine("Wrote TGA image " + image.ID.ToStringHyphenated() + ".tga");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e.ToString());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Failed to download image " + image.ID.ToStringHyphenated());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
using libsecondlife;
|
||||
using libsecondlife.Packets;
|
||||
|
||||
namespace libsecondlife.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)
|
||||
{
|
||||
if (args.Length != 2)
|
||||
return "Usage: exportoutfit avataruuid outputfile.xml";
|
||||
|
||||
LLUUID id;
|
||||
|
||||
try
|
||||
{
|
||||
id = new LLUUID(args[0]);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return "Usage: exportoutfit avataruuid outputfile.xml";
|
||||
}
|
||||
|
||||
lock (Client.Appearances)
|
||||
{
|
||||
if (Client.Appearances.ContainsKey(id))
|
||||
{
|
||||
try
|
||||
{
|
||||
XmlWriterSettings settings = new XmlWriterSettings();
|
||||
settings.Indent = true;
|
||||
XmlWriter writer = XmlWriter.Create(args[1], settings);
|
||||
try
|
||||
{
|
||||
Client.Appearances[id].ToXml(writer);
|
||||
}
|
||||
finally
|
||||
{
|
||||
writer.Close();
|
||||
}
|
||||
}
|
||||
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 libsecondlife;
|
||||
using libsecondlife.Packets;
|
||||
|
||||
namespace libsecondlife.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 == null)
|
||||
return "Unable to send money to console. This command only works when IMed.";
|
||||
|
||||
int amount = Client.Self.Balance;
|
||||
Client.Self.GiveMoney(fromAgentID, Client.Self.Balance, String.Empty);
|
||||
return "Gave $" + amount + " to " + fromAgentID;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
using System.Xml.Serialization;
|
||||
using libsecondlife;
|
||||
using libsecondlife.Packets;
|
||||
|
||||
namespace libsecondlife.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";
|
||||
|
||||
try
|
||||
{
|
||||
XmlReader reader = XmlReader.Create(args[0]);
|
||||
XmlSerializer serializer = new XmlSerializer(typeof(Packet));
|
||||
AvatarAppearancePacket appearance = (AvatarAppearancePacket)serializer.Deserialize(reader);
|
||||
reader.Close();
|
||||
|
||||
AgentSetAppearancePacket set = new AgentSetAppearancePacket();
|
||||
|
||||
set.AgentData.AgentID = Client.Network.AgentID;
|
||||
set.AgentData.SessionID = Client.Network.SessionID;
|
||||
set.AgentData.SerialNum = SerialNum++;
|
||||
|
||||
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,62 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Xml;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
using libsecondlife;
|
||||
using libsecondlife.Packets;
|
||||
using libsecondlife.InventorySystem;
|
||||
|
||||
namespace libsecondlife.TestClient
|
||||
{
|
||||
public class InventoryCommand : Command
|
||||
{
|
||||
public InventoryCommand(TestClient testClient)
|
||||
{
|
||||
Name = "i";
|
||||
Description = "Prints out inventory.";
|
||||
}
|
||||
|
||||
public override string Execute(string[] args, LLUUID fromAgentID)
|
||||
{
|
||||
return "Broken until someone fixes me";
|
||||
|
||||
//Client.Inventory.DownloadInventory();
|
||||
//StringBuilder result = new StringBuilder();
|
||||
//PrintFolder(Client.Inventory.GetRootFolder(), result, 0);
|
||||
//return result.ToString();
|
||||
}
|
||||
|
||||
//void PrintFolder(InventoryFolder folder, StringBuilder output, int indenting)
|
||||
//{
|
||||
// Indent(output, indenting);
|
||||
// output.Append(folder.Name);
|
||||
// output.Append("\n");
|
||||
// foreach (InventoryBase b in folder.GetContents())
|
||||
// {
|
||||
// InventoryItem item = b as InventoryItem;
|
||||
// if (item != null)
|
||||
// {
|
||||
// Indent(output, indenting + 1);
|
||||
// output.Append(item.Name);
|
||||
// output.Append("\n");
|
||||
// continue;
|
||||
// }
|
||||
// InventoryFolder subFolder = b as InventoryFolder;
|
||||
// if (subFolder != null)
|
||||
// PrintFolder(subFolder, output, indenting + 1);
|
||||
// }
|
||||
//}
|
||||
|
||||
//void Indent(StringBuilder output, int indenting)
|
||||
//{
|
||||
// for (int count = 0; count < indenting; count++)
|
||||
// {
|
||||
// output.Append(" ");
|
||||
// }
|
||||
//}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Xml;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
using libsecondlife;
|
||||
using libsecondlife.Packets;
|
||||
using libsecondlife.InventorySystem;
|
||||
|
||||
namespace libsecondlife.TestClient
|
||||
{
|
||||
public class WearCommand : Command
|
||||
{
|
||||
public WearCommand(TestClient testClient)
|
||||
{
|
||||
Name = "wear";
|
||||
Description = "Wear an outfit folder from inventory. Usage: wear [outfit name]";
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
InventoryFolder folder = Client.Inventory.getFolder(target);
|
||||
|
||||
if (folder != null)
|
||||
{
|
||||
Client.Appearance.WearOutfit(folder);
|
||||
return "Outfit " + target + " worn.";
|
||||
}
|
||||
|
||||
return "Unable to find: " + target;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using libsecondlife;
|
||||
using libsecondlife.Packets;
|
||||
|
||||
namespace libsecondlife.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, 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,62 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using libsecondlife;
|
||||
using libsecondlife.Utilities;
|
||||
|
||||
namespace libsecondlife.TestClient
|
||||
{
|
||||
public class ParcelInfoCommand : Command
|
||||
{
|
||||
private ParcelDownloader ParcelDownloader;
|
||||
private ManualResetEvent ParcelsDownloaded = new ManualResetEvent(false);
|
||||
private int ParcelCount = 0;
|
||||
|
||||
public ParcelInfoCommand(TestClient testClient)
|
||||
{
|
||||
Name = "parcelinfo";
|
||||
Description = "Prints out info about all the parcels in this simulator";
|
||||
|
||||
ParcelDownloader = new ParcelDownloader(testClient);
|
||||
ParcelDownloader.OnParcelsDownloaded += new ParcelDownloader.ParcelsDownloadedCallback(Parcels_OnParcelsDownloaded);
|
||||
testClient.Network.OnDisconnected += new NetworkManager.DisconnectedCallback(Network_OnDisconnected);
|
||||
}
|
||||
|
||||
public override string Execute(string[] args, LLUUID fromAgentID)
|
||||
{
|
||||
ParcelDownloader.DownloadSimParcels(Client.Network.CurrentSim);
|
||||
|
||||
ParcelsDownloaded.Reset();
|
||||
ParcelsDownloaded.WaitOne(20000, false);
|
||||
|
||||
if (Client.Network.CurrentSim != null)
|
||||
return "Downloaded information for " + ParcelCount + " parcels in " + Client.Network.CurrentSim.Name;
|
||||
else
|
||||
return String.Empty;
|
||||
}
|
||||
|
||||
void Parcels_OnParcelsDownloaded(Simulator simulator, Dictionary<int, Parcel> Parcels, int[,] map)
|
||||
{
|
||||
foreach (KeyValuePair<int, Parcel> parcel in Parcels)
|
||||
{
|
||||
WaterType type = ParcelDownloader.GetWaterType(map, parcel.Value.LocalID);
|
||||
float delta = ParcelDownloader.GetHeightRange(map, parcel.Value.LocalID);
|
||||
int deviation = ParcelDownloader.GetRectangularDeviation(parcel.Value.AABBMin, parcel.Value.AABBMax,
|
||||
parcel.Value.Area);
|
||||
|
||||
Console.WriteLine("Parcels[{0}]: Name: \"{1}\", Description: \"{2}\" ACL Count: {3}, " +
|
||||
"Location: {4}, Height Range: {5}, Shape Deviation: {6}", parcel.Key, parcel.Value.Name,
|
||||
parcel.Value.Desc, parcel.Value.AccessList.Count, type.ToString(), delta, deviation);
|
||||
}
|
||||
|
||||
ParcelCount = Parcels.Count;
|
||||
|
||||
ParcelsDownloaded.Set();
|
||||
}
|
||||
|
||||
void Network_OnDisconnected(NetworkManager.DisconnectType reason, string message)
|
||||
{
|
||||
ParcelsDownloaded.Set();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using libsecondlife;
|
||||
using libsecondlife.Packets;
|
||||
|
||||
namespace libsecondlife.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.";
|
||||
}
|
||||
|
||||
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;
|
||||
Avatar followAvatar;
|
||||
|
||||
bool Follow(string name)
|
||||
{
|
||||
foreach (Avatar av in Client.AvatarList.Values)
|
||||
{
|
||||
if (av.Name == name)
|
||||
{
|
||||
followAvatar = av;
|
||||
Active = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Follow(LLUUID id)
|
||||
{
|
||||
foreach (Avatar av in Client.AvatarList.Values)
|
||||
{
|
||||
if (av.ID == id)
|
||||
{
|
||||
followAvatar = av;
|
||||
Active = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void Think()
|
||||
{
|
||||
if (Helpers.VecDist(followAvatar.Position, Client.Self.Position) > DISTANCE_BUFFER)
|
||||
{
|
||||
//move toward target
|
||||
LLVector3 avPos = followAvatar.Position;
|
||||
Client.Self.AutoPilot((ulong)avPos.X + (ulong)Client.regionX, (ulong)avPos.Y + (ulong)Client.regionY, avPos.Z);
|
||||
}
|
||||
//else
|
||||
//{
|
||||
// //stop at current position
|
||||
// LLVector3 myPos = client.Self.Position;
|
||||
// client.Self.AutoPilot((ulong)myPos.x, (ulong)myPos.y, myPos.Z);
|
||||
//}
|
||||
|
||||
base.Think();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using libsecondlife;
|
||||
using libsecondlife.Packets;
|
||||
|
||||
namespace libsecondlife.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: Destination should be specified as 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: Destination should be specified as sim/x/y/z";
|
||||
|
||||
string sim = tokens[0];
|
||||
float x = Client.Self.Position.X;
|
||||
float y = Client.Self.Position.Y;
|
||||
float z = Client.Self.Position.Z;
|
||||
float.TryParse(tokens[1], out x);
|
||||
float.TryParse(tokens[2], out y);
|
||||
float.TryParse(tokens[3], out 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,34 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using libsecondlife;
|
||||
using libsecondlife.Packets;
|
||||
|
||||
namespace libsecondlife.TestClient
|
||||
{
|
||||
public class JumpCommand: Command
|
||||
{
|
||||
public JumpCommand(TestClient testClient)
|
||||
{
|
||||
Name = "jump";
|
||||
Description = "Teleports to the specified height. (e.g. \"jump 1000\")";
|
||||
}
|
||||
|
||||
public override string Execute(string[] args, LLUUID fromAgentID)
|
||||
{
|
||||
if (args.Length != 1)
|
||||
return "usage: jump 1000";
|
||||
|
||||
float height = 0;
|
||||
float.TryParse(args[0], out height);
|
||||
|
||||
Client.Self.Teleport
|
||||
(
|
||||
Client.Network.CurrentSim.Name,
|
||||
new LLVector3(Client.Self.Position.X, Client.Self.Position.Y, Client.Self.Position.Z + height)
|
||||
);
|
||||
|
||||
return "Jumped " + height;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using libsecondlife;
|
||||
using libsecondlife.Packets;
|
||||
|
||||
namespace libsecondlife.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.Position.ToString();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace libsecondlife.TestClient.Commands.Movement {
|
||||
class MovetoCommand : Command {
|
||||
public MovetoCommand(TestClient client) {
|
||||
Name = "moveto";
|
||||
Description = "Moves the avatar to the specified global position using simulator autopilot.";
|
||||
}
|
||||
public override string Execute(string[] args, LLUUID fromAgentID) {
|
||||
if (args.Length != 3)
|
||||
return "usage: moveto x y z";
|
||||
float x = Client.Self.Position.X + Client.regionX;
|
||||
float y = Client.Self.Position.Y + Client.regionY;
|
||||
float z = Client.Self.Position.Z;
|
||||
float.TryParse(args[0], out x);
|
||||
float.TryParse(args[1], out y);
|
||||
float.TryParse(args[2], out z);
|
||||
Client.Self.AutoPilot((ulong)x, (ulong)y, z);
|
||||
return "Attempting to move to <" + x + ", " + y + ", " + z + ">";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using libsecondlife;
|
||||
using libsecondlife.Packets;
|
||||
|
||||
namespace libsecondlife.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";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using libsecondlife;
|
||||
using libsecondlife.Packets;
|
||||
|
||||
namespace libsecondlife.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;
|
||||
|
||||
lock (Client.SimPrims)
|
||||
{
|
||||
if (Client.SimPrims.ContainsKey(Client.Network.CurrentSim))
|
||||
{
|
||||
foreach (Primitive p in Client.SimPrims[Client.Network.CurrentSim].Values)
|
||||
{
|
||||
float distance = Helpers.VecDist(Client.Self.Position, p.Position);
|
||||
|
||||
if (closest == null || distance < closestDistance)
|
||||
{
|
||||
closest = p;
|
||||
closestDistance = distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (closest != null)
|
||||
{
|
||||
Client.Self.RequestSit(closest.ID, LLVector3.Zero);
|
||||
Client.Self.Sit();
|
||||
|
||||
return "Sat on " + closest.ID + ". Distance: " + closestDistance;
|
||||
}
|
||||
else
|
||||
{
|
||||
return "Couldn't find a nearby prim to sit on";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using libsecondlife;
|
||||
using libsecondlife.Packets;
|
||||
|
||||
namespace libsecondlife.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)
|
||||
{
|
||||
LLObject targetSeat = null;
|
||||
|
||||
lock (Client.SimPrims)
|
||||
{
|
||||
if (Client.SimPrims.ContainsKey(Client.Network.CurrentSim))
|
||||
{
|
||||
foreach (LLObject p in Client.SimPrims[Client.Network.CurrentSim].Values)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (p.ID == args[0])
|
||||
targetSeat = p;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// handle exception
|
||||
return "Sorry, I don't think " + args[0] + " is a valid UUID. I'm unable to sit there.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (targetSeat != null)
|
||||
{
|
||||
Client.Self.RequestSit(targetSeat.ID, LLVector3.Zero);
|
||||
Client.Self.Sit();
|
||||
|
||||
return "Sat on prim " + targetSeat.ID + ".";
|
||||
}
|
||||
else
|
||||
{
|
||||
return "Couldn't find specified prim to sit on";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using libsecondlife;
|
||||
using libsecondlife.Packets;
|
||||
|
||||
namespace libsecondlife.TestClient
|
||||
{
|
||||
public class StandCommand: Command
|
||||
{
|
||||
public StandCommand(TestClient testClient)
|
||||
{
|
||||
Name = "stand";
|
||||
Description = "Stand";
|
||||
}
|
||||
|
||||
public override string Execute(string[] args, LLUUID fromAgentID)
|
||||
{
|
||||
Client.Self.Status.StandUp = true;
|
||||
stand(Client);
|
||||
return "Standing up.";
|
||||
}
|
||||
|
||||
void stand(SecondLife client)
|
||||
{
|
||||
SendAgentUpdate(client, (uint)MainAvatar.ControlFlags.AGENT_CONTROL_STAND_UP);
|
||||
}
|
||||
|
||||
const float DRAW_DISTANCE = 96.0f;
|
||||
void SendAgentUpdate(SecondLife client, uint ControlID)
|
||||
{
|
||||
AgentUpdatePacket p = new AgentUpdatePacket();
|
||||
p.AgentData.Far = DRAW_DISTANCE;
|
||||
//LLVector3 myPos = client.Self.Position;
|
||||
p.AgentData.CameraCenter = new LLVector3(0, 0, 0);
|
||||
p.AgentData.CameraAtAxis = new LLVector3(0, 0, 0);
|
||||
p.AgentData.CameraLeftAxis = new LLVector3(0, 0, 0);
|
||||
p.AgentData.CameraUpAxis = new LLVector3(0, 0, 0);
|
||||
p.AgentData.HeadRotation = new LLQuaternion(0, 0, 0, 1); ;
|
||||
p.AgentData.BodyRotation = new LLQuaternion(0, 0, 0, 1); ;
|
||||
p.AgentData.AgentID = client.Network.AgentID;
|
||||
p.AgentData.SessionID = client.Network.SessionID;
|
||||
p.AgentData.ControlFlags = ControlID;
|
||||
client.Network.SendPacket(p);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,209 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using libsecondlife;
|
||||
using libsecondlife.Packets;
|
||||
|
||||
namespace libsecondlife.TestClient
|
||||
{
|
||||
public class ExportCommand : Command
|
||||
{
|
||||
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.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 = 0;
|
||||
int count = 0;
|
||||
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;
|
||||
}
|
||||
|
||||
lock (Client.SimPrims)
|
||||
{
|
||||
if (Client.SimPrims.ContainsKey(Client.Network.CurrentSim))
|
||||
{
|
||||
foreach (Primitive prim in Client.SimPrims[Client.Network.CurrentSim].Values)
|
||||
{
|
||||
if (prim.ID == id)
|
||||
{
|
||||
if (prim.ParentID != 0)
|
||||
localid = prim.ParentID;
|
||||
else
|
||||
localid = prim.LocalID;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (localid != 0)
|
||||
{
|
||||
// Check for export permission first
|
||||
Client.Objects.RequestObjectPropertiesFamily(Client.Network.CurrentSim, id);
|
||||
GotPermissionsEvent.WaitOne(8000, false);
|
||||
|
||||
if (!GotPermissions)
|
||||
{
|
||||
return "Couldn't fetch permissions for the requested object, try again";
|
||||
}
|
||||
else
|
||||
{
|
||||
GotPermissions = false;
|
||||
if (Properties.OwnerID != Client.Network.AgentID &&
|
||||
Properties.OwnerID != Client.MasterKey &&
|
||||
Client.Network.AgentID != Client.Self.ID)
|
||||
{
|
||||
return "That object is owned by " + Properties.OwnerID + ", we don't have permission " +
|
||||
"to export it";
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
XmlWriterSettings settings = new XmlWriterSettings();
|
||||
settings.Indent = true;
|
||||
XmlWriter writer = XmlWriter.Create(file, settings);
|
||||
|
||||
try
|
||||
{
|
||||
List<Primitive> prims = new List<Primitive>();
|
||||
|
||||
lock (Client.SimPrims)
|
||||
{
|
||||
if (Client.SimPrims.ContainsKey(Client.Network.CurrentSim))
|
||||
{
|
||||
foreach (Primitive prim in Client.SimPrims[Client.Network.CurrentSim].Values)
|
||||
{
|
||||
if (prim.LocalID == localid || prim.ParentID == localid)
|
||||
{
|
||||
prims.Add(prim);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool complete = RequestObjectProperties(prims, 250);
|
||||
|
||||
//Serialize it!
|
||||
Helpers.PrimListToXml(prims, writer);
|
||||
|
||||
if (!complete) {
|
||||
Console.WriteLine("Warning: Unable to retrieve full properties for:");
|
||||
foreach (LLUUID uuid in PrimsWaiting.Keys)
|
||||
Console.WriteLine(uuid);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
writer.Close();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
string ret = "Failed to write to " + file + ":" + e.ToString();
|
||||
if (ret.Length > 1000)
|
||||
{
|
||||
ret = ret.Remove(1000);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
return "Exported " + count + " prims to " + file;
|
||||
}
|
||||
else
|
||||
{
|
||||
return "Couldn't find UUID " + id.ToString() + " in the " +
|
||||
Client.SimPrims[Client.Network.CurrentSim].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);
|
||||
}
|
||||
|
||||
void Avatars_OnPointAt(LLUUID sourceID, LLUUID targetID, LLVector3d targetPos,
|
||||
MainAvatar.PointAtType pointType, float duration, LLUUID id)
|
||||
{
|
||||
if (sourceID == Client.MasterKey)
|
||||
{
|
||||
//Client.DebugLog("Master is now selecting " + targetID.ToStringHyphenated());
|
||||
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)
|
||||
{
|
||||
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,119 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using libsecondlife;
|
||||
|
||||
namespace libsecondlife.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.SimPrims)
|
||||
{
|
||||
if (Client.SimPrims.ContainsKey(Client.Network.CurrentSim))
|
||||
{
|
||||
foreach (Primitive prim in Client.SimPrims[Client.Network.CurrentSim].Values)
|
||||
{
|
||||
if (prim.ID == id)
|
||||
{
|
||||
if (prim.ParticleSys.CRC != 0)
|
||||
{
|
||||
StringBuilder lsl = new StringBuilder();
|
||||
|
||||
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 ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.InterpColor) != 0)
|
||||
lsl.Append(" | PSYS_PART_INTERP_COLOR_MASK");
|
||||
if ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.InterpScale) != 0)
|
||||
lsl.Append(" | PSYS_PART_INTERP_SCALE_MASK");
|
||||
if ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.Bounce) != 0)
|
||||
lsl.Append(" | PSYS_PART_BOUNCE_MASK");
|
||||
if ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.Wind) != 0)
|
||||
lsl.Append(" | PSYS_PART_WIND_MASK");
|
||||
if ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.FollowSrc) != 0)
|
||||
lsl.Append(" | PSYS_PART_FOLLOW_SRC_MASK");
|
||||
if ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.FollowVelocity) != 0)
|
||||
lsl.Append(" | PSYS_PART_FOLLOW_VELOCITY_MASK");
|
||||
if ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.TargetPos) != 0)
|
||||
lsl.Append(" | PSYS_PART_TARGET_POS_MASK");
|
||||
if ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.TargetLinear) != 0)
|
||||
lsl.Append(" | PSYS_PART_TARGET_LINEAR_MASK");
|
||||
if ((prim.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 ((prim.ParticleSys.Pattern & Primitive.ParticleSystem.SourcePattern.Drop) != 0)
|
||||
lsl.Append(" | PSYS_SRC_PATTERN_DROP");
|
||||
if ((prim.ParticleSys.Pattern & Primitive.ParticleSystem.SourcePattern.Explode) != 0)
|
||||
lsl.Append(" | PSYS_SRC_PATTERN_EXPLODE");
|
||||
if ((prim.ParticleSys.Pattern & Primitive.ParticleSystem.SourcePattern.Angle) != 0)
|
||||
lsl.Append(" | PSYS_SRC_PATTERN_ANGLE");
|
||||
if ((prim.ParticleSys.Pattern & Primitive.ParticleSystem.SourcePattern.AngleCone) != 0)
|
||||
lsl.Append(" | PSYS_SRC_PATTERN_ANGLE_CONE");
|
||||
if ((prim.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}", prim.ParticleSys.PartStartColor.A) + "," + Environment.NewLine);
|
||||
lsl.Append(" PSYS_PART_END_ALPHA, " + String.Format("{0:0.00000}", prim.ParticleSys.PartEndColor.A) + "," + Environment.NewLine);
|
||||
lsl.Append(" PSYS_PART_START_COLOR, " + prim.ParticleSys.PartStartColor.ToStringRGB() + "," + Environment.NewLine);
|
||||
lsl.Append(" PSYS_PART_END_COLOR, " + prim.ParticleSys.PartEndColor.ToStringRGB() + "," + Environment.NewLine);
|
||||
lsl.Append(" PSYS_PART_START_SCALE, <" + String.Format("{0:0.00000}", prim.ParticleSys.PartStartScaleX) + ", " + String.Format("{0:0.00000}", prim.ParticleSys.PartStartScaleY) + ", 0>, " + Environment.NewLine);
|
||||
lsl.Append(" PSYS_PART_END_SCALE, <" + String.Format("{0:0.00000}", prim.ParticleSys.PartEndScaleX) + ", " + String.Format("{0:0.00000}", prim.ParticleSys.PartEndScaleY) + ", 0>, " + Environment.NewLine);
|
||||
lsl.Append(" PSYS_PART_MAX_AGE, " + String.Format("{0:0.00000}", prim.ParticleSys.PartMaxAge) + "," + Environment.NewLine);
|
||||
lsl.Append(" PSYS_SRC_MAX_AGE, " + String.Format("{0:0.00000}", prim.ParticleSys.MaxAge) + "," + Environment.NewLine);
|
||||
lsl.Append(" PSYS_SRC_ACCEL, " + prim.ParticleSys.PartAcceleration.ToString() + "," + Environment.NewLine);
|
||||
lsl.Append(" PSYS_SRC_BURST_PART_COUNT, " + String.Format("{0:0}", prim.ParticleSys.BurstPartCount) + "," + Environment.NewLine);
|
||||
lsl.Append(" PSYS_SRC_BURST_RADIUS, " + String.Format("{0:0.00000}", prim.ParticleSys.BurstRadius) + "," + Environment.NewLine);
|
||||
lsl.Append(" PSYS_SRC_BURST_RATE, " + String.Format("{0:0.00000}", prim.ParticleSys.BurstRate) + "," + Environment.NewLine);
|
||||
lsl.Append(" PSYS_SRC_BURST_SPEED_MIN, " + String.Format("{0:0.00000}", prim.ParticleSys.BurstSpeedMin) + "," + Environment.NewLine);
|
||||
lsl.Append(" PSYS_SRC_BURST_SPEED_MAX, " + String.Format("{0:0.00000}", prim.ParticleSys.BurstSpeedMax) + "," + Environment.NewLine);
|
||||
lsl.Append(" PSYS_SRC_INNERANGLE, " + String.Format("{0:0.00000}", prim.ParticleSys.InnerAngle) + "," + Environment.NewLine);
|
||||
lsl.Append(" PSYS_SRC_OUTERANGLE, " + String.Format("{0:0.00000}", prim.ParticleSys.OuterAngle) + "," + Environment.NewLine);
|
||||
lsl.Append(" PSYS_SRC_OMEGA, " + prim.ParticleSys.AngularVelocity.ToString() + "," + Environment.NewLine);
|
||||
lsl.Append(" PSYS_SRC_TEXTURE, (key)\"" + prim.ParticleSys.Texture.ToStringHyphenated() + "\"," + Environment.NewLine);
|
||||
lsl.Append(" PSYS_SRC_TARGET_KEY, (key)\"" + prim.ParticleSys.Target.ToStringHyphenated() + "\"" + Environment.NewLine);
|
||||
|
||||
lsl.Append(" ]);" + Environment.NewLine);
|
||||
lsl.Append(" }" + Environment.NewLine);
|
||||
lsl.Append("}" + Environment.NewLine);
|
||||
|
||||
return lsl.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
return "Prim " + prim.LocalID + " does not have a particle system";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "Couldn't find prim " + id.ToStringHyphenated();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,246 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml;
|
||||
using System.Xml.Serialization;
|
||||
using System.Threading;
|
||||
using System.IO;
|
||||
using libsecondlife;
|
||||
|
||||
namespace libsecondlife.TestClient
|
||||
{
|
||||
enum ImporterState
|
||||
{
|
||||
RezzingParent,
|
||||
RezzingChildren,
|
||||
Linking,
|
||||
Idle
|
||||
}
|
||||
|
||||
public class Linkset
|
||||
{
|
||||
public Primitive RootPrim;
|
||||
public List<Primitive> Children = new List<Primitive>();
|
||||
|
||||
public Linkset()
|
||||
{
|
||||
RootPrim = new Primitive();
|
||||
}
|
||||
|
||||
public Linkset(Primitive rootPrim)
|
||||
{
|
||||
RootPrim = rootPrim;
|
||||
}
|
||||
}
|
||||
|
||||
public class ImportCommand : Command
|
||||
{
|
||||
Primitive currentPrim;
|
||||
LLVector3 currentPosition;
|
||||
SecondLife currentClient;
|
||||
AutoResetEvent primDone;
|
||||
List<Primitive> primsCreated;
|
||||
List<uint> linkQueue;
|
||||
uint rootLocalID = 0;
|
||||
bool registeredCreateEvent = false;
|
||||
|
||||
ImporterState state = ImporterState.Idle;
|
||||
|
||||
public ImportCommand(TestClient testClient)
|
||||
{
|
||||
Name = "import";
|
||||
Description = "Import prims from an exported xml file. Usage: import inputfile.xml";
|
||||
primDone = new AutoResetEvent(false);
|
||||
registeredCreateEvent = false;
|
||||
}
|
||||
|
||||
public override string Execute(string[] args, LLUUID fromAgentID)
|
||||
{
|
||||
if (args.Length != 1)
|
||||
return "Usage: import inputfile.xml";
|
||||
|
||||
string filename = args[0];
|
||||
Dictionary<uint, Primitive> prims;
|
||||
|
||||
currentClient = Client;
|
||||
|
||||
try
|
||||
{
|
||||
XmlReader reader = XmlReader.Create(filename);
|
||||
List<Primitive> listprims = Helpers.PrimListFromXml(reader);
|
||||
reader.Close();
|
||||
|
||||
// Create a dictionary indexed by the old local ID of the prims
|
||||
prims = new Dictionary<uint, Primitive>();
|
||||
foreach (Primitive prim in listprims)
|
||||
{
|
||||
prims.Add(prim.LocalID, prim);
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return "Failed to import the object XML file, maybe it doesn't exist or is in the wrong format?";
|
||||
}
|
||||
|
||||
if (!registeredCreateEvent)
|
||||
{
|
||||
Client.OnPrimCreated += new TestClient.PrimCreatedCallback(TestClient_OnPrimCreated);
|
||||
registeredCreateEvent = true;
|
||||
}
|
||||
|
||||
// Build an organized structure from the imported prims
|
||||
Dictionary<uint, Linkset> linksets = new Dictionary<uint, Linkset>();
|
||||
foreach (Primitive prim in prims.Values)
|
||||
{
|
||||
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: Offset the root prim position so it's not lying on top of the original
|
||||
// We need a more elaborate solution for importing with relative or absolute offsets
|
||||
linkset.RootPrim.Position = Client.Self.Position;
|
||||
linkset.RootPrim.Position.Z += 3.0f;
|
||||
currentPosition = linkset.RootPrim.Position;
|
||||
// A better solution would move the bot to the desired position.
|
||||
// or to check if we are within a certain distance of the desired 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, LLUUID.Zero,
|
||||
linkset.RootPrim.Position, linkset.RootPrim.Scale, linkset.RootPrim.Rotation);
|
||||
|
||||
if (!primDone.WaitOne(10000, false))
|
||||
return "Rez failed, timed out while creating the root prim.";
|
||||
|
||||
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, LLUUID.Zero, currentPosition,
|
||||
prim.Scale, prim.Rotation);
|
||||
|
||||
if (!primDone.WaitOne(10000, false))
|
||||
return "Rez failed, timed out while creating child prim.";
|
||||
}
|
||||
|
||||
if (linkset.Children.Count != 0)
|
||||
{
|
||||
// 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.
|
||||
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(100000 * linkset.Children.Count, false))
|
||||
{
|
||||
Client.Objects.SetPermissions(Client.Network.CurrentSim, primIDs,
|
||||
Helpers.PermissionWho.Everyone | Helpers.PermissionWho.Group | Helpers.PermissionWho.NextOwner,
|
||||
Helpers.PermissionType.Copy | Helpers.PermissionType.Modify | Helpers.PermissionType.Move |
|
||||
Helpers.PermissionType.Transfer, true);
|
||||
|
||||
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);
|
||||
}
|
||||
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 TestClient_OnPrimCreated(Simulator simulator, Primitive prim)
|
||||
{
|
||||
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?
|
||||
currentClient.Objects.SetPosition(simulator, prim.LocalID, currentPosition);
|
||||
currentClient.Objects.SetTextures(simulator, prim.LocalID, currentPrim.Textures);
|
||||
currentClient.Objects.SetLight(simulator, prim.LocalID, currentPrim.Light);
|
||||
currentClient.Objects.SetFlexible(simulator, prim.LocalID, currentPrim.Flexible);
|
||||
|
||||
if (!String.IsNullOrEmpty(currentPrim.Properties.Name))
|
||||
currentClient.Objects.SetName(simulator, prim.LocalID, currentPrim.Properties.Name);
|
||||
if (!String.IsNullOrEmpty(currentPrim.Properties.Description))
|
||||
currentClient.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,32 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using libsecondlife;
|
||||
using libsecondlife.Packets;
|
||||
|
||||
namespace libsecondlife.TestClient
|
||||
{
|
||||
public class PrimCountCommand: Command
|
||||
{
|
||||
public PrimCountCommand(TestClient testClient)
|
||||
{
|
||||
Name = "primcount";
|
||||
Description = "Shows the number of prims that have been received.";
|
||||
}
|
||||
|
||||
public override string Execute(string[] args, LLUUID fromAgentID)
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
lock (Client.SimPrims)
|
||||
{
|
||||
foreach (Dictionary<uint, Primitive> prims in Client.SimPrims.Values)
|
||||
{
|
||||
count += prims.Count;
|
||||
}
|
||||
}
|
||||
|
||||
return count.ToString();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using libsecondlife;
|
||||
using libsecondlife.Packets;
|
||||
|
||||
namespace libsecondlife.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.Dilation.ToString();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
using libsecondlife;
|
||||
|
||||
namespace libsecondlife.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("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.ToStringHyphenated());
|
||||
output.Append("TerrainBase1: ");
|
||||
output.AppendLine(Client.Network.CurrentSim.TerrainBase1.ToStringHyphenated());
|
||||
output.Append("TerrainBase2: ");
|
||||
output.AppendLine(Client.Network.CurrentSim.TerrainBase2.ToStringHyphenated());
|
||||
output.Append("TerrainBase3: ");
|
||||
output.AppendLine(Client.Network.CurrentSim.TerrainBase3.ToStringHyphenated());
|
||||
output.Append("TerrainDetail0: ");
|
||||
output.AppendLine(Client.Network.CurrentSim.TerrainDetail0.ToStringHyphenated());
|
||||
output.Append("TerrainDetail1: ");
|
||||
output.AppendLine(Client.Network.CurrentSim.TerrainDetail1.ToStringHyphenated());
|
||||
output.Append("TerrainDetail2: ");
|
||||
output.AppendLine(Client.Network.CurrentSim.TerrainDetail2.ToStringHyphenated());
|
||||
output.Append("TerrainDetail3: ");
|
||||
output.AppendLine(Client.Network.CurrentSim.TerrainDetail3.ToStringHyphenated());
|
||||
output.Append("Water Height: ");
|
||||
output.AppendLine(Client.Network.CurrentSim.WaterHeight.ToString());
|
||||
|
||||
return output.ToString();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using libsecondlife;
|
||||
using libsecondlife.Packets;
|
||||
|
||||
namespace libsecondlife.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.Dilation, sim.IncomingBPS, sim.OutgoingBPS, sim.ResentPackets,
|
||||
sim.ReceivedResends));
|
||||
}
|
||||
}
|
||||
output.Append("Packets in the queue: " + Client.Network.InboxCount);
|
||||
output.AppendLine(String.Format("FPS : {0} PhysicsFPS : {1} AgentUpdates : {2} Objects : {3} Scripted Objects : {4}",
|
||||
Client.Network.CurrentSim.FPS, Client.Network.CurrentSim.PhysicsFPS, Client.Network.CurrentSim.AgentUpdates, Client.Network.CurrentSim.Objects, Client.Network.CurrentSim.ScriptedObjects));
|
||||
output.AppendLine(String.Format("Frame Time : {0} Net Time : {1} Image Time : {2} Physics Time : {3} Script Time : {4} Other Time : {5}",
|
||||
Client.Network.CurrentSim.FrameTime, Client.Network.CurrentSim.NetTime, Client.Network.CurrentSim.ImageTime, Client.Network.CurrentSim.PhysicsTime, Client.Network.CurrentSim.ScriptTime, Client.Network.CurrentSim.OtherTime));
|
||||
output.AppendLine(String.Format("Agents : {0} Child Agents : {1} Active Scripts : {2}",
|
||||
Client.Network.CurrentSim.Agents, Client.Network.CurrentSim.ChildAgents, Client.Network.CurrentSim.ActiveScripts));
|
||||
|
||||
return output.ToString();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using libsecondlife;
|
||||
using libsecondlife.Packets;
|
||||
|
||||
namespace libsecondlife.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) + ")";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using libsecondlife;
|
||||
using libsecondlife.Packets;
|
||||
|
||||
namespace libsecondlife.TestClient
|
||||
{
|
||||
public class DebugCommand : Command
|
||||
{
|
||||
public DebugCommand(TestClient testClient)
|
||||
{
|
||||
Name = "debug";
|
||||
Description = "Turn debug messages on or off. Usage: debug [on/off]";
|
||||
}
|
||||
|
||||
public override string Execute(string[] args, LLUUID fromAgentID)
|
||||
{
|
||||
if (args.Length != 1)
|
||||
return "Usage: debug [on/off]";
|
||||
|
||||
if (args[0].ToLower() == "on")
|
||||
{
|
||||
Client.Settings.DEBUG = true;
|
||||
return "Debug logging is on";
|
||||
}
|
||||
else if (args[0].ToLower() == "off")
|
||||
{
|
||||
Client.Settings.DEBUG = false;
|
||||
return "Debug logging is off";
|
||||
}
|
||||
else
|
||||
{
|
||||
return "Usage: debug [on/off]";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using libsecondlife;
|
||||
using libsecondlife.Packets;
|
||||
|
||||
namespace libsecondlife.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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Reflection;
|
||||
using libsecondlife;
|
||||
using libsecondlife.Packets;
|
||||
|
||||
namespace libsecondlife.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.";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using libsecondlife;
|
||||
using libsecondlife.Packets;
|
||||
|
||||
namespace libsecondlife.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]";
|
||||
|
||||
SecondLife 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 libsecondlife;
|
||||
using libsecondlife.Packets;
|
||||
|
||||
namespace libsecondlife.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";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
using System;
|
||||
using libsecondlife;
|
||||
|
||||
namespace libsecondlife.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,84 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml;
|
||||
using libsecondlife;
|
||||
using libsecondlife.Packets;
|
||||
|
||||
namespace libsecondlife.TestClient
|
||||
{
|
||||
public class PacketLogCommand : Command
|
||||
{
|
||||
List<Packet> Packets = new List<Packet>();
|
||||
bool Done = false;
|
||||
int Count = 0;
|
||||
int Total = 0;
|
||||
|
||||
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";
|
||||
|
||||
XmlWriter writer;
|
||||
NetworkManager.PacketCallback callback = new NetworkManager.PacketCallback(OnPacket);
|
||||
|
||||
Packets.Clear();
|
||||
Done = false;
|
||||
Count = 0;
|
||||
|
||||
try
|
||||
{
|
||||
Total = Int32.Parse(args[0]);
|
||||
writer = XmlWriter.Create(args[1]);
|
||||
|
||||
Client.Network.RegisterCallback(PacketType.Default, callback);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return "Usage: packetlog 10 tenpackets.xml (" + e + ")";
|
||||
}
|
||||
|
||||
while (!Done)
|
||||
{
|
||||
System.Threading.Thread.Sleep(100);
|
||||
}
|
||||
|
||||
Client.Network.UnregisterCallback(PacketType.Default, callback);
|
||||
|
||||
try
|
||||
{
|
||||
Helpers.PacketListToXml(Packets, writer);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return "Serialization failed: " + e.ToString();
|
||||
}
|
||||
|
||||
writer.Close();
|
||||
Packets.Clear();
|
||||
|
||||
return "Exported " + Count + " packets to " + args[1];
|
||||
}
|
||||
|
||||
private void OnPacket(Packet packet, Simulator simulator)
|
||||
{
|
||||
lock (Packets)
|
||||
{
|
||||
if (Count >= Total)
|
||||
{
|
||||
Done = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Packets.Add(packet);
|
||||
Count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using libsecondlife;
|
||||
using libsecondlife.Packets;
|
||||
|
||||
namespace libsecondlife.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,73 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using libsecondlife;
|
||||
using libsecondlife.Packets;
|
||||
|
||||
namespace libsecondlife.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.";
|
||||
|
||||
}
|
||||
|
||||
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.";
|
||||
}
|
||||
|
||||
|
||||
foreach (Avatar av in Client.AvatarList.Values)
|
||||
{
|
||||
if (av.ID == Client.MasterKey)
|
||||
{
|
||||
Client.Self.InstantMessage(av.ID, "You are now my master. IM me with \"help\" for a command list.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return "Master set to " + masterName + " (" + Client.MasterKey.ToStringHyphenated() + ")";
|
||||
}
|
||||
|
||||
private void KeyResolvHandler(LLUUID queryid, List<DirectoryManager.AgentSearchData> matches)
|
||||
{
|
||||
if (query != queryid)
|
||||
return;
|
||||
// We can't handle ambiguities here as nicely as we can in ClientManager.
|
||||
resolvedMasterKey = matches[0].AgentID;
|
||||
keyResolution.Set();
|
||||
query = LLUUID.Zero;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using libsecondlife;
|
||||
using libsecondlife.Packets;
|
||||
|
||||
namespace libsecondlife.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]);
|
||||
|
||||
foreach (Avatar av in Client.AvatarList.Values)
|
||||
{
|
||||
if (av.ID == Client.MasterKey)
|
||||
{
|
||||
Client.Self.InstantMessage(av.ID, "You are now my master. IM me with \"help\" for a command list.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return "Master set to " + Client.MasterKey;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
using System;
|
||||
using libsecondlife;
|
||||
|
||||
namespace libsecondlife.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,
|
||||
MainAvatar.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.ToStringHyphenated(), targetID.ToStringHyphenated(), targetPos, pointType, duration,
|
||||
id.ToStringHyphenated());
|
||||
}
|
||||
|
||||
private void Avatars_OnLookAt(LLUUID sourceID, LLUUID targetID, LLVector3d targetPos,
|
||||
MainAvatar.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.ToStringHyphenated(), targetID.ToStringHyphenated(), targetPos, lookType, duration,
|
||||
id.ToStringHyphenated());
|
||||
}
|
||||
|
||||
private void Avatars_OnEffect(MainAvatar.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.ToStringHyphenated(), targetID.ToStringHyphenated(), targetPos, duration,
|
||||
id.ToStringHyphenated());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using libsecondlife;
|
||||
using libsecondlife.Packets;
|
||||
|
||||
namespace libsecondlife.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)
|
||||
{
|
||||
Primitive target = null;
|
||||
|
||||
lock (Client.SimPrims)
|
||||
{
|
||||
if (Client.SimPrims.ContainsKey(Client.Network.CurrentSim))
|
||||
{
|
||||
foreach (Primitive p in Client.SimPrims[Client.Network.CurrentSim].Values)
|
||||
{
|
||||
if (args.Length == 0)
|
||||
return "You must specify a UUID of the prim.";
|
||||
|
||||
try
|
||||
{
|
||||
if (p.ID == args[0])
|
||||
target = p;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// handle exception
|
||||
return "Sorry, I don't think " + args[0] + " is a valid UUID. I'm unable to touch it.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (target != null)
|
||||
{
|
||||
Client.Self.Touch(target.LocalID);
|
||||
return "Touched prim " + target.ID + ".";
|
||||
}
|
||||
else
|
||||
{
|
||||
return "Couldn't find that prim.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using libsecondlife;
|
||||
using libsecondlife.Packets;
|
||||
|
||||
namespace libsecondlife.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[] { ' ' });
|
||||
ObjectManager.Tree tree = (ObjectManager.Tree)Enum.Parse(typeof(ObjectManager.Tree), treeName);
|
||||
|
||||
LLVector3 treePosition = new LLVector3(Client.Self.Position.X, Client.Self.Position.Y,
|
||||
Client.Self.Position.Z);
|
||||
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(ObjectManager.Tree)))
|
||||
{
|
||||
usage += value + ",";
|
||||
}
|
||||
usage = usage.TrimEnd(new char[] { ',' });
|
||||
usage += "]";
|
||||
return usage;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using libsecondlife;
|
||||
using libsecondlife.Packets;
|
||||
|
||||
namespace libsecondlife.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();
|
||||
foreach (Avatar av in Client.AvatarList.Values)
|
||||
{
|
||||
result.AppendFormat("\n{0} {1} {2}/{3} ID: {4}", av.Name, av.GroupName,
|
||||
(av.CurrentSim != null ? av.CurrentSim.Name : String.Empty), av.Position, av.ID);
|
||||
}
|
||||
|
||||
return result.ToString();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
<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>libsecondlife.MassTestClient</RootNamespace>
|
||||
<AssemblyName>MassTestClient</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>
|
||||
<ItemGroup>
|
||||
<Reference Include="libsecondlife, Version=0.9.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>bin\libsecondlife.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="libsecondlife.Utilities, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>bin\libsecondlife.Utilities.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="openjpegnet, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>bin\openjpegnet.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Arguments.cs" />
|
||||
<Compile Include="Command.cs" />
|
||||
<Compile Include="Commands\Inventory\AppearanceCommand.cs" />
|
||||
<Compile Include="Commands\CloneProfileCommand.cs" />
|
||||
<Compile Include="Commands\System\DebugCommand.cs" />
|
||||
<Compile Include="Commands\Inventory\DumpOutfitCommand.cs" />
|
||||
<Compile Include="Commands\Prims\ExportParticlesCommand.cs" />
|
||||
<Compile Include="Commands\Inventory\BalanceCommand.cs" />
|
||||
<Compile Include="Commands\Inventory\DeleteFolderCommand.cs" />
|
||||
<Compile Include="Commands\Inventory\GiveAllCommand.cs" />
|
||||
<Compile Include="Commands\Inventory\WearCommand.cs" />
|
||||
<Compile Include="Commands\Inventory\InventoryCommand.cs" />
|
||||
<Compile Include="Commands\Inventory\ExportOutfitCommand.cs" />
|
||||
<Compile Include="Commands\Land\FindSimCommand.cs" />
|
||||
<Compile Include="Commands\Inventory\ImportOutfitCommand.cs" />
|
||||
<Compile Include="Commands\System\LoginCommand.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Commands\System\LogoutCommand.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Commands\Communication\EchoMasterCommand.cs" />
|
||||
<Compile Include="Commands\Communication\IMCommand.cs" />
|
||||
<Compile Include="Commands\Communication\SayCommand.cs" />
|
||||
<Compile Include="Commands\Communication\ShoutCommand.cs" />
|
||||
<Compile Include="Commands\Communication\WhisperCommand.cs" />
|
||||
<Compile Include="Commands\System\MD5Command.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\SitCommand.cs" />
|
||||
<Compile Include="Commands\System\PacketLogCommand.cs" />
|
||||
<Compile Include="Commands\Land\ParcelInfoCommand.cs" />
|
||||
<Compile Include="Commands\System\QuitCommand.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Commands\Stats\RegionInfoCommand.cs" />
|
||||
<Compile Include="Commands\System\SetMasterCommand.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Commands\Prims\ExportCommand.cs" />
|
||||
<Compile Include="Commands\Prims\ImportCommand.cs" />
|
||||
<Compile Include="Commands\System\LoadCommand.cs" />
|
||||
<Compile Include="Commands\Prims\PrimCountCommand.cs" />
|
||||
<Compile Include="Commands\System\SetMasterKeyCommand.cs" />
|
||||
<Compile Include="Commands\System\ShowEffectsCommand.cs" />
|
||||
<Compile Include="Commands\Stats\StatsCommand.cs" />
|
||||
<Compile Include="Commands\TouchCommand.cs" />
|
||||
<Compile Include="Commands\TreeCommand.cs" />
|
||||
<Compile Include="Commands\Stats\UptimeCommand.cs" />
|
||||
<Compile Include="Commands\System\HelpCommand.cs" />
|
||||
<Compile Include="ClientManager.cs" />
|
||||
<Compile Include="Commands\WhoCommand.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Parsing.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="TestClient.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</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>
|
||||
-->
|
||||
<PropertyGroup>
|
||||
<PreBuildEvent>
|
||||
</PreBuildEvent>
|
||||
</PropertyGroup>
|
||||
</Project>
|
|
@ -0,0 +1,10 @@
|
|||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<StartArguments>
|
||||
</StartArguments>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<StartArguments>
|
||||
</StartArguments>
|
||||
</PropertyGroup>
|
||||
</Project>
|
|
@ -0,0 +1,20 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 9.00
|
||||
# Visual C# Express 2005
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MassTestClient", "MassTestClient.csproj", "{B87682F6-B2D7-4C4D-A529-400C24FD4880}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{B87682F6-B2D7-4C4D-A529-400C24FD4880}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B87682F6-B2D7-4C4D-A529-400C24FD4880}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B87682F6-B2D7-4C4D-A529-400C24FD4880}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B87682F6-B2D7-4C4D-A529-400C24FD4880}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
Binary file not shown.
|
@ -0,0 +1,61 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace libsecondlife.TestClient {
|
||||
class Parsing {
|
||||
public static string[] ParseArguments(string str) {
|
||||
List<string> list = new List<string>();
|
||||
string current = "";
|
||||
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 = "";
|
||||
}
|
||||
} 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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,218 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using CommandLine.Utility;
|
||||
|
||||
namespace libsecondlife.TestClient
|
||||
{
|
||||
public class CommandLineArgumentsException : Exception
|
||||
{
|
||||
}
|
||||
|
||||
public class Program
|
||||
{
|
||||
|
||||
private static void Usage()
|
||||
{
|
||||
Console.WriteLine("Usage: " + Environment.NewLine +
|
||||
"MassTestClient.exe --first \"firstname\" --last \"lastname\" --pass \"password\" --contact \"youremail\" [--startpos \"sim/x/y/z\"] [--master \"master name\"] [--masterkey \"master uuid\"] [--loginuri \"loginuri\"] [--masscommandfile \"filename\"]" +
|
||||
Environment.NewLine + Environment.NewLine + "MassTestClient.exe --loginfile \"filename\" --contact \"youremail\" [--master \"master name\"] [--masterkey \"master uuid\"] [--loginuri \"loginuri\"] [--masscommandfile \"filename\"]");
|
||||
Console.ReadLine();
|
||||
}
|
||||
|
||||
private static List<string> getMassTestCommands()
|
||||
{
|
||||
List<string> givenCommands = new List<string>();
|
||||
Console.WriteLine("Please enter mass test commands to run in an infinite loop. Press enter to end the current command. Entering a blank command represents that you are done.");
|
||||
Console.WriteLine("");
|
||||
|
||||
int curCommand = 0;
|
||||
string lastCommand = "NULL";
|
||||
while (lastCommand.Length > 0)
|
||||
{
|
||||
Console.Write("Command #" + curCommand + ">");
|
||||
lastCommand = Console.ReadLine().Trim();
|
||||
if (lastCommand.Length > 0)
|
||||
{
|
||||
givenCommands.Add(lastCommand);
|
||||
curCommand++;
|
||||
}
|
||||
}
|
||||
|
||||
return givenCommands;
|
||||
}
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
Arguments arguments = new Arguments(args);
|
||||
|
||||
ClientManager manager;
|
||||
List<LoginDetails> accounts = new List<LoginDetails>();
|
||||
LoginDetails account;
|
||||
string masterName = String.Empty;
|
||||
LLUUID masterKey = LLUUID.Zero;
|
||||
string file = String.Empty;
|
||||
string contact = String.Empty;
|
||||
string loginURI = "https://login.agni.lindenlab.com/cgi-bin/login.cgi";
|
||||
try
|
||||
{
|
||||
if (arguments["masterkey"] != null)
|
||||
{
|
||||
masterKey = LLUUID.Parse(arguments["masterkey"]);
|
||||
}
|
||||
|
||||
if (arguments["master"] != null)
|
||||
{
|
||||
masterName = arguments["master"];
|
||||
}
|
||||
|
||||
if (arguments["contact"] == null)
|
||||
throw new CommandLineArgumentsException();
|
||||
|
||||
contact = arguments["contact"];
|
||||
|
||||
if (arguments["file"] != null)
|
||||
{
|
||||
file = arguments["file"];
|
||||
|
||||
// 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());
|
||||
Console.ReadLine();
|
||||
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;
|
||||
}
|
||||
|
||||
if(arguments["loginuri"] != null)
|
||||
{
|
||||
loginURI = arguments["loginuri"];
|
||||
}
|
||||
|
||||
List<string> massTestCommands = new List<string>();
|
||||
if(arguments["masscommandfile"] != null)
|
||||
{
|
||||
string massCommandFile = arguments["masscommandfile"];
|
||||
try
|
||||
{
|
||||
using (StreamReader reader = new StreamReader(massCommandFile))
|
||||
{
|
||||
string line;
|
||||
|
||||
while ((line = reader.ReadLine()) != null)
|
||||
{
|
||||
|
||||
line = line.Trim();
|
||||
if(line.Length > 0)
|
||||
{
|
||||
massTestCommands.Add(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine("Error reading from " + args[1]);
|
||||
Console.WriteLine(e.ToString());
|
||||
Console.ReadLine();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Clear();
|
||||
massTestCommands = getMassTestCommands();
|
||||
}
|
||||
|
||||
Console.Clear();
|
||||
if (massTestCommands.Count == 0)
|
||||
{
|
||||
Console.WriteLine("No mass commands entered; Normal 'TestClient' operation will be used");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Detected " + massTestCommands.Count + " mass commands; MassTestClient operation will be used");
|
||||
}
|
||||
|
||||
foreach (LoginDetails a in accounts)
|
||||
{
|
||||
a.MasterName = masterName;
|
||||
a.MasterKey = masterKey;
|
||||
a.LoginURI = loginURI;
|
||||
}
|
||||
|
||||
// Login the accounts and run the input loop
|
||||
if (arguments["startpos"] != null)
|
||||
{
|
||||
manager = new ClientManager(accounts, contact, arguments["startpos"]);
|
||||
}
|
||||
else
|
||||
{
|
||||
manager = new ClientManager(accounts, contact);
|
||||
}
|
||||
|
||||
|
||||
manager.Run(massTestCommands);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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("MassTestClient")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("MassTestClient")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2007")]
|
||||
[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")]
|
|
@ -0,0 +1,125 @@
|
|||
<?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"/>
|
||||
</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>
|
|
@ -0,0 +1,324 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Xml;
|
||||
using libsecondlife;
|
||||
using libsecondlife.Packets;
|
||||
using libsecondlife.AssetSystem;
|
||||
|
||||
namespace libsecondlife.TestClient
|
||||
{
|
||||
public class TestClient : SecondLife
|
||||
{
|
||||
public delegate void PrimCreatedCallback(Simulator simulator, Primitive prim);
|
||||
|
||||
public event PrimCreatedCallback OnPrimCreated;
|
||||
|
||||
public Dictionary<Simulator, Dictionary<uint, Primitive>> SimPrims;
|
||||
public LLUUID GroupID = LLUUID.Zero;
|
||||
public Dictionary<LLUUID, GroupMember> GroupMembers;
|
||||
public Dictionary<uint, Avatar> AvatarList = new Dictionary<uint,Avatar>();
|
||||
public Dictionary<LLUUID, AvatarAppearancePacket> Appearances = new Dictionary<LLUUID, AvatarAppearancePacket>();
|
||||
public Dictionary<string, Command> Commands = new Dictionary<string,Command>();
|
||||
public bool Running = true;
|
||||
public string MasterName = String.Empty;
|
||||
public LLUUID MasterKey = LLUUID.Zero;
|
||||
public ClientManager ClientManager;
|
||||
public int regionX;
|
||||
public int regionY;
|
||||
|
||||
//internal libsecondlife.InventorySystem.InventoryFolder currentDirectory;
|
||||
|
||||
private System.Timers.Timer updateTimer;
|
||||
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public TestClient(ClientManager manager)
|
||||
{
|
||||
ClientManager = manager;
|
||||
|
||||
updateTimer = new System.Timers.Timer(1000);
|
||||
updateTimer.Elapsed += new System.Timers.ElapsedEventHandler(updateTimer_Elapsed);
|
||||
|
||||
RegisterAllCommands(Assembly.GetExecutingAssembly());
|
||||
|
||||
Settings.DEBUG = true;
|
||||
Settings.STORE_LAND_PATCHES = true;
|
||||
Settings.ALWAYS_REQUEST_OBJECTS = true;
|
||||
|
||||
Network.RegisterCallback(PacketType.AgentDataUpdate, new NetworkManager.PacketCallback(AgentDataUpdateHandler));
|
||||
|
||||
Objects.OnNewPrim += new ObjectManager.NewPrimCallback(Objects_OnNewPrim);
|
||||
Objects.OnObjectUpdated += new ObjectManager.ObjectUpdatedCallback(Objects_OnObjectUpdated);
|
||||
Objects.OnObjectKilled += new ObjectManager.KillObjectCallback(Objects_OnObjectKilled);
|
||||
Objects.OnNewAvatar += new ObjectManager.NewAvatarCallback(Objects_OnNewAvatar);
|
||||
Self.OnInstantMessage += new MainAvatar.InstantMessageCallback(Self_OnInstantMessage);
|
||||
Groups.OnGroupMembers += new GroupManager.GroupMembersCallback(GroupMembersHandler);
|
||||
this.OnLogMessage += new LogCallback(TestClient_OnLogMessage);
|
||||
|
||||
Network.RegisterCallback(PacketType.AvatarAppearance, new NetworkManager.PacketCallback(AvatarAppearanceHandler));
|
||||
|
||||
updateTimer.Start();
|
||||
}
|
||||
|
||||
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(SecondLife client, LLUUID fromAgentID, string data, LLUUID imSessionID)
|
||||
{
|
||||
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, imSessionID);
|
||||
}
|
||||
}
|
||||
|
||||
public void DoCommand(string cmd, LLUUID fromAgentID, LLUUID imSessionID)
|
||||
{
|
||||
string[] tokens = Parsing.ParseArguments(cmd);
|
||||
|
||||
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, imSessionID);
|
||||
|
||||
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 (response.Length > 0)
|
||||
{
|
||||
Console.WriteLine(response);
|
||||
|
||||
if (fromAgentID != null && Network.Connected)
|
||||
{
|
||||
// IMs don't like \r\n line endings, clean them up first
|
||||
response = response.Replace("\r", "");
|
||||
SendResponseIM(this, fromAgentID, response, imSessionID);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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.Network.AgentID)
|
||||
{
|
||||
Console.WriteLine("Got the group ID for " + sim.Client.ToString() + ", requesting group members...");
|
||||
GroupID = p.AgentData.ActiveGroupID;
|
||||
|
||||
sim.Client.Groups.BeginGetGroupMembers(GroupID);
|
||||
}
|
||||
}
|
||||
|
||||
private void TestClient_OnLogMessage(string message, Helpers.LogLevel level)
|
||||
{
|
||||
Console.WriteLine("<" + this.ToString() + "> " + level.ToString() + ": " + message);
|
||||
}
|
||||
|
||||
private void GroupMembersHandler(Dictionary<LLUUID, GroupMember> members)
|
||||
{
|
||||
Console.WriteLine("Got " + members.Count + " group members.");
|
||||
GroupMembers = members;
|
||||
}
|
||||
|
||||
private void Objects_OnObjectKilled(Simulator simulator, uint objectID)
|
||||
{
|
||||
lock (SimPrims)
|
||||
{
|
||||
if (SimPrims.ContainsKey(simulator) && SimPrims[simulator].ContainsKey(objectID))
|
||||
SimPrims[simulator].Remove(objectID);
|
||||
}
|
||||
|
||||
lock (AvatarList)
|
||||
{
|
||||
if (AvatarList.ContainsKey(objectID))
|
||||
AvatarList.Remove(objectID);
|
||||
}
|
||||
}
|
||||
|
||||
private void Objects_OnObjectUpdated(Simulator simulator, ObjectUpdate update, ulong regionHandle, ushort timeDilation)
|
||||
{
|
||||
regionX = (int)(regionHandle >> 32);
|
||||
regionY = (int)(regionHandle & 0xFFFFFFFF);
|
||||
|
||||
if (update.Avatar)
|
||||
{
|
||||
lock (AvatarList)
|
||||
{
|
||||
// TODO: We really need a solid avatar and object tracker in Utilities to use here
|
||||
if (AvatarList.ContainsKey(update.LocalID))
|
||||
{
|
||||
AvatarList[update.LocalID].CollisionPlane = update.CollisionPlane;
|
||||
AvatarList[update.LocalID].Position = update.Position;
|
||||
AvatarList[update.LocalID].Velocity = update.Velocity;
|
||||
AvatarList[update.LocalID].Acceleration = update.Acceleration;
|
||||
AvatarList[update.LocalID].Rotation = update.Rotation;
|
||||
AvatarList[update.LocalID].AngularVelocity = update.AngularVelocity;
|
||||
AvatarList[update.LocalID].Textures = update.Textures;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lock (SimPrims)
|
||||
{
|
||||
if (SimPrims.ContainsKey(simulator) && SimPrims[simulator].ContainsKey(update.LocalID))
|
||||
{
|
||||
SimPrims[simulator][update.LocalID].Position = update.Position;
|
||||
SimPrims[simulator][update.LocalID].Velocity = update.Velocity;
|
||||
SimPrims[simulator][update.LocalID].Acceleration = update.Acceleration;
|
||||
SimPrims[simulator][update.LocalID].Rotation = update.Rotation;
|
||||
SimPrims[simulator][update.LocalID].AngularVelocity = update.AngularVelocity;
|
||||
SimPrims[simulator][update.LocalID].Textures = update.Textures;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Objects_OnNewPrim(Simulator simulator, Primitive prim, ulong regionHandle, ushort timeDilation)
|
||||
{
|
||||
lock (SimPrims)
|
||||
{
|
||||
if (!SimPrims.ContainsKey(simulator))
|
||||
{
|
||||
SimPrims[simulator] = new Dictionary<uint, Primitive>(10000);
|
||||
}
|
||||
|
||||
SimPrims[simulator][prim.LocalID] = prim;
|
||||
}
|
||||
|
||||
if ((prim.Flags & LLObject.ObjectFlags.CreateSelected) != 0 && OnPrimCreated != null)
|
||||
{
|
||||
OnPrimCreated(simulator, prim);
|
||||
}
|
||||
}
|
||||
|
||||
private void Objects_OnNewAvatar(Simulator simulator, Avatar avatar, ulong regionHandle, ushort timeDilation)
|
||||
{
|
||||
lock (AvatarList)
|
||||
{
|
||||
AvatarList[avatar.LocalID] = avatar;
|
||||
}
|
||||
}
|
||||
|
||||
private void AvatarAppearanceHandler(Packet packet, Simulator simulator)
|
||||
{
|
||||
AvatarAppearancePacket appearance = (AvatarAppearancePacket)packet;
|
||||
|
||||
lock (Appearances) Appearances[appearance.Sender.ID] = appearance;
|
||||
}
|
||||
|
||||
private void Self_OnInstantMessage(LLUUID fromAgentID, string fromAgentName, LLUUID toAgentID,
|
||||
uint parentEstateID, LLUUID regionID, LLVector3 position, MainAvatar.InstantMessageDialog dialog,
|
||||
bool groupIM, LLUUID imSessionID, DateTime timestamp, string message,
|
||||
MainAvatar.InstantMessageOnline offline, byte[] binaryBucket)
|
||||
{
|
||||
if (MasterKey != LLUUID.Zero)
|
||||
{
|
||||
if (fromAgentID != MasterKey)
|
||||
{
|
||||
// Received an IM from someone that is not the bot's master, ignore
|
||||
Console.WriteLine("<IM>" + fromAgentName + " (not master): " + message + "@" + regionID.ToString() + ":" + position.ToString() );
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GroupMembers != null && !GroupMembers.ContainsKey(fromAgentID))
|
||||
{
|
||||
// Received an IM from someone outside the bot's group, ignore
|
||||
Console.WriteLine("<IM>" + fromAgentName + " (not in group): " + message + "@" + regionID.ToString() + ":" + position.ToString());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine("<IM>" + fromAgentName + ": " + message);
|
||||
|
||||
if (dialog == MainAvatar.InstantMessageDialog.RequestTeleport)
|
||||
{
|
||||
Console.WriteLine("Accepting teleport lure.");
|
||||
Self.TeleportLureRespond(fromAgentID, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dialog == MainAvatar.InstantMessageDialog.InventoryOffered)
|
||||
{
|
||||
Console.WriteLine("Accepting inventory offer.");
|
||||
|
||||
Self.InstantMessage(Self.FirstName + " " + Self.LastName, fromAgentID, String.Empty,
|
||||
imSessionID, MainAvatar.InstantMessageDialog.InventoryAccepted,
|
||||
MainAvatar.InstantMessageOnline.Offline, Self.Position, LLUUID.Zero,
|
||||
Self.InventoryRootFolderUUID.GetBytes());
|
||||
}
|
||||
else
|
||||
{
|
||||
DoCommand(message, fromAgentID, imSessionID);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue