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