diff --git a/libsecondlife-cs/BitPack.cs b/libsecondlife-cs/BitPack.cs index 99ee0757..08a74181 100644 --- a/libsecondlife-cs/BitPack.cs +++ b/libsecondlife-cs/BitPack.cs @@ -100,6 +100,69 @@ namespace libsecondlife return BitConverter.ToInt32(output, 0); } + /// + /// Unpack a variable number of bits from the data in to unsigned + /// integer format + /// + /// Number of bits to unpack + /// An unsigned integer containing the unpacked bits + /// This function is only useful up to 32 bits + public uint UnpackUBits(int totalCount) + { + byte[] output = UnpackBitsArray(totalCount); + + if (!BitConverter.IsLittleEndian) Array.Reverse(output); + return BitConverter.ToUInt32(output, 0); + } + + public byte UnpackByte() + { + byte[] output = UnpackBitsArray(8); + return output[0]; + } + + public float UnpackFixed(bool signed, int intBits, int fracBits) + { + int minVal; + int maxVal; + int unsignedBits = intBits + fracBits; + int totalBits = unsignedBits; + float fixedVal; + + if (signed) + { + totalBits++; + + minVal = 1 << intBits; + minVal *= -1; + } + maxVal = 1 << intBits; + + if (totalBits <= 8) + fixedVal = (float)UnpackByte(); + else if (totalBits <= 16) + fixedVal = (float)UnpackUBits(16); + else if (totalBits <= 31) + fixedVal = (float)UnpackUBits(32); + else + return 0.0f; + + fixedVal /= (float)(1 << fracBits); + + if (signed) fixedVal -= (float)maxVal; + + return fixedVal; + } + + public LLUUID UnpackUUID() + { + if (bitPos != 0) return LLUUID.Zero; + + LLUUID val = new LLUUID(Data, bytePos); + bytePos += 16; + return val; + } + private void PackBitArray(byte[] data, int totalCount) { int count = 0; diff --git a/libsecondlife-cs/MainAvatarStatus.cs b/libsecondlife-cs/MainAvatarStatus.cs index ff963073..e26d3d32 100644 --- a/libsecondlife-cs/MainAvatarStatus.cs +++ b/libsecondlife-cs/MainAvatarStatus.cs @@ -317,7 +317,6 @@ namespace libsecondlife UpdateTimer = new Timer(Client.Settings.AGENT_UPDATE_INTERVAL); UpdateTimer.Elapsed += new ElapsedEventHandler(UpdateTimer_Elapsed); UpdateTimer.Enabled = Client.Settings.SEND_AGENT_UPDATES; - if (UpdateTimer.Enabled) UpdateTimer.Start(); } /// diff --git a/libsecondlife-cs/ObjectManager.cs b/libsecondlife-cs/ObjectManager.cs index 24d29c2c..35445f45 100644 --- a/libsecondlife-cs/ObjectManager.cs +++ b/libsecondlife-cs/ObjectManager.cs @@ -1274,17 +1274,18 @@ namespace libsecondlife } #endregion - // Unknown - if (block.Data.Length != 0) - Client.DebugLog("Got an ObjectUpdate block with generic data length " + block.Data.Length); + // TODO: Figure out what this is used for and implement it + //if (block.Data.Length != 0) + // Client.DebugLog("Got an ObjectUpdate block with generic data length " + block.Data.Length); // Determine the object type and create the appropriate class - byte pcode = block.PCode; + PCode pcode = (PCode)block.PCode; switch (pcode) { - case (byte)PCode.Grass: - case (byte)PCode.Tree: - case (byte)PCode.Prim: + case PCode.Grass: + case PCode.Tree: + case PCode.NewTree: + case PCode.Prim: Primitive prim = GetPrimitive(simulator, block.ID, block.FullID); #region Update Prim Info with decoded data @@ -1347,13 +1348,13 @@ namespace libsecondlife if (prim.NameValues.ContainsKey("AttachItemID")) FireOnNewAttachment(simulator, prim, update.RegionData.RegionHandle, update.RegionData.TimeDilation); - else if (block.PCode == (byte)PCode.Tree || block.PCode == (byte)PCode.Grass || block.PCode == (byte)PCode.NewTree) + else if (pcode == PCode.Tree || pcode == PCode.Grass || pcode == PCode.NewTree) FireOnNewFoliage(simulator, prim, update.RegionData.RegionHandle, update.RegionData.TimeDilation); else FireOnNewPrim(simulator, prim, update.RegionData.RegionHandle, update.RegionData.TimeDilation); break; - case (byte)PCode.Avatar: + case PCode.Avatar: // Update some internals if this is our avatar if (block.FullID == Client.Network.AgentID) { @@ -1416,21 +1417,59 @@ namespace libsecondlife } break; - case (byte)PCode.ParticleSystem: - // FIXME: Handle ParticleSystem - Client.DebugLog("Got an ObjectUpdate block with a ParticleSystem PCode"); - + case PCode.ParticleSystem: + DecodeParticleUpdate(block); break; default: - Client.DebugLog("Got an ObjectUpdate block with an unrecognized PCode " + - ((PCode)pcode).ToString()); - + Client.DebugLog("Got an ObjectUpdate block with an unrecognized PCode " + pcode.ToString()); break; } } } } + protected void DecodeParticleUpdate(ObjectUpdatePacket.ObjectDataBlock block) + { + // TODO: Handle ParticleSystem ObjectUpdate blocks + + // float bounce_b + // LLVector4 scale_range + // LLVector4 alpha_range + // LLVector3 vel_offset + // float dist_begin_fadeout + // float dist_end_fadeout + // LLUUID image_uuid + // long flags + // byte createme + // LLVector3 diff_eq_alpha + // LLVector3 diff_eq_scale + // byte max_particles + // byte initial_particles + // float kill_plane_z + // LLVector3 kill_plane_normal + // float bounce_plane_z + // LLVector3 bounce_plane_normal + // float spawn_range + // float spawn_frequency + // float spawn_frequency_range + // LLVector3 spawn_direction + // float spawn_direction_range + // float spawn_velocity + // float spawn_velocity_range + // float speed_limit + // float wind_weight + // LLVector3 current_gravity + // float gravity_weight + // float global_lifetime + // float individual_lifetime + // float individual_lifetime_range + // float alpha_decay + // float scale_decay + // float distance_death + // float damp_motion_factor + // LLVector3 wind_diffusion_factor + } + /// /// Usually called when an Prim moves. /// diff --git a/libsecondlife-cs/ParticleSystem.cs b/libsecondlife-cs/ParticleSystem.cs index 3b6fa360..390a8a49 100644 --- a/libsecondlife-cs/ParticleSystem.cs +++ b/libsecondlife-cs/ParticleSystem.cs @@ -19,30 +19,39 @@ namespace libsecondlife public enum SourcePattern : byte { /// - [XmlEnum("None")] None = 0, /// - [XmlEnum("Drop")] Drop = 0x01, /// - [XmlEnum("Explode")] Explode = 0x02, /// - [XmlEnum("Angle")] Angle = 0x04, /// - [XmlEnum("AngleCone")] AngleCone = 0x08, /// - [XmlEnum("AngleConeEmpty")] AngleConeEmpty = 0x10 } /// - /// Information on a particle system assocaited with a prim + /// Flags for the particle system behavior /// [Flags] - public enum ParticleFlags : ushort + public enum ParticleSystemFlags : uint + { + /// + None = 0, + /// Acceleration and velocity for particles are + /// relative to the object rotation + ObjectRelative = 0x01, + /// Particles use new 'correct' angle parameters + UseNewAngle = 0x02 + } + + /// + /// Flags for the particles in this particle system + /// + [Flags] + public enum ParticleFlags : uint { /// None = 0, @@ -63,72 +72,37 @@ namespace libsecondlife /// TargetLinear = 0x080, /// - Emissive = 0x100 + Emissive = 0x100, + /// + Beam = 0x200 } - /// - [XmlAttribute("startrgba"), DefaultValue(0)] - public uint PartStartRGBA; - /// - [XmlAttribute("endrgba"), DefaultValue(0)] - public uint PartEndRGBA; - /// - [XmlAttribute("maxage"), DefaultValue(0)] + + public uint CRC; + public SourcePattern Pattern = SourcePattern.None; + public ParticleSystemFlags Flags = ParticleSystemFlags.None; + public float MaxAge; + public float StartAge; + public float InnerAngle; + public float OuterAngle; + public float BurstRate; + public float BurstRadius; + public float BurstSpeedMin; + public float BurstSpeedMax; + public float BurstPartCount; + public LLVector3 AngularVelocity; + public LLVector3 PartAcceleration; + public LLUUID Texture; + public LLUUID Target; + public LLColor PartStartColor; + public LLColor PartEndColor; + public float PartStartScaleX; + public float PartStartScaleY; + public float PartEndScaleX; + public float PartEndScaleY; public float PartMaxAge; - /// - [XmlAttribute("srcmaxage"), DefaultValue(0)] - public float SrcMaxAge; - /// - [XmlAttribute("srcanglebegin"), DefaultValue(0)] - public float SrcAngleBegin; - /// - [XmlAttribute("srcangleend"), DefaultValue(0)] - public float SrcAngleEnd; - /// - [XmlAttribute("srcburstpartcount"), DefaultValue(0)] - public int SrcBurstPartCount; - /// - [XmlAttribute("srcburstradius"), DefaultValue(0)] - public float SrcBurstRadius; - /// - [XmlAttribute("srcburstrate"), DefaultValue(0)] - public float SrcBurstRate; - /// - [XmlAttribute("srcburstspeedmin"), DefaultValue(0)] - public float SrcBurstSpeedMin; - /// - [XmlAttribute("srcburstspeedmax"), DefaultValue(0)] - public float SrcBurstSpeedMax; - /// Unknown - [XmlAttribute("serial"), DefaultValue(0)] - public uint Serial; - /// Unknown - [XmlAttribute("starttick"), DefaultValue(0)] - public uint StartTick; - /// - [XmlAttribute("srcpattern"), DefaultValue(SourcePattern.None)] - public SourcePattern SrcPattern = SourcePattern.None; - /// Various options that describe the behavior of this system - [XmlAttribute("particleflags"), DefaultValue(ParticleFlags.None)] public ParticleFlags PartFlags = ParticleFlags.None; - /// - [XmlElement("srctarget")] - public LLUUID SrcTargetKey = LLUUID.Zero; - /// Texture that will be applied to the particles - [XmlElement("srctexture")] - public LLUUID SrcTexture = LLUUID.Zero; - /// - [XmlElement("partstartscale")] - public LLVector3 PartStartScale = LLVector3.Zero; - /// - [XmlElement("partendscale")] - public LLVector3 PartEndScale = LLVector3.Zero; - /// - [XmlElement("srcaccel")] - public LLVector3 SrcAccel = LLVector3.Zero; - /// - [XmlElement("srcomega")] - public LLVector3 SrcOmega = LLVector3.Zero; + /// /// @@ -165,68 +139,49 @@ namespace libsecondlife /// private void FromBytes(byte[] data, int pos) { - int i = pos; - if (data.Length == 0) return; - Serial = (uint)(data[i++] + (data[i++] << 8) + - (data[i++] << 16) + (data[i++] << 24)); + BitPack pack = new BitPack(data, pos); - StartTick = (uint)(data[i++] + (data[i++] << 8) + - (data[i++] << 16) + (data[i++] << 24)); - - SrcPattern = (SourcePattern)data[i++]; - - SrcMaxAge = (data[i++] + (data[i++] << 8)) / 256.0f; - - // TODO: Unknown - i += 2; - - SrcAngleBegin = (data[i++] / 100.0f) * (float)Math.PI; - SrcAngleEnd = (data[i++] / 100.0f) * (float)Math.PI; - - SrcBurstRate = (data[i++] + (data[i++] << 8)) / 256.0f; - SrcBurstRadius = (data[i++] + (data[i++] << 8)) / 256.0f; - SrcBurstSpeedMin = (data[i++] + (data[i++] << 8)) / 256.0f; - SrcBurstSpeedMax = (data[i++] + (data[i++] << 8)) / 256.0f; - SrcBurstPartCount = data[i++]; - - SrcOmega = new LLVector3(); - SrcOmega.X = (data[i++] + (data[i++] << 8)) / 128.0f - 256.0f; - SrcOmega.Y = (data[i++] + (data[i++] << 8)) / 128.0f - 256.0f; - SrcOmega.Z = (data[i++] + (data[i++] << 8)) / 128.0f - 256.0f; - - SrcAccel = new LLVector3(); - SrcAccel.X = (data[i++] + (data[i++] << 8)) / 128.0f - 256.0f; - SrcAccel.Y = (data[i++] + (data[i++] << 8)) / 128.0f - 256.0f; - SrcAccel.Z = (data[i++] + (data[i++] << 8)) / 128.0f - 256.0f; - - SrcTexture = new LLUUID(data, i); - i += 16; - SrcTargetKey = new LLUUID(data, i); - i += 16; - - PartFlags = (ParticleFlags)(data[i++] + (data[i++] << 8)); - - PartMaxAge = (data[i++] + (data[i++] << 8)) / 256.0f; - - // TODO: Unknown - i += 2; - - PartStartRGBA = (uint)(data[i++] + (data[i++] << 8) + - (data[i++] << 16) + (data[i++] << 24)); - - PartEndRGBA = (uint)(data[i++] + (data[i++] << 8) + - (data[i++] << 16) + (data[i++] << 24)); - - PartStartScale = new LLVector3(); - PartStartScale.X = data[i++] / 32.0f; - PartStartScale.Y = data[i++] / 32.0f; - - PartEndScale = new LLVector3(); - PartEndScale.X = data[i++] / 32.0f; - PartEndScale.Y = data[i++] / 32.0f; + CRC = pack.UnpackUBits(32); + Flags = (ParticleSystemFlags)pack.UnpackUBits(32); + Pattern = (SourcePattern)pack.UnpackByte(); + MaxAge = pack.UnpackFixed(false, 8, 8); + StartAge = pack.UnpackFixed(false, 8, 8); + InnerAngle = pack.UnpackFixed(false, 3, 5); + OuterAngle = pack.UnpackFixed(false, 3, 5); + BurstRate = pack.UnpackFixed(false, 8, 8); + BurstRadius = pack.UnpackFixed(false, 8, 8); + BurstSpeedMin = pack.UnpackFixed(false, 8, 8); + BurstSpeedMax = pack.UnpackFixed(false, 8, 8); + BurstPartCount = (uint)pack.UnpackByte(); + float x = pack.UnpackFixed(true, 8, 7); + float y = pack.UnpackFixed(true, 8, 7); + float z = pack.UnpackFixed(true, 8, 7); + AngularVelocity = new LLVector3(x, y, z); + x = pack.UnpackFixed(true, 8, 7); + y = pack.UnpackFixed(true, 8, 7); + z = pack.UnpackFixed(true, 8, 7); + PartAcceleration = new LLVector3(x, y, z); + Texture = pack.UnpackUUID(); + Target = pack.UnpackUUID(); + PartFlags = (ParticleFlags)pack.UnpackUBits(32); + PartMaxAge = pack.UnpackFixed(false, 8, 8); + byte r = pack.UnpackByte(); + byte g = pack.UnpackByte(); + byte b = pack.UnpackByte(); + byte a = pack.UnpackByte(); + PartStartColor = new LLColor(r, g, b, a); + r = pack.UnpackByte(); + g = pack.UnpackByte(); + b = pack.UnpackByte(); + a = pack.UnpackByte(); + PartEndColor = new LLColor(r, g, b, a); + PartStartScaleX = pack.UnpackFixed(false, 3, 5); + PartStartScaleY = pack.UnpackFixed(false, 3, 5); + PartEndScaleX = pack.UnpackFixed(false, 3, 5); + PartEndScaleY = pack.UnpackFixed(false, 3, 5); } } } diff --git a/libsecondlife-cs/Types.cs b/libsecondlife-cs/Types.cs index 27466728..90feb798 100644 --- a/libsecondlife-cs/Types.cs +++ b/libsecondlife-cs/Types.cs @@ -369,10 +369,10 @@ namespace libsecondlife { uuid += Data[i].ToString("x2"); } - uuid = uuid.Insert(20,"-"); - uuid = uuid.Insert(16,"-"); - uuid = uuid.Insert(12,"-"); - uuid = uuid.Insert(8,"-"); + uuid = uuid.Insert(20, "-"); + uuid = uuid.Insert(16, "-"); + uuid = uuid.Insert(12, "-"); + uuid = uuid.Insert(8, "-"); return uuid; } @@ -487,7 +487,7 @@ namespace libsecondlife /// vector to string conversion in Second Life public override string ToString() { - return "<" + X.ToString() + ", " + Y.ToString() + ", " + Z.ToString() + ">"; + return String.Format("<{0}, {1}, {2}>", X, Y, Z); } /// @@ -765,7 +765,7 @@ namespace libsecondlife /// public override string ToString() { - return "<" + X.ToString() + ", " + Y.ToString() + ", " + Z.ToString() + ">"; + return String.Format("<{0}, {1}, {2}>", X, Y, Z); } /// @@ -849,7 +849,7 @@ namespace libsecondlife /// public override string ToString() { - return "<" + X.ToString() + ", " + Y.ToString() + ", " + Z.ToString() + ", " + S.ToString() + ">"; + return String.Format("<{0}, {1}, {2}, {3}>", X, Y, Z, S); } /// @@ -866,16 +866,16 @@ namespace libsecondlife { /// Red [XmlAttribute("r"), DefaultValue(0)] - public byte R; + public float R; /// Green [XmlAttribute("g"), DefaultValue(0)] - public byte G; + public float G; /// Blue [XmlAttribute("b"), DefaultValue(0)] - public byte B; + public float B; /// Alpha [XmlAttribute("a"), DefaultValue(0)] - public byte A; + public float A; /// /// @@ -886,10 +886,12 @@ namespace libsecondlife /// public LLColor(byte r, byte g, byte b, byte a) { - R = r; - G = g; - B = b; - A = a; + float quanta = 1.0f / 255.0f; + + R = (float)r * quanta; + G = (float)g * quanta; + B = (float)b * quanta; + A = (float)a * quanta; } /// @@ -899,10 +901,12 @@ namespace libsecondlife /// public LLColor(byte[] byteArray, int pos) { - R = byteArray[pos]; - G = byteArray[pos + 1]; - B = byteArray[pos + 2]; - A = byteArray[pos + 3]; + float quanta = 1.0f / 255.0f; + + R = (float)byteArray[pos] * quanta; + G = (float)byteArray[pos + 1] * quanta; + B = (float)byteArray[pos + 2] * quanta; + A = (float)byteArray[pos + 3] * quanta; } /// @@ -913,10 +917,10 @@ namespace libsecondlife { byte[] byteArray = new byte[4]; - byteArray[0] = R; - byteArray[1] = G; - byteArray[2] = B; - byteArray[3] = A; + byteArray[0] = Helpers.FloatToByte(R, 0.0f, 255.0f); + byteArray[1] = Helpers.FloatToByte(G, 0.0f, 255.0f); + byteArray[2] = Helpers.FloatToByte(B, 0.0f, 255.0f); + byteArray[3] = Helpers.FloatToByte(A, 0.0f, 255.0f); return byteArray; } @@ -927,7 +931,16 @@ namespace libsecondlife /// public override string ToString() { - return "<" + R.ToString() + ", " + G.ToString() + ", " + B.ToString() + ", " + A.ToString() + ">"; + return String.Format("<{0}, {1}, {2}, {3}>", R, G, B, A); + } + + /// + /// + /// + /// + public string ToStringRGB() + { + return String.Format("<{0}, {1}, {2}>", R, G, B); } /// diff --git a/libsecondlife-cs/examples/TestClient/Commands/ExportCommand.cs b/libsecondlife-cs/examples/TestClient/Commands/ExportCommand.cs index 5ea9368f..7baeea8d 100644 --- a/libsecondlife-cs/examples/TestClient/Commands/ExportCommand.cs +++ b/libsecondlife-cs/examples/TestClient/Commands/ExportCommand.cs @@ -36,14 +36,8 @@ namespace libsecondlife.TestClient int count = 0; string file = args[1]; - try - { - id = new LLUUID(args[0]); - } - catch (Exception) - { + if (!LLUUID.TryParse(args[0], out id)) return "Usage: export uuid outputfile.xml"; - } lock (Client.SimPrims) { diff --git a/libsecondlife-cs/examples/TestClient/Commands/ExportScriptCommand.cs b/libsecondlife-cs/examples/TestClient/Commands/ExportScriptCommand.cs new file mode 100644 index 00000000..0e706911 --- /dev/null +++ b/libsecondlife-cs/examples/TestClient/Commands/ExportScriptCommand.cs @@ -0,0 +1,119 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using libsecondlife; + +namespace libsecondlife.TestClient +{ + public class ExportScriptCommand : Command + { + public ExportScriptCommand(TestClient testClient) + { + Name = "exportscript"; + 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: exportscript [prim-uuid]"; + + LLUUID id; + if (!LLUUID.TryParse(args[0], out id)) + return "Usage: exportscript [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.PartFlags & Primitive.ParticleSystem.ParticleFlags.InterpColor) != 0) + lsl.Append(" | PSYS_PART_INTERP_COLOR_MASK"); + if ((prim.ParticleSys.PartFlags & Primitive.ParticleSystem.ParticleFlags.InterpScale) != 0) + lsl.Append(" | PSYS_PART_INTERP_SCALE_MASK"); + if ((prim.ParticleSys.PartFlags & Primitive.ParticleSystem.ParticleFlags.Bounce) != 0) + lsl.Append(" | PSYS_PART_BOUNCE_MASK"); + if ((prim.ParticleSys.PartFlags & Primitive.ParticleSystem.ParticleFlags.Wind) != 0) + lsl.Append(" | PSYS_PART_WIND_MASK"); + if ((prim.ParticleSys.PartFlags & Primitive.ParticleSystem.ParticleFlags.FollowSrc) != 0) + lsl.Append(" | PSYS_PART_FOLLOW_SRC_MASK"); + if ((prim.ParticleSys.PartFlags & Primitive.ParticleSystem.ParticleFlags.FollowVelocity) != 0) + lsl.Append(" | PSYS_PART_FOLLOW_VELOCITY_MASK"); + if ((prim.ParticleSys.PartFlags & Primitive.ParticleSystem.ParticleFlags.TargetPos) != 0) + lsl.Append(" | PSYS_PART_TARGET_POS_MASK"); + if ((prim.ParticleSys.PartFlags & Primitive.ParticleSystem.ParticleFlags.TargetLinear) != 0) + lsl.Append(" | PSYS_PART_TARGET_LINEAR_MASK"); + if ((prim.ParticleSys.PartFlags & Primitive.ParticleSystem.ParticleFlags.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/libsecondlife-cs/examples/TestClient/TestClient.csproj b/libsecondlife-cs/examples/TestClient/TestClient.csproj index 37ef26cd..fc1a3b4d 100644 --- a/libsecondlife-cs/examples/TestClient/TestClient.csproj +++ b/libsecondlife-cs/examples/TestClient/TestClient.csproj @@ -40,6 +40,7 @@ +