From 5b6afeafbc249ba88dcc20d1fbc98ce12418b21b Mon Sep 17 00:00:00 2001 From: gareth Date: Tue, 8 May 2007 00:10:04 +0000 Subject: Brought in TestClient code for teh fork --- ExportBot/Commands/AppearanceCommand.cs | 29 +++ ExportBot/Commands/CloneProfileCommand.cs | 131 +++++++++++ .../Commands/Communication/EchoMasterCommand.cs | 42 ++++ ExportBot/Commands/Communication/IMCommand.cs | 71 ++++++ ExportBot/Commands/Communication/SayCommand.cs | 44 ++++ ExportBot/Commands/Communication/ShoutCommand.cs | 49 ++++ ExportBot/Commands/Communication/TtsCommand.cs | 51 +++++ ExportBot/Commands/Communication/WhisperCommand.cs | 49 ++++ ExportBot/Commands/DebugCommand.cs | 37 ++++ ExportBot/Commands/DilationCommand.cs | 22 ++ ExportBot/Commands/DumpOutfitCommand.cs | 98 ++++++++ ExportBot/Commands/ExportCommand.cs | 209 +++++++++++++++++ ExportBot/Commands/ExportOutfitCommand.cs | 66 ++++++ ExportBot/Commands/ExportParticlesCommand.cs | 119 ++++++++++ ExportBot/Commands/FindSimCommand.cs | 43 ++++ ExportBot/Commands/HelpCommand.cs | 29 +++ ExportBot/Commands/ImportCommand.cs | 246 +++++++++++++++++++++ ExportBot/Commands/ImportOutfitCommand.cs | 66 ++++++ ExportBot/Commands/Inventory/BalanceCommand.cs | 21 ++ .../Commands/Inventory/DeleteFolderCommand.cs | 43 ++++ ExportBot/Commands/Inventory/GiveAllCommand.cs | 27 +++ ExportBot/Commands/Inventory/InventoryCommand.cs | 62 ++++++ ExportBot/Commands/Inventory/WearCommand.cs | 43 ++++ ExportBot/Commands/LoadCommand.cs | 28 +++ ExportBot/Commands/LoginCommand.cs | 34 +++ ExportBot/Commands/LogoutCommand.cs | 24 ++ ExportBot/Commands/MD5Command.cs | 22 ++ ExportBot/Commands/Movement/FollowCommand.cs | 90 ++++++++ ExportBot/Commands/Movement/GotoCommand.cs | 53 +++++ ExportBot/Commands/Movement/JumpCommand.cs | 34 +++ ExportBot/Commands/Movement/LocationCommand.cs | 23 ++ ExportBot/Commands/Movement/MoveToCommand.cs | 24 ++ ExportBot/Commands/Movement/SitCommand.cs | 52 +++++ ExportBot/Commands/Movement/SitOnCommand.cs | 54 +++++ ExportBot/Commands/Movement/StandCommand.cs | 47 ++++ ExportBot/Commands/PacketLogCommand.cs | 84 +++++++ ExportBot/Commands/ParcelInfoCommand.cs | 62 ++++++ ExportBot/Commands/PrimCountCommand.cs | 32 +++ ExportBot/Commands/QuitCommand.cs | 24 ++ ExportBot/Commands/RegionInfoCommand.cs | 45 ++++ ExportBot/Commands/SetMasterCommand.cs | 73 ++++++ ExportBot/Commands/SetMasterKeyCommand.cs | 35 +++ ExportBot/Commands/ShowEffectsCommand.cs | 76 +++++++ ExportBot/Commands/StatsCommand.cs | 39 ++++ ExportBot/Commands/TouchCommand.cs | 55 +++++ ExportBot/Commands/TreeCommand.cs | 51 +++++ ExportBot/Commands/UptimeCommand.cs | 25 +++ ExportBot/Commands/WhoCommand.cs | 29 +++ 48 files changed, 2712 insertions(+) create mode 100644 ExportBot/Commands/AppearanceCommand.cs create mode 100644 ExportBot/Commands/CloneProfileCommand.cs create mode 100644 ExportBot/Commands/Communication/EchoMasterCommand.cs create mode 100644 ExportBot/Commands/Communication/IMCommand.cs create mode 100644 ExportBot/Commands/Communication/SayCommand.cs create mode 100644 ExportBot/Commands/Communication/ShoutCommand.cs create mode 100644 ExportBot/Commands/Communication/TtsCommand.cs create mode 100644 ExportBot/Commands/Communication/WhisperCommand.cs create mode 100644 ExportBot/Commands/DebugCommand.cs create mode 100644 ExportBot/Commands/DilationCommand.cs create mode 100644 ExportBot/Commands/DumpOutfitCommand.cs create mode 100644 ExportBot/Commands/ExportCommand.cs create mode 100644 ExportBot/Commands/ExportOutfitCommand.cs create mode 100644 ExportBot/Commands/ExportParticlesCommand.cs create mode 100644 ExportBot/Commands/FindSimCommand.cs create mode 100644 ExportBot/Commands/HelpCommand.cs create mode 100644 ExportBot/Commands/ImportCommand.cs create mode 100644 ExportBot/Commands/ImportOutfitCommand.cs create mode 100644 ExportBot/Commands/Inventory/BalanceCommand.cs create mode 100644 ExportBot/Commands/Inventory/DeleteFolderCommand.cs create mode 100644 ExportBot/Commands/Inventory/GiveAllCommand.cs create mode 100644 ExportBot/Commands/Inventory/InventoryCommand.cs create mode 100644 ExportBot/Commands/Inventory/WearCommand.cs create mode 100644 ExportBot/Commands/LoadCommand.cs create mode 100644 ExportBot/Commands/LoginCommand.cs create mode 100644 ExportBot/Commands/LogoutCommand.cs create mode 100644 ExportBot/Commands/MD5Command.cs create mode 100644 ExportBot/Commands/Movement/FollowCommand.cs create mode 100644 ExportBot/Commands/Movement/GotoCommand.cs create mode 100644 ExportBot/Commands/Movement/JumpCommand.cs create mode 100644 ExportBot/Commands/Movement/LocationCommand.cs create mode 100644 ExportBot/Commands/Movement/MoveToCommand.cs create mode 100644 ExportBot/Commands/Movement/SitCommand.cs create mode 100644 ExportBot/Commands/Movement/SitOnCommand.cs create mode 100644 ExportBot/Commands/Movement/StandCommand.cs create mode 100644 ExportBot/Commands/PacketLogCommand.cs create mode 100644 ExportBot/Commands/ParcelInfoCommand.cs create mode 100644 ExportBot/Commands/PrimCountCommand.cs create mode 100644 ExportBot/Commands/QuitCommand.cs create mode 100644 ExportBot/Commands/RegionInfoCommand.cs create mode 100644 ExportBot/Commands/SetMasterCommand.cs create mode 100644 ExportBot/Commands/SetMasterKeyCommand.cs create mode 100644 ExportBot/Commands/ShowEffectsCommand.cs create mode 100644 ExportBot/Commands/StatsCommand.cs create mode 100644 ExportBot/Commands/TouchCommand.cs create mode 100644 ExportBot/Commands/TreeCommand.cs create mode 100644 ExportBot/Commands/UptimeCommand.cs create mode 100644 ExportBot/Commands/WhoCommand.cs (limited to 'ExportBot/Commands') diff --git a/ExportBot/Commands/AppearanceCommand.cs b/ExportBot/Commands/AppearanceCommand.cs new file mode 100644 index 0000000..6f003a7 --- /dev/null +++ b/ExportBot/Commands/AppearanceCommand.cs @@ -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."; + } + } +} diff --git a/ExportBot/Commands/CloneProfileCommand.cs b/ExportBot/Commands/CloneProfileCommand.cs new file mode 100644 index 0000000..d7fb5fc --- /dev/null +++ b/ExportBot/Commands/CloneProfileCommand.cs @@ -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 Groups = new List(); + 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); + } + } + } +} diff --git a/ExportBot/Commands/Communication/EchoMasterCommand.cs b/ExportBot/Commands/Communication/EchoMasterCommand.cs new file mode 100644 index 0000000..2e426a8 --- /dev/null +++ b/ExportBot/Commands/Communication/EchoMasterCommand.cs @@ -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); + } + } + } +} diff --git a/ExportBot/Commands/Communication/IMCommand.cs b/ExportBot/Commands/Communication/IMCommand.cs new file mode 100644 index 0000000..32d7fff --- /dev/null +++ b/ExportBot/Commands/Communication/IMCommand.cs @@ -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 Name2Key = new Dictionary(); + + 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 avatars) + { + foreach (KeyValuePair kvp in avatars) + { + if (kvp.Value.ToLower() == ToAvatarName.ToLower()) + { + Name2Key[ToAvatarName.ToLower()] = kvp.Key; + NameSearchEvent.Set(); + return; + } + } + } + } +} diff --git a/ExportBot/Commands/Communication/SayCommand.cs b/ExportBot/Commands/Communication/SayCommand.cs new file mode 100644 index 0000000..d5717a6 --- /dev/null +++ b/ExportBot/Commands/Communication/SayCommand.cs @@ -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(); + } + } +} diff --git a/ExportBot/Commands/Communication/ShoutCommand.cs b/ExportBot/Commands/Communication/ShoutCommand.cs new file mode 100644 index 0000000..cf4b6c5 --- /dev/null +++ b/ExportBot/Commands/Communication/ShoutCommand.cs @@ -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; + } + } +} diff --git a/ExportBot/Commands/Communication/TtsCommand.cs b/ExportBot/Commands/Communication/TtsCommand.cs new file mode 100644 index 0000000..e8bd122 --- /dev/null +++ b/ExportBot/Commands/Communication/TtsCommand.cs @@ -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); + } + } + } +} \ No newline at end of file diff --git a/ExportBot/Commands/Communication/WhisperCommand.cs b/ExportBot/Commands/Communication/WhisperCommand.cs new file mode 100644 index 0000000..89ba0f3 --- /dev/null +++ b/ExportBot/Commands/Communication/WhisperCommand.cs @@ -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; + } + } +} diff --git a/ExportBot/Commands/DebugCommand.cs b/ExportBot/Commands/DebugCommand.cs new file mode 100644 index 0000000..fbfde7c --- /dev/null +++ b/ExportBot/Commands/DebugCommand.cs @@ -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]"; + } + } + } +} diff --git a/ExportBot/Commands/DilationCommand.cs b/ExportBot/Commands/DilationCommand.cs new file mode 100644 index 0000000..c1d3c04 --- /dev/null +++ b/ExportBot/Commands/DilationCommand.cs @@ -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(); + } + } +} \ No newline at end of file diff --git a/ExportBot/Commands/DumpOutfitCommand.cs b/ExportBot/Commands/DumpOutfitCommand.cs new file mode 100644 index 0000000..2d3d0d8 --- /dev/null +++ b/ExportBot/Commands/DumpOutfitCommand.cs @@ -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 OutfitAssets = new List(); + + 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 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()); + } + } + } +} diff --git a/ExportBot/Commands/ExportCommand.cs b/ExportBot/Commands/ExportCommand.cs new file mode 100644 index 0000000..2baac1a --- /dev/null +++ b/ExportBot/Commands/ExportCommand.cs @@ -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 PrimsWaiting = new Dictionary(); + 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 prims = new List(); + + 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 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(); + } + } + } +} diff --git a/ExportBot/Commands/ExportOutfitCommand.cs b/ExportBot/Commands/ExportOutfitCommand.cs new file mode 100644 index 0000000..6ec2776 --- /dev/null +++ b/ExportBot/Commands/ExportOutfitCommand.cs @@ -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(); + } + } + } + } +} \ No newline at end of file diff --git a/ExportBot/Commands/ExportParticlesCommand.cs b/ExportBot/Commands/ExportParticlesCommand.cs new file mode 100644 index 0000000..4b2c322 --- /dev/null +++ b/ExportBot/Commands/ExportParticlesCommand.cs @@ -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(); + } + } +} diff --git a/ExportBot/Commands/FindSimCommand.cs b/ExportBot/Commands/FindSimCommand.cs new file mode 100644 index 0000000..c6cc9c4 --- /dev/null +++ b/ExportBot/Commands/FindSimCommand.cs @@ -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"; + } + } +} diff --git a/ExportBot/Commands/HelpCommand.cs b/ExportBot/Commands/HelpCommand.cs new file mode 100644 index 0000000..5cbdcb2 --- /dev/null +++ b/ExportBot/Commands/HelpCommand.cs @@ -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(); + } + } +} diff --git a/ExportBot/Commands/ImportCommand.cs b/ExportBot/Commands/ImportCommand.cs new file mode 100644 index 0000000..4cdcaee --- /dev/null +++ b/ExportBot/Commands/ImportCommand.cs @@ -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 Children = new List(); + + public Linkset() + { + RootPrim = new Primitive(); + } + + public Linkset(Primitive rootPrim) + { + RootPrim = rootPrim; + } + } + + public class ImportCommand : Command + { + Primitive currentPrim; + LLVector3 currentPosition; + SecondLife currentClient; + AutoResetEvent primDone; + List primsCreated; + List 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 prims; + + currentClient = Client; + + try + { + XmlReader reader = XmlReader.Create(filename); + List listprims = Helpers.PrimListFromXml(reader); + reader.Close(); + + // Create a dictionary indexed by the old local ID of the prims + prims = new Dictionary(); + 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 linksets = new Dictionary(); + 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(); + 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 primIDs = new List(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(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; + } + } + } +} diff --git a/ExportBot/Commands/ImportOutfitCommand.cs b/ExportBot/Commands/ImportOutfitCommand.cs new file mode 100644 index 0000000..5ac7b8a --- /dev/null +++ b/ExportBot/Commands/ImportOutfitCommand.cs @@ -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"; + } + } +} diff --git a/ExportBot/Commands/Inventory/BalanceCommand.cs b/ExportBot/Commands/Inventory/BalanceCommand.cs new file mode 100644 index 0000000..92e9b39 --- /dev/null +++ b/ExportBot/Commands/Inventory/BalanceCommand.cs @@ -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; + } + } +} diff --git a/ExportBot/Commands/Inventory/DeleteFolderCommand.cs b/ExportBot/Commands/Inventory/DeleteFolderCommand.cs new file mode 100644 index 0000000..ddbb86c --- /dev/null +++ b/ExportBot/Commands/Inventory/DeleteFolderCommand.cs @@ -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; + } + } +} \ No newline at end of file diff --git a/ExportBot/Commands/Inventory/GiveAllCommand.cs b/ExportBot/Commands/Inventory/GiveAllCommand.cs new file mode 100644 index 0000000..fe42fce --- /dev/null +++ b/ExportBot/Commands/Inventory/GiveAllCommand.cs @@ -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; + } + } +} diff --git a/ExportBot/Commands/Inventory/InventoryCommand.cs b/ExportBot/Commands/Inventory/InventoryCommand.cs new file mode 100644 index 0000000..7b01bb1 --- /dev/null +++ b/ExportBot/Commands/Inventory/InventoryCommand.cs @@ -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(" "); + // } + //} + } +} \ No newline at end of file diff --git a/ExportBot/Commands/Inventory/WearCommand.cs b/ExportBot/Commands/Inventory/WearCommand.cs new file mode 100644 index 0000000..d1bc32c --- /dev/null +++ b/ExportBot/Commands/Inventory/WearCommand.cs @@ -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; + } + } +} \ No newline at end of file diff --git a/ExportBot/Commands/LoadCommand.cs b/ExportBot/Commands/LoadCommand.cs new file mode 100644 index 0000000..70dada4 --- /dev/null +++ b/ExportBot/Commands/LoadCommand.cs @@ -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."; + } + } +} diff --git a/ExportBot/Commands/LoginCommand.cs b/ExportBot/Commands/LoginCommand.cs new file mode 100644 index 0000000..64675f5 --- /dev/null +++ b/ExportBot/Commands/LoginCommand.cs @@ -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; + } + } + } +} diff --git a/ExportBot/Commands/LogoutCommand.cs b/ExportBot/Commands/LogoutCommand.cs new file mode 100644 index 0000000..cdb5bde --- /dev/null +++ b/ExportBot/Commands/LogoutCommand.cs @@ -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"; + } + } +} diff --git a/ExportBot/Commands/MD5Command.cs b/ExportBot/Commands/MD5Command.cs new file mode 100644 index 0000000..0a2ee5d --- /dev/null +++ b/ExportBot/Commands/MD5Command.cs @@ -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]"; + } + } +} diff --git a/ExportBot/Commands/Movement/FollowCommand.cs b/ExportBot/Commands/Movement/FollowCommand.cs new file mode 100644 index 0000000..f5074a3 --- /dev/null +++ b/ExportBot/Commands/Movement/FollowCommand.cs @@ -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(); + } + + } +} diff --git a/ExportBot/Commands/Movement/GotoCommand.cs b/ExportBot/Commands/Movement/GotoCommand.cs new file mode 100644 index 0000000..df2b8a7 --- /dev/null +++ b/ExportBot/Commands/Movement/GotoCommand.cs @@ -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; + } + } + } +} diff --git a/ExportBot/Commands/Movement/JumpCommand.cs b/ExportBot/Commands/Movement/JumpCommand.cs new file mode 100644 index 0000000..29b11a0 --- /dev/null +++ b/ExportBot/Commands/Movement/JumpCommand.cs @@ -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; + } + } +} diff --git a/ExportBot/Commands/Movement/LocationCommand.cs b/ExportBot/Commands/Movement/LocationCommand.cs new file mode 100644 index 0000000..2fd62bb --- /dev/null +++ b/ExportBot/Commands/Movement/LocationCommand.cs @@ -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(); + } + } +} diff --git a/ExportBot/Commands/Movement/MoveToCommand.cs b/ExportBot/Commands/Movement/MoveToCommand.cs new file mode 100644 index 0000000..6d0a225 --- /dev/null +++ b/ExportBot/Commands/Movement/MoveToCommand.cs @@ -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 + ">"; + } + } +} diff --git a/ExportBot/Commands/Movement/SitCommand.cs b/ExportBot/Commands/Movement/SitCommand.cs new file mode 100644 index 0000000..b9ef6be --- /dev/null +++ b/ExportBot/Commands/Movement/SitCommand.cs @@ -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"; + } + } + } +} diff --git a/ExportBot/Commands/Movement/SitOnCommand.cs b/ExportBot/Commands/Movement/SitOnCommand.cs new file mode 100644 index 0000000..ec9d201 --- /dev/null +++ b/ExportBot/Commands/Movement/SitOnCommand.cs @@ -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"; + } + } + } +} \ No newline at end of file diff --git a/ExportBot/Commands/Movement/StandCommand.cs b/ExportBot/Commands/Movement/StandCommand.cs new file mode 100644 index 0000000..8a00552 --- /dev/null +++ b/ExportBot/Commands/Movement/StandCommand.cs @@ -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); + } + } +} diff --git a/ExportBot/Commands/PacketLogCommand.cs b/ExportBot/Commands/PacketLogCommand.cs new file mode 100644 index 0000000..827b147 --- /dev/null +++ b/ExportBot/Commands/PacketLogCommand.cs @@ -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 Packets = new List(); + 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++; + } + } + } + } +} diff --git a/ExportBot/Commands/ParcelInfoCommand.cs b/ExportBot/Commands/ParcelInfoCommand.cs new file mode 100644 index 0000000..e4108a9 --- /dev/null +++ b/ExportBot/Commands/ParcelInfoCommand.cs @@ -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 Parcels, int[,] map) + { + foreach (KeyValuePair 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(); + } + } +} diff --git a/ExportBot/Commands/PrimCountCommand.cs b/ExportBot/Commands/PrimCountCommand.cs new file mode 100644 index 0000000..8adc563 --- /dev/null +++ b/ExportBot/Commands/PrimCountCommand.cs @@ -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 prims in Client.SimPrims.Values) + { + count += prims.Count; + } + } + + return count.ToString(); + } + } +} diff --git a/ExportBot/Commands/QuitCommand.cs b/ExportBot/Commands/QuitCommand.cs new file mode 100644 index 0000000..4cd7209 --- /dev/null +++ b/ExportBot/Commands/QuitCommand.cs @@ -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"; + } + } +} diff --git a/ExportBot/Commands/RegionInfoCommand.cs b/ExportBot/Commands/RegionInfoCommand.cs new file mode 100644 index 0000000..7581137 --- /dev/null +++ b/ExportBot/Commands/RegionInfoCommand.cs @@ -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(); + } + } +} diff --git a/ExportBot/Commands/SetMasterCommand.cs b/ExportBot/Commands/SetMasterCommand.cs new file mode 100644 index 0000000..a6ecbdc --- /dev/null +++ b/ExportBot/Commands/SetMasterCommand.cs @@ -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 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; + } + } +} diff --git a/ExportBot/Commands/SetMasterKeyCommand.cs b/ExportBot/Commands/SetMasterKeyCommand.cs new file mode 100644 index 0000000..0085f79 --- /dev/null +++ b/ExportBot/Commands/SetMasterKeyCommand.cs @@ -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; + } + } +} diff --git a/ExportBot/Commands/ShowEffectsCommand.cs b/ExportBot/Commands/ShowEffectsCommand.cs new file mode 100644 index 0000000..c0b20a7 --- /dev/null +++ b/ExportBot/Commands/ShowEffectsCommand.cs @@ -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()); + } + } +} diff --git a/ExportBot/Commands/StatsCommand.cs b/ExportBot/Commands/StatsCommand.cs new file mode 100644 index 0000000..7835ec8 --- /dev/null +++ b/ExportBot/Commands/StatsCommand.cs @@ -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(); + } + } +} diff --git a/ExportBot/Commands/TouchCommand.cs b/ExportBot/Commands/TouchCommand.cs new file mode 100644 index 0000000..4103d21 --- /dev/null +++ b/ExportBot/Commands/TouchCommand.cs @@ -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."; + } + } + } +} \ No newline at end of file diff --git a/ExportBot/Commands/TreeCommand.cs b/ExportBot/Commands/TreeCommand.cs new file mode 100644 index 0000000..2029e37 --- /dev/null +++ b/ExportBot/Commands/TreeCommand.cs @@ -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; + } + } +} diff --git a/ExportBot/Commands/UptimeCommand.cs b/ExportBot/Commands/UptimeCommand.cs new file mode 100644 index 0000000..3edec73 --- /dev/null +++ b/ExportBot/Commands/UptimeCommand.cs @@ -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) + ")"; + } + } +} \ No newline at end of file diff --git a/ExportBot/Commands/WhoCommand.cs b/ExportBot/Commands/WhoCommand.cs new file mode 100644 index 0000000..83d8610 --- /dev/null +++ b/ExportBot/Commands/WhoCommand.cs @@ -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(); + } + } +} -- cgit v1.1