private Packet mProxy_ImprovedTerseObjectUpdatePacketReceived(Packet p, IPEndPoint ep) { if (mLocalID != 0 && mProxy != null) { mProxy.RemoveDelegate(PacketType.ObjectUpdate, Direction.Incoming, mObjectUpdateListener); } ImprovedTerseObjectUpdatePacket packet = p as ImprovedTerseObjectUpdatePacket; /*foreach (var block in packet.ObjectData) { * uint localid = Utils.BytesToUInt(block.Data, 0); * * if (block.Data[0x5] != 0 && localid == mLocalID) { * mAvatarPosition = new Vector3(block.Data, 0x16); * mPositionOffset = mAvatarPosition - mFrame.Core.Position; * Quaternion rotation = Quaternion.Identity; * * // Rotation (theta) * rotation = new Quaternion( * Utils.UInt16ToFloat(block.Data, 0x2E, -1.0f, 1.0f), * Utils.UInt16ToFloat(block.Data, 0x2E + 2, -1.0f, 1.0f), * Utils.UInt16ToFloat(block.Data, 0x2E + 4, -1.0f, 1.0f), * Utils.UInt16ToFloat(block.Data, 0x2E + 6, -1.0f, 1.0f)); * * mAvatarOrientation = new Rotation(rotation); * //mAvatarOrientation = Frame.Core.Orientation; * } * }*/ objectUpdatePacketQueue.Add(packet); return(p); }
/// <summary> /// Return a packet to the packet pool /// </summary> /// <param name="packet"></param> public void ReturnPacket(Packet packet) { if (dataBlockPoolEnabled) { switch (packet.Type) { case PacketType.ObjectUpdate: ObjectUpdatePacket oup = (ObjectUpdatePacket)packet; foreach (ObjectUpdatePacket.ObjectDataBlock oupod in oup.ObjectData) { ReturnDataBlock <ObjectUpdatePacket.ObjectDataBlock>(oupod); } oup.ObjectData = null; break; case PacketType.ImprovedTerseObjectUpdate: ImprovedTerseObjectUpdatePacket itoup = (ImprovedTerseObjectUpdatePacket)packet; foreach (ImprovedTerseObjectUpdatePacket.ObjectDataBlock itoupod in itoup.ObjectData) { ReturnDataBlock <ImprovedTerseObjectUpdatePacket.ObjectDataBlock>(itoupod); } itoup.ObjectData = null; break; } } if (packetPoolEnabled) { switch (packet.Type) { // List pooling packets here case PacketType.PacketAck: case PacketType.ObjectUpdate: case PacketType.ImprovedTerseObjectUpdate: lock (pool) { PacketType type = packet.Type; if (!pool.ContainsKey(type)) { pool[type] = new Stack <Packet>(); } if ((pool[type]).Count < 50) { (pool[type]).Push(packet); } } break; // Other packets wont pool default: return; } } }
private Packet InImprovedTerseObjectUpdateHandler(Packet packet, IPEndPoint sim) { string simIP = sim.ToString(); // If the sim doesn't exist, add it if (!SharedInfo.Aux_Simulators.ContainsKey(simIP)) { SharedInfo.Aux_Simulators.Add(simIP, new PubComb.Aux_Simulator(simIP)); } ImprovedTerseObjectUpdatePacket update = (ImprovedTerseObjectUpdatePacket)packet; foreach (ImprovedTerseObjectUpdatePacket.ObjectDataBlock block in update.ObjectData) { // Is it an avatar? if (block.Data[5] != 0) { uint localid = Utils.BytesToUInt(block.Data, 0); PubComb.Aux_Avatar avatar = SharedInfo.Aux_Simulators[simIP].AvatarByLocalID(localid); if (avatar != null) { // update position avatar.Position = new Vector3(block.Data, 22); SharedInfo.Aux_Simulators[simIP].Avatars[avatar.UUID].Position = avatar.Position; if (avatar.UUID == frame.AgentID) { SharedInfo.AvPosition = avatar.Position; } form.UpdateAvatar(avatar); } } } return(packet); }
/// <summary> /// Return a packet to the packet pool /// </summary> /// <param name="packet"></param> public void ReturnPacket(Packet packet) { if (!RecyclePackets) { return; } bool trypool = false; PacketType type = packet.Type; switch (type) { case PacketType.ObjectUpdate: ObjectUpdatePacket oup = (ObjectUpdatePacket)packet; oup.ObjectData = null; trypool = true; break; case PacketType.ImprovedTerseObjectUpdate: ImprovedTerseObjectUpdatePacket itoup = (ImprovedTerseObjectUpdatePacket)packet; itoup.ObjectData = null; trypool = true; break; case PacketType.PacketAck: PacketAckPacket ackup = (PacketAckPacket)packet; ackup.Packets = null; trypool = true; break; case PacketType.AgentUpdate: trypool = true; break; default: return; } if (!trypool) { return; } lock (pool) { if (!pool.ContainsKey(type)) { pool[type] = new Stack <Packet>(); } if ((pool[type]).Count < 50) { // m_log.DebugFormat("[PACKETPOOL]: Pushing {0} packet", type); pool[type].Push(packet); } } }
public override void update() { LLVector3 pos2 = new LLVector3(0, 0, 0); if (this._physActor != null && this.physicsEnabled) { PhysicsVector pPos = this._physActor.Position; pos2 = new LLVector3(pPos.X, pPos.Y, pPos.Z); } if (this.newPrimFlag) { foreach (SimClient client in m_clientThreads.Values) { client.OutPacket(OurPacket); } this.newPrimFlag = false; } else if (this.updateFlag) { ImprovedTerseObjectUpdatePacket terse = new ImprovedTerseObjectUpdatePacket(); terse.RegionData.RegionHandle = m_regionHandle; // FIXME terse.RegionData.TimeDilation = 64096; terse.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1]; terse.ObjectData[0] = this.CreateImprovedBlock(); foreach (SimClient client in m_clientThreads.Values) { client.OutPacket(terse); } this.updateFlag = false; } else if (this.dirtyFlag) { foreach (SimClient client in m_clientThreads.Values) { UpdateClient(client); } this.dirtyFlag = false; } else { if (this._physActor != null && this.physicsEnabled) { if (pos2 != this.positionLastFrame) { ImprovedTerseObjectUpdatePacket terse = new ImprovedTerseObjectUpdatePacket(); terse.RegionData.RegionHandle = m_regionHandle; // FIXME terse.RegionData.TimeDilation = 64096; terse.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1]; terse.ObjectData[0] = this.CreateImprovedBlock(); foreach (SimClient client in m_clientThreads.Values) { client.OutPacket(terse); } } this.positionLastFrame = pos2; } } if (this.physicstest) { LLVector3 pos = this.Pos; pos.Z += 0.0001f; this.UpdatePosition(pos); this.physicstest = false; } }
/// <summary> /// Return a packet to the packet pool /// </summary> /// <param name="packet"></param> public void ReturnPacket(Packet packet) { if (RecycleDataBlocks) { switch (packet.Type) { case PacketType.ObjectUpdate: ObjectUpdatePacket oup = (ObjectUpdatePacket)packet; foreach (ObjectUpdatePacket.ObjectDataBlock oupod in oup.ObjectData) { ReturnDataBlock <ObjectUpdatePacket.ObjectDataBlock>(oupod); } oup.ObjectData = null; break; case PacketType.ImprovedTerseObjectUpdate: ImprovedTerseObjectUpdatePacket itoup = (ImprovedTerseObjectUpdatePacket)packet; foreach (ImprovedTerseObjectUpdatePacket.ObjectDataBlock itoupod in itoup.ObjectData) { ReturnDataBlock <ImprovedTerseObjectUpdatePacket.ObjectDataBlock>(itoupod); } itoup.ObjectData = null; break; } } if (RecyclePackets) { switch (packet.Type) { // List pooling packets here case PacketType.AgentUpdate: case PacketType.PacketAck: case PacketType.ObjectUpdate: case PacketType.ImprovedTerseObjectUpdate: lock (pool) { PacketType type = packet.Type; if (!pool.ContainsKey(type)) { pool[type] = new Stack <Packet>(); } if ((pool[type]).Count < 50) { // m_log.DebugFormat("[PACKETPOOL]: Pushing {0} packet", type); pool[type].Push(packet); } } break; // Other packets wont pool default: return; } } }
private void TerseUpdateHandler(Packet packet, Simulator simulator) { float x, y, z, w; uint localid; LLVector4 CollisionPlane = null; LLVector3 Position; LLVector3 Velocity; LLVector3 Acceleration; LLQuaternion Rotation; LLVector3 RotationVelocity; ImprovedTerseObjectUpdatePacket update = (ImprovedTerseObjectUpdatePacket)packet; foreach (ImprovedTerseObjectUpdatePacket.ObjectDataBlock block in update.ObjectData) { int i = 0; bool avatar; localid = (uint)(block.Data[i++] + (block.Data[i++] << 8) + (block.Data[i++] << 16) + (block.Data[i++] << 24)); byte state = block.Data[i++]; avatar = Convert.ToBoolean(block.Data[i++]); if (avatar) { if (OnAvatarMoved == null) { return; } CollisionPlane = new LLVector4(block.Data, i); i += 16; } else { if (OnPrimMoved == null) { return; } } // Position Position = new LLVector3(block.Data, i); i += 12; // Velocity x = Dequantize(block.Data, i, -128.0F, 128.0F); i += 2; y = Dequantize(block.Data, i, -128.0F, 128.0F); i += 2; z = Dequantize(block.Data, i, -128.0F, 128.0F); i += 2; Velocity = new LLVector3(x, y, z); // Acceleration x = Dequantize(block.Data, i, -64.0F, 64.0F); i += 2; y = Dequantize(block.Data, i, -64.0F, 64.0F); i += 2; z = Dequantize(block.Data, i, -64.0F, 64.0F); i += 2; Acceleration = new LLVector3(x, y, z); // Rotation x = Dequantize(block.Data, i, -1.0F, 1.0F); i += 2; y = Dequantize(block.Data, i, -1.0F, 1.0F); i += 2; z = Dequantize(block.Data, i, -1.0F, 1.0F); i += 2; w = Dequantize(block.Data, i, -1.0F, 1.0F); i += 2; Rotation = new LLQuaternion(x, y, z, w); // Rotation velocity x = Dequantize(block.Data, i, -64.0F, 64.0F); i += 2; y = Dequantize(block.Data, i, -64.0F, 64.0F); i += 2; z = Dequantize(block.Data, i, -64.0F, 64.0F); i += 2; RotationVelocity = new LLVector3(x, y, z); if (avatar) { if (localid == Client.Self.LocalID) { Client.Self.Position = Position; Client.Self.Rotation = Rotation; } AvatarUpdate avupdate = new AvatarUpdate(); avupdate.LocalID = localid; avupdate.State = state; avupdate.Position = Position; avupdate.CollisionPlane = CollisionPlane; avupdate.Velocity = Velocity; avupdate.Acceleration = Acceleration; avupdate.Rotation = Rotation; avupdate.RotationVelocity = RotationVelocity; if (OnAvatarMoved != null) { OnAvatarMoved(simulator, avupdate, update.RegionData.RegionHandle, update.RegionData.TimeDilation); } } else { // TODO: Is there an easy way to distinguish prims from trees in this packet, // or would the client have to do it's own lookup to determine whether it's a // prim or a tree? If the latter, we should rename this update to something // less prim specific PrimUpdate primupdate = new PrimUpdate(); primupdate.LocalID = localid; primupdate.State = state; primupdate.Position = Position; primupdate.Velocity = Velocity; primupdate.Acceleration = Acceleration; primupdate.Rotation = Rotation; primupdate.RotationVelocity = RotationVelocity; if (OnPrimMoved != null) { OnPrimMoved(simulator, primupdate, update.RegionData.RegionHandle, update.RegionData.TimeDilation); } } } }
public void AddTerseUpdateToViewersList(ImprovedTerseObjectUpdatePacket.ObjectDataBlock terseBlock) { }
public override void update() { if (this._physActor == null) { //HACKHACK: Note to work out why this entity does not have a physics actor // and prehaps create one. return; } libsecondlife.LLVector3 pos2 = new LLVector3(this._physActor.Position.X, this._physActor.Position.Y, this._physActor.Position.Z); if (this.updateflag) { //need to send movement info //so create the improvedterseobjectupdate packet //use CreateTerseBlock() ImprovedTerseObjectUpdatePacket.ObjectDataBlock terseBlock = CreateTerseBlock(); ImprovedTerseObjectUpdatePacket terse = new ImprovedTerseObjectUpdatePacket(); terse.RegionData.RegionHandle = m_regionHandle; // FIXME terse.RegionData.TimeDilation = 64096; terse.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1]; terse.ObjectData[0] = terseBlock; foreach (SimClient client in m_clientThreads.Values) { client.OutPacket(terse); } updateflag = false; //this._updateCount = 0; } else { if ((pos2 != this.positionLastFrame) || (this.movementflag == 16)) { _updateCount++; if (((!PhysicsEngineFlying) && (_updateCount > 3)) || (PhysicsEngineFlying) && (_updateCount > 0)) { //It has been a while since last update was sent so lets send one. ImprovedTerseObjectUpdatePacket.ObjectDataBlock terseBlock = CreateTerseBlock(); ImprovedTerseObjectUpdatePacket terse = new ImprovedTerseObjectUpdatePacket(); terse.RegionData.RegionHandle = m_regionHandle; // FIXME terse.RegionData.TimeDilation = 64096; terse.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1]; terse.ObjectData[0] = terseBlock; foreach (SimClient client in m_clientThreads.Values) { client.OutPacket(terse); } _updateCount = 0; } if (this.movementflag == 16) { movementflag = 0; } } } this.positionLastFrame = pos2; if (!this.ControllingClient.m_sandboxMode) { if (pos2.X < 0) { ControllingClient.CrossSimBorder(new LLVector3(this._physActor.Position.X, this._physActor.Position.Y, this._physActor.Position.Z)); } if (pos2.Y < 0) { ControllingClient.CrossSimBorder(new LLVector3(this._physActor.Position.X, this._physActor.Position.Y, this._physActor.Position.Z)); } if (pos2.X > 255) { ControllingClient.CrossSimBorder(new LLVector3(this._physActor.Position.X, this._physActor.Position.Y, this._physActor.Position.Z)); } if (pos2.Y > 255) { ControllingClient.CrossSimBorder(new LLVector3(this._physActor.Position.X, this._physActor.Position.Y, this._physActor.Position.Z)); } } }
private void SendEntityPackets(QueuedInterestListEvent[] eventDatas, IScenePresence presence) { if (!(presence is LLAgent) || presence.InterestList == null) return; LLAgent agent = (LLAgent)presence; Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>(); Lazy<List<ObjectUpdateCompressedPacket.ObjectDataBlock>> compressedUpdateBlocks = new Lazy<List<ObjectUpdateCompressedPacket.ObjectDataBlock>>(); Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseUpdateBlocks = new Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>(); for (int i = 0; i < eventDatas.Length; i++) { EntityAddOrUpdateArgs e = (EntityAddOrUpdateArgs)eventDatas[i].Event.State; ISceneEntity entity = e.Entity; #region UpdateFlags to packet type conversion UpdateFlags updateFlags = e.UpdateFlags; LLUpdateFlags llUpdateFlags = (LLUpdateFlags)e.ExtraFlags; bool canUseImproved = true; if (updateFlags.HasFlag(UpdateFlags.FullUpdate) || updateFlags.HasFlag(UpdateFlags.Parent) || updateFlags.HasFlag(UpdateFlags.Scale) || updateFlags.HasFlag(UpdateFlags.Shape) || llUpdateFlags.HasFlag(LLUpdateFlags.PrimFlags) || llUpdateFlags.HasFlag(LLUpdateFlags.Text) || llUpdateFlags.HasFlag(LLUpdateFlags.NameValue) || llUpdateFlags.HasFlag(LLUpdateFlags.ExtraData) || llUpdateFlags.HasFlag(LLUpdateFlags.TextureAnim) || llUpdateFlags.HasFlag(LLUpdateFlags.Sound) || llUpdateFlags.HasFlag(LLUpdateFlags.Particles) || llUpdateFlags.HasFlag(LLUpdateFlags.Material) || llUpdateFlags.HasFlag(LLUpdateFlags.ClickAction) || llUpdateFlags.HasFlag(LLUpdateFlags.MediaURL) || llUpdateFlags.HasFlag(LLUpdateFlags.Joint)) { canUseImproved = false; } #endregion UpdateFlags to packet type conversion #region Block Construction if (!canUseImproved) { if (entity is IScenePresence) objectUpdateBlocks.Value.Add(CreateAvatarObjectUpdateBlock((IScenePresence)entity, presence)); else objectUpdateBlocks.Value.Add(CreateObjectUpdateBlock(entity, presence)); } else { terseUpdateBlocks.Value.Add(CreateTerseUpdateBlock(entity, llUpdateFlags.HasFlag(LLUpdateFlags.Textures))); } #endregion Block Construction // Unset CreateSelected after it has been sent once if (entity is LLPrimitive) { LLPrimitive prim = (LLPrimitive)entity; prim.Prim.Flags &= ~PrimFlags.CreateSelected; } } #region Packet Sending ushort timeDilation = (m_physics != null) ? Utils.FloatToUInt16(m_physics.TimeDilation, 0.0f, 1.0f) : UInt16.MaxValue; if (objectUpdateBlocks.IsValueCreated) { List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value; ObjectUpdatePacket packet = new ObjectUpdatePacket(); packet.RegionData.RegionHandle = Util.PositionToRegionHandle(m_scene.MinPosition); packet.RegionData.TimeDilation = timeDilation; packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[blocks.Count]; for (int i = 0; i < blocks.Count; i++) packet.ObjectData[i] = blocks[i]; m_udp.SendPacket(agent, packet, ThrottleCategory.Task, true); } if (compressedUpdateBlocks.IsValueCreated) { List<ObjectUpdateCompressedPacket.ObjectDataBlock> blocks = compressedUpdateBlocks.Value; ObjectUpdateCompressedPacket packet = new ObjectUpdateCompressedPacket(); packet.RegionData.RegionHandle = Util.PositionToRegionHandle(m_scene.MinPosition); packet.RegionData.TimeDilation = timeDilation; packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[blocks.Count]; for (int i = 0; i < blocks.Count; i++) packet.ObjectData[i] = blocks[i]; m_udp.SendPacket(agent, packet, ThrottleCategory.Task, true); } if (terseUpdateBlocks.IsValueCreated) { List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value; ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket(); packet.RegionData.RegionHandle = Util.PositionToRegionHandle(m_scene.MinPosition); packet.RegionData.TimeDilation = timeDilation; packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; for (int i = 0; i < blocks.Count; i++) packet.ObjectData[i] = blocks[i]; m_udp.SendPacket(agent, packet, ThrottleCategory.Task, true); } #endregion Packet Sending }
/// <summary> /// A terse object update, used when a transformation matrix or /// velocity/acceleration for an object changes but nothing else /// (scale/position/rotation/acceleration/velocity). (From OpenMetaverse, with edits) /// </summary> /// <param name="packet"></param> /// <param name="simulator"></param> private Packet TerseUpdateHandler(Packet packet, IPEndPoint simulator) { ImprovedTerseObjectUpdatePacket terse = (ImprovedTerseObjectUpdatePacket)packet; //UpdateDilation(simulator, terse.RegionData.TimeDilation); for (int i = 0; i < terse.ObjectData.Length; i++) { ImprovedTerseObjectUpdatePacket.ObjectDataBlock block = terse.ObjectData[i]; try { int pos = 4; uint localid = Utils.BytesToUInt(block.Data, 0); // Check if we are interested in this update //if (!Client.Settings.ALWAYS_DECODE_OBJECTS && localid != Client.Self.localID && OnObjectUpdated == null) //continue; #region Decode update data ObjectUpdate update = new ObjectUpdate(); // LocalID update.LocalID = localid; // State update.State = block.Data[pos++]; // Avatar boolean update.Avatar = (block.Data[pos++] != 0); // Collision normal for avatar if (update.Avatar) { update.CollisionPlane = new Vector4(block.Data, pos); pos += 16; } // Position update.Position = new Vector3(block.Data, pos); pos += 12; // Velocity update.Velocity = new Vector3( Utils.UInt16ToFloat(block.Data, pos, -128.0f, 128.0f), Utils.UInt16ToFloat(block.Data, pos + 2, -128.0f, 128.0f), Utils.UInt16ToFloat(block.Data, pos + 4, -128.0f, 128.0f)); pos += 6; // Acceleration update.Acceleration = new Vector3( Utils.UInt16ToFloat(block.Data, pos, -64.0f, 64.0f), Utils.UInt16ToFloat(block.Data, pos + 2, -64.0f, 64.0f), Utils.UInt16ToFloat(block.Data, pos + 4, -64.0f, 64.0f)); pos += 6; // Rotation (theta) update.Rotation = new Quaternion( Utils.UInt16ToFloat(block.Data, pos, -1.0f, 1.0f), Utils.UInt16ToFloat(block.Data, pos + 2, -1.0f, 1.0f), Utils.UInt16ToFloat(block.Data, pos + 4, -1.0f, 1.0f), Utils.UInt16ToFloat(block.Data, pos + 6, -1.0f, 1.0f)); pos += 8; // Angular velocity update.AngularVelocity = new Vector3( Utils.UInt16ToFloat(block.Data, pos, -64.0f, 64.0f), Utils.UInt16ToFloat(block.Data, pos + 2, -64.0f, 64.0f), Utils.UInt16ToFloat(block.Data, pos + 4, -64.0f, 64.0f)); pos += 6; // Textures // FIXME: Why are we ignoring the first four bytes here? if (block.TextureEntry.Length != 0) { update.Textures = new Primitive.TextureEntry(block.TextureEntry, 4, block.TextureEntry.Length - 4); } #endregion Decode update data //Primitive obj = (update.Avatar) ? //(Primitive)GetAvatar(simulator, update.LocalID, UUID.Zero) : //(Primitive)GetPrimitive(simulator, update.LocalID, UUID.Zero); #region Update Client.Self /* * if (update.LocalID == Client.Self.localID) * { * Client.Self.collisionPlane = update.CollisionPlane; * Client.Self.relativePosition = update.Position; * Client.Self.velocity = update.Velocity; * Client.Self.acceleration = update.Acceleration; * Client.Self.relativeRotation = update.Rotation; * Client.Self.angularVelocity = update.AngularVelocity; * } * */ #endregion Update Client.Self if (update.LocalID == mid) { mpos = update.Position; } else { ObjectWithVel(update.Position, update.Velocity); } } catch { //Logger.Log(e.Message, Helpers.LogLevel.Warning, Client, e); } } return(packet); }
void SendObjectPacket(SimulationObject obj, bool canUseCompressed, bool canUseImproved, PrimFlags creatorFlags, UpdateFlags updateFlags) { if (!canUseImproved && !canUseCompressed) { #region ObjectUpdate Logger.DebugLog("Sending ObjectUpdate"); if (sceneAgents.ContainsKey(obj.Prim.OwnerID)) { // Send an update out to the creator ObjectUpdatePacket updateToOwner = new ObjectUpdatePacket(); updateToOwner.RegionData.RegionHandle = regionHandle; updateToOwner.RegionData.TimeDilation = (ushort)(timeDilation * (float)UInt16.MaxValue); updateToOwner.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1]; updateToOwner.ObjectData[0] = SimulationObject.BuildUpdateBlock(obj.Prim, obj.Prim.Flags | creatorFlags | PrimFlags.ObjectYouOwner, obj.CRC); udp.SendPacket(obj.Prim.OwnerID, updateToOwner, PacketCategory.State); } // Send an update out to everyone else ObjectUpdatePacket updateToOthers = new ObjectUpdatePacket(); updateToOthers.RegionData.RegionHandle = regionHandle; updateToOthers.RegionData.TimeDilation = UInt16.MaxValue; updateToOthers.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1]; updateToOthers.ObjectData[0] = SimulationObject.BuildUpdateBlock(obj.Prim, obj.Prim.Flags, obj.CRC); ForEachAgent( delegate(Agent recipient) { if (recipient.ID != obj.Prim.OwnerID) udp.SendPacket(recipient.ID, updateToOthers, PacketCategory.State); } ); #endregion ObjectUpdate } else if (!canUseImproved) { #region ObjectUpdateCompressed #region Size calculation and field serialization CompressedFlags flags = 0; int size = 84; byte[] textBytes = null; byte[] mediaURLBytes = null; byte[] particleBytes = null; byte[] extraParamBytes = null; byte[] nameValueBytes = null; byte[] textureBytes = null; byte[] textureAnimBytes = null; if ((updateFlags & UpdateFlags.AngularVelocity) != 0) { flags |= CompressedFlags.HasAngularVelocity; size += 12; } if ((updateFlags & UpdateFlags.ParentID) != 0) { flags |= CompressedFlags.HasParent; size += 4; } if ((updateFlags & UpdateFlags.ScratchPad) != 0) { switch (obj.Prim.PrimData.PCode) { case PCode.Grass: case PCode.Tree: case PCode.NewTree: flags |= CompressedFlags.Tree; size += 2; // Size byte plus one byte break; default: flags |= CompressedFlags.ScratchPad; size += 1 + obj.Prim.ScratchPad.Length; // Size byte plus bytes break; } } if ((updateFlags & UpdateFlags.Text) != 0) { flags |= CompressedFlags.HasText; textBytes = Utils.StringToBytes(obj.Prim.Text); size += textBytes.Length; // Null-terminated, no size byte size += 4; // Text color } if ((updateFlags & UpdateFlags.MediaURL) != 0) { flags |= CompressedFlags.MediaURL; mediaURLBytes = Utils.StringToBytes(obj.Prim.MediaURL); size += mediaURLBytes.Length; // Null-terminated, no size byte } if ((updateFlags & UpdateFlags.Particles) != 0) { flags |= CompressedFlags.HasParticles; particleBytes = obj.Prim.ParticleSys.GetBytes(); size += particleBytes.Length; // Should be exactly 86 bytes } // Extra Params extraParamBytes = obj.Prim.GetExtraParamsBytes(); size += extraParamBytes.Length; if ((updateFlags & UpdateFlags.Sound) != 0) { flags |= CompressedFlags.HasSound; size += 25; // SoundID, SoundGain, SoundFlags, SoundRadius } if ((updateFlags & UpdateFlags.NameValue) != 0) { flags |= CompressedFlags.HasNameValues; nameValueBytes = Utils.StringToBytes(NameValue.NameValuesToString(obj.Prim.NameValues)); size += nameValueBytes.Length; // Null-terminated, no size byte } size += 23; // PrimData size += 4; // Texture Length textureBytes = obj.Prim.Textures.GetBytes(); size += textureBytes.Length; // Texture Entry if ((updateFlags & UpdateFlags.TextureAnim) != 0) { flags |= CompressedFlags.TextureAnimation; size += 4; // TextureAnim Length textureAnimBytes = obj.Prim.TextureAnim.GetBytes(); size += textureAnimBytes.Length; // TextureAnim } #endregion Size calculation and field serialization #region Packet serialization int pos = 0; byte[] data = new byte[size]; // UUID obj.Prim.ID.ToBytes(data, 0); pos += 16; // LocalID Utils.UIntToBytes(obj.Prim.LocalID, data, pos); pos += 4; // PCode data[pos++] = (byte)obj.Prim.PrimData.PCode; // State data[pos++] = obj.Prim.PrimData.State; // CRC Utils.UIntToBytes(obj.CRC, data, pos); pos += 4; // Material data[pos++] = (byte)obj.Prim.PrimData.Material; // ClickAction data[pos++] = (byte)obj.Prim.ClickAction; // Scale obj.Prim.Scale.ToBytes(data, pos); pos += 12; // Position obj.Prim.Position.ToBytes(data, pos); pos += 12; // Rotation obj.Prim.Rotation.ToBytes(data, pos); pos += 12; // Compressed Flags Utils.UIntToBytes((uint)flags, data, pos); pos += 4; // OwnerID obj.Prim.OwnerID.ToBytes(data, pos); pos += 16; if ((flags & CompressedFlags.HasAngularVelocity) != 0) { obj.Prim.AngularVelocity.ToBytes(data, pos); pos += 12; } if ((flags & CompressedFlags.HasParent) != 0) { Utils.UIntToBytes(obj.Prim.ParentID, data, pos); pos += 4; } if ((flags & CompressedFlags.ScratchPad) != 0) { data[pos++] = (byte)obj.Prim.ScratchPad.Length; Buffer.BlockCopy(obj.Prim.ScratchPad, 0, data, pos, obj.Prim.ScratchPad.Length); pos += obj.Prim.ScratchPad.Length; } else if ((flags & CompressedFlags.Tree) != 0) { data[pos++] = 1; data[pos++] = (byte)obj.Prim.TreeSpecies; } if ((flags & CompressedFlags.HasText) != 0) { Buffer.BlockCopy(textBytes, 0, data, pos, textBytes.Length); pos += textBytes.Length; obj.Prim.TextColor.ToBytes(data, pos, false); pos += 4; } if ((flags & CompressedFlags.MediaURL) != 0) { Buffer.BlockCopy(mediaURLBytes, 0, data, pos, mediaURLBytes.Length); pos += mediaURLBytes.Length; } if ((flags & CompressedFlags.HasParticles) != 0) { Buffer.BlockCopy(particleBytes, 0, data, pos, particleBytes.Length); pos += particleBytes.Length; } // Extra Params Buffer.BlockCopy(extraParamBytes, 0, data, pos, extraParamBytes.Length); pos += extraParamBytes.Length; if ((flags & CompressedFlags.HasSound) != 0) { obj.Prim.Sound.ToBytes(data, pos); pos += 16; Utils.FloatToBytes(obj.Prim.SoundGain, data, pos); pos += 4; data[pos++] = (byte)obj.Prim.SoundFlags; Utils.FloatToBytes(obj.Prim.SoundRadius, data, pos); pos += 4; } if ((flags & CompressedFlags.HasNameValues) != 0) { Buffer.BlockCopy(nameValueBytes, 0, data, pos, nameValueBytes.Length); pos += nameValueBytes.Length; } // Path PrimData data[pos++] = (byte)obj.Prim.PrimData.PathCurve; Utils.UInt16ToBytes(Primitive.PackBeginCut(obj.Prim.PrimData.PathBegin), data, pos); pos += 2; Utils.UInt16ToBytes(Primitive.PackEndCut(obj.Prim.PrimData.PathEnd), data, pos); pos += 2; data[pos++] = Primitive.PackPathScale(obj.Prim.PrimData.PathScaleX); data[pos++] = Primitive.PackPathScale(obj.Prim.PrimData.PathScaleY); data[pos++] = (byte)Primitive.PackPathShear(obj.Prim.PrimData.PathShearX); data[pos++] = (byte)Primitive.PackPathShear(obj.Prim.PrimData.PathShearY); data[pos++] = (byte)Primitive.PackPathTwist(obj.Prim.PrimData.PathTwist); data[pos++] = (byte)Primitive.PackPathTwist(obj.Prim.PrimData.PathTwistBegin); data[pos++] = (byte)Primitive.PackPathTwist(obj.Prim.PrimData.PathRadiusOffset); data[pos++] = (byte)Primitive.PackPathTaper(obj.Prim.PrimData.PathTaperX); data[pos++] = (byte)Primitive.PackPathTaper(obj.Prim.PrimData.PathTaperY); data[pos++] = Primitive.PackPathRevolutions(obj.Prim.PrimData.PathRevolutions); data[pos++] = (byte)Primitive.PackPathTwist(obj.Prim.PrimData.PathSkew); // Profile PrimData data[pos++] = obj.Prim.PrimData.profileCurve; Utils.UInt16ToBytes(Primitive.PackBeginCut(obj.Prim.PrimData.ProfileBegin), data, pos); pos += 2; Utils.UInt16ToBytes(Primitive.PackEndCut(obj.Prim.PrimData.ProfileEnd), data, pos); pos += 2; Utils.UInt16ToBytes(Primitive.PackProfileHollow(obj.Prim.PrimData.ProfileHollow), data, pos); pos += 2; // Texture Length Utils.UIntToBytes((uint)textureBytes.Length, data, pos); pos += 4; // Texture Entry Buffer.BlockCopy(textureBytes, 0, data, pos, textureBytes.Length); pos += textureBytes.Length; if ((flags & CompressedFlags.TextureAnimation) != 0) { Utils.UIntToBytes((uint)textureAnimBytes.Length, data, pos); pos += 4; Buffer.BlockCopy(textureAnimBytes, 0, data, pos, textureAnimBytes.Length); pos += textureAnimBytes.Length; } #endregion Packet serialization #region Packet sending //Logger.DebugLog("Sending ObjectUpdateCompressed with " + flags.ToString()); if (sceneAgents.ContainsKey(obj.Prim.OwnerID)) { // Send an update out to the creator ObjectUpdateCompressedPacket updateToOwner = new ObjectUpdateCompressedPacket(); updateToOwner.RegionData.RegionHandle = regionHandle; updateToOwner.RegionData.TimeDilation = (ushort)(timeDilation * (float)UInt16.MaxValue); updateToOwner.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[1]; updateToOwner.ObjectData[0] = new ObjectUpdateCompressedPacket.ObjectDataBlock(); updateToOwner.ObjectData[0].UpdateFlags = (uint)(obj.Prim.Flags | creatorFlags | PrimFlags.ObjectYouOwner); updateToOwner.ObjectData[0].Data = data; udp.SendPacket(obj.Prim.OwnerID, updateToOwner, PacketCategory.State); } // Send an update out to everyone else ObjectUpdateCompressedPacket updateToOthers = new ObjectUpdateCompressedPacket(); updateToOthers.RegionData.RegionHandle = regionHandle; updateToOthers.RegionData.TimeDilation = UInt16.MaxValue; updateToOthers.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[1]; updateToOthers.ObjectData[0] = new ObjectUpdateCompressedPacket.ObjectDataBlock(); updateToOthers.ObjectData[0].UpdateFlags = (uint)obj.Prim.Flags; updateToOthers.ObjectData[0].Data = data; ForEachAgent( delegate(Agent recipient) { if (recipient.ID != obj.Prim.OwnerID) udp.SendPacket(recipient.ID, updateToOthers, PacketCategory.State); } ); #endregion Packet sending #endregion ObjectUpdateCompressed } else { #region ImprovedTerseObjectUpdate //Logger.DebugLog("Sending ImprovedTerseObjectUpdate"); int pos = 0; byte[] data = new byte[(obj.Prim is Avatar ? 60 : 44)]; // LocalID Utils.UIntToBytes(obj.Prim.LocalID, data, pos); pos += 4; // Avatar/CollisionPlane data[pos++] = obj.Prim.PrimData.State; if (obj.Prim is Avatar) { data[pos++] = 1; obj.Prim.CollisionPlane.ToBytes(data, pos); pos += 16; } else { ++pos; } // Position obj.Prim.Position.ToBytes(data, pos); pos += 12; // Velocity Utils.UInt16ToBytes(Utils.FloatToUInt16(obj.Prim.Velocity.X, -128.0f, 128.0f), data, pos); pos += 2; Utils.UInt16ToBytes(Utils.FloatToUInt16(obj.Prim.Velocity.Y, -128.0f, 128.0f), data, pos); pos += 2; Utils.UInt16ToBytes(Utils.FloatToUInt16(obj.Prim.Velocity.Z, -128.0f, 128.0f), data, pos); pos += 2; // Acceleration Utils.UInt16ToBytes(Utils.FloatToUInt16(obj.Prim.Acceleration.X, -64.0f, 64.0f), data, pos); pos += 2; Utils.UInt16ToBytes(Utils.FloatToUInt16(obj.Prim.Acceleration.Y, -64.0f, 64.0f), data, pos); pos += 2; Utils.UInt16ToBytes(Utils.FloatToUInt16(obj.Prim.Acceleration.Z, -64.0f, 64.0f), data, pos); pos += 2; // Rotation Utils.UInt16ToBytes(Utils.FloatToUInt16(obj.Prim.Rotation.X, -1.0f, 1.0f), data, pos); pos += 2; Utils.UInt16ToBytes(Utils.FloatToUInt16(obj.Prim.Rotation.Y, -1.0f, 1.0f), data, pos); pos += 2; Utils.UInt16ToBytes(Utils.FloatToUInt16(obj.Prim.Rotation.Z, -1.0f, 1.0f), data, pos); pos += 2; Utils.UInt16ToBytes(Utils.FloatToUInt16(obj.Prim.Rotation.W, -1.0f, 1.0f), data, pos); pos += 2; // Angular Velocity Utils.UInt16ToBytes(Utils.FloatToUInt16(obj.Prim.AngularVelocity.X, -64.0f, 64.0f), data, pos); pos += 2; Utils.UInt16ToBytes(Utils.FloatToUInt16(obj.Prim.AngularVelocity.Y, -64.0f, 64.0f), data, pos); pos += 2; Utils.UInt16ToBytes(Utils.FloatToUInt16(obj.Prim.AngularVelocity.Z, -64.0f, 64.0f), data, pos); pos += 2; ImprovedTerseObjectUpdatePacket update = new ImprovedTerseObjectUpdatePacket(); update.RegionData.RegionHandle = RegionHandle; update.RegionData.TimeDilation = (ushort)(timeDilation * (float)UInt16.MaxValue); update.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1]; update.ObjectData[0] = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock(); update.ObjectData[0].Data = data; if ((updateFlags & UpdateFlags.Textures) != 0) { byte[] textureBytes = obj.Prim.Textures.GetBytes(); byte[] textureEntry = new byte[textureBytes.Length + 4]; // Texture Length Utils.IntToBytes(textureBytes.Length, textureEntry, 0); // Texture Buffer.BlockCopy(textureBytes, 0, textureEntry, 4, textureBytes.Length); update.ObjectData[0].TextureEntry = textureEntry; } else { update.ObjectData[0].TextureEntry = Utils.EmptyBytes; } udp.BroadcastPacket(update, PacketCategory.State); #endregion ImprovedTerseObjectUpdate } }
private void SendEntityPackets(QueuedInterestListEvent[] eventDatas, IScenePresence presence) { if (!(presence is LLAgent) || presence.InterestList == null) return; LLAgent agent = (LLAgent)presence; Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>(); Lazy<List<ObjectUpdateCompressedPacket.ObjectDataBlock>> compressedUpdateBlocks = new Lazy<List<ObjectUpdateCompressedPacket.ObjectDataBlock>>(); Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseUpdateBlocks = new Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>(); Lazy<List<ObjectUpdateCachedPacket.ObjectDataBlock>> cachedUpdateBlocks = new Lazy<List<ObjectUpdateCachedPacket.ObjectDataBlock>>(); for (int i = 0; i < eventDatas.Length; i++) { EntityAddOrUpdateArgs e = (EntityAddOrUpdateArgs)eventDatas[i].Event.State; ISceneEntity entity = e.Entity; #region Determine packet type UpdateFlags updateFlags = e.UpdateFlags; LLUpdateFlags llUpdateFlags = (LLUpdateFlags)e.ExtraFlags; LLPrimitive prim = entity as LLPrimitive; bool canUseCached = false; bool canUseTerse = true; DateTime lastSeen; if (CACHE_CHECK_ENABLED && prim != null && updateFlags.HasFlag(UpdateFlags.FullUpdate) && !llUpdateFlags.HasFlag(LLUpdateFlags.NoCachedUpdate) && m_recentAvatars.TryGetValue(presence.ID, out lastSeen) && lastSeen > prim.LastUpdated) { // This avatar was marked as leaving the same later than the last update // timestamp of this prim. Send a cache check canUseCached = true; } else if (updateFlags.HasFlag(UpdateFlags.FullUpdate) || updateFlags.HasFlag(UpdateFlags.Parent) || updateFlags.HasFlag(UpdateFlags.Scale) || updateFlags.HasFlag(UpdateFlags.Shape) || llUpdateFlags.HasFlag(LLUpdateFlags.PrimFlags) || llUpdateFlags.HasFlag(LLUpdateFlags.Text) || llUpdateFlags.HasFlag(LLUpdateFlags.NameValue) || llUpdateFlags.HasFlag(LLUpdateFlags.ExtraData) || llUpdateFlags.HasFlag(LLUpdateFlags.TextureAnim) || llUpdateFlags.HasFlag(LLUpdateFlags.Sound) || llUpdateFlags.HasFlag(LLUpdateFlags.Particles) || llUpdateFlags.HasFlag(LLUpdateFlags.Material) || llUpdateFlags.HasFlag(LLUpdateFlags.ClickAction) || llUpdateFlags.HasFlag(LLUpdateFlags.MediaURL) || llUpdateFlags.HasFlag(LLUpdateFlags.Joint)) { canUseTerse = false; } #endregion Determine packet type #region Block Construction if (canUseCached && prim != null) { cachedUpdateBlocks.Value.Add(new ObjectUpdateCachedPacket.ObjectDataBlock { CRC = prim.GetCrc(), ID = prim.LocalID }); } else if (!canUseTerse) { if (entity is IScenePresence) { IScenePresence thisPresence = (IScenePresence)entity; ObjectUpdatePacket.ObjectDataBlock block = CreateAvatarObjectUpdateBlock(thisPresence); block.UpdateFlags = (uint)GetUpdateFlags(thisPresence, presence); objectUpdateBlocks.Value.Add(block); } else if (prim != null) { ObjectUpdateCompressedPacket.ObjectDataBlock block = CreateCompressedObjectUpdateBlock(prim, prim.GetCrc()); block.UpdateFlags = (uint)GetUpdateFlags(prim, presence, m_permissions); compressedUpdateBlocks.Value.Add(block); // ObjectUpdateCompressed doesn't carry velocity or acceleration fields, so // we need to send a separate terse packet if this prim has a non-zero // velocity or acceleration if (prim.Velocity != Vector3.Zero || prim.Acceleration != Vector3.Zero) terseUpdateBlocks.Value.Add(CreateTerseUpdateBlock(entity, false)); //ObjectUpdatePacket.ObjectDataBlock block = CreateObjectUpdateBlock(prim); //block.UpdateFlags = (uint)GetUpdateFlags(prim, presence, m_permissions); //block.CRC = prim.GetCrc(); //objectUpdateBlocks.Value.Add(block); } else { // TODO: Create a generic representation for non-LLPrimitive entities? continue; } } else { terseUpdateBlocks.Value.Add(CreateTerseUpdateBlock(entity, llUpdateFlags.HasFlag(LLUpdateFlags.Textures))); } #endregion Block Construction // Unset CreateSelected after it has been sent once if (prim != null) prim.Prim.Flags &= ~PrimFlags.CreateSelected; } #region Packet Sending ushort timeDilation = (m_physics != null) ? Utils.FloatToUInt16(m_physics.TimeDilation, 0.0f, 1.0f) : UInt16.MaxValue; if (objectUpdateBlocks.IsValueCreated) { List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value; ObjectUpdatePacket packet = new ObjectUpdatePacket(); packet.RegionData.RegionHandle = Util.PositionToRegionHandle(m_scene.MinPosition); packet.RegionData.TimeDilation = timeDilation; packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[blocks.Count]; for (int i = 0; i < blocks.Count; i++) packet.ObjectData[i] = blocks[i]; m_udp.SendPacket(agent, packet, ThrottleCategory.Task, true); } if (compressedUpdateBlocks.IsValueCreated) { List<ObjectUpdateCompressedPacket.ObjectDataBlock> blocks = compressedUpdateBlocks.Value; ObjectUpdateCompressedPacket packet = new ObjectUpdateCompressedPacket(); packet.RegionData.RegionHandle = Util.PositionToRegionHandle(m_scene.MinPosition); packet.RegionData.TimeDilation = timeDilation; packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[blocks.Count]; for (int i = 0; i < blocks.Count; i++) packet.ObjectData[i] = blocks[i]; m_udp.SendPacket(agent, packet, ThrottleCategory.Task, true); } if (terseUpdateBlocks.IsValueCreated) { List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value; ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket(); packet.RegionData.RegionHandle = Util.PositionToRegionHandle(m_scene.MinPosition); packet.RegionData.TimeDilation = timeDilation; packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; for (int i = 0; i < blocks.Count; i++) packet.ObjectData[i] = blocks[i]; m_udp.SendPacket(agent, packet, ThrottleCategory.Task, true); } if (cachedUpdateBlocks.IsValueCreated) { List<ObjectUpdateCachedPacket.ObjectDataBlock> blocks = cachedUpdateBlocks.Value; ObjectUpdateCachedPacket packet = new ObjectUpdateCachedPacket(); packet.RegionData.RegionHandle = Util.PositionToRegionHandle(m_scene.MinPosition); packet.RegionData.TimeDilation = timeDilation; packet.ObjectData = new ObjectUpdateCachedPacket.ObjectDataBlock[blocks.Count]; for (int i = 0; i < blocks.Count; i++) packet.ObjectData[i] = blocks[i]; m_udp.SendPacket(agent, packet, ThrottleCategory.Task, true); } #endregion Packet Sending }