Brought in TestClient code for teh fork

zircon^2
gareth 2007-05-08 00:10:04 +00:00
parent 74321101e0
commit 5b6afeafbc
58 changed files with 3958 additions and 0 deletions

111
ExportBot/Arguments.cs Normal file
View File

@ -0,0 +1,111 @@
using System;
using System.Collections.Specialized;
using System.Text.RegularExpressions;
namespace CommandLine.Utility
{
/// <summary>
/// Arguments class
/// </summary>
public class Arguments
{
// Variables
private StringDictionary Parameters;
// Constructor
public Arguments(string[] Args)
{
Parameters = new StringDictionary();
Regex Splitter = new Regex(@"^-{1,2}|=|:",
RegexOptions.IgnoreCase | RegexOptions.Compiled);
Regex Remover = new Regex(@"^['""]?(.*?)['""]?$",
RegexOptions.IgnoreCase | RegexOptions.Compiled);
string Parameter = null;
string[] Parts;
// Valid parameters forms:
// {-,/,--}param{ ,=,:}((",')value(",'))
// Examples:
// -param1 value1 --param2 /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]);
}
}
}
}

307
ExportBot/ClientManager.cs Normal file
View File

@ -0,0 +1,307 @@
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 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;
if (!String.IsNullOrEmpty(account.StartLocation))
{
if (!client.Network.Login(account.FirstName, account.LastName, account.Password, "TestClient",
account.StartLocation, contactPerson))
{
Console.WriteLine("Failed to login " + account.FirstName + " " + account.LastName + ": " +
client.Network.LoginMessage);
}
}
else
{
if (!client.Network.Login(account.FirstName, account.LastName, account.Password, "TestClient",
contactPerson))
{
Console.WriteLine("Failed to login " + account.FirstName + " " + account.LastName + ": " +
client.Network.LoginStatusMessage);
}
}
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);
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()
{
Console.WriteLine("Type quit to exit. Type help for a command list.");
while (Running)
{
PrintPrompt();
string input = Console.ReadLine();
DoCommandAll(input, null, null);
}
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.
}
}
}

29
ExportBot/Command.cs Normal file
View File

@ -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()
{
}
}
}

View File

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

View File

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

View File

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

View File

@ -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;
}
}
}
}
}

View File

@ -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();
}
}
}

View File

@ -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;
}
}
}

View File

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

View File

@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.Text;
using 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;
}
}
}

View File

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

View File

@ -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();
}
}
}

View File

@ -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());
}
}
}
}

View File

@ -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();
}
}
}
}

View File

@ -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();
}
}
}
}
}

View File

@ -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();
}
}
}

View File

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

View File

@ -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();
}
}
}

View File

@ -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;
}
}
}
}

View File

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

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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(" ");
// }
//}
}
}

View File

@ -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.";
}
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)
//{
// Client.Appearance.WearOutfit(folder);
// return "Outfit " + target + " worn.";
//}
//return "Unable to find: " + target;
}
}
}

View File

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

View File

@ -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.LoginStatusMessage;
}
}
}
}

View File

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

View File

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

View File

@ -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();
}
}
}

View File

@ -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;
}
}
}
}

View File

@ -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;
}
}
}

View File

@ -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();
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

@ -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++;
}
}
}
}
}

View File

@ -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();
}
}
}

View File

@ -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();
}
}
}

View File

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

View File

@ -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();
}
}
}

View File

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

View File

@ -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;
}
}
}

View File

@ -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());
}
}
}

View File

@ -0,0 +1,39 @@
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);
return output.ToString();
}
}
}

View File

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

View File

@ -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;
}
}
}

View File

@ -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) + ")";
}
}
}

View File

@ -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();
}
}
}

61
ExportBot/Parsing.cs Normal file
View File

@ -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();
}
}
}

127
ExportBot/Program.cs Normal file
View File

@ -0,0 +1,127 @@
using System;
using System.Collections.Generic;
using System.IO;
using CommandLine.Utility;
namespace libsecondlife.TestClient
{
public class Program
{
private static void Usage()
{
Console.WriteLine("Usage: " + Environment.NewLine +
"TestClient.exe --first firstname --last lastname --pass password --contact \"youremail\" [--startpos \"sim/x/y/z\"] [--master \"master name\"] [--masterkey \"master uuid\"]" +
Environment.NewLine + "TestClient.exe --file filename --contact \"youremail\" [--master \"master name\"] [--masterkey \"master uuid\"]");
}
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;
if (arguments["masterkey"] != null)
{
masterKey = LLUUID.Parse(arguments["masterkey"]);
}
if (arguments["master"] != null)
{
masterName = arguments["master"];
}
if (arguments["contact"] != null)
{
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());
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
{
Usage();
return;
}
foreach (LoginDetails a in accounts)
{
a.MasterName = masterName;
a.MasterKey = masterKey;
}
// Login the accounts and run the input loop
if ( arguments["start"] != null ) {
manager = new ClientManager(accounts, contact, arguments["start"]);
} else {
manager = new ClientManager(accounts, contact);
}
manager.Run();
}
}
}

View File

@ -0,0 +1,33 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("TestClient")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("TestClient")]
[assembly: AssemblyCopyright("Copyright © 2006")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("0563f706-7fa9-42f6-bf23-c6acd1175964")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

5
ExportBot/README Normal file
View File

@ -0,0 +1,5 @@
This is a fork of TestClient from the main libsl project, it is not built as a normal part of the opensim release and is designed to allow migration of avatars from the main LL grid to an OGS system.
It's essentially a "good CopyBot" - before an avatar is copied consent is taken and the avatar data is exported out to the remote grid via a web service. The bot is designed to be evoked remotely via an LSL script in-world.
THE AUTHOR ACCEPTS NO RESPONSIBILITY WHATSOEVER FOR ANY POTENTIALLY INFRINGING USES OF THIS CODE.

125
ExportBot/TestClient.build Normal file
View File

@ -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>

328
ExportBot/TestClient.cs Normal file
View File

@ -0,0 +1,328 @@
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 LLQuaternion bodyRotation = LLQuaternion.Identity;
private LLVector3 forward = new LLVector3(0, 0.9999f, 0);
private LLVector3 left = new LLVector3(0.9999f, 0, 0);
private LLVector3 up = new LLVector3(0, 0, 0.9999f);
private System.Timers.Timer updateTimer;
/// <summary>
///
/// </summary>
public TestClient(ClientManager manager)
{
ClientManager = manager;
updateTimer = new System.Timers.Timer(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 = 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);
}
}
}
}
}

120
ExportBot/TestClient.csproj Normal file
View File

@ -0,0 +1,120 @@
<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.TestClient</RootNamespace>
<AssemblyName>TestClient</AssemblyName>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\..\..\bin\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>..\..\bin\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Speech, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Arguments.cs" />
<Compile Include="Command.cs" />
<Compile Include="Commands\AppearanceCommand.cs" />
<Compile Include="Commands\CloneProfileCommand.cs" />
<Compile Include="Commands\DebugCommand.cs" />
<Compile Include="Commands\DumpOutfitCommand.cs" />
<Compile Include="Commands\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\ExportOutfitCommand.cs" />
<Compile Include="Commands\FindSimCommand.cs" />
<Compile Include="Commands\ImportOutfitCommand.cs" />
<Compile Include="Commands\LoginCommand.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Commands\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\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\PacketLogCommand.cs" />
<Compile Include="Commands\ParcelInfoCommand.cs" />
<Compile Include="Commands\QuitCommand.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Commands\RegionInfoCommand.cs" />
<Compile Include="Commands\SetMasterCommand.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Commands\ExportCommand.cs" />
<Compile Include="Commands\ImportCommand.cs" />
<Compile Include="Commands\LoadCommand.cs" />
<Compile Include="Commands\PrimCountCommand.cs" />
<Compile Include="Commands\SetMasterKeyCommand.cs" />
<Compile Include="Commands\ShowEffectsCommand.cs" />
<Compile Include="Commands\StatsCommand.cs" />
<Compile Include="Commands\TouchCommand.cs" />
<Compile Include="Commands\TreeCommand.cs" />
<Compile Include="Commands\UptimeCommand.cs" />
<Compile Include="Commands\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>
<ItemGroup>
<ProjectReference Include="..\..\..\openjpegnet\openjpegnet.csproj">
<Project>{D0DCFDCB-71FA-4343-A8D1-24D4665A94A4}</Project>
<Name>openjpegnet</Name>
</ProjectReference>
<ProjectReference Include="..\..\libsecondlife.csproj">
<Project>{D9CDEDFB-8169-4B03-B57F-0DF638F044EC}</Project>
<Name>libsecondlife</Name>
</ProjectReference>
<ProjectReference Include="..\..\libsecondlife.Utilities\libsecondlife.Utilities.csproj">
<Project>{CE5E06C2-2428-416B-ADC1-F1FE16A0FB27}</Project>
<Name>libsecondlife.Utilities</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>