From e93869c7a785a4f375685ffa33c913033ed1c85a Mon Sep 17 00:00:00 2001 From: Adam Frisby Date: Thu, 21 Jun 2007 17:08:21 +0000 Subject: * Importing Ming's mass test client --- .../Commands/Prims/ExportCommand.cs | 209 +++++++++++++++++ .../Commands/Prims/ExportParticlesCommand.cs | 119 ++++++++++ .../Commands/Prims/ImportCommand.cs | 246 +++++++++++++++++++++ .../Commands/Prims/PrimCountCommand.cs | 32 +++ 4 files changed, 606 insertions(+) create mode 100644 tools/mass test client/Commands/Prims/ExportCommand.cs create mode 100644 tools/mass test client/Commands/Prims/ExportParticlesCommand.cs create mode 100644 tools/mass test client/Commands/Prims/ImportCommand.cs create mode 100644 tools/mass test client/Commands/Prims/PrimCountCommand.cs (limited to 'tools/mass test client/Commands/Prims') diff --git a/tools/mass test client/Commands/Prims/ExportCommand.cs b/tools/mass test client/Commands/Prims/ExportCommand.cs new file mode 100644 index 0000000..da4e45f --- /dev/null +++ b/tools/mass test client/Commands/Prims/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/tools/mass test client/Commands/Prims/ExportParticlesCommand.cs b/tools/mass test client/Commands/Prims/ExportParticlesCommand.cs new file mode 100644 index 0000000..8fced68 --- /dev/null +++ b/tools/mass test client/Commands/Prims/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/tools/mass test client/Commands/Prims/ImportCommand.cs b/tools/mass test client/Commands/Prims/ImportCommand.cs new file mode 100644 index 0000000..5f8723a --- /dev/null +++ b/tools/mass test client/Commands/Prims/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/tools/mass test client/Commands/Prims/PrimCountCommand.cs b/tools/mass test client/Commands/Prims/PrimCountCommand.cs new file mode 100644 index 0000000..5d07e8b --- /dev/null +++ b/tools/mass test client/Commands/Prims/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(); + } + } +} -- cgit v1.1