/* * Copyright (c) Contributors, http://opensimulator.org/ * See CONTRIBUTORS.TXT for a full list of copyright holders. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the OpenSim Project nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ using System; using System.Collections.Generic; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Timers; using Axiom.Math; using libsecondlife; using libsecondlife.Packets; using OpenSim.Framework; using OpenSim.Framework.Communications.Cache; using OpenSim.Framework.Console; using OpenSim.Region.Environment.Scenes; using Timer = System.Timers.Timer; namespace OpenSim.Region.ClientStack { public delegate bool PacketMethod(IClientAPI simClient, Packet packet); /// /// Handles new client connections /// Constructor takes a single Packet and authenticates everything /// public class ClientView : IClientAPI { // ~ClientView() // { // System.Console.WriteLine("[CLIENTVIEW]: Destructor called"); // } private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); /* static variables */ public static TerrainManager TerrainManager; /* private variables */ private readonly LLUUID m_sessionId; private LLUUID m_secureSessionId = LLUUID.Zero; //private AgentAssetUpload UploadAssets; private int m_debug = 0; private readonly AssetCache m_assetCache; // private InventoryCache m_inventoryCache; private int m_cachedTextureSerial = 0; private Timer m_clientPingTimer; private int m_packetsReceived = 0; private int m_lastPacketsReceivedSentToScene = 0; private int m_unAckedBytes = 0; private int m_packetsSent = 0; private int m_lastPacketsSentSentToScene = 0; private int m_probesWithNoIngressPackets = 0; private int m_lastPacketsReceived = 0; private byte[] ZeroOutBuffer = new byte[4096]; private readonly Encoding m_encoding = Encoding.ASCII; private readonly LLUUID m_agentId; private readonly uint m_circuitCode; private int m_moneyBalance; private byte[] m_channelVersion = Helpers.StringToField("OpenSimulator 0.5"); // Dummy value needed by libSL /* protected variables */ protected static Dictionary PacketHandlers = new Dictionary(); //Global/static handlers for all clients protected Dictionary m_packetHandlers = new Dictionary(); protected IScene m_scene; protected AgentCircuitManager m_authenticateSessionsHandler; protected PacketQueue m_packetQueue; protected Dictionary m_pendingAcks = new Dictionary(); protected Dictionary m_needAck = new Dictionary(); protected Timer m_ackTimer; protected uint m_sequence = 0; protected object m_sequenceLock = new object(); protected const int MAX_APPENDED_ACKS = 10; protected const int RESEND_TIMEOUT = 4000; protected const int MAX_SEQUENCE = 0xFFFFFF; protected PacketServer m_networkServer; /* public variables */ protected string m_firstName; protected string m_lastName; protected Thread m_clientThread; protected LLVector3 m_startpos; protected EndPoint m_userEndPoint; /* Properties */ public LLUUID SecureSessionId { get { return m_secureSessionId; } } public IScene Scene { get { return m_scene; } } public LLUUID SessionId { get { return m_sessionId; } } public LLVector3 StartPos { get { return m_startpos; } set { m_startpos = value; } } public LLUUID AgentId { get { return m_agentId; } } /// /// This is a utility method used by single states to not duplicate kicks and blue card of death messages. /// public bool ChildAgentStatus() { return m_scene.PresenceChildStatus(AgentId); } /// /// First name of the agent/avatar represented by the client /// public string FirstName { get { return m_firstName; } } /// /// Last name of the agent/avatar represented by the client /// public string LastName { get { return m_lastName; } } /// /// Full name of the client (first name and last name) /// public string Name { get { return FirstName + " " + LastName; } } public uint CircuitCode { get { return m_circuitCode; } } public int MoneyBalance { get { return m_moneyBalance; } } /* METHODS */ public ClientView(EndPoint remoteEP, IScene scene, AssetCache assetCache, PacketServer packServer, AgentCircuitManager authenSessions, LLUUID agentId, LLUUID sessionId, uint circuitCode) { m_moneyBalance = 1000; m_channelVersion = Helpers.StringToField(scene.GetSimulatorVersion()); m_scene = scene; m_assetCache = assetCache; m_networkServer = packServer; // m_inventoryCache = inventoryCache; m_authenticateSessionsHandler = authenSessions; m_log.Info("[CLIENT]: Started up new client thread to handle incoming request"); m_agentId = agentId; m_sessionId = sessionId; m_circuitCode = circuitCode; m_userEndPoint = remoteEP; m_startpos = m_authenticateSessionsHandler.GetPosition(circuitCode); // While working on this, the BlockingQueue had me fooled for a bit. // The Blocking queue causes the thread to stop until there's something // in it to process. It's an on-purpose threadlock though because // without it, the clientloop will suck up all sim resources. m_packetQueue = new PacketQueue(); RegisterLocalPacketHandlers(); m_clientThread = new Thread(new ThreadStart(AuthUser)); m_clientThread.Name = "ClientThread"; m_clientThread.IsBackground = true; m_clientThread.Start(); OpenSim.Framework.ThreadTracker.Add(m_clientThread); } public void SetDebug(int newDebug) { m_debug = newDebug; } # region Client Methods private void CloseCleanup(bool ShutdownCircult) { m_scene.RemoveClient(AgentId); //m_log.InfoFormat("[CLIENTVIEW] Memory pre GC {0}", System.GC.GetTotalMemory(false)); //m_log.InfoFormat("[CLIENTVIEW] Memory post GC {0}", System.GC.GetTotalMemory(true)); // Send the STOP packet DisableSimulatorPacket disable = (DisableSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.DisableSimulator); OutPacket(disable, ThrottleOutPacketType.Task); // FLUSH Packets m_packetQueue.Close(); m_packetQueue.Flush(); Thread.Sleep(2000); // Shut down timers m_ackTimer.Stop(); m_clientPingTimer.Stop(); // This is just to give the client a reasonable chance of // flushing out all it's packets. There should probably // be a better mechanism here // We can't reach into other scenes and close the connection // We need to do this over grid communications //m_scene.CloseAllAgents(CircuitCode); // If we're not shutting down the circuit, then this is the last time we'll go here. // If we are shutting down the circuit, the UDP Server will come back here with // ShutDownCircuit = false if (!(ShutdownCircult)) { GC.Collect(); m_clientThread.Abort(); } } /// /// Close down the client view. This *must* be the last method called, since the last # /// statement of CloseCleanup() aborts the thread. /// /// public void Close(bool ShutdownCircult) { // Pull Client out of Region m_log.Info("[CLIENT]: Close has been called"); //raiseevent on the packet server to Shutdown the circuit if (ShutdownCircult) OnConnectionClosed(this); CloseCleanup(ShutdownCircult); } public void Kick(string message) { if (!ChildAgentStatus()) { KickUserPacket kupack = (KickUserPacket)PacketPool.Instance.GetPacket(PacketType.KickUser); kupack.UserInfo.AgentID = AgentId; kupack.UserInfo.SessionID = SessionId; kupack.TargetBlock.TargetIP = (uint)0; kupack.TargetBlock.TargetPort = (ushort)0; kupack.UserInfo.Reason = Helpers.StringToField(message); OutPacket(kupack, ThrottleOutPacketType.Task); } } public void Stop() { m_log.Info("[BUG]: Stop called, please find out where and remove it"); } #endregion # region Packet Handling public static bool AddPacketHandler(PacketType packetType, PacketMethod handler) { bool result = false; lock (PacketHandlers) { if (!PacketHandlers.ContainsKey(packetType)) { PacketHandlers.Add(packetType, handler); result = true; } } return result; } public bool AddLocalPacketHandler(PacketType packetType, PacketMethod handler) { bool result = false; lock (m_packetHandlers) { if (!m_packetHandlers.ContainsKey(packetType)) { m_packetHandlers.Add(packetType, handler); result = true; } } return result; } protected virtual bool ProcessPacketMethod(Packet packet) { bool result = false; bool found = false; PacketMethod method; if (m_packetHandlers.TryGetValue(packet.Type, out method)) { //there is a local handler for this packet type result = method(this, packet); } else { //there is not a local handler so see if there is a Global handler lock (PacketHandlers) { found = PacketHandlers.TryGetValue(packet.Type, out method); } if (found) { result = method(this, packet); } } return result; } protected void DebugPacket(string direction, Packet packet) { if (m_debug > 0) { string info = String.Empty; if (m_debug < 255 && packet.Type == PacketType.AgentUpdate) return; if (m_debug < 254 && packet.Type == PacketType.ViewerEffect) return; if (m_debug < 253 && ( packet.Type == PacketType.CompletePingCheck || packet.Type == PacketType.StartPingCheck )) return; if (m_debug < 252 && packet.Type == PacketType.PacketAck) return; if (m_debug > 1) { info = packet.ToString(); } else { info = packet.Type.ToString(); } Console.WriteLine(m_circuitCode + ":" + direction + ": " + info); } } protected virtual void ClientLoop() { m_log.Info("[CLIENT]: Entered loop"); while (true) { QueItem nextPacket = m_packetQueue.Dequeue(); if (nextPacket.Incoming) { if (nextPacket.Packet.Type != PacketType.AgentUpdate) { m_packetsReceived++; } DebugPacket("IN", nextPacket.Packet); ProcessInPacket(nextPacket.Packet); } else { DebugPacket("OUT", nextPacket.Packet); ProcessOutPacket(nextPacket.Packet); } } } # endregion protected void CheckClientConnectivity(object sender, ElapsedEventArgs e) { if (m_packetsReceived == m_lastPacketsReceived) { m_probesWithNoIngressPackets++; if (m_probesWithNoIngressPackets > 30) { if (OnConnectionClosed != null) { OnConnectionClosed(this); } } else { // this will normally trigger at least one packet (ping response) SendStartPingCheck(0); } } else { // Something received in the meantime - we can reset the counters m_probesWithNoIngressPackets = 0; m_lastPacketsReceived = m_packetsReceived; } //SendPacketStats(); } # region Setup protected virtual void InitNewClient() { //this.UploadAssets = new AgentAssetUpload(this, m_assetCache, m_inventoryCache); // Establish our two timers. We could probably get this down to one m_ackTimer = new Timer(750); m_ackTimer.Elapsed += new ElapsedEventHandler(AckTimer_Elapsed); m_ackTimer.Start(); m_clientPingTimer = new Timer(5000); m_clientPingTimer.Elapsed += new ElapsedEventHandler(CheckClientConnectivity); m_clientPingTimer.Enabled = true; m_log.Info("[CLIENT]: Adding viewer agent to scene"); m_scene.AddNewClient(this, true); } protected virtual void AuthUser() { // AuthenticateResponse sessionInfo = m_gridServer.AuthenticateSession(m_cirpack.m_circuitCode.m_sessionId, m_cirpack.m_circuitCode.ID, m_cirpack.m_circuitCode.Code); AuthenticateResponse sessionInfo = m_authenticateSessionsHandler.AuthenticateSession(m_sessionId, m_agentId, m_circuitCode); if (!sessionInfo.Authorised) { //session/circuit not authorised m_log.Info("[CLIENT]: New user request denied to " + m_userEndPoint.ToString()); m_packetQueue.Flush(); m_packetQueue.Close(); m_clientThread.Abort(); } else { m_log.Info("[CLIENT]: Got authenticated connection from " + m_userEndPoint.ToString()); //session is authorised m_firstName = sessionInfo.LoginInfo.First; m_lastName = sessionInfo.LoginInfo.Last; if (sessionInfo.LoginInfo.SecureSession != LLUUID.Zero) { m_secureSessionId = sessionInfo.LoginInfo.SecureSession; } // This sets up all the timers InitNewClient(); ClientLoop(); } } # endregion // Previously ClientView.API partial class public event Action OnLogout; public event ObjectPermissions OnObjectPermissions; public event Action OnConnectionClosed; public event ViewerEffectEventHandler OnViewerEffect; public event ImprovedInstantMessage OnInstantMessage; public event ChatFromViewer OnChatFromViewer; public event TextureRequest OnRequestTexture; public event RezObject OnRezObject; public event GenericCall4 OnDeRezObject; public event ModifyTerrain OnModifyTerrain; public event Action OnRegionHandShakeReply; public event GenericCall2 OnRequestWearables; public event SetAppearance OnSetAppearance; public event AvatarNowWearing OnAvatarNowWearing; public event RezSingleAttachmentFromInv OnRezSingleAttachmentFromInv; public event ObjectAttach OnObjectAttach; public event GenericCall2 OnCompleteMovementToRegion; public event UpdateAgent OnAgentUpdate; public event AgentRequestSit OnAgentRequestSit; public event AgentSit OnAgentSit; public event AvatarPickerRequest OnAvatarPickerRequest; public event StartAnim OnStartAnim; public event StopAnim OnStopAnim; public event Action OnRequestAvatarsData; public event LinkObjects OnLinkObjects; public event DelinkObjects OnDelinkObjects; public event UpdateVector OnGrabObject; public event ObjectSelect OnDeGrabObject; public event ObjectDuplicate OnObjectDuplicate; public event MoveObject OnGrabUpdate; public event AddNewPrim OnAddPrim; public event RequestGodlikePowers OnRequestGodlikePowers; public event GodKickUser OnGodKickUser; public event ObjectExtraParams OnUpdateExtraParams; public event UpdateShape OnUpdatePrimShape; public event ObjectSelect OnObjectSelect; public event ObjectDeselect OnObjectDeselect; public event GenericCall7 OnObjectDescription; public event GenericCall7 OnObjectName; public event RequestObjectPropertiesFamily OnRequestObjectPropertiesFamily; public event UpdatePrimFlags OnUpdatePrimFlags; public event UpdatePrimTexture OnUpdatePrimTexture; public event UpdateVector OnUpdatePrimGroupPosition; public event UpdateVector OnUpdatePrimSinglePosition; public event UpdatePrimRotation OnUpdatePrimGroupRotation; public event UpdatePrimSingleRotation OnUpdatePrimSingleRotation; public event UpdatePrimGroupRotation OnUpdatePrimGroupMouseRotation; public event UpdateVector OnUpdatePrimScale; public event StatusChange OnChildAgentStatus; public event GenericCall2 OnStopMovement; public event Action OnRemoveAvatar; public event RequestMapBlocks OnRequestMapBlocks; public event RequestMapName OnMapNameRequest; public event TeleportLocationRequest OnTeleportLocationRequest; public event DisconnectUser OnDisconnectUser; public event RequestAvatarProperties OnRequestAvatarProperties; public event SetAlwaysRun OnSetAlwaysRun; public event FetchInventory OnAgentDataUpdateRequest; public event FetchInventory OnUserInfoRequest; public event TeleportLocationRequest OnSetStartLocationRequest; public event CreateNewInventoryItem OnCreateNewInventoryItem; public event CreateInventoryFolder OnCreateNewInventoryFolder; public event UpdateInventoryFolder OnUpdateInventoryFolder; public event MoveInventoryFolder OnMoveInventoryFolder; public event FetchInventoryDescendents OnFetchInventoryDescendents; public event PurgeInventoryDescendents OnPurgeInventoryDescendents; public event FetchInventory OnFetchInventory; public event RequestTaskInventory OnRequestTaskInventory; public event UpdateInventoryItem OnUpdateInventoryItem; public event CopyInventoryItem OnCopyInventoryItem; public event MoveInventoryItem OnMoveInventoryItem; public event RemoveInventoryItem OnRemoveInventoryItem; public event RemoveInventoryFolder OnRemoveInventoryFolder; public event UDPAssetUploadRequest OnAssetUploadRequest; public event XferReceive OnXferReceive; public event RequestXfer OnRequestXfer; public event ConfirmXfer OnConfirmXfer; public event RezScript OnRezScript; public event UpdateTaskInventory OnUpdateTaskInventory; public event RemoveTaskInventory OnRemoveTaskItem; public event UUIDNameRequest OnNameFromUUIDRequest; public event ParcelAccessListRequest OnParcelAccessListRequest; public event ParcelAccessListUpdateRequest OnParcelAccessListUpdateRequest; public event ParcelPropertiesRequest OnParcelPropertiesRequest; public event ParcelDivideRequest OnParcelDivideRequest; public event ParcelJoinRequest OnParcelJoinRequest; public event ParcelPropertiesUpdateRequest OnParcelPropertiesUpdateRequest; public event ParcelSelectObjects OnParcelSelectObjects; public event ParcelObjectOwnerRequest OnParcelObjectOwnerRequest; public event EstateOwnerMessageRequest OnEstateOwnerMessage; public event RegionInfoRequest OnRegionInfoRequest; public event EstateCovenantRequest OnEstateCovenantRequest; public event FriendActionDelegate OnApproveFriendRequest; public event FriendActionDelegate OnDenyFriendRequest; public event FriendshipTermination OnTerminateFriendship; public event PacketStats OnPacketStats; public event MoneyTransferRequest OnMoneyTransferRequest; public event MoneyBalanceRequest OnMoneyBalanceRequest; #region Scene/Avatar to Client /// /// /// /// public void SendRegionHandshake(RegionInfo regionInfo) { RegionHandshakePacket handshake = (RegionHandshakePacket)PacketPool.Instance.GetPacket(PacketType.RegionHandshake); bool estatemanager = false; LLUUID[] EstateManagers = regionInfo.EstateSettings.estateManagers; for (int i = 0; i < EstateManagers.Length; i++) { if (EstateManagers[i] == AgentId) estatemanager = true; } handshake.RegionInfo.BillableFactor = regionInfo.EstateSettings.billableFactor; handshake.RegionInfo.IsEstateManager = estatemanager; handshake.RegionInfo.TerrainHeightRange00 = regionInfo.EstateSettings.terrainHeightRange0; handshake.RegionInfo.TerrainHeightRange01 = regionInfo.EstateSettings.terrainHeightRange1; handshake.RegionInfo.TerrainHeightRange10 = regionInfo.EstateSettings.terrainHeightRange2; handshake.RegionInfo.TerrainHeightRange11 = regionInfo.EstateSettings.terrainHeightRange3; handshake.RegionInfo.TerrainStartHeight00 = regionInfo.EstateSettings.terrainStartHeight0; handshake.RegionInfo.TerrainStartHeight01 = regionInfo.EstateSettings.terrainStartHeight1; handshake.RegionInfo.TerrainStartHeight10 = regionInfo.EstateSettings.terrainStartHeight2; handshake.RegionInfo.TerrainStartHeight11 = regionInfo.EstateSettings.terrainStartHeight3; handshake.RegionInfo.SimAccess = (byte)regionInfo.EstateSettings.simAccess; handshake.RegionInfo.WaterHeight = regionInfo.EstateSettings.waterHeight; handshake.RegionInfo.RegionFlags = (uint)regionInfo.EstateSettings.regionFlags; handshake.RegionInfo.SimName = Helpers.StringToField(regionInfo.RegionName); handshake.RegionInfo.SimOwner = regionInfo.MasterAvatarAssignedUUID; handshake.RegionInfo.TerrainBase0 = regionInfo.EstateSettings.terrainBase0; handshake.RegionInfo.TerrainBase1 = regionInfo.EstateSettings.terrainBase1; handshake.RegionInfo.TerrainBase2 = regionInfo.EstateSettings.terrainBase2; handshake.RegionInfo.TerrainBase3 = regionInfo.EstateSettings.terrainBase3; handshake.RegionInfo.TerrainDetail0 = regionInfo.EstateSettings.terrainDetail0; handshake.RegionInfo.TerrainDetail1 = regionInfo.EstateSettings.terrainDetail1; handshake.RegionInfo.TerrainDetail2 = regionInfo.EstateSettings.terrainDetail2; handshake.RegionInfo.TerrainDetail3 = regionInfo.EstateSettings.terrainDetail3; handshake.RegionInfo.CacheID = LLUUID.Random(); //I guess this is for the client to remember an old setting? OutPacket(handshake, ThrottleOutPacketType.Task); } /// /// /// /// public void MoveAgentIntoRegion(RegionInfo regInfo, LLVector3 pos, LLVector3 look) { AgentMovementCompletePacket mov = (AgentMovementCompletePacket)PacketPool.Instance.GetPacket(PacketType.AgentMovementComplete); mov.SimData.ChannelVersion = m_channelVersion; mov.AgentData.SessionID = m_sessionId; mov.AgentData.AgentID = AgentId; mov.Data.RegionHandle = regInfo.RegionHandle; mov.Data.Timestamp = 1172750370; // TODO - dynamicalise this if ((pos.X == 0) && (pos.Y == 0) && (pos.Z == 0)) { mov.Data.Position = m_startpos; } else { mov.Data.Position = pos; } mov.Data.LookAt = look; // Hack to get this out immediately and skip the throttles OutPacket(mov, ThrottleOutPacketType.Unknown); } /// /// /// /// /// /// /// /// public void SendChatMessage(string message, byte type, LLVector3 fromPos, string fromName, LLUUID fromAgentID) { SendChatMessage(Helpers.StringToField(message), type, fromPos, fromName, fromAgentID); } public void SendChatMessage(byte[] message, byte type, LLVector3 fromPos, string fromName, LLUUID fromAgentID) { ChatFromSimulatorPacket reply = (ChatFromSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.ChatFromSimulator); reply.ChatData.Audible = 1; reply.ChatData.Message = message; reply.ChatData.ChatType = type; reply.ChatData.SourceType = 1; reply.ChatData.Position = fromPos; reply.ChatData.FromName = Helpers.StringToField(fromName); reply.ChatData.OwnerID = fromAgentID; reply.ChatData.SourceID = fromAgentID; OutPacket(reply, ThrottleOutPacketType.Task); } /// /// /// /// /// public void SendInstantMessage(LLUUID fromAgent, LLUUID fromAgentSession, string message, LLUUID toAgent, LLUUID imSessionID, string fromName, byte dialog, uint timeStamp) { ImprovedInstantMessagePacket msg = (ImprovedInstantMessagePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedInstantMessage); msg.AgentData.AgentID = fromAgent; msg.AgentData.SessionID = fromAgentSession; msg.MessageBlock.FromAgentName = Helpers.StringToField(fromName); msg.MessageBlock.Dialog = dialog; msg.MessageBlock.FromGroup = false; msg.MessageBlock.ID = imSessionID; msg.MessageBlock.Offline = 0; msg.MessageBlock.ParentEstateID = 0; msg.MessageBlock.Position = new LLVector3(); msg.MessageBlock.RegionID = LLUUID.Random(); msg.MessageBlock.Timestamp = timeStamp; msg.MessageBlock.ToAgentID = toAgent; msg.MessageBlock.Message = Helpers.StringToField(message); msg.MessageBlock.BinaryBucket = new byte[0]; OutPacket(msg, ThrottleOutPacketType.Task); } /// /// Send the region heightmap to the client /// /// heightmap public virtual void SendLayerData(float[] map) { try { int[] patches = new int[4]; for (int y = 0; y < 16; y++) { for (int x = 0; x < 16; x += 4) { patches[0] = x + 0 + y * 16; patches[1] = x + 1 + y * 16; patches[2] = x + 2 + y * 16; patches[3] = x + 3 + y * 16; Packet layerpack = TerrainManager.CreateLandPacket(map, patches); OutPacket(layerpack, ThrottleOutPacketType.Land); } } } catch (Exception e) { m_log.Warn("[client]: " + "ClientView.API.cs: SendLayerData() - Failed with exception " + e.ToString()); } } /// /// Sends a specified patch to a client /// /// Patch coordinate (x) 0..16 /// Patch coordinate (y) 0..16 /// heightmap public void SendLayerData(int px, int py, float[] map) { try { int[] patches = new int[1]; int patchx, patchy; patchx = px; patchy = py; patches[0] = patchx + 0 + patchy * 16; Packet layerpack = TerrainManager.CreateLandPacket(map, patches); OutPacket(layerpack, ThrottleOutPacketType.Land); } catch (Exception e) { m_log.Warn("[client]: " + "ClientView.API.cs: SendLayerData() - Failed with exception " + e.ToString()); } } /// /// /// /// /// /// public void InformClientOfNeighbour(ulong neighbourHandle, IPEndPoint neighbourEndPoint) { IPAddress neighbourIP = neighbourEndPoint.Address; ushort neighbourPort = (ushort)neighbourEndPoint.Port; EnableSimulatorPacket enablesimpacket = (EnableSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.EnableSimulator); // TODO: don't create new blocks if recycling an old packet enablesimpacket.SimulatorInfo = new EnableSimulatorPacket.SimulatorInfoBlock(); enablesimpacket.SimulatorInfo.Handle = neighbourHandle; byte[] byteIP = neighbourIP.GetAddressBytes(); enablesimpacket.SimulatorInfo.IP = (uint)byteIP[3] << 24; enablesimpacket.SimulatorInfo.IP += (uint)byteIP[2] << 16; enablesimpacket.SimulatorInfo.IP += (uint)byteIP[1] << 8; enablesimpacket.SimulatorInfo.IP += (uint)byteIP[0]; enablesimpacket.SimulatorInfo.Port = neighbourPort; OutPacket(enablesimpacket, ThrottleOutPacketType.Task); } /// /// /// /// public AgentCircuitData RequestClientInfo() { AgentCircuitData agentData = new AgentCircuitData(); agentData.AgentID = AgentId; agentData.SessionID = m_sessionId; agentData.SecureSessionID = SecureSessionId; agentData.circuitcode = m_circuitCode; agentData.child = false; agentData.firstname = m_firstName; agentData.lastname = m_lastName; agentData.CapsPath = String.Empty; return agentData; } public void CrossRegion(ulong newRegionHandle, LLVector3 pos, LLVector3 lookAt, IPEndPoint externalIPEndPoint, string capsURL) { LLVector3 look = new LLVector3(lookAt.X * 10, lookAt.Y * 10, lookAt.Z * 10); //CrossedRegionPacket newSimPack = (CrossedRegionPacket)PacketPool.Instance.GetPacket(PacketType.CrossedRegion); CrossedRegionPacket newSimPack = new CrossedRegionPacket(); // TODO: don't create new blocks if recycling an old packet newSimPack.AgentData = new CrossedRegionPacket.AgentDataBlock(); newSimPack.AgentData.AgentID = AgentId; newSimPack.AgentData.SessionID = m_sessionId; newSimPack.Info = new CrossedRegionPacket.InfoBlock(); newSimPack.Info.Position = pos; newSimPack.Info.LookAt = look; newSimPack.RegionData = new CrossedRegionPacket.RegionDataBlock(); newSimPack.RegionData.RegionHandle = newRegionHandle; byte[] byteIP = externalIPEndPoint.Address.GetAddressBytes(); newSimPack.RegionData.SimIP = (uint)byteIP[3] << 24; newSimPack.RegionData.SimIP += (uint)byteIP[2] << 16; newSimPack.RegionData.SimIP += (uint)byteIP[1] << 8; newSimPack.RegionData.SimIP += (uint)byteIP[0]; newSimPack.RegionData.SimPort = (ushort)externalIPEndPoint.Port; newSimPack.RegionData.SeedCapability = Helpers.StringToField(capsURL); // Hack to get this out immediately and skip throttles OutPacket(newSimPack, ThrottleOutPacketType.Unknown); } public void SendMapBlock(List mapBlocks) { MapBlockReplyPacket mapReply = (MapBlockReplyPacket)PacketPool.Instance.GetPacket(PacketType.MapBlockReply); // TODO: don't create new blocks if recycling an old packet mapReply.AgentData.AgentID = AgentId; mapReply.Data = new MapBlockReplyPacket.DataBlock[mapBlocks.Count]; mapReply.AgentData.Flags = 0; for (int i = 0; i < mapBlocks.Count; i++) { mapReply.Data[i] = new MapBlockReplyPacket.DataBlock(); mapReply.Data[i].MapImageID = mapBlocks[i].MapImageId; mapReply.Data[i].X = mapBlocks[i].X; mapReply.Data[i].Y = mapBlocks[i].Y; mapReply.Data[i].WaterHeight = mapBlocks[i].WaterHeight; mapReply.Data[i].Name = Helpers.StringToField(mapBlocks[i].Name); mapReply.Data[i].RegionFlags = mapBlocks[i].RegionFlags; mapReply.Data[i].Access = mapBlocks[i].Access; mapReply.Data[i].Agents = mapBlocks[i].Agents; } OutPacket(mapReply, ThrottleOutPacketType.Land); } public void SendLocalTeleport(LLVector3 position, LLVector3 lookAt, uint flags) { TeleportLocalPacket tpLocal = (TeleportLocalPacket)PacketPool.Instance.GetPacket(PacketType.TeleportLocal); tpLocal.Info.AgentID = AgentId; tpLocal.Info.TeleportFlags = flags; tpLocal.Info.LocationID = 2; tpLocal.Info.LookAt = lookAt; tpLocal.Info.Position = position; // Hack to get this out immediately and skip throttles OutPacket(tpLocal, ThrottleOutPacketType.Unknown); } public void SendRegionTeleport(ulong regionHandle, byte simAccess, IPEndPoint newRegionEndPoint, uint locationID, uint flags, string capsURL) { //TeleportFinishPacket teleport = (TeleportFinishPacket)PacketPool.Instance.GetPacket(PacketType.TeleportFinish); TeleportFinishPacket teleport = new TeleportFinishPacket(); teleport.Info.AgentID = AgentId; teleport.Info.RegionHandle = regionHandle; teleport.Info.SimAccess = simAccess; teleport.Info.SeedCapability = Helpers.StringToField(capsURL); IPAddress oIP = newRegionEndPoint.Address; byte[] byteIP = oIP.GetAddressBytes(); uint ip = (uint)byteIP[3] << 24; ip += (uint)byteIP[2] << 16; ip += (uint)byteIP[1] << 8; ip += (uint)byteIP[0]; teleport.Info.SimIP = ip; teleport.Info.SimPort = (ushort)newRegionEndPoint.Port; teleport.Info.LocationID = 4; teleport.Info.TeleportFlags = 1 << 4; // Hack to get this out immediately and skip throttles. OutPacket(teleport, ThrottleOutPacketType.Unknown); } /// /// /// public void SendTeleportFailed(string reason) { TeleportFailedPacket tpFailed = (TeleportFailedPacket)PacketPool.Instance.GetPacket(PacketType.TeleportFailed); tpFailed.Info.AgentID = AgentId; tpFailed.Info.Reason = Helpers.StringToField(reason); // Hack to get this out immediately and skip throttles OutPacket(tpFailed, ThrottleOutPacketType.Unknown); } /// /// /// public void SendTeleportLocationStart() { //TeleportStartPacket tpStart = (TeleportStartPacket)PacketPool.Instance.GetPacket(PacketType.TeleportStart); TeleportStartPacket tpStart = new TeleportStartPacket(); tpStart.Info.TeleportFlags = 16; // Teleport via location // Hack to get this out immediately and skip throttles OutPacket(tpStart, ThrottleOutPacketType.Unknown); } public void SendMoneyBalance(LLUUID transaction, bool success, byte[] description, int balance) { MoneyBalanceReplyPacket money = (MoneyBalanceReplyPacket)PacketPool.Instance.GetPacket(PacketType.MoneyBalanceReply); money.MoneyData.AgentID = AgentId; money.MoneyData.TransactionID = transaction; money.MoneyData.TransactionSuccess = success; money.MoneyData.Description = description; money.MoneyData.MoneyBalance = balance; OutPacket(money, ThrottleOutPacketType.Task); } public void SendStartPingCheck(byte seq) { StartPingCheckPacket pc = (StartPingCheckPacket)PacketPool.Instance.GetPacket(PacketType.StartPingCheck); pc.PingID.PingID = seq; pc.Header.Reliable = false; OutPacket(pc, ThrottleOutPacketType.Task); } public void SendKillObject(ulong regionHandle, uint localID) { KillObjectPacket kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject); // TODO: don't create new blocks if recycling an old packet kill.ObjectData = new KillObjectPacket.ObjectDataBlock[1]; kill.ObjectData[0] = new KillObjectPacket.ObjectDataBlock(); kill.ObjectData[0].ID = localID; kill.Header.Reliable = false; OutPacket(kill, ThrottleOutPacketType.Task); } /// /// Send information about the items contained in a folder to the client. /// /// XXX This method needs some refactoring loving /// /// The owner of the folder /// The id of the folder /// The items contained in the folder identified by folderID /// Do we need to send folder information? /// Do we need to send item information? public void SendInventoryFolderDetails(LLUUID ownerID, LLUUID folderID, List items, List folders, bool fetchFolders, bool fetchItems) { // An inventory descendents packet consists of a single agent section and an inventory details // section for each inventory item. The size of each inventory item is approximately 550 bytes. // In theory, UDP has a maximum packet size of 64k, so it should be possible to send descendent // packets containing metadata for in excess of 100 items. But in practice, there may be other // factors (e.g. firewalls) restraining the maximum UDP packet size. See, // // http://opensimulator.org/mantis/view.php?id=226 // // for one example of this kind of thing. In fact, the Linden servers appear to only send about // 6 to 7 items at a time, so let's stick with 6 int MAX_ITEMS_PER_PACKET = 6; Encoding enc = Encoding.ASCII; uint FULL_MASK_PERMISSIONS = (uint)PermissionMask.All; InventoryDescendentsPacket descend; int i; int count; if (fetchItems) { descend = CreateInventoryDescendentsPacket(ownerID, folderID); if (items.Count < MAX_ITEMS_PER_PACKET) { descend.ItemData = new InventoryDescendentsPacket.ItemDataBlock[items.Count]; descend.AgentData.Descendents = items.Count; } else { descend.ItemData = new InventoryDescendentsPacket.ItemDataBlock[MAX_ITEMS_PER_PACKET]; descend.AgentData.Descendents = MAX_ITEMS_PER_PACKET; } // Even if we aren't fetching the folders, we still need to include the folder count // in the total number of descendents. Failure to do so will cause subtle bugs such // as the failure of textures which haven't been expanded in inventory to show up // in the texture prim edit selection panel. if (!fetchFolders) { descend.AgentData.Descendents += folders.Count; } count = 0; i = 0; foreach (InventoryItemBase item in items) { descend.ItemData[i] = new InventoryDescendentsPacket.ItemDataBlock(); descend.ItemData[i].ItemID = item.inventoryID; descend.ItemData[i].AssetID = item.assetID; descend.ItemData[i].CreatorID = item.creatorsID; descend.ItemData[i].BaseMask = item.inventoryBasePermissions; descend.ItemData[i].CreationDate = 1000; descend.ItemData[i].Description = Helpers.StringToField(item.inventoryDescription); descend.ItemData[i].EveryoneMask = item.inventoryEveryOnePermissions; descend.ItemData[i].Flags = 1; descend.ItemData[i].FolderID = item.parentFolderID; descend.ItemData[i].GroupID = new LLUUID("00000000-0000-0000-0000-000000000000"); descend.ItemData[i].GroupMask = 0; descend.ItemData[i].InvType = (sbyte)item.invType; descend.ItemData[i].Name = Helpers.StringToField(item.inventoryName); descend.ItemData[i].NextOwnerMask = item.inventoryNextPermissions; descend.ItemData[i].OwnerID = item.avatarID; descend.ItemData[i].OwnerMask = item.inventoryCurrentPermissions; descend.ItemData[i].SalePrice = 0; descend.ItemData[i].SaleType = 0; descend.ItemData[i].Type = (sbyte)item.assetType; descend.ItemData[i].CRC = Helpers.InventoryCRC(descend.ItemData[i].CreationDate, descend.ItemData[i].SaleType, descend.ItemData[i].InvType, descend.ItemData[i].Type, descend.ItemData[i].AssetID, descend.ItemData[i].GroupID, descend.ItemData[i].SalePrice, descend.ItemData[i].OwnerID, descend.ItemData[i].CreatorID, descend.ItemData[i].ItemID, descend.ItemData[i].FolderID, descend.ItemData[i].EveryoneMask, descend.ItemData[i].Flags, descend.ItemData[i].OwnerMask, descend.ItemData[i].GroupMask, item.inventoryCurrentPermissions); i++; count++; if (i == MAX_ITEMS_PER_PACKET) { OutPacket(descend, ThrottleOutPacketType.Asset); if ((items.Count - count) > 0) { descend = CreateInventoryDescendentsPacket(ownerID, folderID); if ((items.Count - count) < MAX_ITEMS_PER_PACKET) { descend.ItemData = new InventoryDescendentsPacket.ItemDataBlock[items.Count - count]; descend.AgentData.Descendents = items.Count - count; } else { descend.ItemData = new InventoryDescendentsPacket.ItemDataBlock[MAX_ITEMS_PER_PACKET]; descend.AgentData.Descendents = MAX_ITEMS_PER_PACKET; } i = 0; } } } if (i < MAX_ITEMS_PER_PACKET) { OutPacket(descend, ThrottleOutPacketType.Asset); } } //send subfolders descend = CreateInventoryDescendentsPacket(ownerID, folderID); if (folders.Count < MAX_ITEMS_PER_PACKET) { descend.FolderData = new InventoryDescendentsPacket.FolderDataBlock[folders.Count]; descend.AgentData.Descendents = folders.Count; } else { descend.FolderData = new InventoryDescendentsPacket.FolderDataBlock[MAX_ITEMS_PER_PACKET]; descend.AgentData.Descendents = MAX_ITEMS_PER_PACKET; } // Not sure if this scenario ever actually occurs, but nonetheless we include the items // count even if we're not sending item data for the same reasons as above. if (!fetchItems) { descend.AgentData.Descendents += items.Count; } i = 0; count = 0; foreach (InventoryFolderBase folder in folders) { descend.FolderData[i] = new InventoryDescendentsPacket.FolderDataBlock(); descend.FolderData[i].FolderID = folder.folderID; descend.FolderData[i].Name = Helpers.StringToField(folder.name); descend.FolderData[i].ParentID = folder.parentID; descend.FolderData[i].Type = (sbyte)folder.type; i++; count++; if (i == MAX_ITEMS_PER_PACKET) { OutPacket(descend, ThrottleOutPacketType.Asset); if ((folders.Count - count) > 0) { descend = CreateInventoryDescendentsPacket(ownerID, folderID); if ((folders.Count - count) < MAX_ITEMS_PER_PACKET) { descend.FolderData = new InventoryDescendentsPacket.FolderDataBlock[folders.Count - count]; descend.AgentData.Descendents = folders.Count - count; } else { descend.FolderData = new InventoryDescendentsPacket.FolderDataBlock[MAX_ITEMS_PER_PACKET]; descend.AgentData.Descendents = MAX_ITEMS_PER_PACKET; } i = 0; } } } if (i < MAX_ITEMS_PER_PACKET) { OutPacket(descend, ThrottleOutPacketType.Asset); } } private InventoryDescendentsPacket CreateInventoryDescendentsPacket(LLUUID ownerID, LLUUID folderID) { InventoryDescendentsPacket descend = (InventoryDescendentsPacket)PacketPool.Instance.GetPacket(PacketType.InventoryDescendents); descend.AgentData.AgentID = AgentId; descend.AgentData.OwnerID = ownerID; descend.AgentData.FolderID = folderID; descend.AgentData.Version = 0; return descend; } public void SendInventoryItemDetails(LLUUID ownerID, InventoryItemBase item) { Encoding enc = Encoding.ASCII; uint FULL_MASK_PERMISSIONS = (uint)PermissionMask.All; FetchInventoryReplyPacket inventoryReply = (FetchInventoryReplyPacket)PacketPool.Instance.GetPacket(PacketType.FetchInventoryReply); // TODO: don't create new blocks if recycling an old packet inventoryReply.AgentData.AgentID = AgentId; inventoryReply.InventoryData = new FetchInventoryReplyPacket.InventoryDataBlock[1]; inventoryReply.InventoryData[0] = new FetchInventoryReplyPacket.InventoryDataBlock(); inventoryReply.InventoryData[0].ItemID = item.inventoryID; inventoryReply.InventoryData[0].AssetID = item.assetID; inventoryReply.InventoryData[0].CreatorID = item.creatorsID; inventoryReply.InventoryData[0].BaseMask = item.inventoryBasePermissions; inventoryReply.InventoryData[0].CreationDate = (int)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds; inventoryReply.InventoryData[0].Description = Helpers.StringToField(item.inventoryDescription); inventoryReply.InventoryData[0].EveryoneMask = item.inventoryEveryOnePermissions; inventoryReply.InventoryData[0].Flags = 0; inventoryReply.InventoryData[0].FolderID = item.parentFolderID; inventoryReply.InventoryData[0].GroupID = new LLUUID("00000000-0000-0000-0000-000000000000"); inventoryReply.InventoryData[0].GroupMask = 0; inventoryReply.InventoryData[0].InvType = (sbyte)item.invType; inventoryReply.InventoryData[0].Name = Helpers.StringToField(item.inventoryName); inventoryReply.InventoryData[0].NextOwnerMask = item.inventoryNextPermissions; inventoryReply.InventoryData[0].OwnerID = item.avatarID; inventoryReply.InventoryData[0].OwnerMask = item.inventoryCurrentPermissions; inventoryReply.InventoryData[0].SalePrice = 0; inventoryReply.InventoryData[0].SaleType = 0; inventoryReply.InventoryData[0].Type = (sbyte)item.assetType; inventoryReply.InventoryData[0].CRC = Helpers.InventoryCRC(1000, 0, inventoryReply.InventoryData[0].InvType, inventoryReply.InventoryData[0].Type, inventoryReply.InventoryData[0].AssetID, inventoryReply.InventoryData[0].GroupID, 100, inventoryReply.InventoryData[0].OwnerID, inventoryReply.InventoryData[0].CreatorID, inventoryReply.InventoryData[0].ItemID, inventoryReply.InventoryData[0].FolderID, FULL_MASK_PERMISSIONS, 1, FULL_MASK_PERMISSIONS, FULL_MASK_PERMISSIONS, FULL_MASK_PERMISSIONS); OutPacket(inventoryReply, ThrottleOutPacketType.Asset); } /// IClientAPI.SendInventoryItemCreateUpdate(InventoryItemBase) public void SendInventoryItemCreateUpdate(InventoryItemBase Item) { Encoding enc = Encoding.ASCII; uint FULL_MASK_PERMISSIONS = (uint)PermissionMask.All; UpdateCreateInventoryItemPacket InventoryReply = (UpdateCreateInventoryItemPacket)PacketPool.Instance.GetPacket(PacketType.UpdateCreateInventoryItem); // TODO: don't create new blocks if recycling an old packet InventoryReply.AgentData.AgentID = AgentId; InventoryReply.AgentData.SimApproved = true; InventoryReply.InventoryData = new UpdateCreateInventoryItemPacket.InventoryDataBlock[1]; InventoryReply.InventoryData[0] = new UpdateCreateInventoryItemPacket.InventoryDataBlock(); InventoryReply.InventoryData[0].ItemID = Item.inventoryID; InventoryReply.InventoryData[0].AssetID = Item.assetID; InventoryReply.InventoryData[0].CreatorID = Item.creatorsID; InventoryReply.InventoryData[0].BaseMask = Item.inventoryBasePermissions; InventoryReply.InventoryData[0].CreationDate = 1000; InventoryReply.InventoryData[0].Description = Helpers.StringToField(Item.inventoryDescription); InventoryReply.InventoryData[0].EveryoneMask = Item.inventoryEveryOnePermissions; InventoryReply.InventoryData[0].Flags = 0; InventoryReply.InventoryData[0].FolderID = Item.parentFolderID; InventoryReply.InventoryData[0].GroupID = new LLUUID("00000000-0000-0000-0000-000000000000"); InventoryReply.InventoryData[0].GroupMask = 0; InventoryReply.InventoryData[0].InvType = (sbyte)Item.invType; InventoryReply.InventoryData[0].Name = Helpers.StringToField(Item.inventoryName); InventoryReply.InventoryData[0].NextOwnerMask = Item.inventoryNextPermissions; InventoryReply.InventoryData[0].OwnerID = Item.avatarID; InventoryReply.InventoryData[0].OwnerMask = Item.inventoryCurrentPermissions; InventoryReply.InventoryData[0].SalePrice = 100; InventoryReply.InventoryData[0].SaleType = 0; InventoryReply.InventoryData[0].Type = (sbyte)Item.assetType; InventoryReply.InventoryData[0].CRC = Helpers.InventoryCRC(1000, 0, InventoryReply.InventoryData[0].InvType, InventoryReply.InventoryData[0].Type, InventoryReply.InventoryData[0].AssetID, InventoryReply.InventoryData[0].GroupID, 100, InventoryReply.InventoryData[0].OwnerID, InventoryReply.InventoryData[0].CreatorID, InventoryReply.InventoryData[0].ItemID, InventoryReply.InventoryData[0].FolderID, FULL_MASK_PERMISSIONS, 1, FULL_MASK_PERMISSIONS, FULL_MASK_PERMISSIONS, FULL_MASK_PERMISSIONS); OutPacket(InventoryReply, ThrottleOutPacketType.Asset); } public void SendRemoveInventoryItem(LLUUID itemID) { RemoveInventoryItemPacket remove = (RemoveInventoryItemPacket)PacketPool.Instance.GetPacket(PacketType.RemoveInventoryItem); // TODO: don't create new blocks if recycling an old packet remove.AgentData.AgentID = AgentId; remove.AgentData.SessionID = m_sessionId; remove.InventoryData = new RemoveInventoryItemPacket.InventoryDataBlock[1]; remove.InventoryData[0] = new RemoveInventoryItemPacket.InventoryDataBlock(); remove.InventoryData[0].ItemID = itemID; OutPacket(remove, ThrottleOutPacketType.Asset); } public void SendTaskInventory(LLUUID taskID, short serial, byte[] fileName) { ReplyTaskInventoryPacket replytask = (ReplyTaskInventoryPacket)PacketPool.Instance.GetPacket(PacketType.ReplyTaskInventory); replytask.InventoryData.TaskID = taskID; replytask.InventoryData.Serial = serial; replytask.InventoryData.Filename = fileName; OutPacket(replytask, ThrottleOutPacketType.Asset); } public void SendXferPacket(ulong xferID, uint packet, byte[] data) { SendXferPacketPacket sendXfer = (SendXferPacketPacket)PacketPool.Instance.GetPacket(PacketType.SendXferPacket); sendXfer.XferID.ID = xferID; sendXfer.XferID.Packet = packet; sendXfer.DataPacket.Data = data; OutPacket(sendXfer, ThrottleOutPacketType.Task); } public void SendAvatarPickerReply(AvatarPickerReplyPacket replyPacket) { OutPacket(replyPacket, ThrottleOutPacketType.Task); } public void SendAgentDataUpdate(LLUUID agentid, LLUUID activegroupid, string firstname, string lastname, ulong grouppowers, string groupname,string grouptitle) { AgentDataUpdatePacket sendAgentDataUpdate = (AgentDataUpdatePacket)PacketPool.Instance.GetPacket(PacketType.AgentDataUpdate); sendAgentDataUpdate.AgentData.ActiveGroupID = activegroupid; sendAgentDataUpdate.AgentData.AgentID = agentid; sendAgentDataUpdate.AgentData.FirstName = Helpers.StringToField(firstname); sendAgentDataUpdate.AgentData.GroupName = Helpers.StringToField(groupname); sendAgentDataUpdate.AgentData.GroupPowers = grouppowers; sendAgentDataUpdate.AgentData.GroupTitle = Helpers.StringToField(grouptitle); sendAgentDataUpdate.AgentData.LastName = Helpers.StringToField(lastname); OutPacket(sendAgentDataUpdate,ThrottleOutPacketType.Task); } /// /// /// /// public void SendAlertMessage(string message) { AlertMessagePacket alertPack = (AlertMessagePacket)PacketPool.Instance.GetPacket(PacketType.AlertMessage); alertPack.AlertData.Message = Helpers.StringToField(message); OutPacket(alertPack, ThrottleOutPacketType.Task); } /// /// /// /// /// public void SendAgentAlertMessage(string message, bool modal) { AgentAlertMessagePacket alertPack = (AgentAlertMessagePacket)PacketPool.Instance.GetPacket(PacketType.AgentAlertMessage); alertPack.AgentData.AgentID = AgentId; alertPack.AlertData.Message = Helpers.StringToField(message); alertPack.AlertData.Modal = modal; OutPacket(alertPack, ThrottleOutPacketType.Task); } public void SendLoadURL(string objectname, LLUUID objectID, LLUUID ownerID, bool groupOwned, string message, string url) { LoadURLPacket loadURL = (LoadURLPacket)PacketPool.Instance.GetPacket(PacketType.LoadURL); loadURL.Data.ObjectName = Helpers.StringToField(objectname); loadURL.Data.ObjectID = objectID; loadURL.Data.OwnerID = ownerID; loadURL.Data.OwnerIsGroup = groupOwned; loadURL.Data.Message = Helpers.StringToField(message); loadURL.Data.URL = Helpers.StringToField(url); OutPacket(loadURL, ThrottleOutPacketType.Task); } public void SendDialog(string objectname, LLUUID objectID, LLUUID ownerID, string msg, LLUUID textureID, int ch, string[] buttonlabels) { ScriptDialogPacket dialog = (ScriptDialogPacket)PacketPool.Instance.GetPacket(PacketType.ScriptDialog); dialog.Data.ObjectID = objectID; dialog.Data.ObjectName = Helpers.StringToField(objectname); dialog.Data.FirstName = Helpers.StringToField(this.FirstName); dialog.Data.LastName = Helpers.StringToField(this.LastName); dialog.Data.Message = Helpers.StringToField(msg); dialog.Data.ImageID = textureID; dialog.Data.ChatChannel = ch; ScriptDialogPacket.ButtonsBlock[] buttons = new ScriptDialogPacket.ButtonsBlock[buttonlabels.Length]; for (int i = 0; i < buttonlabels.Length; i++) { buttons[i] = new ScriptDialogPacket.ButtonsBlock(); buttons[i].ButtonLabel = Helpers.StringToField(buttonlabels[i]); } dialog.Buttons = buttons; OutPacket(dialog, ThrottleOutPacketType.Task); } public void SendPreLoadSound(LLUUID objectID, LLUUID ownerID, LLUUID soundID) { PreloadSoundPacket preSound = (PreloadSoundPacket)PacketPool.Instance.GetPacket(PacketType.PreloadSound); // TODO: don't create new blocks if recycling an old packet preSound.DataBlock = new PreloadSoundPacket.DataBlockBlock[1]; preSound.DataBlock[0] = new PreloadSoundPacket.DataBlockBlock(); preSound.DataBlock[0].ObjectID = objectID; preSound.DataBlock[0].OwnerID = ownerID; preSound.DataBlock[0].SoundID = soundID; OutPacket(preSound, ThrottleOutPacketType.Task); } public void SendPlayAttachedSound(LLUUID soundID, LLUUID objectID, LLUUID ownerID, float gain, byte flags) { AttachedSoundPacket sound = (AttachedSoundPacket)PacketPool.Instance.GetPacket(PacketType.AttachedSound); sound.DataBlock.SoundID = soundID; sound.DataBlock.ObjectID = objectID; sound.DataBlock.OwnerID = ownerID; sound.DataBlock.Gain = gain; sound.DataBlock.Flags = flags; OutPacket(sound, ThrottleOutPacketType.Task); } public void SendTriggeredSound(LLUUID soundID, LLUUID ownerID, LLUUID objectID, LLUUID parentID, ulong handle, LLVector3 position, float gain) { SoundTriggerPacket sound = (SoundTriggerPacket)PacketPool.Instance.GetPacket(PacketType.SoundTrigger); sound.SoundData.SoundID = soundID; sound.SoundData.OwnerID = ownerID; sound.SoundData.ObjectID = objectID; sound.SoundData.ParentID = parentID; sound.SoundData.Handle = handle; sound.SoundData.Position = position; sound.SoundData.Gain = gain; OutPacket(sound, ThrottleOutPacketType.Task); } public void SendSunPos(LLVector3 sunPos, LLVector3 sunVel) { SimulatorViewerTimeMessagePacket viewertime = (SimulatorViewerTimeMessagePacket)PacketPool.Instance.GetPacket(PacketType.SimulatorViewerTimeMessage); viewertime.TimeInfo.SunDirection = sunPos; viewertime.TimeInfo.SunAngVelocity = sunVel; viewertime.TimeInfo.UsecSinceStart = (ulong)Util.UnixTimeSinceEpoch(); viewertime.Header.Reliable = false; OutPacket(viewertime, ThrottleOutPacketType.Task); } public void SendViewerTime(int phase) { Console.WriteLine("SunPhase: {0}", phase); SimulatorViewerTimeMessagePacket viewertime = (SimulatorViewerTimeMessagePacket)PacketPool.Instance.GetPacket(PacketType.SimulatorViewerTimeMessage); //viewertime.TimeInfo.SecPerDay = 86400; //viewertime.TimeInfo.SecPerYear = 31536000; viewertime.TimeInfo.SecPerDay = 1000; viewertime.TimeInfo.SecPerYear = 365000; viewertime.TimeInfo.SunPhase = 1; int sunPhase = (phase + 2) / 2; if ((sunPhase < 6) || (sunPhase > 36)) { viewertime.TimeInfo.SunDirection = new LLVector3(0f, 0.8f, -0.8f); Console.WriteLine("sending night"); } else { if (sunPhase < 12) { sunPhase = 12; } sunPhase = sunPhase - 12; float yValue = 0.1f * (sunPhase); Console.WriteLine("Computed SunPhase: {0}, yValue: {1}", sunPhase, yValue); if (yValue > 1.2f) { yValue = yValue - 1.2f; } yValue = Util.Clip(yValue, 0, 1); if (sunPhase < 14) { yValue = 1 - yValue; } if (sunPhase < 12) { yValue *= -1; } viewertime.TimeInfo.SunDirection = new LLVector3(0f, yValue, 0.3f); Console.WriteLine("sending sun update " + yValue); } viewertime.TimeInfo.SunAngVelocity = new LLVector3(0, 0.0f, 10.0f); viewertime.TimeInfo.UsecSinceStart = (ulong)Util.UnixTimeSinceEpoch(); viewertime.Header.Reliable = false; OutPacket(viewertime, ThrottleOutPacketType.Task); } public void SendAvatarProperties(LLUUID avatarID, string aboutText, string bornOn, string charterMember, string flAbout, uint flags, LLUUID flImageID, LLUUID imageID, string profileURL, LLUUID partnerID) { AvatarPropertiesReplyPacket avatarReply = (AvatarPropertiesReplyPacket)PacketPool.Instance.GetPacket(PacketType.AvatarPropertiesReply); avatarReply.AgentData.AgentID = AgentId; avatarReply.AgentData.AvatarID = avatarID; avatarReply.PropertiesData.AboutText = Helpers.StringToField(aboutText); avatarReply.PropertiesData.BornOn = Helpers.StringToField(bornOn); avatarReply.PropertiesData.CharterMember = Helpers.StringToField(charterMember); avatarReply.PropertiesData.FLAboutText = Helpers.StringToField(flAbout); avatarReply.PropertiesData.Flags = 0; avatarReply.PropertiesData.FLImageID = flImageID; avatarReply.PropertiesData.ImageID = imageID; avatarReply.PropertiesData.ProfileURL = Helpers.StringToField(profileURL); avatarReply.PropertiesData.PartnerID = partnerID; OutPacket(avatarReply, ThrottleOutPacketType.Task); } #endregion #region Appearance/ Wearables Methods /// /// /// /// public void SendWearables(AvatarWearable[] wearables, int serial) { AgentWearablesUpdatePacket aw = (AgentWearablesUpdatePacket)PacketPool.Instance.GetPacket(PacketType.AgentWearablesUpdate); aw.AgentData.AgentID = AgentId; aw.AgentData.SerialNum = (uint)serial; aw.AgentData.SessionID = m_sessionId; // TODO: don't create new blocks if recycling an old packet aw.WearableData = new AgentWearablesUpdatePacket.WearableDataBlock[13]; AgentWearablesUpdatePacket.WearableDataBlock awb; for (int i = 0; i < wearables.Length; i++) { awb = new AgentWearablesUpdatePacket.WearableDataBlock(); awb.WearableType = (byte)i; awb.AssetID = wearables[i].AssetID; awb.ItemID = wearables[i].ItemID; aw.WearableData[i] = awb; } OutPacket(aw, ThrottleOutPacketType.Task); } /// /// /// /// /// /// public void SendAppearance(LLUUID agentID, byte[] visualParams, byte[] textureEntry) { AvatarAppearancePacket avp = (AvatarAppearancePacket)PacketPool.Instance.GetPacket(PacketType.AvatarAppearance); // TODO: don't create new blocks if recycling an old packet avp.VisualParam = new AvatarAppearancePacket.VisualParamBlock[218]; avp.ObjectData.TextureEntry = textureEntry; AvatarAppearancePacket.VisualParamBlock avblock = null; for (int i = 0; i < visualParams.Length; i++) { avblock = new AvatarAppearancePacket.VisualParamBlock(); avblock.ParamValue = visualParams[i]; avp.VisualParam[i] = avblock; } avp.Sender.IsTrial = false; avp.Sender.ID = agentID; OutPacket(avp, ThrottleOutPacketType.Task); } public void SendAnimations(LLUUID[] animations, int[] seqs, LLUUID sourceAgentId) { AvatarAnimationPacket ani = (AvatarAnimationPacket)PacketPool.Instance.GetPacket(PacketType.AvatarAnimation); // TODO: don't create new blocks if recycling an old packet ani.AnimationSourceList = new AvatarAnimationPacket.AnimationSourceListBlock[1]; ani.AnimationSourceList[0] = new AvatarAnimationPacket.AnimationSourceListBlock(); ani.AnimationSourceList[0].ObjectID = sourceAgentId; ani.Sender = new AvatarAnimationPacket.SenderBlock(); ani.Sender.ID = sourceAgentId; ani.AnimationList = new AvatarAnimationPacket.AnimationListBlock[animations.Length]; for (int i = 0; i < animations.Length; ++i) { ani.AnimationList[i] = new AvatarAnimationPacket.AnimationListBlock(); ani.AnimationList[i].AnimID = animations[i]; ani.AnimationList[i].AnimSequenceID = seqs[i]; } ani.Header.Reliable = false; OutPacket(ani, ThrottleOutPacketType.Task); } #endregion #region Avatar Packet/data sending Methods /// /// send a objectupdate packet with information about the clients avatar /// /// /// /// /// /// /// public void SendAvatarData(ulong regionHandle, string firstName, string lastName, LLUUID avatarID, uint avatarLocalID, LLVector3 Pos, byte[] textureEntry, uint parentID) { ObjectUpdatePacket objupdate = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate); // TODO: don't create new blocks if recycling an old packet objupdate.RegionData.RegionHandle = regionHandle; objupdate.RegionData.TimeDilation = ushort.MaxValue; objupdate.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1]; objupdate.ObjectData[0] = CreateDefaultAvatarPacket(textureEntry); //give this avatar object a local id and assign the user a name objupdate.ObjectData[0].ID = avatarLocalID; objupdate.ObjectData[0].FullID = avatarID; objupdate.ObjectData[0].ParentID = parentID; objupdate.ObjectData[0].NameValue = Helpers.StringToField("FirstName STRING RW SV " + firstName + "\nLastName STRING RW SV " + lastName); LLVector3 pos2 = new LLVector3((float)Pos.X, (float)Pos.Y, (float)Pos.Z); byte[] pb = pos2.GetBytes(); Array.Copy(pb, 0, objupdate.ObjectData[0].ObjectData, 16, pb.Length); OutPacket(objupdate, ThrottleOutPacketType.Task); } /// /// /// /// /// /// /// /// public void SendAvatarTerseUpdate(ulong regionHandle, ushort timeDilation, uint localID, LLVector3 position, LLVector3 velocity, LLQuaternion rotation) { ImprovedTerseObjectUpdatePacket.ObjectDataBlock terseBlock = CreateAvatarImprovedBlock(localID, position, velocity, rotation); ImprovedTerseObjectUpdatePacket terse = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate); // TODO: don't create new blocks if recycling an old packet terse.RegionData.RegionHandle = regionHandle; terse.RegionData.TimeDilation = timeDilation; terse.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1]; terse.ObjectData[0] = terseBlock; terse.Header.Reliable = false; OutPacket(terse, ThrottleOutPacketType.Task); } public void SendCoarseLocationUpdate(List CoarseLocations) { CoarseLocationUpdatePacket loc = (CoarseLocationUpdatePacket)PacketPool.Instance.GetPacket(PacketType.CoarseLocationUpdate); // TODO: don't create new blocks if recycling an old packet int total = CoarseLocations.Count; CoarseLocationUpdatePacket.IndexBlock ib = new CoarseLocationUpdatePacket.IndexBlock(); loc.Location = new CoarseLocationUpdatePacket.LocationBlock[total]; for (int i = 0; i < total; i++) { CoarseLocationUpdatePacket.LocationBlock lb = new CoarseLocationUpdatePacket.LocationBlock(); lb.X = (byte)CoarseLocations[i].X; lb.Y = (byte)CoarseLocations[i].Y; lb.Z = (byte)(CoarseLocations[i].Z / 4); loc.Location[i] = lb; } ib.You = -1; ib.Prey = -1; loc.Index = ib; loc.Header.Reliable = false; OutPacket(loc, ThrottleOutPacketType.Task); } #endregion #region Primitive Packet/data Sending Methods /// /// /// /// /// /// public void AttachObject(uint localID, LLQuaternion rotation, byte attachPoint) { ObjectAttachPacket attach = (ObjectAttachPacket)PacketPool.Instance.GetPacket(PacketType.ObjectAttach); System.Console.WriteLine("Attach object!"); // TODO: don't create new blocks if recycling an old packet attach.AgentData.AgentID = AgentId; attach.AgentData.SessionID = m_sessionId; attach.AgentData.AttachmentPoint = attachPoint; attach.ObjectData = new ObjectAttachPacket.ObjectDataBlock[1]; attach.ObjectData[0] = new ObjectAttachPacket.ObjectDataBlock(); attach.ObjectData[0].ObjectLocalID = localID; attach.ObjectData[0].Rotation = rotation; OutPacket(attach, ThrottleOutPacketType.Task); } public void SendPrimitiveToClient( ulong regionHandle, ushort timeDilation, uint localID, PrimitiveBaseShape primShape, LLVector3 pos, uint flags, LLUUID objectID, LLUUID ownerID, string text, byte[] color, uint parentID, byte[] particleSystem, LLQuaternion rotation, byte clickAction) { byte[] textureanim = new byte[0]; SendPrimitiveToClient(regionHandle, timeDilation, localID, primShape, pos, flags, objectID, ownerID, text, color, parentID, particleSystem, rotation, clickAction, textureanim); } public void SendPrimitiveToClient( ulong regionHandle, ushort timeDilation, uint localID, PrimitiveBaseShape primShape, LLVector3 pos, uint flags, LLUUID objectID, LLUUID ownerID, string text, byte[] color, uint parentID, byte[] particleSystem, LLQuaternion rotation, byte clickAction, byte[] textureanim) { ObjectUpdatePacket outPacket = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate); // TODO: don't create new blocks if recycling an old packet outPacket.RegionData.RegionHandle = regionHandle; outPacket.RegionData.TimeDilation = timeDilation; outPacket.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1]; outPacket.ObjectData[0] = CreatePrimUpdateBlock(primShape, flags); outPacket.ObjectData[0].ID = localID; outPacket.ObjectData[0].FullID = objectID; outPacket.ObjectData[0].OwnerID = ownerID; outPacket.ObjectData[0].Text = Helpers.StringToField(text); outPacket.ObjectData[0].TextColor[0] = color[0]; outPacket.ObjectData[0].TextColor[1] = color[1]; outPacket.ObjectData[0].TextColor[2] = color[2]; outPacket.ObjectData[0].TextColor[3] = color[3]; outPacket.ObjectData[0].ParentID = parentID; outPacket.ObjectData[0].PSBlock = particleSystem; outPacket.ObjectData[0].ClickAction = clickAction; //outPacket.ObjectData[0].Flags = 0; // Sound Radius outPacket.ObjectData[0].Radius = 20; byte[] pb = pos.GetBytes(); Array.Copy(pb, 0, outPacket.ObjectData[0].ObjectData, 0, pb.Length); byte[] rot = rotation.GetBytes(); Array.Copy(rot, 0, outPacket.ObjectData[0].ObjectData, 36, rot.Length); if (textureanim.Length > 0) { outPacket.ObjectData[0].TextureAnim = textureanim; } OutPacket(outPacket, ThrottleOutPacketType.Task); } /// /// /// /// /// /// /// /// public void SendPrimTerseUpdate(ulong regionHandle, ushort timeDilation, uint localID, LLVector3 position, LLQuaternion rotation) { LLVector3 velocity = new LLVector3(0f, 0f, 0f); LLVector3 rotationalvelocity = new LLVector3(0f, 0f, 0f); ImprovedTerseObjectUpdatePacket terse = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate); // TODO: don't create new blocks if recycling an old packet terse.RegionData.RegionHandle = regionHandle; terse.RegionData.TimeDilation = timeDilation; terse.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1]; terse.ObjectData[0] = CreatePrimImprovedBlock(localID, position, rotation, velocity, rotationalvelocity); terse.Header.Reliable = false; OutPacket(terse, ThrottleOutPacketType.Task); } public void SendPrimTerseUpdate(ulong regionHandle, ushort timeDilation, uint localID, LLVector3 position, LLQuaternion rotation, LLVector3 velocity, LLVector3 rotationalvelocity) { ImprovedTerseObjectUpdatePacket terse = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate); // TODO: don't create new blocks if recycling an old packet terse.RegionData.RegionHandle = regionHandle; terse.RegionData.TimeDilation = timeDilation; terse.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1]; terse.ObjectData[0] = CreatePrimImprovedBlock(localID, position, rotation, velocity, rotationalvelocity); terse.Header.Reliable = false; OutPacket(terse, ThrottleOutPacketType.Task); } #endregion #region Helper Methods protected ImprovedTerseObjectUpdatePacket.ObjectDataBlock CreateAvatarImprovedBlock(uint localID, LLVector3 pos, LLVector3 velocity, LLQuaternion rotation) { byte[] bytes = new byte[60]; int i = 0; ImprovedTerseObjectUpdatePacket.ObjectDataBlock dat = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock(); dat.TextureEntry = new byte[0]; // AvatarTemplate.TextureEntry; uint ID = localID; bytes[i++] = (byte)(ID % 256); bytes[i++] = (byte)((ID >> 8) % 256); bytes[i++] = (byte)((ID >> 16) % 256); bytes[i++] = (byte)((ID >> 24) % 256); bytes[i++] = 0; bytes[i++] = 1; i += 14; bytes[i++] = 128; bytes[i++] = 63; byte[] pb = pos.GetBytes(); Array.Copy(pb, 0, bytes, i, pb.Length); i += 12; ushort InternVelocityX; ushort InternVelocityY; ushort InternVelocityZ; Vector3 internDirec = new Vector3(0, 0, 0); internDirec = new Vector3(velocity.X, velocity.Y, velocity.Z); internDirec = internDirec / 128.0f; internDirec.x += 1; internDirec.y += 1; internDirec.z += 1; InternVelocityX = (ushort)(32768 * internDirec.x); InternVelocityY = (ushort)(32768 * internDirec.y); InternVelocityZ = (ushort)(32768 * internDirec.z); ushort ac = 32767; bytes[i++] = (byte)(InternVelocityX % 256); bytes[i++] = (byte)((InternVelocityX >> 8) % 256); bytes[i++] = (byte)(InternVelocityY % 256); bytes[i++] = (byte)((InternVelocityY >> 8) % 256); bytes[i++] = (byte)(InternVelocityZ % 256); bytes[i++] = (byte)((InternVelocityZ >> 8) % 256); //accel bytes[i++] = (byte)(ac % 256); bytes[i++] = (byte)((ac >> 8) % 256); bytes[i++] = (byte)(ac % 256); bytes[i++] = (byte)((ac >> 8) % 256); bytes[i++] = (byte)(ac % 256); bytes[i++] = (byte)((ac >> 8) % 256); //rotation ushort rw, rx, ry, rz; rw = (ushort)(32768 * (rotation.W + 1)); rx = (ushort)(32768 * (rotation.X + 1)); ry = (ushort)(32768 * (rotation.Y + 1)); rz = (ushort)(32768 * (rotation.Z + 1)); //rot bytes[i++] = (byte)(rx % 256); bytes[i++] = (byte)((rx >> 8) % 256); bytes[i++] = (byte)(ry % 256); bytes[i++] = (byte)((ry >> 8) % 256); bytes[i++] = (byte)(rz % 256); bytes[i++] = (byte)((rz >> 8) % 256); bytes[i++] = (byte)(rw % 256); bytes[i++] = (byte)((rw >> 8) % 256); //rotation vel bytes[i++] = (byte)(ac % 256); bytes[i++] = (byte)((ac >> 8) % 256); bytes[i++] = (byte)(ac % 256); bytes[i++] = (byte)((ac >> 8) % 256); bytes[i++] = (byte)(ac % 256); bytes[i++] = (byte)((ac >> 8) % 256); dat.Data = bytes; return (dat); } /// /// /// /// /// /// /// protected ImprovedTerseObjectUpdatePacket.ObjectDataBlock CreatePrimImprovedBlock(uint localID, LLVector3 position, LLQuaternion rotation, LLVector3 velocity, LLVector3 rotationalvelocity) { uint ID = localID; byte[] bytes = new byte[60]; int i = 0; ImprovedTerseObjectUpdatePacket.ObjectDataBlock dat = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock(); dat.TextureEntry = new byte[0]; bytes[i++] = (byte)(ID % 256); bytes[i++] = (byte)((ID >> 8) % 256); bytes[i++] = (byte)((ID >> 16) % 256); bytes[i++] = (byte)((ID >> 24) % 256); bytes[i++] = 0; bytes[i++] = 0; byte[] pb = position.GetBytes(); Array.Copy(pb, 0, bytes, i, pb.Length); i += 12; ushort ac = 32767; ushort velx, vely, velz; Vector3 vel = new Vector3(velocity.X, velocity.Y, velocity.Z); vel = vel / 128.0f; vel.x += 1; vel.y += 1; vel.z += 1; //vel velx = (ushort)(32768 * (vel.x)); vely = (ushort)(32768 * (vel.y)); velz = (ushort)(32768 * (vel.z)); bytes[i++] = (byte)(velx % 256); bytes[i++] = (byte)((velx >> 8) % 256); bytes[i++] = (byte)(vely % 256); bytes[i++] = (byte)((vely >> 8) % 256); bytes[i++] = (byte)(velz % 256); bytes[i++] = (byte)((velz >> 8) % 256); //accel bytes[i++] = (byte)(ac % 256); bytes[i++] = (byte)((ac >> 8) % 256); bytes[i++] = (byte)(ac % 256); bytes[i++] = (byte)((ac >> 8) % 256); bytes[i++] = (byte)(ac % 256); bytes[i++] = (byte)((ac >> 8) % 256); ushort rw, rx, ry, rz; rw = (ushort)(32768 * (rotation.W + 1)); rx = (ushort)(32768 * (rotation.X + 1)); ry = (ushort)(32768 * (rotation.Y + 1)); rz = (ushort)(32768 * (rotation.Z + 1)); //rot bytes[i++] = (byte)(rx % 256); bytes[i++] = (byte)((rx >> 8) % 256); bytes[i++] = (byte)(ry % 256); bytes[i++] = (byte)((ry >> 8) % 256); bytes[i++] = (byte)(rz % 256); bytes[i++] = (byte)((rz >> 8) % 256); bytes[i++] = (byte)(rw % 256); bytes[i++] = (byte)((rw >> 8) % 256); //rotation vel ushort rvelx, rvely, rvelz; Vector3 rvel = new Vector3(rotationalvelocity.X, rotationalvelocity.Y, rotationalvelocity.Z); rvel = rvel / 128.0f; rvel.x += 1; rvel.y += 1; rvel.z += 1; //vel rvelx = (ushort)(32768 * (rvel.x)); rvely = (ushort)(32768 * (rvel.y)); rvelz = (ushort)(32768 * (rvel.z)); bytes[i++] = (byte)(rvelx % 256); bytes[i++] = (byte)((rvelx >> 8) % 256); bytes[i++] = (byte)(rvely % 256); bytes[i++] = (byte)((rvely >> 8) % 256); bytes[i++] = (byte)(rvelz % 256); bytes[i++] = (byte)((rvelz >> 8) % 256); dat.Data = bytes; return dat; } /// /// Create the ObjectDataBlock for a ObjectUpdatePacket (for a Primitive) /// /// /// protected ObjectUpdatePacket.ObjectDataBlock CreatePrimUpdateBlock(PrimitiveBaseShape primShape, uint flags) { ObjectUpdatePacket.ObjectDataBlock objupdate = new ObjectUpdatePacket.ObjectDataBlock(); SetDefaultPrimPacketValues(objupdate); objupdate.UpdateFlags = flags; SetPrimPacketShapeData(objupdate, primShape); return objupdate; } protected void SetPrimPacketShapeData(ObjectUpdatePacket.ObjectDataBlock objectData, PrimitiveBaseShape primData) { objectData.TextureEntry = primData.TextureEntry; objectData.PCode = primData.PCode; objectData.State = primData.State; objectData.PathBegin = primData.PathBegin; objectData.PathEnd = primData.PathEnd; objectData.PathScaleX = primData.PathScaleX; objectData.PathScaleY = primData.PathScaleY; objectData.PathShearX = primData.PathShearX; objectData.PathShearY = primData.PathShearY; objectData.PathSkew = primData.PathSkew; objectData.ProfileBegin = primData.ProfileBegin; objectData.ProfileEnd = primData.ProfileEnd; objectData.Scale = primData.Scale; objectData.PathCurve = primData.PathCurve; objectData.ProfileCurve = primData.ProfileCurve; objectData.ProfileHollow = primData.ProfileHollow; objectData.PathRadiusOffset = primData.PathRadiusOffset; objectData.PathRevolutions = primData.PathRevolutions; objectData.PathTaperX = primData.PathTaperX; objectData.PathTaperY = primData.PathTaperY; objectData.PathTwist = primData.PathTwist; objectData.PathTwistBegin = primData.PathTwistBegin; objectData.ExtraParams = primData.ExtraParams; } /// /// Set some default values in a ObjectUpdatePacket /// /// protected void SetDefaultPrimPacketValues(ObjectUpdatePacket.ObjectDataBlock objdata) { objdata.PSBlock = new byte[0]; objdata.ExtraParams = new byte[1]; objdata.MediaURL = new byte[0]; objdata.NameValue = new byte[0]; objdata.Text = new byte[0]; objdata.TextColor = new byte[4]; objdata.JointAxisOrAnchor = new LLVector3(0, 0, 0); objdata.JointPivot = new LLVector3(0, 0, 0); objdata.Material = 3; objdata.TextureAnim = new byte[0]; objdata.Sound = LLUUID.Zero; objdata.State = 0; objdata.Data = new byte[0]; objdata.ObjectData = new byte[60]; objdata.ObjectData[46] = 128; objdata.ObjectData[47] = 63; } /// /// /// /// public ObjectUpdatePacket.ObjectDataBlock CreateDefaultAvatarPacket(byte[] textureEntry) { ObjectUpdatePacket.ObjectDataBlock objdata = new ObjectUpdatePacket.ObjectDataBlock(); // new libsecondlife.Packets.ObjectUpdatePacket.ObjectDataBlock(data1, ref i); SetDefaultAvatarPacketValues(ref objdata); objdata.UpdateFlags = 61 + (9 << 8) + (130 << 16) + (16 << 24); objdata.PathCurve = 16; objdata.ProfileCurve = 1; objdata.PathScaleX = 100; objdata.PathScaleY = 100; objdata.ParentID = 0; objdata.OwnerID = LLUUID.Zero; objdata.Scale = new LLVector3(1, 1, 1); objdata.PCode = 47; if (textureEntry != null) { objdata.TextureEntry = textureEntry; } Encoding enc = Encoding.ASCII; LLVector3 pos = new LLVector3(objdata.ObjectData, 16); pos.X = 100f; objdata.ID = 8880000; objdata.NameValue = enc.GetBytes("FirstName STRING RW SV Test \nLastName STRING RW SV User \0"); //LLVector3 pos2 = new LLVector3(100f, 100f, 23f); //objdata.FullID=user.AgentId; byte[] pb = pos.GetBytes(); Array.Copy(pb, 0, objdata.ObjectData, 16, pb.Length); return objdata; } /// /// /// /// protected void SetDefaultAvatarPacketValues(ref ObjectUpdatePacket.ObjectDataBlock objdata) { objdata.PSBlock = new byte[0]; objdata.ExtraParams = new byte[1]; objdata.MediaURL = new byte[0]; objdata.NameValue = new byte[0]; objdata.Text = new byte[0]; objdata.TextColor = new byte[4]; objdata.JointAxisOrAnchor = new LLVector3(0, 0, 0); objdata.JointPivot = new LLVector3(0, 0, 0); objdata.Material = 4; objdata.TextureAnim = new byte[0]; objdata.Sound = LLUUID.Zero; LLObject.TextureEntry ntex = new LLObject.TextureEntry(new LLUUID("00000000-0000-0000-5005-000000000005")); objdata.TextureEntry = ntex.ToBytes(); objdata.State = 0; objdata.Data = new byte[0]; objdata.ObjectData = new byte[76]; objdata.ObjectData[15] = 128; objdata.ObjectData[16] = 63; objdata.ObjectData[56] = 128; objdata.ObjectData[61] = 102; objdata.ObjectData[62] = 40; objdata.ObjectData[63] = 61; objdata.ObjectData[64] = 189; } public void SendNameReply(LLUUID profileId, string firstname, string lastname) { UUIDNameReplyPacket packet = (UUIDNameReplyPacket)PacketPool.Instance.GetPacket(PacketType.UUIDNameReply); // TODO: don't create new blocks if recycling an old packet packet.UUIDNameBlock = new UUIDNameReplyPacket.UUIDNameBlockBlock[1]; packet.UUIDNameBlock[0] = new UUIDNameReplyPacket.UUIDNameBlockBlock(); packet.UUIDNameBlock[0].ID = profileId; packet.UUIDNameBlock[0].FirstName = Helpers.StringToField(firstname); packet.UUIDNameBlock[0].LastName = Helpers.StringToField(lastname); OutPacket(packet, ThrottleOutPacketType.Task); } #endregion protected virtual void RegisterLocalPacketHandlers() { AddLocalPacketHandler(PacketType.LogoutRequest, Logout); AddLocalPacketHandler(PacketType.ViewerEffect, HandleViewerEffect); AddLocalPacketHandler(PacketType.AgentCachedTexture, AgentTextureCached); AddLocalPacketHandler(PacketType.MultipleObjectUpdate, MultipleObjUpdate); AddLocalPacketHandler(PacketType.MoneyTransferRequest, HandleMoneyTransferRequest); } private bool HandleMoneyTransferRequest(IClientAPI sender, Packet Pack) { MoneyTransferRequestPacket money = (MoneyTransferRequestPacket)Pack; // validate the agent owns the agentID and sessionID if (money.MoneyData.SourceID == sender.AgentId && money.AgentData.AgentID == sender.AgentId && money.AgentData.SessionID == sender.SessionId) { if (OnMoneyTransferRequest != null) { OnMoneyTransferRequest(money.MoneyData.SourceID, money.MoneyData.DestID, money.MoneyData.Amount, money.MoneyData.TransactionType, Util.FieldToString(money.MoneyData.Description)); } return true; } else { return false; } } private bool HandleViewerEffect(IClientAPI sender, Packet Pack) { ViewerEffectPacket viewer = (ViewerEffectPacket)Pack; if (OnViewerEffect != null) { OnViewerEffect(sender, viewer.Effect); } return true; } protected virtual bool Logout(IClientAPI client, Packet packet) { m_log.Info("[CLIENT]: Got a logout request"); if (OnLogout != null) { OnLogout(client); } return true; } protected bool AgentTextureCached(IClientAPI simclient, Packet packet) { //System.Console.WriteLine("texture cached: " + packet.ToString()); AgentCachedTexturePacket chechedtex = (AgentCachedTexturePacket)packet; AgentCachedTextureResponsePacket cachedresp = (AgentCachedTextureResponsePacket)PacketPool.Instance.GetPacket(PacketType.AgentCachedTextureResponse); // TODO: don't create new blocks if recycling an old packet cachedresp.AgentData.AgentID = AgentId; cachedresp.AgentData.SessionID = m_sessionId; cachedresp.AgentData.SerialNum = m_cachedTextureSerial; m_cachedTextureSerial++; cachedresp.WearableData = new AgentCachedTextureResponsePacket.WearableDataBlock[chechedtex.WearableData.Length]; for (int i = 0; i < chechedtex.WearableData.Length; i++) { cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock(); cachedresp.WearableData[i].TextureIndex = chechedtex.WearableData[i].TextureIndex; cachedresp.WearableData[i].TextureID = LLUUID.Zero; cachedresp.WearableData[i].HostName = new byte[0]; } OutPacket(cachedresp, ThrottleOutPacketType.Texture); return true; } protected bool MultipleObjUpdate(IClientAPI simClient, Packet packet) { MultipleObjectUpdatePacket multipleupdate = (MultipleObjectUpdatePacket)packet; // System.Console.WriteLine("new multi update packet " + multipleupdate.ToString()); Scene tScene = (Scene)m_scene; for (int i = 0; i < multipleupdate.ObjectData.Length; i++) { MultipleObjectUpdatePacket.ObjectDataBlock block = multipleupdate.ObjectData[i]; // Can't act on Null Data if (block.Data != null) { uint localId = block.ObjectLocalID; SceneObjectPart part = tScene.GetSceneObjectPart(localId); if (part == null) { // It's a ghost! tell the client to delete it from view. simClient.SendKillObject(Scene.RegionInfo.RegionHandle, localId); } else { LLUUID partId = part.UUID; switch (block.Type) { case 1: if (OnUpdatePrimSinglePosition != null) { LLVector3 pos = new LLVector3(block.Data, 0); // System.Console.WriteLine("new movement position is " + pos.X + " , " + pos.Y + " , " + pos.Z); OnUpdatePrimSinglePosition(localId, pos, this); } break; case 2: if (OnUpdatePrimSingleRotation != null) { LLQuaternion rot = new LLQuaternion(block.Data, 0, true); //System.Console.WriteLine("new tab rotation is " + rot.X + " , " + rot.Y + " , " + rot.Z + " , " + rot.W); OnUpdatePrimSingleRotation(localId, rot, this); } break; case 3: if (OnUpdatePrimSingleRotation != null) { LLQuaternion rot = new LLQuaternion(block.Data, 12, true); //System.Console.WriteLine("new mouse rotation is " + rot.X + " , " + rot.Y + " , " + rot.Z + " , " + rot.W); OnUpdatePrimSingleRotation(localId, rot, this); } break; case 5: if (OnUpdatePrimScale != null) { LLVector3 scale = new LLVector3(block.Data, 12); // Console.WriteLine("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z); OnUpdatePrimScale(localId, scale, this); } break; case 9: if (OnUpdatePrimGroupPosition != null) { LLVector3 pos = new LLVector3(block.Data, 0); OnUpdatePrimGroupPosition(localId, pos, this); } break; case 10: if (OnUpdatePrimGroupRotation != null) { LLQuaternion rot = new LLQuaternion(block.Data, 0, true); // Console.WriteLine("new rotation is " + rot.X + " , " + rot.Y + " , " + rot.Z + " , " + rot.W); OnUpdatePrimGroupRotation(localId, rot, this); } break; case 11: if (OnUpdatePrimGroupMouseRotation != null) { LLVector3 pos = new LLVector3(block.Data, 0); LLQuaternion rot = new LLQuaternion(block.Data, 12, true); //Console.WriteLine("new rotation position is " + pos.X + " , " + pos.Y + " , " + pos.Z); // Console.WriteLine("new rotation is " + rot.X + " , " + rot.Y + " , " + rot.Z + " , " + rot.W); OnUpdatePrimGroupMouseRotation(localId, pos, rot, this); } break; case 13: if (OnUpdatePrimScale != null) { LLVector3 scale = new LLVector3(block.Data, 12); //Console.WriteLine("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z); OnUpdatePrimScale(localId, scale, this); // Change the position based on scale (for bug number 246) LLVector3 pos = new LLVector3(block.Data, 0); // System.Console.WriteLine("new movement position is " + pos.X + " , " + pos.Y + " , " + pos.Z); OnUpdatePrimSinglePosition(localId, pos, this); } break; case 29: if (OnUpdatePrimScale != null) { LLVector3 scale = new LLVector3(block.Data, 12); // Console.WriteLine("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z ); OnUpdatePrimScale(localId, scale, this); LLVector3 pos = new LLVector3(block.Data, 0); OnUpdatePrimSinglePosition(localId, pos, this); } break; case 21: if (OnUpdatePrimScale != null) { LLVector3 scale = new LLVector3(block.Data, 12); // Console.WriteLine("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z); OnUpdatePrimScale(localId, scale, this); } break; } } } } return true; } public void RequestMapLayer() { //should be getting the map layer from the grid server //send a layer covering the 800,800 - 1200,1200 area (should be covering the requested area) MapLayerReplyPacket mapReply = (MapLayerReplyPacket)PacketPool.Instance.GetPacket(PacketType.MapLayerReply); // TODO: don't create new blocks if recycling an old packet mapReply.AgentData.AgentID = AgentId; mapReply.AgentData.Flags = 0; mapReply.LayerData = new MapLayerReplyPacket.LayerDataBlock[1]; mapReply.LayerData[0] = new MapLayerReplyPacket.LayerDataBlock(); mapReply.LayerData[0].Bottom = 0; mapReply.LayerData[0].Left = 0; mapReply.LayerData[0].Top = 30000; mapReply.LayerData[0].Right = 30000; mapReply.LayerData[0].ImageID = new LLUUID("00000000-0000-0000-9999-000000000006"); OutPacket(mapReply, ThrottleOutPacketType.Land); } public void RequestMapBlocks(int minX, int minY, int maxX, int maxY) { /* IList simMapProfiles = m_gridServer.RequestMapBlocks(minX, minY, maxX, maxY); MapBlockReplyPacket mbReply = new MapBlockReplyPacket(); mbReply.AgentData.AgentId = this.AgentId; int len; if (simMapProfiles == null) len = 0; else len = simMapProfiles.Count; mbReply.Data = new MapBlockReplyPacket.DataBlock[len]; int iii; for (iii = 0; iii < len; iii++) { Hashtable mp = (Hashtable)simMapProfiles[iii]; mbReply.Data[iii] = new MapBlockReplyPacket.DataBlock(); mbReply.Data[iii].Name = System.Text.Encoding.UTF8.GetBytes((string)mp["name"]); mbReply.Data[iii].Access = System.Convert.ToByte(mp["access"]); mbReply.Data[iii].Agents = System.Convert.ToByte(mp["agents"]); mbReply.Data[iii].MapImageID = new LLUUID((string)mp["map-image-id"]); mbReply.Data[iii].RegionFlags = System.Convert.ToUInt32(mp["region-flags"]); mbReply.Data[iii].WaterHeight = System.Convert.ToByte(mp["water-height"]); mbReply.Data[iii].X = System.Convert.ToUInt16(mp["x"]); mbReply.Data[iii].Y = System.Convert.ToUInt16(mp["y"]); } this.OutPacket(mbReply, ThrottleOutPacketType.Land); */ } public byte[] GetThrottlesPacked(float multiplier) { return m_packetQueue.GetThrottlesPacked(multiplier); } public void SetChildAgentThrottle(byte[] throttles) { m_packetQueue.SetThrottleFromClient(throttles); } // Previously ClientView.m_packetQueue // A thread safe sequence number allocator. protected uint NextSeqNum() { // Set the sequence number uint seq = 1; lock (m_sequenceLock) { if (m_sequence >= MAX_SEQUENCE) { m_sequence = 1; } else { m_sequence++; } seq = m_sequence; } return seq; } protected void AddAck(Packet Pack) { lock (m_needAck) { if (!m_needAck.ContainsKey(Pack.Header.Sequence)) { try { m_needAck.Add(Pack.Header.Sequence, Pack); m_unAckedBytes += Pack.ToBytes().Length; } catch (Exception) // HACKY { // Ignore // Seems to throw a exception here occasionally // of 'duplicate key' despite being locked. // !?!?!? } } else { // Client.Log("Attempted to add a duplicate sequence number (" + // packet.Header.m_sequence + ") to the m_needAck dictionary for packet type " + // packet.Type.ToString(), Helpers.LogLevel.Warning); } } } protected virtual void SetPendingAcks(ref Packet Pack) { // Append any ACKs that need to be sent out to this packet lock (m_pendingAcks) { // TODO: If we are over MAX_APPENDED_ACKS we should drain off some of these if (m_pendingAcks.Count > 0 && m_pendingAcks.Count < MAX_APPENDED_ACKS) { Pack.Header.AckList = new uint[m_pendingAcks.Count]; int i = 0; foreach (uint ack in m_pendingAcks.Values) { Pack.Header.AckList[i] = ack; i++; } m_pendingAcks.Clear(); Pack.Header.AppendedAcks = true; } } } protected virtual void ProcessOutPacket(Packet Pack) { // Keep track of when this packet was sent out Pack.TickCount = System.Environment.TickCount; if (!Pack.Header.Resent) { Pack.Header.Sequence = NextSeqNum(); if (Pack.Header.Reliable) //DIRTY HACK { AddAck(Pack); // this adds the need to ack this packet later if (Pack.Type != PacketType.PacketAck && Pack.Type != PacketType.LogoutRequest) { SetPendingAcks(ref Pack); } } } // Actually make the byte array and send it try { byte[] sendbuffer = Pack.ToBytes(); PacketPool.Instance.ReturnPacket(Pack); if (Pack.Header.Zerocoded) { int packetsize = Helpers.ZeroEncode(sendbuffer, sendbuffer.Length, ZeroOutBuffer); m_networkServer.SendPacketTo(ZeroOutBuffer, packetsize, SocketFlags.None, m_circuitCode); } else { m_networkServer.SendPacketTo(sendbuffer, sendbuffer.Length, SocketFlags.None, m_circuitCode); } } catch (Exception e) { m_log.Warn("[client]: " + "ClientView.m_packetQueue.cs:ProcessOutPacket() - WARNING: Socket exception occurred on connection " + m_userEndPoint.ToString() + " - killing thread"); m_log.Error(e.ToString()); Close(true); } } public virtual void InPacket(Packet NewPack) { // Handle appended ACKs if (NewPack != null) { if (NewPack.Header.AppendedAcks) { lock (m_needAck) { foreach (uint ackedPacketId in NewPack.Header.AckList) { Packet ackedPacket; if (m_needAck.TryGetValue(ackedPacketId, out ackedPacket)) { m_unAckedBytes -= ackedPacket.ToBytes().Length; m_needAck.Remove(ackedPacketId); } } } } // Handle PacketAck packets if (NewPack.Type == PacketType.PacketAck) { PacketAckPacket ackPacket = (PacketAckPacket)NewPack; lock (m_needAck) { foreach (PacketAckPacket.PacketsBlock block in ackPacket.Packets) { uint ackedPackId = block.ID; Packet ackedPacket; if (m_needAck.TryGetValue(ackedPackId, out ackedPacket)) { m_unAckedBytes -= ackedPacket.ToBytes().Length; m_needAck.Remove(ackedPackId); } } } } else if ((NewPack.Type == PacketType.StartPingCheck)) { //reply to pingcheck StartPingCheckPacket startPing = (StartPingCheckPacket)NewPack; CompletePingCheckPacket endPing = (CompletePingCheckPacket)PacketPool.Instance.GetPacket(PacketType.CompletePingCheck); endPing.PingID.PingID = startPing.PingID.PingID; OutPacket(endPing, ThrottleOutPacketType.Task); } else { QueItem item = new QueItem(); item.Packet = NewPack; item.Incoming = true; m_packetQueue.Enqueue(item); } } } public virtual void OutPacket(Packet NewPack, ThrottleOutPacketType throttlePacketType) { QueItem item = new QueItem(); item.Packet = NewPack; item.Incoming = false; item.throttleType = throttlePacketType; // Packet throttle type m_packetQueue.Enqueue(item); m_packetsSent++; } # region Low Level Packet Methods protected void ack_pack(Packet Pack) { if (Pack.Header.Reliable) { PacketAckPacket ack_it = (PacketAckPacket)PacketPool.Instance.GetPacket(PacketType.PacketAck); // TODO: don't create new blocks if recycling an old packet ack_it.Packets = new PacketAckPacket.PacketsBlock[1]; ack_it.Packets[0] = new PacketAckPacket.PacketsBlock(); ack_it.Packets[0].ID = Pack.Header.Sequence; ack_it.Header.Reliable = false; OutPacket(ack_it, ThrottleOutPacketType.Unknown); } /* if (Pack.Header.Reliable) { lock (m_pendingAcks) { uint sequence = (uint)Pack.Header.m_sequence; if (!m_pendingAcks.ContainsKey(sequence)) { m_pendingAcks[sequence] = sequence; } } }*/ } protected void ResendUnacked() { int now = System.Environment.TickCount; lock (m_needAck) { foreach (Packet packet in m_needAck.Values) { if ((now - packet.TickCount > RESEND_TIMEOUT) && (!packet.Header.Resent)) { //m_log.Debug("[NETWORK]: Resending " + packet.Type.ToString() + " packet, " + //(now - packet.TickCount) + "ms have passed"); packet.Header.Resent = true; OutPacket(packet, ThrottleOutPacketType.Resend); } } } } protected void SendAcks() { lock (m_pendingAcks) { if (m_pendingAcks.Count > 0) { if (m_pendingAcks.Count > 250) { // FIXME: Handle the odd case where we have too many pending ACKs queued up m_log.Info("[NETWORK]: Too many ACKs queued up!"); return; } //m_log.Info("[NETWORK]: Sending PacketAck"); int i = 0; PacketAckPacket acks = (PacketAckPacket)PacketPool.Instance.GetPacket(PacketType.PacketAck); // TODO: don't create new blocks if recycling an old packet acks.Packets = new PacketAckPacket.PacketsBlock[m_pendingAcks.Count]; foreach (uint ack in m_pendingAcks.Values) { acks.Packets[i] = new PacketAckPacket.PacketsBlock(); acks.Packets[i].ID = ack; i++; } acks.Header.Reliable = false; OutPacket(acks, ThrottleOutPacketType.Unknown); m_pendingAcks.Clear(); } } } protected void AckTimer_Elapsed(object sender, ElapsedEventArgs ea) { SendAcks(); ResendUnacked(); SendPacketStats(); } protected void SendPacketStats() { if (OnPacketStats != null) { OnPacketStats(m_packetsReceived - m_lastPacketsReceivedSentToScene, m_packetsSent - m_lastPacketsSentSentToScene, m_unAckedBytes); m_lastPacketsReceivedSentToScene = m_packetsReceived; m_lastPacketsSentSentToScene = m_packetsSent; } } #endregion // Previously ClientView.ProcessPackets public bool AddMoney(int debit) { if (m_moneyBalance + debit >= 0) { m_moneyBalance += debit; SendMoneyBalance(LLUUID.Zero, true, Helpers.StringToField("Poof Poof!"), m_moneyBalance); return true; } else { return false; } } protected void ProcessInPacket(Packet Pack) { ack_pack(Pack); if (ProcessPacketMethod(Pack)) { //there is a handler registered that handled this packet type return; } else { Encoding _enc = Encoding.ASCII; switch (Pack.Type) { #region Scene/Avatar case PacketType.AvatarPropertiesRequest: AvatarPropertiesRequestPacket avatarProperties = (AvatarPropertiesRequestPacket)Pack; if (OnRequestAvatarProperties != null) { OnRequestAvatarProperties(this, avatarProperties.AgentData.AvatarID); } break; case PacketType.ChatFromViewer: ChatFromViewerPacket inchatpack = (ChatFromViewerPacket)Pack; string fromName = String.Empty; //ClientAvatar.firstname + " " + ClientAvatar.lastname; byte[] message = inchatpack.ChatData.Message; byte type = inchatpack.ChatData.Type; LLVector3 fromPos = new LLVector3(); // ClientAvatar.Pos; LLUUID fromAgentID = AgentId; int channel = inchatpack.ChatData.Channel; if (OnChatFromViewer != null) { ChatFromViewerArgs args = new ChatFromViewerArgs(); args.Channel = channel; args.From = fromName; args.Message = Helpers.FieldToUTF8String(message); args.Type = (ChatTypeEnum)type; args.Position = fromPos; args.Scene = Scene; args.Sender = this; OnChatFromViewer(this, args); } break; case PacketType.ScriptDialogReply: ScriptDialogReplyPacket rdialog = (ScriptDialogReplyPacket)Pack; int ch = rdialog.Data.ChatChannel; byte[] msg = rdialog.Data.ButtonLabel; if (OnChatFromViewer != null) { ChatFromViewerArgs args = new ChatFromViewerArgs(); args.Channel = ch; args.From = String.Empty; args.Message = Helpers.FieldToUTF8String(msg); args.Type = ChatTypeEnum.Shout; args.Position = new LLVector3(); args.Scene = Scene; args.Sender = this; OnChatFromViewer(this, args); } break; case PacketType.ImprovedInstantMessage: ImprovedInstantMessagePacket msgpack = (ImprovedInstantMessagePacket)Pack; string IMfromName = Util.FieldToString(msgpack.MessageBlock.FromAgentName); string IMmessage = Helpers.FieldToUTF8String(msgpack.MessageBlock.Message); if (OnInstantMessage != null) { OnInstantMessage(this, msgpack.AgentData.AgentID, msgpack.AgentData.SessionID, msgpack.MessageBlock.ToAgentID, msgpack.MessageBlock.ID, msgpack.MessageBlock.Timestamp, IMfromName, IMmessage, msgpack.MessageBlock.Dialog, msgpack.MessageBlock.FromGroup, msgpack.MessageBlock.Offline, msgpack.MessageBlock.ParentEstateID, msgpack.MessageBlock.Position, msgpack.MessageBlock.RegionID, msgpack.MessageBlock.BinaryBucket); } break; case PacketType.AcceptFriendship: AcceptFriendshipPacket afriendpack = (AcceptFriendshipPacket)Pack; // My guess is this is the folder to stick the calling card into List callingCardFolders = new List(); LLUUID agentID = afriendpack.AgentData.AgentID; LLUUID transactionID = afriendpack.TransactionBlock.TransactionID; for (int fi = 0; fi < afriendpack.FolderData.Length; fi++) { callingCardFolders.Add(afriendpack.FolderData[fi].FolderID); } if (OnApproveFriendRequest != null) { OnApproveFriendRequest(this, agentID, transactionID, callingCardFolders); } break; case PacketType.TerminateFriendship: TerminateFriendshipPacket tfriendpack = (TerminateFriendshipPacket)Pack; LLUUID listOwnerAgentID = tfriendpack.AgentData.AgentID; LLUUID exFriendID = tfriendpack.ExBlock.OtherID; if (OnTerminateFriendship != null) { OnTerminateFriendship(this, listOwnerAgentID, exFriendID); } break; case PacketType.RezObject: RezObjectPacket rezPacket = (RezObjectPacket)Pack; if (OnRezObject != null) { //rezPacket.RezData.BypassRaycast; //rezPacket.RezData.RayEnd; //rezPacket.RezData.RayEndIsIntersection; //rezPacket.RezData.RayStart; //rezPacket.RezData.RayTargetID; //rezPacket.RezData.RemoveItem; //rezPacket.RezData.RezSelected; //rezPacket.RezData.FromTaskID; //m_log.Info("[REZData]: " + rezPacket.ToString()); OnRezObject(this, rezPacket.InventoryData.ItemID, rezPacket.RezData.RayEnd, rezPacket.RezData.RayStart, rezPacket.RezData.RayTargetID, rezPacket.RezData.BypassRaycast, rezPacket.RezData.RayEndIsIntersection, rezPacket.RezData.EveryoneMask, rezPacket.RezData.GroupMask, rezPacket.RezData.NextOwnerMask, rezPacket.RezData.ItemFlags, rezPacket.RezData.RezSelected, rezPacket.RezData.RemoveItem, rezPacket.RezData.FromTaskID); } break; case PacketType.DeRezObject: if (OnDeRezObject != null) { OnDeRezObject(Pack, this); } break; case PacketType.ModifyLand: ModifyLandPacket modify = (ModifyLandPacket)Pack; //m_log.Info("[LAND]: LAND:" + modify.ToString()); if (modify.ParcelData.Length > 0) { if (OnModifyTerrain != null) { for (int i = 0; i < modify.ParcelData.Length; i++) { OnModifyTerrain(modify.ModifyBlock.Height, modify.ModifyBlock.Seconds, modify.ModifyBlock.BrushSize, modify.ModifyBlock.Action, modify.ParcelData[i].North, modify.ParcelData[i].West, modify.ParcelData[i].South, modify.ParcelData[i].East, this); } } } break; case PacketType.RegionHandshakeReply: if (OnRegionHandShakeReply != null) { OnRegionHandShakeReply(this); } break; case PacketType.AgentWearablesRequest: if (OnRequestWearables != null) { OnRequestWearables(); } if (OnRequestAvatarsData != null) { OnRequestAvatarsData(this); } break; case PacketType.AgentSetAppearance: AgentSetAppearancePacket appear = (AgentSetAppearancePacket)Pack; if (OnSetAppearance != null) { OnSetAppearance(appear.ObjectData.TextureEntry, appear.VisualParam); } break; case PacketType.AgentIsNowWearing: if (OnAvatarNowWearing != null) { AgentIsNowWearingPacket nowWearing = (AgentIsNowWearingPacket)Pack; AvatarWearingArgs wearingArgs = new AvatarWearingArgs(); for (int i = 0; i < nowWearing.WearableData.Length; i++) { AvatarWearingArgs.Wearable wearable = new AvatarWearingArgs.Wearable(nowWearing.WearableData[i].ItemID, nowWearing.WearableData[i].WearableType); wearingArgs.NowWearing.Add(wearable); } OnAvatarNowWearing(this, wearingArgs); } break; case PacketType.RezSingleAttachmentFromInv: if (OnRezSingleAttachmentFromInv != null) { RezSingleAttachmentFromInvPacket rez = (RezSingleAttachmentFromInvPacket) Pack; OnRezSingleAttachmentFromInv(this, rez.ObjectData.ItemID, rez.ObjectData.AttachmentPt, rez.ObjectData.ItemFlags, rez.ObjectData.NextOwnerMask); } break; case PacketType.ObjectAttach: if (OnObjectAttach != null) { ObjectAttachPacket att = (ObjectAttachPacket) Pack; OnObjectAttach(this, att.ObjectData[0].ObjectLocalID, att.AgentData.AttachmentPoint, att.ObjectData[0].Rotation); } break; case PacketType.SetAlwaysRun: SetAlwaysRunPacket run = (SetAlwaysRunPacket)Pack; if (OnSetAlwaysRun != null) OnSetAlwaysRun(this, run.AgentData.AlwaysRun); break; case PacketType.CompleteAgentMovement: if (OnCompleteMovementToRegion != null) { OnCompleteMovementToRegion(); } break; case PacketType.AgentUpdate: if (OnAgentUpdate != null) { AgentUpdatePacket agenUpdate = (AgentUpdatePacket)Pack; OnAgentUpdate(this, agenUpdate); //agenUpdate.AgentData.ControlFlags, agenUpdate.AgentData.BodyRotationa); } break; case PacketType.AgentAnimation: AgentAnimationPacket AgentAni = (AgentAnimationPacket)Pack; for (int i = 0; i < AgentAni.AnimationList.Length; i++) { if (AgentAni.AnimationList[i].StartAnim) { if (OnStartAnim != null) { OnStartAnim(this, AgentAni.AnimationList[i].AnimID, 1); } } else { if (OnStopAnim != null) { OnStopAnim(this, AgentAni.AnimationList[i].AnimID); } } } break; case PacketType.AgentRequestSit: if (OnAgentRequestSit != null) { AgentRequestSitPacket agentRequestSit = (AgentRequestSitPacket)Pack; OnAgentRequestSit(this, agentRequestSit.AgentData.AgentID, agentRequestSit.TargetObject.TargetID, agentRequestSit.TargetObject.Offset); } break; case PacketType.AgentSit: if (OnAgentSit != null) { AgentSitPacket agentSit = (AgentSitPacket)Pack; OnAgentSit(this, agentSit.AgentData.AgentID); } break; case PacketType.AvatarPickerRequest: AvatarPickerRequestPacket avRequestQuery = (AvatarPickerRequestPacket)Pack; AvatarPickerRequestPacket.AgentDataBlock Requestdata = avRequestQuery.AgentData; AvatarPickerRequestPacket.DataBlock querydata = avRequestQuery.Data; //System.Console.WriteLine("Agent Sends:" + Helpers.FieldToUTF8String(querydata.Name)); if (OnAvatarPickerRequest != null) { OnAvatarPickerRequest(this, Requestdata.AgentID, Requestdata.QueryID, Helpers.FieldToUTF8String(querydata.Name)); } break; case PacketType.AgentDataUpdateRequest: AgentDataUpdateRequestPacket avRequestDataUpdatePacket = (AgentDataUpdateRequestPacket)Pack; if (OnAgentDataUpdateRequest != null) { OnAgentDataUpdateRequest(this, avRequestDataUpdatePacket.AgentData.AgentID, avRequestDataUpdatePacket.AgentData.SessionID); } break; case PacketType.UserInfoRequest: UserInfoRequestPacket avUserInfoRequestPacket = (UserInfoRequestPacket)Pack; if (OnUserInfoRequest != null) { OnUserInfoRequest(this,avUserInfoRequestPacket.AgentData.AgentID,avUserInfoRequestPacket.AgentData.SessionID); } break; case PacketType.SetStartLocationRequest: SetStartLocationRequestPacket avSetStartLocationRequestPacket = (SetStartLocationRequestPacket)Pack; if (avSetStartLocationRequestPacket.AgentData.AgentID == AgentId && avSetStartLocationRequestPacket.AgentData.SessionID == SessionId) { if (OnSetStartLocationRequest != null) { OnSetStartLocationRequest(this, 0, avSetStartLocationRequestPacket.StartLocationData.LocationPos, avSetStartLocationRequestPacket.StartLocationData.LocationLookAt, avSetStartLocationRequestPacket.StartLocationData.LocationID); } } break; case PacketType.AgentThrottle: AgentThrottlePacket atpack = (AgentThrottlePacket)Pack; m_packetQueue.SetThrottleFromClient(atpack.Throttle.Throttles); break; #endregion #region Objects/m_sceneObjects case PacketType.ObjectLink: ObjectLinkPacket link = (ObjectLinkPacket)Pack; uint parentprimid = 0; List childrenprims = new List(); if (link.ObjectData.Length > 1) { parentprimid = link.ObjectData[0].ObjectLocalID; for (int i = 1; i < link.ObjectData.Length; i++) { childrenprims.Add(link.ObjectData[i].ObjectLocalID); } } if (OnLinkObjects != null) { OnLinkObjects(parentprimid, childrenprims); } break; case PacketType.ObjectDelink: ObjectDelinkPacket delink = (ObjectDelinkPacket)Pack; // It appears the prim at index 0 is not always the root prim (for // instance, when one prim of a link set has been edited independently // of the others). Therefore, we'll pass all the ids onto the delink // method for it to decide which is the root. List prims = new List(); for (int i = 0; i < delink.ObjectData.Length; i++) { prims.Add(delink.ObjectData[i].ObjectLocalID); } if (OnDelinkObjects != null) { OnDelinkObjects(prims); } break; case PacketType.ObjectAdd: if (OnAddPrim != null) { ObjectAddPacket addPacket = (ObjectAddPacket)Pack; PrimitiveBaseShape shape = GetShapeFromAddPacket(addPacket); // m_log.Info("[REZData]: " + addPacket.ToString()); //BypassRaycast: 1 //RayStart: <69.79469, 158.2652, 98.40343> //RayEnd: <61.97724, 141.995, 92.58341> //RayTargetID: 00000000-0000-0000-0000-000000000000 OnAddPrim(AgentId, addPacket.ObjectData.RayEnd, addPacket.ObjectData.Rotation, shape, addPacket.ObjectData.BypassRaycast, addPacket.ObjectData.RayStart, addPacket.ObjectData.RayTargetID, addPacket.ObjectData.RayEndIsIntersection); } break; case PacketType.ObjectShape: ObjectShapePacket shapePacket = (ObjectShapePacket)Pack; for (int i = 0; i < shapePacket.ObjectData.Length; i++) { if (OnUpdatePrimShape != null) { OnUpdatePrimShape(m_agentId, shapePacket.ObjectData[i].ObjectLocalID, shapePacket.ObjectData[i]); } } break; case PacketType.ObjectExtraParams: ObjectExtraParamsPacket extraPar = (ObjectExtraParamsPacket)Pack; if (OnUpdateExtraParams != null) { OnUpdateExtraParams(m_agentId, extraPar.ObjectData[0].ObjectLocalID, extraPar.ObjectData[0].ParamType, extraPar.ObjectData[0].ParamInUse, extraPar.ObjectData[0].ParamData); } break; case PacketType.ObjectDuplicate: ObjectDuplicatePacket dupe = (ObjectDuplicatePacket)Pack; ObjectDuplicatePacket.AgentDataBlock AgentandGroupData = dupe.AgentData; for (int i = 0; i < dupe.ObjectData.Length; i++) { if (OnObjectDuplicate != null) { OnObjectDuplicate(dupe.ObjectData[i].ObjectLocalID, dupe.SharedData.Offset, dupe.SharedData.DuplicateFlags, AgentandGroupData.AgentID, AgentandGroupData.GroupID); } } break; case PacketType.ObjectSelect: ObjectSelectPacket incomingselect = (ObjectSelectPacket)Pack; for (int i = 0; i < incomingselect.ObjectData.Length; i++) { if (OnObjectSelect != null) { OnObjectSelect(incomingselect.ObjectData[i].ObjectLocalID, this); } } break; case PacketType.ObjectDeselect: ObjectDeselectPacket incomingdeselect = (ObjectDeselectPacket)Pack; for (int i = 0; i < incomingdeselect.ObjectData.Length; i++) { if (OnObjectDeselect != null) { OnObjectDeselect(incomingdeselect.ObjectData[i].ObjectLocalID, this); } } break; case PacketType.ObjectFlagUpdate: ObjectFlagUpdatePacket flags = (ObjectFlagUpdatePacket)Pack; if (OnUpdatePrimFlags != null) { OnUpdatePrimFlags(flags.AgentData.ObjectLocalID, Pack, this); } break; case PacketType.ObjectImage: ObjectImagePacket imagePack = (ObjectImagePacket)Pack; for (int i = 0; i < imagePack.ObjectData.Length; i++) { if (OnUpdatePrimTexture != null) { OnUpdatePrimTexture(imagePack.ObjectData[i].ObjectLocalID, imagePack.ObjectData[i].TextureEntry, this); } } break; case PacketType.ObjectGrab: ObjectGrabPacket grab = (ObjectGrabPacket)Pack; if (OnGrabObject != null) { OnGrabObject(grab.ObjectData.LocalID, grab.ObjectData.GrabOffset, this); } break; case PacketType.ObjectGrabUpdate: ObjectGrabUpdatePacket grabUpdate = (ObjectGrabUpdatePacket)Pack; if (OnGrabUpdate != null) { OnGrabUpdate(grabUpdate.ObjectData.ObjectID, grabUpdate.ObjectData.GrabOffsetInitial, grabUpdate.ObjectData.GrabPosition, this); } break; case PacketType.ObjectDeGrab: ObjectDeGrabPacket deGrab = (ObjectDeGrabPacket)Pack; if (OnDeGrabObject != null) { OnDeGrabObject(deGrab.ObjectData.LocalID, this); } break; case PacketType.ObjectDescription: ObjectDescriptionPacket objDes = (ObjectDescriptionPacket)Pack; for (int i = 0; i < objDes.ObjectData.Length; i++) { if (OnObjectDescription != null) { OnObjectDescription(this, objDes.ObjectData[i].LocalID, m_encoding.GetString(objDes.ObjectData[i].Description)); } } break; case PacketType.ObjectName: ObjectNamePacket objName = (ObjectNamePacket)Pack; for (int i = 0; i < objName.ObjectData.Length; i++) { if (OnObjectName != null) { OnObjectName(this, objName.ObjectData[i].LocalID, m_encoding.GetString(objName.ObjectData[i].Name)); } } break; case PacketType.ObjectPermissions: if (OnObjectPermissions != null) { ObjectPermissionsPacket newobjPerms = (ObjectPermissionsPacket)Pack; LLUUID AgentID = newobjPerms.AgentData.AgentID; LLUUID SessionID = newobjPerms.AgentData.SessionID; for (int i = 0; i < newobjPerms.ObjectData.Length; i++) { ObjectPermissionsPacket.ObjectDataBlock permChanges = newobjPerms.ObjectData[i]; byte field = permChanges.Field; uint localID = permChanges.ObjectLocalID; uint mask = permChanges.Mask; byte set = permChanges.Set; OnObjectPermissions(this, AgentID, SessionID, field, localID, mask, set); } } // Here's our data, // PermField contains the field the info goes into // PermField determines which mask we're changing // // chmask is the mask of the change // setTF is whether we're adding it or taking it away // // objLocalID is the localID of the object. // Unfortunately, we have to pass the event the packet because objData is an array // That means multiple object perms may be updated in a single packet. break; case PacketType.RequestObjectPropertiesFamily: //This powers the little tooltip that appears when you move your mouse over an object RequestObjectPropertiesFamilyPacket packToolTip = (RequestObjectPropertiesFamilyPacket)Pack; RequestObjectPropertiesFamilyPacket.ObjectDataBlock packObjBlock = packToolTip.ObjectData; if (OnRequestObjectPropertiesFamily != null) { OnRequestObjectPropertiesFamily(this, m_agentId, packObjBlock.RequestFlags, packObjBlock.ObjectID); } break; #endregion #region Inventory/Asset/Other related packets case PacketType.RequestImage: RequestImagePacket imageRequest = (RequestImagePacket)Pack; //Console.WriteLine("image request: " + Pack.ToString()); for (int i = 0; i < imageRequest.RequestImage.Length; i++) { if (OnRequestTexture != null) { TextureRequestArgs args = new TextureRequestArgs(); args.RequestedAssetID = imageRequest.RequestImage[i].Image; args.DiscardLevel = imageRequest.RequestImage[i].DiscardLevel; args.PacketNumber = imageRequest.RequestImage[i].Packet; args.Priority = imageRequest.RequestImage[i].DownloadPriority; OnRequestTexture(this, args); } } break; case PacketType.TransferRequest: //Console.WriteLine("ClientView.ProcessPackets.cs:ProcessInPacket() - Got transfer request"); TransferRequestPacket transfer = (TransferRequestPacket)Pack; m_assetCache.AddAssetRequest(this, transfer); break; case PacketType.AssetUploadRequest: AssetUploadRequestPacket request = (AssetUploadRequestPacket)Pack; // Console.WriteLine("upload request " + Pack.ToString()); // Console.WriteLine("upload request was for assetid: " + request.AssetBlock.TransactionID.Combine(this.SecureSessionId).ToString()); if (OnAssetUploadRequest != null) { LLUUID temp = LLUUID.Combine(request.AssetBlock.TransactionID, SecureSessionId); OnAssetUploadRequest(this, temp, request.AssetBlock.TransactionID, request.AssetBlock.Type, request.AssetBlock.AssetData, request.AssetBlock.StoreLocal, request.AssetBlock.Tempfile); } break; case PacketType.RequestXfer: RequestXferPacket xferReq = (RequestXferPacket)Pack; if (OnRequestXfer != null) { OnRequestXfer(this, xferReq.XferID.ID, Util.FieldToString(xferReq.XferID.Filename)); } break; case PacketType.SendXferPacket: SendXferPacketPacket xferRec = (SendXferPacketPacket)Pack; if (OnXferReceive != null) { OnXferReceive(this, xferRec.XferID.ID, xferRec.XferID.Packet, xferRec.DataPacket.Data); } break; case PacketType.ConfirmXferPacket: ConfirmXferPacketPacket confirmXfer = (ConfirmXferPacketPacket)Pack; if (OnConfirmXfer != null) { OnConfirmXfer(this, confirmXfer.XferID.ID, confirmXfer.XferID.Packet); } break; case PacketType.CreateInventoryFolder: if (OnCreateNewInventoryFolder != null) { CreateInventoryFolderPacket invFolder = (CreateInventoryFolderPacket)Pack; OnCreateNewInventoryFolder(this, invFolder.FolderData.FolderID, (ushort)invFolder.FolderData.Type, Util.FieldToString(invFolder.FolderData.Name), invFolder.FolderData.ParentID); } break; case PacketType.UpdateInventoryFolder: if (OnUpdateInventoryFolder != null) { UpdateInventoryFolderPacket invFolder = (UpdateInventoryFolderPacket)Pack; for (int i = 0; i < invFolder.FolderData.Length; i++) { OnUpdateInventoryFolder(this, invFolder.FolderData[i].FolderID, (ushort)invFolder.FolderData[i].Type, Util.FieldToString(invFolder.FolderData[i].Name), invFolder.FolderData[i].ParentID); } } break; case PacketType.MoveInventoryFolder: if (OnMoveInventoryFolder != null) { MoveInventoryFolderPacket invFolder = (MoveInventoryFolderPacket)Pack; for (int i = 0; i < invFolder.InventoryData.Length; i++) { OnMoveInventoryFolder(this, invFolder.InventoryData[i].FolderID, invFolder.InventoryData[i].ParentID); } } break; case PacketType.CreateInventoryItem: CreateInventoryItemPacket createItem = (CreateInventoryItemPacket)Pack; if (OnCreateNewInventoryItem != null) { OnCreateNewInventoryItem(this, createItem.InventoryBlock.TransactionID, createItem.InventoryBlock.FolderID, createItem.InventoryBlock.CallbackID, Util.FieldToString(createItem.InventoryBlock.Description), Util.FieldToString(createItem.InventoryBlock.Name), createItem.InventoryBlock.InvType, createItem.InventoryBlock.Type, createItem.InventoryBlock.WearableType, createItem.InventoryBlock.NextOwnerMask); } break; case PacketType.FetchInventory: if (OnFetchInventory != null) { FetchInventoryPacket FetchInventory = (FetchInventoryPacket)Pack; for (int i = 0; i < FetchInventory.InventoryData.Length; i++) { OnFetchInventory(this, FetchInventory.InventoryData[i].ItemID, FetchInventory.InventoryData[i].OwnerID); } } break; case PacketType.FetchInventoryDescendents: if (OnFetchInventoryDescendents != null) { FetchInventoryDescendentsPacket Fetch = (FetchInventoryDescendentsPacket)Pack; OnFetchInventoryDescendents(this, Fetch.InventoryData.FolderID, Fetch.InventoryData.OwnerID, Fetch.InventoryData.FetchFolders, Fetch.InventoryData.FetchItems, Fetch.InventoryData.SortOrder); } break; case PacketType.PurgeInventoryDescendents: if (OnPurgeInventoryDescendents != null) { PurgeInventoryDescendentsPacket Purge = (PurgeInventoryDescendentsPacket)Pack; OnPurgeInventoryDescendents(this, Purge.InventoryData.FolderID); } break; case PacketType.UpdateInventoryItem: UpdateInventoryItemPacket update = (UpdateInventoryItemPacket)Pack; if (OnUpdateInventoryItem != null) { for (int i = 0; i < update.InventoryData.Length; i++) { OnUpdateInventoryItem(this, update.InventoryData[i].TransactionID, update.InventoryData[i].ItemID, Util.FieldToString(update.InventoryData[i].Name), Util.FieldToString(update.InventoryData[i].Description), update.InventoryData[i].NextOwnerMask); } } //Console.WriteLine(Pack.ToString()); /*for (int i = 0; i < update.InventoryData.Length; i++) { if (update.InventoryData[i].TransactionID != LLUUID.Zero) { AssetBase asset = m_assetCache.GetAsset(update.InventoryData[i].TransactionID.Combine(this.SecureSessionId)); if (asset != null) { // Console.WriteLine("updating inventory item, found asset" + asset.FullID.ToString() + " already in cache"); m_inventoryCache.UpdateInventoryItemAsset(this, update.InventoryData[i].ItemID, asset); } else { asset = this.UploadAssets.AddUploadToAssetCache(update.InventoryData[i].TransactionID); if (asset != null) { //Console.WriteLine("updating inventory item, adding asset" + asset.FullID.ToString() + " to cache"); m_inventoryCache.UpdateInventoryItemAsset(this, update.InventoryData[i].ItemID, asset); } else { //Console.WriteLine("trying to update inventory item, but asset is null"); } } } else { m_inventoryCache.UpdateInventoryItemDetails(this, update.InventoryData[i].ItemID, update.InventoryData[i]); ; } }*/ break; case PacketType.CopyInventoryItem: CopyInventoryItemPacket copyitem = (CopyInventoryItemPacket)Pack; if (OnCopyInventoryItem != null) { foreach (CopyInventoryItemPacket.InventoryDataBlock datablock in copyitem.InventoryData) { OnCopyInventoryItem(this, datablock.CallbackID, datablock.OldAgentID, datablock.OldItemID, datablock.NewFolderID, Util.FieldToString(datablock.NewName)); } } break; case PacketType.MoveInventoryItem: MoveInventoryItemPacket moveitem = (MoveInventoryItemPacket)Pack; if (OnMoveInventoryItem != null) { foreach (MoveInventoryItemPacket.InventoryDataBlock datablock in moveitem.InventoryData) { OnMoveInventoryItem(this, datablock.FolderID, datablock.ItemID, datablock.Length, Util.FieldToString(datablock.NewName)); } } break; case PacketType.RemoveInventoryItem: RemoveInventoryItemPacket removeItem = (RemoveInventoryItemPacket)Pack; if (OnRemoveInventoryItem != null) { foreach (RemoveInventoryItemPacket.InventoryDataBlock datablock in removeItem.InventoryData) { OnRemoveInventoryItem(this, datablock.ItemID); } } break; case PacketType.RemoveInventoryFolder: RemoveInventoryFolderPacket removeFolder = (RemoveInventoryFolderPacket)Pack; if (OnRemoveInventoryFolder != null) { foreach (RemoveInventoryFolderPacket.FolderDataBlock datablock in removeFolder.FolderData) { OnRemoveInventoryFolder(this, datablock.FolderID); } } break; case PacketType.RequestTaskInventory: RequestTaskInventoryPacket requesttask = (RequestTaskInventoryPacket)Pack; if (OnRequestTaskInventory != null) { OnRequestTaskInventory(this, requesttask.InventoryData.LocalID); } break; case PacketType.UpdateTaskInventory: UpdateTaskInventoryPacket updatetask = (UpdateTaskInventoryPacket)Pack; if (OnUpdateTaskInventory != null) { if (updatetask.UpdateData.Key == 0) { OnUpdateTaskInventory(this, updatetask.InventoryData.ItemID, updatetask.InventoryData.FolderID, updatetask.UpdateData.LocalID); } } break; case PacketType.RemoveTaskInventory: RemoveTaskInventoryPacket removeTask = (RemoveTaskInventoryPacket)Pack; if (OnRemoveTaskItem != null) { OnRemoveTaskItem(this, removeTask.InventoryData.ItemID, removeTask.InventoryData.LocalID); } break; case PacketType.MoveTaskInventory: m_log.Warn("[CLIENT]: unhandled MoveTaskInventory packet"); break; case PacketType.RezScript: //Console.WriteLine(Pack.ToString()); RezScriptPacket rezScript = (RezScriptPacket)Pack; if (OnRezScript != null) { OnRezScript(this, rezScript.InventoryBlock.ItemID, rezScript.UpdateBlock.ObjectLocalID); } break; case PacketType.MapLayerRequest: RequestMapLayer(); break; case PacketType.MapBlockRequest: MapBlockRequestPacket MapRequest = (MapBlockRequestPacket)Pack; if (OnRequestMapBlocks != null) { OnRequestMapBlocks(this, MapRequest.PositionData.MinX, MapRequest.PositionData.MinY, MapRequest.PositionData.MaxX, MapRequest.PositionData.MaxY); } break; case PacketType.MapNameRequest: MapNameRequestPacket map = (MapNameRequestPacket)Pack; string mapName = UTF8Encoding.UTF8.GetString(map.NameData.Name, 0, map.NameData.Name.Length - 1); if (OnMapNameRequest != null) { OnMapNameRequest(this, mapName); } break; case PacketType.TeleportLandmarkRequest: TeleportLandmarkRequestPacket tpReq = (TeleportLandmarkRequestPacket)Pack; TeleportStartPacket tpStart = (TeleportStartPacket)PacketPool.Instance.GetPacket(PacketType.TeleportStart); tpStart.Info.TeleportFlags = 8; // tp via lm OutPacket(tpStart, ThrottleOutPacketType.Task); TeleportProgressPacket tpProgress = (TeleportProgressPacket)PacketPool.Instance.GetPacket(PacketType.TeleportProgress); tpProgress.Info.Message = (new ASCIIEncoding()).GetBytes("sending_landmark"); tpProgress.Info.TeleportFlags = 8; tpProgress.AgentData.AgentID = tpReq.Info.AgentID; OutPacket(tpProgress, ThrottleOutPacketType.Task); // Fetch landmark LLUUID lmid = tpReq.Info.LandmarkID; AssetBase lma = m_assetCache.GetAsset(lmid, false); if (lma != null) { AssetLandmark lm = new AssetLandmark(lma); if (lm.RegionID == m_scene.RegionInfo.RegionID) { TeleportLocalPacket tpLocal = (TeleportLocalPacket)PacketPool.Instance.GetPacket(PacketType.TeleportLocal); tpLocal.Info.AgentID = tpReq.Info.AgentID; tpLocal.Info.TeleportFlags = 8; // Teleport via landmark tpLocal.Info.LocationID = 2; tpLocal.Info.Position = lm.Position; OutPacket(tpLocal, ThrottleOutPacketType.Task); } else { TeleportCancelPacket tpCancel = (TeleportCancelPacket)PacketPool.Instance.GetPacket(PacketType.TeleportCancel); tpCancel.Info.AgentID = tpReq.Info.AgentID; tpCancel.Info.SessionID = tpReq.Info.SessionID; OutPacket(tpCancel, ThrottleOutPacketType.Task); } } else { Console.WriteLine("Cancelling Teleport - fetch asset not yet implemented"); TeleportCancelPacket tpCancel = (TeleportCancelPacket)PacketPool.Instance.GetPacket(PacketType.TeleportCancel); tpCancel.Info.AgentID = tpReq.Info.AgentID; tpCancel.Info.SessionID = tpReq.Info.SessionID; OutPacket(tpCancel, ThrottleOutPacketType.Task); } break; case PacketType.TeleportLocationRequest: TeleportLocationRequestPacket tpLocReq = (TeleportLocationRequestPacket)Pack; // Console.WriteLine(tpLocReq.ToString()); if (OnTeleportLocationRequest != null) { OnTeleportLocationRequest(this, tpLocReq.Info.RegionHandle, tpLocReq.Info.Position, tpLocReq.Info.LookAt, 16); } else { //no event handler so cancel request TeleportCancelPacket tpCancel = (TeleportCancelPacket)PacketPool.Instance.GetPacket(PacketType.TeleportCancel); tpCancel.Info.SessionID = tpLocReq.AgentData.SessionID; tpCancel.Info.AgentID = tpLocReq.AgentData.AgentID; OutPacket(tpCancel, ThrottleOutPacketType.Task); } break; #endregion case PacketType.MoneyBalanceRequest: MoneyBalanceRequestPacket moneybalancerequestpacket = (MoneyBalanceRequestPacket)Pack; if (OnMoneyBalanceRequest != null) { OnMoneyBalanceRequest(this, moneybalancerequestpacket.AgentData.AgentID, moneybalancerequestpacket.AgentData.SessionID, moneybalancerequestpacket.MoneyData.TransactionID); } break; case PacketType.UUIDNameRequest: UUIDNameRequestPacket incoming = (UUIDNameRequestPacket)Pack; foreach (UUIDNameRequestPacket.UUIDNameBlockBlock UUIDBlock in incoming.UUIDNameBlock) { OnNameFromUUIDRequest(UUIDBlock.ID, this); } break; #region Parcel related packets case PacketType.ParcelAccessListRequest: ParcelAccessListRequestPacket requestPacket = (ParcelAccessListRequestPacket)Pack; if (OnParcelAccessListRequest != null) { OnParcelAccessListRequest(requestPacket.AgentData.AgentID, requestPacket.AgentData.SessionID, requestPacket.Data.Flags, requestPacket.Data.SequenceID, requestPacket.Data.LocalID, this); } break; case PacketType.ParcelAccessListUpdate: ParcelAccessListUpdatePacket updatePacket = (ParcelAccessListUpdatePacket)Pack; List entries = new List(); foreach (ParcelAccessListUpdatePacket.ListBlock block in updatePacket.List) { ParcelManager.ParcelAccessEntry entry = new ParcelManager.ParcelAccessEntry(); entry.AgentID = block.ID; entry.Flags = (ParcelManager.AccessList)block.Flags; entry.Time = new DateTime(); entries.Add(entry); } if (OnParcelAccessListUpdateRequest != null) { OnParcelAccessListUpdateRequest(updatePacket.AgentData.AgentID, updatePacket.AgentData.SessionID, updatePacket.Data.Flags, updatePacket.Data.LocalID, entries, this); } break; case PacketType.ParcelPropertiesRequest: ParcelPropertiesRequestPacket propertiesRequest = (ParcelPropertiesRequestPacket)Pack; if (OnParcelPropertiesRequest != null) { OnParcelPropertiesRequest((int)Math.Round(propertiesRequest.ParcelData.West), (int)Math.Round(propertiesRequest.ParcelData.South), (int)Math.Round(propertiesRequest.ParcelData.East), (int)Math.Round(propertiesRequest.ParcelData.North), propertiesRequest.ParcelData.SequenceID, propertiesRequest.ParcelData.SnapSelection, this); } break; case PacketType.ParcelDivide: ParcelDividePacket landDivide = (ParcelDividePacket)Pack; if (OnParcelDivideRequest != null) { OnParcelDivideRequest((int)Math.Round(landDivide.ParcelData.West), (int)Math.Round(landDivide.ParcelData.South), (int)Math.Round(landDivide.ParcelData.East), (int)Math.Round(landDivide.ParcelData.North), this); } break; case PacketType.ParcelJoin: ParcelJoinPacket landJoin = (ParcelJoinPacket)Pack; if (OnParcelJoinRequest != null) { OnParcelJoinRequest((int)Math.Round(landJoin.ParcelData.West), (int)Math.Round(landJoin.ParcelData.South), (int)Math.Round(landJoin.ParcelData.East), (int)Math.Round(landJoin.ParcelData.North), this); } break; case PacketType.ParcelPropertiesUpdate: ParcelPropertiesUpdatePacket parcelPropertiesPacket = (ParcelPropertiesUpdatePacket)Pack; if (OnParcelPropertiesUpdateRequest != null) { OnParcelPropertiesUpdateRequest(parcelPropertiesPacket, this); } break; case PacketType.ParcelSelectObjects: ParcelSelectObjectsPacket selectPacket = (ParcelSelectObjectsPacket)Pack; if (OnParcelSelectObjects != null) { OnParcelSelectObjects(selectPacket.ParcelData.LocalID, Convert.ToInt32(selectPacket.ParcelData.ReturnType), this); } break; case PacketType.ParcelObjectOwnersRequest: //System.Console.WriteLine(Pack.ToString()); ParcelObjectOwnersRequestPacket reqPacket = (ParcelObjectOwnersRequestPacket)Pack; if (OnParcelObjectOwnerRequest != null) { OnParcelObjectOwnerRequest(reqPacket.ParcelData.LocalID, this); } break; #endregion #region Estate Packets case PacketType.EstateOwnerMessage: EstateOwnerMessagePacket messagePacket = (EstateOwnerMessagePacket)Pack; if (OnEstateOwnerMessage != null) { OnEstateOwnerMessage(messagePacket, this); } break; case PacketType.RequestRegionInfo: RequestRegionInfoPacket.AgentDataBlock mPacket = ((RequestRegionInfoPacket)Pack).AgentData; if (OnRegionInfoRequest != null) { OnRegionInfoRequest(this, mPacket.SessionID); } break; case PacketType.EstateCovenantRequest: // TODO: handle this packet EstateCovenantRequestPacket.AgentDataBlock epack = ((EstateCovenantRequestPacket)Pack).AgentData; if (OnEstateCovenantRequest != null) { OnEstateCovenantRequest(this, epack.SessionID); } break; #endregion #region GodPackets case PacketType.RequestGodlikePowers: RequestGodlikePowersPacket rglpPack = (RequestGodlikePowersPacket)Pack; RequestGodlikePowersPacket.RequestBlockBlock rblock = rglpPack.RequestBlock; LLUUID token = rblock.Token; RequestGodlikePowersPacket.AgentDataBlock ablock = rglpPack.AgentData; OnRequestGodlikePowers(ablock.AgentID, ablock.SessionID, token, this); break; case PacketType.GodKickUser: m_log.Warn("[CLIENT]: unhandled GodKickUser packet"); GodKickUserPacket gkupack = (GodKickUserPacket)Pack; if (gkupack.UserInfo.GodSessionID == SessionId && AgentId == gkupack.UserInfo.GodID) { OnGodKickUser(gkupack.UserInfo.GodID, gkupack.UserInfo.GodSessionID, gkupack.UserInfo.AgentID, (uint)0, gkupack.UserInfo.Reason); } else { SendAgentAlertMessage("Kick request denied", false); } //KickUserPacket kupack = new KickUserPacket(); //KickUserPacket.UserInfoBlock kupackib = kupack.UserInfo; //kupack.UserInfo.AgentID = gkupack.UserInfo.AgentID; //kupack.UserInfo.SessionID = gkupack.UserInfo.GodSessionID; //kupack.TargetBlock.TargetIP = (uint)0; //kupack.TargetBlock.TargetPort = (ushort)0; //kupack.UserInfo.Reason = gkupack.UserInfo.Reason; //OutPacket(kupack, ThrottleOutPacketType.Task); break; #endregion #region unimplemented handlers case PacketType.StartPingCheck: // Send the client the ping response back // Pass the same PingID in the matching packet // Handled In the packet processing //m_log.Debug("[CLIENT]: possibly unhandled StartPingCheck packet"); break; case PacketType.CompletePingCheck: // TODO: Perhaps this should be processed on the Sim to determine whether or not to drop a dead client //m_log.Warn("[CLIENT]: unhandled CompletePingCheck packet"); break; case PacketType.ObjectScale: // TODO: handle this packet m_log.Warn("[CLIENT]: unhandled ObjectScale packet"); break; case PacketType.ViewerStats: // TODO: handle this packet m_log.Warn("[CLIENT]: unhandled ViewerStats packet"); break; case PacketType.CreateGroupRequest: // TODO: handle this packet m_log.Warn("[CLIENT]: unhandled CreateGroupRequest packet"); break; case PacketType.GenericMessage: // TODO: handle this packet m_log.Warn("[CLIENT]: unhandled GenericMessage packet"); break; case PacketType.MapItemRequest: // TODO: handle this packet m_log.Warn("[CLIENT]: unhandled MapItemRequest packet"); break; case PacketType.AgentResume: // TODO: handle this packet m_log.Warn("[CLIENT]: unhandled AgentResume packet"); break; case PacketType.AgentPause: // TODO: handle this packet m_log.Warn("[CLIENT]: unhandled AgentPause packet"); break; case PacketType.TransferAbort: // TODO: handle this packet m_log.Warn("[CLIENT]: unhandled TransferAbort packet"); break; case PacketType.MuteListRequest: // TODO: handle this packet m_log.Warn("[CLIENT]: unhandled MuteListRequest packet"); break; //case PacketType.AgentDataUpdateRequest: // TODO: handle this packet //m_log.Warn("[CLIENT]: unhandled AgentDataUpdateRequest packet"); //break; case PacketType.ParcelDwellRequest: // TODO: handle this packet m_log.Warn("[CLIENT]: unhandled ParcelDwellRequest packet"); break; case PacketType.UseCircuitCode: // TODO: Don't display this one, we handle it at a lower level //m_log.Warn("[CLIENT]: unhandled UseCircuitCode packet"); break; case PacketType.EconomyDataRequest: // TODO: handle this packet m_log.Warn("[CLIENT]: unhandled EconomyDataRequest packet"); break; case PacketType.AgentHeightWidth: // TODO: handle this packet m_log.Warn("[CLIENT]: unhandled AgentHeightWidth packet"); break; case PacketType.ObjectSpinStop: // TODO: handle this packet m_log.Warn("[CLIENT]: unhandled ObjectSpinStop packet"); break; case PacketType.SoundTrigger: // TODO: handle this packet m_log.Warn("[CLIENT]: unhandled SoundTrigger packet"); break; //case PacketType.UserInfoRequest: // TODO: handle this packet //m_log.Warn("[CLIENT]: unhandled UserInfoRequest packet"); //break; case PacketType.InventoryDescendents: // TODO: handle this packet m_log.Warn("[CLIENT]: unhandled InventoryDescent packet"); break; default: m_log.Warn("[CLIENT]: unhandled packet " + Pack.ToString()); break; #endregion } } PacketPool.Instance.ReturnPacket(Pack); } private static PrimitiveBaseShape GetShapeFromAddPacket(ObjectAddPacket addPacket) { PrimitiveBaseShape shape = new PrimitiveBaseShape(); shape.PCode = addPacket.ObjectData.PCode; shape.State = addPacket.ObjectData.State; shape.PathBegin = addPacket.ObjectData.PathBegin; shape.PathEnd = addPacket.ObjectData.PathEnd; shape.PathScaleX = addPacket.ObjectData.PathScaleX; shape.PathScaleY = addPacket.ObjectData.PathScaleY; shape.PathShearX = addPacket.ObjectData.PathShearX; shape.PathShearY = addPacket.ObjectData.PathShearY; shape.PathSkew = addPacket.ObjectData.PathSkew; shape.ProfileBegin = addPacket.ObjectData.ProfileBegin; shape.ProfileEnd = addPacket.ObjectData.ProfileEnd; shape.Scale = addPacket.ObjectData.Scale; shape.PathCurve = addPacket.ObjectData.PathCurve; shape.ProfileCurve = addPacket.ObjectData.ProfileCurve; shape.ProfileHollow = addPacket.ObjectData.ProfileHollow; shape.PathRadiusOffset = addPacket.ObjectData.PathRadiusOffset; shape.PathRevolutions = addPacket.ObjectData.PathRevolutions; shape.PathTaperX = addPacket.ObjectData.PathTaperX; shape.PathTaperY = addPacket.ObjectData.PathTaperY; shape.PathTwist = addPacket.ObjectData.PathTwist; shape.PathTwistBegin = addPacket.ObjectData.PathTwistBegin; LLObject.TextureEntry ntex = new LLObject.TextureEntry(new LLUUID("89556747-24cb-43ed-920b-47caed15465f")); shape.TextureEntry = ntex.ToBytes(); //shape.Textures = ntex; return shape; } public void SendBlueBoxMessage(LLUUID FromAvatarID, LLUUID fromSessionID, String FromAvatarName, String Message) { if (!ChildAgentStatus()) SendInstantMessage(FromAvatarID, fromSessionID, Message, AgentId, SessionId, FromAvatarName, (byte)1, (uint)Util.UnixTimeSinceEpoch()); //SendInstantMessage(FromAvatarID, fromSessionID, Message, AgentId, SessionId, FromAvatarName, (byte)21,(uint) Util.UnixTimeSinceEpoch()); } public void SendLogoutPacket() { LogoutReplyPacket logReply = (LogoutReplyPacket)PacketPool.Instance.GetPacket(PacketType.LogoutReply); // TODO: don't create new blocks if recycling an old packet logReply.AgentData.AgentID = AgentId; logReply.AgentData.SessionID = SessionId; logReply.InventoryData = new LogoutReplyPacket.InventoryDataBlock[1]; logReply.InventoryData[0] = new LogoutReplyPacket.InventoryDataBlock(); logReply.InventoryData[0].ItemID = LLUUID.Zero; OutPacket(logReply, ThrottleOutPacketType.Task); } } }