diff --git a/libsecondlife/FriendsManager.cs b/libsecondlife/FriendsManager.cs
index 54b724e1..1e0d18d1 100644
--- a/libsecondlife/FriendsManager.cs
+++ b/libsecondlife/FriendsManager.cs
@@ -374,7 +374,7 @@ namespace libsecondlife
{
// HACK: folder id stored as "message"
LLUUID callingCardFolder = Client.Inventory.FindFolderForType(AssetType.CallingCard);
- Client.Self.InstantMessage(Client.ToString(),
+ Client.Self.InstantMessage(Client.Self.Name,
agentID,
callingCardFolder.ToString(),
LLUUID.Random(),
diff --git a/libsecondlife/GroupManager.cs b/libsecondlife/GroupManager.cs
index 6d52bcbe..f094430a 100644
--- a/libsecondlife/GroupManager.cs
+++ b/libsecondlife/GroupManager.cs
@@ -923,7 +923,7 @@ namespace libsecondlife
///
public void SendGroupNotice(LLUUID group, GroupNotice notice)
{
- Client.Self.InstantMessage(Client.ToString(), group, notice.Subject + "|" + notice.Message,
+ Client.Self.InstantMessage(Client.Self.Name, group, notice.Subject + "|" + notice.Message,
LLUUID.Zero, InstantMessageDialog.GroupNotice, InstantMessageOnline.Online,
LLVector3.Zero, LLUUID.Zero, notice.SerializeAttachment());
}
diff --git a/libsecondlife/InventoryManager.cs b/libsecondlife/InventoryManager.cs
index d8645e0a..286e472f 100644
--- a/libsecondlife/InventoryManager.cs
+++ b/libsecondlife/InventoryManager.cs
@@ -917,7 +917,7 @@ namespace libsecondlife
/// InventoryObject object containing item details
public LLUUID RezFromInventory(Simulator simulator, LLQuaternion rotation, LLVector3 position, InventoryObject item)
{
- return RezFromInventory(simulator, rotation, position, item, Client.Self.ActiveGroup, LLUUID.Zero);
+ return RezFromInventory(simulator, rotation, position, item, Client.Self.ActiveGroup, LLUUID.Random());
}
///
@@ -931,7 +931,7 @@ namespace libsecondlife
public LLUUID RezFromInventory(Simulator simulator, LLQuaternion rotation, LLVector3 position, InventoryObject item,
LLUUID groupOwner)
{
- return RezFromInventory(simulator, rotation, position, item, groupOwner, LLUUID.Zero);
+ return RezFromInventory(simulator, rotation, position, item, groupOwner, LLUUID.Random());
}
///
@@ -1266,7 +1266,7 @@ namespace libsecondlife
imp.MessageBlock.Offline = 0;
imp.MessageBlock.ID = im.IMSessionID;
imp.MessageBlock.Timestamp = 0;
- imp.MessageBlock.FromAgentName = Helpers.StringToField(Client.ToString());
+ imp.MessageBlock.FromAgentName = Helpers.StringToField(Client.Self.Name);
imp.MessageBlock.Message = new byte[0];
imp.MessageBlock.ParentEstateID = 0;
imp.MessageBlock.RegionID = LLUUID.Zero;
diff --git a/libsecondlife/MainAvatar.cs b/libsecondlife/MainAvatar.cs
index 660d6fa9..fddc2b72 100644
--- a/libsecondlife/MainAvatar.cs
+++ b/libsecondlife/MainAvatar.cs
@@ -595,9 +595,9 @@ namespace libsecondlife
// FIXME: Most all of these should change from public variables to read-only public properties
/// Your (client) avatar UUID
- public LLUUID ID = LLUUID.Zero;
+ public LLUUID ID;
/// Your (client) avatar ID, local to the current region/sim
- public uint LocalID = 0;
+ public uint LocalID;
/// Where the avatar started at login. Can be "last", "home"
/// or a login URI
public string StartLocation = String.Empty;
@@ -606,46 +606,58 @@ namespace libsecondlife
/// Positive and negative ratings
/// This information is read-only and any changes will not be
/// reflected on the server
- public Avatar.Statistics ProfileStatistics = new Avatar.Statistics();
+ public Avatar.Statistics ProfileStatistics;
/// Avatar properties including about text, profile URL, image IDs and
/// publishing settings
/// If you change fields in this struct, the changes will not
/// be reflected on the server until you call SetAvatarInformation
- public Avatar.AvatarProperties ProfileProperties = new Avatar.AvatarProperties();
+ public Avatar.AvatarProperties ProfileProperties;
/// Avatar interests including spoken languages, skills, and "want to"
/// choices
/// If you change fields in this struct, the changes will not
/// be reflected on the server until you call SetAvatarInformation
- public Avatar.Interests ProfileInterests = new Avatar.Interests();
+ public Avatar.Interests ProfileInterests;
/// Current position of avatar
- public LLVector3 Position = LLVector3.Zero;
+ public LLVector3 Position;
/// Current rotation of avatar
public LLQuaternion Rotation = LLQuaternion.Identity;
///
- public LLVector4 CollisionPlane = LLVector4.Zero;
+ public LLVector4 CollisionPlane;
///
- public LLVector3 Velocity = LLVector3.Zero;
+ public LLVector3 Velocity;
///
- public LLVector3 Acceleration = LLVector3.Zero;
+ public LLVector3 Acceleration;
///
- public LLVector3 AngularVelocity = LLVector3.Zero;
+ public LLVector3 AngularVelocity;
/// The point the avatar is currently looking at
/// (may not stay updated)
- public LLVector3 LookAt = LLVector3.Zero;
+ public LLVector3 LookAt;
/// Position avatar client will goto when login to 'home' or during
/// teleport request to 'home' region.
- public LLVector3 HomePosition = LLVector3.Zero;
+ public LLVector3 HomePosition;
/// LookAt point saved/restored with HomePosition
- public LLVector3 HomeLookAt = LLVector3.Zero;
+ public LLVector3 HomeLookAt;
/// Used for camera and control key state tracking
public MainAvatarStatus Status;
/// The UUID of your root inventory folder
- public LLUUID InventoryRootFolderUUID = LLUUID.Zero;
+ public LLUUID InventoryRootFolderUUID;
/// Avatar First Name (i.e. Philip)
public string FirstName { get { return firstName; } }
/// Avatar Last Name (i.e. Linden)
public string LastName { get { return lastName; } }
+ /// Avatar Full Name (i.e. Philip Linden)
+ public string Name
+ {
+ get
+ {
+ // This is a fairly common request, so assume the name doesn't
+ // change mid-session and cache the result
+ if (fullName == null)
+ fullName = String.Format("{0} {1}", firstName, lastName);
+ return fullName;
+ }
+ }
/// Gets the health of the agent
public float Health { get { return health; } }
/// Gets the current balance of the agent
@@ -681,15 +693,16 @@ namespace libsecondlife
internal string firstName = String.Empty;
internal string lastName = String.Empty;
internal string teleportMessage = String.Empty;
- internal uint sittingOn = 0;
+ internal uint sittingOn;
internal DateTime lastInterpolation;
+ private string fullName;
private TeleportStatus TeleportStat = TeleportStatus.None;
private ManualResetEvent TeleportEvent = new ManualResetEvent(false);
- private uint HeightWidthGenCounter = 0;
- private float health = 0.0f;
- private int balance = 0;
- private LLUUID activeGroup = LLUUID.Zero;
+ private uint HeightWidthGenCounter;
+ private float health;
+ private int balance;
+ private LLUUID activeGroup;
#region AgentUpdate Constants
@@ -740,6 +753,8 @@ namespace libsecondlife
Status = new MainAvatarStatus(Client);
NetworkManager.PacketCallback callback;
+ Client.Network.OnDisconnected += new NetworkManager.DisconnectedCallback(Network_OnDisconnected);
+
// Teleport callbacks
callback = new NetworkManager.PacketCallback(TeleportHandler);
Client.Network.RegisterCallback(PacketType.TeleportStart, callback);
@@ -786,7 +801,7 @@ namespace libsecondlife
/// Text message being sent
public void InstantMessage(LLUUID target, string message)
{
- InstantMessage(Client.ToString(), target, message, LLUUID.Random(),
+ InstantMessage(Name, target, message, LLUUID.Random(),
InstantMessageDialog.MessageFromAgent, InstantMessageOnline.Offline, this.Position,
LLUUID.Zero, new byte[0]);
}
@@ -799,7 +814,7 @@ namespace libsecondlife
/// IM session ID (to differentiate between IM windows)
public void InstantMessage(LLUUID target, string message, LLUUID imSessionID)
{
- InstantMessage(Client.ToString(), target, message, imSessionID,
+ InstantMessage(Name, target, message, imSessionID,
InstantMessageDialog.MessageFromAgent, InstantMessageOnline.Offline, this.Position,
LLUUID.Zero, new byte[0]);
}
@@ -883,7 +898,7 @@ namespace libsecondlife
/// Text Message being sent.
public void InstantMessageGroup(LLUUID groupUUID, string message)
{
- InstantMessageGroup(Client.ToString(), groupUUID, message);
+ InstantMessageGroup(Name, groupUUID, message);
}
///
@@ -1657,7 +1672,7 @@ namespace libsecondlife
/// Accept the teleport request or deny it
public void TeleportLureRespond(LLUUID requesterID, bool accept)
{
- InstantMessage(Client.ToString(), requesterID, String.Empty, LLUUID.Random(),
+ InstantMessage(Name, requesterID, String.Empty, LLUUID.Random(),
accept ? InstantMessageDialog.AcceptTeleport : InstantMessageDialog.DenyTeleport,
InstantMessageOnline.Offline, this.Position, LLUUID.Zero, new byte[0]);
@@ -1927,7 +1942,7 @@ namespace libsecondlife
}
///
- /// Used for parsing llDialog's
+ /// Used for parsing llDialogs
///
/// Incoming ScriptDialog packet
/// Unused
@@ -2001,9 +2016,7 @@ namespace libsecondlife
health = ((HealthMessagePacket)packet).HealthData.Health;
}
-
-
- public void AgentDataUpdateHandler(Packet packet, Simulator simulator)
+ private void AgentDataUpdateHandler(Packet packet, Simulator simulator)
{
AgentDataUpdatePacket p = (AgentDataUpdatePacket)packet;
@@ -2079,7 +2092,7 @@ namespace libsecondlife
Client.DebugLog(String.Format(
"Received a TeleportFinish event from {0}, SimIP: {1}, Location: {2}, RegionHandle: {3}",
- caps.Simulator.ToString(), packet.Info.SimIP, packet.Info.LocationID, packet.Info.RegionHandle));
+ caps.Simulator, packet.Info.SimIP, packet.Info.LocationID, packet.Info.RegionHandle));
TeleportHandler(packet, Client.Network.CurrentSim);
}
@@ -2218,7 +2231,15 @@ namespace libsecondlife
if (finished) TeleportEvent.Set();
}
- }
- #endregion Packet Handlers
+ private void Network_OnDisconnected(NetworkManager.DisconnectType reason, string message)
+ {
+ // Null out the cached fullName since it can change after logging
+ // in again (with a different account name or different login
+ // server but using the same SecondLife object
+ fullName = null;
+ }
+
+ #endregion Packet Handlers
+ }
}
diff --git a/libsecondlife/ObjectTracker.cs b/libsecondlife/ObjectTracker.cs
index 6870f285..bfd8230e 100644
--- a/libsecondlife/ObjectTracker.cs
+++ b/libsecondlife/ObjectTracker.cs
@@ -31,7 +31,128 @@ namespace libsecondlife
{
public class ObjectTracker
{
- public Dictionary Avatars = new Dictionary();
- public Dictionary Prims = new Dictionary();
+ internal Dictionary Avatars = new Dictionary();
+ internal Dictionary Prims = new Dictionary();
+
+ #region Properties
+
+ public int AvatarCount
+ {
+ get { return Avatars.Count; }
+ }
+
+ public int PrimCount
+ {
+ get { return Prims.Count; }
+ }
+
+ #endregion Properties
+
+ public bool TryGetValue(uint objectLocalID, out LLObject obj)
+ {
+ Avatar avatar;
+ Primitive prim;
+
+ if (Avatars.TryGetValue(objectLocalID, out avatar))
+ {
+ obj = avatar;
+ return true;
+ }
+
+ if (Prims.TryGetValue(objectLocalID, out prim))
+ {
+ obj = prim;
+ return true;
+ }
+
+ obj = null;
+ return false;
+ }
+
+ public bool TryGetAvatar(uint avatarLocalID, out Avatar avatar)
+ {
+ return Avatars.TryGetValue(avatarLocalID, out avatar);
+ }
+
+ public bool TryGetPrimitive(uint primLocalID, out Primitive prim)
+ {
+ return Prims.TryGetValue(primLocalID, out prim);
+ }
+
+ public List FindAll(Predicate match)
+ {
+ List found = new List();
+ lock (Prims)
+ {
+ foreach (KeyValuePair kvp in Prims)
+ {
+ if (match(kvp.Value))
+ found.Add(kvp.Value);
+ }
+ }
+ return found;
+ }
+
+ public List FindAll(Predicate match)
+ {
+ List found = new List();
+ lock (Avatars)
+ {
+ foreach (KeyValuePair kvp in Avatars)
+ {
+ if (match(kvp.Value))
+ found.Add(kvp.Value);
+ }
+ }
+ return found;
+ }
+
+ public Primitive Find(Predicate match)
+ {
+ lock (Prims)
+ {
+ foreach (Primitive prim in Prims.Values)
+ {
+ if (match(prim))
+ return prim;
+ }
+ }
+ return null;
+ }
+
+ public Avatar Find(Predicate match)
+ {
+ lock (Avatars)
+ {
+ foreach (Avatar avatar in Avatars.Values)
+ {
+ if (match(avatar))
+ return avatar;
+ }
+ }
+ return null;
+ }
+
+ public void ForEach(Action action)
+ {
+ lock (Avatars)
+ {
+ foreach (Primitive prim in Prims.Values)
+ {
+ action(prim);
+ }
+ }
+ }
+
+ public void ForEach(Action action)
+ {
+ lock (Prims)
+ {
+ foreach (Avatar avatar in Avatars.Values)
+ {
+ action(avatar);
+ }
+ }
+ }
}
}
diff --git a/libsecondlife/SecondLife.cs b/libsecondlife/SecondLife.cs
index 0497fe8a..a3c8dd66 100644
--- a/libsecondlife/SecondLife.cs
+++ b/libsecondlife/SecondLife.cs
@@ -116,7 +116,7 @@ namespace libsecondlife
/// Client avatars full name
public override string ToString()
{
- return Self.FirstName + " " + Self.LastName;
+ return Self.Name;
}
///
diff --git a/libsecondlife/examples/TestClient/Commands/Inventory/BackupCommand.cs b/libsecondlife/examples/TestClient/Commands/Inventory/BackupCommand.cs
new file mode 100644
index 00000000..2544a2ed
--- /dev/null
+++ b/libsecondlife/examples/TestClient/Commands/Inventory/BackupCommand.cs
@@ -0,0 +1,362 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using System.Threading;
+using System.ComponentModel;
+using System.Xml;
+using System.Xml.Serialization;
+using libsecondlife;
+using libsecondlife.Packets;
+using libsecondlife.TestClient;
+
+namespace libsecondlife.TestClient
+{
+ public class QueuedDownloadInfo
+ {
+ public LLUUID TransferID;
+ public LLUUID AssetID;
+ public LLUUID ItemID;
+ public LLUUID TaskID;
+ public LLUUID OwnerID;
+ public AssetType Type;
+ public string FileName;
+ public DateTime WhenRequested;
+ public bool IsRequested;
+
+ public QueuedDownloadInfo(string file, LLUUID asset, LLUUID item, LLUUID task, LLUUID owner, AssetType type)
+ {
+ FileName = file;
+ AssetID = asset;
+ ItemID = item;
+ TaskID = task;
+ OwnerID = owner;
+ Type = type;
+ TransferID = LLUUID.Zero;
+ WhenRequested = DateTime.Now;
+ IsRequested = false;
+ }
+ }
+
+ public class BackupCommand : Command
+ {
+ /// Maximum number of transfer requests to send to the server
+ private const int MAX_TRANSFERS = 10;
+
+ // all items here, fed by the inventory walking thread
+ private Queue PendingDownloads = new Queue();
+
+ // items sent to the server here
+ private List CurrentDownloads = new List(MAX_TRANSFERS);
+
+ // background workers
+ private BackgroundWorker BackupWorker;
+ private BackgroundWorker QueueWorker;
+
+ // some stats
+ private int TextItemsFound;
+ private int TextItemsTransferred;
+ private int TextItemErrors;
+
+ #region Properties
+
+ ///
+ /// true if either of the background threads is running
+ ///
+ private bool BackgroundBackupRunning
+ {
+ get { return InventoryWalkerRunning || QueueRunnerRunning; }
+ }
+
+ ///
+ /// true if the thread walking inventory is running
+ ///
+ private bool InventoryWalkerRunning
+ {
+ get { return BackupWorker != null; }
+ }
+
+ ///
+ /// true if the thread feeding the queue to the server is running
+ ///
+ private bool QueueRunnerRunning
+ {
+ get { return QueueWorker != null; }
+ }
+
+ ///
+ /// returns a string summarizing activity
+ ///
+ ///
+ private string BackgroundBackupStatus
+ {
+ get
+ {
+ StringBuilder sbResult = new StringBuilder();
+ sbResult.AppendFormat("{0} is {1} running.", Name, BoolToNot(BackgroundBackupRunning));
+ if (TextItemErrors != 0 || TextItemsFound != 0 || TextItemsTransferred != 0)
+ {
+ sbResult.AppendFormat("\r\n{0} : Inventory walker ( {1} running ) has found {2} items.",
+ Name, BoolToNot(InventoryWalkerRunning), TextItemsFound);
+ sbResult.AppendFormat("\r\n{0} : Server Transfers ( {1} running ) has transferred {2} items with {3} errors.",
+ Name, BoolToNot(QueueRunnerRunning), TextItemsTransferred, TextItemErrors);
+ sbResult.AppendFormat("\r\n{0} : {1} items in Queue, {2} items requested from server.",
+ Name, PendingDownloads.Count, CurrentDownloads.Count);
+ }
+ return sbResult.ToString();
+ }
+ }
+
+ #endregion Properties
+
+ public BackupCommand(TestClient testClient)
+ {
+ Name = "backuptext";
+ Description = "Backup inventory to a folder on your hard drive. Usage: " + Name + " [to ] | [abort] | [status]";
+ testClient.Assets.OnAssetReceived += new AssetManager.AssetReceivedCallback(Assets_OnAssetReceived);
+ }
+
+ public override string Execute(string[] args, LLUUID fromAgentID)
+ {
+ StringBuilder sbResult = new StringBuilder();
+
+ if (args.Length == 1 && args[0] == "status")
+ {
+ return BackgroundBackupStatus;
+ }
+ else if (args.Length == 1 && args[0] == "abort")
+ {
+ if (!BackgroundBackupRunning)
+ return BackgroundBackupStatus;
+
+ BackupWorker.CancelAsync();
+ QueueWorker.CancelAsync();
+
+ Thread.Sleep(500);
+
+ // check status
+ return BackgroundBackupStatus;
+ }
+ else if (args.Length != 2)
+ {
+ return "Usage: " + Name + " [to ] | [abort] | [status]";
+ }
+ else if (BackgroundBackupRunning)
+ {
+ return BackgroundBackupStatus;
+ }
+
+ QueueWorker = new BackgroundWorker();
+ QueueWorker.WorkerSupportsCancellation = true;
+ QueueWorker.DoWork += new DoWorkEventHandler(bwQueueRunner_DoWork);
+ QueueWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bwQueueRunner_RunWorkerCompleted);
+
+ QueueWorker.RunWorkerAsync();
+
+ BackupWorker = new BackgroundWorker();
+ BackupWorker.WorkerSupportsCancellation = true;
+ BackupWorker.DoWork +=new DoWorkEventHandler(bwBackup_DoWork);
+ BackupWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bwBackup_RunWorkerCompleted);
+
+ BackupWorker.RunWorkerAsync(args);
+ return "Started background operations.";
+ }
+
+ void bwQueueRunner_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
+ {
+ QueueWorker = null;
+ Console.WriteLine(BackgroundBackupStatus);
+ }
+
+ void bwQueueRunner_DoWork(object sender, DoWorkEventArgs e)
+ {
+ TextItemErrors = TextItemsTransferred = 0;
+
+ while (QueueWorker.CancellationPending == false)
+ {
+ // have any timed out?
+ if (CurrentDownloads.Count > 0)
+ {
+ foreach (QueuedDownloadInfo qdi in CurrentDownloads)
+ {
+ if ((qdi.WhenRequested + TimeSpan.FromSeconds(60)) < DateTime.Now)
+ {
+ Client.DebugLog(Name + ": timeout on asset " + qdi.AssetID.ToStringHyphenated());
+ // submit request again
+ qdi.TransferID = Client.Assets.RequestInventoryAsset(
+ qdi.AssetID, qdi.ItemID, qdi.TaskID, qdi.OwnerID, qdi.Type, true);
+ qdi.WhenRequested = DateTime.Now;
+ qdi.IsRequested = true;
+ }
+ }
+ }
+
+ if (PendingDownloads.Count != 0)
+ {
+ // room in the server queue?
+ if (CurrentDownloads.Count < MAX_TRANSFERS)
+ {
+ // yes
+ QueuedDownloadInfo qdi = PendingDownloads.Dequeue();
+ qdi.WhenRequested = DateTime.Now;
+ qdi.IsRequested = true;
+ qdi.TransferID = Client.Assets.RequestInventoryAsset(
+ qdi.AssetID, qdi.ItemID, qdi.TaskID, qdi.OwnerID, qdi.Type, true);
+
+ lock (CurrentDownloads) CurrentDownloads.Add(qdi);
+ }
+ }
+
+ if (CurrentDownloads.Count == 0 && PendingDownloads.Count == 0 && BackupWorker == null)
+ {
+ Client.DebugLog(Name + ": both transfer queues empty AND inventory walking thread is done");
+ return;
+ }
+
+ Thread.Sleep(100);
+ }
+ }
+
+ void bwBackup_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
+ {
+ Console.WriteLine(Name + ": Inventory walking thread done.");
+ BackupWorker = null;
+ }
+
+ private void bwBackup_DoWork(object sender, DoWorkEventArgs e)
+ {
+ string[] args;
+
+ TextItemsFound = 0;
+
+ args = (string[]) e.Argument;
+
+ lock (CurrentDownloads) CurrentDownloads.Clear();
+
+ // this call blocks
+ Client.Inventory.RequestFolderContents(Client.Inventory.Store.RootFolder.UUID, Client.Network.AgentID,
+ true, true, false, InventorySortOrder.ByName);
+
+ DirectoryInfo di = new DirectoryInfo(args[1]);
+
+ // recurse on the root folder into the entire inventory
+ BackupFolder(Client.Inventory.Store.RootNode, di.FullName);
+ }
+
+ ///
+ /// BackupFolder - recurse through the inventory nodes sending scripts and notecards to the transfer queue
+ ///
+ /// The current leaf in the inventory tree
+ /// path so far, in the form @"c:\here" -- this needs to be "clean" for the current filesystem
+ private void BackupFolder(InventoryNode folder, string sPathSoFar)
+ {
+ StringBuilder sbRequests = new StringBuilder();
+
+ // blocking call
+ Client.Inventory.RequestFolderContents(folder.Data.UUID, Client.Network.AgentID, true, true, false,
+ InventorySortOrder.ByName);
+
+ // first scan this folder for text
+ foreach (InventoryNode iNode in folder.Nodes.Values)
+ {
+ if (BackupWorker.CancellationPending)
+ return;
+ if (iNode.Data is libsecondlife.InventoryItem)
+ {
+ InventoryItem ii = iNode.Data as InventoryItem;
+ if (ii.AssetType == AssetType.LSLText || ii.AssetType == AssetType.Notecard)
+ {
+ // check permissions on scripts
+ if (ii.AssetType == AssetType.LSLText)
+ {
+ if ((ii.Permissions.OwnerMask & PermissionMask.Modify) == PermissionMask.None)
+ {
+ // skip this one
+ continue;
+ }
+ }
+
+ string sExtension = (ii.AssetType == AssetType.LSLText) ? ".lsl" : ".txt";
+ // make the output file
+ string sPath = sPathSoFar + @"\" + MakeValid(ii.Name.Trim()) + sExtension;
+
+ // create the new qdi
+ QueuedDownloadInfo qdi = new QueuedDownloadInfo(sPath, ii.AssetUUID, iNode.Data.UUID, LLUUID.Zero,
+ Client.Network.AgentID, ii.AssetType);
+
+ // add it to the queue
+ lock (PendingDownloads)
+ {
+ TextItemsFound++;
+ PendingDownloads.Enqueue(qdi);
+ }
+ }
+ }
+ }
+
+ // now run any subfolders
+ foreach (InventoryNode i in folder.Nodes.Values)
+ {
+ if (BackupWorker.CancellationPending)
+ return;
+ else if (i.Data is libsecondlife.InventoryFolder)
+ BackupFolder(i, sPathSoFar + @"\" + MakeValid(i.Data.Name.Trim()));
+ }
+ }
+
+ private string MakeValid(string path)
+ {
+ // FIXME: We need to strip illegal characters out
+ return path.Trim().Replace('"', '\'');
+ }
+
+ private void Assets_OnAssetReceived(AssetDownload asset, Asset blah)
+ {
+ lock (CurrentDownloads)
+ {
+ // see if we have this in our transfer list
+ QueuedDownloadInfo r = CurrentDownloads.Find(delegate(QueuedDownloadInfo q)
+ {
+ return q.TransferID == asset.ID;
+ });
+
+ if (r != null && r.TransferID == asset.ID)
+ {
+ if (asset.Success)
+ {
+ // create the directory to put this in
+ Directory.CreateDirectory(Path.GetDirectoryName(r.FileName));
+
+ // write out the file
+ File.WriteAllBytes(r.FileName, asset.AssetData);
+ Client.DebugLog(Name + " Wrote: " + r.FileName);
+ TextItemsTransferred++;
+ }
+ else
+ {
+ TextItemErrors++;
+ Console.WriteLine("{0}: Download of asset {1} ({2}) failed with status {3}", Name, r.FileName,
+ r.AssetID.ToStringHyphenated(), asset.Status.ToString());
+ }
+
+ // remove the entry
+ CurrentDownloads.Remove(r);
+ }
+ else
+ {
+ Client.DebugLog(Name + ": Unexpected asset " + asset.AssetID.ToStringHyphenated());
+ }
+ }
+ }
+
+ ///
+ /// returns blank or "not" if false
+ ///
+ ///
+ ///
+ private static string BoolToNot(bool b)
+ {
+ return b ? String.Empty : "not";
+ }
+ }
+}
diff --git a/libsecondlife/examples/TestClient/Commands/Inventory/DumpOutfitCommand.cs b/libsecondlife/examples/TestClient/Commands/Inventory/DumpOutfitCommand.cs
index fe205973..fdf4ebe4 100644
--- a/libsecondlife/examples/TestClient/Commands/Inventory/DumpOutfitCommand.cs
+++ b/libsecondlife/examples/TestClient/Commands/Inventory/DumpOutfitCommand.cs
@@ -32,47 +32,50 @@ namespace libsecondlife.TestClient
{
for (int i = 0; i < Client.Network.Simulators.Count; i++)
{
- lock (Client.Network.Simulators[i].Objects.Avatars)
- {
- foreach (Avatar avatar in Client.Network.Simulators[i].Objects.Avatars.Values)
+ Avatar targetAv;
+
+ targetAv = Client.Network.Simulators[i].Objects.Find(
+ delegate(Avatar avatar)
{
- if (avatar.ID == target)
+ return avatar.ID == target;
+ }
+ );
+
+ if (targetAv != null)
+ {
+ StringBuilder output = new StringBuilder("Downloading ");
+
+ lock (OutfitAssets) OutfitAssets.Clear();
+ Client.Assets.OnImageReceived += ImageReceivedHandler;
+
+ for (int j = 0; j < targetAv.Textures.FaceTextures.Length; j++)
+ {
+ LLObject.TextureEntryFace face = targetAv.Textures.FaceTextures[j];
+
+ if (face != null)
{
- StringBuilder output = new StringBuilder("Downloading ");
+ ImageType type = ImageType.Normal;
- lock (OutfitAssets) OutfitAssets.Clear();
- Client.Assets.OnImageReceived += ImageReceivedHandler;
-
- for (int j = 0; j < avatar.Textures.FaceTextures.Length; j++)
+ switch ((AppearanceManager.TextureIndex)j)
{
- LLObject.TextureEntryFace face = avatar.Textures.FaceTextures[j];
-
- if (face != null)
- {
- ImageType type = ImageType.Normal;
-
- switch ((AppearanceManager.TextureIndex)j)
- {
- case AppearanceManager.TextureIndex.HeadBaked:
- case AppearanceManager.TextureIndex.EyesBaked:
- case AppearanceManager.TextureIndex.UpperBaked:
- case AppearanceManager.TextureIndex.LowerBaked:
- case AppearanceManager.TextureIndex.SkirtBaked:
- type = ImageType.Baked;
- break;
- }
-
- OutfitAssets.Add(face.TextureID);
- Client.Assets.RequestImage(face.TextureID, type, 100000.0f, 0);
-
- output.Append(((AppearanceManager.TextureIndex)j).ToString());
- output.Append(" ");
- }
+ case AppearanceManager.TextureIndex.HeadBaked:
+ case AppearanceManager.TextureIndex.EyesBaked:
+ case AppearanceManager.TextureIndex.UpperBaked:
+ case AppearanceManager.TextureIndex.LowerBaked:
+ case AppearanceManager.TextureIndex.SkirtBaked:
+ type = ImageType.Baked;
+ break;
}
- return output.ToString();
+ OutfitAssets.Add(face.TextureID);
+ Client.Assets.RequestImage(face.TextureID, type, 100000.0f, 0);
+
+ output.Append(((AppearanceManager.TextureIndex)j).ToString());
+ output.Append(" ");
}
}
+
+ return output.ToString();
}
}
}
diff --git a/libsecondlife/examples/TestClient/Commands/Movement/FollowCommand.cs b/libsecondlife/examples/TestClient/Commands/Movement/FollowCommand.cs
index b6ce0e93..3067a8ef 100644
--- a/libsecondlife/examples/TestClient/Commands/Movement/FollowCommand.cs
+++ b/libsecondlife/examples/TestClient/Commands/Movement/FollowCommand.cs
@@ -48,17 +48,18 @@ namespace libsecondlife.TestClient
{
for (int i = 0; i < Client.Network.Simulators.Count; i++)
{
- lock (Client.Network.Simulators[i].Objects.Avatars)
- {
- foreach (Avatar avatar in Client.Network.Simulators[i].Objects.Avatars.Values)
+ Avatar target = Client.Network.Simulators[i].Objects.Find(
+ delegate(Avatar avatar)
{
- if (avatar.Name == name)
- {
- targetLocalID = avatar.LocalID;
- Active = true;
- return true;
- }
+ return avatar.Name == name;
}
+ );
+
+ if (target != null)
+ {
+ targetLocalID = target.LocalID;
+ Active = true;
+ return true;
}
}
}
@@ -73,17 +74,18 @@ namespace libsecondlife.TestClient
{
for (int i = 0; i < Client.Network.Simulators.Count; i++)
{
- lock (Client.Network.Simulators[i].Objects.Avatars)
- {
- foreach (Avatar avatar in Client.Network.Simulators[i].Objects.Avatars.Values)
+ Avatar target = Client.Network.Simulators[i].Objects.Find(
+ delegate(Avatar avatar)
{
- if (avatar.ID == id)
- {
- targetLocalID = avatar.LocalID;
- Active = true;
- return true;
- }
+ return avatar.ID == id;
}
+ );
+
+ if (target != null)
+ {
+ targetLocalID = target.LocalID;
+ Active = true;
+ return true;
}
}
}
@@ -99,9 +101,10 @@ namespace libsecondlife.TestClient
{
for (int i = 0; i < Client.Network.Simulators.Count; i++)
{
- if (Client.Network.Simulators[i].Objects.Avatars.ContainsKey(targetLocalID))
+ Avatar targetAv;
+
+ if (Client.Network.Simulators[i].Objects.TryGetAvatar(targetLocalID, out targetAv))
{
- Avatar targetAv = Client.Network.Simulators[i].Objects.Avatars[targetLocalID];
float distance = 0.0f;
if (Client.Network.Simulators[i] == Client.Network.CurrentSim)
diff --git a/libsecondlife/examples/TestClient/Commands/Movement/SitCommand.cs b/libsecondlife/examples/TestClient/Commands/Movement/SitCommand.cs
index bb915c03..e16ee834 100644
--- a/libsecondlife/examples/TestClient/Commands/Movement/SitCommand.cs
+++ b/libsecondlife/examples/TestClient/Commands/Movement/SitCommand.cs
@@ -19,19 +19,18 @@ namespace libsecondlife.TestClient
Primitive closest = null;
double closestDistance = Double.MaxValue;
- lock (Client.Network.CurrentSim.Objects.Prims)
- {
- foreach (Primitive p in Client.Network.CurrentSim.Objects.Prims.Values)
+ Client.Network.CurrentSim.Objects.ForEach(
+ delegate(Primitive prim)
{
- float distance = Helpers.VecDist(Client.Self.Position, p.Position);
+ float distance = Helpers.VecDist(Client.Self.Position, prim.Position);
if (closest == null || distance < closestDistance)
{
- closest = p;
+ closest = prim;
closestDistance = distance;
}
}
- }
+ );
if (closest != null)
{
diff --git a/libsecondlife/examples/TestClient/Commands/Movement/SitOnCommand.cs b/libsecondlife/examples/TestClient/Commands/Movement/SitOnCommand.cs
index 75baefe2..d2279e31 100644
--- a/libsecondlife/examples/TestClient/Commands/Movement/SitOnCommand.cs
+++ b/libsecondlife/examples/TestClient/Commands/Movement/SitOnCommand.cs
@@ -23,18 +23,19 @@ namespace libsecondlife.TestClient
if (LLUUID.TryParse(args[0], out target))
{
- lock (Client.Network.CurrentSim.Objects.Prims)
- {
- foreach (Primitive prim in Client.Network.CurrentSim.Objects.Prims.Values)
+ Primitive targetPrim = Client.Network.CurrentSim.Objects.Find(
+ delegate(Primitive prim)
{
- if (prim.ID == target)
- {
- Client.Self.RequestSit(prim.ID, LLVector3.Zero);
- Client.Self.Sit();
- return "Requested to sit on prim " + prim.ID.ToStringHyphenated() +
- " (" + prim.LocalID + ")";
- }
+ return prim.ID == target;
}
+ );
+
+ if (targetPrim != null)
+ {
+ Client.Self.RequestSit(targetPrim.ID, LLVector3.Zero);
+ Client.Self.Sit();
+ return "Requested to sit on prim " + targetPrim.ID.ToStringHyphenated() +
+ " (" + targetPrim.LocalID + ")";
}
}
diff --git a/libsecondlife/examples/TestClient/Commands/Prims/ExportCommand.cs b/libsecondlife/examples/TestClient/Commands/Prims/ExportCommand.cs
index 71a40006..d9900ee9 100644
--- a/libsecondlife/examples/TestClient/Commands/Prims/ExportCommand.cs
+++ b/libsecondlife/examples/TestClient/Commands/Prims/ExportCommand.cs
@@ -35,8 +35,8 @@ namespace libsecondlife.TestClient
return "Usage: export uuid outputfile.xml";
LLUUID id;
- uint localid = 0;
- int count = 0;
+ uint localid;
+ int count;
string file;
if (args.Length == 2)
@@ -51,27 +51,25 @@ namespace libsecondlife.TestClient
id = SelectedObject;
}
- lock (Client.Network.CurrentSim.Objects.Prims)
- {
- foreach (Primitive prim in Client.Network.CurrentSim.Objects.Prims.Values)
- {
- if (prim.ID == id)
- {
- if (prim.ParentID != 0)
- localid = prim.ParentID;
- else
- localid = prim.LocalID;
+ Primitive exportPrim;
- break;
- }
+ exportPrim = Client.Network.CurrentSim.Objects.Find(
+ delegate(Primitive prim)
+ {
+ return prim.ID == id;
}
- }
-
- if (localid != 0)
+ );
+
+ if (exportPrim != null)
{
+ if (exportPrim.ParentID != 0)
+ localid = exportPrim.ParentID;
+ else
+ localid = exportPrim.LocalID;
+
// Check for export permission first
Client.Objects.RequestObjectPropertiesFamily(Client.Network.CurrentSim, id);
- GotPermissionsEvent.WaitOne(8000, false);
+ GotPermissionsEvent.WaitOne(1000 * 10, false);
if (!GotPermissions)
{
@@ -97,19 +95,13 @@ namespace libsecondlife.TestClient
try
{
- List prims = new List();
-
- lock (Client.Network.CurrentSim.Objects.Prims)
- {
- foreach (Primitive prim in Client.Network.CurrentSim.Objects.Prims.Values)
+ List prims = Client.Network.CurrentSim.Objects.FindAll(
+ delegate(Primitive prim)
{
- if (prim.LocalID == localid || prim.ParentID == localid)
- {
- prims.Add(prim);
- count++;
- }
- }
- }
+ return (prim.LocalID == localid || prim.ParentID == localid);
+ }
+ );
+ count = prims.Count;
bool complete = RequestObjectProperties(prims, 250);
@@ -141,7 +133,7 @@ namespace libsecondlife.TestClient
else
{
return "Couldn't find UUID " + id.ToString() + " in the " +
- Client.Network.CurrentSim.Objects.Prims.Count +
+ Client.Network.CurrentSim.Objects.PrimCount +
"objects currently indexed in the current simulator";
}
}
diff --git a/libsecondlife/examples/TestClient/Commands/Prims/ExportParticlesCommand.cs b/libsecondlife/examples/TestClient/Commands/Prims/ExportParticlesCommand.cs
index 5081337a..6dab8068 100644
--- a/libsecondlife/examples/TestClient/Commands/Prims/ExportParticlesCommand.cs
+++ b/libsecondlife/examples/TestClient/Commands/Prims/ExportParticlesCommand.cs
@@ -23,16 +23,25 @@ namespace libsecondlife.TestClient
if (!LLUUID.TryParse(args[0], out id))
return "Usage: exportparticles [prim-uuid]";
- lock (Client.Network.CurrentSim.Objects.Prims)
+ lock (Client.Network.Simulators)
{
- foreach (Primitive prim in Client.Network.CurrentSim.Objects.Prims.Values)
+ for (int i = 0; i < Client.Network.Simulators.Count; i++)
{
- if (prim.ID == id)
+ Primitive exportPrim = Client.Network.Simulators[i].Objects.Find(
+ delegate(Primitive prim)
+ {
+ return prim.ID == id;
+ }
+ );
+
+ if (exportPrim != null)
{
- if (prim.ParticleSys.CRC != 0)
+ if (exportPrim.ParticleSys.CRC != 0)
{
StringBuilder lsl = new StringBuilder();
+ #region Particle System to LSL
+
lsl.Append("default" + Environment.NewLine);
lsl.Append("{" + Environment.NewLine);
lsl.Append(" state_entry()" + Environment.NewLine);
@@ -41,70 +50,72 @@ namespace libsecondlife.TestClient
lsl.Append(" PSYS_PART_FLAGS, 0");
- if ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.InterpColor) != 0)
+ if ((exportPrim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.InterpColor) != 0)
lsl.Append(" | PSYS_PART_INTERP_COLOR_MASK");
- if ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.InterpScale) != 0)
+ if ((exportPrim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.InterpScale) != 0)
lsl.Append(" | PSYS_PART_INTERP_SCALE_MASK");
- if ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.Bounce) != 0)
+ if ((exportPrim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.Bounce) != 0)
lsl.Append(" | PSYS_PART_BOUNCE_MASK");
- if ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.Wind) != 0)
+ if ((exportPrim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.Wind) != 0)
lsl.Append(" | PSYS_PART_WIND_MASK");
- if ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.FollowSrc) != 0)
+ if ((exportPrim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.FollowSrc) != 0)
lsl.Append(" | PSYS_PART_FOLLOW_SRC_MASK");
- if ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.FollowVelocity) != 0)
+ if ((exportPrim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.FollowVelocity) != 0)
lsl.Append(" | PSYS_PART_FOLLOW_VELOCITY_MASK");
- if ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.TargetPos) != 0)
+ if ((exportPrim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.TargetPos) != 0)
lsl.Append(" | PSYS_PART_TARGET_POS_MASK");
- if ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.TargetLinear) != 0)
+ if ((exportPrim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.TargetLinear) != 0)
lsl.Append(" | PSYS_PART_TARGET_LINEAR_MASK");
- if ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.Emissive) != 0)
+ if ((exportPrim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.Emissive) != 0)
lsl.Append(" | PSYS_PART_EMISSIVE_MASK");
lsl.Append(","); lsl.Append(Environment.NewLine);
lsl.Append(" PSYS_SRC_PATTERN, 0");
- if ((prim.ParticleSys.Pattern & Primitive.ParticleSystem.SourcePattern.Drop) != 0)
+ if ((exportPrim.ParticleSys.Pattern & Primitive.ParticleSystem.SourcePattern.Drop) != 0)
lsl.Append(" | PSYS_SRC_PATTERN_DROP");
- if ((prim.ParticleSys.Pattern & Primitive.ParticleSystem.SourcePattern.Explode) != 0)
+ if ((exportPrim.ParticleSys.Pattern & Primitive.ParticleSystem.SourcePattern.Explode) != 0)
lsl.Append(" | PSYS_SRC_PATTERN_EXPLODE");
- if ((prim.ParticleSys.Pattern & Primitive.ParticleSystem.SourcePattern.Angle) != 0)
+ if ((exportPrim.ParticleSys.Pattern & Primitive.ParticleSystem.SourcePattern.Angle) != 0)
lsl.Append(" | PSYS_SRC_PATTERN_ANGLE");
- if ((prim.ParticleSys.Pattern & Primitive.ParticleSystem.SourcePattern.AngleCone) != 0)
+ if ((exportPrim.ParticleSys.Pattern & Primitive.ParticleSystem.SourcePattern.AngleCone) != 0)
lsl.Append(" | PSYS_SRC_PATTERN_ANGLE_CONE");
- if ((prim.ParticleSys.Pattern & Primitive.ParticleSystem.SourcePattern.AngleConeEmpty) != 0)
+ if ((exportPrim.ParticleSys.Pattern & Primitive.ParticleSystem.SourcePattern.AngleConeEmpty) != 0)
lsl.Append(" | PSYS_SRC_PATTERN_ANGLE_CONE_EMPTY");
lsl.Append("," + Environment.NewLine);
- lsl.Append(" PSYS_PART_START_ALPHA, " + String.Format("{0:0.00000}", 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(" PSYS_PART_START_ALPHA, " + String.Format("{0:0.00000}", exportPrim.ParticleSys.PartStartColor.A) + "," + Environment.NewLine);
+ lsl.Append(" PSYS_PART_END_ALPHA, " + String.Format("{0:0.00000}", exportPrim.ParticleSys.PartEndColor.A) + "," + Environment.NewLine);
+ lsl.Append(" PSYS_PART_START_COLOR, " + exportPrim.ParticleSys.PartStartColor.ToStringRGB() + "," + Environment.NewLine);
+ lsl.Append(" PSYS_PART_END_COLOR, " + exportPrim.ParticleSys.PartEndColor.ToStringRGB() + "," + Environment.NewLine);
+ lsl.Append(" PSYS_PART_START_SCALE, <" + String.Format("{0:0.00000}", exportPrim.ParticleSys.PartStartScaleX) + ", " + String.Format("{0:0.00000}", exportPrim.ParticleSys.PartStartScaleY) + ", 0>, " + Environment.NewLine);
+ lsl.Append(" PSYS_PART_END_SCALE, <" + String.Format("{0:0.00000}", exportPrim.ParticleSys.PartEndScaleX) + ", " + String.Format("{0:0.00000}", exportPrim.ParticleSys.PartEndScaleY) + ", 0>, " + Environment.NewLine);
+ lsl.Append(" PSYS_PART_MAX_AGE, " + String.Format("{0:0.00000}", exportPrim.ParticleSys.PartMaxAge) + "," + Environment.NewLine);
+ lsl.Append(" PSYS_SRC_MAX_AGE, " + String.Format("{0:0.00000}", exportPrim.ParticleSys.MaxAge) + "," + Environment.NewLine);
+ lsl.Append(" PSYS_SRC_ACCEL, " + exportPrim.ParticleSys.PartAcceleration.ToString() + "," + Environment.NewLine);
+ lsl.Append(" PSYS_SRC_BURST_PART_COUNT, " + String.Format("{0:0}", exportPrim.ParticleSys.BurstPartCount) + "," + Environment.NewLine);
+ lsl.Append(" PSYS_SRC_BURST_RADIUS, " + String.Format("{0:0.00000}", exportPrim.ParticleSys.BurstRadius) + "," + Environment.NewLine);
+ lsl.Append(" PSYS_SRC_BURST_RATE, " + String.Format("{0:0.00000}", exportPrim.ParticleSys.BurstRate) + "," + Environment.NewLine);
+ lsl.Append(" PSYS_SRC_BURST_SPEED_MIN, " + String.Format("{0:0.00000}", exportPrim.ParticleSys.BurstSpeedMin) + "," + Environment.NewLine);
+ lsl.Append(" PSYS_SRC_BURST_SPEED_MAX, " + String.Format("{0:0.00000}", exportPrim.ParticleSys.BurstSpeedMax) + "," + Environment.NewLine);
+ lsl.Append(" PSYS_SRC_INNERANGLE, " + String.Format("{0:0.00000}", exportPrim.ParticleSys.InnerAngle) + "," + Environment.NewLine);
+ lsl.Append(" PSYS_SRC_OUTERANGLE, " + String.Format("{0:0.00000}", exportPrim.ParticleSys.OuterAngle) + "," + Environment.NewLine);
+ lsl.Append(" PSYS_SRC_OMEGA, " + exportPrim.ParticleSys.AngularVelocity.ToString() + "," + Environment.NewLine);
+ lsl.Append(" PSYS_SRC_TEXTURE, (key)\"" + exportPrim.ParticleSys.Texture.ToStringHyphenated() + "\"," + Environment.NewLine);
+ lsl.Append(" PSYS_SRC_TARGET_KEY, (key)\"" + exportPrim.ParticleSys.Target.ToStringHyphenated() + "\"" + Environment.NewLine);
+
lsl.Append(" ]);" + Environment.NewLine);
lsl.Append(" }" + Environment.NewLine);
lsl.Append("}" + Environment.NewLine);
+ #endregion Particle System to LSL
+
return lsl.ToString();
}
else
{
- return "Prim " + prim.LocalID + " does not have a particle system";
+ return "Prim " + exportPrim.LocalID + " does not have a particle system";
}
}
}
diff --git a/libsecondlife/examples/TestClient/Commands/Prims/PrimCountCommand.cs b/libsecondlife/examples/TestClient/Commands/Prims/PrimCountCommand.cs
index 0ac24faf..2367a44d 100644
--- a/libsecondlife/examples/TestClient/Commands/Prims/PrimCountCommand.cs
+++ b/libsecondlife/examples/TestClient/Commands/Prims/PrimCountCommand.cs
@@ -22,13 +22,14 @@ namespace libsecondlife.TestClient
{
for (int i = 0; i < Client.Network.Simulators.Count; i++)
{
- Console.WriteLine("{0} (Avatars: {1} Primitives: {2})",
- Client.Network.Simulators[i].Name,
- Client.Network.Simulators[i].Objects.Avatars.Count,
- Client.Network.Simulators[i].Objects.Prims.Count);
+ int avcount = Client.Network.Simulators[i].Objects.AvatarCount;
+ int primcount = Client.Network.Simulators[i].Objects.PrimCount;
- count += Client.Network.Simulators[i].Objects.Avatars.Count;
- count += Client.Network.Simulators[i].Objects.Prims.Count;
+ Console.WriteLine("{0} (Avatars: {1} Primitives: {2})",
+ Client.Network.Simulators[i].Name, avcount, primcount);
+
+ count += avcount;
+ count += primcount;
}
}
diff --git a/libsecondlife/examples/TestClient/Commands/System/SetMasterCommand.cs b/libsecondlife/examples/TestClient/Commands/System/SetMasterCommand.cs
index 49039dd8..393c0094 100644
--- a/libsecondlife/examples/TestClient/Commands/System/SetMasterCommand.cs
+++ b/libsecondlife/examples/TestClient/Commands/System/SetMasterCommand.cs
@@ -48,26 +48,11 @@ namespace libsecondlife.TestClient
return "Unable to obtain UUID for \"" + masterName + "\". Master unchanged.";
}
- // If we see this avatar standing around, IM them. Otherwise don't bother
- // because they may be offline
- lock (Client.Network.Simulators)
- {
- for (int i = 0; i < Client.Network.Simulators.Count; i++)
- {
- lock (Client.Network.Simulators[i].Objects.Avatars)
- {
- foreach (Avatar avatar in Client.Network.Simulators[i].Objects.Avatars.Values)
- {
- if (avatar.ID == Client.MasterKey)
- {
- Client.Self.InstantMessage(avatar.ID,
- "You are now my master. IM me with \"help\" for a command list.");
- break;
- }
- }
- }
- }
- }
+ // Send an Online-only IM to the new master
+ Client.Self.InstantMessage(Client.Self.Name, Client.MasterKey,
+ "You are now my master. IM me with \"help\" for a command list.", LLUUID.Random(),
+ InstantMessageDialog.MessageFromAgent, InstantMessageOnline.Online, Client.Self.Position,
+ Client.Network.CurrentSim.ID, new byte[0]);
return String.Format("Master set to {0} ({1})", masterName, Client.MasterKey.ToStringHyphenated());
}
diff --git a/libsecondlife/examples/TestClient/Commands/System/SetMasterKeyCommand.cs b/libsecondlife/examples/TestClient/Commands/System/SetMasterKeyCommand.cs
index 837eaccd..574f7b98 100644
--- a/libsecondlife/examples/TestClient/Commands/System/SetMasterKeyCommand.cs
+++ b/libsecondlife/examples/TestClient/Commands/System/SetMasterKeyCommand.cs
@@ -24,17 +24,18 @@ namespace libsecondlife.TestClient
{
for (int i = 0; i < Client.Network.Simulators.Count; i++)
{
- lock (Client.Network.Simulators[i].Objects.Avatars)
- {
- foreach (Avatar avatar in Client.Network.Simulators[i].Objects.Avatars.Values)
+ Avatar master = Client.Network.Simulators[i].Objects.Find(
+ delegate(Avatar avatar)
{
- if (avatar.ID == Client.MasterKey)
- {
- Client.Self.InstantMessage(avatar.ID,
- "You are now my master. IM me with \"help\" for a command list.");
- break;
- }
+ return avatar.ID == Client.MasterKey;
}
+ );
+
+ if (master != null)
+ {
+ Client.Self.InstantMessage(master.ID,
+ "You are now my master. IM me with \"help\" for a command list.");
+ break;
}
}
}
diff --git a/libsecondlife/examples/TestClient/Commands/TouchCommand.cs b/libsecondlife/examples/TestClient/Commands/TouchCommand.cs
index c5cc59bc..cdd9e095 100644
--- a/libsecondlife/examples/TestClient/Commands/TouchCommand.cs
+++ b/libsecondlife/examples/TestClient/Commands/TouchCommand.cs
@@ -23,16 +23,17 @@ namespace libsecondlife.TestClient
if (LLUUID.TryParse(args[0], out target))
{
- lock (Client.Network.CurrentSim.Objects.Prims)
- {
- foreach (Primitive prim in Client.Network.CurrentSim.Objects.Prims.Values)
+ Primitive targetPrim = Client.Network.CurrentSim.Objects.Find(
+ delegate(Primitive prim)
{
- if (prim.ID == target)
- {
- Client.Self.Touch(prim.LocalID);
- return "Touched prim " + prim.LocalID;
- }
+ return prim.ID == target;
}
+ );
+
+ if (targetPrim != null)
+ {
+ Client.Self.Touch(targetPrim.LocalID);
+ return "Touched prim " + targetPrim.LocalID;
}
}
diff --git a/libsecondlife/examples/TestClient/Commands/WhoCommand.cs b/libsecondlife/examples/TestClient/Commands/WhoCommand.cs
index 87950ed7..e19507f5 100644
--- a/libsecondlife/examples/TestClient/Commands/WhoCommand.cs
+++ b/libsecondlife/examples/TestClient/Commands/WhoCommand.cs
@@ -22,16 +22,15 @@ namespace libsecondlife.TestClient
{
for (int i = 0; i < Client.Network.Simulators.Count; i++)
{
- lock (Client.Network.Simulators[i].Objects.Avatars)
- {
- foreach (Avatar av in Client.Network.Simulators[i].Objects.Avatars.Values)
+ Client.Network.Simulators[i].Objects.ForEach(
+ delegate(Avatar av)
{
result.AppendLine();
- result.AppendFormat("{0} (Group: {1}, Location: {2}/{3}, UUID: {4})", av.Name,
- av.GroupName, (av.CurrentSim != null ? av.CurrentSim.Name : String.Empty),
+ result.AppendFormat("{0} (Group: {1}, Location: {2}/{3}, UUID: {4})", av.Name,
+ av.GroupName, (av.CurrentSim != null ? av.CurrentSim.Name : String.Empty),
av.Position, av.ID.ToStringHyphenated());
}
- }
+ );
}
}
diff --git a/libsecondlife/examples/TestClient/Parsing.cs b/libsecondlife/examples/TestClient/Parsing.cs
index 1e081c1c..d54d8190 100644
--- a/libsecondlife/examples/TestClient/Parsing.cs
+++ b/libsecondlife/examples/TestClient/Parsing.cs
@@ -2,59 +2,86 @@ using System;
using System.Collections.Generic;
using System.Text;
-namespace libsecondlife.TestClient {
- class Parsing {
- public static string[] ParseArguments(string str) {
+namespace libsecondlife.TestClient
+{
+ class Parsing
+ {
+ public static string[] ParseArguments(string str)
+ {
List list = new List();
- string current = "";
+ string current = String.Empty;
string trimmed = null;
bool withinQuote = false;
bool escaped = false;
- foreach (char c in str) {
- if (c == '"') {
- if (escaped) {
+
+ foreach (char c in str)
+ {
+ if (c == '"')
+ {
+ if (escaped)
+ {
current += '"';
escaped = false;
- } else {
+ }
+ else
+ {
current += '"';
withinQuote = !withinQuote;
}
- } else if (c == ' ' || c == '\t') {
- if (escaped || withinQuote) {
+ }
+ else if (c == ' ' || c == '\t')
+ {
+ if (escaped || withinQuote)
+ {
current += c;
escaped = false;
- } else {
+ }
+ else
+ {
trimmed = current.Trim();
- if (trimmed.StartsWith("\"") && trimmed.EndsWith("\"")) {
+ 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 = "";
+ current = String.Empty;
}
- } else if (c == '\\') {
- if (escaped) {
+ }
+ else if (c == '\\')
+ {
+ if (escaped)
+ {
current += '\\';
escaped = false;
- } else {
+ }
+ else
+ {
escaped = true;
}
- } else {
+ }
+ else
+ {
if (escaped)
throw new FormatException(c.ToString() + " is not an escapable character.");
current += c;
}
}
+
trimmed = current.Trim();
- if (trimmed.StartsWith("\"") && trimmed.EndsWith("\"")) {
+
+ 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();
}
}
diff --git a/libsecondlife/examples/TestClient/TestClient.cs b/libsecondlife/examples/TestClient/TestClient.cs
index 9a9e48ac..123ec0fa 100644
--- a/libsecondlife/examples/TestClient/TestClient.cs
+++ b/libsecondlife/examples/TestClient/TestClient.cs
@@ -105,11 +105,14 @@ namespace libsecondlife.TestClient
public void DoCommand(string cmd, LLUUID fromAgentID, LLUUID imSessionID)
{
- string[] tokens = Parsing.ParseArguments(cmd);
+ string[] tokens;
+
+ try { tokens = Parsing.ParseArguments(cmd); }
+ catch (FormatException ex) { Console.WriteLine(ex.Message); return; }
if (tokens.Length == 0)
return;
-
+
string firstToken = tokens[0].ToLower();
// "all balance" will send the balance command to all currently logged in bots
diff --git a/libsecondlife/examples/TestClient/TestClient.csproj b/libsecondlife/examples/TestClient/TestClient.csproj
index 08438e26..c2b31d01 100644
--- a/libsecondlife/examples/TestClient/TestClient.csproj
+++ b/libsecondlife/examples/TestClient/TestClient.csproj
@@ -45,6 +45,7 @@
+