From 1edb7992f16795ef97323eba994d5451c4df240a Mon Sep 17 00:00:00 2001 From: Sean Dague Date: Fri, 2 May 2008 19:21:33 +0000 Subject: fixed the dos line endings --- .../LindenUDP/LLClientStackNetworkHandler.cs | 74 +- .../Region/ClientStack/LindenUDP/LLClientView.cs | 9852 ++++++++++---------- .../Region/ClientStack/LindenUDP/LLPacketQueue.cs | 1062 +-- .../Region/ClientStack/LindenUDP/LLPacketServer.cs | 298 +- .../ClientStack/LindenUDP/LLPacketThrottle.cs | 184 +- OpenSim/Region/ClientStack/LindenUDP/LLQueItem.cs | 84 +- .../Region/ClientStack/LindenUDP/LLUDPServer.cs | 1016 +- 7 files changed, 6285 insertions(+), 6285 deletions(-) (limited to 'OpenSim/Region/ClientStack/LindenUDP') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientStackNetworkHandler.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientStackNetworkHandler.cs index c1989a5..857ce13 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientStackNetworkHandler.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientStackNetworkHandler.cs @@ -1,38 +1,38 @@ -/* - * 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.Net.Sockets; - -namespace OpenSim.Region.ClientStack.LindenUDP -{ - public interface LLClientStackNetworkHandler - { - void SendPacketTo(byte[] buffer, int size, SocketFlags flags, uint circuitcode); // EndPoint packetSender); - void RemoveClientCircuit(uint circuitcode); - void RegisterPacketServer(LLPacketServer server); - } +/* + * 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.Net.Sockets; + +namespace OpenSim.Region.ClientStack.LindenUDP +{ + public interface LLClientStackNetworkHandler + { + void SendPacketTo(byte[] buffer, int size, SocketFlags flags, uint circuitcode); // EndPoint packetSender); + void RemoveClientCircuit(uint circuitcode); + void RegisterPacketServer(LLPacketServer server); + } } \ No newline at end of file diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index f4dd127..9d77a14 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -1,4927 +1,4927 @@ -/* - * 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.Reflection; -using System.Text; -using System.Threading; -using System.Timers; -using Axiom.Math; -using libsecondlife; -using libsecondlife.Packets; -using log4net; -using OpenSim.Framework; -using OpenSim.Framework.Communications.Cache; -using OpenSim.Region.ClientStack.LindenUDP; -using OpenSim.Region.Environment.Scenes; -using Timer=System.Timers.Timer; - -namespace OpenSim.Region.ClientStack.LindenUDP -{ - public delegate bool PacketMethod(IClientAPI simClient, Packet packet); - - /// - /// Handles new client connections - /// Constructor takes a single Packet and authenticates everything - /// - public class LLClientView : IClientAPI - { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - // ~ClientView() - // { - // m_log.Info("[CLIENTVIEW]: Destructor called"); - // } - - /* static variables */ - public static TerrainManager TerrainManager; - - public delegate bool SynchronizeClientHandler(IScene scene, Packet packet, LLUUID agentID, ThrottleOutPacketType throttlePacketType); - public static SynchronizeClientHandler SynchronizeClient = null; - /* 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 bool m_clientBlocked = false; - - 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 LLUUID m_agentId; - private readonly uint m_circuitCode; - private int m_moneyBalance; - - private int m_animationSequenceNumber = 1; - - 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 LLPacketQueue 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 LLPacketServer m_networkServer; - - /* public variables */ - protected string m_firstName; - protected string m_lastName; - protected Thread m_clientThread; - protected LLVector3 m_startpos; - protected EndPoint m_userEndPoint; - protected EndPoint m_proxyEndPoint; - - /* Instantiated Designated Event Delegates */ - //- used so we don't create new objects for each incoming packet and then toss it out later */ - - private RequestAvatarProperties handlerRequestAvatarProperties = null; //OnRequestAvatarProperties; - private UpdateAvatarProperties handlerUpdateAvatarProperties = null; // OnUpdateAvatarProperties; - private ChatFromViewer handlerChatFromViewer = null; //OnChatFromViewer; - private ChatFromViewer handlerChatFromViewer2 = null; //OnChatFromViewer; - private ImprovedInstantMessage handlerInstantMessage = null; //OnInstantMessage; - private FriendActionDelegate handlerApproveFriendRequest = null; //OnApproveFriendRequest; - private FriendshipTermination handlerTerminateFriendship = null; //OnTerminateFriendship; - private RezObject handlerRezObject = null; //OnRezObject; - private GenericCall4 handlerDeRezObject = null; //OnDeRezObject; - private ModifyTerrain handlerModifyTerrain = null; - private Action handlerRegionHandShakeReply = null; //OnRegionHandShakeReply; - private GenericCall2 handlerRequestWearables = null; //OnRequestWearables; - private Action handlerRequestAvatarsData = null; //OnRequestAvatarsData; - private SetAppearance handlerSetAppearance = null; //OnSetAppearance; - private AvatarNowWearing handlerAvatarNowWearing = null; //OnAvatarNowWearing; - private RezSingleAttachmentFromInv handlerRezSingleAttachment = null; //OnRezSingleAttachmentFromInv; - private UUIDNameRequest handlerDetachAttachmentIntoInv = null; // Detach attachment! - private ObjectAttach handlerObjectAttach = null; //OnObjectAttach; - private SetAlwaysRun handlerSetAlwaysRun = null; //OnSetAlwaysRun; - private GenericCall2 handlerCompleteMovementToRegion = null; //OnCompleteMovementToRegion; - private UpdateAgent handlerAgentUpdate = null; //OnAgentUpdate; - private StartAnim handlerStartAnim = null; - private StopAnim handlerStopAnim = null; - private AgentRequestSit handlerAgentRequestSit = null; //OnAgentRequestSit; - private AgentSit handlerAgentSit = null; //OnAgentSit; - private AvatarPickerRequest handlerAvatarPickerRequest = null; //OnAvatarPickerRequest; - private FetchInventory handlerAgentDataUpdateRequest = null; //OnAgentDataUpdateRequest; - private FetchInventory handlerUserInfoRequest = null; //OnUserInfoRequest; - private TeleportLocationRequest handlerSetStartLocationRequest = null; //OnSetStartLocationRequest; - private TeleportLandmarkRequest handlerTeleportLandmarkRequest = null; //OnTeleportLandmarkRequest; - private LinkObjects handlerLinkObjects = null; //OnLinkObjects; - private DelinkObjects handlerDelinkObjects = null; //OnDelinkObjects; - private AddNewPrim handlerAddPrim = null; //OnAddPrim; - private UpdateShape handlerUpdatePrimShape = null; //null; - private ObjectExtraParams handlerUpdateExtraParams = null; //OnUpdateExtraParams; - private ObjectDuplicate handlerObjectDuplicate = null; - private ObjectDuplicateOnRay handlerObjectDuplicateOnRay = null; - private ObjectSelect handlerObjectSelect = null; - private ObjectDeselect handlerObjectDeselect = null; - private ObjectIncludeInSearch handlerObjectIncludeInSearch = null; - private UpdatePrimFlags handlerUpdatePrimFlags = null; //OnUpdatePrimFlags; - private UpdatePrimTexture handlerUpdatePrimTexture = null; - private UpdateVector handlerGrabObject = null; //OnGrabObject; - private MoveObject handlerGrabUpdate = null; //OnGrabUpdate; - private ObjectSelect handlerDeGrabObject = null; //OnDeGrabObject; - private GenericCall7 handlerObjectDescription = null; - private GenericCall7 handlerObjectName = null; - private ObjectPermissions handlerObjectPermissions = null; - private RequestObjectPropertiesFamily handlerRequestObjectPropertiesFamily = null; //OnRequestObjectPropertiesFamily; - private TextureRequest handlerTextureRequest = null; - private UDPAssetUploadRequest handlerAssetUploadRequest = null; //OnAssetUploadRequest; - private RequestXfer handlerRequestXfer = null; //OnRequestXfer; - private XferReceive handlerXferReceive = null; //OnXferReceive; - private ConfirmXfer handlerConfirmXfer = null; //OnConfirmXfer; - private CreateInventoryFolder handlerCreateInventoryFolder = null; //OnCreateNewInventoryFolder; - private UpdateInventoryFolder handlerUpdateInventoryFolder = null; - private MoveInventoryFolder handlerMoveInventoryFolder = null; - private CreateNewInventoryItem handlerCreateNewInventoryItem = null; //OnCreateNewInventoryItem; - private FetchInventory handlerFetchInventory = null; - private FetchInventoryDescendents handlerFetchInventoryDescendents = null; //OnFetchInventoryDescendents; - private PurgeInventoryDescendents handlerPurgeInventoryDescendents = null; //OnPurgeInventoryDescendents; - private UpdateInventoryItem handlerUpdateInventoryItem = null; - private CopyInventoryItem handlerCopyInventoryItem = null; - private MoveInventoryItem handlerMoveInventoryItem = null; - private RemoveInventoryItem handlerRemoveInventoryItem = null; - private RemoveInventoryFolder handlerRemoveInventoryFolder = null; - private RequestTaskInventory handlerRequestTaskInventory = null; //OnRequestTaskInventory; - private UpdateTaskInventory handlerUpdateTaskInventory = null; //OnUpdateTaskInventory; - private MoveTaskInventory handlerMoveTaskItem = null; - private RemoveTaskInventory handlerRemoveTaskItem = null; //OnRemoveTaskItem; - private RezScript handlerRezScript = null; //OnRezScript; - private RequestMapBlocks handlerRequestMapBlocks = null; //OnRequestMapBlocks; - private RequestMapName handlerMapNameRequest = null; //OnMapNameRequest; - private TeleportLocationRequest handlerTeleportLocationRequest = null; //OnTeleportLocationRequest; - private MoneyBalanceRequest handlerMoneyBalanceRequest = null; //OnMoneyBalanceRequest; - private UUIDNameRequest handlerNameRequest = null; - private ParcelAccessListRequest handlerParcelAccessListRequest = null; //OnParcelAccessListRequest; - private ParcelAccessListUpdateRequest handlerParcelAccessListUpdateRequest = null; //OnParcelAccessListUpdateRequest; - private ParcelPropertiesRequest handlerParcelPropertiesRequest = null; //OnParcelPropertiesRequest; - private ParcelDivideRequest handlerParcelDivideRequest = null; //OnParcelDivideRequest; - private ParcelJoinRequest handlerParcelJoinRequest = null; //OnParcelJoinRequest; - private ParcelPropertiesUpdateRequest handlerParcelPropertiesUpdateRequest = null; //OnParcelPropertiesUpdateRequest; - private ParcelSelectObjects handlerParcelSelectObjects = null; //OnParcelSelectObjects; - private ParcelObjectOwnerRequest handlerParcelObjectOwnerRequest = null; //OnParcelObjectOwnerRequest; - private EstateOwnerMessageRequest handlerEstateOwnerMessage = null; //OnEstateOwnerMessage; - private RegionInfoRequest handlerRegionInfoRequest = null; //OnRegionInfoRequest; - private EstateCovenantRequest handlerEstateCovenantRequest = null; //OnEstateCovenantRequest; - private RequestGodlikePowers handlerReqGodlikePowers = null; //OnRequestGodlikePowers; - private GodKickUser handlerGodKickUser = null; //OnGodKickUser; - private ViewerEffectEventHandler handlerViewerEffect = null; //OnViewerEffect; - private Action handlerLogout = null; //OnLogout; - private MoneyTransferRequest handlerMoneyTransferRequest = null; //OnMoneyTransferRequest; - private ParcelBuy handlerParcelBuy = null; - private EconomyDataRequest handlerEconomoyDataRequest = null; - - private UpdateVector handlerUpdatePrimSinglePosition = null; //OnUpdatePrimSinglePosition; - private UpdatePrimSingleRotation handlerUpdatePrimSingleRotation = null; //OnUpdatePrimSingleRotation; - private UpdateVector handlerUpdatePrimScale = null; //OnUpdatePrimScale; - private UpdateVector handlerUpdatePrimGroupScale = null; //OnUpdateGroupScale; - private UpdateVector handlerUpdateVector = null; //OnUpdatePrimGroupPosition; - private UpdatePrimRotation handlerUpdatePrimRotation = null; //OnUpdatePrimGroupRotation; - private UpdatePrimGroupRotation handlerUpdatePrimGroupRotation = null; //OnUpdatePrimGroupMouseRotation; - private PacketStats handlerPacketStats = null; // OnPacketStats;# - private RequestAsset handlerRequestAsset = null; // OnRequestAsset; - private UUIDNameRequest handlerTeleportHomeRequest = null; - - private ScriptAnswer handlerScriptAnswer = null; - private RequestPayPrice handlerRequestPayPrice = null; - private ObjectDeselect handlerObjectDetach = null; - private AgentSit handlerOnUndo = null; - - /* 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; } - } - - public int NextAnimationSequenceNumber - { - get { return m_animationSequenceNumber++; } - } - - /* METHODS */ - - public LLClientView(EndPoint remoteEP, IScene scene, AssetCache assetCache, LLPacketServer packServer, - AgentCircuitManager authenSessions, LLUUID agentId, LLUUID sessionId, uint circuitCode, EndPoint proxyEP) - { - 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_proxyEndPoint = proxyEP; - - 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 LLPacketQueue(agentId); - - RegisterLocalPacketHandlers(); - - m_clientThread = new Thread(new ThreadStart(AuthUser)); - m_clientThread.Name = "ClientThread"; - m_clientThread.IsBackground = true; - m_clientThread.Start(); - ThreadTracker.Add(m_clientThread); - } - - public void SetDebug(int newDebug) - { - m_debug = newDebug; - } - - # region Client Methods - - private void CloseCleanup(bool shutdownCircuit) - { - 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.Unknown); - - m_packetQueue.Close(); - - 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 (!(shutdownCircuit)) - { - 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 shutdownCircuit) - { - // Pull Client out of Region - m_log.Info("[CLIENT]: Close has been called"); - m_packetQueue.Flush(); - - //raiseevent on the packet server to Shutdown the circuit - if (shutdownCircuit) - { - OnConnectionClosed(this); - } - - CloseCleanup(shutdownCircuit); - } - - 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() - { - // Shut down timers - m_ackTimer.Stop(); - m_clientPingTimer.Stop(); - } - - public void Restart() - { - // re-construct - m_pendingAcks = new Dictionary(); - m_needAck = new Dictionary(); - m_sequence += 1000000; - - 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; - } - - public void Terminate() - { - // disable blocking queue - m_packetQueue.Enqueue(null); - - // wait for thread stoped - m_clientThread.Join(); - - // delete circuit code - m_networkServer.CloseClient(this); - } - - #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; - } - - /// - /// Try to process a packet using registered packet handlers - /// - /// - /// True if a handler was found which successfully processed the packet. - 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) - { - LLQueItem nextPacket = m_packetQueue.Dequeue(); - if (nextPacket == null) - { - break; - } - 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 && !m_clientBlocked) || (m_probesWithNoIngressPackets > 90 && m_clientBlocked)) - { - - 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.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 UUIDNameRequest OnDetachAttachmentIntoInv; - public event ObjectAttach OnObjectAttach; - public event ObjectDeselect OnObjectDetach; - 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 ObjectDuplicateOnRay OnObjectDuplicateOnRay; - 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 ObjectIncludeInSearch OnObjectIncludeInSearch; - 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 UpdateVector OnUpdatePrimGroupScale; - 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 TeleportLandmarkRequest OnTeleportLandmarkRequest; - 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 UpdateAvatarProperties OnUpdateAvatarProperties; - - - 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 MoveTaskInventory OnMoveTaskItem; - public event RemoveTaskInventory OnRemoveTaskItem; - public event RequestAsset OnRequestAsset; - - 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 EconomyDataRequest OnEconomyDataRequest; - - public event MoneyBalanceRequest OnMoneyBalanceRequest; - public event ParcelBuy OnParcelBuy; - - public event UUIDNameRequest OnTeleportHomeRequest; - - public event ScriptAnswer OnScriptAnswer; - public event RequestPayPrice OnRequestPayPrice; - public event AgentSit OnUndo; - - #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); - } - - /// - /// Send an instant message to this client - /// - /// - /// - public void SendInstantMessage(LLUUID fromAgent, LLUUID fromAgentSession, string message, LLUUID toAgent, - LLUUID imSessionID, string fromName, byte dialog, uint timeStamp) - { - SendInstantMessage( - fromAgent, fromAgentSession, message, toAgent, - imSessionID, fromName, dialog, timeStamp, new byte[0]); - } - - /// - /// Send an instant message to this client - /// - /// - /// - public void SendInstantMessage(LLUUID fromAgent, LLUUID fromAgentSession, string message, LLUUID toAgent, - LLUUID imSessionID, string fromName, byte dialog, uint timeStamp, - byte[] binaryBucket) - { - 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 = binaryBucket; - - 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 = LLClientView.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 = LLClientView.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 = m_scene.GetCapsPath(m_agentId); - 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 SendPayPrice(LLUUID objectID, int[] payPrice) - { - if(payPrice[0] == 0 && - payPrice[1] == 0 && - payPrice[2] == 0 && - payPrice[3] == 0 && - payPrice[4] == 0) - return; - - PayPriceReplyPacket payPriceReply = (PayPriceReplyPacket)PacketPool.Instance.GetPacket(PacketType.PayPriceReply); - payPriceReply.ObjectData.ObjectID = objectID; - payPriceReply.ObjectData.DefaultPayPrice = payPrice[0]; - - payPriceReply.ButtonData=new PayPriceReplyPacket.ButtonDataBlock[4]; - payPriceReply.ButtonData[0]=new PayPriceReplyPacket.ButtonDataBlock(); - payPriceReply.ButtonData[0].PayButton = payPrice[1]; - payPriceReply.ButtonData[1]=new PayPriceReplyPacket.ButtonDataBlock(); - payPriceReply.ButtonData[1].PayButton = payPrice[2]; - payPriceReply.ButtonData[2]=new PayPriceReplyPacket.ButtonDataBlock(); - payPriceReply.ButtonData[2].PayButton = payPrice[3]; - payPriceReply.ButtonData[3]=new PayPriceReplyPacket.ButtonDataBlock(); - payPriceReply.ButtonData[3].PayButton = payPrice[4]; - - OutPacket(payPriceReply, 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.Unknown); - } - - 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; - -//Ckrinke This variable is not used, so comment out to remove the warning from the compiler (3-21-08) -//Ckrinke uint FULL_MASK_PERMISSIONS = 2147483647; - - if (fetchItems) - { - InventoryDescendentsPacket 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; - } - - int count = 0; - int i = 0; - foreach (InventoryItemBase item in items) - { - descend.ItemData[i] = new InventoryDescendentsPacket.ItemDataBlock(); - descend.ItemData[i].ItemID = item.ID; - descend.ItemData[i].AssetID = item.AssetID; - descend.ItemData[i].CreatorID = item.Creator; - descend.ItemData[i].BaseMask = item.BasePermissions; - descend.ItemData[i].Description = Helpers.StringToField(item.Description); - descend.ItemData[i].EveryoneMask = item.EveryOnePermissions; - descend.ItemData[i].OwnerMask = item.CurrentPermissions; - descend.ItemData[i].FolderID = item.Folder; - descend.ItemData[i].InvType = (sbyte)item.InvType; - descend.ItemData[i].Name = Helpers.StringToField(item.Name); - descend.ItemData[i].NextOwnerMask = item.NextPermissions; - descend.ItemData[i].OwnerID = item.Owner; - descend.ItemData[i].Type = (sbyte)item.AssetType; - - //descend.ItemData[i].GroupID = new LLUUID("00000000-0000-0000-0000-000000000000"); - descend.ItemData[i].GroupID = item.GroupID; - descend.ItemData[i].GroupOwned = item.GroupOwned; - descend.ItemData[i].GroupMask = 0; - descend.ItemData[i].CreationDate = item.CreationDate; - descend.ItemData[i].SalePrice = item.SalePrice; - descend.ItemData[i].SaleType = item.SaleType; - descend.ItemData[i].Flags = item.Flags; - - 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.CurrentPermissions); - - 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 - if (fetchFolders) - { - InventoryDescendentsPacket 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; - } - - int i = 0; - int count = 0; - foreach (InventoryFolderBase folder in folders) - { - descend.FolderData[i] = new InventoryDescendentsPacket.FolderDataBlock(); - descend.FolderData[i].FolderID = folder.ID; - 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 = 1; - - return descend; - } - - public void SendInventoryItemDetails(LLUUID ownerID, InventoryItemBase item) - { - 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.ID; - inventoryReply.InventoryData[0].AssetID = item.AssetID; - inventoryReply.InventoryData[0].CreatorID = item.Creator; - inventoryReply.InventoryData[0].BaseMask = item.BasePermissions; - inventoryReply.InventoryData[0].CreationDate = - (int)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds; - inventoryReply.InventoryData[0].Description = Helpers.StringToField(item.Description); - inventoryReply.InventoryData[0].EveryoneMask = item.EveryOnePermissions; - inventoryReply.InventoryData[0].FolderID = item.Folder; - inventoryReply.InventoryData[0].InvType = (sbyte)item.InvType; - inventoryReply.InventoryData[0].Name = Helpers.StringToField(item.Name); - inventoryReply.InventoryData[0].NextOwnerMask = item.NextPermissions; - inventoryReply.InventoryData[0].OwnerID = item.Owner; - inventoryReply.InventoryData[0].OwnerMask = item.CurrentPermissions; - inventoryReply.InventoryData[0].Type = (sbyte)item.AssetType; - - //inventoryReply.InventoryData[0].GroupID = new LLUUID("00000000-0000-0000-0000-000000000000"); - inventoryReply.InventoryData[0].GroupID = item.GroupID; - inventoryReply.InventoryData[0].GroupOwned = item.GroupOwned; - inventoryReply.InventoryData[0].GroupMask = 0; - inventoryReply.InventoryData[0].Flags = item.Flags; - inventoryReply.InventoryData[0].SalePrice = item.SalePrice; - inventoryReply.InventoryData[0].SaleType = item.SaleType; - - 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.SendBulkUpdateInventory(InventoryItemBase) - public void SendBulkUpdateInventory(InventoryItemBase item) - { - uint FULL_MASK_PERMISSIONS = (uint)PermissionMask.All; - - BulkUpdateInventoryPacket bulkUpdate - = (BulkUpdateInventoryPacket)PacketPool.Instance.GetPacket(PacketType.BulkUpdateInventory); - - bulkUpdate.AgentData.AgentID = AgentId; - bulkUpdate.AgentData.TransactionID = LLUUID.Random(); - - bulkUpdate.FolderData = new BulkUpdateInventoryPacket.FolderDataBlock[1]; - bulkUpdate.FolderData[0] = new BulkUpdateInventoryPacket.FolderDataBlock(); - bulkUpdate.FolderData[0].FolderID = LLUUID.Zero; - bulkUpdate.FolderData[0].ParentID = LLUUID.Zero; - bulkUpdate.FolderData[0].Type = -1; - bulkUpdate.FolderData[0].Name = new byte[0]; - - bulkUpdate.ItemData = new BulkUpdateInventoryPacket.ItemDataBlock[1]; - bulkUpdate.ItemData[0] = new BulkUpdateInventoryPacket.ItemDataBlock(); - bulkUpdate.ItemData[0].ItemID = item.ID; - bulkUpdate.ItemData[0].AssetID = item.AssetID; - bulkUpdate.ItemData[0].CreatorID = item.Creator; - bulkUpdate.ItemData[0].BaseMask = item.BasePermissions; - bulkUpdate.ItemData[0].CreationDate = 1000; - bulkUpdate.ItemData[0].Description = Helpers.StringToField(item.Description); - bulkUpdate.ItemData[0].EveryoneMask = item.EveryOnePermissions; - bulkUpdate.ItemData[0].FolderID = item.Folder; - bulkUpdate.ItemData[0].InvType = (sbyte)item.InvType; - bulkUpdate.ItemData[0].Name = Helpers.StringToField(item.Name); - bulkUpdate.ItemData[0].NextOwnerMask = item.NextPermissions; - bulkUpdate.ItemData[0].OwnerID = item.Owner; - bulkUpdate.ItemData[0].OwnerMask = item.CurrentPermissions; - bulkUpdate.ItemData[0].Type = (sbyte)item.AssetType; - - //bulkUpdate.ItemData[0].GroupID = new LLUUID("00000000-0000-0000-0000-000000000000"); - bulkUpdate.ItemData[0].GroupID = item.GroupID; - bulkUpdate.ItemData[0].GroupOwned = item.GroupOwned; - bulkUpdate.ItemData[0].GroupMask = 0; - bulkUpdate.ItemData[0].Flags = item.Flags; - bulkUpdate.ItemData[0].SalePrice = item.SalePrice; - bulkUpdate.ItemData[0].SaleType = item.SaleType; - - bulkUpdate.ItemData[0].CRC = - Helpers.InventoryCRC(1000, 0, bulkUpdate.ItemData[0].InvType, - bulkUpdate.ItemData[0].Type, bulkUpdate.ItemData[0].AssetID, - bulkUpdate.ItemData[0].GroupID, 100, - bulkUpdate.ItemData[0].OwnerID, bulkUpdate.ItemData[0].CreatorID, - bulkUpdate.ItemData[0].ItemID, bulkUpdate.ItemData[0].FolderID, - FULL_MASK_PERMISSIONS, 1, FULL_MASK_PERMISSIONS, FULL_MASK_PERMISSIONS, - FULL_MASK_PERMISSIONS); - - OutPacket(bulkUpdate, ThrottleOutPacketType.Asset); - } - - /// IClientAPI.SendInventoryItemCreateUpdate(InventoryItemBase) - public void SendInventoryItemCreateUpdate(InventoryItemBase Item) - { - 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.ID; - InventoryReply.InventoryData[0].AssetID = Item.AssetID; - InventoryReply.InventoryData[0].CreatorID = Item.Creator; - InventoryReply.InventoryData[0].BaseMask = Item.BasePermissions; - InventoryReply.InventoryData[0].Description = Helpers.StringToField(Item.Description); - InventoryReply.InventoryData[0].EveryoneMask = Item.EveryOnePermissions; - InventoryReply.InventoryData[0].FolderID = Item.Folder; - InventoryReply.InventoryData[0].InvType = (sbyte)Item.InvType; - InventoryReply.InventoryData[0].Name = Helpers.StringToField(Item.Name); - InventoryReply.InventoryData[0].NextOwnerMask = Item.NextPermissions; - InventoryReply.InventoryData[0].OwnerID = Item.Owner; - InventoryReply.InventoryData[0].OwnerMask = Item.CurrentPermissions; - InventoryReply.InventoryData[0].Type = (sbyte)Item.AssetType; - - //InventoryReply.InventoryData[0].GroupID = new LLUUID("00000000-0000-0000-0000-000000000000"); - InventoryReply.InventoryData[0].GroupID = Item.GroupID; - InventoryReply.InventoryData[0].GroupOwned = Item.GroupOwned; - InventoryReply.InventoryData[0].GroupMask = 0; - InventoryReply.InventoryData[0].Flags = Item.Flags; - InventoryReply.InventoryData[0].SalePrice = Item.SalePrice; - InventoryReply.InventoryData[0].SaleType = Item.SaleType; - - 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 SendEconomyData(float EnergyEfficiency, int ObjectCapacity, int ObjectCount, int PriceEnergyUnit, - int PriceGroupCreate, int PriceObjectClaim, float PriceObjectRent, float PriceObjectScaleFactor, - int PriceParcelClaim, float PriceParcelClaimFactor, int PriceParcelRent, int PricePublicObjectDecay, - int PricePublicObjectDelete, int PriceRentLight, int PriceUpload, int TeleportMinPrice, float TeleportPriceExponent) - { - EconomyDataPacket economyData = (EconomyDataPacket)PacketPool.Instance.GetPacket(PacketType.EconomyData); - economyData.Info.EnergyEfficiency = EnergyEfficiency; - economyData.Info.ObjectCapacity = ObjectCapacity; - economyData.Info.ObjectCount = ObjectCount; - economyData.Info.PriceEnergyUnit = PriceEnergyUnit; - economyData.Info.PriceGroupCreate = PriceGroupCreate; - economyData.Info.PriceObjectClaim = PriceObjectClaim; - economyData.Info.PriceObjectRent = PriceObjectRent; - economyData.Info.PriceObjectScaleFactor = PriceObjectScaleFactor; - economyData.Info.PriceParcelClaim = PriceParcelClaim; - economyData.Info.PriceParcelClaimFactor = PriceParcelClaimFactor; - economyData.Info.PriceParcelRent = PriceParcelRent; - economyData.Info.PricePublicObjectDecay = PricePublicObjectDecay; - economyData.Info.PricePublicObjectDelete = PricePublicObjectDelete; - economyData.Info.PriceRentLight = PriceRentLight; - economyData.Info.PriceUpload = PriceUpload; - economyData.Info.TeleportMinPrice = TeleportMinPrice; - economyData.Info.TeleportPriceExponent = TeleportPriceExponent; - economyData.Header.Reliable = true; - OutPacket(economyData, ThrottleOutPacketType.Unknown); - - } - - 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); - } - - /// - /// Send an alert message to the client. On the Linden client (tested 1.19.1.4), this pops up a brief duration - /// blue information box in the bottom right hand corner. - /// - /// - public void SendAlertMessage(string message) - { - AlertMessagePacket alertPack = (AlertMessagePacket)PacketPool.Instance.GetPacket(PacketType.AlertMessage); - alertPack.AlertData.Message = Helpers.StringToField(message); - OutPacket(alertPack, ThrottleOutPacketType.Task); - } - - /// - /// Send an agent alert message to the client. - /// - /// - /// On the linden client, if this true then it displays a one button text box placed in the - /// middle of the window. If false, the message is displayed in a brief duration blue information box (as for - /// the AlertMessage packet). - 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 SendAttachedSoundGainChange(LLUUID objectID, float gain) - { - AttachedSoundGainChangePacket sound = (AttachedSoundGainChangePacket)PacketPool.Instance.GetPacket(PacketType.AttachedSoundGainChange); - sound.DataBlock.ObjectID = objectID; - sound.DataBlock.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; - if (aboutText != null) - avatarReply.PropertiesData.AboutText = Helpers.StringToField(aboutText); - else - avatarReply.PropertiesData.AboutText = Helpers.StringToField(""); - avatarReply.PropertiesData.BornOn = Helpers.StringToField(bornOn); - avatarReply.PropertiesData.CharterMember = Helpers.StringToField(charterMember); - if (flAbout != null) - avatarReply.PropertiesData.FLAboutText = Helpers.StringToField(flAbout); - else - avatarReply.PropertiesData.FLAboutText = Helpers.StringToField(""); - 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); - 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, false,(uint)0, LLUUID.Zero); - } - 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, bool attachment, uint AttachPoint, LLUUID AssetId) - { - 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; - - // Anything more than 255 will cause libsecondlife to barf - if (text.Length > 255) - { - text = text.Remove(255); - } - - 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; - - if (attachment) - { - // Necessary??? - outPacket.ObjectData[0].JointAxisOrAnchor = new LLVector3(0, 0, 2); - outPacket.ObjectData[0].JointPivot = new LLVector3(0, 0, 0); - - // Item from inventory??? - outPacket.ObjectData[0].NameValue = - Helpers.StringToField("AttachItemID STRING RW SV " + AssetId.UUID); - outPacket.ObjectData[0].State = (byte)((AttachPoint % 16) * 16 + (AttachPoint / 16)); - } - - // 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, byte state, LLUUID AssetId) - { - 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, state); // AssetID should fall into here probably somehow... - 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, 0); - 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, - byte state) - { - 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++] = state; - 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); - - if ((primShape.PCode == (byte)PCode.NewTree) || (primShape.PCode == (byte)PCode.Tree) || (primShape.PCode == (byte)PCode.Grass)) - { - objupdate.Data = new byte[1]; - objupdate.Data[0] = primShape.State; - } - 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 = (byte)PCode.Avatar; - if (textureEntry != null) - { - objdata.TextureEntry = textureEntry; - } - LLVector3 pos = new LLVector3(objdata.ObjectData, 16); - pos.X = 100f; - objdata.ID = 8880000; - objdata.NameValue = Helpers.StringToField("FirstName STRING RW SV Test \nLastName STRING RW SV User "); - //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); - AddLocalPacketHandler(PacketType.ParcelBuy, HandleParcelBuyRequest); - } - - 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) - { - handlerMoneyTransferRequest = OnMoneyTransferRequest; - if (handlerMoneyTransferRequest != null) - { - handlerMoneyTransferRequest(money.MoneyData.SourceID, money.MoneyData.DestID, - money.MoneyData.Amount, money.MoneyData.TransactionType, - Util.FieldToString(money.MoneyData.Description)); - } - - return true; - } - else - { - return false; - } - } - - private bool HandleParcelBuyRequest(IClientAPI sender, Packet Pack) - { - ParcelBuyPacket parcel = (ParcelBuyPacket)Pack; - if (parcel.AgentData.AgentID == AgentId && parcel.AgentData.SessionID == this.SessionId) - { - handlerParcelBuy = OnParcelBuy; - if (handlerParcelBuy != null) - { - handlerParcelBuy(parcel.AgentData.AgentID, parcel.Data.GroupID, parcel.Data.Final, parcel.Data.IsGroupOwned, - parcel.Data.RemoveContribution, parcel.Data.LocalID, parcel.ParcelData.Area, parcel.ParcelData.Price, - false); - } - return true; - - } - else - { - return false; - } - - } - - private bool HandleViewerEffect(IClientAPI sender, Packet Pack) - { - ViewerEffectPacket viewer = (ViewerEffectPacket)Pack; - handlerViewerEffect = OnViewerEffect; - if (handlerViewerEffect != null) - { - handlerViewerEffect(sender, viewer.Effect); - } - - return true; - } - - public void SendScriptQuestion(LLUUID taskID, string taskName, string ownerName, LLUUID itemID, int question) - { - ScriptQuestionPacket scriptQuestion = (ScriptQuestionPacket)PacketPool.Instance.GetPacket(PacketType.ScriptQuestion); - scriptQuestion.Data = new ScriptQuestionPacket.DataBlock(); - // TODO: don't create new blocks if recycling an old packet - scriptQuestion.Data.TaskID = taskID; - scriptQuestion.Data.ItemID = itemID; - scriptQuestion.Data.Questions = question; - scriptQuestion.Data.ObjectName = Helpers.StringToField(taskName); - scriptQuestion.Data.ObjectOwner = Helpers.StringToField(ownerName); - - OutPacket(scriptQuestion, ThrottleOutPacketType.Task); - } - - protected virtual bool Logout(IClientAPI client, Packet packet) - { - m_log.Info("[CLIENT]: Got a logout request"); - - handlerLogout = OnLogout; - - if (handlerLogout != null) - { - handlerLogout(client); - } - - return true; - } - - /// - /// Send a response back to a client when it asks the asset server (via the region server) if it has - /// its appearance texture cached. - /// - /// At the moment, we always reply that there is no cached texture. - /// - /// - /// - /// - protected bool AgentTextureCached(IClientAPI simclient, Packet packet) - { - //Console.WriteLine("texture cached: " + packet.ToString()); - AgentCachedTexturePacket cachedtex = (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[cachedtex.WearableData.Length]; - - for (int i = 0; i < cachedtex.WearableData.Length; i++) - { - cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock(); - cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex; - cachedresp.WearableData[i].TextureID = LLUUID.Zero; - cachedresp.WearableData[i].HostName = new byte[0]; - } - - // Temporarily throw these packets on to the wind queue, so we can identify whether these - // are somehow the source of the packet bloat. - OutPacket(cachedresp, ThrottleOutPacketType.Wind); - return true; - } - - protected bool MultipleObjUpdate(IClientAPI simClient, Packet packet) - { - MultipleObjectUpdatePacket multipleupdate = (MultipleObjectUpdatePacket)packet; - // 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; - UpdatePrimRotation handlerUpdatePrimRotation = OnUpdatePrimGroupRotation; - UpdatePrimGroupRotation handlerUpdatePrimGroupRotation = OnUpdatePrimGroupMouseRotation; - - switch (block.Type) - { - case 1: - LLVector3 pos1 = new LLVector3(block.Data, 0); - - handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; - if (handlerUpdatePrimSinglePosition != null) - { - - // Console.WriteLine("new movement position is " + pos.X + " , " + pos.Y + " , " + pos.Z); - handlerUpdatePrimSinglePosition(localId, pos1, this); - } - break; - case 2: - LLQuaternion rot1 = new LLQuaternion(block.Data, 0, true); - - handlerUpdatePrimSingleRotation = OnUpdatePrimSingleRotation; - if (handlerUpdatePrimSingleRotation != null) - { - - //Console.WriteLine("new tab rotation is " + rot.X + " , " + rot.Y + " , " + rot.Z + " , " + rot.W); - handlerUpdatePrimSingleRotation(localId, rot1, this); - } - break; - case 3: - - LLQuaternion rot2 = new LLQuaternion(block.Data, 12, true); - handlerUpdatePrimSingleRotation = OnUpdatePrimSingleRotation; - if (handlerUpdatePrimSingleRotation != null) - { - - //Console.WriteLine("new mouse rotation is " + rot.X + " , " + rot.Y + " , " + rot.Z + " , " + rot.W); - handlerUpdatePrimSingleRotation(localId, rot2, this); - } - break; - case 5: - - LLVector3 scale1 = new LLVector3(block.Data, 12); - LLVector3 pos11 = new LLVector3(block.Data, 0); - - handlerUpdatePrimScale = OnUpdatePrimScale; - if (handlerUpdatePrimScale != null) - { - - // Console.WriteLine("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z); - handlerUpdatePrimScale(localId, scale1, this); - - - handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; - if (handlerUpdatePrimSinglePosition != null) - { - handlerUpdatePrimSinglePosition(localId, pos11, this); - } - } - break; - case 9: - LLVector3 pos2 = new LLVector3(block.Data, 0); - - handlerUpdateVector = OnUpdatePrimGroupPosition; - - if (handlerUpdateVector != null) - { - - handlerUpdateVector(localId, pos2, this); - } - break; - case 10: - - LLQuaternion rot3 = new LLQuaternion(block.Data, 0, true); - - handlerUpdatePrimRotation = OnUpdatePrimGroupRotation; - if (handlerUpdatePrimRotation != null) - { - - // Console.WriteLine("new rotation is " + rot.X + " , " + rot.Y + " , " + rot.Z + " , " + rot.W); - handlerUpdatePrimRotation(localId, rot3, this); - } - break; - case 11: - - LLVector3 pos3 = new LLVector3(block.Data, 0); - LLQuaternion rot4 = new LLQuaternion(block.Data, 12, true); - - handlerUpdatePrimGroupRotation = OnUpdatePrimGroupMouseRotation; - if (handlerUpdatePrimGroupRotation != null) - { - - //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); - handlerUpdatePrimGroupRotation(localId, pos3, rot4, this); - } - break; - case 13: - - LLVector3 scale2 = new LLVector3(block.Data, 12); - LLVector3 pos4 = new LLVector3(block.Data, 0); - - handlerUpdatePrimScale = OnUpdatePrimScale; - if (handlerUpdatePrimScale != null) - { - - //Console.WriteLine("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z); - handlerUpdatePrimScale(localId, scale2, this); - - // Change the position based on scale (for bug number 246) - handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; - // Console.WriteLine("new movement position is " + pos.X + " , " + pos.Y + " , " + pos.Z); - if (handlerUpdatePrimSinglePosition != null) - { - handlerUpdatePrimSinglePosition(localId, pos4, this); - } - } - break; - case 29: - LLVector3 scale5 = new LLVector3(block.Data, 12); - LLVector3 pos5 = new LLVector3(block.Data, 0); - - handlerUpdatePrimGroupScale = OnUpdatePrimGroupScale; - if (handlerUpdatePrimGroupScale != null) - { - - // Console.WriteLine("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z ); - handlerUpdatePrimGroupScale(localId, scale5, this); - handlerUpdateVector = OnUpdatePrimGroupPosition; - - if (handlerUpdateVector != null) - { - - handlerUpdateVector(localId, pos5, this); - } - } - break; - case 21: - LLVector3 scale6 = new LLVector3(block.Data, 12); - LLVector3 pos6 = new LLVector3(block.Data, 0); - - handlerUpdatePrimScale = OnUpdatePrimScale; - if (handlerUpdatePrimScale != null) - { - // Console.WriteLine("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z); - handlerUpdatePrimScale(localId, scale6, this); - handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; - if (handlerUpdatePrimSinglePosition != null) - { - handlerUpdatePrimSinglePosition(localId, pos6, 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-1111-9999-000000000006"); - OutPacket(mapReply, ThrottleOutPacketType.Land); - } - - public void RequestMapBlocksX(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 - { - //Need some extra space in case we need to add proxy information to the message later - Buffer.BlockCopy(sendbuffer, 0, ZeroOutBuffer, 0, sendbuffer.Length); - m_networkServer.SendPacketTo(ZeroOutBuffer, 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) - { - if (!m_packetProcessingEnabled && NewPack.Type != PacketType.LogoutRequest) - { - PacketPool.Instance.ReturnPacket(NewPack); - return; - } - - // 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 - { - LLQueItem item = new LLQueItem(); - item.Packet = NewPack; - item.Incoming = true; - m_packetQueue.Enqueue(item); - } - } - } - - public virtual void OutPacket(Packet NewPack, ThrottleOutPacketType throttlePacketType) - { - if ((SynchronizeClient != null) && (!IsActive)) - { - // Sending packet to active client's server. - if (SynchronizeClient(m_scene, NewPack, m_agentId, throttlePacketType)) - { - return; - } - } - - LLQueItem item = new LLQueItem(); - 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() - { - handlerPacketStats = OnPacketStats; - if (handlerPacketStats != null) - { - handlerPacketStats(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; - } - } - - private bool m_packetProcessingEnabled = true; - - public bool IsActive { - get { return m_packetProcessingEnabled; } - set { m_packetProcessingEnabled = value; } - } - - protected void ProcessInPacket(Packet Pack) - { - ack_pack(Pack); - - if (ProcessPacketMethod(Pack)) - { - //there is a handler registered that handled this packet type - return; - } - else - { - switch (Pack.Type) - { - #region Scene/Avatar - - case PacketType.AvatarPropertiesRequest: - AvatarPropertiesRequestPacket avatarProperties = (AvatarPropertiesRequestPacket)Pack; - - handlerRequestAvatarProperties = OnRequestAvatarProperties; - if (handlerRequestAvatarProperties != null) - { - handlerRequestAvatarProperties(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; - - handlerChatFromViewer = OnChatFromViewer; - if (handlerChatFromViewer != null) - handlerChatFromViewer(this, args); - } - break; - case PacketType.AvatarPropertiesUpdate: - AvatarPropertiesUpdatePacket Packet = (AvatarPropertiesUpdatePacket)Pack; - - handlerUpdateAvatarProperties = OnUpdateAvatarProperties; - if (handlerUpdateAvatarProperties != null) - { - AvatarPropertiesUpdatePacket.PropertiesDataBlock Properties = Packet.PropertiesData; - UserProfileData UserProfile = new UserProfileData(); - UserProfile.ID = AgentId; - UserProfile.AboutText = Helpers.FieldToUTF8String(Properties.AboutText); - UserProfile.FirstLifeAboutText = Helpers.FieldToUTF8String(Properties.FLAboutText); - UserProfile.FirstLifeImage = Properties.FLImageID; - UserProfile.Image = Properties.ImageID; - - handlerUpdateAvatarProperties(this, UserProfile); - } - 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; - handlerChatFromViewer2 = OnChatFromViewer; - if (handlerChatFromViewer2 != null) - handlerChatFromViewer2(this, args); - } - - break; - case PacketType.ImprovedInstantMessage: - ImprovedInstantMessagePacket msgpack = (ImprovedInstantMessagePacket)Pack; - string IMfromName = Util.FieldToString(msgpack.MessageBlock.FromAgentName); - string IMmessage = Helpers.FieldToUTF8String(msgpack.MessageBlock.Message); - handlerInstantMessage = OnInstantMessage; - - if (handlerInstantMessage != null) - { - handlerInstantMessage(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); - } - - handlerApproveFriendRequest = OnApproveFriendRequest; - if (handlerApproveFriendRequest != null) - { - handlerApproveFriendRequest(this, agentID, transactionID, callingCardFolders); - } - break; - case PacketType.TerminateFriendship: - TerminateFriendshipPacket tfriendpack = (TerminateFriendshipPacket)Pack; - LLUUID listOwnerAgentID = tfriendpack.AgentData.AgentID; - LLUUID exFriendID = tfriendpack.ExBlock.OtherID; - - handlerTerminateFriendship = OnTerminateFriendship; - if (handlerTerminateFriendship != null) - { - handlerTerminateFriendship(this, listOwnerAgentID, exFriendID); - } - break; - case PacketType.RezObject: - RezObjectPacket rezPacket = (RezObjectPacket)Pack; - - handlerRezObject = OnRezObject; - if (handlerRezObject != 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()); - - handlerRezObject(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: - handlerDeRezObject = OnDeRezObject; - if (handlerDeRezObject != null) - { - handlerDeRezObject(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++) - { - handlerModifyTerrain = OnModifyTerrain; - if (handlerModifyTerrain != null) - { - handlerModifyTerrain(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: - - handlerRegionHandShakeReply = OnRegionHandShakeReply; - if (handlerRegionHandShakeReply != null) - { - handlerRegionHandShakeReply(this); - } - - break; - case PacketType.AgentWearablesRequest: - handlerRequestWearables = OnRequestWearables; - - if (handlerRequestWearables != null) - { - handlerRequestWearables(); - } - - handlerRequestAvatarsData = OnRequestAvatarsData; - - if (handlerRequestAvatarsData != null) - { - handlerRequestAvatarsData(this); - } - - break; - case PacketType.AgentSetAppearance: - AgentSetAppearancePacket appear = (AgentSetAppearancePacket)Pack; - - handlerSetAppearance = OnSetAppearance; - if (handlerSetAppearance != null) - { - // Temporarily protect ourselves from the mantis #951 failure. - // However, we could do this for several other handlers where a failure isn't terminal - // for the client session anyway, in order to protect ourselves against bad code in plugins - try - { - handlerSetAppearance(appear.ObjectData.TextureEntry, appear.VisualParam); - } - catch (Exception e) - { - m_log.ErrorFormat( - "[CLIENT VIEW]: AgentSetApperance packet handler threw an exception, {0}", - e); - } - } - - 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); - } - - handlerAvatarNowWearing = OnAvatarNowWearing; - if (handlerAvatarNowWearing != null) - { - handlerAvatarNowWearing(this, wearingArgs); - } - } - break; - case PacketType.RezSingleAttachmentFromInv: - handlerRezSingleAttachment = OnRezSingleAttachmentFromInv; - if (handlerRezSingleAttachment != null) - { - RezSingleAttachmentFromInvPacket rez = (RezSingleAttachmentFromInvPacket)Pack; - handlerRezSingleAttachment(this, rez.ObjectData.ItemID, - rez.ObjectData.AttachmentPt, rez.ObjectData.ItemFlags, rez.ObjectData.NextOwnerMask); - } - - break; - case PacketType.DetachAttachmentIntoInv: - handlerDetachAttachmentIntoInv = OnDetachAttachmentIntoInv; - if (handlerDetachAttachmentIntoInv != null) - { - DetachAttachmentIntoInvPacket detachtoInv = (DetachAttachmentIntoInvPacket)Pack; - - LLUUID itemID = detachtoInv.ObjectData.ItemID; - LLUUID ATTACH_agentID = detachtoInv.ObjectData.AgentID; - - handlerDetachAttachmentIntoInv(itemID, this); - } - break; - case PacketType.ObjectAttach: - if (OnObjectAttach != null) - { - ObjectAttachPacket att = (ObjectAttachPacket)Pack; - - handlerObjectAttach = OnObjectAttach; - - if (handlerObjectAttach != null) - { - if (att.ObjectData.Length > 0) - { - handlerObjectAttach(this, att.ObjectData[0].ObjectLocalID, att.AgentData.AttachmentPoint, att.ObjectData[0].Rotation); - } - } - } - - break; - case PacketType.ObjectDetach: - - ObjectDetachPacket dett = (ObjectDetachPacket)Pack; - for (int j = 0; j < dett.ObjectData.Length; j++) - { - uint obj = dett.ObjectData[j].ObjectLocalID; - handlerObjectDetach = OnObjectDetach; - if (handlerObjectDetach != null) - { - handlerObjectDetach(obj,this); - } - - } - - break; - case PacketType.SetAlwaysRun: - SetAlwaysRunPacket run = (SetAlwaysRunPacket)Pack; - - handlerSetAlwaysRun = OnSetAlwaysRun; - if (handlerSetAlwaysRun != null) - handlerSetAlwaysRun(this, run.AgentData.AlwaysRun); - - break; - case PacketType.CompleteAgentMovement: - handlerCompleteMovementToRegion = OnCompleteMovementToRegion; - if (handlerCompleteMovementToRegion != null) - { - handlerCompleteMovementToRegion(); - } - handlerCompleteMovementToRegion = null; - - break; - case PacketType.AgentUpdate: - if (OnAgentUpdate != null) - { - AgentUpdatePacket agenUpdate = (AgentUpdatePacket)Pack; - - handlerAgentUpdate = OnAgentUpdate; - if (handlerAgentUpdate != null) - OnAgentUpdate(this, agenUpdate); - - handlerAgentUpdate = null; - //agenUpdate.AgentData.ControlFlags, agenUpdate.AgentData.BodyRotationa); - } - break; - case PacketType.AgentAnimation: - AgentAnimationPacket AgentAni = (AgentAnimationPacket)Pack; - - handlerStartAnim = null; - handlerStopAnim = null; - - for (int i = 0; i < AgentAni.AnimationList.Length; i++) - { - if (AgentAni.AnimationList[i].StartAnim) - { - handlerStartAnim = OnStartAnim; - if (handlerStartAnim != null) - { - handlerStartAnim(this, AgentAni.AnimationList[i].AnimID); - } - } - else - { - handlerStopAnim = OnStopAnim; - if (handlerStopAnim != null) - { - handlerStopAnim(this, AgentAni.AnimationList[i].AnimID); - } - } - } - break; - case PacketType.AgentRequestSit: - if (OnAgentRequestSit != null) - { - AgentRequestSitPacket agentRequestSit = (AgentRequestSitPacket)Pack; - - handlerAgentRequestSit = OnAgentRequestSit; - if (handlerAgentRequestSit != null) - handlerAgentRequestSit(this, agentRequestSit.AgentData.AgentID, - agentRequestSit.TargetObject.TargetID, agentRequestSit.TargetObject.Offset); - } - break; - case PacketType.AgentSit: - if (OnAgentSit != null) - { - AgentSitPacket agentSit = (AgentSitPacket)Pack; - - handlerAgentSit = OnAgentSit; - if (handlerAgentSit != null) - { - OnAgentSit(this, agentSit.AgentData.AgentID); - } - } - break; - case PacketType.AvatarPickerRequest: - AvatarPickerRequestPacket avRequestQuery = (AvatarPickerRequestPacket)Pack; - AvatarPickerRequestPacket.AgentDataBlock Requestdata = avRequestQuery.AgentData; - AvatarPickerRequestPacket.DataBlock querydata = avRequestQuery.Data; - //Console.WriteLine("Agent Sends:" + Helpers.FieldToUTF8String(querydata.Name)); - - handlerAvatarPickerRequest = OnAvatarPickerRequest; - if (handlerAvatarPickerRequest != null) - { - handlerAvatarPickerRequest(this, Requestdata.AgentID, Requestdata.QueryID, - Helpers.FieldToUTF8String(querydata.Name)); - } - break; - case PacketType.AgentDataUpdateRequest: - AgentDataUpdateRequestPacket avRequestDataUpdatePacket = (AgentDataUpdateRequestPacket)Pack; - - handlerAgentDataUpdateRequest = OnAgentDataUpdateRequest; - - if (handlerAgentDataUpdateRequest != null) - { - handlerAgentDataUpdateRequest(this, avRequestDataUpdatePacket.AgentData.AgentID, avRequestDataUpdatePacket.AgentData.SessionID); - } - - break; - case PacketType.UserInfoRequest: - UserInfoRequestPacket avUserInfoRequestPacket = (UserInfoRequestPacket)Pack; - - handlerUserInfoRequest = OnUserInfoRequest; - if (handlerUserInfoRequest != null) - { - handlerUserInfoRequest(this, avUserInfoRequestPacket.AgentData.AgentID, avUserInfoRequestPacket.AgentData.SessionID); - } - break; - - case PacketType.SetStartLocationRequest: - SetStartLocationRequestPacket avSetStartLocationRequestPacket = (SetStartLocationRequestPacket)Pack; - - if (avSetStartLocationRequestPacket.AgentData.AgentID == AgentId && avSetStartLocationRequestPacket.AgentData.SessionID == SessionId) - { - handlerSetStartLocationRequest = OnSetStartLocationRequest; - if (handlerSetStartLocationRequest != null) - { - handlerSetStartLocationRequest(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; - - case PacketType.AgentPause: - m_probesWithNoIngressPackets = 0; - m_clientBlocked = true; - break; - - case PacketType.AgentResume: - m_probesWithNoIngressPackets = 0; - m_clientBlocked = false; - SendStartPingCheck(0); - - 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); - } - } - handlerLinkObjects = OnLinkObjects; - if (handlerLinkObjects != null) - { - handlerLinkObjects(this, 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); - } - handlerDelinkObjects = OnDelinkObjects; - if (handlerDelinkObjects != null) - { - handlerDelinkObjects(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 - - handlerAddPrim = OnAddPrim; - if (handlerAddPrim != null) - handlerAddPrim(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; - handlerUpdatePrimShape = null; - for (int i = 0; i < shapePacket.ObjectData.Length; i++) - { - handlerUpdatePrimShape = OnUpdatePrimShape; - if (handlerUpdatePrimShape != null) - { - handlerUpdatePrimShape(m_agentId, shapePacket.ObjectData[i].ObjectLocalID, - shapePacket.ObjectData[i]); - } - } - break; - case PacketType.ObjectExtraParams: - ObjectExtraParamsPacket extraPar = (ObjectExtraParamsPacket)Pack; - - handlerUpdateExtraParams = OnUpdateExtraParams; - if (handlerUpdateExtraParams != null) - { - handlerUpdateExtraParams(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; - - handlerObjectDuplicate = null; - - for (int i = 0; i < dupe.ObjectData.Length; i++) - { - handlerObjectDuplicate = OnObjectDuplicate; - if (handlerObjectDuplicate != null) - { - handlerObjectDuplicate(dupe.ObjectData[i].ObjectLocalID, dupe.SharedData.Offset, - dupe.SharedData.DuplicateFlags, AgentandGroupData.AgentID, - AgentandGroupData.GroupID); - } - } - - break; - - case PacketType.ObjectSelect: - ObjectSelectPacket incomingselect = (ObjectSelectPacket)Pack; - - handlerObjectSelect = null; - - for (int i = 0; i < incomingselect.ObjectData.Length; i++) - { - handlerObjectSelect = OnObjectSelect; - if (handlerObjectSelect != null) - { - handlerObjectSelect(incomingselect.ObjectData[i].ObjectLocalID, this); - } - } - break; - case PacketType.ObjectDeselect: - ObjectDeselectPacket incomingdeselect = (ObjectDeselectPacket)Pack; - - handlerObjectDeselect = null; - - for (int i = 0; i < incomingdeselect.ObjectData.Length; i++) - { - handlerObjectDeselect = OnObjectDeselect; - if (handlerObjectDeselect != null) - { - OnObjectDeselect(incomingdeselect.ObjectData[i].ObjectLocalID, this); - } - } - break; - case PacketType.ObjectFlagUpdate: - ObjectFlagUpdatePacket flags = (ObjectFlagUpdatePacket)Pack; - - handlerUpdatePrimFlags = OnUpdatePrimFlags; - - if (handlerUpdatePrimFlags != null) - { - handlerUpdatePrimFlags(flags.AgentData.ObjectLocalID, Pack, this); - } - break; - case PacketType.ObjectImage: - ObjectImagePacket imagePack = (ObjectImagePacket)Pack; - - handlerUpdatePrimTexture = null; - for (int i = 0; i < imagePack.ObjectData.Length; i++) - { - handlerUpdatePrimTexture = OnUpdatePrimTexture; - if (handlerUpdatePrimTexture != null) - { - handlerUpdatePrimTexture(imagePack.ObjectData[i].ObjectLocalID, - imagePack.ObjectData[i].TextureEntry, this); - } - } - break; - case PacketType.ObjectGrab: - ObjectGrabPacket grab = (ObjectGrabPacket)Pack; - - handlerGrabObject = OnGrabObject; - - if (handlerGrabObject != null) - { - handlerGrabObject(grab.ObjectData.LocalID, grab.ObjectData.GrabOffset, this); - } - break; - case PacketType.ObjectGrabUpdate: - ObjectGrabUpdatePacket grabUpdate = (ObjectGrabUpdatePacket)Pack; - - handlerGrabUpdate = OnGrabUpdate; - - if (handlerGrabUpdate != null) - { - handlerGrabUpdate(grabUpdate.ObjectData.ObjectID, grabUpdate.ObjectData.GrabOffsetInitial, - grabUpdate.ObjectData.GrabPosition, this); - } - break; - case PacketType.ObjectDeGrab: - ObjectDeGrabPacket deGrab = (ObjectDeGrabPacket)Pack; - - handlerDeGrabObject = OnDeGrabObject; - if (handlerDeGrabObject != null) - { - handlerDeGrabObject(deGrab.ObjectData.LocalID, this); - } - break; - case PacketType.ObjectDescription: - ObjectDescriptionPacket objDes = (ObjectDescriptionPacket)Pack; - - handlerObjectDescription = null; - - for (int i = 0; i < objDes.ObjectData.Length; i++) - { - handlerObjectDescription = OnObjectDescription; - if (handlerObjectDescription != null) - { - handlerObjectDescription(this, objDes.ObjectData[i].LocalID, - Util.FieldToString(objDes.ObjectData[i].Description)); - } - } - break; - case PacketType.ObjectName: - ObjectNamePacket objName = (ObjectNamePacket)Pack; - - handlerObjectName = null; - for (int i = 0; i < objName.ObjectData.Length; i++) - { - handlerObjectName = OnObjectName; - if (handlerObjectName != null) - { - handlerObjectName(this, objName.ObjectData[i].LocalID, - Util.FieldToString(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; - - handlerObjectPermissions = null; - - 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; - - handlerObjectPermissions = OnObjectPermissions; - - if (handlerObjectPermissions != null) - 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.Undo: - UndoPacket undoitem = (UndoPacket)Pack; - if (undoitem.ObjectData.Length > 0) - { - for (int i = 0; i < undoitem.ObjectData.Length; i++) - { - LLUUID objiD = undoitem.ObjectData[i].ObjectID; - handlerOnUndo = OnUndo; - if (handlerOnUndo != null) - { - handlerOnUndo(this, objiD); - } - - } - } - break; - case PacketType.ObjectDuplicateOnRay: - ObjectDuplicateOnRayPacket dupeOnRay = (ObjectDuplicateOnRayPacket)Pack; - - handlerObjectDuplicateOnRay = null; - - - for (int i = 0; i < dupeOnRay.ObjectData.Length; i++) - { - handlerObjectDuplicateOnRay = OnObjectDuplicateOnRay; - if (handlerObjectDuplicateOnRay != null) - { - handlerObjectDuplicateOnRay(dupeOnRay.ObjectData[i].ObjectLocalID, dupeOnRay.AgentData.DuplicateFlags, - dupeOnRay.AgentData.AgentID, dupeOnRay.AgentData.GroupID, dupeOnRay.AgentData.RayTargetID, dupeOnRay.AgentData.RayEnd, - dupeOnRay.AgentData.RayStart, dupeOnRay.AgentData.BypassRaycast, dupeOnRay.AgentData.RayEndIsIntersection, - dupeOnRay.AgentData.CopyCenters, dupeOnRay.AgentData.CopyRotates); - } - } - - 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; - - handlerRequestObjectPropertiesFamily = OnRequestObjectPropertiesFamily; - - if (handlerRequestObjectPropertiesFamily != null) - { - handlerRequestObjectPropertiesFamily(this, m_agentId, packObjBlock.RequestFlags, - packObjBlock.ObjectID); - } - - break; - case PacketType.ObjectIncludeInSearch: - //This lets us set objects to appear in search (stuff like DataSnapshot, etc) - ObjectIncludeInSearchPacket packInSearch = (ObjectIncludeInSearchPacket)Pack; - handlerObjectIncludeInSearch = null; - - foreach (ObjectIncludeInSearchPacket.ObjectDataBlock objData in packInSearch.ObjectData) { - bool inSearch = objData.IncludeInSearch; - uint localID = objData.ObjectLocalID; - - handlerObjectIncludeInSearch = OnObjectIncludeInSearch; - - if (handlerObjectIncludeInSearch != null) { - handlerObjectIncludeInSearch(this, inSearch, localID); - } - } - break; - - case PacketType.ScriptAnswerYes: - ScriptAnswerYesPacket scriptAnswer = (ScriptAnswerYesPacket)Pack; - - handlerScriptAnswer = OnScriptAnswer; - if (handlerScriptAnswer != null) - { - handlerScriptAnswer(this, scriptAnswer.Data.TaskID, scriptAnswer.Data.ItemID, scriptAnswer.Data.Questions); - } - break; - - #endregion - - #region Inventory/Asset/Other related packets - - case PacketType.RequestImage: - RequestImagePacket imageRequest = (RequestImagePacket)Pack; - //Console.WriteLine("image request: " + Pack.ToString()); - - handlerTextureRequest = null; - - 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; - - handlerTextureRequest = OnRequestTexture; - - if (handlerTextureRequest != null) - 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); - /* RequestAsset = OnRequestAsset; - if (RequestAsset != null) - { - RequestAsset(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()); - LLUUID temp = LLUUID.Combine(request.AssetBlock.TransactionID, SecureSessionId); - - handlerAssetUploadRequest = OnAssetUploadRequest; - - if (handlerAssetUploadRequest != null) - { - handlerAssetUploadRequest(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; - - handlerRequestXfer = OnRequestXfer; - - if (handlerRequestXfer != null) - { - handlerRequestXfer(this, xferReq.XferID.ID, Util.FieldToString(xferReq.XferID.Filename)); - } - break; - case PacketType.SendXferPacket: - SendXferPacketPacket xferRec = (SendXferPacketPacket)Pack; - - handlerXferReceive = OnXferReceive; - if (handlerXferReceive != null) - { - handlerXferReceive(this, xferRec.XferID.ID, xferRec.XferID.Packet, xferRec.DataPacket.Data); - } - break; - case PacketType.ConfirmXferPacket: - ConfirmXferPacketPacket confirmXfer = (ConfirmXferPacketPacket)Pack; - - handlerConfirmXfer = OnConfirmXfer; - if (handlerConfirmXfer != null) - { - handlerConfirmXfer(this, confirmXfer.XferID.ID, confirmXfer.XferID.Packet); - } - break; - case PacketType.CreateInventoryFolder: - CreateInventoryFolderPacket invFolder = (CreateInventoryFolderPacket)Pack; - - handlerCreateInventoryFolder = OnCreateNewInventoryFolder; - if (handlerCreateInventoryFolder != null) - { - handlerCreateInventoryFolder(this, invFolder.FolderData.FolderID, - (ushort)invFolder.FolderData.Type, - Util.FieldToString(invFolder.FolderData.Name), - invFolder.FolderData.ParentID); - } - break; - case PacketType.UpdateInventoryFolder: - if (OnUpdateInventoryFolder != null) - { - UpdateInventoryFolderPacket invFolderx = (UpdateInventoryFolderPacket)Pack; - - handlerUpdateInventoryFolder = null; - - for (int i = 0; i < invFolderx.FolderData.Length; i++) - { - handlerUpdateInventoryFolder = OnUpdateInventoryFolder; - if (handlerUpdateInventoryFolder != null) - { - OnUpdateInventoryFolder(this, invFolderx.FolderData[i].FolderID, - (ushort)invFolderx.FolderData[i].Type, - Util.FieldToString(invFolderx.FolderData[i].Name), - invFolderx.FolderData[i].ParentID); - } - } - } - break; - case PacketType.MoveInventoryFolder: - if (OnMoveInventoryFolder != null) - { - MoveInventoryFolderPacket invFoldery = (MoveInventoryFolderPacket)Pack; - - handlerMoveInventoryFolder = null; - - for (int i = 0; i < invFoldery.InventoryData.Length; i++) - { - handlerMoveInventoryFolder = OnMoveInventoryFolder; - if (handlerMoveInventoryFolder != null) - { - OnMoveInventoryFolder(this, invFoldery.InventoryData[i].FolderID, - invFoldery.InventoryData[i].ParentID); - } - } - } - break; - case PacketType.CreateInventoryItem: - CreateInventoryItemPacket createItem = (CreateInventoryItemPacket)Pack; - - handlerCreateNewInventoryItem = OnCreateNewInventoryItem; - if (handlerCreateNewInventoryItem != null) - { - handlerCreateNewInventoryItem(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 FetchInventoryx = (FetchInventoryPacket)Pack; - - handlerFetchInventory = null; - - for (int i = 0; i < FetchInventoryx.InventoryData.Length; i++) - { - handlerFetchInventory = OnFetchInventory; - - if (handlerFetchInventory != null) - { - OnFetchInventory(this, FetchInventoryx.InventoryData[i].ItemID, - FetchInventoryx.InventoryData[i].OwnerID); - } - } - } - break; - case PacketType.FetchInventoryDescendents: - FetchInventoryDescendentsPacket Fetch = (FetchInventoryDescendentsPacket)Pack; - - handlerFetchInventoryDescendents = OnFetchInventoryDescendents; - if (handlerFetchInventoryDescendents != null) - { - handlerFetchInventoryDescendents(this, Fetch.InventoryData.FolderID, Fetch.InventoryData.OwnerID, - Fetch.InventoryData.FetchFolders, Fetch.InventoryData.FetchItems, - Fetch.InventoryData.SortOrder); - } - break; - case PacketType.PurgeInventoryDescendents: - PurgeInventoryDescendentsPacket Purge = (PurgeInventoryDescendentsPacket)Pack; - - handlerPurgeInventoryDescendents = OnPurgeInventoryDescendents; - if (handlerPurgeInventoryDescendents != null) - { - handlerPurgeInventoryDescendents(this, Purge.InventoryData.FolderID); - } - break; - case PacketType.UpdateInventoryItem: - UpdateInventoryItemPacket update = (UpdateInventoryItemPacket)Pack; - if (OnUpdateInventoryItem != null) - { - handlerUpdateInventoryItem = null; - for (int i = 0; i < update.InventoryData.Length; i++) - { - handlerUpdateInventoryItem = OnUpdateInventoryItem; - - if (handlerUpdateInventoryItem != null) - { - InventoryItemBase itemUpd = new InventoryItemBase(); - itemUpd.ID = update.InventoryData[i].ItemID; - itemUpd.Name = Util.FieldToString(update.InventoryData[i].Name); - itemUpd.Description = Util.FieldToString(update.InventoryData[i].Description); - itemUpd.GroupID = update.InventoryData[i].GroupID; - itemUpd.GroupOwned = update.InventoryData[i].GroupOwned; - itemUpd.NextPermissions = update.InventoryData[i].NextOwnerMask; - itemUpd.EveryOnePermissions = update.InventoryData[i].EveryoneMask; - itemUpd.CreationDate = update.InventoryData[i].CreationDate; - itemUpd.Folder = update.InventoryData[i].FolderID; - itemUpd.InvType = update.InventoryData[i].InvType; - itemUpd.SalePrice = update.InventoryData[i].SalePrice; - itemUpd.SaleType = update.InventoryData[i].SaleType; - itemUpd.Flags = update.InventoryData[i].Flags; - /* - 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); - */ - OnUpdateInventoryItem(this, update.InventoryData[i].TransactionID, - update.InventoryData[i].ItemID, - itemUpd); - } - } - } - //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; - - handlerCopyInventoryItem = null; - if (OnCopyInventoryItem != null) - { - foreach (CopyInventoryItemPacket.InventoryDataBlock datablock in copyitem.InventoryData) - { - handlerCopyInventoryItem = OnCopyInventoryItem; - if (handlerCopyInventoryItem != null) - { - handlerCopyInventoryItem(this, datablock.CallbackID, datablock.OldAgentID, - datablock.OldItemID, datablock.NewFolderID, - Util.FieldToString(datablock.NewName)); - } - } - } - break; - case PacketType.MoveInventoryItem: - MoveInventoryItemPacket moveitem = (MoveInventoryItemPacket)Pack; - if (OnMoveInventoryItem != null) - { - handlerMoveInventoryItem = null; - foreach (MoveInventoryItemPacket.InventoryDataBlock datablock in moveitem.InventoryData) - { - handlerMoveInventoryItem = OnMoveInventoryItem; - if (handlerMoveInventoryItem != null) - { - handlerMoveInventoryItem(this, datablock.FolderID, datablock.ItemID, datablock.Length, - Util.FieldToString(datablock.NewName)); - } - } - } - break; - case PacketType.RemoveInventoryItem: - RemoveInventoryItemPacket removeItem = (RemoveInventoryItemPacket)Pack; - if (OnRemoveInventoryItem != null) - { - handlerRemoveInventoryItem = null; - foreach (RemoveInventoryItemPacket.InventoryDataBlock datablock in removeItem.InventoryData) - { - handlerRemoveInventoryItem = OnRemoveInventoryItem; - if (handlerRemoveInventoryItem != null) - { - handlerRemoveInventoryItem(this, datablock.ItemID); - } - } - } - break; - case PacketType.RemoveInventoryFolder: - RemoveInventoryFolderPacket removeFolder = (RemoveInventoryFolderPacket)Pack; - if (OnRemoveInventoryFolder != null) - { - handlerRemoveInventoryFolder = null; - foreach (RemoveInventoryFolderPacket.FolderDataBlock datablock in removeFolder.FolderData) - { - handlerRemoveInventoryFolder = OnRemoveInventoryFolder; - - if (handlerRemoveInventoryFolder != null) - { - handlerRemoveInventoryFolder(this, datablock.FolderID); - } - } - } - break; - case PacketType.RequestTaskInventory: - RequestTaskInventoryPacket requesttask = (RequestTaskInventoryPacket)Pack; - - handlerRequestTaskInventory = OnRequestTaskInventory; - if (handlerRequestTaskInventory != null) - { - handlerRequestTaskInventory(this, requesttask.InventoryData.LocalID); - } - break; - case PacketType.UpdateTaskInventory: - UpdateTaskInventoryPacket updatetask = (UpdateTaskInventoryPacket)Pack; - if (OnUpdateTaskInventory != null) - { - if (updatetask.UpdateData.Key == 0) - { - handlerUpdateTaskInventory = OnUpdateTaskInventory; - if (handlerUpdateTaskInventory != null) - { - handlerUpdateTaskInventory(this, updatetask.InventoryData.ItemID, - updatetask.InventoryData.FolderID, updatetask.UpdateData.LocalID); - } - } - } - - break; - - case PacketType.RemoveTaskInventory: - - RemoveTaskInventoryPacket removeTask = (RemoveTaskInventoryPacket)Pack; - - handlerRemoveTaskItem = OnRemoveTaskItem; - - if (handlerRemoveTaskItem != null) - { - handlerRemoveTaskItem(this, removeTask.InventoryData.ItemID, removeTask.InventoryData.LocalID); - } - - break; - - case PacketType.MoveTaskInventory: - - MoveTaskInventoryPacket moveTaskInventoryPacket = (MoveTaskInventoryPacket)Pack; - - handlerMoveTaskItem = OnMoveTaskItem; - - if (handlerMoveTaskItem != null) - { - handlerMoveTaskItem( - this, moveTaskInventoryPacket.AgentData.FolderID, - moveTaskInventoryPacket.InventoryData.LocalID, - moveTaskInventoryPacket.InventoryData.ItemID); - } - - break; - - case PacketType.RezScript: - - //Console.WriteLine(Pack.ToString()); - RezScriptPacket rezScriptx = (RezScriptPacket)Pack; - - handlerRezScript = OnRezScript; - - if (handlerRezScript != null) - { - handlerRezScript(this, rezScriptx.InventoryBlock.ItemID, rezScriptx.UpdateBlock.ObjectLocalID); - } - break; - - case PacketType.MapLayerRequest: - RequestMapLayer(); - break; - case PacketType.MapBlockRequest: - MapBlockRequestPacket MapRequest = (MapBlockRequestPacket)Pack; - - handlerRequestMapBlocks = OnRequestMapBlocks; - if (handlerRequestMapBlocks != null) - { - handlerRequestMapBlocks(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); - handlerMapNameRequest = OnMapNameRequest; - if (handlerMapNameRequest != null) - { - handlerMapNameRequest(this, mapName); - } - break; - case PacketType.TeleportLandmarkRequest: - TeleportLandmarkRequestPacket tpReq = (TeleportLandmarkRequestPacket)Pack; - LLUUID lmid = tpReq.Info.LandmarkID; - AssetLandmark lm; - if (lmid != LLUUID.Zero) - { - AssetBase lma = m_assetCache.GetAsset(lmid, false); - - if (lma == null) - { - // Failed to find landmark - - TeleportCancelPacket tpCancel = (TeleportCancelPacket)PacketPool.Instance.GetPacket(PacketType.TeleportCancel); - tpCancel.Info.SessionID = tpReq.Info.SessionID; - tpCancel.Info.AgentID = tpReq.Info.AgentID; - OutPacket(tpCancel, ThrottleOutPacketType.Task); - } - - - try - { - lm = new AssetLandmark(lma); - } - catch (NullReferenceException) - { - // asset not found generates null ref inside the assetlandmark constructor. - TeleportCancelPacket tpCancel = (TeleportCancelPacket)PacketPool.Instance.GetPacket(PacketType.TeleportCancel); - tpCancel.Info.SessionID = tpReq.Info.SessionID; - tpCancel.Info.AgentID = tpReq.Info.AgentID; - OutPacket(tpCancel, ThrottleOutPacketType.Task); - break; - } - } - else - { - - // Teleport home request - handlerTeleportHomeRequest = OnTeleportHomeRequest; - if (handlerTeleportHomeRequest != null) - { - handlerTeleportHomeRequest(this.AgentId,this); - } - break; - } - - handlerTeleportLandmarkRequest = OnTeleportLandmarkRequest; - if (handlerTeleportLandmarkRequest != null) - { - handlerTeleportLandmarkRequest(this, lm.RegionHandle, lm.Position); - } - else - { - //no event handler so cancel request - - - 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()); - - handlerTeleportLocationRequest = OnTeleportLocationRequest; - if (handlerTeleportLocationRequest != null) - { - handlerTeleportLocationRequest(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.UUIDNameRequest: - UUIDNameRequestPacket incoming = (UUIDNameRequestPacket)Pack; - foreach (UUIDNameRequestPacket.UUIDNameBlockBlock UUIDBlock in incoming.UUIDNameBlock) - { - handlerNameRequest = OnNameFromUUIDRequest; - if (handlerNameRequest != null) - { - handlerNameRequest(UUIDBlock.ID, this); - } - } - break; - - #region Parcel related packets - - case PacketType.ParcelAccessListRequest: - ParcelAccessListRequestPacket requestPacket = (ParcelAccessListRequestPacket)Pack; - - handlerParcelAccessListRequest = OnParcelAccessListRequest; - - if (handlerParcelAccessListRequest != null) - { - handlerParcelAccessListRequest(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); - } - - handlerParcelAccessListUpdateRequest = OnParcelAccessListUpdateRequest; - if (handlerParcelAccessListUpdateRequest != null) - { - handlerParcelAccessListUpdateRequest(updatePacket.AgentData.AgentID, - updatePacket.AgentData.SessionID, updatePacket.Data.Flags, - updatePacket.Data.LocalID, entries, this); - } - break; - case PacketType.ParcelPropertiesRequest: - - ParcelPropertiesRequestPacket propertiesRequest = (ParcelPropertiesRequestPacket)Pack; - - handlerParcelPropertiesRequest = OnParcelPropertiesRequest; - if (handlerParcelPropertiesRequest != null) - { - handlerParcelPropertiesRequest((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; - - handlerParcelDivideRequest = OnParcelDivideRequest; - if (handlerParcelDivideRequest != null) - { - handlerParcelDivideRequest((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; - - handlerParcelJoinRequest = OnParcelJoinRequest; - - if (handlerParcelJoinRequest != null) - { - handlerParcelJoinRequest((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; - - handlerParcelPropertiesUpdateRequest = OnParcelPropertiesUpdateRequest; - - if (handlerParcelPropertiesUpdateRequest != null) - { - handlerParcelPropertiesUpdateRequest(parcelPropertiesPacket, this); - } - break; - case PacketType.ParcelSelectObjects: - ParcelSelectObjectsPacket selectPacket = (ParcelSelectObjectsPacket)Pack; - - handlerParcelSelectObjects = OnParcelSelectObjects; - - if (handlerParcelSelectObjects != null) - { - handlerParcelSelectObjects(selectPacket.ParcelData.LocalID, - Convert.ToInt32(selectPacket.ParcelData.ReturnType), this); - } - break; - case PacketType.ParcelObjectOwnersRequest: - //Console.WriteLine(Pack.ToString()); - ParcelObjectOwnersRequestPacket reqPacket = (ParcelObjectOwnersRequestPacket)Pack; - - handlerParcelObjectOwnerRequest = OnParcelObjectOwnerRequest; - - if (handlerParcelObjectOwnerRequest != null) - { - handlerParcelObjectOwnerRequest(reqPacket.ParcelData.LocalID, this); - } - break; - - #endregion - - #region Estate Packets - - case PacketType.EstateOwnerMessage: - EstateOwnerMessagePacket messagePacket = (EstateOwnerMessagePacket)Pack; - - handlerEstateOwnerMessage = OnEstateOwnerMessage; - - if (handlerEstateOwnerMessage != null) - { - handlerEstateOwnerMessage(messagePacket, this); - } - break; - case PacketType.RequestRegionInfo: - RequestRegionInfoPacket.AgentDataBlock mPacket = ((RequestRegionInfoPacket)Pack).AgentData; - - handlerRegionInfoRequest = OnRegionInfoRequest; - if (handlerRegionInfoRequest != null) - { - handlerRegionInfoRequest(this, mPacket.SessionID); - } - break; - case PacketType.EstateCovenantRequest: - - EstateCovenantRequestPacket.AgentDataBlock epack = - ((EstateCovenantRequestPacket)Pack).AgentData; - - handlerEstateCovenantRequest = OnEstateCovenantRequest; - if (handlerEstateCovenantRequest != null) - { - handlerEstateCovenantRequest(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; - - handlerReqGodlikePowers = OnRequestGodlikePowers; - - if (handlerReqGodlikePowers != null) - { - handlerReqGodlikePowers(ablock.AgentID, ablock.SessionID, token, rblock.Godlike, 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) - { - handlerGodKickUser = OnGodKickUser; - if (handlerGodKickUser != null) - { - handlerGodKickUser(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 Economy/Transaction Packets - - case PacketType.MoneyBalanceRequest: - MoneyBalanceRequestPacket moneybalancerequestpacket = (MoneyBalanceRequestPacket)Pack; - - handlerMoneyBalanceRequest = OnMoneyBalanceRequest; - - if (handlerMoneyBalanceRequest != null) - { - handlerMoneyBalanceRequest(this, moneybalancerequestpacket.AgentData.AgentID, moneybalancerequestpacket.AgentData.SessionID, moneybalancerequestpacket.MoneyData.TransactionID); - } - - break; - case PacketType.EconomyDataRequest: - - handlerEconomoyDataRequest = OnEconomyDataRequest; - if (handlerEconomoyDataRequest != null) - { - handlerEconomoyDataRequest(AgentId); - } - // TODO: handle this packet - //m_log.Warn("[CLIENT]: unhandled EconomyDataRequest packet"); - break; - case PacketType.RequestPayPrice: - RequestPayPricePacket requestPayPricePacket = (RequestPayPricePacket)Pack; - handlerRequestPayPrice = OnRequestPayPrice; - if (handlerRequestPayPrice != null) - { - handlerRequestPayPrice(this, requestPayPricePacket.ObjectData.ObjectID); - } - 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.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.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.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.InventoryDescendents: - // TODO: handle this packet - m_log.Warn("[CLIENT]: unhandled InventoryDescent packet"); - break; - case PacketType.GetScriptRunning: - m_log.Warn("[CLIENT]: unhandled GetScriptRunning 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); - } - - public ClientInfo GetClientInfo() - { - //MainLog.Instance.Verbose("CLIENT", "GetClientInfo BGN"); - - ClientInfo info = new ClientInfo(); - info.userEP = this.m_userEndPoint; - info.proxyEP = this.m_proxyEndPoint; - info.agentcircuit = new sAgentCircuitData(RequestClientInfo()); - - info.pendingAcks = m_pendingAcks; - - info.needAck = new Dictionary(); - - lock (m_needAck) - { - foreach (uint key in m_needAck.Keys) - { - info.needAck.Add(key, m_needAck[key].ToBytes()); - } - } - -/* pending - QueItem[] queitems = m_packetQueue.GetQueueArray(); - - MainLog.Instance.Verbose("CLIENT", "Queue Count : [{0}]", queitems.Length); - - for (int i = 0; i < queitems.Length; i++) - { - if (queitems[i].Incoming == false) - { - info.out_packets.Add(queitems[i].Packet.ToBytes()); - MainLog.Instance.Verbose("CLIENT", "Add OutPacket [{0}]", queitems[i].Packet.Type.ToString()); - } - } -*/ - - info.sequence = m_sequence; - - //MainLog.Instance.Verbose("CLIENT", "GetClientInfo END"); - - return info; - } - - public void SetClientInfo(ClientInfo info) - { - m_pendingAcks = info.pendingAcks; - - m_needAck = new Dictionary(); - - Packet packet = null; - int packetEnd = 0; - byte[] zero = new byte[3000]; - - foreach (uint key in info.needAck.Keys) - { - byte[] buff = info.needAck[key]; - - packetEnd = buff.Length - 1; - - try - { - packet = PacketPool.Instance.GetPacket(buff, ref packetEnd, zero); - } - catch (Exception) - { - - } - - m_needAck.Add(key, packet); - } - - m_sequence = info.sequence; - } - } +/* + * 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.Reflection; +using System.Text; +using System.Threading; +using System.Timers; +using Axiom.Math; +using libsecondlife; +using libsecondlife.Packets; +using log4net; +using OpenSim.Framework; +using OpenSim.Framework.Communications.Cache; +using OpenSim.Region.ClientStack.LindenUDP; +using OpenSim.Region.Environment.Scenes; +using Timer=System.Timers.Timer; + +namespace OpenSim.Region.ClientStack.LindenUDP +{ + public delegate bool PacketMethod(IClientAPI simClient, Packet packet); + + /// + /// Handles new client connections + /// Constructor takes a single Packet and authenticates everything + /// + public class LLClientView : IClientAPI + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + // ~ClientView() + // { + // m_log.Info("[CLIENTVIEW]: Destructor called"); + // } + + /* static variables */ + public static TerrainManager TerrainManager; + + public delegate bool SynchronizeClientHandler(IScene scene, Packet packet, LLUUID agentID, ThrottleOutPacketType throttlePacketType); + public static SynchronizeClientHandler SynchronizeClient = null; + /* 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 bool m_clientBlocked = false; + + 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 LLUUID m_agentId; + private readonly uint m_circuitCode; + private int m_moneyBalance; + + private int m_animationSequenceNumber = 1; + + 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 LLPacketQueue 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 LLPacketServer m_networkServer; + + /* public variables */ + protected string m_firstName; + protected string m_lastName; + protected Thread m_clientThread; + protected LLVector3 m_startpos; + protected EndPoint m_userEndPoint; + protected EndPoint m_proxyEndPoint; + + /* Instantiated Designated Event Delegates */ + //- used so we don't create new objects for each incoming packet and then toss it out later */ + + private RequestAvatarProperties handlerRequestAvatarProperties = null; //OnRequestAvatarProperties; + private UpdateAvatarProperties handlerUpdateAvatarProperties = null; // OnUpdateAvatarProperties; + private ChatFromViewer handlerChatFromViewer = null; //OnChatFromViewer; + private ChatFromViewer handlerChatFromViewer2 = null; //OnChatFromViewer; + private ImprovedInstantMessage handlerInstantMessage = null; //OnInstantMessage; + private FriendActionDelegate handlerApproveFriendRequest = null; //OnApproveFriendRequest; + private FriendshipTermination handlerTerminateFriendship = null; //OnTerminateFriendship; + private RezObject handlerRezObject = null; //OnRezObject; + private GenericCall4 handlerDeRezObject = null; //OnDeRezObject; + private ModifyTerrain handlerModifyTerrain = null; + private Action handlerRegionHandShakeReply = null; //OnRegionHandShakeReply; + private GenericCall2 handlerRequestWearables = null; //OnRequestWearables; + private Action handlerRequestAvatarsData = null; //OnRequestAvatarsData; + private SetAppearance handlerSetAppearance = null; //OnSetAppearance; + private AvatarNowWearing handlerAvatarNowWearing = null; //OnAvatarNowWearing; + private RezSingleAttachmentFromInv handlerRezSingleAttachment = null; //OnRezSingleAttachmentFromInv; + private UUIDNameRequest handlerDetachAttachmentIntoInv = null; // Detach attachment! + private ObjectAttach handlerObjectAttach = null; //OnObjectAttach; + private SetAlwaysRun handlerSetAlwaysRun = null; //OnSetAlwaysRun; + private GenericCall2 handlerCompleteMovementToRegion = null; //OnCompleteMovementToRegion; + private UpdateAgent handlerAgentUpdate = null; //OnAgentUpdate; + private StartAnim handlerStartAnim = null; + private StopAnim handlerStopAnim = null; + private AgentRequestSit handlerAgentRequestSit = null; //OnAgentRequestSit; + private AgentSit handlerAgentSit = null; //OnAgentSit; + private AvatarPickerRequest handlerAvatarPickerRequest = null; //OnAvatarPickerRequest; + private FetchInventory handlerAgentDataUpdateRequest = null; //OnAgentDataUpdateRequest; + private FetchInventory handlerUserInfoRequest = null; //OnUserInfoRequest; + private TeleportLocationRequest handlerSetStartLocationRequest = null; //OnSetStartLocationRequest; + private TeleportLandmarkRequest handlerTeleportLandmarkRequest = null; //OnTeleportLandmarkRequest; + private LinkObjects handlerLinkObjects = null; //OnLinkObjects; + private DelinkObjects handlerDelinkObjects = null; //OnDelinkObjects; + private AddNewPrim handlerAddPrim = null; //OnAddPrim; + private UpdateShape handlerUpdatePrimShape = null; //null; + private ObjectExtraParams handlerUpdateExtraParams = null; //OnUpdateExtraParams; + private ObjectDuplicate handlerObjectDuplicate = null; + private ObjectDuplicateOnRay handlerObjectDuplicateOnRay = null; + private ObjectSelect handlerObjectSelect = null; + private ObjectDeselect handlerObjectDeselect = null; + private ObjectIncludeInSearch handlerObjectIncludeInSearch = null; + private UpdatePrimFlags handlerUpdatePrimFlags = null; //OnUpdatePrimFlags; + private UpdatePrimTexture handlerUpdatePrimTexture = null; + private UpdateVector handlerGrabObject = null; //OnGrabObject; + private MoveObject handlerGrabUpdate = null; //OnGrabUpdate; + private ObjectSelect handlerDeGrabObject = null; //OnDeGrabObject; + private GenericCall7 handlerObjectDescription = null; + private GenericCall7 handlerObjectName = null; + private ObjectPermissions handlerObjectPermissions = null; + private RequestObjectPropertiesFamily handlerRequestObjectPropertiesFamily = null; //OnRequestObjectPropertiesFamily; + private TextureRequest handlerTextureRequest = null; + private UDPAssetUploadRequest handlerAssetUploadRequest = null; //OnAssetUploadRequest; + private RequestXfer handlerRequestXfer = null; //OnRequestXfer; + private XferReceive handlerXferReceive = null; //OnXferReceive; + private ConfirmXfer handlerConfirmXfer = null; //OnConfirmXfer; + private CreateInventoryFolder handlerCreateInventoryFolder = null; //OnCreateNewInventoryFolder; + private UpdateInventoryFolder handlerUpdateInventoryFolder = null; + private MoveInventoryFolder handlerMoveInventoryFolder = null; + private CreateNewInventoryItem handlerCreateNewInventoryItem = null; //OnCreateNewInventoryItem; + private FetchInventory handlerFetchInventory = null; + private FetchInventoryDescendents handlerFetchInventoryDescendents = null; //OnFetchInventoryDescendents; + private PurgeInventoryDescendents handlerPurgeInventoryDescendents = null; //OnPurgeInventoryDescendents; + private UpdateInventoryItem handlerUpdateInventoryItem = null; + private CopyInventoryItem handlerCopyInventoryItem = null; + private MoveInventoryItem handlerMoveInventoryItem = null; + private RemoveInventoryItem handlerRemoveInventoryItem = null; + private RemoveInventoryFolder handlerRemoveInventoryFolder = null; + private RequestTaskInventory handlerRequestTaskInventory = null; //OnRequestTaskInventory; + private UpdateTaskInventory handlerUpdateTaskInventory = null; //OnUpdateTaskInventory; + private MoveTaskInventory handlerMoveTaskItem = null; + private RemoveTaskInventory handlerRemoveTaskItem = null; //OnRemoveTaskItem; + private RezScript handlerRezScript = null; //OnRezScript; + private RequestMapBlocks handlerRequestMapBlocks = null; //OnRequestMapBlocks; + private RequestMapName handlerMapNameRequest = null; //OnMapNameRequest; + private TeleportLocationRequest handlerTeleportLocationRequest = null; //OnTeleportLocationRequest; + private MoneyBalanceRequest handlerMoneyBalanceRequest = null; //OnMoneyBalanceRequest; + private UUIDNameRequest handlerNameRequest = null; + private ParcelAccessListRequest handlerParcelAccessListRequest = null; //OnParcelAccessListRequest; + private ParcelAccessListUpdateRequest handlerParcelAccessListUpdateRequest = null; //OnParcelAccessListUpdateRequest; + private ParcelPropertiesRequest handlerParcelPropertiesRequest = null; //OnParcelPropertiesRequest; + private ParcelDivideRequest handlerParcelDivideRequest = null; //OnParcelDivideRequest; + private ParcelJoinRequest handlerParcelJoinRequest = null; //OnParcelJoinRequest; + private ParcelPropertiesUpdateRequest handlerParcelPropertiesUpdateRequest = null; //OnParcelPropertiesUpdateRequest; + private ParcelSelectObjects handlerParcelSelectObjects = null; //OnParcelSelectObjects; + private ParcelObjectOwnerRequest handlerParcelObjectOwnerRequest = null; //OnParcelObjectOwnerRequest; + private EstateOwnerMessageRequest handlerEstateOwnerMessage = null; //OnEstateOwnerMessage; + private RegionInfoRequest handlerRegionInfoRequest = null; //OnRegionInfoRequest; + private EstateCovenantRequest handlerEstateCovenantRequest = null; //OnEstateCovenantRequest; + private RequestGodlikePowers handlerReqGodlikePowers = null; //OnRequestGodlikePowers; + private GodKickUser handlerGodKickUser = null; //OnGodKickUser; + private ViewerEffectEventHandler handlerViewerEffect = null; //OnViewerEffect; + private Action handlerLogout = null; //OnLogout; + private MoneyTransferRequest handlerMoneyTransferRequest = null; //OnMoneyTransferRequest; + private ParcelBuy handlerParcelBuy = null; + private EconomyDataRequest handlerEconomoyDataRequest = null; + + private UpdateVector handlerUpdatePrimSinglePosition = null; //OnUpdatePrimSinglePosition; + private UpdatePrimSingleRotation handlerUpdatePrimSingleRotation = null; //OnUpdatePrimSingleRotation; + private UpdateVector handlerUpdatePrimScale = null; //OnUpdatePrimScale; + private UpdateVector handlerUpdatePrimGroupScale = null; //OnUpdateGroupScale; + private UpdateVector handlerUpdateVector = null; //OnUpdatePrimGroupPosition; + private UpdatePrimRotation handlerUpdatePrimRotation = null; //OnUpdatePrimGroupRotation; + private UpdatePrimGroupRotation handlerUpdatePrimGroupRotation = null; //OnUpdatePrimGroupMouseRotation; + private PacketStats handlerPacketStats = null; // OnPacketStats;# + private RequestAsset handlerRequestAsset = null; // OnRequestAsset; + private UUIDNameRequest handlerTeleportHomeRequest = null; + + private ScriptAnswer handlerScriptAnswer = null; + private RequestPayPrice handlerRequestPayPrice = null; + private ObjectDeselect handlerObjectDetach = null; + private AgentSit handlerOnUndo = null; + + /* 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; } + } + + public int NextAnimationSequenceNumber + { + get { return m_animationSequenceNumber++; } + } + + /* METHODS */ + + public LLClientView(EndPoint remoteEP, IScene scene, AssetCache assetCache, LLPacketServer packServer, + AgentCircuitManager authenSessions, LLUUID agentId, LLUUID sessionId, uint circuitCode, EndPoint proxyEP) + { + 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_proxyEndPoint = proxyEP; + + 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 LLPacketQueue(agentId); + + RegisterLocalPacketHandlers(); + + m_clientThread = new Thread(new ThreadStart(AuthUser)); + m_clientThread.Name = "ClientThread"; + m_clientThread.IsBackground = true; + m_clientThread.Start(); + ThreadTracker.Add(m_clientThread); + } + + public void SetDebug(int newDebug) + { + m_debug = newDebug; + } + + # region Client Methods + + private void CloseCleanup(bool shutdownCircuit) + { + 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.Unknown); + + m_packetQueue.Close(); + + 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 (!(shutdownCircuit)) + { + 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 shutdownCircuit) + { + // Pull Client out of Region + m_log.Info("[CLIENT]: Close has been called"); + m_packetQueue.Flush(); + + //raiseevent on the packet server to Shutdown the circuit + if (shutdownCircuit) + { + OnConnectionClosed(this); + } + + CloseCleanup(shutdownCircuit); + } + + 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() + { + // Shut down timers + m_ackTimer.Stop(); + m_clientPingTimer.Stop(); + } + + public void Restart() + { + // re-construct + m_pendingAcks = new Dictionary(); + m_needAck = new Dictionary(); + m_sequence += 1000000; + + 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; + } + + public void Terminate() + { + // disable blocking queue + m_packetQueue.Enqueue(null); + + // wait for thread stoped + m_clientThread.Join(); + + // delete circuit code + m_networkServer.CloseClient(this); + } + + #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; + } + + /// + /// Try to process a packet using registered packet handlers + /// + /// + /// True if a handler was found which successfully processed the packet. + 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) + { + LLQueItem nextPacket = m_packetQueue.Dequeue(); + if (nextPacket == null) + { + break; + } + 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 && !m_clientBlocked) || (m_probesWithNoIngressPackets > 90 && m_clientBlocked)) + { + + 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.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 UUIDNameRequest OnDetachAttachmentIntoInv; + public event ObjectAttach OnObjectAttach; + public event ObjectDeselect OnObjectDetach; + 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 ObjectDuplicateOnRay OnObjectDuplicateOnRay; + 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 ObjectIncludeInSearch OnObjectIncludeInSearch; + 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 UpdateVector OnUpdatePrimGroupScale; + 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 TeleportLandmarkRequest OnTeleportLandmarkRequest; + 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 UpdateAvatarProperties OnUpdateAvatarProperties; + + + 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 MoveTaskInventory OnMoveTaskItem; + public event RemoveTaskInventory OnRemoveTaskItem; + public event RequestAsset OnRequestAsset; + + 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 EconomyDataRequest OnEconomyDataRequest; + + public event MoneyBalanceRequest OnMoneyBalanceRequest; + public event ParcelBuy OnParcelBuy; + + public event UUIDNameRequest OnTeleportHomeRequest; + + public event ScriptAnswer OnScriptAnswer; + public event RequestPayPrice OnRequestPayPrice; + public event AgentSit OnUndo; + + #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); + } + + /// + /// Send an instant message to this client + /// + /// + /// + public void SendInstantMessage(LLUUID fromAgent, LLUUID fromAgentSession, string message, LLUUID toAgent, + LLUUID imSessionID, string fromName, byte dialog, uint timeStamp) + { + SendInstantMessage( + fromAgent, fromAgentSession, message, toAgent, + imSessionID, fromName, dialog, timeStamp, new byte[0]); + } + + /// + /// Send an instant message to this client + /// + /// + /// + public void SendInstantMessage(LLUUID fromAgent, LLUUID fromAgentSession, string message, LLUUID toAgent, + LLUUID imSessionID, string fromName, byte dialog, uint timeStamp, + byte[] binaryBucket) + { + 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 = binaryBucket; + + 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 = LLClientView.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 = LLClientView.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 = m_scene.GetCapsPath(m_agentId); + 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 SendPayPrice(LLUUID objectID, int[] payPrice) + { + if(payPrice[0] == 0 && + payPrice[1] == 0 && + payPrice[2] == 0 && + payPrice[3] == 0 && + payPrice[4] == 0) + return; + + PayPriceReplyPacket payPriceReply = (PayPriceReplyPacket)PacketPool.Instance.GetPacket(PacketType.PayPriceReply); + payPriceReply.ObjectData.ObjectID = objectID; + payPriceReply.ObjectData.DefaultPayPrice = payPrice[0]; + + payPriceReply.ButtonData=new PayPriceReplyPacket.ButtonDataBlock[4]; + payPriceReply.ButtonData[0]=new PayPriceReplyPacket.ButtonDataBlock(); + payPriceReply.ButtonData[0].PayButton = payPrice[1]; + payPriceReply.ButtonData[1]=new PayPriceReplyPacket.ButtonDataBlock(); + payPriceReply.ButtonData[1].PayButton = payPrice[2]; + payPriceReply.ButtonData[2]=new PayPriceReplyPacket.ButtonDataBlock(); + payPriceReply.ButtonData[2].PayButton = payPrice[3]; + payPriceReply.ButtonData[3]=new PayPriceReplyPacket.ButtonDataBlock(); + payPriceReply.ButtonData[3].PayButton = payPrice[4]; + + OutPacket(payPriceReply, 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.Unknown); + } + + 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; + +//Ckrinke This variable is not used, so comment out to remove the warning from the compiler (3-21-08) +//Ckrinke uint FULL_MASK_PERMISSIONS = 2147483647; + + if (fetchItems) + { + InventoryDescendentsPacket 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; + } + + int count = 0; + int i = 0; + foreach (InventoryItemBase item in items) + { + descend.ItemData[i] = new InventoryDescendentsPacket.ItemDataBlock(); + descend.ItemData[i].ItemID = item.ID; + descend.ItemData[i].AssetID = item.AssetID; + descend.ItemData[i].CreatorID = item.Creator; + descend.ItemData[i].BaseMask = item.BasePermissions; + descend.ItemData[i].Description = Helpers.StringToField(item.Description); + descend.ItemData[i].EveryoneMask = item.EveryOnePermissions; + descend.ItemData[i].OwnerMask = item.CurrentPermissions; + descend.ItemData[i].FolderID = item.Folder; + descend.ItemData[i].InvType = (sbyte)item.InvType; + descend.ItemData[i].Name = Helpers.StringToField(item.Name); + descend.ItemData[i].NextOwnerMask = item.NextPermissions; + descend.ItemData[i].OwnerID = item.Owner; + descend.ItemData[i].Type = (sbyte)item.AssetType; + + //descend.ItemData[i].GroupID = new LLUUID("00000000-0000-0000-0000-000000000000"); + descend.ItemData[i].GroupID = item.GroupID; + descend.ItemData[i].GroupOwned = item.GroupOwned; + descend.ItemData[i].GroupMask = 0; + descend.ItemData[i].CreationDate = item.CreationDate; + descend.ItemData[i].SalePrice = item.SalePrice; + descend.ItemData[i].SaleType = item.SaleType; + descend.ItemData[i].Flags = item.Flags; + + 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.CurrentPermissions); + + 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 + if (fetchFolders) + { + InventoryDescendentsPacket 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; + } + + int i = 0; + int count = 0; + foreach (InventoryFolderBase folder in folders) + { + descend.FolderData[i] = new InventoryDescendentsPacket.FolderDataBlock(); + descend.FolderData[i].FolderID = folder.ID; + 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 = 1; + + return descend; + } + + public void SendInventoryItemDetails(LLUUID ownerID, InventoryItemBase item) + { + 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.ID; + inventoryReply.InventoryData[0].AssetID = item.AssetID; + inventoryReply.InventoryData[0].CreatorID = item.Creator; + inventoryReply.InventoryData[0].BaseMask = item.BasePermissions; + inventoryReply.InventoryData[0].CreationDate = + (int)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds; + inventoryReply.InventoryData[0].Description = Helpers.StringToField(item.Description); + inventoryReply.InventoryData[0].EveryoneMask = item.EveryOnePermissions; + inventoryReply.InventoryData[0].FolderID = item.Folder; + inventoryReply.InventoryData[0].InvType = (sbyte)item.InvType; + inventoryReply.InventoryData[0].Name = Helpers.StringToField(item.Name); + inventoryReply.InventoryData[0].NextOwnerMask = item.NextPermissions; + inventoryReply.InventoryData[0].OwnerID = item.Owner; + inventoryReply.InventoryData[0].OwnerMask = item.CurrentPermissions; + inventoryReply.InventoryData[0].Type = (sbyte)item.AssetType; + + //inventoryReply.InventoryData[0].GroupID = new LLUUID("00000000-0000-0000-0000-000000000000"); + inventoryReply.InventoryData[0].GroupID = item.GroupID; + inventoryReply.InventoryData[0].GroupOwned = item.GroupOwned; + inventoryReply.InventoryData[0].GroupMask = 0; + inventoryReply.InventoryData[0].Flags = item.Flags; + inventoryReply.InventoryData[0].SalePrice = item.SalePrice; + inventoryReply.InventoryData[0].SaleType = item.SaleType; + + 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.SendBulkUpdateInventory(InventoryItemBase) + public void SendBulkUpdateInventory(InventoryItemBase item) + { + uint FULL_MASK_PERMISSIONS = (uint)PermissionMask.All; + + BulkUpdateInventoryPacket bulkUpdate + = (BulkUpdateInventoryPacket)PacketPool.Instance.GetPacket(PacketType.BulkUpdateInventory); + + bulkUpdate.AgentData.AgentID = AgentId; + bulkUpdate.AgentData.TransactionID = LLUUID.Random(); + + bulkUpdate.FolderData = new BulkUpdateInventoryPacket.FolderDataBlock[1]; + bulkUpdate.FolderData[0] = new BulkUpdateInventoryPacket.FolderDataBlock(); + bulkUpdate.FolderData[0].FolderID = LLUUID.Zero; + bulkUpdate.FolderData[0].ParentID = LLUUID.Zero; + bulkUpdate.FolderData[0].Type = -1; + bulkUpdate.FolderData[0].Name = new byte[0]; + + bulkUpdate.ItemData = new BulkUpdateInventoryPacket.ItemDataBlock[1]; + bulkUpdate.ItemData[0] = new BulkUpdateInventoryPacket.ItemDataBlock(); + bulkUpdate.ItemData[0].ItemID = item.ID; + bulkUpdate.ItemData[0].AssetID = item.AssetID; + bulkUpdate.ItemData[0].CreatorID = item.Creator; + bulkUpdate.ItemData[0].BaseMask = item.BasePermissions; + bulkUpdate.ItemData[0].CreationDate = 1000; + bulkUpdate.ItemData[0].Description = Helpers.StringToField(item.Description); + bulkUpdate.ItemData[0].EveryoneMask = item.EveryOnePermissions; + bulkUpdate.ItemData[0].FolderID = item.Folder; + bulkUpdate.ItemData[0].InvType = (sbyte)item.InvType; + bulkUpdate.ItemData[0].Name = Helpers.StringToField(item.Name); + bulkUpdate.ItemData[0].NextOwnerMask = item.NextPermissions; + bulkUpdate.ItemData[0].OwnerID = item.Owner; + bulkUpdate.ItemData[0].OwnerMask = item.CurrentPermissions; + bulkUpdate.ItemData[0].Type = (sbyte)item.AssetType; + + //bulkUpdate.ItemData[0].GroupID = new LLUUID("00000000-0000-0000-0000-000000000000"); + bulkUpdate.ItemData[0].GroupID = item.GroupID; + bulkUpdate.ItemData[0].GroupOwned = item.GroupOwned; + bulkUpdate.ItemData[0].GroupMask = 0; + bulkUpdate.ItemData[0].Flags = item.Flags; + bulkUpdate.ItemData[0].SalePrice = item.SalePrice; + bulkUpdate.ItemData[0].SaleType = item.SaleType; + + bulkUpdate.ItemData[0].CRC = + Helpers.InventoryCRC(1000, 0, bulkUpdate.ItemData[0].InvType, + bulkUpdate.ItemData[0].Type, bulkUpdate.ItemData[0].AssetID, + bulkUpdate.ItemData[0].GroupID, 100, + bulkUpdate.ItemData[0].OwnerID, bulkUpdate.ItemData[0].CreatorID, + bulkUpdate.ItemData[0].ItemID, bulkUpdate.ItemData[0].FolderID, + FULL_MASK_PERMISSIONS, 1, FULL_MASK_PERMISSIONS, FULL_MASK_PERMISSIONS, + FULL_MASK_PERMISSIONS); + + OutPacket(bulkUpdate, ThrottleOutPacketType.Asset); + } + + /// IClientAPI.SendInventoryItemCreateUpdate(InventoryItemBase) + public void SendInventoryItemCreateUpdate(InventoryItemBase Item) + { + 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.ID; + InventoryReply.InventoryData[0].AssetID = Item.AssetID; + InventoryReply.InventoryData[0].CreatorID = Item.Creator; + InventoryReply.InventoryData[0].BaseMask = Item.BasePermissions; + InventoryReply.InventoryData[0].Description = Helpers.StringToField(Item.Description); + InventoryReply.InventoryData[0].EveryoneMask = Item.EveryOnePermissions; + InventoryReply.InventoryData[0].FolderID = Item.Folder; + InventoryReply.InventoryData[0].InvType = (sbyte)Item.InvType; + InventoryReply.InventoryData[0].Name = Helpers.StringToField(Item.Name); + InventoryReply.InventoryData[0].NextOwnerMask = Item.NextPermissions; + InventoryReply.InventoryData[0].OwnerID = Item.Owner; + InventoryReply.InventoryData[0].OwnerMask = Item.CurrentPermissions; + InventoryReply.InventoryData[0].Type = (sbyte)Item.AssetType; + + //InventoryReply.InventoryData[0].GroupID = new LLUUID("00000000-0000-0000-0000-000000000000"); + InventoryReply.InventoryData[0].GroupID = Item.GroupID; + InventoryReply.InventoryData[0].GroupOwned = Item.GroupOwned; + InventoryReply.InventoryData[0].GroupMask = 0; + InventoryReply.InventoryData[0].Flags = Item.Flags; + InventoryReply.InventoryData[0].SalePrice = Item.SalePrice; + InventoryReply.InventoryData[0].SaleType = Item.SaleType; + + 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 SendEconomyData(float EnergyEfficiency, int ObjectCapacity, int ObjectCount, int PriceEnergyUnit, + int PriceGroupCreate, int PriceObjectClaim, float PriceObjectRent, float PriceObjectScaleFactor, + int PriceParcelClaim, float PriceParcelClaimFactor, int PriceParcelRent, int PricePublicObjectDecay, + int PricePublicObjectDelete, int PriceRentLight, int PriceUpload, int TeleportMinPrice, float TeleportPriceExponent) + { + EconomyDataPacket economyData = (EconomyDataPacket)PacketPool.Instance.GetPacket(PacketType.EconomyData); + economyData.Info.EnergyEfficiency = EnergyEfficiency; + economyData.Info.ObjectCapacity = ObjectCapacity; + economyData.Info.ObjectCount = ObjectCount; + economyData.Info.PriceEnergyUnit = PriceEnergyUnit; + economyData.Info.PriceGroupCreate = PriceGroupCreate; + economyData.Info.PriceObjectClaim = PriceObjectClaim; + economyData.Info.PriceObjectRent = PriceObjectRent; + economyData.Info.PriceObjectScaleFactor = PriceObjectScaleFactor; + economyData.Info.PriceParcelClaim = PriceParcelClaim; + economyData.Info.PriceParcelClaimFactor = PriceParcelClaimFactor; + economyData.Info.PriceParcelRent = PriceParcelRent; + economyData.Info.PricePublicObjectDecay = PricePublicObjectDecay; + economyData.Info.PricePublicObjectDelete = PricePublicObjectDelete; + economyData.Info.PriceRentLight = PriceRentLight; + economyData.Info.PriceUpload = PriceUpload; + economyData.Info.TeleportMinPrice = TeleportMinPrice; + economyData.Info.TeleportPriceExponent = TeleportPriceExponent; + economyData.Header.Reliable = true; + OutPacket(economyData, ThrottleOutPacketType.Unknown); + + } + + 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); + } + + /// + /// Send an alert message to the client. On the Linden client (tested 1.19.1.4), this pops up a brief duration + /// blue information box in the bottom right hand corner. + /// + /// + public void SendAlertMessage(string message) + { + AlertMessagePacket alertPack = (AlertMessagePacket)PacketPool.Instance.GetPacket(PacketType.AlertMessage); + alertPack.AlertData.Message = Helpers.StringToField(message); + OutPacket(alertPack, ThrottleOutPacketType.Task); + } + + /// + /// Send an agent alert message to the client. + /// + /// + /// On the linden client, if this true then it displays a one button text box placed in the + /// middle of the window. If false, the message is displayed in a brief duration blue information box (as for + /// the AlertMessage packet). + 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 SendAttachedSoundGainChange(LLUUID objectID, float gain) + { + AttachedSoundGainChangePacket sound = (AttachedSoundGainChangePacket)PacketPool.Instance.GetPacket(PacketType.AttachedSoundGainChange); + sound.DataBlock.ObjectID = objectID; + sound.DataBlock.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; + if (aboutText != null) + avatarReply.PropertiesData.AboutText = Helpers.StringToField(aboutText); + else + avatarReply.PropertiesData.AboutText = Helpers.StringToField(""); + avatarReply.PropertiesData.BornOn = Helpers.StringToField(bornOn); + avatarReply.PropertiesData.CharterMember = Helpers.StringToField(charterMember); + if (flAbout != null) + avatarReply.PropertiesData.FLAboutText = Helpers.StringToField(flAbout); + else + avatarReply.PropertiesData.FLAboutText = Helpers.StringToField(""); + 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); + 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, false,(uint)0, LLUUID.Zero); + } + 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, bool attachment, uint AttachPoint, LLUUID AssetId) + { + 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; + + // Anything more than 255 will cause libsecondlife to barf + if (text.Length > 255) + { + text = text.Remove(255); + } + + 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; + + if (attachment) + { + // Necessary??? + outPacket.ObjectData[0].JointAxisOrAnchor = new LLVector3(0, 0, 2); + outPacket.ObjectData[0].JointPivot = new LLVector3(0, 0, 0); + + // Item from inventory??? + outPacket.ObjectData[0].NameValue = + Helpers.StringToField("AttachItemID STRING RW SV " + AssetId.UUID); + outPacket.ObjectData[0].State = (byte)((AttachPoint % 16) * 16 + (AttachPoint / 16)); + } + + // 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, byte state, LLUUID AssetId) + { + 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, state); // AssetID should fall into here probably somehow... + 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, 0); + 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, + byte state) + { + 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++] = state; + 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); + + if ((primShape.PCode == (byte)PCode.NewTree) || (primShape.PCode == (byte)PCode.Tree) || (primShape.PCode == (byte)PCode.Grass)) + { + objupdate.Data = new byte[1]; + objupdate.Data[0] = primShape.State; + } + 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 = (byte)PCode.Avatar; + if (textureEntry != null) + { + objdata.TextureEntry = textureEntry; + } + LLVector3 pos = new LLVector3(objdata.ObjectData, 16); + pos.X = 100f; + objdata.ID = 8880000; + objdata.NameValue = Helpers.StringToField("FirstName STRING RW SV Test \nLastName STRING RW SV User "); + //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); + AddLocalPacketHandler(PacketType.ParcelBuy, HandleParcelBuyRequest); + } + + 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) + { + handlerMoneyTransferRequest = OnMoneyTransferRequest; + if (handlerMoneyTransferRequest != null) + { + handlerMoneyTransferRequest(money.MoneyData.SourceID, money.MoneyData.DestID, + money.MoneyData.Amount, money.MoneyData.TransactionType, + Util.FieldToString(money.MoneyData.Description)); + } + + return true; + } + else + { + return false; + } + } + + private bool HandleParcelBuyRequest(IClientAPI sender, Packet Pack) + { + ParcelBuyPacket parcel = (ParcelBuyPacket)Pack; + if (parcel.AgentData.AgentID == AgentId && parcel.AgentData.SessionID == this.SessionId) + { + handlerParcelBuy = OnParcelBuy; + if (handlerParcelBuy != null) + { + handlerParcelBuy(parcel.AgentData.AgentID, parcel.Data.GroupID, parcel.Data.Final, parcel.Data.IsGroupOwned, + parcel.Data.RemoveContribution, parcel.Data.LocalID, parcel.ParcelData.Area, parcel.ParcelData.Price, + false); + } + return true; + + } + else + { + return false; + } + + } + + private bool HandleViewerEffect(IClientAPI sender, Packet Pack) + { + ViewerEffectPacket viewer = (ViewerEffectPacket)Pack; + handlerViewerEffect = OnViewerEffect; + if (handlerViewerEffect != null) + { + handlerViewerEffect(sender, viewer.Effect); + } + + return true; + } + + public void SendScriptQuestion(LLUUID taskID, string taskName, string ownerName, LLUUID itemID, int question) + { + ScriptQuestionPacket scriptQuestion = (ScriptQuestionPacket)PacketPool.Instance.GetPacket(PacketType.ScriptQuestion); + scriptQuestion.Data = new ScriptQuestionPacket.DataBlock(); + // TODO: don't create new blocks if recycling an old packet + scriptQuestion.Data.TaskID = taskID; + scriptQuestion.Data.ItemID = itemID; + scriptQuestion.Data.Questions = question; + scriptQuestion.Data.ObjectName = Helpers.StringToField(taskName); + scriptQuestion.Data.ObjectOwner = Helpers.StringToField(ownerName); + + OutPacket(scriptQuestion, ThrottleOutPacketType.Task); + } + + protected virtual bool Logout(IClientAPI client, Packet packet) + { + m_log.Info("[CLIENT]: Got a logout request"); + + handlerLogout = OnLogout; + + if (handlerLogout != null) + { + handlerLogout(client); + } + + return true; + } + + /// + /// Send a response back to a client when it asks the asset server (via the region server) if it has + /// its appearance texture cached. + /// + /// At the moment, we always reply that there is no cached texture. + /// + /// + /// + /// + protected bool AgentTextureCached(IClientAPI simclient, Packet packet) + { + //Console.WriteLine("texture cached: " + packet.ToString()); + AgentCachedTexturePacket cachedtex = (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[cachedtex.WearableData.Length]; + + for (int i = 0; i < cachedtex.WearableData.Length; i++) + { + cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock(); + cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex; + cachedresp.WearableData[i].TextureID = LLUUID.Zero; + cachedresp.WearableData[i].HostName = new byte[0]; + } + + // Temporarily throw these packets on to the wind queue, so we can identify whether these + // are somehow the source of the packet bloat. + OutPacket(cachedresp, ThrottleOutPacketType.Wind); + return true; + } + + protected bool MultipleObjUpdate(IClientAPI simClient, Packet packet) + { + MultipleObjectUpdatePacket multipleupdate = (MultipleObjectUpdatePacket)packet; + // 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; + UpdatePrimRotation handlerUpdatePrimRotation = OnUpdatePrimGroupRotation; + UpdatePrimGroupRotation handlerUpdatePrimGroupRotation = OnUpdatePrimGroupMouseRotation; + + switch (block.Type) + { + case 1: + LLVector3 pos1 = new LLVector3(block.Data, 0); + + handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; + if (handlerUpdatePrimSinglePosition != null) + { + + // Console.WriteLine("new movement position is " + pos.X + " , " + pos.Y + " , " + pos.Z); + handlerUpdatePrimSinglePosition(localId, pos1, this); + } + break; + case 2: + LLQuaternion rot1 = new LLQuaternion(block.Data, 0, true); + + handlerUpdatePrimSingleRotation = OnUpdatePrimSingleRotation; + if (handlerUpdatePrimSingleRotation != null) + { + + //Console.WriteLine("new tab rotation is " + rot.X + " , " + rot.Y + " , " + rot.Z + " , " + rot.W); + handlerUpdatePrimSingleRotation(localId, rot1, this); + } + break; + case 3: + + LLQuaternion rot2 = new LLQuaternion(block.Data, 12, true); + handlerUpdatePrimSingleRotation = OnUpdatePrimSingleRotation; + if (handlerUpdatePrimSingleRotation != null) + { + + //Console.WriteLine("new mouse rotation is " + rot.X + " , " + rot.Y + " , " + rot.Z + " , " + rot.W); + handlerUpdatePrimSingleRotation(localId, rot2, this); + } + break; + case 5: + + LLVector3 scale1 = new LLVector3(block.Data, 12); + LLVector3 pos11 = new LLVector3(block.Data, 0); + + handlerUpdatePrimScale = OnUpdatePrimScale; + if (handlerUpdatePrimScale != null) + { + + // Console.WriteLine("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z); + handlerUpdatePrimScale(localId, scale1, this); + + + handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; + if (handlerUpdatePrimSinglePosition != null) + { + handlerUpdatePrimSinglePosition(localId, pos11, this); + } + } + break; + case 9: + LLVector3 pos2 = new LLVector3(block.Data, 0); + + handlerUpdateVector = OnUpdatePrimGroupPosition; + + if (handlerUpdateVector != null) + { + + handlerUpdateVector(localId, pos2, this); + } + break; + case 10: + + LLQuaternion rot3 = new LLQuaternion(block.Data, 0, true); + + handlerUpdatePrimRotation = OnUpdatePrimGroupRotation; + if (handlerUpdatePrimRotation != null) + { + + // Console.WriteLine("new rotation is " + rot.X + " , " + rot.Y + " , " + rot.Z + " , " + rot.W); + handlerUpdatePrimRotation(localId, rot3, this); + } + break; + case 11: + + LLVector3 pos3 = new LLVector3(block.Data, 0); + LLQuaternion rot4 = new LLQuaternion(block.Data, 12, true); + + handlerUpdatePrimGroupRotation = OnUpdatePrimGroupMouseRotation; + if (handlerUpdatePrimGroupRotation != null) + { + + //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); + handlerUpdatePrimGroupRotation(localId, pos3, rot4, this); + } + break; + case 13: + + LLVector3 scale2 = new LLVector3(block.Data, 12); + LLVector3 pos4 = new LLVector3(block.Data, 0); + + handlerUpdatePrimScale = OnUpdatePrimScale; + if (handlerUpdatePrimScale != null) + { + + //Console.WriteLine("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z); + handlerUpdatePrimScale(localId, scale2, this); + + // Change the position based on scale (for bug number 246) + handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; + // Console.WriteLine("new movement position is " + pos.X + " , " + pos.Y + " , " + pos.Z); + if (handlerUpdatePrimSinglePosition != null) + { + handlerUpdatePrimSinglePosition(localId, pos4, this); + } + } + break; + case 29: + LLVector3 scale5 = new LLVector3(block.Data, 12); + LLVector3 pos5 = new LLVector3(block.Data, 0); + + handlerUpdatePrimGroupScale = OnUpdatePrimGroupScale; + if (handlerUpdatePrimGroupScale != null) + { + + // Console.WriteLine("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z ); + handlerUpdatePrimGroupScale(localId, scale5, this); + handlerUpdateVector = OnUpdatePrimGroupPosition; + + if (handlerUpdateVector != null) + { + + handlerUpdateVector(localId, pos5, this); + } + } + break; + case 21: + LLVector3 scale6 = new LLVector3(block.Data, 12); + LLVector3 pos6 = new LLVector3(block.Data, 0); + + handlerUpdatePrimScale = OnUpdatePrimScale; + if (handlerUpdatePrimScale != null) + { + // Console.WriteLine("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z); + handlerUpdatePrimScale(localId, scale6, this); + handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; + if (handlerUpdatePrimSinglePosition != null) + { + handlerUpdatePrimSinglePosition(localId, pos6, 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-1111-9999-000000000006"); + OutPacket(mapReply, ThrottleOutPacketType.Land); + } + + public void RequestMapBlocksX(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 + { + //Need some extra space in case we need to add proxy information to the message later + Buffer.BlockCopy(sendbuffer, 0, ZeroOutBuffer, 0, sendbuffer.Length); + m_networkServer.SendPacketTo(ZeroOutBuffer, 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) + { + if (!m_packetProcessingEnabled && NewPack.Type != PacketType.LogoutRequest) + { + PacketPool.Instance.ReturnPacket(NewPack); + return; + } + + // 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 + { + LLQueItem item = new LLQueItem(); + item.Packet = NewPack; + item.Incoming = true; + m_packetQueue.Enqueue(item); + } + } + } + + public virtual void OutPacket(Packet NewPack, ThrottleOutPacketType throttlePacketType) + { + if ((SynchronizeClient != null) && (!IsActive)) + { + // Sending packet to active client's server. + if (SynchronizeClient(m_scene, NewPack, m_agentId, throttlePacketType)) + { + return; + } + } + + LLQueItem item = new LLQueItem(); + 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() + { + handlerPacketStats = OnPacketStats; + if (handlerPacketStats != null) + { + handlerPacketStats(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; + } + } + + private bool m_packetProcessingEnabled = true; + + public bool IsActive { + get { return m_packetProcessingEnabled; } + set { m_packetProcessingEnabled = value; } + } + + protected void ProcessInPacket(Packet Pack) + { + ack_pack(Pack); + + if (ProcessPacketMethod(Pack)) + { + //there is a handler registered that handled this packet type + return; + } + else + { + switch (Pack.Type) + { + #region Scene/Avatar + + case PacketType.AvatarPropertiesRequest: + AvatarPropertiesRequestPacket avatarProperties = (AvatarPropertiesRequestPacket)Pack; + + handlerRequestAvatarProperties = OnRequestAvatarProperties; + if (handlerRequestAvatarProperties != null) + { + handlerRequestAvatarProperties(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; + + handlerChatFromViewer = OnChatFromViewer; + if (handlerChatFromViewer != null) + handlerChatFromViewer(this, args); + } + break; + case PacketType.AvatarPropertiesUpdate: + AvatarPropertiesUpdatePacket Packet = (AvatarPropertiesUpdatePacket)Pack; + + handlerUpdateAvatarProperties = OnUpdateAvatarProperties; + if (handlerUpdateAvatarProperties != null) + { + AvatarPropertiesUpdatePacket.PropertiesDataBlock Properties = Packet.PropertiesData; + UserProfileData UserProfile = new UserProfileData(); + UserProfile.ID = AgentId; + UserProfile.AboutText = Helpers.FieldToUTF8String(Properties.AboutText); + UserProfile.FirstLifeAboutText = Helpers.FieldToUTF8String(Properties.FLAboutText); + UserProfile.FirstLifeImage = Properties.FLImageID; + UserProfile.Image = Properties.ImageID; + + handlerUpdateAvatarProperties(this, UserProfile); + } + 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; + handlerChatFromViewer2 = OnChatFromViewer; + if (handlerChatFromViewer2 != null) + handlerChatFromViewer2(this, args); + } + + break; + case PacketType.ImprovedInstantMessage: + ImprovedInstantMessagePacket msgpack = (ImprovedInstantMessagePacket)Pack; + string IMfromName = Util.FieldToString(msgpack.MessageBlock.FromAgentName); + string IMmessage = Helpers.FieldToUTF8String(msgpack.MessageBlock.Message); + handlerInstantMessage = OnInstantMessage; + + if (handlerInstantMessage != null) + { + handlerInstantMessage(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); + } + + handlerApproveFriendRequest = OnApproveFriendRequest; + if (handlerApproveFriendRequest != null) + { + handlerApproveFriendRequest(this, agentID, transactionID, callingCardFolders); + } + break; + case PacketType.TerminateFriendship: + TerminateFriendshipPacket tfriendpack = (TerminateFriendshipPacket)Pack; + LLUUID listOwnerAgentID = tfriendpack.AgentData.AgentID; + LLUUID exFriendID = tfriendpack.ExBlock.OtherID; + + handlerTerminateFriendship = OnTerminateFriendship; + if (handlerTerminateFriendship != null) + { + handlerTerminateFriendship(this, listOwnerAgentID, exFriendID); + } + break; + case PacketType.RezObject: + RezObjectPacket rezPacket = (RezObjectPacket)Pack; + + handlerRezObject = OnRezObject; + if (handlerRezObject != 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()); + + handlerRezObject(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: + handlerDeRezObject = OnDeRezObject; + if (handlerDeRezObject != null) + { + handlerDeRezObject(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++) + { + handlerModifyTerrain = OnModifyTerrain; + if (handlerModifyTerrain != null) + { + handlerModifyTerrain(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: + + handlerRegionHandShakeReply = OnRegionHandShakeReply; + if (handlerRegionHandShakeReply != null) + { + handlerRegionHandShakeReply(this); + } + + break; + case PacketType.AgentWearablesRequest: + handlerRequestWearables = OnRequestWearables; + + if (handlerRequestWearables != null) + { + handlerRequestWearables(); + } + + handlerRequestAvatarsData = OnRequestAvatarsData; + + if (handlerRequestAvatarsData != null) + { + handlerRequestAvatarsData(this); + } + + break; + case PacketType.AgentSetAppearance: + AgentSetAppearancePacket appear = (AgentSetAppearancePacket)Pack; + + handlerSetAppearance = OnSetAppearance; + if (handlerSetAppearance != null) + { + // Temporarily protect ourselves from the mantis #951 failure. + // However, we could do this for several other handlers where a failure isn't terminal + // for the client session anyway, in order to protect ourselves against bad code in plugins + try + { + handlerSetAppearance(appear.ObjectData.TextureEntry, appear.VisualParam); + } + catch (Exception e) + { + m_log.ErrorFormat( + "[CLIENT VIEW]: AgentSetApperance packet handler threw an exception, {0}", + e); + } + } + + 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); + } + + handlerAvatarNowWearing = OnAvatarNowWearing; + if (handlerAvatarNowWearing != null) + { + handlerAvatarNowWearing(this, wearingArgs); + } + } + break; + case PacketType.RezSingleAttachmentFromInv: + handlerRezSingleAttachment = OnRezSingleAttachmentFromInv; + if (handlerRezSingleAttachment != null) + { + RezSingleAttachmentFromInvPacket rez = (RezSingleAttachmentFromInvPacket)Pack; + handlerRezSingleAttachment(this, rez.ObjectData.ItemID, + rez.ObjectData.AttachmentPt, rez.ObjectData.ItemFlags, rez.ObjectData.NextOwnerMask); + } + + break; + case PacketType.DetachAttachmentIntoInv: + handlerDetachAttachmentIntoInv = OnDetachAttachmentIntoInv; + if (handlerDetachAttachmentIntoInv != null) + { + DetachAttachmentIntoInvPacket detachtoInv = (DetachAttachmentIntoInvPacket)Pack; + + LLUUID itemID = detachtoInv.ObjectData.ItemID; + LLUUID ATTACH_agentID = detachtoInv.ObjectData.AgentID; + + handlerDetachAttachmentIntoInv(itemID, this); + } + break; + case PacketType.ObjectAttach: + if (OnObjectAttach != null) + { + ObjectAttachPacket att = (ObjectAttachPacket)Pack; + + handlerObjectAttach = OnObjectAttach; + + if (handlerObjectAttach != null) + { + if (att.ObjectData.Length > 0) + { + handlerObjectAttach(this, att.ObjectData[0].ObjectLocalID, att.AgentData.AttachmentPoint, att.ObjectData[0].Rotation); + } + } + } + + break; + case PacketType.ObjectDetach: + + ObjectDetachPacket dett = (ObjectDetachPacket)Pack; + for (int j = 0; j < dett.ObjectData.Length; j++) + { + uint obj = dett.ObjectData[j].ObjectLocalID; + handlerObjectDetach = OnObjectDetach; + if (handlerObjectDetach != null) + { + handlerObjectDetach(obj,this); + } + + } + + break; + case PacketType.SetAlwaysRun: + SetAlwaysRunPacket run = (SetAlwaysRunPacket)Pack; + + handlerSetAlwaysRun = OnSetAlwaysRun; + if (handlerSetAlwaysRun != null) + handlerSetAlwaysRun(this, run.AgentData.AlwaysRun); + + break; + case PacketType.CompleteAgentMovement: + handlerCompleteMovementToRegion = OnCompleteMovementToRegion; + if (handlerCompleteMovementToRegion != null) + { + handlerCompleteMovementToRegion(); + } + handlerCompleteMovementToRegion = null; + + break; + case PacketType.AgentUpdate: + if (OnAgentUpdate != null) + { + AgentUpdatePacket agenUpdate = (AgentUpdatePacket)Pack; + + handlerAgentUpdate = OnAgentUpdate; + if (handlerAgentUpdate != null) + OnAgentUpdate(this, agenUpdate); + + handlerAgentUpdate = null; + //agenUpdate.AgentData.ControlFlags, agenUpdate.AgentData.BodyRotationa); + } + break; + case PacketType.AgentAnimation: + AgentAnimationPacket AgentAni = (AgentAnimationPacket)Pack; + + handlerStartAnim = null; + handlerStopAnim = null; + + for (int i = 0; i < AgentAni.AnimationList.Length; i++) + { + if (AgentAni.AnimationList[i].StartAnim) + { + handlerStartAnim = OnStartAnim; + if (handlerStartAnim != null) + { + handlerStartAnim(this, AgentAni.AnimationList[i].AnimID); + } + } + else + { + handlerStopAnim = OnStopAnim; + if (handlerStopAnim != null) + { + handlerStopAnim(this, AgentAni.AnimationList[i].AnimID); + } + } + } + break; + case PacketType.AgentRequestSit: + if (OnAgentRequestSit != null) + { + AgentRequestSitPacket agentRequestSit = (AgentRequestSitPacket)Pack; + + handlerAgentRequestSit = OnAgentRequestSit; + if (handlerAgentRequestSit != null) + handlerAgentRequestSit(this, agentRequestSit.AgentData.AgentID, + agentRequestSit.TargetObject.TargetID, agentRequestSit.TargetObject.Offset); + } + break; + case PacketType.AgentSit: + if (OnAgentSit != null) + { + AgentSitPacket agentSit = (AgentSitPacket)Pack; + + handlerAgentSit = OnAgentSit; + if (handlerAgentSit != null) + { + OnAgentSit(this, agentSit.AgentData.AgentID); + } + } + break; + case PacketType.AvatarPickerRequest: + AvatarPickerRequestPacket avRequestQuery = (AvatarPickerRequestPacket)Pack; + AvatarPickerRequestPacket.AgentDataBlock Requestdata = avRequestQuery.AgentData; + AvatarPickerRequestPacket.DataBlock querydata = avRequestQuery.Data; + //Console.WriteLine("Agent Sends:" + Helpers.FieldToUTF8String(querydata.Name)); + + handlerAvatarPickerRequest = OnAvatarPickerRequest; + if (handlerAvatarPickerRequest != null) + { + handlerAvatarPickerRequest(this, Requestdata.AgentID, Requestdata.QueryID, + Helpers.FieldToUTF8String(querydata.Name)); + } + break; + case PacketType.AgentDataUpdateRequest: + AgentDataUpdateRequestPacket avRequestDataUpdatePacket = (AgentDataUpdateRequestPacket)Pack; + + handlerAgentDataUpdateRequest = OnAgentDataUpdateRequest; + + if (handlerAgentDataUpdateRequest != null) + { + handlerAgentDataUpdateRequest(this, avRequestDataUpdatePacket.AgentData.AgentID, avRequestDataUpdatePacket.AgentData.SessionID); + } + + break; + case PacketType.UserInfoRequest: + UserInfoRequestPacket avUserInfoRequestPacket = (UserInfoRequestPacket)Pack; + + handlerUserInfoRequest = OnUserInfoRequest; + if (handlerUserInfoRequest != null) + { + handlerUserInfoRequest(this, avUserInfoRequestPacket.AgentData.AgentID, avUserInfoRequestPacket.AgentData.SessionID); + } + break; + + case PacketType.SetStartLocationRequest: + SetStartLocationRequestPacket avSetStartLocationRequestPacket = (SetStartLocationRequestPacket)Pack; + + if (avSetStartLocationRequestPacket.AgentData.AgentID == AgentId && avSetStartLocationRequestPacket.AgentData.SessionID == SessionId) + { + handlerSetStartLocationRequest = OnSetStartLocationRequest; + if (handlerSetStartLocationRequest != null) + { + handlerSetStartLocationRequest(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; + + case PacketType.AgentPause: + m_probesWithNoIngressPackets = 0; + m_clientBlocked = true; + break; + + case PacketType.AgentResume: + m_probesWithNoIngressPackets = 0; + m_clientBlocked = false; + SendStartPingCheck(0); + + 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); + } + } + handlerLinkObjects = OnLinkObjects; + if (handlerLinkObjects != null) + { + handlerLinkObjects(this, 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); + } + handlerDelinkObjects = OnDelinkObjects; + if (handlerDelinkObjects != null) + { + handlerDelinkObjects(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 + + handlerAddPrim = OnAddPrim; + if (handlerAddPrim != null) + handlerAddPrim(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; + handlerUpdatePrimShape = null; + for (int i = 0; i < shapePacket.ObjectData.Length; i++) + { + handlerUpdatePrimShape = OnUpdatePrimShape; + if (handlerUpdatePrimShape != null) + { + handlerUpdatePrimShape(m_agentId, shapePacket.ObjectData[i].ObjectLocalID, + shapePacket.ObjectData[i]); + } + } + break; + case PacketType.ObjectExtraParams: + ObjectExtraParamsPacket extraPar = (ObjectExtraParamsPacket)Pack; + + handlerUpdateExtraParams = OnUpdateExtraParams; + if (handlerUpdateExtraParams != null) + { + handlerUpdateExtraParams(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; + + handlerObjectDuplicate = null; + + for (int i = 0; i < dupe.ObjectData.Length; i++) + { + handlerObjectDuplicate = OnObjectDuplicate; + if (handlerObjectDuplicate != null) + { + handlerObjectDuplicate(dupe.ObjectData[i].ObjectLocalID, dupe.SharedData.Offset, + dupe.SharedData.DuplicateFlags, AgentandGroupData.AgentID, + AgentandGroupData.GroupID); + } + } + + break; + + case PacketType.ObjectSelect: + ObjectSelectPacket incomingselect = (ObjectSelectPacket)Pack; + + handlerObjectSelect = null; + + for (int i = 0; i < incomingselect.ObjectData.Length; i++) + { + handlerObjectSelect = OnObjectSelect; + if (handlerObjectSelect != null) + { + handlerObjectSelect(incomingselect.ObjectData[i].ObjectLocalID, this); + } + } + break; + case PacketType.ObjectDeselect: + ObjectDeselectPacket incomingdeselect = (ObjectDeselectPacket)Pack; + + handlerObjectDeselect = null; + + for (int i = 0; i < incomingdeselect.ObjectData.Length; i++) + { + handlerObjectDeselect = OnObjectDeselect; + if (handlerObjectDeselect != null) + { + OnObjectDeselect(incomingdeselect.ObjectData[i].ObjectLocalID, this); + } + } + break; + case PacketType.ObjectFlagUpdate: + ObjectFlagUpdatePacket flags = (ObjectFlagUpdatePacket)Pack; + + handlerUpdatePrimFlags = OnUpdatePrimFlags; + + if (handlerUpdatePrimFlags != null) + { + handlerUpdatePrimFlags(flags.AgentData.ObjectLocalID, Pack, this); + } + break; + case PacketType.ObjectImage: + ObjectImagePacket imagePack = (ObjectImagePacket)Pack; + + handlerUpdatePrimTexture = null; + for (int i = 0; i < imagePack.ObjectData.Length; i++) + { + handlerUpdatePrimTexture = OnUpdatePrimTexture; + if (handlerUpdatePrimTexture != null) + { + handlerUpdatePrimTexture(imagePack.ObjectData[i].ObjectLocalID, + imagePack.ObjectData[i].TextureEntry, this); + } + } + break; + case PacketType.ObjectGrab: + ObjectGrabPacket grab = (ObjectGrabPacket)Pack; + + handlerGrabObject = OnGrabObject; + + if (handlerGrabObject != null) + { + handlerGrabObject(grab.ObjectData.LocalID, grab.ObjectData.GrabOffset, this); + } + break; + case PacketType.ObjectGrabUpdate: + ObjectGrabUpdatePacket grabUpdate = (ObjectGrabUpdatePacket)Pack; + + handlerGrabUpdate = OnGrabUpdate; + + if (handlerGrabUpdate != null) + { + handlerGrabUpdate(grabUpdate.ObjectData.ObjectID, grabUpdate.ObjectData.GrabOffsetInitial, + grabUpdate.ObjectData.GrabPosition, this); + } + break; + case PacketType.ObjectDeGrab: + ObjectDeGrabPacket deGrab = (ObjectDeGrabPacket)Pack; + + handlerDeGrabObject = OnDeGrabObject; + if (handlerDeGrabObject != null) + { + handlerDeGrabObject(deGrab.ObjectData.LocalID, this); + } + break; + case PacketType.ObjectDescription: + ObjectDescriptionPacket objDes = (ObjectDescriptionPacket)Pack; + + handlerObjectDescription = null; + + for (int i = 0; i < objDes.ObjectData.Length; i++) + { + handlerObjectDescription = OnObjectDescription; + if (handlerObjectDescription != null) + { + handlerObjectDescription(this, objDes.ObjectData[i].LocalID, + Util.FieldToString(objDes.ObjectData[i].Description)); + } + } + break; + case PacketType.ObjectName: + ObjectNamePacket objName = (ObjectNamePacket)Pack; + + handlerObjectName = null; + for (int i = 0; i < objName.ObjectData.Length; i++) + { + handlerObjectName = OnObjectName; + if (handlerObjectName != null) + { + handlerObjectName(this, objName.ObjectData[i].LocalID, + Util.FieldToString(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; + + handlerObjectPermissions = null; + + 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; + + handlerObjectPermissions = OnObjectPermissions; + + if (handlerObjectPermissions != null) + 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.Undo: + UndoPacket undoitem = (UndoPacket)Pack; + if (undoitem.ObjectData.Length > 0) + { + for (int i = 0; i < undoitem.ObjectData.Length; i++) + { + LLUUID objiD = undoitem.ObjectData[i].ObjectID; + handlerOnUndo = OnUndo; + if (handlerOnUndo != null) + { + handlerOnUndo(this, objiD); + } + + } + } + break; + case PacketType.ObjectDuplicateOnRay: + ObjectDuplicateOnRayPacket dupeOnRay = (ObjectDuplicateOnRayPacket)Pack; + + handlerObjectDuplicateOnRay = null; + + + for (int i = 0; i < dupeOnRay.ObjectData.Length; i++) + { + handlerObjectDuplicateOnRay = OnObjectDuplicateOnRay; + if (handlerObjectDuplicateOnRay != null) + { + handlerObjectDuplicateOnRay(dupeOnRay.ObjectData[i].ObjectLocalID, dupeOnRay.AgentData.DuplicateFlags, + dupeOnRay.AgentData.AgentID, dupeOnRay.AgentData.GroupID, dupeOnRay.AgentData.RayTargetID, dupeOnRay.AgentData.RayEnd, + dupeOnRay.AgentData.RayStart, dupeOnRay.AgentData.BypassRaycast, dupeOnRay.AgentData.RayEndIsIntersection, + dupeOnRay.AgentData.CopyCenters, dupeOnRay.AgentData.CopyRotates); + } + } + + 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; + + handlerRequestObjectPropertiesFamily = OnRequestObjectPropertiesFamily; + + if (handlerRequestObjectPropertiesFamily != null) + { + handlerRequestObjectPropertiesFamily(this, m_agentId, packObjBlock.RequestFlags, + packObjBlock.ObjectID); + } + + break; + case PacketType.ObjectIncludeInSearch: + //This lets us set objects to appear in search (stuff like DataSnapshot, etc) + ObjectIncludeInSearchPacket packInSearch = (ObjectIncludeInSearchPacket)Pack; + handlerObjectIncludeInSearch = null; + + foreach (ObjectIncludeInSearchPacket.ObjectDataBlock objData in packInSearch.ObjectData) { + bool inSearch = objData.IncludeInSearch; + uint localID = objData.ObjectLocalID; + + handlerObjectIncludeInSearch = OnObjectIncludeInSearch; + + if (handlerObjectIncludeInSearch != null) { + handlerObjectIncludeInSearch(this, inSearch, localID); + } + } + break; + + case PacketType.ScriptAnswerYes: + ScriptAnswerYesPacket scriptAnswer = (ScriptAnswerYesPacket)Pack; + + handlerScriptAnswer = OnScriptAnswer; + if (handlerScriptAnswer != null) + { + handlerScriptAnswer(this, scriptAnswer.Data.TaskID, scriptAnswer.Data.ItemID, scriptAnswer.Data.Questions); + } + break; + + #endregion + + #region Inventory/Asset/Other related packets + + case PacketType.RequestImage: + RequestImagePacket imageRequest = (RequestImagePacket)Pack; + //Console.WriteLine("image request: " + Pack.ToString()); + + handlerTextureRequest = null; + + 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; + + handlerTextureRequest = OnRequestTexture; + + if (handlerTextureRequest != null) + 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); + /* RequestAsset = OnRequestAsset; + if (RequestAsset != null) + { + RequestAsset(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()); + LLUUID temp = LLUUID.Combine(request.AssetBlock.TransactionID, SecureSessionId); + + handlerAssetUploadRequest = OnAssetUploadRequest; + + if (handlerAssetUploadRequest != null) + { + handlerAssetUploadRequest(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; + + handlerRequestXfer = OnRequestXfer; + + if (handlerRequestXfer != null) + { + handlerRequestXfer(this, xferReq.XferID.ID, Util.FieldToString(xferReq.XferID.Filename)); + } + break; + case PacketType.SendXferPacket: + SendXferPacketPacket xferRec = (SendXferPacketPacket)Pack; + + handlerXferReceive = OnXferReceive; + if (handlerXferReceive != null) + { + handlerXferReceive(this, xferRec.XferID.ID, xferRec.XferID.Packet, xferRec.DataPacket.Data); + } + break; + case PacketType.ConfirmXferPacket: + ConfirmXferPacketPacket confirmXfer = (ConfirmXferPacketPacket)Pack; + + handlerConfirmXfer = OnConfirmXfer; + if (handlerConfirmXfer != null) + { + handlerConfirmXfer(this, confirmXfer.XferID.ID, confirmXfer.XferID.Packet); + } + break; + case PacketType.CreateInventoryFolder: + CreateInventoryFolderPacket invFolder = (CreateInventoryFolderPacket)Pack; + + handlerCreateInventoryFolder = OnCreateNewInventoryFolder; + if (handlerCreateInventoryFolder != null) + { + handlerCreateInventoryFolder(this, invFolder.FolderData.FolderID, + (ushort)invFolder.FolderData.Type, + Util.FieldToString(invFolder.FolderData.Name), + invFolder.FolderData.ParentID); + } + break; + case PacketType.UpdateInventoryFolder: + if (OnUpdateInventoryFolder != null) + { + UpdateInventoryFolderPacket invFolderx = (UpdateInventoryFolderPacket)Pack; + + handlerUpdateInventoryFolder = null; + + for (int i = 0; i < invFolderx.FolderData.Length; i++) + { + handlerUpdateInventoryFolder = OnUpdateInventoryFolder; + if (handlerUpdateInventoryFolder != null) + { + OnUpdateInventoryFolder(this, invFolderx.FolderData[i].FolderID, + (ushort)invFolderx.FolderData[i].Type, + Util.FieldToString(invFolderx.FolderData[i].Name), + invFolderx.FolderData[i].ParentID); + } + } + } + break; + case PacketType.MoveInventoryFolder: + if (OnMoveInventoryFolder != null) + { + MoveInventoryFolderPacket invFoldery = (MoveInventoryFolderPacket)Pack; + + handlerMoveInventoryFolder = null; + + for (int i = 0; i < invFoldery.InventoryData.Length; i++) + { + handlerMoveInventoryFolder = OnMoveInventoryFolder; + if (handlerMoveInventoryFolder != null) + { + OnMoveInventoryFolder(this, invFoldery.InventoryData[i].FolderID, + invFoldery.InventoryData[i].ParentID); + } + } + } + break; + case PacketType.CreateInventoryItem: + CreateInventoryItemPacket createItem = (CreateInventoryItemPacket)Pack; + + handlerCreateNewInventoryItem = OnCreateNewInventoryItem; + if (handlerCreateNewInventoryItem != null) + { + handlerCreateNewInventoryItem(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 FetchInventoryx = (FetchInventoryPacket)Pack; + + handlerFetchInventory = null; + + for (int i = 0; i < FetchInventoryx.InventoryData.Length; i++) + { + handlerFetchInventory = OnFetchInventory; + + if (handlerFetchInventory != null) + { + OnFetchInventory(this, FetchInventoryx.InventoryData[i].ItemID, + FetchInventoryx.InventoryData[i].OwnerID); + } + } + } + break; + case PacketType.FetchInventoryDescendents: + FetchInventoryDescendentsPacket Fetch = (FetchInventoryDescendentsPacket)Pack; + + handlerFetchInventoryDescendents = OnFetchInventoryDescendents; + if (handlerFetchInventoryDescendents != null) + { + handlerFetchInventoryDescendents(this, Fetch.InventoryData.FolderID, Fetch.InventoryData.OwnerID, + Fetch.InventoryData.FetchFolders, Fetch.InventoryData.FetchItems, + Fetch.InventoryData.SortOrder); + } + break; + case PacketType.PurgeInventoryDescendents: + PurgeInventoryDescendentsPacket Purge = (PurgeInventoryDescendentsPacket)Pack; + + handlerPurgeInventoryDescendents = OnPurgeInventoryDescendents; + if (handlerPurgeInventoryDescendents != null) + { + handlerPurgeInventoryDescendents(this, Purge.InventoryData.FolderID); + } + break; + case PacketType.UpdateInventoryItem: + UpdateInventoryItemPacket update = (UpdateInventoryItemPacket)Pack; + if (OnUpdateInventoryItem != null) + { + handlerUpdateInventoryItem = null; + for (int i = 0; i < update.InventoryData.Length; i++) + { + handlerUpdateInventoryItem = OnUpdateInventoryItem; + + if (handlerUpdateInventoryItem != null) + { + InventoryItemBase itemUpd = new InventoryItemBase(); + itemUpd.ID = update.InventoryData[i].ItemID; + itemUpd.Name = Util.FieldToString(update.InventoryData[i].Name); + itemUpd.Description = Util.FieldToString(update.InventoryData[i].Description); + itemUpd.GroupID = update.InventoryData[i].GroupID; + itemUpd.GroupOwned = update.InventoryData[i].GroupOwned; + itemUpd.NextPermissions = update.InventoryData[i].NextOwnerMask; + itemUpd.EveryOnePermissions = update.InventoryData[i].EveryoneMask; + itemUpd.CreationDate = update.InventoryData[i].CreationDate; + itemUpd.Folder = update.InventoryData[i].FolderID; + itemUpd.InvType = update.InventoryData[i].InvType; + itemUpd.SalePrice = update.InventoryData[i].SalePrice; + itemUpd.SaleType = update.InventoryData[i].SaleType; + itemUpd.Flags = update.InventoryData[i].Flags; + /* + 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); + */ + OnUpdateInventoryItem(this, update.InventoryData[i].TransactionID, + update.InventoryData[i].ItemID, + itemUpd); + } + } + } + //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; + + handlerCopyInventoryItem = null; + if (OnCopyInventoryItem != null) + { + foreach (CopyInventoryItemPacket.InventoryDataBlock datablock in copyitem.InventoryData) + { + handlerCopyInventoryItem = OnCopyInventoryItem; + if (handlerCopyInventoryItem != null) + { + handlerCopyInventoryItem(this, datablock.CallbackID, datablock.OldAgentID, + datablock.OldItemID, datablock.NewFolderID, + Util.FieldToString(datablock.NewName)); + } + } + } + break; + case PacketType.MoveInventoryItem: + MoveInventoryItemPacket moveitem = (MoveInventoryItemPacket)Pack; + if (OnMoveInventoryItem != null) + { + handlerMoveInventoryItem = null; + foreach (MoveInventoryItemPacket.InventoryDataBlock datablock in moveitem.InventoryData) + { + handlerMoveInventoryItem = OnMoveInventoryItem; + if (handlerMoveInventoryItem != null) + { + handlerMoveInventoryItem(this, datablock.FolderID, datablock.ItemID, datablock.Length, + Util.FieldToString(datablock.NewName)); + } + } + } + break; + case PacketType.RemoveInventoryItem: + RemoveInventoryItemPacket removeItem = (RemoveInventoryItemPacket)Pack; + if (OnRemoveInventoryItem != null) + { + handlerRemoveInventoryItem = null; + foreach (RemoveInventoryItemPacket.InventoryDataBlock datablock in removeItem.InventoryData) + { + handlerRemoveInventoryItem = OnRemoveInventoryItem; + if (handlerRemoveInventoryItem != null) + { + handlerRemoveInventoryItem(this, datablock.ItemID); + } + } + } + break; + case PacketType.RemoveInventoryFolder: + RemoveInventoryFolderPacket removeFolder = (RemoveInventoryFolderPacket)Pack; + if (OnRemoveInventoryFolder != null) + { + handlerRemoveInventoryFolder = null; + foreach (RemoveInventoryFolderPacket.FolderDataBlock datablock in removeFolder.FolderData) + { + handlerRemoveInventoryFolder = OnRemoveInventoryFolder; + + if (handlerRemoveInventoryFolder != null) + { + handlerRemoveInventoryFolder(this, datablock.FolderID); + } + } + } + break; + case PacketType.RequestTaskInventory: + RequestTaskInventoryPacket requesttask = (RequestTaskInventoryPacket)Pack; + + handlerRequestTaskInventory = OnRequestTaskInventory; + if (handlerRequestTaskInventory != null) + { + handlerRequestTaskInventory(this, requesttask.InventoryData.LocalID); + } + break; + case PacketType.UpdateTaskInventory: + UpdateTaskInventoryPacket updatetask = (UpdateTaskInventoryPacket)Pack; + if (OnUpdateTaskInventory != null) + { + if (updatetask.UpdateData.Key == 0) + { + handlerUpdateTaskInventory = OnUpdateTaskInventory; + if (handlerUpdateTaskInventory != null) + { + handlerUpdateTaskInventory(this, updatetask.InventoryData.ItemID, + updatetask.InventoryData.FolderID, updatetask.UpdateData.LocalID); + } + } + } + + break; + + case PacketType.RemoveTaskInventory: + + RemoveTaskInventoryPacket removeTask = (RemoveTaskInventoryPacket)Pack; + + handlerRemoveTaskItem = OnRemoveTaskItem; + + if (handlerRemoveTaskItem != null) + { + handlerRemoveTaskItem(this, removeTask.InventoryData.ItemID, removeTask.InventoryData.LocalID); + } + + break; + + case PacketType.MoveTaskInventory: + + MoveTaskInventoryPacket moveTaskInventoryPacket = (MoveTaskInventoryPacket)Pack; + + handlerMoveTaskItem = OnMoveTaskItem; + + if (handlerMoveTaskItem != null) + { + handlerMoveTaskItem( + this, moveTaskInventoryPacket.AgentData.FolderID, + moveTaskInventoryPacket.InventoryData.LocalID, + moveTaskInventoryPacket.InventoryData.ItemID); + } + + break; + + case PacketType.RezScript: + + //Console.WriteLine(Pack.ToString()); + RezScriptPacket rezScriptx = (RezScriptPacket)Pack; + + handlerRezScript = OnRezScript; + + if (handlerRezScript != null) + { + handlerRezScript(this, rezScriptx.InventoryBlock.ItemID, rezScriptx.UpdateBlock.ObjectLocalID); + } + break; + + case PacketType.MapLayerRequest: + RequestMapLayer(); + break; + case PacketType.MapBlockRequest: + MapBlockRequestPacket MapRequest = (MapBlockRequestPacket)Pack; + + handlerRequestMapBlocks = OnRequestMapBlocks; + if (handlerRequestMapBlocks != null) + { + handlerRequestMapBlocks(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); + handlerMapNameRequest = OnMapNameRequest; + if (handlerMapNameRequest != null) + { + handlerMapNameRequest(this, mapName); + } + break; + case PacketType.TeleportLandmarkRequest: + TeleportLandmarkRequestPacket tpReq = (TeleportLandmarkRequestPacket)Pack; + LLUUID lmid = tpReq.Info.LandmarkID; + AssetLandmark lm; + if (lmid != LLUUID.Zero) + { + AssetBase lma = m_assetCache.GetAsset(lmid, false); + + if (lma == null) + { + // Failed to find landmark + + TeleportCancelPacket tpCancel = (TeleportCancelPacket)PacketPool.Instance.GetPacket(PacketType.TeleportCancel); + tpCancel.Info.SessionID = tpReq.Info.SessionID; + tpCancel.Info.AgentID = tpReq.Info.AgentID; + OutPacket(tpCancel, ThrottleOutPacketType.Task); + } + + + try + { + lm = new AssetLandmark(lma); + } + catch (NullReferenceException) + { + // asset not found generates null ref inside the assetlandmark constructor. + TeleportCancelPacket tpCancel = (TeleportCancelPacket)PacketPool.Instance.GetPacket(PacketType.TeleportCancel); + tpCancel.Info.SessionID = tpReq.Info.SessionID; + tpCancel.Info.AgentID = tpReq.Info.AgentID; + OutPacket(tpCancel, ThrottleOutPacketType.Task); + break; + } + } + else + { + + // Teleport home request + handlerTeleportHomeRequest = OnTeleportHomeRequest; + if (handlerTeleportHomeRequest != null) + { + handlerTeleportHomeRequest(this.AgentId,this); + } + break; + } + + handlerTeleportLandmarkRequest = OnTeleportLandmarkRequest; + if (handlerTeleportLandmarkRequest != null) + { + handlerTeleportLandmarkRequest(this, lm.RegionHandle, lm.Position); + } + else + { + //no event handler so cancel request + + + 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()); + + handlerTeleportLocationRequest = OnTeleportLocationRequest; + if (handlerTeleportLocationRequest != null) + { + handlerTeleportLocationRequest(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.UUIDNameRequest: + UUIDNameRequestPacket incoming = (UUIDNameRequestPacket)Pack; + foreach (UUIDNameRequestPacket.UUIDNameBlockBlock UUIDBlock in incoming.UUIDNameBlock) + { + handlerNameRequest = OnNameFromUUIDRequest; + if (handlerNameRequest != null) + { + handlerNameRequest(UUIDBlock.ID, this); + } + } + break; + + #region Parcel related packets + + case PacketType.ParcelAccessListRequest: + ParcelAccessListRequestPacket requestPacket = (ParcelAccessListRequestPacket)Pack; + + handlerParcelAccessListRequest = OnParcelAccessListRequest; + + if (handlerParcelAccessListRequest != null) + { + handlerParcelAccessListRequest(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); + } + + handlerParcelAccessListUpdateRequest = OnParcelAccessListUpdateRequest; + if (handlerParcelAccessListUpdateRequest != null) + { + handlerParcelAccessListUpdateRequest(updatePacket.AgentData.AgentID, + updatePacket.AgentData.SessionID, updatePacket.Data.Flags, + updatePacket.Data.LocalID, entries, this); + } + break; + case PacketType.ParcelPropertiesRequest: + + ParcelPropertiesRequestPacket propertiesRequest = (ParcelPropertiesRequestPacket)Pack; + + handlerParcelPropertiesRequest = OnParcelPropertiesRequest; + if (handlerParcelPropertiesRequest != null) + { + handlerParcelPropertiesRequest((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; + + handlerParcelDivideRequest = OnParcelDivideRequest; + if (handlerParcelDivideRequest != null) + { + handlerParcelDivideRequest((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; + + handlerParcelJoinRequest = OnParcelJoinRequest; + + if (handlerParcelJoinRequest != null) + { + handlerParcelJoinRequest((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; + + handlerParcelPropertiesUpdateRequest = OnParcelPropertiesUpdateRequest; + + if (handlerParcelPropertiesUpdateRequest != null) + { + handlerParcelPropertiesUpdateRequest(parcelPropertiesPacket, this); + } + break; + case PacketType.ParcelSelectObjects: + ParcelSelectObjectsPacket selectPacket = (ParcelSelectObjectsPacket)Pack; + + handlerParcelSelectObjects = OnParcelSelectObjects; + + if (handlerParcelSelectObjects != null) + { + handlerParcelSelectObjects(selectPacket.ParcelData.LocalID, + Convert.ToInt32(selectPacket.ParcelData.ReturnType), this); + } + break; + case PacketType.ParcelObjectOwnersRequest: + //Console.WriteLine(Pack.ToString()); + ParcelObjectOwnersRequestPacket reqPacket = (ParcelObjectOwnersRequestPacket)Pack; + + handlerParcelObjectOwnerRequest = OnParcelObjectOwnerRequest; + + if (handlerParcelObjectOwnerRequest != null) + { + handlerParcelObjectOwnerRequest(reqPacket.ParcelData.LocalID, this); + } + break; + + #endregion + + #region Estate Packets + + case PacketType.EstateOwnerMessage: + EstateOwnerMessagePacket messagePacket = (EstateOwnerMessagePacket)Pack; + + handlerEstateOwnerMessage = OnEstateOwnerMessage; + + if (handlerEstateOwnerMessage != null) + { + handlerEstateOwnerMessage(messagePacket, this); + } + break; + case PacketType.RequestRegionInfo: + RequestRegionInfoPacket.AgentDataBlock mPacket = ((RequestRegionInfoPacket)Pack).AgentData; + + handlerRegionInfoRequest = OnRegionInfoRequest; + if (handlerRegionInfoRequest != null) + { + handlerRegionInfoRequest(this, mPacket.SessionID); + } + break; + case PacketType.EstateCovenantRequest: + + EstateCovenantRequestPacket.AgentDataBlock epack = + ((EstateCovenantRequestPacket)Pack).AgentData; + + handlerEstateCovenantRequest = OnEstateCovenantRequest; + if (handlerEstateCovenantRequest != null) + { + handlerEstateCovenantRequest(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; + + handlerReqGodlikePowers = OnRequestGodlikePowers; + + if (handlerReqGodlikePowers != null) + { + handlerReqGodlikePowers(ablock.AgentID, ablock.SessionID, token, rblock.Godlike, 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) + { + handlerGodKickUser = OnGodKickUser; + if (handlerGodKickUser != null) + { + handlerGodKickUser(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 Economy/Transaction Packets + + case PacketType.MoneyBalanceRequest: + MoneyBalanceRequestPacket moneybalancerequestpacket = (MoneyBalanceRequestPacket)Pack; + + handlerMoneyBalanceRequest = OnMoneyBalanceRequest; + + if (handlerMoneyBalanceRequest != null) + { + handlerMoneyBalanceRequest(this, moneybalancerequestpacket.AgentData.AgentID, moneybalancerequestpacket.AgentData.SessionID, moneybalancerequestpacket.MoneyData.TransactionID); + } + + break; + case PacketType.EconomyDataRequest: + + handlerEconomoyDataRequest = OnEconomyDataRequest; + if (handlerEconomoyDataRequest != null) + { + handlerEconomoyDataRequest(AgentId); + } + // TODO: handle this packet + //m_log.Warn("[CLIENT]: unhandled EconomyDataRequest packet"); + break; + case PacketType.RequestPayPrice: + RequestPayPricePacket requestPayPricePacket = (RequestPayPricePacket)Pack; + handlerRequestPayPrice = OnRequestPayPrice; + if (handlerRequestPayPrice != null) + { + handlerRequestPayPrice(this, requestPayPricePacket.ObjectData.ObjectID); + } + 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.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.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.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.InventoryDescendents: + // TODO: handle this packet + m_log.Warn("[CLIENT]: unhandled InventoryDescent packet"); + break; + case PacketType.GetScriptRunning: + m_log.Warn("[CLIENT]: unhandled GetScriptRunning 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); + } + + public ClientInfo GetClientInfo() + { + //MainLog.Instance.Verbose("CLIENT", "GetClientInfo BGN"); + + ClientInfo info = new ClientInfo(); + info.userEP = this.m_userEndPoint; + info.proxyEP = this.m_proxyEndPoint; + info.agentcircuit = new sAgentCircuitData(RequestClientInfo()); + + info.pendingAcks = m_pendingAcks; + + info.needAck = new Dictionary(); + + lock (m_needAck) + { + foreach (uint key in m_needAck.Keys) + { + info.needAck.Add(key, m_needAck[key].ToBytes()); + } + } + +/* pending + QueItem[] queitems = m_packetQueue.GetQueueArray(); + + MainLog.Instance.Verbose("CLIENT", "Queue Count : [{0}]", queitems.Length); + + for (int i = 0; i < queitems.Length; i++) + { + if (queitems[i].Incoming == false) + { + info.out_packets.Add(queitems[i].Packet.ToBytes()); + MainLog.Instance.Verbose("CLIENT", "Add OutPacket [{0}]", queitems[i].Packet.Type.ToString()); + } + } +*/ + + info.sequence = m_sequence; + + //MainLog.Instance.Verbose("CLIENT", "GetClientInfo END"); + + return info; + } + + public void SetClientInfo(ClientInfo info) + { + m_pendingAcks = info.pendingAcks; + + m_needAck = new Dictionary(); + + Packet packet = null; + int packetEnd = 0; + byte[] zero = new byte[3000]; + + foreach (uint key in info.needAck.Keys) + { + byte[] buff = info.needAck[key]; + + packetEnd = buff.Length - 1; + + try + { + packet = PacketPool.Instance.GetPacket(buff, ref packetEnd, zero); + } + catch (Exception) + { + + } + + m_needAck.Add(key, packet); + } + + m_sequence = info.sequence; + } + } } \ No newline at end of file diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLPacketQueue.cs b/OpenSim/Region/ClientStack/LindenUDP/LLPacketQueue.cs index 5dd1da6..c6da96e 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLPacketQueue.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLPacketQueue.cs @@ -1,532 +1,532 @@ -/* - * 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.Threading; -using System.Timers; -using libsecondlife; -using libsecondlife.Packets; -using OpenSim.Framework; -using OpenSim.Framework.Statistics; -using OpenSim.Framework.Statistics.Interfaces; -using Timer=System.Timers.Timer; - -namespace OpenSim.Region.ClientStack.LindenUDP -{ - public class LLPacketQueue : IPullStatsProvider - { - //private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); - - private bool m_enabled = true; - - private BlockingQueue SendQueue; - - private Queue IncomingPacketQueue; - private Queue OutgoingPacketQueue; - private Queue ResendOutgoingPacketQueue; - private Queue LandOutgoingPacketQueue; - private Queue WindOutgoingPacketQueue; - private Queue CloudOutgoingPacketQueue; - private Queue TaskOutgoingPacketQueue; - private Queue TextureOutgoingPacketQueue; - private Queue AssetOutgoingPacketQueue; - - private Dictionary PendingAcks = new Dictionary(); - private Dictionary NeedAck = new Dictionary(); - - // All throttle times and number of bytes are calculated by dividing by this value - // This value also determines how many times per throttletimems the timer will run - // If throttleimems is 1000 ms, then the timer will fire every 1000/7 milliseconds - - private int throttleTimeDivisor = 7; - - private int throttletimems = 1000; - - private LLPacketThrottle ResendThrottle; - private LLPacketThrottle LandThrottle; - private LLPacketThrottle WindThrottle; - private LLPacketThrottle CloudThrottle; - private LLPacketThrottle TaskThrottle; - private LLPacketThrottle AssetThrottle; - private LLPacketThrottle TextureThrottle; - private LLPacketThrottle TotalThrottle; - - // private long LastThrottle; - // private long ThrottleInterval; - private Timer throttleTimer; - - private LLUUID m_agentId; - - public LLPacketQueue(LLUUID agentId) - { - // 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. - - SendQueue = new BlockingQueue(); - - IncomingPacketQueue = new Queue(); - OutgoingPacketQueue = new Queue(); - ResendOutgoingPacketQueue = new Queue(); - LandOutgoingPacketQueue = new Queue(); - WindOutgoingPacketQueue = new Queue(); - CloudOutgoingPacketQueue = new Queue(); - TaskOutgoingPacketQueue = new Queue(); - TextureOutgoingPacketQueue = new Queue(); - AssetOutgoingPacketQueue = new Queue(); - - - // Set up the throttle classes (min, max, current) in bytes - ResendThrottle = new LLPacketThrottle(5000, 100000, 16000); - LandThrottle = new LLPacketThrottle(1000, 100000, 2000); - WindThrottle = new LLPacketThrottle(1000, 100000, 1000); - CloudThrottle = new LLPacketThrottle(1000, 100000, 1000); - TaskThrottle = new LLPacketThrottle(1000, 800000, 3000); - AssetThrottle = new LLPacketThrottle(1000, 800000, 1000); - TextureThrottle = new LLPacketThrottle(1000, 800000, 4000); - // Total Throttle trumps all - // Number of bytes allowed to go out per second. (256kbps per client) - TotalThrottle = new LLPacketThrottle(0, 1500000, 28000); - - throttleTimer = new Timer((int) (throttletimems/throttleTimeDivisor)); - throttleTimer.Elapsed += new ElapsedEventHandler(ThrottleTimerElapsed); - throttleTimer.Start(); - - // TIMERS needed for this - // LastThrottle = DateTime.Now.Ticks; - // ThrottleInterval = (long)(throttletimems/throttleTimeDivisor); - - m_agentId = agentId; - - if (StatsManager.SimExtraStats != null) - { - StatsManager.SimExtraStats.RegisterPacketQueueStatsProvider(m_agentId, this); - } - } - - /* STANDARD QUEUE MANIPULATION INTERFACES */ - - - public void Enqueue(LLQueItem item) - { - if (!m_enabled) - { - return; - } - // We could micro lock, but that will tend to actually - // probably be worse than just synchronizing on SendQueue - - if (item == null) - { - SendQueue.Enqueue(item); - return; - } - - lock (this) { - switch (item.throttleType) - { - case ThrottleOutPacketType.Resend: - ThrottleCheck(ref ResendThrottle, ref ResendOutgoingPacketQueue, item); - break; - case ThrottleOutPacketType.Texture: - ThrottleCheck(ref TextureThrottle, ref TextureOutgoingPacketQueue, item); - break; - case ThrottleOutPacketType.Task: - ThrottleCheck(ref TaskThrottle, ref TaskOutgoingPacketQueue, item); - break; - case ThrottleOutPacketType.Land: - ThrottleCheck(ref LandThrottle, ref LandOutgoingPacketQueue, item); - break; - case ThrottleOutPacketType.Asset: - ThrottleCheck(ref AssetThrottle, ref AssetOutgoingPacketQueue, item); - break; - case ThrottleOutPacketType.Cloud: - ThrottleCheck(ref CloudThrottle, ref CloudOutgoingPacketQueue, item); - break; - case ThrottleOutPacketType.Wind: - ThrottleCheck(ref WindThrottle, ref WindOutgoingPacketQueue, item); - break; - - default: - // Acknowledgements and other such stuff should go directly to the blocking Queue - // Throttling them may and likely 'will' be problematic - SendQueue.Enqueue(item); - break; - } - } - } - - public LLQueItem Dequeue() - { - return SendQueue.Dequeue(); - } - - public void Flush() - { - lock (this) - { - while (PacketsWaiting()) - { - //Now comes the fun part.. we dump all our elements into m_packetQueue that we've saved up. - if (ResendOutgoingPacketQueue.Count > 0) - { - SendQueue.Enqueue(ResendOutgoingPacketQueue.Dequeue()); - } - if (LandOutgoingPacketQueue.Count > 0) - { - SendQueue.Enqueue(LandOutgoingPacketQueue.Dequeue()); - } - if (WindOutgoingPacketQueue.Count > 0) - { - SendQueue.Enqueue(WindOutgoingPacketQueue.Dequeue()); - } - if (CloudOutgoingPacketQueue.Count > 0) - { - SendQueue.Enqueue(CloudOutgoingPacketQueue.Dequeue()); - } - if (TaskOutgoingPacketQueue.Count > 0) - { - SendQueue.Enqueue(TaskOutgoingPacketQueue.Dequeue()); - } - if (TextureOutgoingPacketQueue.Count > 0) - { - SendQueue.Enqueue(TextureOutgoingPacketQueue.Dequeue()); - } - if (AssetOutgoingPacketQueue.Count > 0) - { - SendQueue.Enqueue(AssetOutgoingPacketQueue.Dequeue()); - } - } - // m_log.Info("[THROTTLE]: Processed " + throttleLoops + " packets"); - } - } - - public void Close() - { - Flush(); - - m_enabled = false; - throttleTimer.Stop(); - - if (StatsManager.SimExtraStats != null) - { - StatsManager.SimExtraStats.DeregisterPacketQueueStatsProvider(m_agentId); - } - } - - private void ResetCounters() - { - ResendThrottle.Reset(); - LandThrottle.Reset(); - WindThrottle.Reset(); - CloudThrottle.Reset(); - TaskThrottle.Reset(); - AssetThrottle.Reset(); - TextureThrottle.Reset(); - TotalThrottle.Reset(); - } - - private bool PacketsWaiting() - { - return (ResendOutgoingPacketQueue.Count > 0 || - LandOutgoingPacketQueue.Count > 0 || - WindOutgoingPacketQueue.Count > 0 || - CloudOutgoingPacketQueue.Count > 0 || - TaskOutgoingPacketQueue.Count > 0 || - AssetOutgoingPacketQueue.Count > 0 || - TextureOutgoingPacketQueue.Count > 0); - } - - public void ProcessThrottle() - { - // I was considering this.. Will an event fire if the thread it's on is blocked? - - // Then I figured out.. it doesn't really matter.. because this thread won't be blocked for long - // The General overhead of the UDP protocol gets sent to the queue un-throttled by this - // so This'll pick up about around the right time. - - int MaxThrottleLoops = 4550; // 50*7 packets can be dequeued at once. - int throttleLoops = 0; - - // We're going to dequeue all of the saved up packets until - // we've hit the throttle limit or there's no more packets to send - lock (this) - { - ResetCounters(); - // m_log.Info("[THROTTLE]: Entering Throttle"); - while (TotalThrottle.UnderLimit() && PacketsWaiting() && - (throttleLoops <= MaxThrottleLoops)) - { - throttleLoops++; - //Now comes the fun part.. we dump all our elements into m_packetQueue that we've saved up. - if (ResendThrottle.UnderLimit() && ResendOutgoingPacketQueue.Count > 0) - { - LLQueItem qpack = ResendOutgoingPacketQueue.Dequeue(); - - SendQueue.Enqueue(qpack); - TotalThrottle.Add(qpack.Packet.ToBytes().Length); - ResendThrottle.Add(qpack.Packet.ToBytes().Length); - } - if (LandThrottle.UnderLimit() && LandOutgoingPacketQueue.Count > 0) - { - LLQueItem qpack = LandOutgoingPacketQueue.Dequeue(); - - SendQueue.Enqueue(qpack); - TotalThrottle.Add(qpack.Packet.ToBytes().Length); - LandThrottle.Add(qpack.Packet.ToBytes().Length); - } - if (WindThrottle.UnderLimit() && WindOutgoingPacketQueue.Count > 0) - { - LLQueItem qpack = WindOutgoingPacketQueue.Dequeue(); - - SendQueue.Enqueue(qpack); - TotalThrottle.Add(qpack.Packet.ToBytes().Length); - WindThrottle.Add(qpack.Packet.ToBytes().Length); - } - if (CloudThrottle.UnderLimit() && CloudOutgoingPacketQueue.Count > 0) - { - LLQueItem qpack = CloudOutgoingPacketQueue.Dequeue(); - - SendQueue.Enqueue(qpack); - TotalThrottle.Add(qpack.Packet.ToBytes().Length); - CloudThrottle.Add(qpack.Packet.ToBytes().Length); - } - if (TaskThrottle.UnderLimit() && TaskOutgoingPacketQueue.Count > 0) - { - LLQueItem qpack = TaskOutgoingPacketQueue.Dequeue(); - - SendQueue.Enqueue(qpack); - TotalThrottle.Add(qpack.Packet.ToBytes().Length); - TaskThrottle.Add(qpack.Packet.ToBytes().Length); - } - if (TextureThrottle.UnderLimit() && TextureOutgoingPacketQueue.Count > 0) - { - LLQueItem qpack = TextureOutgoingPacketQueue.Dequeue(); - - SendQueue.Enqueue(qpack); - TotalThrottle.Add(qpack.Packet.ToBytes().Length); - TextureThrottle.Add(qpack.Packet.ToBytes().Length); - } - if (AssetThrottle.UnderLimit() && AssetOutgoingPacketQueue.Count > 0) - { - LLQueItem qpack = AssetOutgoingPacketQueue.Dequeue(); - - SendQueue.Enqueue(qpack); - TotalThrottle.Add(qpack.Packet.ToBytes().Length); - AssetThrottle.Add(qpack.Packet.ToBytes().Length); - } - } - // m_log.Info("[THROTTLE]: Processed " + throttleLoops + " packets"); - } - } - - private void ThrottleTimerElapsed(object sender, ElapsedEventArgs e) - { - // just to change the signature, and that ProcessThrottle - // will be used elsewhere possibly - ProcessThrottle(); - } - - private void ThrottleCheck(ref LLPacketThrottle throttle, ref Queue q, LLQueItem item) - { - // The idea.. is if the packet throttle queues are empty - // and the client is under throttle for the type. Queue - // it up directly. This basically short cuts having to - // wait for the timer to fire to put things into the - // output queue - - if ((q.Count == 0) && (throttle.UnderLimit())) - { - Monitor.Enter(this); - throttle.Add(item.Packet.ToBytes().Length); - TotalThrottle.Add(item.Packet.ToBytes().Length); - SendQueue.Enqueue(item); - Monitor.Pulse(this); - Monitor.Exit(this); - } - else - { - q.Enqueue(item); - } - } - - - private static int ScaleThrottle(int value, int curmax, int newmax) - { - return (value / curmax) * newmax; - } - - public byte[] GetThrottlesPacked(float multiplier) - { - int singlefloat = 4; - float tResend = ResendThrottle.Throttle*multiplier; - float tLand = LandThrottle.Throttle*multiplier; - float tWind = WindThrottle.Throttle*multiplier; - float tCloud = CloudThrottle.Throttle*multiplier; - float tTask = TaskThrottle.Throttle*multiplier; - float tTexture = TextureThrottle.Throttle*multiplier; - float tAsset = AssetThrottle.Throttle*multiplier; - - byte[] throttles = new byte[singlefloat*7]; - int i = 0; - Buffer.BlockCopy(BitConverter.GetBytes(tResend), 0, throttles, singlefloat*i, singlefloat); - i++; - Buffer.BlockCopy(BitConverter.GetBytes(tLand), 0, throttles, singlefloat*i, singlefloat); - i++; - Buffer.BlockCopy(BitConverter.GetBytes(tWind), 0, throttles, singlefloat*i, singlefloat); - i++; - Buffer.BlockCopy(BitConverter.GetBytes(tCloud), 0, throttles, singlefloat*i, singlefloat); - i++; - Buffer.BlockCopy(BitConverter.GetBytes(tTask), 0, throttles, singlefloat*i, singlefloat); - i++; - Buffer.BlockCopy(BitConverter.GetBytes(tTexture), 0, throttles, singlefloat*i, singlefloat); - i++; - Buffer.BlockCopy(BitConverter.GetBytes(tAsset), 0, throttles, singlefloat*i, singlefloat); - - return throttles; - } - - public void SetThrottleFromClient(byte[] throttle) - { - int tResend = -1; - int tLand = -1; - int tWind = -1; - int tCloud = -1; - int tTask = -1; - int tTexture = -1; - int tAsset = -1; - int tall = -1; - int singlefloat = 4; - - //Agent Throttle Block contains 7 single floatingpoint values. - int j = 0; - - // Some Systems may be big endian... - // it might be smart to do this check more often... - if (!BitConverter.IsLittleEndian) - for (int i = 0; i < 7; i++) - Array.Reverse(throttle, j + i*singlefloat, singlefloat); - - // values gotten from libsecondlife.org/wiki/Throttle. Thanks MW_ - // bytes - // Convert to integer, since.. the full fp space isn't used. - tResend = (int) BitConverter.ToSingle(throttle, j); - j += singlefloat; - tLand = (int) BitConverter.ToSingle(throttle, j); - j += singlefloat; - tWind = (int) BitConverter.ToSingle(throttle, j); - j += singlefloat; - tCloud = (int) BitConverter.ToSingle(throttle, j); - j += singlefloat; - tTask = (int) BitConverter.ToSingle(throttle, j); - j += singlefloat; - tTexture = (int) BitConverter.ToSingle(throttle, j); - j += singlefloat; - tAsset = (int) BitConverter.ToSingle(throttle, j); - - tall = tResend + tLand + tWind + tCloud + tTask + tTexture + tAsset; - /* - m_log.Info("[CLIENT]: Client AgentThrottle - Got throttle:resendbytes=" + tResend + - " landbytes=" + tLand + - " windbytes=" + tWind + - " cloudbytes=" + tCloud + - " taskbytes=" + tTask + - " texturebytes=" + tTexture + - " Assetbytes=" + tAsset + - " Allbytes=" + tall); - */ - - // Total Sanity - // Make sure that the client sent sane total values. - - // If the client didn't send acceptable values.... - // Scale the clients values down until they are acceptable. - - if (tall <= TotalThrottle.Max) - { - ResendThrottle.Throttle = tResend; - LandThrottle.Throttle = tLand; - WindThrottle.Throttle = tWind; - CloudThrottle.Throttle = tCloud; - TaskThrottle.Throttle = tTask; - TextureThrottle.Throttle = tTexture; - AssetThrottle.Throttle = tAsset; - TotalThrottle.Throttle = tall; - } - else if (tall < 1) - { - // client is stupid, penalize him by minning everything - ResendThrottle.Throttle = ResendThrottle.Min; - LandThrottle.Throttle = LandThrottle.Min; - WindThrottle.Throttle = WindThrottle.Min; - CloudThrottle.Throttle = CloudThrottle.Min; - TaskThrottle.Throttle = TaskThrottle.Min; - TextureThrottle.Throttle = TextureThrottle.Min; - AssetThrottle.Throttle = AssetThrottle.Min; - TotalThrottle.Throttle = TotalThrottle.Min; - } - else - { - // we're over so figure out percentages and use those - ResendThrottle.Throttle = tResend; - - LandThrottle.Throttle = ScaleThrottle(tLand, tall, TotalThrottle.Max); - WindThrottle.Throttle = ScaleThrottle(tWind, tall, TotalThrottle.Max); - CloudThrottle.Throttle = ScaleThrottle(tCloud, tall, TotalThrottle.Max); - TaskThrottle.Throttle = ScaleThrottle(tTask, tall, TotalThrottle.Max); - TextureThrottle.Throttle = ScaleThrottle(tTexture, tall, TotalThrottle.Max); - AssetThrottle.Throttle = ScaleThrottle(tAsset, tall, TotalThrottle.Max); - TotalThrottle.Throttle = TotalThrottle.Max; - } - // effectively wiggling the slider causes things reset - ResetCounters(); - } - - // See IPullStatsProvider - public string GetStats() - { - return string.Format("{0,7} {1,7} {2,7} {3,7} {4,7} {5,7} {6,7} {7,7} {8,7} {9,7}", - SendQueue.Count(), - IncomingPacketQueue.Count, - OutgoingPacketQueue.Count, - ResendOutgoingPacketQueue.Count, - LandOutgoingPacketQueue.Count, - WindOutgoingPacketQueue.Count, - CloudOutgoingPacketQueue.Count, - TaskOutgoingPacketQueue.Count, - TextureOutgoingPacketQueue.Count, - AssetOutgoingPacketQueue.Count); - } - - public LLQueItem[] GetQueueArray() - { - return SendQueue.GetQueueArray(); - } - } +/* + * 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.Threading; +using System.Timers; +using libsecondlife; +using libsecondlife.Packets; +using OpenSim.Framework; +using OpenSim.Framework.Statistics; +using OpenSim.Framework.Statistics.Interfaces; +using Timer=System.Timers.Timer; + +namespace OpenSim.Region.ClientStack.LindenUDP +{ + public class LLPacketQueue : IPullStatsProvider + { + //private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + + private bool m_enabled = true; + + private BlockingQueue SendQueue; + + private Queue IncomingPacketQueue; + private Queue OutgoingPacketQueue; + private Queue ResendOutgoingPacketQueue; + private Queue LandOutgoingPacketQueue; + private Queue WindOutgoingPacketQueue; + private Queue CloudOutgoingPacketQueue; + private Queue TaskOutgoingPacketQueue; + private Queue TextureOutgoingPacketQueue; + private Queue AssetOutgoingPacketQueue; + + private Dictionary PendingAcks = new Dictionary(); + private Dictionary NeedAck = new Dictionary(); + + // All throttle times and number of bytes are calculated by dividing by this value + // This value also determines how many times per throttletimems the timer will run + // If throttleimems is 1000 ms, then the timer will fire every 1000/7 milliseconds + + private int throttleTimeDivisor = 7; + + private int throttletimems = 1000; + + private LLPacketThrottle ResendThrottle; + private LLPacketThrottle LandThrottle; + private LLPacketThrottle WindThrottle; + private LLPacketThrottle CloudThrottle; + private LLPacketThrottle TaskThrottle; + private LLPacketThrottle AssetThrottle; + private LLPacketThrottle TextureThrottle; + private LLPacketThrottle TotalThrottle; + + // private long LastThrottle; + // private long ThrottleInterval; + private Timer throttleTimer; + + private LLUUID m_agentId; + + public LLPacketQueue(LLUUID agentId) + { + // 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. + + SendQueue = new BlockingQueue(); + + IncomingPacketQueue = new Queue(); + OutgoingPacketQueue = new Queue(); + ResendOutgoingPacketQueue = new Queue(); + LandOutgoingPacketQueue = new Queue(); + WindOutgoingPacketQueue = new Queue(); + CloudOutgoingPacketQueue = new Queue(); + TaskOutgoingPacketQueue = new Queue(); + TextureOutgoingPacketQueue = new Queue(); + AssetOutgoingPacketQueue = new Queue(); + + + // Set up the throttle classes (min, max, current) in bytes + ResendThrottle = new LLPacketThrottle(5000, 100000, 16000); + LandThrottle = new LLPacketThrottle(1000, 100000, 2000); + WindThrottle = new LLPacketThrottle(1000, 100000, 1000); + CloudThrottle = new LLPacketThrottle(1000, 100000, 1000); + TaskThrottle = new LLPacketThrottle(1000, 800000, 3000); + AssetThrottle = new LLPacketThrottle(1000, 800000, 1000); + TextureThrottle = new LLPacketThrottle(1000, 800000, 4000); + // Total Throttle trumps all + // Number of bytes allowed to go out per second. (256kbps per client) + TotalThrottle = new LLPacketThrottle(0, 1500000, 28000); + + throttleTimer = new Timer((int) (throttletimems/throttleTimeDivisor)); + throttleTimer.Elapsed += new ElapsedEventHandler(ThrottleTimerElapsed); + throttleTimer.Start(); + + // TIMERS needed for this + // LastThrottle = DateTime.Now.Ticks; + // ThrottleInterval = (long)(throttletimems/throttleTimeDivisor); + + m_agentId = agentId; + + if (StatsManager.SimExtraStats != null) + { + StatsManager.SimExtraStats.RegisterPacketQueueStatsProvider(m_agentId, this); + } + } + + /* STANDARD QUEUE MANIPULATION INTERFACES */ + + + public void Enqueue(LLQueItem item) + { + if (!m_enabled) + { + return; + } + // We could micro lock, but that will tend to actually + // probably be worse than just synchronizing on SendQueue + + if (item == null) + { + SendQueue.Enqueue(item); + return; + } + + lock (this) { + switch (item.throttleType) + { + case ThrottleOutPacketType.Resend: + ThrottleCheck(ref ResendThrottle, ref ResendOutgoingPacketQueue, item); + break; + case ThrottleOutPacketType.Texture: + ThrottleCheck(ref TextureThrottle, ref TextureOutgoingPacketQueue, item); + break; + case ThrottleOutPacketType.Task: + ThrottleCheck(ref TaskThrottle, ref TaskOutgoingPacketQueue, item); + break; + case ThrottleOutPacketType.Land: + ThrottleCheck(ref LandThrottle, ref LandOutgoingPacketQueue, item); + break; + case ThrottleOutPacketType.Asset: + ThrottleCheck(ref AssetThrottle, ref AssetOutgoingPacketQueue, item); + break; + case ThrottleOutPacketType.Cloud: + ThrottleCheck(ref CloudThrottle, ref CloudOutgoingPacketQueue, item); + break; + case ThrottleOutPacketType.Wind: + ThrottleCheck(ref WindThrottle, ref WindOutgoingPacketQueue, item); + break; + + default: + // Acknowledgements and other such stuff should go directly to the blocking Queue + // Throttling them may and likely 'will' be problematic + SendQueue.Enqueue(item); + break; + } + } + } + + public LLQueItem Dequeue() + { + return SendQueue.Dequeue(); + } + + public void Flush() + { + lock (this) + { + while (PacketsWaiting()) + { + //Now comes the fun part.. we dump all our elements into m_packetQueue that we've saved up. + if (ResendOutgoingPacketQueue.Count > 0) + { + SendQueue.Enqueue(ResendOutgoingPacketQueue.Dequeue()); + } + if (LandOutgoingPacketQueue.Count > 0) + { + SendQueue.Enqueue(LandOutgoingPacketQueue.Dequeue()); + } + if (WindOutgoingPacketQueue.Count > 0) + { + SendQueue.Enqueue(WindOutgoingPacketQueue.Dequeue()); + } + if (CloudOutgoingPacketQueue.Count > 0) + { + SendQueue.Enqueue(CloudOutgoingPacketQueue.Dequeue()); + } + if (TaskOutgoingPacketQueue.Count > 0) + { + SendQueue.Enqueue(TaskOutgoingPacketQueue.Dequeue()); + } + if (TextureOutgoingPacketQueue.Count > 0) + { + SendQueue.Enqueue(TextureOutgoingPacketQueue.Dequeue()); + } + if (AssetOutgoingPacketQueue.Count > 0) + { + SendQueue.Enqueue(AssetOutgoingPacketQueue.Dequeue()); + } + } + // m_log.Info("[THROTTLE]: Processed " + throttleLoops + " packets"); + } + } + + public void Close() + { + Flush(); + + m_enabled = false; + throttleTimer.Stop(); + + if (StatsManager.SimExtraStats != null) + { + StatsManager.SimExtraStats.DeregisterPacketQueueStatsProvider(m_agentId); + } + } + + private void ResetCounters() + { + ResendThrottle.Reset(); + LandThrottle.Reset(); + WindThrottle.Reset(); + CloudThrottle.Reset(); + TaskThrottle.Reset(); + AssetThrottle.Reset(); + TextureThrottle.Reset(); + TotalThrottle.Reset(); + } + + private bool PacketsWaiting() + { + return (ResendOutgoingPacketQueue.Count > 0 || + LandOutgoingPacketQueue.Count > 0 || + WindOutgoingPacketQueue.Count > 0 || + CloudOutgoingPacketQueue.Count > 0 || + TaskOutgoingPacketQueue.Count > 0 || + AssetOutgoingPacketQueue.Count > 0 || + TextureOutgoingPacketQueue.Count > 0); + } + + public void ProcessThrottle() + { + // I was considering this.. Will an event fire if the thread it's on is blocked? + + // Then I figured out.. it doesn't really matter.. because this thread won't be blocked for long + // The General overhead of the UDP protocol gets sent to the queue un-throttled by this + // so This'll pick up about around the right time. + + int MaxThrottleLoops = 4550; // 50*7 packets can be dequeued at once. + int throttleLoops = 0; + + // We're going to dequeue all of the saved up packets until + // we've hit the throttle limit or there's no more packets to send + lock (this) + { + ResetCounters(); + // m_log.Info("[THROTTLE]: Entering Throttle"); + while (TotalThrottle.UnderLimit() && PacketsWaiting() && + (throttleLoops <= MaxThrottleLoops)) + { + throttleLoops++; + //Now comes the fun part.. we dump all our elements into m_packetQueue that we've saved up. + if (ResendThrottle.UnderLimit() && ResendOutgoingPacketQueue.Count > 0) + { + LLQueItem qpack = ResendOutgoingPacketQueue.Dequeue(); + + SendQueue.Enqueue(qpack); + TotalThrottle.Add(qpack.Packet.ToBytes().Length); + ResendThrottle.Add(qpack.Packet.ToBytes().Length); + } + if (LandThrottle.UnderLimit() && LandOutgoingPacketQueue.Count > 0) + { + LLQueItem qpack = LandOutgoingPacketQueue.Dequeue(); + + SendQueue.Enqueue(qpack); + TotalThrottle.Add(qpack.Packet.ToBytes().Length); + LandThrottle.Add(qpack.Packet.ToBytes().Length); + } + if (WindThrottle.UnderLimit() && WindOutgoingPacketQueue.Count > 0) + { + LLQueItem qpack = WindOutgoingPacketQueue.Dequeue(); + + SendQueue.Enqueue(qpack); + TotalThrottle.Add(qpack.Packet.ToBytes().Length); + WindThrottle.Add(qpack.Packet.ToBytes().Length); + } + if (CloudThrottle.UnderLimit() && CloudOutgoingPacketQueue.Count > 0) + { + LLQueItem qpack = CloudOutgoingPacketQueue.Dequeue(); + + SendQueue.Enqueue(qpack); + TotalThrottle.Add(qpack.Packet.ToBytes().Length); + CloudThrottle.Add(qpack.Packet.ToBytes().Length); + } + if (TaskThrottle.UnderLimit() && TaskOutgoingPacketQueue.Count > 0) + { + LLQueItem qpack = TaskOutgoingPacketQueue.Dequeue(); + + SendQueue.Enqueue(qpack); + TotalThrottle.Add(qpack.Packet.ToBytes().Length); + TaskThrottle.Add(qpack.Packet.ToBytes().Length); + } + if (TextureThrottle.UnderLimit() && TextureOutgoingPacketQueue.Count > 0) + { + LLQueItem qpack = TextureOutgoingPacketQueue.Dequeue(); + + SendQueue.Enqueue(qpack); + TotalThrottle.Add(qpack.Packet.ToBytes().Length); + TextureThrottle.Add(qpack.Packet.ToBytes().Length); + } + if (AssetThrottle.UnderLimit() && AssetOutgoingPacketQueue.Count > 0) + { + LLQueItem qpack = AssetOutgoingPacketQueue.Dequeue(); + + SendQueue.Enqueue(qpack); + TotalThrottle.Add(qpack.Packet.ToBytes().Length); + AssetThrottle.Add(qpack.Packet.ToBytes().Length); + } + } + // m_log.Info("[THROTTLE]: Processed " + throttleLoops + " packets"); + } + } + + private void ThrottleTimerElapsed(object sender, ElapsedEventArgs e) + { + // just to change the signature, and that ProcessThrottle + // will be used elsewhere possibly + ProcessThrottle(); + } + + private void ThrottleCheck(ref LLPacketThrottle throttle, ref Queue q, LLQueItem item) + { + // The idea.. is if the packet throttle queues are empty + // and the client is under throttle for the type. Queue + // it up directly. This basically short cuts having to + // wait for the timer to fire to put things into the + // output queue + + if ((q.Count == 0) && (throttle.UnderLimit())) + { + Monitor.Enter(this); + throttle.Add(item.Packet.ToBytes().Length); + TotalThrottle.Add(item.Packet.ToBytes().Length); + SendQueue.Enqueue(item); + Monitor.Pulse(this); + Monitor.Exit(this); + } + else + { + q.Enqueue(item); + } + } + + + private static int ScaleThrottle(int value, int curmax, int newmax) + { + return (value / curmax) * newmax; + } + + public byte[] GetThrottlesPacked(float multiplier) + { + int singlefloat = 4; + float tResend = ResendThrottle.Throttle*multiplier; + float tLand = LandThrottle.Throttle*multiplier; + float tWind = WindThrottle.Throttle*multiplier; + float tCloud = CloudThrottle.Throttle*multiplier; + float tTask = TaskThrottle.Throttle*multiplier; + float tTexture = TextureThrottle.Throttle*multiplier; + float tAsset = AssetThrottle.Throttle*multiplier; + + byte[] throttles = new byte[singlefloat*7]; + int i = 0; + Buffer.BlockCopy(BitConverter.GetBytes(tResend), 0, throttles, singlefloat*i, singlefloat); + i++; + Buffer.BlockCopy(BitConverter.GetBytes(tLand), 0, throttles, singlefloat*i, singlefloat); + i++; + Buffer.BlockCopy(BitConverter.GetBytes(tWind), 0, throttles, singlefloat*i, singlefloat); + i++; + Buffer.BlockCopy(BitConverter.GetBytes(tCloud), 0, throttles, singlefloat*i, singlefloat); + i++; + Buffer.BlockCopy(BitConverter.GetBytes(tTask), 0, throttles, singlefloat*i, singlefloat); + i++; + Buffer.BlockCopy(BitConverter.GetBytes(tTexture), 0, throttles, singlefloat*i, singlefloat); + i++; + Buffer.BlockCopy(BitConverter.GetBytes(tAsset), 0, throttles, singlefloat*i, singlefloat); + + return throttles; + } + + public void SetThrottleFromClient(byte[] throttle) + { + int tResend = -1; + int tLand = -1; + int tWind = -1; + int tCloud = -1; + int tTask = -1; + int tTexture = -1; + int tAsset = -1; + int tall = -1; + int singlefloat = 4; + + //Agent Throttle Block contains 7 single floatingpoint values. + int j = 0; + + // Some Systems may be big endian... + // it might be smart to do this check more often... + if (!BitConverter.IsLittleEndian) + for (int i = 0; i < 7; i++) + Array.Reverse(throttle, j + i*singlefloat, singlefloat); + + // values gotten from libsecondlife.org/wiki/Throttle. Thanks MW_ + // bytes + // Convert to integer, since.. the full fp space isn't used. + tResend = (int) BitConverter.ToSingle(throttle, j); + j += singlefloat; + tLand = (int) BitConverter.ToSingle(throttle, j); + j += singlefloat; + tWind = (int) BitConverter.ToSingle(throttle, j); + j += singlefloat; + tCloud = (int) BitConverter.ToSingle(throttle, j); + j += singlefloat; + tTask = (int) BitConverter.ToSingle(throttle, j); + j += singlefloat; + tTexture = (int) BitConverter.ToSingle(throttle, j); + j += singlefloat; + tAsset = (int) BitConverter.ToSingle(throttle, j); + + tall = tResend + tLand + tWind + tCloud + tTask + tTexture + tAsset; + /* + m_log.Info("[CLIENT]: Client AgentThrottle - Got throttle:resendbytes=" + tResend + + " landbytes=" + tLand + + " windbytes=" + tWind + + " cloudbytes=" + tCloud + + " taskbytes=" + tTask + + " texturebytes=" + tTexture + + " Assetbytes=" + tAsset + + " Allbytes=" + tall); + */ + + // Total Sanity + // Make sure that the client sent sane total values. + + // If the client didn't send acceptable values.... + // Scale the clients values down until they are acceptable. + + if (tall <= TotalThrottle.Max) + { + ResendThrottle.Throttle = tResend; + LandThrottle.Throttle = tLand; + WindThrottle.Throttle = tWind; + CloudThrottle.Throttle = tCloud; + TaskThrottle.Throttle = tTask; + TextureThrottle.Throttle = tTexture; + AssetThrottle.Throttle = tAsset; + TotalThrottle.Throttle = tall; + } + else if (tall < 1) + { + // client is stupid, penalize him by minning everything + ResendThrottle.Throttle = ResendThrottle.Min; + LandThrottle.Throttle = LandThrottle.Min; + WindThrottle.Throttle = WindThrottle.Min; + CloudThrottle.Throttle = CloudThrottle.Min; + TaskThrottle.Throttle = TaskThrottle.Min; + TextureThrottle.Throttle = TextureThrottle.Min; + AssetThrottle.Throttle = AssetThrottle.Min; + TotalThrottle.Throttle = TotalThrottle.Min; + } + else + { + // we're over so figure out percentages and use those + ResendThrottle.Throttle = tResend; + + LandThrottle.Throttle = ScaleThrottle(tLand, tall, TotalThrottle.Max); + WindThrottle.Throttle = ScaleThrottle(tWind, tall, TotalThrottle.Max); + CloudThrottle.Throttle = ScaleThrottle(tCloud, tall, TotalThrottle.Max); + TaskThrottle.Throttle = ScaleThrottle(tTask, tall, TotalThrottle.Max); + TextureThrottle.Throttle = ScaleThrottle(tTexture, tall, TotalThrottle.Max); + AssetThrottle.Throttle = ScaleThrottle(tAsset, tall, TotalThrottle.Max); + TotalThrottle.Throttle = TotalThrottle.Max; + } + // effectively wiggling the slider causes things reset + ResetCounters(); + } + + // See IPullStatsProvider + public string GetStats() + { + return string.Format("{0,7} {1,7} {2,7} {3,7} {4,7} {5,7} {6,7} {7,7} {8,7} {9,7}", + SendQueue.Count(), + IncomingPacketQueue.Count, + OutgoingPacketQueue.Count, + ResendOutgoingPacketQueue.Count, + LandOutgoingPacketQueue.Count, + WindOutgoingPacketQueue.Count, + CloudOutgoingPacketQueue.Count, + TaskOutgoingPacketQueue.Count, + TextureOutgoingPacketQueue.Count, + AssetOutgoingPacketQueue.Count); + } + + public LLQueItem[] GetQueueArray() + { + return SendQueue.GetQueueArray(); + } + } } \ No newline at end of file diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLPacketServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLPacketServer.cs index 48afa84..6a033c8 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLPacketServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLPacketServer.cs @@ -1,150 +1,150 @@ -/* - * 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.Net; -using System.Net.Sockets; -using libsecondlife; -using libsecondlife.Packets; -using OpenSim.Framework; -using OpenSim.Framework.Communications.Cache; -using OpenSim.Region.ClientStack.LindenUDP; - -namespace OpenSim.Region.ClientStack.LindenUDP -{ - public class LLPacketServer - { - //private static readonly log4net.ILog m_log - // = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); - - private LLClientStackNetworkHandler m_networkHandler; - private IScene m_scene; - - //private readonly ClientManager m_clientManager = new ClientManager(); - //public ClientManager ClientManager - //{ - // get { return m_clientManager; } - //} - - public LLPacketServer(LLClientStackNetworkHandler networkHandler) - { - m_networkHandler = networkHandler; - m_networkHandler.RegisterPacketServer(this); - } - - public IScene LocalScene - { - set { m_scene = value; } - } - - /// - /// - /// - /// - /// - public virtual void InPacket(uint circuitCode, Packet packet) - { - m_scene.ClientManager.InPacket(circuitCode, packet); - } - - protected virtual IClientAPI CreateNewClient(EndPoint remoteEP, UseCircuitCodePacket initialcirpack, - ClientManager clientManager, IScene scene, AssetCache assetCache, - LLPacketServer packServer, AgentCircuitManager authenSessions, - LLUUID agentId, LLUUID sessionId, uint circuitCode, EndPoint proxyEP) - { - return - new LLClientView(remoteEP, scene, assetCache, packServer, authenSessions, agentId, sessionId, circuitCode, proxyEP); - } - - public virtual bool AddNewClient(EndPoint epSender, UseCircuitCodePacket useCircuit, AssetCache assetCache, - AgentCircuitManager authenticateSessionsClass, EndPoint proxyEP) - { - IClientAPI newuser; - - if (m_scene.ClientManager.TryGetClient(useCircuit.CircuitCode.Code, out newuser)) - { - return false; - } - else - { - newuser = CreateNewClient(epSender, useCircuit, m_scene.ClientManager, m_scene, assetCache, this, - authenticateSessionsClass, useCircuit.CircuitCode.ID, - useCircuit.CircuitCode.SessionID, useCircuit.CircuitCode.Code, proxyEP); - - m_scene.ClientManager.Add(useCircuit.CircuitCode.Code, newuser); - - newuser.OnViewerEffect += m_scene.ClientManager.ViewerEffectHandler; - newuser.OnLogout += LogoutHandler; - newuser.OnConnectionClosed += CloseClient; - - return true; - } - } - - public void LogoutHandler(IClientAPI client) - { - client.SendLogoutPacket(); - - CloseClient(client); - } - - /// - /// - /// - /// - /// - /// - /// - public virtual void SendPacketTo(byte[] buffer, int size, SocketFlags flags, uint circuitcode) - { - m_networkHandler.SendPacketTo(buffer, size, flags, circuitcode); - } - - /// - /// - /// - /// - public virtual void CloseCircuit(uint circuitcode) - { - m_networkHandler.RemoveClientCircuit(circuitcode); - - //m_scene.ClientManager.CloseAllAgents(circuitcode); - } - - /// - /// Completely close down the given client. - /// - /// - public virtual void CloseClient(IClientAPI client) - { - //m_log.Info("PacketServer:CloseClient()"); - - CloseCircuit(client.CircuitCode); - m_scene.ClientManager.Remove(client.CircuitCode); - client.Close(false); - } - } +/* + * 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.Net; +using System.Net.Sockets; +using libsecondlife; +using libsecondlife.Packets; +using OpenSim.Framework; +using OpenSim.Framework.Communications.Cache; +using OpenSim.Region.ClientStack.LindenUDP; + +namespace OpenSim.Region.ClientStack.LindenUDP +{ + public class LLPacketServer + { + //private static readonly log4net.ILog m_log + // = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + + private LLClientStackNetworkHandler m_networkHandler; + private IScene m_scene; + + //private readonly ClientManager m_clientManager = new ClientManager(); + //public ClientManager ClientManager + //{ + // get { return m_clientManager; } + //} + + public LLPacketServer(LLClientStackNetworkHandler networkHandler) + { + m_networkHandler = networkHandler; + m_networkHandler.RegisterPacketServer(this); + } + + public IScene LocalScene + { + set { m_scene = value; } + } + + /// + /// + /// + /// + /// + public virtual void InPacket(uint circuitCode, Packet packet) + { + m_scene.ClientManager.InPacket(circuitCode, packet); + } + + protected virtual IClientAPI CreateNewClient(EndPoint remoteEP, UseCircuitCodePacket initialcirpack, + ClientManager clientManager, IScene scene, AssetCache assetCache, + LLPacketServer packServer, AgentCircuitManager authenSessions, + LLUUID agentId, LLUUID sessionId, uint circuitCode, EndPoint proxyEP) + { + return + new LLClientView(remoteEP, scene, assetCache, packServer, authenSessions, agentId, sessionId, circuitCode, proxyEP); + } + + public virtual bool AddNewClient(EndPoint epSender, UseCircuitCodePacket useCircuit, AssetCache assetCache, + AgentCircuitManager authenticateSessionsClass, EndPoint proxyEP) + { + IClientAPI newuser; + + if (m_scene.ClientManager.TryGetClient(useCircuit.CircuitCode.Code, out newuser)) + { + return false; + } + else + { + newuser = CreateNewClient(epSender, useCircuit, m_scene.ClientManager, m_scene, assetCache, this, + authenticateSessionsClass, useCircuit.CircuitCode.ID, + useCircuit.CircuitCode.SessionID, useCircuit.CircuitCode.Code, proxyEP); + + m_scene.ClientManager.Add(useCircuit.CircuitCode.Code, newuser); + + newuser.OnViewerEffect += m_scene.ClientManager.ViewerEffectHandler; + newuser.OnLogout += LogoutHandler; + newuser.OnConnectionClosed += CloseClient; + + return true; + } + } + + public void LogoutHandler(IClientAPI client) + { + client.SendLogoutPacket(); + + CloseClient(client); + } + + /// + /// + /// + /// + /// + /// + /// + public virtual void SendPacketTo(byte[] buffer, int size, SocketFlags flags, uint circuitcode) + { + m_networkHandler.SendPacketTo(buffer, size, flags, circuitcode); + } + + /// + /// + /// + /// + public virtual void CloseCircuit(uint circuitcode) + { + m_networkHandler.RemoveClientCircuit(circuitcode); + + //m_scene.ClientManager.CloseAllAgents(circuitcode); + } + + /// + /// Completely close down the given client. + /// + /// + public virtual void CloseClient(IClientAPI client) + { + //m_log.Info("PacketServer:CloseClient()"); + + CloseCircuit(client.CircuitCode); + m_scene.ClientManager.Remove(client.CircuitCode); + client.Close(false); + } + } } \ No newline at end of file diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLPacketThrottle.cs b/OpenSim/Region/ClientStack/LindenUDP/LLPacketThrottle.cs index 792429a..cd5ff7e 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLPacketThrottle.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLPacketThrottle.cs @@ -1,93 +1,93 @@ -/* - * 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. - */ - -namespace OpenSim.Region.ClientStack.LindenUDP -{ - public class LLPacketThrottle - { - private int max; // max allowable throttle - private int min; // min allowable throttle - private int throttle; // current throttle setting - private static int divisor = 7; // the throttle time divisor, this probably should factor out - private int sent; // current number of bytes sent - - public LLPacketThrottle(int Min, int Max, int Throttle) - { - max = Max; - min = Min; - throttle = Throttle; - sent = 0; - } - - public void Reset() - { - sent = 0; - } - - public bool UnderLimit() - { - return (sent < (throttle/divisor)); - } - - public int Add(int bytes) - { - sent += bytes; - return sent; - } - - // Properties - public int Max - { - get { return max; } - } - - public int Min - { - get { return min; } - } - - public int Throttle - { - get { return throttle; } - set - { - if (value > max) - { - throttle = max; - } - else if (value < min) - { - throttle = min; - } - else - { - throttle = value; - } - } - } - } +/* + * 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. + */ + +namespace OpenSim.Region.ClientStack.LindenUDP +{ + public class LLPacketThrottle + { + private int max; // max allowable throttle + private int min; // min allowable throttle + private int throttle; // current throttle setting + private static int divisor = 7; // the throttle time divisor, this probably should factor out + private int sent; // current number of bytes sent + + public LLPacketThrottle(int Min, int Max, int Throttle) + { + max = Max; + min = Min; + throttle = Throttle; + sent = 0; + } + + public void Reset() + { + sent = 0; + } + + public bool UnderLimit() + { + return (sent < (throttle/divisor)); + } + + public int Add(int bytes) + { + sent += bytes; + return sent; + } + + // Properties + public int Max + { + get { return max; } + } + + public int Min + { + get { return min; } + } + + public int Throttle + { + get { return throttle; } + set + { + if (value > max) + { + throttle = max; + } + else if (value < min) + { + throttle = min; + } + else + { + throttle = value; + } + } + } + } } \ No newline at end of file diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLQueItem.cs b/OpenSim/Region/ClientStack/LindenUDP/LLQueItem.cs index 4253378..2b6e781 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLQueItem.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLQueItem.cs @@ -1,43 +1,43 @@ -/* - * 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 libsecondlife.Packets; -using OpenSim.Framework; - -namespace OpenSim.Region.ClientStack.LindenUDP -{ - public class LLQueItem - { - public LLQueItem() - { - } - - public Packet Packet; - public bool Incoming; - public ThrottleOutPacketType throttleType; - } +/* + * 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 libsecondlife.Packets; +using OpenSim.Framework; + +namespace OpenSim.Region.ClientStack.LindenUDP +{ + public class LLQueItem + { + public LLQueItem() + { + } + + public Packet Packet; + public bool Incoming; + public ThrottleOutPacketType throttleType; + } } \ No newline at end of file diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index b5ace50..95510e1 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs @@ -1,509 +1,509 @@ -/* - * 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.Reflection; -using libsecondlife.Packets; -using log4net; -using OpenSim.Framework; -using OpenSim.Framework.Communications.Cache; -using OpenSim.Region.ClientStack.LindenUDP; -using OpenSim.Region.Environment.Scenes; - -namespace OpenSim.Region.ClientStack.LindenUDP -{ - public class LLUDPServer : LLClientStackNetworkHandler, IClientNetworkServer - { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - protected Dictionary clientCircuits = new Dictionary(); - public Dictionary clientCircuits_reverse = new Dictionary(); - protected Dictionary proxyCircuits = new Dictionary(); - private Socket m_socket; - protected IPEndPoint ServerIncoming; - protected byte[] RecvBuffer = new byte[4096]; - protected byte[] ZeroBuffer = new byte[8192]; - protected IPEndPoint ipeSender; - protected EndPoint epSender; - protected EndPoint epProxy; - protected int proxyPortOffset; - protected AsyncCallback ReceivedData; - protected LLPacketServer m_packetServer; - protected Location m_location; - - protected uint listenPort; - protected bool Allow_Alternate_Port; - protected IPAddress listenIP = IPAddress.Parse("0.0.0.0"); - protected IScene m_localScene; - protected AssetCache m_assetCache; - protected AgentCircuitManager m_authenticateSessionsClass; - - public LLPacketServer PacketServer - { - get { return m_packetServer; } - set { m_packetServer = value; } - } - - public IScene LocalScene - { - set - { - m_localScene = value; - m_packetServer.LocalScene = m_localScene; - m_location = new Location(m_localScene.RegionInfo.RegionHandle); - } - } - - public ulong RegionHandle - { - get { return m_location.RegionHandle; } - } - - Socket IClientNetworkServer.Server - { - get { return m_socket; } - } - - public bool HandlesRegion(Location x) - { - return x == m_location; - } - - public void AddScene(Scene x) - { - LocalScene = x; - } - - public void Start() - { - ServerListener(); - } - - public void Stop() - { - m_socket.Close(); - } - - public LLUDPServer() - { - } - - public LLUDPServer(IPAddress _listenIP, ref uint port, int proxyPortOffset, bool allow_alternate_port, AssetCache assetCache, AgentCircuitManager authenticateClass) - { - this.proxyPortOffset = proxyPortOffset; - listenPort = (uint) (port + proxyPortOffset); - listenIP = _listenIP; - Allow_Alternate_Port = allow_alternate_port; - m_assetCache = assetCache; - m_authenticateSessionsClass = authenticateClass; - CreatePacketServer(); - - // Return new port - // This because in Grid mode it is not really important what port the region listens to as long as it is correctly registered. - // So the option allow_alternate_ports="true" was added to default.xml - port = (uint)(listenPort - proxyPortOffset); - } - - protected virtual void CreatePacketServer() - { - LLPacketServer packetServer = new LLPacketServer(this); - } - - protected virtual void OnReceivedData(IAsyncResult result) - { - ipeSender = new IPEndPoint(listenIP, 0); - epSender = (EndPoint) ipeSender; - Packet packet = null; - - int numBytes = 1; - - try - { - numBytes = m_socket.EndReceiveFrom(result, ref epSender); - } - catch (SocketException e) - { - // TODO : Actually only handle those states that we have control over, re-throw everything else, - // TODO: implement cases as we encounter them. - //m_log.Error("[UDPSERVER]: Connection Error! - " + e.ToString()); - switch (e.SocketErrorCode) - { - case SocketError.AlreadyInProgress: - case SocketError.NetworkReset: - case SocketError.ConnectionReset: - try - { - CloseEndPoint(epSender); - } - catch (Exception a) - { - m_log.Info("[UDPSERVER]: " + a.ToString()); - } - try - { - m_socket.BeginReceiveFrom(RecvBuffer, 0, RecvBuffer.Length, SocketFlags.None, ref epSender, - ReceivedData, null); - - // Ter: For some stupid reason ConnectionReset basically kills our async event structure.. - // so therefore.. we've got to tell the server to BeginReceiveFrom again. - // This will happen over and over until we've gone through all packets - // sent to and from this particular user. - // Stupid I know.. - // but Flusing the buffer would be even more stupid... so, we're stuck with this ugly method. - } - catch (SocketException) - { - } - break; - default: - try - { - CloseEndPoint(epSender); - } - catch (Exception) - { - //m_log.Info("[UDPSERVER]" + a.ToString()); - } - try - { - m_socket.BeginReceiveFrom(RecvBuffer, 0, RecvBuffer.Length, SocketFlags.None, ref epSender, - ReceivedData, null); - - // Ter: For some stupid reason ConnectionReset basically kills our async event structure.. - // so therefore.. we've got to tell the server to BeginReceiveFrom again. - // This will happen over and over until we've gone through all packets - // sent to and from this particular user. - // Stupid I know.. - // but Flusing the buffer would be even more stupid... so, we're stuck with this ugly method. - } - catch (SocketException e2) - { - m_log.Error("[UDPSERVER]: " + e2.ToString()); - } - - // Here's some reference code! :D - // Shutdown and restart the UDP listener! hehe - // Shiny - - //Server.Shutdown(SocketShutdown.Both); - //CloseEndPoint(epSender); - //ServerListener(); - break; - } - - //return; - } - catch (ObjectDisposedException e) - { - m_log.Debug("[UDPSERVER]: " + e.ToString()); - try - { - m_socket.BeginReceiveFrom(RecvBuffer, 0, RecvBuffer.Length, SocketFlags.None, ref epSender, - ReceivedData, null); - - // Ter: For some stupid reason ConnectionReset basically kills our async event structure.. - // so therefore.. we've got to tell the server to BeginReceiveFrom again. - // This will happen over and over until we've gone through all packets - // sent to and from this particular user. - // Stupid I know.. - // but Flusing the buffer would be even more stupid... so, we're stuck with this ugly method. - } - - catch (SocketException e2) - { - m_log.Error("[UDPSERVER]: " + e2.ToString()); - } - catch (ObjectDisposedException) - { - } - //return; - } - - //System.Console.WriteLine("UDPServer : recieved message from {0}", epSender.ToString()); - epProxy = epSender; - if (proxyPortOffset != 0) - { - epSender = PacketPool.DecodeProxyMessage(RecvBuffer, ref numBytes); - } - - int packetEnd = numBytes - 1; - - try - { - packet = PacketPool.Instance.GetPacket(RecvBuffer, ref packetEnd, ZeroBuffer); - } - catch (Exception e) - { - m_log.Debug("[UDPSERVER]: " + e.ToString()); - } - - try - { - m_socket.BeginReceiveFrom(RecvBuffer, 0, RecvBuffer.Length, SocketFlags.None, ref epSender, ReceivedData, null); - } - catch (SocketException) - { - try - { - CloseEndPoint(epSender); - } - catch (Exception a) - { - m_log.Info("[UDPSERVER]: " + a.ToString()); - } - try - { - m_socket.BeginReceiveFrom(RecvBuffer, 0, RecvBuffer.Length, SocketFlags.None, ref epSender, - ReceivedData, null); - - // Ter: For some stupid reason ConnectionReset basically kills our async event structure.. - // so therefore.. we've got to tell the server to BeginReceiveFrom again. - // This will happen over and over until we've gone through all packets - // sent to and from this particular user. - // Stupid I know.. - // but Flusing the buffer would be even more stupid... so, we're stuck with this ugly method. - } - catch (SocketException e5) - { - m_log.Error("[UDPSERVER]: " + e5.ToString()); - } - } - catch (ObjectDisposedException) - { - } - - if (packet != null) - { - try - { - // do we already have a circuit for this endpoint - uint circuit; - - bool ret = false; - lock (clientCircuits) - { - ret = clientCircuits.TryGetValue(epSender, out circuit); - } - if (ret) - { - //if so then send packet to the packetserver - //m_log.Warn("[UDPSERVER]: ALREADY HAVE Circuit!"); - m_packetServer.InPacket(circuit, packet); - } - else if (packet.Type == PacketType.UseCircuitCode) - { - // new client - m_log.Debug("[UDPSERVER]: Adding New Client"); - AddNewClient(packet); - - UseCircuitCodePacket p = (UseCircuitCodePacket)packet; - - // Ack the first UseCircuitCode packet - 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 = packet.Header.Sequence; - ack_it.Header.Reliable = false; - SendPacketTo(ack_it.ToBytes(),ack_it.ToBytes().Length,SocketFlags.None,p.CircuitCode.Code); - } - } - catch (Exception) - { - m_log.Error("[UDPSERVER]: Exception in processing packet."); - m_log.Debug("[UDPSERVER]: Adding New Client"); - try - { - AddNewClient(packet); - } - catch (Exception e3) - { - m_log.Error("[UDPSERVER]: Adding New Client threw exception " + e3.ToString()); - m_socket.BeginReceiveFrom(RecvBuffer, 0, RecvBuffer.Length, SocketFlags.None, ref epSender, - ReceivedData, null); - } - } - } - - } - - private void CloseEndPoint(EndPoint sender) - { - uint circuit; - lock (clientCircuits) - { - if (clientCircuits.TryGetValue(sender, out circuit)) - { - m_packetServer.CloseCircuit(circuit); - } - } - } - - protected virtual void AddNewClient(Packet packet) - { - //Slave regions don't accept new clients - if(m_localScene.Region_Status != RegionStatus.SlaveScene) - { - UseCircuitCodePacket useCircuit = (UseCircuitCodePacket) packet; - lock (clientCircuits) - { - if (!clientCircuits.ContainsKey(epSender)) - clientCircuits.Add(epSender, useCircuit.CircuitCode.Code); - else - m_log.Error("[UDPSERVER]: clientCircuits already contans entry for user " + useCircuit.CircuitCode.Code.ToString() + ". NOT adding."); - } - lock (clientCircuits_reverse) - { - if (!clientCircuits_reverse.ContainsKey(useCircuit.CircuitCode.Code)) - clientCircuits_reverse.Add(useCircuit.CircuitCode.Code, epSender); - else - m_log.Error("[UDPSERVER]: clientCurcuits_reverse already contains entry for user " + useCircuit.CircuitCode.Code.ToString() + ". NOT adding."); - } - - lock (proxyCircuits) - { - if (!proxyCircuits.ContainsKey(useCircuit.CircuitCode.Code)) - proxyCircuits.Add(useCircuit.CircuitCode.Code, epProxy); - else - m_log.Error("[UDPSERVER]: proxyCircuits already contains entry for user " + useCircuit.CircuitCode.Code.ToString() + ". NOT adding."); - } - - PacketServer.AddNewClient(epSender, useCircuit, m_assetCache, m_authenticateSessionsClass, epProxy); - } - PacketPool.Instance.ReturnPacket(packet); - } - - public void ServerListener() - { - uint newPort = listenPort; - m_log.Info("[SERVER]: Opening UDP socket on " + listenIP.ToString() + " " + newPort + "."); - - ServerIncoming = new IPEndPoint(listenIP, (int)newPort); - m_socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); - m_socket.Bind(ServerIncoming); - listenPort = newPort; - - m_log.Info("[SERVER]: UDP socket bound, getting ready to listen"); - - ipeSender = new IPEndPoint(listenIP, 0); - epSender = (EndPoint)ipeSender; - ReceivedData = new AsyncCallback(OnReceivedData); - m_socket.BeginReceiveFrom(RecvBuffer, 0, RecvBuffer.Length, SocketFlags.None, ref epSender, ReceivedData, null); - - m_log.Info("[SERVER]: Listening on port " + newPort); - } - - public virtual void RegisterPacketServer(LLPacketServer server) - { - m_packetServer = server; - } - - public virtual void SendPacketTo(byte[] buffer, int size, SocketFlags flags, uint circuitcode) - //EndPoint packetSender) - { - // find the endpoint for this circuit - EndPoint sendto = null; - lock (clientCircuits_reverse) - { - if (clientCircuits_reverse.TryGetValue(circuitcode, out sendto)) - { - //we found the endpoint so send the packet to it - if (proxyPortOffset != 0) - { - //MainLog.Instance.Verbose("UDPSERVER", "SendPacketTo proxy " + proxyCircuits[circuitcode].ToString() + ": client " + sendto.ToString()); - PacketPool.EncodeProxyMessage(buffer, ref size, sendto); - m_socket.SendTo(buffer, size, flags, proxyCircuits[circuitcode]); - } - else - { - //MainLog.Instance.Verbose("UDPSERVER", "SendPacketTo : client " + sendto.ToString()); - m_socket.SendTo(buffer, size, flags, sendto); - } - } - } - } - - public virtual void RemoveClientCircuit(uint circuitcode) - { - EndPoint sendto = null; - lock (clientCircuits_reverse) - { - if (clientCircuits_reverse.TryGetValue(circuitcode, out sendto)) - { - clientCircuits.Remove(sendto); - - clientCircuits_reverse.Remove(circuitcode); - proxyCircuits.Remove(circuitcode); - } - } - } - - public void RestoreClient(AgentCircuitData circuit, EndPoint userEP, EndPoint proxyEP) - { - //MainLog.Instance.Verbose("UDPSERVER", "RestoreClient"); - - UseCircuitCodePacket useCircuit = new UseCircuitCodePacket(); - useCircuit.CircuitCode.Code = circuit.circuitcode; - useCircuit.CircuitCode.ID = circuit.AgentID; - useCircuit.CircuitCode.SessionID = circuit.SessionID; - - lock (clientCircuits) - { - if (!clientCircuits.ContainsKey(userEP)) - clientCircuits.Add(userEP, useCircuit.CircuitCode.Code); - else - m_log.Error("[UDPSERVER]: clientCircuits already contans entry for user " + useCircuit.CircuitCode.Code.ToString() + ". NOT adding."); - } - lock (clientCircuits_reverse) - { - if (!clientCircuits_reverse.ContainsKey(useCircuit.CircuitCode.Code)) - clientCircuits_reverse.Add(useCircuit.CircuitCode.Code, userEP); - else - m_log.Error("[UDPSERVER]: clientCurcuits_reverse already contains entry for user " + useCircuit.CircuitCode.Code.ToString() + ". NOT adding."); - } - - lock (proxyCircuits) - { - if (!proxyCircuits.ContainsKey(useCircuit.CircuitCode.Code)) - { - proxyCircuits.Add(useCircuit.CircuitCode.Code, proxyEP); - } - else - { - // re-set proxy endpoint - proxyCircuits.Remove(useCircuit.CircuitCode.Code); - proxyCircuits.Add(useCircuit.CircuitCode.Code, proxyEP); - } - } - - PacketServer.AddNewClient(userEP, useCircuit, m_assetCache, m_authenticateSessionsClass, proxyEP); - } - } +/* + * 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.Reflection; +using libsecondlife.Packets; +using log4net; +using OpenSim.Framework; +using OpenSim.Framework.Communications.Cache; +using OpenSim.Region.ClientStack.LindenUDP; +using OpenSim.Region.Environment.Scenes; + +namespace OpenSim.Region.ClientStack.LindenUDP +{ + public class LLUDPServer : LLClientStackNetworkHandler, IClientNetworkServer + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + protected Dictionary clientCircuits = new Dictionary(); + public Dictionary clientCircuits_reverse = new Dictionary(); + protected Dictionary proxyCircuits = new Dictionary(); + private Socket m_socket; + protected IPEndPoint ServerIncoming; + protected byte[] RecvBuffer = new byte[4096]; + protected byte[] ZeroBuffer = new byte[8192]; + protected IPEndPoint ipeSender; + protected EndPoint epSender; + protected EndPoint epProxy; + protected int proxyPortOffset; + protected AsyncCallback ReceivedData; + protected LLPacketServer m_packetServer; + protected Location m_location; + + protected uint listenPort; + protected bool Allow_Alternate_Port; + protected IPAddress listenIP = IPAddress.Parse("0.0.0.0"); + protected IScene m_localScene; + protected AssetCache m_assetCache; + protected AgentCircuitManager m_authenticateSessionsClass; + + public LLPacketServer PacketServer + { + get { return m_packetServer; } + set { m_packetServer = value; } + } + + public IScene LocalScene + { + set + { + m_localScene = value; + m_packetServer.LocalScene = m_localScene; + m_location = new Location(m_localScene.RegionInfo.RegionHandle); + } + } + + public ulong RegionHandle + { + get { return m_location.RegionHandle; } + } + + Socket IClientNetworkServer.Server + { + get { return m_socket; } + } + + public bool HandlesRegion(Location x) + { + return x == m_location; + } + + public void AddScene(Scene x) + { + LocalScene = x; + } + + public void Start() + { + ServerListener(); + } + + public void Stop() + { + m_socket.Close(); + } + + public LLUDPServer() + { + } + + public LLUDPServer(IPAddress _listenIP, ref uint port, int proxyPortOffset, bool allow_alternate_port, AssetCache assetCache, AgentCircuitManager authenticateClass) + { + this.proxyPortOffset = proxyPortOffset; + listenPort = (uint) (port + proxyPortOffset); + listenIP = _listenIP; + Allow_Alternate_Port = allow_alternate_port; + m_assetCache = assetCache; + m_authenticateSessionsClass = authenticateClass; + CreatePacketServer(); + + // Return new port + // This because in Grid mode it is not really important what port the region listens to as long as it is correctly registered. + // So the option allow_alternate_ports="true" was added to default.xml + port = (uint)(listenPort - proxyPortOffset); + } + + protected virtual void CreatePacketServer() + { + LLPacketServer packetServer = new LLPacketServer(this); + } + + protected virtual void OnReceivedData(IAsyncResult result) + { + ipeSender = new IPEndPoint(listenIP, 0); + epSender = (EndPoint) ipeSender; + Packet packet = null; + + int numBytes = 1; + + try + { + numBytes = m_socket.EndReceiveFrom(result, ref epSender); + } + catch (SocketException e) + { + // TODO : Actually only handle those states that we have control over, re-throw everything else, + // TODO: implement cases as we encounter them. + //m_log.Error("[UDPSERVER]: Connection Error! - " + e.ToString()); + switch (e.SocketErrorCode) + { + case SocketError.AlreadyInProgress: + case SocketError.NetworkReset: + case SocketError.ConnectionReset: + try + { + CloseEndPoint(epSender); + } + catch (Exception a) + { + m_log.Info("[UDPSERVER]: " + a.ToString()); + } + try + { + m_socket.BeginReceiveFrom(RecvBuffer, 0, RecvBuffer.Length, SocketFlags.None, ref epSender, + ReceivedData, null); + + // Ter: For some stupid reason ConnectionReset basically kills our async event structure.. + // so therefore.. we've got to tell the server to BeginReceiveFrom again. + // This will happen over and over until we've gone through all packets + // sent to and from this particular user. + // Stupid I know.. + // but Flusing the buffer would be even more stupid... so, we're stuck with this ugly method. + } + catch (SocketException) + { + } + break; + default: + try + { + CloseEndPoint(epSender); + } + catch (Exception) + { + //m_log.Info("[UDPSERVER]" + a.ToString()); + } + try + { + m_socket.BeginReceiveFrom(RecvBuffer, 0, RecvBuffer.Length, SocketFlags.None, ref epSender, + ReceivedData, null); + + // Ter: For some stupid reason ConnectionReset basically kills our async event structure.. + // so therefore.. we've got to tell the server to BeginReceiveFrom again. + // This will happen over and over until we've gone through all packets + // sent to and from this particular user. + // Stupid I know.. + // but Flusing the buffer would be even more stupid... so, we're stuck with this ugly method. + } + catch (SocketException e2) + { + m_log.Error("[UDPSERVER]: " + e2.ToString()); + } + + // Here's some reference code! :D + // Shutdown and restart the UDP listener! hehe + // Shiny + + //Server.Shutdown(SocketShutdown.Both); + //CloseEndPoint(epSender); + //ServerListener(); + break; + } + + //return; + } + catch (ObjectDisposedException e) + { + m_log.Debug("[UDPSERVER]: " + e.ToString()); + try + { + m_socket.BeginReceiveFrom(RecvBuffer, 0, RecvBuffer.Length, SocketFlags.None, ref epSender, + ReceivedData, null); + + // Ter: For some stupid reason ConnectionReset basically kills our async event structure.. + // so therefore.. we've got to tell the server to BeginReceiveFrom again. + // This will happen over and over until we've gone through all packets + // sent to and from this particular user. + // Stupid I know.. + // but Flusing the buffer would be even more stupid... so, we're stuck with this ugly method. + } + + catch (SocketException e2) + { + m_log.Error("[UDPSERVER]: " + e2.ToString()); + } + catch (ObjectDisposedException) + { + } + //return; + } + + //System.Console.WriteLine("UDPServer : recieved message from {0}", epSender.ToString()); + epProxy = epSender; + if (proxyPortOffset != 0) + { + epSender = PacketPool.DecodeProxyMessage(RecvBuffer, ref numBytes); + } + + int packetEnd = numBytes - 1; + + try + { + packet = PacketPool.Instance.GetPacket(RecvBuffer, ref packetEnd, ZeroBuffer); + } + catch (Exception e) + { + m_log.Debug("[UDPSERVER]: " + e.ToString()); + } + + try + { + m_socket.BeginReceiveFrom(RecvBuffer, 0, RecvBuffer.Length, SocketFlags.None, ref epSender, ReceivedData, null); + } + catch (SocketException) + { + try + { + CloseEndPoint(epSender); + } + catch (Exception a) + { + m_log.Info("[UDPSERVER]: " + a.ToString()); + } + try + { + m_socket.BeginReceiveFrom(RecvBuffer, 0, RecvBuffer.Length, SocketFlags.None, ref epSender, + ReceivedData, null); + + // Ter: For some stupid reason ConnectionReset basically kills our async event structure.. + // so therefore.. we've got to tell the server to BeginReceiveFrom again. + // This will happen over and over until we've gone through all packets + // sent to and from this particular user. + // Stupid I know.. + // but Flusing the buffer would be even more stupid... so, we're stuck with this ugly method. + } + catch (SocketException e5) + { + m_log.Error("[UDPSERVER]: " + e5.ToString()); + } + } + catch (ObjectDisposedException) + { + } + + if (packet != null) + { + try + { + // do we already have a circuit for this endpoint + uint circuit; + + bool ret = false; + lock (clientCircuits) + { + ret = clientCircuits.TryGetValue(epSender, out circuit); + } + if (ret) + { + //if so then send packet to the packetserver + //m_log.Warn("[UDPSERVER]: ALREADY HAVE Circuit!"); + m_packetServer.InPacket(circuit, packet); + } + else if (packet.Type == PacketType.UseCircuitCode) + { + // new client + m_log.Debug("[UDPSERVER]: Adding New Client"); + AddNewClient(packet); + + UseCircuitCodePacket p = (UseCircuitCodePacket)packet; + + // Ack the first UseCircuitCode packet + 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 = packet.Header.Sequence; + ack_it.Header.Reliable = false; + SendPacketTo(ack_it.ToBytes(),ack_it.ToBytes().Length,SocketFlags.None,p.CircuitCode.Code); + } + } + catch (Exception) + { + m_log.Error("[UDPSERVER]: Exception in processing packet."); + m_log.Debug("[UDPSERVER]: Adding New Client"); + try + { + AddNewClient(packet); + } + catch (Exception e3) + { + m_log.Error("[UDPSERVER]: Adding New Client threw exception " + e3.ToString()); + m_socket.BeginReceiveFrom(RecvBuffer, 0, RecvBuffer.Length, SocketFlags.None, ref epSender, + ReceivedData, null); + } + } + } + + } + + private void CloseEndPoint(EndPoint sender) + { + uint circuit; + lock (clientCircuits) + { + if (clientCircuits.TryGetValue(sender, out circuit)) + { + m_packetServer.CloseCircuit(circuit); + } + } + } + + protected virtual void AddNewClient(Packet packet) + { + //Slave regions don't accept new clients + if(m_localScene.Region_Status != RegionStatus.SlaveScene) + { + UseCircuitCodePacket useCircuit = (UseCircuitCodePacket) packet; + lock (clientCircuits) + { + if (!clientCircuits.ContainsKey(epSender)) + clientCircuits.Add(epSender, useCircuit.CircuitCode.Code); + else + m_log.Error("[UDPSERVER]: clientCircuits already contans entry for user " + useCircuit.CircuitCode.Code.ToString() + ". NOT adding."); + } + lock (clientCircuits_reverse) + { + if (!clientCircuits_reverse.ContainsKey(useCircuit.CircuitCode.Code)) + clientCircuits_reverse.Add(useCircuit.CircuitCode.Code, epSender); + else + m_log.Error("[UDPSERVER]: clientCurcuits_reverse already contains entry for user " + useCircuit.CircuitCode.Code.ToString() + ". NOT adding."); + } + + lock (proxyCircuits) + { + if (!proxyCircuits.ContainsKey(useCircuit.CircuitCode.Code)) + proxyCircuits.Add(useCircuit.CircuitCode.Code, epProxy); + else + m_log.Error("[UDPSERVER]: proxyCircuits already contains entry for user " + useCircuit.CircuitCode.Code.ToString() + ". NOT adding."); + } + + PacketServer.AddNewClient(epSender, useCircuit, m_assetCache, m_authenticateSessionsClass, epProxy); + } + PacketPool.Instance.ReturnPacket(packet); + } + + public void ServerListener() + { + uint newPort = listenPort; + m_log.Info("[SERVER]: Opening UDP socket on " + listenIP.ToString() + " " + newPort + "."); + + ServerIncoming = new IPEndPoint(listenIP, (int)newPort); + m_socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); + m_socket.Bind(ServerIncoming); + listenPort = newPort; + + m_log.Info("[SERVER]: UDP socket bound, getting ready to listen"); + + ipeSender = new IPEndPoint(listenIP, 0); + epSender = (EndPoint)ipeSender; + ReceivedData = new AsyncCallback(OnReceivedData); + m_socket.BeginReceiveFrom(RecvBuffer, 0, RecvBuffer.Length, SocketFlags.None, ref epSender, ReceivedData, null); + + m_log.Info("[SERVER]: Listening on port " + newPort); + } + + public virtual void RegisterPacketServer(LLPacketServer server) + { + m_packetServer = server; + } + + public virtual void SendPacketTo(byte[] buffer, int size, SocketFlags flags, uint circuitcode) + //EndPoint packetSender) + { + // find the endpoint for this circuit + EndPoint sendto = null; + lock (clientCircuits_reverse) + { + if (clientCircuits_reverse.TryGetValue(circuitcode, out sendto)) + { + //we found the endpoint so send the packet to it + if (proxyPortOffset != 0) + { + //MainLog.Instance.Verbose("UDPSERVER", "SendPacketTo proxy " + proxyCircuits[circuitcode].ToString() + ": client " + sendto.ToString()); + PacketPool.EncodeProxyMessage(buffer, ref size, sendto); + m_socket.SendTo(buffer, size, flags, proxyCircuits[circuitcode]); + } + else + { + //MainLog.Instance.Verbose("UDPSERVER", "SendPacketTo : client " + sendto.ToString()); + m_socket.SendTo(buffer, size, flags, sendto); + } + } + } + } + + public virtual void RemoveClientCircuit(uint circuitcode) + { + EndPoint sendto = null; + lock (clientCircuits_reverse) + { + if (clientCircuits_reverse.TryGetValue(circuitcode, out sendto)) + { + clientCircuits.Remove(sendto); + + clientCircuits_reverse.Remove(circuitcode); + proxyCircuits.Remove(circuitcode); + } + } + } + + public void RestoreClient(AgentCircuitData circuit, EndPoint userEP, EndPoint proxyEP) + { + //MainLog.Instance.Verbose("UDPSERVER", "RestoreClient"); + + UseCircuitCodePacket useCircuit = new UseCircuitCodePacket(); + useCircuit.CircuitCode.Code = circuit.circuitcode; + useCircuit.CircuitCode.ID = circuit.AgentID; + useCircuit.CircuitCode.SessionID = circuit.SessionID; + + lock (clientCircuits) + { + if (!clientCircuits.ContainsKey(userEP)) + clientCircuits.Add(userEP, useCircuit.CircuitCode.Code); + else + m_log.Error("[UDPSERVER]: clientCircuits already contans entry for user " + useCircuit.CircuitCode.Code.ToString() + ". NOT adding."); + } + lock (clientCircuits_reverse) + { + if (!clientCircuits_reverse.ContainsKey(useCircuit.CircuitCode.Code)) + clientCircuits_reverse.Add(useCircuit.CircuitCode.Code, userEP); + else + m_log.Error("[UDPSERVER]: clientCurcuits_reverse already contains entry for user " + useCircuit.CircuitCode.Code.ToString() + ". NOT adding."); + } + + lock (proxyCircuits) + { + if (!proxyCircuits.ContainsKey(useCircuit.CircuitCode.Code)) + { + proxyCircuits.Add(useCircuit.CircuitCode.Code, proxyEP); + } + else + { + // re-set proxy endpoint + proxyCircuits.Remove(useCircuit.CircuitCode.Code); + proxyCircuits.Add(useCircuit.CircuitCode.Code, proxyEP); + } + } + + PacketServer.AddNewClient(userEP, useCircuit, m_assetCache, m_authenticateSessionsClass, proxyEP); + } + } } \ No newline at end of file -- cgit v1.1