/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSim Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Timers;
using Axiom.Math;
using libsecondlife;
using libsecondlife.Packets;
using OpenSim.Framework;
using OpenSim.Framework.Communications.Cache;
using OpenSim.Framework.Console;
using Timer=System.Timers.Timer;
namespace OpenSim.Region.ClientStack
{
public delegate bool PacketMethod(IClientAPI simClient, Packet packet);
///
/// Handles new client connections
/// Constructor takes a single Packet and authenticates everything
///
public class ClientView : IClientAPI
{
public static TerrainManager TerrainManager;
protected static Dictionary PacketHandlers =
new Dictionary(); //Global/static handlers for all clients
protected Dictionary m_packetHandlers = new Dictionary();
//local handlers for this instance
private LLUUID m_sessionId;
private LLUUID m_secureSessionId = LLUUID.Zero;
public LLUUID SecureSessionId
{
get { return m_secureSessionId; }
}
public string firstName;
public string lastName;
private UseCircuitCodePacket cirpack;
public Thread ClientThread;
public LLVector3 startpos;
//private AgentAssetUpload UploadAssets;
private LLUUID newAssetFolder = LLUUID.Zero;
private int debug = 0;
protected IScene m_scene;
public IScene Scene
{
get { return m_scene; }
}
private ClientManager m_clientManager;
private AssetCache m_assetCache;
// private InventoryCache m_inventoryCache;
private int cachedtextureserial = 0;
protected AgentCircuitManager m_authenticateSessionsHandler;
private Encoding enc = Encoding.ASCII;
// Dead client detection vars
private Timer clientPingTimer;
private int packetsReceived = 0;
private int probesWithNoIngressPackets = 0;
private int lastPacketsReceived = 0;
// 1536000
private int throttleOutboundMax = 1536000; // Number of bytes allowed to go out per second. (256kbps per client)
// TODO: Make this variable. Lower throttle on un-ack. Raise over time?
private int bytesSent = 0; // Number of bytes sent this period
private int throttleOutbound = 162144; // Number of bytes allowed to go out per second. (256kbps per client)
// TODO: Make this variable. Lower throttle on un-ack. Raise over time
// 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;
// Maximum -per type- throttle
private int ResendthrottleMAX = 100000;
private int LandthrottleMax = 100000;
private int WindthrottleMax = 100000;
private int CloudthrottleMax = 100000;
private int TaskthrottleMax = 800000;
private int AssetthrottleMax = 800000;
private int TexturethrottleMax = 800000;
// Minimum -per type- throttle
private int ResendthrottleMin = 5000; // setting resendmin to 0 results in mostly dropped packets
private int LandthrottleMin = 1000;
private int WindthrottleMin = 1000;
private int CloudthrottleMin = 1000;
private int TaskthrottleMin = 1000;
private int AssetthrottleMin = 1000;
private int TexturethrottleMin = 1000;
// Sim default per-client settings.
private int ResendthrottleOutbound = 50000;
private int ResendBytesSent = 0;
private int LandthrottleOutbound = 100000;
private int LandBytesSent = 0;
private int WindthrottleOutbound = 10000;
private int WindBytesSent = 0;
private int CloudthrottleOutbound = 5000;
private int CloudBytesSent = 0;
private int TaskthrottleOutbound = 100000;
private int TaskBytesSent = 0;
private int AssetthrottleOutbound = 80000;
private int AssetBytesSent = 0;
private int TexturethrottleOutbound = 100000;
private int TextureBytesSent = 0;
private Timer throttleTimer;
public ClientView(EndPoint remoteEP, UseCircuitCodePacket initialcirpack, ClientManager clientManager,
IScene scene, AssetCache assetCache, PacketServer packServer,
AgentCircuitManager authenSessions)
{
m_moneyBalance = 1000;
m_scene = scene;
m_clientManager = clientManager;
m_assetCache = assetCache;
m_networkServer = packServer;
// m_inventoryCache = inventoryCache;
m_authenticateSessionsHandler = authenSessions;
MainLog.Instance.Verbose("CLIENT", "Started up new client thread to handle incoming request");
cirpack = initialcirpack;
userEP = remoteEP;
startpos = m_authenticateSessionsHandler.GetPosition(initialcirpack.CircuitCode.Code);
// 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.
PacketQueue = 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();
//this.UploadAssets = new AgentAssetUpload(this, m_assetCache, m_inventoryCache);
AckTimer = new Timer(750);
AckTimer.Elapsed += new ElapsedEventHandler(AckTimer_Elapsed);
AckTimer.Start();
throttleTimer = new Timer((int)(throttletimems/throttleTimeDivisor));
throttleTimer.Elapsed += new ElapsedEventHandler(throttleTimer_Elapsed);
throttleTimer.Start();
RegisterLocalPacketHandlers();
ClientThread = new Thread(new ThreadStart(AuthUser));
ClientThread.IsBackground = true;
ClientThread.Start();
}
void throttleTimer_Elapsed(object sender, ElapsedEventArgs e)
{
bytesSent = 0;
ResendBytesSent = 0;
LandBytesSent = 0;
WindBytesSent = 0;
CloudBytesSent = 0;
TaskBytesSent = 0;
AssetBytesSent = 0;
TextureBytesSent = 0;
// 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
while ((bytesSent <= ((int)(throttleOutbound/throttleTimeDivisor)) &&
(ResendOutgoingPacketQueue.Count > 0 ||
LandOutgoingPacketQueue.Count > 0 ||
WindOutgoingPacketQueue.Count > 0 ||
CloudOutgoingPacketQueue.Count > 0 ||
TaskOutgoingPacketQueue.Count > 0 ||
AssetOutgoingPacketQueue.Count > 0 ||
TextureOutgoingPacketQueue.Count > 0)) && throttleLoops <= MaxThrottleLoops)
{
throttleLoops++;
//Now comes the fun part.. we dump all our elements into PacketQueue that we've saved up.
if (ResendBytesSent <= ((int)(ResendthrottleOutbound/throttleTimeDivisor)) && ResendOutgoingPacketQueue.Count > 0)
{
QueItem qpack = ResendOutgoingPacketQueue.Dequeue();
PacketQueue.Enqueue(qpack);
bytesSent += qpack.Packet.ToBytes().Length;
ResendBytesSent += qpack.Packet.ToBytes().Length;
}
if (LandBytesSent <= ((int)(LandthrottleOutbound/throttleTimeDivisor)) && LandOutgoingPacketQueue.Count > 0)
{
QueItem qpack = LandOutgoingPacketQueue.Dequeue();
PacketQueue.Enqueue(qpack);
bytesSent += qpack.Packet.ToBytes().Length;
LandBytesSent += qpack.Packet.ToBytes().Length;
}
if (WindBytesSent <= ((int)(WindthrottleOutbound/throttleTimeDivisor)) && WindOutgoingPacketQueue.Count > 0)
{
QueItem qpack = WindOutgoingPacketQueue.Dequeue();
PacketQueue.Enqueue(qpack);
bytesSent += qpack.Packet.ToBytes().Length;
WindBytesSent += qpack.Packet.ToBytes().Length;
}
if (CloudBytesSent <= ((int)(CloudthrottleOutbound/throttleTimeDivisor)) && CloudOutgoingPacketQueue.Count > 0)
{
QueItem qpack = CloudOutgoingPacketQueue.Dequeue();
PacketQueue.Enqueue(qpack);
bytesSent += qpack.Packet.ToBytes().Length;
CloudBytesSent += qpack.Packet.ToBytes().Length;
}
if (TaskBytesSent <= ((int)(TaskthrottleOutbound/throttleTimeDivisor)) && TaskOutgoingPacketQueue.Count > 0)
{
QueItem qpack = TaskOutgoingPacketQueue.Dequeue();
PacketQueue.Enqueue(qpack);
bytesSent += qpack.Packet.ToBytes().Length;
TaskBytesSent += qpack.Packet.ToBytes().Length;
}
if (TextureBytesSent <= ((int)(TexturethrottleOutbound/throttleTimeDivisor)) && TextureOutgoingPacketQueue.Count > 0)
{
QueItem qpack = TextureOutgoingPacketQueue.Dequeue();
PacketQueue.Enqueue(qpack);
bytesSent += qpack.Packet.ToBytes().Length;
TextureBytesSent += qpack.Packet.ToBytes().Length;
}
if (AssetBytesSent <= ((int)(AssetthrottleOutbound/throttleTimeDivisor)) && AssetOutgoingPacketQueue.Count > 0)
{
QueItem qpack = AssetOutgoingPacketQueue.Dequeue();
PacketQueue.Enqueue(qpack);
bytesSent += qpack.Packet.ToBytes().Length;
AssetBytesSent += qpack.Packet.ToBytes().Length;
}
}
}
public LLUUID SessionId
{
get { return m_sessionId; }
}
public void SetDebug(int newDebug)
{
debug = newDebug;
}
# region Client Methods
public void Close()
{
clientPingTimer.Stop();
m_scene.RemoveClient(AgentId);
ClientThread.Abort();
}
public void Kick(string message)
{
KickUserPacket kupack = new KickUserPacket();
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()
{
clientPingTimer.Stop();
libsecondlife.Packets.DisableSimulatorPacket disable = new libsecondlife.Packets.DisableSimulatorPacket();
OutPacket(disable, ThrottleOutPacketType.Task);
ClientThread.Abort();
}
#endregion
# region Packet Handling
public static bool AddPacketHandler(PacketType packetType, PacketMethod handler)
{
bool result = false;
lock (PacketHandlers)
{
if (!PacketHandlers.ContainsKey(packetType))
{
PacketHandlers.Add(packetType, handler);
result = true;
}
}
return result;
}
public bool AddLocalPacketHandler(PacketType packetType, PacketMethod handler)
{
bool result = false;
lock (m_packetHandlers)
{
if (!m_packetHandlers.ContainsKey(packetType))
{
m_packetHandlers.Add(packetType, handler);
result = true;
}
}
return result;
}
protected virtual bool ProcessPacketMethod(Packet packet)
{
bool result = false;
bool found = false;
PacketMethod method;
if (m_packetHandlers.TryGetValue(packet.Type, out method))
{
//there is a local handler for this packet type
result = method(this, packet);
}
else
{
//there is not a local handler so see if there is a Global handler
lock (PacketHandlers)
{
found = PacketHandlers.TryGetValue(packet.Type, out method);
}
if (found)
{
result = method(this, packet);
}
}
return result;
}
protected void DebugPacket(string direction, Packet packet)
{
if (debug > 0)
{
string info = "";
if (debug < 255 && packet.Type == PacketType.AgentUpdate)
return;
if (debug < 254 && packet.Type == PacketType.ViewerEffect)
return;
if (debug < 253 && (
packet.Type == PacketType.CompletePingCheck ||
packet.Type == PacketType.StartPingCheck
))
return;
if (debug < 252 && packet.Type == PacketType.PacketAck)
return;
if (debug > 1)
{
info = packet.ToString();
}
else
{
info = packet.Type.ToString();
}
Console.WriteLine(m_circuitCode + ":" + direction + ": " + info);
}
}
protected virtual void ClientLoop()
{
bool queuedLast = false;
MainLog.Instance.Verbose("CLIENT", "Entered loop");
while (true)
{
QueItem nextPacket = PacketQueue.Dequeue();
if (nextPacket.Incoming)
{
queuedLast = false;
//is a incoming packet
if (nextPacket.Packet.Type != PacketType.AgentUpdate)
{
packetsReceived++;
}
DebugPacket("IN", nextPacket.Packet);
ProcessInPacket(nextPacket.Packet);
}
else
{
// Throw it back on the queue if it's going to cause us to flood the client
if (bytesSent > throttleOutboundMax)
{
PacketQueue.Enqueue(nextPacket);
MainLog.Instance.Verbose("THROTTLE", "Client over throttle limit, requeuing packet");
if (queuedLast)
{
MainLog.Instance.Verbose("THROTTLE", "No more sendable packets, need to sleep now");
Thread.Sleep(100); // Wait a little while if this was the last packet we saw
}
queuedLast = true;
}
else
{
queuedLast = false;
// TODO: May be a bit expensive doing this twice.
//Don't throttle AvatarPickerReplies!, they return a null .ToBytes()!
if (nextPacket.Packet.Type != PacketType.AvatarPickerReply)
bytesSent += nextPacket.Packet.ToBytes().Length;
//is a out going packet
DebugPacket("OUT", nextPacket.Packet);
ProcessOutPacket(nextPacket.Packet);
}
}
}
}
# endregion
protected void CheckClientConnectivity(object sender, ElapsedEventArgs e)
{
if (packetsReceived == lastPacketsReceived)
{
probesWithNoIngressPackets++;
if (probesWithNoIngressPackets > 30)
{
if (OnConnectionClosed != null)
{
OnConnectionClosed(this);
}
}
else
{
// this will normally trigger at least one packet (ping response)
SendStartPingCheck(0);
}
}
else
{
// Something received in the meantime - we can reset the counters
probesWithNoIngressPackets = 0;
lastPacketsReceived = packetsReceived;
}
}
# region Setup
protected virtual void InitNewClient()
{
clientPingTimer = new Timer(5000);
clientPingTimer.Elapsed += new ElapsedEventHandler(CheckClientConnectivity);
clientPingTimer.Enabled = true;
MainLog.Instance.Verbose("CLIENT", "Adding viewer agent to scene");
m_scene.AddNewClient(this, true);
}
protected virtual void AuthUser()
{
// AuthenticateResponse sessionInfo = m_gridServer.AuthenticateSession(cirpack.m_circuitCode.m_sessionId, cirpack.m_circuitCode.ID, cirpack.m_circuitCode.Code);
AuthenticateResponse sessionInfo =
m_authenticateSessionsHandler.AuthenticateSession(cirpack.CircuitCode.SessionID, cirpack.CircuitCode.ID,
cirpack.CircuitCode.Code);
if (!sessionInfo.Authorised)
{
//session/circuit not authorised
MainLog.Instance.Notice("CLIENT", "New user request denied to " + userEP.ToString());
ClientThread.Abort();
}
else
{
MainLog.Instance.Notice("CLIENT", "Got authenticated connection from " + userEP.ToString());
//session is authorised
m_agentId = cirpack.CircuitCode.ID;
m_sessionId = cirpack.CircuitCode.SessionID;
m_circuitCode = cirpack.CircuitCode.Code;
firstName = sessionInfo.LoginInfo.First;
lastName = sessionInfo.LoginInfo.Last;
if (sessionInfo.LoginInfo.SecureSession != LLUUID.Zero)
{
m_secureSessionId = sessionInfo.LoginInfo.SecureSession;
}
InitNewClient();
ClientLoop();
}
}
# endregion
protected void KillThread()
{
ClientThread.Abort();
}
// Previously ClientView.API partial class
public event Action OnLogout;
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 GenericCall2 OnCompleteMovementToRegion;
public event UpdateAgent OnAgentUpdate;
public event AgentRequestSit OnAgentRequestSit;
public event AgentSit OnAgentSit;
public event AvatarPickerRequest OnAvatarPickerRequest;
public event StartAnim OnStartAnim;
public event Action OnRequestAvatarsData;
public event LinkObjects OnLinkObjects;
public event DelinkObjects OnDelinkObjects;
public event UpdateVector OnGrabObject;
public event ObjectSelect OnDeGrabObject;
public event ObjectDuplicate OnObjectDuplicate;
public event MoveObject OnGrabUpdate;
public event AddNewPrim OnAddPrim;
public event RequestGodlikePowers OnRequestGodlikePowers;
public event GodKickUser OnGodKickUser;
public event ObjectExtraParams OnUpdateExtraParams;
public event UpdateShape OnUpdatePrimShape;
public event ObjectSelect OnObjectSelect;
public event ObjectDeselect OnObjectDeselect;
public event GenericCall7 OnObjectDescription;
public event GenericCall7 OnObjectName;
public event RequestObjectPropertiesFamily OnRequestObjectPropertiesFamily;
public event UpdatePrimFlags OnUpdatePrimFlags;
public event UpdatePrimTexture OnUpdatePrimTexture;
public event UpdateVector OnUpdatePrimGroupPosition;
public event UpdateVector OnUpdatePrimSinglePosition;
public event UpdatePrimRotation OnUpdatePrimGroupRotation;
public event UpdatePrimSingleRotation OnUpdatePrimSingleRotation;
public event UpdatePrimGroupRotation OnUpdatePrimGroupMouseRotation;
public event UpdateVector OnUpdatePrimScale;
public event StatusChange OnChildAgentStatus;
public event GenericCall2 OnStopMovement;
public event Action OnRemoveAvatar;
public event RequestMapBlocks OnRequestMapBlocks;
public event RequestMapName OnMapNameRequest;
public event TeleportLocationRequest OnTeleportLocationRequest;
public event DisconnectUser OnDisconnectUser;
public event RequestAvatarProperties OnRequestAvatarProperties;
public event SetAlwaysRun OnSetAlwaysRun;
public event CreateNewInventoryItem OnCreateNewInventoryItem;
public event CreateInventoryFolder OnCreateNewInventoryFolder;
public event FetchInventoryDescendents OnFetchInventoryDescendents;
public event FetchInventory OnFetchInventory;
public event RequestTaskInventory OnRequestTaskInventory;
public event UpdateInventoryItem OnUpdateInventoryItem;
public event CopyInventoryItem OnCopyInventoryItem;
public event UDPAssetUploadRequest OnAssetUploadRequest;
public event XferReceive OnXferReceive;
public event RequestXfer OnRequestXfer;
public event ConfirmXfer OnConfirmXfer;
public event RezScript OnRezScript;
public event UpdateTaskInventory OnUpdateTaskInventory;
public event RemoveTaskInventory OnRemoveTaskItem;
public event UUIDNameRequest OnNameFromUUIDRequest;
public event 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 LLVector3 StartPos
{
get { return startpos; }
set { startpos = value; }
}
///
///
///
private LLUUID m_agentId;
public LLUUID AgentId
{
get { return m_agentId; }
}
///
///
///
public string FirstName
{
get { return firstName; }
}
///
///
///
public string LastName
{
get { return lastName; }
}
#region Scene/Avatar to Client
///
///
///
///
public void SendRegionHandshake(RegionInfo regionInfo)
{
Encoding _enc = Encoding.ASCII;
RegionHandshakePacket handshake = new RegionHandshakePacket();
handshake.RegionInfo.BillableFactor = regionInfo.EstateSettings.billableFactor;
handshake.RegionInfo.IsEstateManager = false;
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 = _enc.GetBytes(regionInfo.RegionName + "\0");
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 = new AgentMovementCompletePacket();
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 = startpos;
}
else
{
mov.Data.Position = pos;
}
mov.Data.LookAt = look;
OutPacket(mov, ThrottleOutPacketType.Task);
}
///
///
///
///
///
///
///
///
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)
{
Encoding enc = Encoding.ASCII;
ChatFromSimulatorPacket reply = new ChatFromSimulatorPacket();
reply.ChatData.Audible = 1;
reply.ChatData.Message = message;
reply.ChatData.ChatType = type;
reply.ChatData.SourceType = 1;
reply.ChatData.Position = fromPos;
reply.ChatData.FromName = enc.GetBytes(fromName + "\0");
reply.ChatData.OwnerID = fromAgentID;
reply.ChatData.SourceID = fromAgentID;
OutPacket(reply, ThrottleOutPacketType.Task);
}
///
///
///
/// TODO
///
///
public void SendInstantMessage(LLUUID fromAgent, LLUUID fromAgentSession, string message, LLUUID toAgent,
LLUUID imSessionID, string fromName, byte dialog, uint timeStamp)
{
Encoding enc = Encoding.ASCII;
Encoding encUTF8 = Encoding.UTF8;
ImprovedInstantMessagePacket msg = new ImprovedInstantMessagePacket();
msg.AgentData.AgentID = fromAgent;
msg.AgentData.SessionID = fromAgentSession;
msg.MessageBlock.FromAgentName = enc.GetBytes(fromName + " \0");
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 = encUTF8.GetBytes(message + "\0");
msg.MessageBlock.BinaryBucket = new byte[0];
OutPacket(msg, ThrottleOutPacketType.Task);
}
///
/// Send the region heightmap to the client
///
/// heightmap
public virtual void SendLayerData(float[] map)
{
try
{
int[] patches = new int[4];
for (int y = 0; y < 16; y++)
{
for (int x = 0; x < 16; x = x + 4)
{
patches[0] = x + 0 + y*16;
patches[1] = x + 1 + y*16;
patches[2] = x + 2 + y*16;
patches[3] = x + 3 + y*16;
Packet layerpack = TerrainManager.CreateLandPacket(map, patches);
OutPacket(layerpack, ThrottleOutPacketType.Land);
}
}
}
catch (Exception e)
{
MainLog.Instance.Warn("client",
"ClientView.API.cs: SendLayerData() - Failed with exception " + e.ToString());
}
}
///
/// Sends a specified patch to a client
///
/// Patch coordinate (x) 0..16
/// Patch coordinate (y) 0..16
/// heightmap
public void SendLayerData(int px, int py, float[] map)
{
try
{
int[] patches = new int[1];
int patchx, patchy;
patchx = px;
patchy = py;
patches[0] = patchx + 0 + patchy*16;
Packet layerpack = TerrainManager.CreateLandPacket(map, patches);
OutPacket(layerpack, ThrottleOutPacketType.Land);
}
catch (Exception e)
{
MainLog.Instance.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 = new EnableSimulatorPacket();
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 = firstName;
agentData.lastname = lastName;
agentData.CapsPath = "";
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 = new CrossedRegionPacket();
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;
// new LLVector3(0.0f, 0.0f, 0.0f); // copied from Avatar.cs - SHOULD BE DYNAMIC!!!!!!!!!!
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 = new byte[0];
newSimPack.RegionData.SeedCapability = Helpers.StringToField(capsURL);
OutPacket(newSimPack, ThrottleOutPacketType.Task);
}
public void SendMapBlock(List mapBlocks)
{
MapBlockReplyPacket mapReply = new MapBlockReplyPacket();
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 = new TeleportLocalPacket();
tpLocal.Info.AgentID = AgentId;
tpLocal.Info.TeleportFlags = flags;
tpLocal.Info.LocationID = 2;
tpLocal.Info.LookAt = lookAt;
tpLocal.Info.Position = position;
OutPacket(tpLocal, ThrottleOutPacketType.Task);
}
public void SendRegionTeleport(ulong regionHandle, byte simAccess, IPEndPoint newRegionEndPoint, uint locationID,
uint flags, string capsURL)
{
TeleportFinishPacket teleport = new TeleportFinishPacket();
teleport.Info.AgentID = AgentId;
teleport.Info.RegionHandle = regionHandle;
teleport.Info.SimAccess = simAccess;
teleport.Info.SeedCapability = Helpers.StringToField(capsURL);
//teleport.Info.SeedCapability = new byte[0];
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;
OutPacket(teleport, ThrottleOutPacketType.Task);
}
///
///
///
public void SendTeleportFailed()
{
TeleportFailedPacket tpFailed = new TeleportFailedPacket();
tpFailed.Info.AgentID = this.AgentId;
tpFailed.Info.Reason = Helpers.StringToField("unknown failure of teleport");
OutPacket(tpFailed, ThrottleOutPacketType.Task);
}
///
///
///
public void SendTeleportLocationStart()
{
TeleportStartPacket tpStart = new TeleportStartPacket();
tpStart.Info.TeleportFlags = 16; // Teleport via location
OutPacket(tpStart, ThrottleOutPacketType.Task);
}
public void SendMoneyBalance(LLUUID transaction, bool success, byte[] description, int balance)
{
MoneyBalanceReplyPacket money = new MoneyBalanceReplyPacket();
money.MoneyData.AgentID = AgentId;
money.MoneyData.TransactionID = transaction;
money.MoneyData.TransactionSuccess = success;
money.MoneyData.Description = description;
money.MoneyData.MoneyBalance = balance;
OutPacket(money, ThrottleOutPacketType.Task);
}
public void SendStartPingCheck(byte seq)
{
StartPingCheckPacket pc = new StartPingCheckPacket();
pc.PingID.PingID = seq;
pc.Header.Reliable = false;
OutPacket(pc, ThrottleOutPacketType.Task);
}
public void SendKillObject(ulong regionHandle, uint localID)
{
KillObjectPacket kill = new KillObjectPacket();
kill.ObjectData = new KillObjectPacket.ObjectDataBlock[1];
kill.ObjectData[0] = new KillObjectPacket.ObjectDataBlock();
kill.ObjectData[0].ID = localID;
OutPacket(kill, ThrottleOutPacketType.Task);
}
///
/// Send information about the items contained in a folder to the client.
///
/// The owner of the folder
/// The id of the folder
/// The items contained in the folder identified by folderID
/// The number of subfolders contained in the given folder. This is necessary since
/// the client is expecting inventory packets which incorporate this number into the descendents field, even though
/// we send back no details of the folders themselves (only the items).
public void SendInventoryFolderDetails(LLUUID ownerID, LLUUID folderID, List items, int subFoldersCount)
{
Encoding enc = Encoding.ASCII;
uint FULL_MASK_PERMISSIONS = 2147483647;
InventoryDescendentsPacket descend = CreateInventoryDescendentsPacket(ownerID, folderID);
int count = 0;
if (items.Count < 40)
{
descend.ItemData = new InventoryDescendentsPacket.ItemDataBlock[items.Count];
// In the very first packet, also include the sub folders count so that the total descendents the
// client receives matches its expectations. Subsequent inventory packets need contain only the count
// of the number of items actually in them.
descend.AgentData.Descendents = items.Count + subFoldersCount;
}
else
{
descend.ItemData = new InventoryDescendentsPacket.ItemDataBlock[40];
// In the very first packet, also include the sub folders count so that the total descendents the
// client receives matches its expectations. Subsequent inventory packets need contain only the count
// of the number of items actually in them.
descend.AgentData.Descendents = 40 + subFoldersCount;
}
int i = 0;
foreach (InventoryItemBase item in items)
{
descend.ItemData[i] = new InventoryDescendentsPacket.ItemDataBlock();
descend.ItemData[i].ItemID = item.inventoryID;
descend.ItemData[i].AssetID = item.assetID;
descend.ItemData[i].CreatorID = item.creatorsID;
descend.ItemData[i].BaseMask = item.inventoryBasePermissions;
descend.ItemData[i].CreationDate = 1000;
descend.ItemData[i].Description = enc.GetBytes(item.inventoryDescription + "\0");
descend.ItemData[i].EveryoneMask = item.inventoryEveryOnePermissions;
descend.ItemData[i].Flags = 1;
descend.ItemData[i].FolderID = item.parentFolderID;
descend.ItemData[i].GroupID = new LLUUID("00000000-0000-0000-0000-000000000000");
descend.ItemData[i].GroupMask = 0;
descend.ItemData[i].InvType = (sbyte) item.invType;
descend.ItemData[i].Name = enc.GetBytes(item.inventoryName + "\0");
descend.ItemData[i].NextOwnerMask = item.inventoryNextPermissions;
descend.ItemData[i].OwnerID = item.avatarID;
descend.ItemData[i].OwnerMask = item.inventoryCurrentPermissions;
descend.ItemData[i].SalePrice = 0;
descend.ItemData[i].SaleType = 0;
descend.ItemData[i].Type = (sbyte) item.assetType;
descend.ItemData[i].CRC =
Helpers.InventoryCRC(1000, 0, descend.ItemData[i].InvType, descend.ItemData[i].Type,
descend.ItemData[i].AssetID, descend.ItemData[i].GroupID, 100,
descend.ItemData[i].OwnerID, descend.ItemData[i].CreatorID,
descend.ItemData[i].ItemID, descend.ItemData[i].FolderID, FULL_MASK_PERMISSIONS,
1, FULL_MASK_PERMISSIONS, FULL_MASK_PERMISSIONS, FULL_MASK_PERMISSIONS);
i++;
count++;
if (i == 40)
{
OutPacket(descend, ThrottleOutPacketType.Asset);
if ((items.Count - count) > 0)
{
descend = CreateInventoryDescendentsPacket(ownerID, folderID);
if ((items.Count - count) < 40)
{
descend.ItemData = new InventoryDescendentsPacket.ItemDataBlock[items.Count - count];
descend.AgentData.Descendents = items.Count - count;
}
else
{
descend.ItemData = new InventoryDescendentsPacket.ItemDataBlock[40];
descend.AgentData.Descendents = 40;
}
i = 0;
}
}
}
if (i < 40)
{
OutPacket(descend, ThrottleOutPacketType.Asset);
}
}
private InventoryDescendentsPacket CreateInventoryDescendentsPacket(LLUUID ownerID, LLUUID folderID)
{
InventoryDescendentsPacket descend = new InventoryDescendentsPacket();
descend.AgentData.AgentID = AgentId;
descend.AgentData.OwnerID = ownerID;
descend.AgentData.FolderID = folderID;
descend.AgentData.Version = 0;
return descend;
}
public void SendInventoryItemDetails(LLUUID ownerID, InventoryItemBase item)
{
Encoding enc = Encoding.ASCII;
uint FULL_MASK_PERMISSIONS = 2147483647;
FetchInventoryReplyPacket inventoryReply = new FetchInventoryReplyPacket();
inventoryReply.AgentData.AgentID = AgentId;
inventoryReply.InventoryData = new FetchInventoryReplyPacket.InventoryDataBlock[1];
inventoryReply.InventoryData[0] = new FetchInventoryReplyPacket.InventoryDataBlock();
inventoryReply.InventoryData[0].ItemID = item.inventoryID;
inventoryReply.InventoryData[0].AssetID = item.assetID;
inventoryReply.InventoryData[0].CreatorID = item.creatorsID;
inventoryReply.InventoryData[0].BaseMask = item.inventoryBasePermissions;
inventoryReply.InventoryData[0].CreationDate =
(int) (DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds;
inventoryReply.InventoryData[0].Description = enc.GetBytes(item.inventoryDescription + "\0");
inventoryReply.InventoryData[0].EveryoneMask = item.inventoryEveryOnePermissions;
inventoryReply.InventoryData[0].Flags = 0;
inventoryReply.InventoryData[0].FolderID = item.parentFolderID;
inventoryReply.InventoryData[0].GroupID = new LLUUID("00000000-0000-0000-0000-000000000000");
inventoryReply.InventoryData[0].GroupMask = 0;
inventoryReply.InventoryData[0].InvType = (sbyte) item.invType;
inventoryReply.InventoryData[0].Name = enc.GetBytes(item.inventoryName + "\0");
inventoryReply.InventoryData[0].NextOwnerMask = item.inventoryNextPermissions;
inventoryReply.InventoryData[0].OwnerID = item.avatarID;
inventoryReply.InventoryData[0].OwnerMask = item.inventoryCurrentPermissions;
inventoryReply.InventoryData[0].SalePrice = 0;
inventoryReply.InventoryData[0].SaleType = 0;
inventoryReply.InventoryData[0].Type = (sbyte) item.assetType;
inventoryReply.InventoryData[0].CRC =
Helpers.InventoryCRC(1000, 0, inventoryReply.InventoryData[0].InvType,
inventoryReply.InventoryData[0].Type, inventoryReply.InventoryData[0].AssetID,
inventoryReply.InventoryData[0].GroupID, 100,
inventoryReply.InventoryData[0].OwnerID, inventoryReply.InventoryData[0].CreatorID,
inventoryReply.InventoryData[0].ItemID, inventoryReply.InventoryData[0].FolderID,
FULL_MASK_PERMISSIONS, 1, FULL_MASK_PERMISSIONS, FULL_MASK_PERMISSIONS,
FULL_MASK_PERMISSIONS);
OutPacket(inventoryReply, ThrottleOutPacketType.Asset);
}
/// IClientAPI.SendInventoryItemCreateUpdate(InventoryItemBase)
public void SendInventoryItemCreateUpdate(InventoryItemBase Item)
{
Encoding enc = Encoding.ASCII;
uint FULL_MASK_PERMISSIONS = 2147483647;
UpdateCreateInventoryItemPacket InventoryReply = new UpdateCreateInventoryItemPacket();
InventoryReply.AgentData.AgentID = AgentId;
InventoryReply.AgentData.SimApproved = true;
InventoryReply.InventoryData = new UpdateCreateInventoryItemPacket.InventoryDataBlock[1];
InventoryReply.InventoryData[0] = new UpdateCreateInventoryItemPacket.InventoryDataBlock();
InventoryReply.InventoryData[0].ItemID = Item.inventoryID;
InventoryReply.InventoryData[0].AssetID = Item.assetID;
InventoryReply.InventoryData[0].CreatorID = Item.creatorsID;
InventoryReply.InventoryData[0].BaseMask = Item.inventoryBasePermissions;
InventoryReply.InventoryData[0].CreationDate = 1000;
InventoryReply.InventoryData[0].Description = enc.GetBytes(Item.inventoryDescription + "\0");
InventoryReply.InventoryData[0].EveryoneMask = Item.inventoryEveryOnePermissions;
InventoryReply.InventoryData[0].Flags = 0;
InventoryReply.InventoryData[0].FolderID = Item.parentFolderID;
InventoryReply.InventoryData[0].GroupID = new LLUUID("00000000-0000-0000-0000-000000000000");
InventoryReply.InventoryData[0].GroupMask = 0;
InventoryReply.InventoryData[0].InvType = (sbyte) Item.invType;
InventoryReply.InventoryData[0].Name = enc.GetBytes(Item.inventoryName + "\0");
InventoryReply.InventoryData[0].NextOwnerMask = Item.inventoryNextPermissions;
InventoryReply.InventoryData[0].OwnerID = Item.avatarID;
InventoryReply.InventoryData[0].OwnerMask = Item.inventoryCurrentPermissions;
InventoryReply.InventoryData[0].SalePrice = 100;
InventoryReply.InventoryData[0].SaleType = 0;
InventoryReply.InventoryData[0].Type = (sbyte) Item.assetType;
InventoryReply.InventoryData[0].CRC =
Helpers.InventoryCRC(1000, 0, InventoryReply.InventoryData[0].InvType,
InventoryReply.InventoryData[0].Type, InventoryReply.InventoryData[0].AssetID,
InventoryReply.InventoryData[0].GroupID, 100,
InventoryReply.InventoryData[0].OwnerID, InventoryReply.InventoryData[0].CreatorID,
InventoryReply.InventoryData[0].ItemID, InventoryReply.InventoryData[0].FolderID,
FULL_MASK_PERMISSIONS, 1, FULL_MASK_PERMISSIONS, FULL_MASK_PERMISSIONS,
FULL_MASK_PERMISSIONS);
OutPacket(InventoryReply, ThrottleOutPacketType.Asset);
}
public void SendRemoveInventoryItem(LLUUID itemID)
{
RemoveInventoryItemPacket remove = new RemoveInventoryItemPacket();
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 = new ReplyTaskInventoryPacket();
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 = new SendXferPacketPacket();
sendXfer.XferID.ID = xferID;
sendXfer.XferID.Packet = packet;
sendXfer.DataPacket.Data = data;
OutPacket(sendXfer, ThrottleOutPacketType.Task);
}
public void SendAvatarPickerReply(AvatarPickerReplyPacket replyPacket)
{
OutPacket(replyPacket, ThrottleOutPacketType.Task);
}
///
///
///
///
public void SendAlertMessage(string message)
{
AlertMessagePacket alertPack = new AlertMessagePacket();
alertPack.AlertData.Message = Helpers.StringToField(message);
OutPacket(alertPack, ThrottleOutPacketType.Task);
}
///
///
///
///
///
public void SendAgentAlertMessage(string message, bool modal)
{
AgentAlertMessagePacket alertPack = new AgentAlertMessagePacket();
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 = new LoadURLPacket();
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 SendPreLoadSound(LLUUID objectID, LLUUID ownerID, LLUUID soundID)
{
PreloadSoundPacket preSound = new PreloadSoundPacket();
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 = new AttachedSoundPacket();
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 SendSunPos(LLVector3 sunPos, LLVector3 sunVel)
{
SimulatorViewerTimeMessagePacket viewertime = new SimulatorViewerTimeMessagePacket();
viewertime.TimeInfo.SunDirection = sunPos;
viewertime.TimeInfo.SunAngVelocity = sunVel;
viewertime.TimeInfo.UsecSinceStart = (ulong) Util.UnixTimeSinceEpoch();
OutPacket(viewertime, ThrottleOutPacketType.Task);
}
public void SendViewerTime(int phase)
{
Console.WriteLine("SunPhase: {0}", phase);
SimulatorViewerTimeMessagePacket viewertime = new SimulatorViewerTimeMessagePacket();
//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;
}
if (yValue > 1)
{
yValue = 1;
}
if (yValue < 0)
{
yValue = 0;
}
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();
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 = new AvatarPropertiesReplyPacket();
avatarReply.AgentData.AgentID = AgentId;
avatarReply.AgentData.AvatarID = avatarID;
avatarReply.PropertiesData.AboutText = Helpers.StringToField(aboutText);
avatarReply.PropertiesData.BornOn = Helpers.StringToField(bornOn);
avatarReply.PropertiesData.CharterMember = Helpers.StringToField(charterMember);
avatarReply.PropertiesData.FLAboutText = Helpers.StringToField(flAbout);
avatarReply.PropertiesData.Flags = 0;
avatarReply.PropertiesData.FLImageID = flImageID;
avatarReply.PropertiesData.ImageID = imageID;
avatarReply.PropertiesData.ProfileURL = Helpers.StringToField(profileURL);
avatarReply.PropertiesData.PartnerID = partnerID;
OutPacket(avatarReply, ThrottleOutPacketType.Task);
}
#endregion
#region Appearance/ Wearables Methods
///
///
///
///
public void SendWearables(AvatarWearable[] wearables, int serial)
{
AgentWearablesUpdatePacket aw = new AgentWearablesUpdatePacket();
aw.AgentData.AgentID = AgentId;
aw.AgentData.SerialNum = (uint) serial;
aw.AgentData.SessionID = m_sessionId;
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 = new AvatarAppearancePacket();
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 SendAnimation(LLUUID animID, int seq, LLUUID sourceAgentId)
{
AvatarAnimationPacket ani = new AvatarAnimationPacket();
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[1];
ani.AnimationList[0] = new AvatarAnimationPacket.AnimationListBlock();
ani.AnimationList[0].AnimID = animID;
ani.AnimationList[0].AnimSequenceID = seq;
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 = new ObjectUpdatePacket();
objupdate.RegionData.RegionHandle = regionHandle;
objupdate.RegionData.TimeDilation = 64096;
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 = new ImprovedTerseObjectUpdatePacket();
terse.RegionData.RegionHandle = regionHandle;
terse.RegionData.TimeDilation = timeDilation;
terse.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1];
terse.ObjectData[0] = terseBlock;
OutPacket(terse, ThrottleOutPacketType.Task);
}
public void SendCoarseLocationUpdate(List CoarseLocations)
{
CoarseLocationUpdatePacket loc = new CoarseLocationUpdatePacket();
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;
OutPacket(loc, ThrottleOutPacketType.Task);
}
#endregion
#region Primitive Packet/data Sending Methods
///
///
///
///
///
///
public void AttachObject(uint localID, LLQuaternion rotation, byte attachPoint)
{
ObjectAttachPacket attach = new ObjectAttachPacket();
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)
{
ObjectUpdatePacket outPacket = new ObjectUpdatePacket();
outPacket.RegionData.RegionHandle = regionHandle;
outPacket.RegionData.TimeDilation = timeDilation;
outPacket.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1];
outPacket.ObjectData[0] = CreatePrimUpdateBlock(primShape, flags);
outPacket.ObjectData[0].ID = localID;
outPacket.ObjectData[0].FullID = objectID;
outPacket.ObjectData[0].OwnerID = ownerID;
outPacket.ObjectData[0].Text = Helpers.StringToField(text);
outPacket.ObjectData[0].TextColor[0] = color[0];
outPacket.ObjectData[0].TextColor[1] = color[1];
outPacket.ObjectData[0].TextColor[2] = color[2];
outPacket.ObjectData[0].TextColor[3] = color[3];
outPacket.ObjectData[0].ParentID = parentID;
outPacket.ObjectData[0].PSBlock = particleSystem;
outPacket.ObjectData[0].ClickAction = clickAction;
//outPacket.ObjectData[0].Flags = 0;
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);
OutPacket(outPacket, ThrottleOutPacketType.Task);
}
///
///
///
///
///
///
///
///
public void SendPrimTerseUpdate(ulong regionHandle, ushort timeDilation, uint localID, LLVector3 position,
LLQuaternion rotation)
{
LLVector3 velocity = new LLVector3(0f,0f,0f);
LLVector3 rotationalvelocity = new LLVector3(0f,0f,0f);
ImprovedTerseObjectUpdatePacket terse = new ImprovedTerseObjectUpdatePacket();
terse.RegionData.RegionHandle = regionHandle;
terse.RegionData.TimeDilation = timeDilation;
terse.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1];
terse.ObjectData[0] = CreatePrimImprovedBlock(localID, position, rotation, velocity, rotationalvelocity);
OutPacket(terse, ThrottleOutPacketType.Task);
}
public void SendPrimTerseUpdate(ulong regionHandle, ushort timeDilation, uint localID, LLVector3 position,
LLQuaternion rotation, LLVector3 velocity, LLVector3 rotationalvelocity)
{
ImprovedTerseObjectUpdatePacket terse = new ImprovedTerseObjectUpdatePacket();
terse.RegionData.RegionHandle = regionHandle;
terse.RegionData.TimeDilation = timeDilation;
terse.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1];
terse.ObjectData[0] = CreatePrimImprovedBlock(localID, position, rotation, velocity, rotationalvelocity);
OutPacket(terse, ThrottleOutPacketType.Task);
}
#endregion
#region Helper Methods
protected ImprovedTerseObjectUpdatePacket.ObjectDataBlock CreateAvatarImprovedBlock(uint localID, LLVector3 pos,
LLVector3 velocity,
LLQuaternion rotation)
{
byte[] bytes = new byte[60];
int i = 0;
ImprovedTerseObjectUpdatePacket.ObjectDataBlock dat = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock();
dat.TextureEntry = new byte[0]; // AvatarTemplate.TextureEntry;
uint ID = localID;
bytes[i++] = (byte) (ID%256);
bytes[i++] = (byte) ((ID >> 8)%256);
bytes[i++] = (byte) ((ID >> 16)%256);
bytes[i++] = (byte) ((ID >> 24)%256);
bytes[i++] = 0;
bytes[i++] = 1;
i += 14;
bytes[i++] = 128;
bytes[i++] = 63;
byte[] pb = pos.GetBytes();
Array.Copy(pb, 0, bytes, i, pb.Length);
i += 12;
ushort InternVelocityX;
ushort InternVelocityY;
ushort InternVelocityZ;
Vector3 internDirec = new Vector3(0, 0, 0);
internDirec = new Vector3(velocity.X, velocity.Y, velocity.Z);
internDirec = internDirec/128.0f;
internDirec.x += 1;
internDirec.y += 1;
internDirec.z += 1;
InternVelocityX = (ushort) (32768*internDirec.x);
InternVelocityY = (ushort) (32768*internDirec.y);
InternVelocityZ = (ushort) (32768*internDirec.z);
ushort ac = 32767;
bytes[i++] = (byte) (InternVelocityX%256);
bytes[i++] = (byte) ((InternVelocityX >> 8)%256);
bytes[i++] = (byte) (InternVelocityY%256);
bytes[i++] = (byte) ((InternVelocityY >> 8)%256);
bytes[i++] = (byte) (InternVelocityZ%256);
bytes[i++] = (byte) ((InternVelocityZ >> 8)%256);
//accel
bytes[i++] = (byte) (ac%256);
bytes[i++] = (byte) ((ac >> 8)%256);
bytes[i++] = (byte) (ac%256);
bytes[i++] = (byte) ((ac >> 8)%256);
bytes[i++] = (byte) (ac%256);
bytes[i++] = (byte) ((ac >> 8)%256);
//rotation
ushort rw, rx, ry, rz;
rw = (ushort) (32768*(rotation.W + 1));
rx = (ushort) (32768*(rotation.X + 1));
ry = (ushort) (32768*(rotation.Y + 1));
rz = (ushort) (32768*(rotation.Z + 1));
//rot
bytes[i++] = (byte) (rx%256);
bytes[i++] = (byte) ((rx >> 8)%256);
bytes[i++] = (byte) (ry%256);
bytes[i++] = (byte) ((ry >> 8)%256);
bytes[i++] = (byte) (rz%256);
bytes[i++] = (byte) ((rz >> 8)%256);
bytes[i++] = (byte) (rw%256);
bytes[i++] = (byte) ((rw >> 8)%256);
//rotation vel
bytes[i++] = (byte) (ac%256);
bytes[i++] = (byte) ((ac >> 8)%256);
bytes[i++] = (byte) (ac%256);
bytes[i++] = (byte) ((ac >> 8)%256);
bytes[i++] = (byte) (ac%256);
bytes[i++] = (byte) ((ac >> 8)%256);
dat.Data = bytes;
return (dat);
}
///
///
///
///
///
///
///
protected ImprovedTerseObjectUpdatePacket.ObjectDataBlock CreatePrimImprovedBlock(uint localID,
LLVector3 position,
LLQuaternion rotation, LLVector3 velocity, LLVector3 rotationalvelocity)
{
uint ID = localID;
byte[] bytes = new byte[60];
int i = 0;
ImprovedTerseObjectUpdatePacket.ObjectDataBlock dat = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock();
dat.TextureEntry = new byte[0];
bytes[i++] = (byte) (ID%256);
bytes[i++] = (byte) ((ID >> 8)%256);
bytes[i++] = (byte) ((ID >> 16)%256);
bytes[i++] = (byte) ((ID >> 24)%256);
bytes[i++] = 0;
bytes[i++] = 0;
byte[] pb = position.GetBytes();
Array.Copy(pb, 0, bytes, i, pb.Length);
i += 12;
ushort ac = 32767;
ushort velx, vely, velz;
Vector3 vel = new Vector3(velocity.X, velocity.Y, velocity.Z);
vel = vel/128.0f;
vel.x += 1;
vel.y += 1;
vel.z += 1;
//vel
velx = (ushort)(32768 * (vel.x));
vely = (ushort)(32768 * (vel.y));
velz = (ushort)(32768 * (vel.z));
bytes[i++] = (byte) (velx % 256);
bytes[i++] = (byte) ((velx >> 8) % 256);
bytes[i++] = (byte) (vely % 256);
bytes[i++] = (byte) ((vely >> 8) % 256);
bytes[i++] = (byte) (velz % 256);
bytes[i++] = (byte) ((velz >> 8) % 256);
//accel
bytes[i++] = (byte) (ac%256);
bytes[i++] = (byte) ((ac >> 8)%256);
bytes[i++] = (byte) (ac%256);
bytes[i++] = (byte) ((ac >> 8)%256);
bytes[i++] = (byte) (ac%256);
bytes[i++] = (byte) ((ac >> 8)%256);
ushort rw, rx, ry, rz;
rw = (ushort) (32768*(rotation.W + 1));
rx = (ushort) (32768*(rotation.X + 1));
ry = (ushort) (32768*(rotation.Y + 1));
rz = (ushort) (32768*(rotation.Z + 1));
//rot
bytes[i++] = (byte) (rx%256);
bytes[i++] = (byte) ((rx >> 8)%256);
bytes[i++] = (byte) (ry%256);
bytes[i++] = (byte) ((ry >> 8)%256);
bytes[i++] = (byte) (rz%256);
bytes[i++] = (byte) ((rz >> 8)%256);
bytes[i++] = (byte) (rw%256);
bytes[i++] = (byte) ((rw >> 8)%256);
//rotation vel
ushort rvelx, rvely, rvelz;
Vector3 rvel = new Vector3(rotationalvelocity.X, rotationalvelocity.Y, rotationalvelocity.Z);
rvel = rvel / 128.0f;
rvel.x += 1;
rvel.y += 1;
rvel.z += 1;
//vel
rvelx = (ushort)(32768 * (rvel.x));
rvely = (ushort)(32768 * (rvel.y));
rvelz = (ushort)(32768 * (rvel.z));
bytes[i++] = (byte)(rvelx % 256);
bytes[i++] = (byte)((rvelx >> 8) % 256);
bytes[i++] = (byte)(rvely % 256);
bytes[i++] = (byte)((rvely >> 8) % 256);
bytes[i++] = (byte)(rvelz % 256);
bytes[i++] = (byte)((rvelz >> 8) % 256);
dat.Data = bytes;
return dat;
}
///
/// Create the ObjectDataBlock for a ObjectUpdatePacket (for a Primitive)
///
///
///
protected ObjectUpdatePacket.ObjectDataBlock CreatePrimUpdateBlock(PrimitiveBaseShape primShape, uint flags)
{
ObjectUpdatePacket.ObjectDataBlock objupdate = new ObjectUpdatePacket.ObjectDataBlock();
SetDefaultPrimPacketValues(objupdate);
objupdate.UpdateFlags = flags;
SetPrimPacketShapeData(objupdate, primShape);
return objupdate;
}
protected void SetPrimPacketShapeData(ObjectUpdatePacket.ObjectDataBlock objectData, PrimitiveBaseShape primData)
{
objectData.TextureEntry = primData.TextureEntry;
objectData.PCode = primData.PCode;
objectData.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;
}
///
///
///
///
protected ObjectUpdatePacket.ObjectDataBlock CreateDefaultAvatarPacket(byte[] textureEntry)
{
ObjectUpdatePacket.ObjectDataBlock objdata = new ObjectUpdatePacket.ObjectDataBlock();
// new libsecondlife.Packets.ObjectUpdatePacket.ObjectDataBlock(data1, ref i);
SetDefaultAvatarPacketValues(ref objdata);
objdata.UpdateFlags = 61 + (9 << 8) + (130 << 16) + (16 << 24);
objdata.PathCurve = 16;
objdata.ProfileCurve = 1;
objdata.PathScaleX = 100;
objdata.PathScaleY = 100;
objdata.ParentID = 0;
objdata.OwnerID = LLUUID.Zero;
objdata.Scale = new LLVector3(1, 1, 1);
objdata.PCode = 47;
if (textureEntry != null)
{
objdata.TextureEntry = textureEntry;
}
Encoding enc = Encoding.ASCII;
LLVector3 pos = new LLVector3(objdata.ObjectData, 16);
pos.X = 100f;
objdata.ID = 8880000;
objdata.NameValue = enc.GetBytes("FirstName STRING RW SV Test \nLastName STRING RW SV User \0");
//LLVector3 pos2 = new LLVector3(100f, 100f, 23f);
//objdata.FullID=user.AgentId;
byte[] pb = pos.GetBytes();
Array.Copy(pb, 0, objdata.ObjectData, 16, pb.Length);
return objdata;
}
///
///
///
///
protected void SetDefaultAvatarPacketValues(ref ObjectUpdatePacket.ObjectDataBlock objdata)
{
objdata.PSBlock = new byte[0];
objdata.ExtraParams = new byte[1];
objdata.MediaURL = new byte[0];
objdata.NameValue = new byte[0];
objdata.Text = new byte[0];
objdata.TextColor = new byte[4];
objdata.JointAxisOrAnchor = new LLVector3(0, 0, 0);
objdata.JointPivot = new LLVector3(0, 0, 0);
objdata.Material = 4;
objdata.TextureAnim = new byte[0];
objdata.Sound = LLUUID.Zero;
LLObject.TextureEntry ntex = new LLObject.TextureEntry(new LLUUID("00000000-0000-0000-5005-000000000005"));
objdata.TextureEntry = ntex.ToBytes();
objdata.State = 0;
objdata.Data = new byte[0];
objdata.ObjectData = new byte[76];
objdata.ObjectData[15] = 128;
objdata.ObjectData[16] = 63;
objdata.ObjectData[56] = 128;
objdata.ObjectData[61] = 102;
objdata.ObjectData[62] = 40;
objdata.ObjectData[63] = 61;
objdata.ObjectData[64] = 189;
}
public void SendNameReply(LLUUID profileId, string firstname, string lastname)
{
UUIDNameReplyPacket packet = new UUIDNameReplyPacket();
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);
}
private bool HandleViewerEffect(IClientAPI sender, Packet Pack)
{
ViewerEffectPacket viewer = (ViewerEffectPacket) Pack;
if (OnViewerEffect != null)
{
OnViewerEffect(sender, viewer.Effect);
}
return true;
}
protected virtual bool Logout(IClientAPI client, Packet packet)
{
MainLog.Instance.Verbose("CLIENT", "Got a logout request");
if (OnLogout != null)
{
OnLogout(client);
}
return true;
}
protected bool AgentTextureCached(IClientAPI simclient, Packet packet)
{
//System.Console.WriteLine("texture cached: " + packet.ToString());
AgentCachedTexturePacket chechedtex = (AgentCachedTexturePacket) packet;
AgentCachedTextureResponsePacket cachedresp = new AgentCachedTextureResponsePacket();
cachedresp.AgentData.AgentID = AgentId;
cachedresp.AgentData.SessionID = m_sessionId;
cachedresp.AgentData.SerialNum = cachedtextureserial;
cachedtextureserial++;
cachedresp.WearableData =
new AgentCachedTextureResponsePacket.WearableDataBlock[chechedtex.WearableData.Length];
for (int i = 0; i < chechedtex.WearableData.Length; i++)
{
cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
cachedresp.WearableData[i].TextureIndex = chechedtex.WearableData[i].TextureIndex;
cachedresp.WearableData[i].TextureID = LLUUID.Zero;
cachedresp.WearableData[i].HostName = new byte[0];
}
OutPacket(cachedresp, ThrottleOutPacketType.Texture);
return true;
}
protected bool MultipleObjUpdate(IClientAPI simClient, Packet packet)
{
MultipleObjectUpdatePacket multipleupdate = (MultipleObjectUpdatePacket) packet;
// System.Console.WriteLine("new multi update packet " + multipleupdate.ToString());
OpenSim.Region.Environment.Scenes.Scene tScene = (OpenSim.Region.Environment.Scenes.Scene)this.m_scene;
for (int i = 0; i < multipleupdate.ObjectData.Length; i++)
{
if (tScene.PermissionsMngr.CanEditObject(simClient.AgentId, tScene.GetSceneObjectPart(multipleupdate.ObjectData[i].ObjectLocalID).UUID))
{
#region position
if (multipleupdate.ObjectData[i].Type == 9) //change position
{
if (OnUpdatePrimGroupPosition != null)
{
LLVector3 pos = new LLVector3(multipleupdate.ObjectData[i].Data, 0);
OnUpdatePrimGroupPosition(multipleupdate.ObjectData[i].ObjectLocalID, pos, this);
}
}
else if (multipleupdate.ObjectData[i].Type == 1) //single item of group change position
{
if (OnUpdatePrimSinglePosition != null)
{
LLVector3 pos = new LLVector3(multipleupdate.ObjectData[i].Data, 0);
// System.Console.WriteLine("new movement position is " + pos.X + " , " + pos.Y + " , " + pos.Z);
OnUpdatePrimSinglePosition(multipleupdate.ObjectData[i].ObjectLocalID, pos, this);
}
}
#endregion position
#region rotation
else if (multipleupdate.ObjectData[i].Type == 2) // single item of group rotation from tab
{
if (OnUpdatePrimSingleRotation != null)
{
LLQuaternion rot = new LLQuaternion(multipleupdate.ObjectData[i].Data, 0, true);
//System.Console.WriteLine("new tab rotation is " + rot.X + " , " + rot.Y + " , " + rot.Z + " , " + rot.W);
OnUpdatePrimSingleRotation(multipleupdate.ObjectData[i].ObjectLocalID, rot, this);
}
}
else if (multipleupdate.ObjectData[i].Type == 3) // single item of group rotation from mouse
{
if (OnUpdatePrimSingleRotation != null)
{
LLQuaternion rot = new LLQuaternion(multipleupdate.ObjectData[i].Data, 12, true);
//System.Console.WriteLine("new mouse rotation is " + rot.X + " , " + rot.Y + " , " + rot.Z + " , " + rot.W);
OnUpdatePrimSingleRotation(multipleupdate.ObjectData[i].ObjectLocalID, rot, this);
}
}
else if (multipleupdate.ObjectData[i].Type == 10) //group rotation from object tab
{
if (OnUpdatePrimGroupRotation != null)
{
LLQuaternion rot = new LLQuaternion(multipleupdate.ObjectData[i].Data, 0, true);
// Console.WriteLine("new rotation is " + rot.X + " , " + rot.Y + " , " + rot.Z + " , " + rot.W);
OnUpdatePrimGroupRotation(multipleupdate.ObjectData[i].ObjectLocalID, rot, this);
}
}
else if (multipleupdate.ObjectData[i].Type == 11) //group rotation from mouse
{
if (OnUpdatePrimGroupMouseRotation != null)
{
LLVector3 pos = new LLVector3(multipleupdate.ObjectData[i].Data, 0);
LLQuaternion rot = new LLQuaternion(multipleupdate.ObjectData[i].Data, 12, true);
//Console.WriteLine("new rotation position is " + pos.X + " , " + pos.Y + " , " + pos.Z);
// Console.WriteLine("new rotation is " + rot.X + " , " + rot.Y + " , " + rot.Z + " , " + rot.W);
OnUpdatePrimGroupMouseRotation(multipleupdate.ObjectData[i].ObjectLocalID, pos, rot, this);
}
}
#endregion
#region scale
else if (multipleupdate.ObjectData[i].Type == 13) //group scale from object tab
{
if (OnUpdatePrimScale != null)
{
LLVector3 scale = new LLVector3(multipleupdate.ObjectData[i].Data, 12);
//Console.WriteLine("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z);
OnUpdatePrimScale(multipleupdate.ObjectData[i].ObjectLocalID, scale, this);
// Change the position based on scale (for bug number 246)
LLVector3 pos = new LLVector3(multipleupdate.ObjectData[i].Data, 0);
// System.Console.WriteLine("new movement position is " + pos.X + " , " + pos.Y + " , " + pos.Z);
OnUpdatePrimSinglePosition(multipleupdate.ObjectData[i].ObjectLocalID, pos, this);
}
}
else if (multipleupdate.ObjectData[i].Type == 29) //group scale from mouse
{
if (OnUpdatePrimScale != null)
{
LLVector3 scale = new LLVector3(multipleupdate.ObjectData[i].Data, 12);
// Console.WriteLine("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z );
OnUpdatePrimScale(multipleupdate.ObjectData[i].ObjectLocalID, scale, this);
LLVector3 pos = new LLVector3(multipleupdate.ObjectData[i].Data, 0);
OnUpdatePrimSinglePosition(multipleupdate.ObjectData[i].ObjectLocalID, pos, this);
}
}
else if (multipleupdate.ObjectData[i].Type == 5) //single prim scale from object tab
{
if (OnUpdatePrimScale != null)
{
LLVector3 scale = new LLVector3(multipleupdate.ObjectData[i].Data, 12);
// Console.WriteLine("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z);
OnUpdatePrimScale(multipleupdate.ObjectData[i].ObjectLocalID, scale, this);
}
}
else if (multipleupdate.ObjectData[i].Type == 21) //single prim scale from mouse
{
if (OnUpdatePrimScale != null)
{
LLVector3 scale = new LLVector3(multipleupdate.ObjectData[i].Data, 12);
// Console.WriteLine("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z);
OnUpdatePrimScale(multipleupdate.ObjectData[i].ObjectLocalID, scale, this);
}
}
#endregion
}
}
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 = new MapLayerReplyPacket();
mapReply.AgentData.AgentID = AgentId;
mapReply.AgentData.Flags = 0;
mapReply.LayerData = new MapLayerReplyPacket.LayerDataBlock[1];
mapReply.LayerData[0] = new MapLayerReplyPacket.LayerDataBlock();
mapReply.LayerData[0].Bottom = 0;
mapReply.LayerData[0].Left = 0;
mapReply.LayerData[0].Top = 30000;
mapReply.LayerData[0].Right = 30000;
mapReply.LayerData[0].ImageID = new LLUUID("00000000-0000-0000-9999-000000000006");
OutPacket(mapReply, ThrottleOutPacketType.Land);
}
public void RequestMapBlocks(int minX, int minY, int maxX, int maxY)
{
/*
IList simMapProfiles = m_gridServer.RequestMapBlocks(minX, minY, maxX, maxY);
MapBlockReplyPacket mbReply = new MapBlockReplyPacket();
mbReply.AgentData.AgentId = this.AgentId;
int len;
if (simMapProfiles == null)
len = 0;
else
len = simMapProfiles.Count;
mbReply.Data = new MapBlockReplyPacket.DataBlock[len];
int iii;
for (iii = 0; iii < len; iii++)
{
Hashtable mp = (Hashtable)simMapProfiles[iii];
mbReply.Data[iii] = new MapBlockReplyPacket.DataBlock();
mbReply.Data[iii].Name = System.Text.Encoding.UTF8.GetBytes((string)mp["name"]);
mbReply.Data[iii].Access = System.Convert.ToByte(mp["access"]);
mbReply.Data[iii].Agents = System.Convert.ToByte(mp["agents"]);
mbReply.Data[iii].MapImageID = new LLUUID((string)mp["map-image-id"]);
mbReply.Data[iii].RegionFlags = System.Convert.ToUInt32(mp["region-flags"]);
mbReply.Data[iii].WaterHeight = System.Convert.ToByte(mp["water-height"]);
mbReply.Data[iii].X = System.Convert.ToUInt16(mp["x"]);
mbReply.Data[iii].Y = System.Convert.ToUInt16(mp["y"]);
}
this.OutPacket(mbReply, ThrottleOutPacketType.Land);
*/
}
// Previously ClientView.PacketQueue
protected BlockingQueue PacketQueue;
protected Queue IncomingPacketQueue;
protected Queue OutgoingPacketQueue;
protected Queue ResendOutgoingPacketQueue;
protected Queue LandOutgoingPacketQueue;
protected Queue WindOutgoingPacketQueue;
protected Queue CloudOutgoingPacketQueue;
protected Queue TaskOutgoingPacketQueue;
protected Queue TextureOutgoingPacketQueue;
protected Queue AssetOutgoingPacketQueue;
protected Dictionary PendingAcks = new Dictionary();
protected Dictionary NeedAck = new Dictionary();
protected Timer AckTimer;
protected uint Sequence = 0;
protected object SequenceLock = new object();
protected const int MAX_APPENDED_ACKS = 10;
protected const int RESEND_TIMEOUT = 4000;
protected const int MAX_SEQUENCE = 0xFFFFFF;
private uint m_circuitCode;
public EndPoint userEP;
protected PacketServer m_networkServer;
public uint CircuitCode
{
get { return m_circuitCode; }
set { m_circuitCode = value; }
}
// A thread safe sequence number allocator.
protected uint NextSeqNum()
{
// Set the sequence number
uint seq = 1;
lock (SequenceLock)
{
if (Sequence >= MAX_SEQUENCE)
{
Sequence = 1;
}
else
{
Sequence++;
}
seq = Sequence;
}
return seq;
}
protected void AddAck(Packet Pack)
{
lock (NeedAck)
{
if (!NeedAck.ContainsKey(Pack.Header.Sequence))
{
try
{
NeedAck.Add(Pack.Header.Sequence, Pack);
}
catch (Exception e) // HACKY
{
e.ToString();
// 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.Sequence + ") to the 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 (PendingAcks)
{
// TODO: If we are over MAX_APPENDED_ACKS we should drain off some of these
if (PendingAcks.Count > 0 && PendingAcks.Count < MAX_APPENDED_ACKS)
{
Pack.Header.AckList = new uint[PendingAcks.Count];
int i = 0;
foreach (uint ack in PendingAcks.Values)
{
Pack.Header.AckList[i] = ack;
i++;
}
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();
if (Pack.Header.Zerocoded)
{
byte[] ZeroOutBuffer = new byte[4096];
int packetsize = Helpers.ZeroEncode(sendbuffer, sendbuffer.Length, ZeroOutBuffer);
m_networkServer.SendPacketTo(ZeroOutBuffer, packetsize, SocketFlags.None, m_circuitCode);
}
else
{
m_networkServer.SendPacketTo(sendbuffer, sendbuffer.Length, SocketFlags.None, m_circuitCode);
}
}
catch (Exception e)
{
MainLog.Instance.Warn("client",
"ClientView.PacketQueue.cs:ProcessOutPacket() - WARNING: Socket exception occurred on connection " +
userEP.ToString() + " - killing thread");
MainLog.Instance.Error(e.ToString());
KillThread();
}
}
public virtual void InPacket(Packet NewPack)
{
// Handle appended ACKs
if (NewPack.Header.AppendedAcks)
{
lock (NeedAck)
{
foreach (uint ack in NewPack.Header.AckList)
{
NeedAck.Remove(ack);
}
}
}
// Handle PacketAck packets
if (NewPack.Type == PacketType.PacketAck)
{
PacketAckPacket ackPacket = (PacketAckPacket) NewPack;
lock (NeedAck)
{
foreach (PacketAckPacket.PacketsBlock block in ackPacket.Packets)
{
NeedAck.Remove(block.ID);
}
}
}
else if ((NewPack.Type == PacketType.StartPingCheck))
{
//reply to pingcheck
StartPingCheckPacket startPing = (StartPingCheckPacket) NewPack;
CompletePingCheckPacket endPing = new CompletePingCheckPacket();
endPing.PingID.PingID = startPing.PingID.PingID;
OutPacket(endPing, ThrottleOutPacketType.Task);
}
else
{
QueItem item = new QueItem();
item.Packet = NewPack;
item.Incoming = true;
PacketQueue.Enqueue(item);
}
}
private void ThrottleCheck(ref int TypeBytesSent, int Throttle, ref Queue q, QueItem 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) && (TypeBytesSent <= ((int)(Throttle / throttleTimeDivisor))))
{
bytesSent += item.Packet.ToBytes().Length;
TypeBytesSent += item.Packet.ToBytes().Length;
PacketQueue.Enqueue(item);
}
else
{
q.Enqueue(item);
}
}
public virtual void OutPacket(Packet NewPack, ThrottleOutPacketType throttlePacketType)
{
QueItem item = new QueItem();
item.Packet = NewPack;
item.Incoming = false;
item.throttleType = throttlePacketType; // Packet throttle type
// The idea.. is if the packet throttle queues are empty and the client is under throttle for the type.
// Queue it up directly.
switch (throttlePacketType)
{
case ThrottleOutPacketType.Resend:
ThrottleCheck(ref ResendBytesSent, ResendthrottleOutbound, ref ResendOutgoingPacketQueue, item);
break;
case ThrottleOutPacketType.Texture:
ThrottleCheck(ref TextureBytesSent, TexturethrottleOutbound, ref TextureOutgoingPacketQueue, item);
break;
case ThrottleOutPacketType.Task:
ThrottleCheck(ref TaskBytesSent, TaskthrottleOutbound, ref TaskOutgoingPacketQueue, item);
break;
case ThrottleOutPacketType.Land:
ThrottleCheck(ref LandBytesSent, LandthrottleOutbound, ref LandOutgoingPacketQueue, item);
break;
case ThrottleOutPacketType.Asset:
ThrottleCheck(ref AssetBytesSent, AssetthrottleOutbound, ref AssetOutgoingPacketQueue, item);
break;
case ThrottleOutPacketType.Cloud:
ThrottleCheck(ref CloudBytesSent, CloudthrottleOutbound, ref CloudOutgoingPacketQueue, item);
break;
case ThrottleOutPacketType.Wind:
ThrottleCheck(ref WindBytesSent, WindthrottleOutbound, 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
PacketQueue.Enqueue(item);
break;
}
//OutgoingPacketQueue.Enqueue(item);
}
# region Low Level Packet Methods
protected void ack_pack(Packet Pack)
{
if (Pack.Header.Reliable)
{
PacketAckPacket ack_it = new PacketAckPacket();
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 (PendingAcks)
{
uint sequence = (uint)Pack.Header.Sequence;
if (!PendingAcks.ContainsKey(sequence)) { PendingAcks[sequence] = sequence; }
}
}*/
}
protected void ResendUnacked()
{
int now = System.Environment.TickCount;
lock (NeedAck)
{
foreach (Packet packet in NeedAck.Values)
{
if ((now - packet.TickCount > RESEND_TIMEOUT) && (!packet.Header.Resent))
{
MainLog.Instance.Verbose("NETWORK", "Resending " + packet.Type.ToString() + " packet, " +
(now - packet.TickCount) + "ms have passed");
packet.Header.Resent = true;
OutPacket(packet, ThrottleOutPacketType.Resend);
}
}
}
}
protected void SendAcks()
{
lock (PendingAcks)
{
if (PendingAcks.Count > 0)
{
if (PendingAcks.Count > 250)
{
// FIXME: Handle the odd case where we have too many pending ACKs queued up
MainLog.Instance.Verbose("NETWORK", "Too many ACKs queued up!");
return;
}
//MainLog.Instance.Verbose("Sending PacketAck");
int i = 0;
PacketAckPacket acks = new PacketAckPacket();
acks.Packets = new PacketAckPacket.PacketsBlock[PendingAcks.Count];
foreach (uint ack in PendingAcks.Values)
{
acks.Packets[i] = new PacketAckPacket.PacketsBlock();
acks.Packets[i].ID = ack;
i++;
}
acks.Header.Reliable = false;
OutPacket(acks, ThrottleOutPacketType.Unknown);
PendingAcks.Clear();
}
}
}
protected void AckTimer_Elapsed(object sender, ElapsedEventArgs ea)
{
SendAcks();
ResendUnacked();
}
#endregion
// Previously ClientView.ProcessPackets
private int m_moneyBalance;
public int MoneyBalance
{
get { return m_moneyBalance; }
}
public bool AddMoney(int debit)
{
if (m_moneyBalance + debit >= 0)
{
m_moneyBalance += debit;
SendMoneyBalance(LLUUID.Zero, true, Helpers.StringToField("Poof Poof!"), m_moneyBalance);
return true;
}
else
{
return false;
}
}
protected void ProcessInPacket(Packet Pack)
{
ack_pack(Pack);
if (ProcessPacketMethod(Pack))
{
//there is a handler registered that handled this packet type
return;
}
else
{
Encoding _enc = Encoding.ASCII;
switch (Pack.Type)
{
#region Scene/Avatar
case PacketType.AvatarPropertiesRequest:
AvatarPropertiesRequestPacket avatarProperties = (AvatarPropertiesRequestPacket) Pack;
if (OnRequestAvatarProperties != null)
{
OnRequestAvatarProperties(this, avatarProperties.AgentData.AvatarID);
}
break;
case PacketType.ChatFromViewer:
ChatFromViewerPacket inchatpack = (ChatFromViewerPacket) Pack;
string fromName = ""; //ClientAvatar.firstname + " " + ClientAvatar.lastname;
byte[] message = inchatpack.ChatData.Message;
byte type = inchatpack.ChatData.Type;
LLVector3 fromPos = new LLVector3(); // ClientAvatar.Pos;
LLUUID fromAgentID = AgentId;
int channel = inchatpack.ChatData.Channel;
if (OnChatFromViewer != null)
{
ChatFromViewerArgs args = new ChatFromViewerArgs();
args.Channel = channel;
args.From = fromName;
args.Message = Helpers.FieldToUTF8String(message);
args.Type = (ChatTypeEnum) type;
args.Position = fromPos;
args.Scene = Scene;
args.Sender = this;
OnChatFromViewer(this, args);
}
break;
case PacketType.ImprovedInstantMessage:
ImprovedInstantMessagePacket msgpack = (ImprovedInstantMessagePacket) Pack;
string IMfromName = Util.FieldToString(msgpack.MessageBlock.FromAgentName);
string IMmessage = Helpers.FieldToUTF8String(msgpack.MessageBlock.Message);
if (OnInstantMessage != null)
{
OnInstantMessage(msgpack.AgentData.AgentID, msgpack.AgentData.SessionID,
msgpack.MessageBlock.ToAgentID, msgpack.MessageBlock.ID,
msgpack.MessageBlock.Timestamp, IMfromName, IMmessage,
msgpack.MessageBlock.Dialog);
}
break;
case PacketType.RezObject:
RezObjectPacket rezPacket = (RezObjectPacket) Pack;
if (OnRezObject != null)
{
OnRezObject(this, rezPacket.InventoryData.ItemID, rezPacket.RezData.RayEnd);
}
break;
case PacketType.DeRezObject:
if (OnDeRezObject != null)
{
OnDeRezObject(Pack, this);
}
break;
case PacketType.ModifyLand:
ModifyLandPacket modify = (ModifyLandPacket) Pack;
if (modify.ParcelData.Length > 0)
{
if (OnModifyTerrain != null)
{
OnModifyTerrain(modify.ModifyBlock.Height, modify.ModifyBlock.Seconds,
modify.ModifyBlock.BrushSize,
modify.ModifyBlock.Action, modify.ParcelData[0].North,
modify.ParcelData[0].West, this);
}
}
break;
case PacketType.RegionHandshakeReply:
if (OnRegionHandShakeReply != null)
{
OnRegionHandShakeReply(this);
}
break;
case PacketType.AgentWearablesRequest:
if (OnRequestWearables != null)
{
OnRequestWearables( );
}
if (OnRequestAvatarsData != null)
{
OnRequestAvatarsData(this);
}
break;
case PacketType.AgentSetAppearance:
//MainLog.Instance.Verbose("set appear", Pack.ToString());
AgentSetAppearancePacket appear = (AgentSetAppearancePacket) Pack;
if (OnSetAppearance != null)
{
OnSetAppearance(appear.ObjectData.TextureEntry, appear.VisualParam);
}
break;
case PacketType.AgentIsNowWearing:
if (OnAvatarNowWearing != null)
{
AgentIsNowWearingPacket nowWearing = (AgentIsNowWearingPacket)Pack;
AvatarWearingArgs wearingArgs = new AvatarWearingArgs();
for (int i = 0; i < nowWearing.WearableData.Length; i++)
{
AvatarWearingArgs.Wearable wearable = new AvatarWearingArgs.Wearable(nowWearing.WearableData[i].ItemID, nowWearing.WearableData[i].WearableType);
wearingArgs.NowWearing.Add(wearable);
}
OnAvatarNowWearing(this, wearingArgs);
}
break;
case PacketType.SetAlwaysRun:
SetAlwaysRunPacket run = (SetAlwaysRunPacket)Pack;
if (OnSetAlwaysRun != null)
OnSetAlwaysRun(this,run.AgentData.AlwaysRun);
break;
case PacketType.CompleteAgentMovement:
if (OnCompleteMovementToRegion != null)
{
OnCompleteMovementToRegion();
}
break;
case PacketType.AgentUpdate:
if (OnAgentUpdate != null)
{
AgentUpdatePacket agenUpdate = (AgentUpdatePacket) Pack;
OnAgentUpdate(this, agenUpdate); //agenUpdate.AgentData.ControlFlags, agenUpdate.AgentData.BodyRotationa);
}
break;
case PacketType.AgentAnimation:
AgentAnimationPacket AgentAni = (AgentAnimationPacket) Pack;
for (int i = 0; i < AgentAni.AnimationList.Length; i++)
{
if (AgentAni.AnimationList[i].StartAnim)
{
if (OnStartAnim != null)
{
OnStartAnim(this, AgentAni.AnimationList[i].AnimID, 1);
}
}
}
break;
case PacketType.AgentRequestSit:
if (OnAgentRequestSit != null)
{
AgentRequestSitPacket agentRequestSit = (AgentRequestSitPacket) Pack;
OnAgentRequestSit(this, agentRequestSit.AgentData.AgentID,
agentRequestSit.TargetObject.TargetID, agentRequestSit.TargetObject.Offset);
}
break;
case PacketType.AgentSit:
if (OnAgentSit != null)
{
AgentSitPacket agentSit = (AgentSitPacket) Pack;
OnAgentSit(this, agentSit.AgentData.AgentID);
}
break;
case PacketType.AvatarPickerRequest:
AvatarPickerRequestPacket avRequestQuery = (AvatarPickerRequestPacket)Pack;
AvatarPickerRequestPacket.AgentDataBlock Requestdata = avRequestQuery.AgentData;
AvatarPickerRequestPacket.DataBlock querydata = avRequestQuery.Data;
//System.Console.WriteLine("Agent Sends:" + Helpers.FieldToUTF8String(querydata.Name));
if (OnAvatarPickerRequest != null)
{
OnAvatarPickerRequest(this, Requestdata.AgentID, Requestdata.QueryID, Helpers.FieldToUTF8String(querydata.Name));
}
break;
#endregion
#region Objects/m_sceneObjects
case PacketType.ObjectLink:
//MainLog.Instance.Verbose(Pack.ToString());
ObjectLinkPacket link = (ObjectLinkPacket) Pack;
uint parentprimid = 0;
List childrenprims = new List();
if (link.ObjectData.Length > 1)
{
parentprimid = link.ObjectData[0].ObjectLocalID;
for (int i = 1; i < link.ObjectData.Length; i++)
{
childrenprims.Add(link.ObjectData[i].ObjectLocalID);
}
}
if (OnLinkObjects != null)
{
OnLinkObjects(parentprimid, childrenprims);
}
break;
case PacketType.ObjectDelink:
//MainLog.Instance.Verbose(Pack.ToString());
ObjectDelinkPacket delink = (ObjectDelinkPacket) Pack;
// It appears the prim at index 0 is not always the root prim (for
// instance, when one prim of a link set has been edited independently
// of the others). Therefore, we'll pass all the ids onto the delink
// method for it to decide which is the root.
List prims = new List();
for (int i = 0; i < delink.ObjectData.Length; i++)
{
prims.Add(delink.ObjectData[i].ObjectLocalID);
}
if (OnDelinkObjects != null)
{
OnDelinkObjects(prims);
}
break;
case PacketType.ObjectAdd:
if (OnAddPrim != null)
{
ObjectAddPacket addPacket = (ObjectAddPacket) Pack;
PrimitiveBaseShape shape = GetShapeFromAddPacket(addPacket);
OnAddPrim(AgentId, addPacket.ObjectData.RayEnd, addPacket.ObjectData.Rotation, shape);
}
break;
case PacketType.ObjectShape:
ObjectShapePacket shapePacket = (ObjectShapePacket) Pack;
for (int i = 0; i < shapePacket.ObjectData.Length; i++)
{
if (OnUpdatePrimShape != null)
{
OnUpdatePrimShape(this.m_agentId, shapePacket.ObjectData[i].ObjectLocalID, shapePacket.ObjectData[i]);
}
}
break;
case PacketType.ObjectExtraParams:
ObjectExtraParamsPacket extraPar = (ObjectExtraParamsPacket) Pack;
if (OnUpdateExtraParams != null)
{
OnUpdateExtraParams(this.m_agentId, extraPar.ObjectData[0].ObjectLocalID, extraPar.ObjectData[0].ParamType,
extraPar.ObjectData[0].ParamInUse, extraPar.ObjectData[0].ParamData);
}
break;
case PacketType.ObjectDuplicate:
ObjectDuplicatePacket dupe = (ObjectDuplicatePacket) Pack;
ObjectDuplicatePacket.AgentDataBlock AgentandGroupData = dupe.AgentData;
for (int i = 0; i < dupe.ObjectData.Length; i++)
{
if (OnObjectDuplicate != null)
{
OnObjectDuplicate(dupe.ObjectData[i].ObjectLocalID, dupe.SharedData.Offset,
dupe.SharedData.DuplicateFlags, AgentandGroupData.AgentID, AgentandGroupData.GroupID);
}
}
break;
case PacketType.ObjectSelect:
ObjectSelectPacket incomingselect = (ObjectSelectPacket) Pack;
for (int i = 0; i < incomingselect.ObjectData.Length; i++)
{
if (OnObjectSelect != null)
{
OnObjectSelect(incomingselect.ObjectData[i].ObjectLocalID, this);
}
}
break;
case PacketType.ObjectDeselect:
ObjectDeselectPacket incomingdeselect = (ObjectDeselectPacket) Pack;
for (int i = 0; i < incomingdeselect.ObjectData.Length; i++)
{
if (OnObjectDeselect != null)
{
OnObjectDeselect(incomingdeselect.ObjectData[i].ObjectLocalID, this);
}
}
break;
case PacketType.ObjectFlagUpdate:
ObjectFlagUpdatePacket flags = (ObjectFlagUpdatePacket) Pack;
if (OnUpdatePrimFlags != null)
{
OnUpdatePrimFlags(flags.AgentData.ObjectLocalID, Pack, this);
}
break;
case PacketType.ObjectImage:
ObjectImagePacket imagePack = (ObjectImagePacket) Pack;
for (int i = 0; i < imagePack.ObjectData.Length; i++)
{
if (OnUpdatePrimTexture != null)
{
OnUpdatePrimTexture(imagePack.ObjectData[i].ObjectLocalID,
imagePack.ObjectData[i].TextureEntry, this);
}
}
break;
case PacketType.ObjectGrab:
ObjectGrabPacket grab = (ObjectGrabPacket) Pack;
if (OnGrabObject != null)
{
OnGrabObject(grab.ObjectData.LocalID, grab.ObjectData.GrabOffset, this);
}
break;
case PacketType.ObjectGrabUpdate:
ObjectGrabUpdatePacket grabUpdate = (ObjectGrabUpdatePacket) Pack;
if (OnGrabUpdate != null)
{
OnGrabUpdate(grabUpdate.ObjectData.ObjectID, grabUpdate.ObjectData.GrabOffsetInitial,
grabUpdate.ObjectData.GrabPosition, this);
}
break;
case PacketType.ObjectDeGrab:
ObjectDeGrabPacket deGrab = (ObjectDeGrabPacket) Pack;
if (OnDeGrabObject != null)
{
OnDeGrabObject(deGrab.ObjectData.LocalID, this);
}
break;
case PacketType.ObjectDescription:
ObjectDescriptionPacket objDes = (ObjectDescriptionPacket) Pack;
for (int i = 0; i < objDes.ObjectData.Length; i++)
{
if (OnObjectDescription != null)
{
OnObjectDescription(objDes.ObjectData[i].LocalID,
enc.GetString(objDes.ObjectData[i].Description));
}
}
break;
case PacketType.ObjectName:
ObjectNamePacket objName = (ObjectNamePacket) Pack;
for (int i = 0; i < objName.ObjectData.Length; i++)
{
if (OnObjectName != null)
{
OnObjectName(objName.ObjectData[i].LocalID, enc.GetString(objName.ObjectData[i].Name));
}
}
break;
case PacketType.ObjectPermissions:
// MainLog.Instance.Warn("CLIENT", "unhandled packet " + Pack.ToString());
break;
case PacketType.RequestObjectPropertiesFamily:
//This powers the little tooltip that appears when you move your mouse over an object
RequestObjectPropertiesFamilyPacket packToolTip = (RequestObjectPropertiesFamilyPacket)Pack;
RequestObjectPropertiesFamilyPacket.ObjectDataBlock packObjBlock = packToolTip.ObjectData;
if (OnRequestObjectPropertiesFamily != null)
{
OnRequestObjectPropertiesFamily(this, this.m_agentId, packObjBlock.RequestFlags, packObjBlock.ObjectID);
}
break;
#endregion
#region Inventory/Asset/Other related packets
case PacketType.RequestImage:
RequestImagePacket imageRequest = (RequestImagePacket) Pack;
//Console.WriteLine("image request: " + Pack.ToString());
for (int i = 0; i < imageRequest.RequestImage.Length; i++)
{
// still working on the Texture download module so for now using old method
// TextureRequestArgs args = new TextureRequestArgs();
// args.RequestedAssetID = imageRequest.RequestImage[i].Image;
// args.DiscardLevel = imageRequest.RequestImage[i].DiscardLevel;
// args.PacketNumber = imageRequest.RequestImage[i].Packet;
// if (OnRequestTexture != null)
// {
// OnRequestTexture(this, args);
// }
m_assetCache.AddTextureRequest(this, imageRequest.RequestImage[i].Image,
imageRequest.RequestImage[i].Packet,
imageRequest.RequestImage[i].DiscardLevel);
}
break;
case PacketType.TransferRequest:
//Console.WriteLine("ClientView.ProcessPackets.cs:ProcessInPacket() - Got transfer request");
TransferRequestPacket transfer = (TransferRequestPacket) Pack;
m_assetCache.AddAssetRequest(this, transfer);
break;
case PacketType.AssetUploadRequest:
AssetUploadRequestPacket request = (AssetUploadRequestPacket) Pack;
// Console.WriteLine("upload request " + Pack.ToString());
// Console.WriteLine("upload request was for assetid: " + request.AssetBlock.TransactionID.Combine(this.SecureSessionId).ToStringHyphenated());
if (OnAssetUploadRequest != null)
{
OnAssetUploadRequest(this, request.AssetBlock.TransactionID.Combine(SecureSessionId),
request.AssetBlock.TransactionID, request.AssetBlock.Type,
request.AssetBlock.AssetData, request.AssetBlock.StoreLocal);
}
break;
case PacketType.RequestXfer:
RequestXferPacket xferReq = (RequestXferPacket) Pack;
if (OnRequestXfer != null)
{
OnRequestXfer(this, xferReq.XferID.ID, Util.FieldToString(xferReq.XferID.Filename));
}
break;
case PacketType.SendXferPacket:
SendXferPacketPacket xferRec = (SendXferPacketPacket) Pack;
if (OnXferReceive != null)
{
OnXferReceive(this, xferRec.XferID.ID, xferRec.XferID.Packet, xferRec.DataPacket.Data);
}
break;
case PacketType.ConfirmXferPacket:
ConfirmXferPacketPacket confirmXfer = (ConfirmXferPacketPacket) Pack;
if (OnConfirmXfer != null)
{
OnConfirmXfer(this, confirmXfer.XferID.ID, confirmXfer.XferID.Packet);
}
break;
case PacketType.CreateInventoryFolder:
if (OnCreateNewInventoryFolder != null)
{
CreateInventoryFolderPacket invFolder = (CreateInventoryFolderPacket) Pack;
OnCreateNewInventoryFolder(this, invFolder.FolderData.FolderID,
(ushort) invFolder.FolderData.Type,
Util.FieldToString(invFolder.FolderData.Name),
invFolder.FolderData.ParentID);
}
break;
case PacketType.CreateInventoryItem:
CreateInventoryItemPacket createItem = (CreateInventoryItemPacket) Pack;
if (OnCreateNewInventoryItem != null)
{
OnCreateNewInventoryItem(this, createItem.InventoryBlock.TransactionID,
createItem.InventoryBlock.FolderID,
createItem.InventoryBlock.CallbackID,
Util.FieldToString(createItem.InventoryBlock.Description),
Util.FieldToString(createItem.InventoryBlock.Name),
createItem.InventoryBlock.InvType,
createItem.InventoryBlock.Type,
createItem.InventoryBlock.WearableType,
createItem.InventoryBlock.NextOwnerMask);
}
break;
case PacketType.FetchInventory:
if (OnFetchInventory != null)
{
FetchInventoryPacket FetchInventory = (FetchInventoryPacket) Pack;
for (int i = 0; i < FetchInventory.InventoryData.Length; i++)
{
OnFetchInventory(this, FetchInventory.InventoryData[i].ItemID,
FetchInventory.InventoryData[i].OwnerID);
}
}
break;
case PacketType.FetchInventoryDescendents:
if (OnFetchInventoryDescendents != null)
{
FetchInventoryDescendentsPacket Fetch = (FetchInventoryDescendentsPacket) Pack;
OnFetchInventoryDescendents(this, Fetch.InventoryData.FolderID, Fetch.InventoryData.OwnerID,
Fetch.InventoryData.FetchFolders, Fetch.InventoryData.FetchItems,
Fetch.InventoryData.SortOrder);
}
break;
case PacketType.UpdateInventoryItem:
UpdateInventoryItemPacket update = (UpdateInventoryItemPacket) Pack;
if (OnUpdateInventoryItem != null)
{
for (int i = 0; i < update.InventoryData.Length; i++)
{
OnUpdateInventoryItem(this, update.InventoryData[i].TransactionID,
update.InventoryData[i].ItemID,
Util.FieldToString(update.InventoryData[i].Name),
Util.FieldToString(update.InventoryData[i].Description),
update.InventoryData[i].NextOwnerMask);
}
}
//Console.WriteLine(Pack.ToString());
/*for (int i = 0; i < update.InventoryData.Length; i++)
{
if (update.InventoryData[i].TransactionID != LLUUID.Zero)
{
AssetBase asset = m_assetCache.GetAsset(update.InventoryData[i].TransactionID.Combine(this.SecureSessionId));
if (asset != null)
{
// Console.WriteLine("updating inventory item, found asset" + asset.FullID.ToStringHyphenated() + " 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.ToStringHyphenated() + " to cache");
m_inventoryCache.UpdateInventoryItemAsset(this, update.InventoryData[i].ItemID, asset);
}
else
{
//Console.WriteLine("trying to update inventory item, but asset is null");
}
}
}
else
{
m_inventoryCache.UpdateInventoryItemDetails(this, update.InventoryData[i].ItemID, update.InventoryData[i]); ;
}
}*/
break;
case PacketType.CopyInventoryItem:
CopyInventoryItemPacket copyitem = (CopyInventoryItemPacket) Pack;
if (OnCopyInventoryItem != null)
{
foreach (CopyInventoryItemPacket.InventoryDataBlock datablock in copyitem.InventoryData)
{
OnCopyInventoryItem(this, datablock.CallbackID, datablock.OldAgentID, datablock.OldItemID, datablock.NewFolderID, Util.FieldToString(datablock.NewName));
}
}
break;
case PacketType.RequestTaskInventory:
RequestTaskInventoryPacket requesttask = (RequestTaskInventoryPacket) Pack;
if (OnRequestTaskInventory != null)
{
OnRequestTaskInventory(this, requesttask.InventoryData.LocalID);
}
break;
case PacketType.UpdateTaskInventory:
//Console.WriteLine(Pack.ToString());
UpdateTaskInventoryPacket updatetask = (UpdateTaskInventoryPacket) Pack;
if (OnUpdateTaskInventory != null)
{
if (updatetask.UpdateData.Key == 0)
{
OnUpdateTaskInventory(this, updatetask.InventoryData.ItemID,
updatetask.InventoryData.FolderID, updatetask.UpdateData.LocalID);
}
}
break;
case PacketType.RemoveTaskInventory:
RemoveTaskInventoryPacket removeTask = (RemoveTaskInventoryPacket) Pack;
if (OnRemoveTaskItem != null)
{
OnRemoveTaskItem(this, removeTask.InventoryData.ItemID, removeTask.InventoryData.LocalID);
}
break;
case PacketType.MoveTaskInventory:
MainLog.Instance.Warn("CLIENT", "unhandled MoveTaskInventory packet");
break;
case PacketType.RezScript:
//Console.WriteLine(Pack.ToString());
RezScriptPacket rezScript = (RezScriptPacket) Pack;
if (OnRezScript != null)
{
OnRezScript(this, rezScript.InventoryBlock.ItemID, rezScript.UpdateBlock.ObjectLocalID);
}
break;
case PacketType.MapLayerRequest:
RequestMapLayer();
break;
case PacketType.MapBlockRequest:
MapBlockRequestPacket MapRequest = (MapBlockRequestPacket) Pack;
if (OnRequestMapBlocks != null)
{
OnRequestMapBlocks(this, MapRequest.PositionData.MinX, MapRequest.PositionData.MinY,
MapRequest.PositionData.MaxX, MapRequest.PositionData.MaxY);
}
break;
case PacketType.MapNameRequest:
MapNameRequestPacket map = (MapNameRequestPacket) Pack;
string mapName = UTF8Encoding.UTF8.GetString(map.NameData.Name, 0,
map.NameData.Name.Length - 1);
if (OnMapNameRequest != null)
{
OnMapNameRequest(this, mapName);
}
break;
case PacketType.TeleportLandmarkRequest:
TeleportLandmarkRequestPacket tpReq = (TeleportLandmarkRequestPacket) Pack;
TeleportStartPacket tpStart = new TeleportStartPacket();
tpStart.Info.TeleportFlags = 8; // tp via lm
OutPacket(tpStart, ThrottleOutPacketType.Task);
TeleportProgressPacket tpProgress = new TeleportProgressPacket();
tpProgress.Info.Message = (new ASCIIEncoding()).GetBytes("sending_landmark");
tpProgress.Info.TeleportFlags = 8;
tpProgress.AgentData.AgentID = tpReq.Info.AgentID;
OutPacket(tpProgress, ThrottleOutPacketType.Task);
// Fetch landmark
LLUUID lmid = tpReq.Info.LandmarkID;
AssetBase lma = m_assetCache.GetAsset(lmid);
if (lma != null)
{
AssetLandmark lm = new AssetLandmark(lma);
if (lm.RegionID == m_scene.RegionInfo.RegionID)
{
TeleportLocalPacket tpLocal = new TeleportLocalPacket();
tpLocal.Info.AgentID = tpReq.Info.AgentID;
tpLocal.Info.TeleportFlags = 8; // Teleport via landmark
tpLocal.Info.LocationID = 2;
tpLocal.Info.Position = lm.Position;
OutPacket(tpLocal, ThrottleOutPacketType.Task);
}
else
{
TeleportCancelPacket tpCancel = new TeleportCancelPacket();
tpCancel.Info.AgentID = tpReq.Info.AgentID;
tpCancel.Info.SessionID = tpReq.Info.SessionID;
OutPacket(tpCancel, ThrottleOutPacketType.Task);
}
}
else
{
Console.WriteLine("Cancelling Teleport - fetch asset not yet implemented");
TeleportCancelPacket tpCancel = new TeleportCancelPacket();
tpCancel.Info.AgentID = tpReq.Info.AgentID;
tpCancel.Info.SessionID = tpReq.Info.SessionID;
OutPacket(tpCancel, ThrottleOutPacketType.Task);
}
break;
case PacketType.TeleportLocationRequest:
TeleportLocationRequestPacket tpLocReq = (TeleportLocationRequestPacket) Pack;
// Console.WriteLine(tpLocReq.ToString());
if (OnTeleportLocationRequest != null)
{
OnTeleportLocationRequest(this, tpLocReq.Info.RegionHandle, tpLocReq.Info.Position,
tpLocReq.Info.LookAt, 16);
}
else
{
//no event handler so cancel request
TeleportCancelPacket tpCancel = new TeleportCancelPacket();
tpCancel.Info.SessionID = tpLocReq.AgentData.SessionID;
tpCancel.Info.AgentID = tpLocReq.AgentData.AgentID;
OutPacket(tpCancel, ThrottleOutPacketType.Task);
}
break;
#endregion
case PacketType.MoneyBalanceRequest:
SendMoneyBalance(LLUUID.Zero, true, new byte[0], MoneyBalance);
break;
case PacketType.UUIDNameRequest:
UUIDNameRequestPacket incoming = (UUIDNameRequestPacket) Pack;
foreach (UUIDNameRequestPacket.UUIDNameBlockBlock UUIDBlock in incoming.UUIDNameBlock)
{
OnNameFromUUIDRequest(UUIDBlock.ID, this);
}
break;
#region Parcel related packets
case PacketType.ParcelPropertiesRequest:
ParcelPropertiesRequestPacket propertiesRequest = (ParcelPropertiesRequestPacket) Pack;
if (OnParcelPropertiesRequest != null)
{
OnParcelPropertiesRequest((int) Math.Round(propertiesRequest.ParcelData.West),
(int) Math.Round(propertiesRequest.ParcelData.South),
(int) Math.Round(propertiesRequest.ParcelData.East),
(int) Math.Round(propertiesRequest.ParcelData.North),
propertiesRequest.ParcelData.SequenceID,
propertiesRequest.ParcelData.SnapSelection, this);
}
break;
case PacketType.ParcelDivide:
ParcelDividePacket landDivide = (ParcelDividePacket) Pack;
if (OnParcelDivideRequest != null)
{
OnParcelDivideRequest((int) Math.Round(landDivide.ParcelData.West),
(int) Math.Round(landDivide.ParcelData.South),
(int) Math.Round(landDivide.ParcelData.East),
(int) Math.Round(landDivide.ParcelData.North), this);
}
break;
case PacketType.ParcelJoin:
ParcelJoinPacket landJoin = (ParcelJoinPacket) Pack;
if (OnParcelJoinRequest != null)
{
OnParcelJoinRequest((int) Math.Round(landJoin.ParcelData.West),
(int) Math.Round(landJoin.ParcelData.South),
(int) Math.Round(landJoin.ParcelData.East),
(int) Math.Round(landJoin.ParcelData.North), this);
}
break;
case PacketType.ParcelPropertiesUpdate:
ParcelPropertiesUpdatePacket updatePacket = (ParcelPropertiesUpdatePacket) Pack;
if (OnParcelPropertiesUpdateRequest != null)
{
OnParcelPropertiesUpdateRequest(updatePacket, this);
}
break;
case PacketType.ParcelSelectObjects:
ParcelSelectObjectsPacket selectPacket = (ParcelSelectObjectsPacket) Pack;
if (OnParcelSelectObjects != null)
{
OnParcelSelectObjects(selectPacket.ParcelData.LocalID,
Convert.ToInt32(selectPacket.ParcelData.ReturnType), this);
}
break;
case PacketType.ParcelObjectOwnersRequest:
//System.Console.WriteLine(Pack.ToString());
ParcelObjectOwnersRequestPacket reqPacket = (ParcelObjectOwnersRequestPacket) Pack;
if (OnParcelObjectOwnerRequest != null)
{
OnParcelObjectOwnerRequest(reqPacket.ParcelData.LocalID, this);
}
break;
#endregion
#region Estate Packets
case PacketType.EstateOwnerMessage:
EstateOwnerMessagePacket messagePacket = (EstateOwnerMessagePacket) Pack;
if (OnEstateOwnerMessage != null)
{
OnEstateOwnerMessage(messagePacket, this);
}
break;
case PacketType.AgentThrottle:
AgentThrottlePacket atpack = (AgentThrottlePacket)Pack;
byte[] throttle = atpack.Throttle.Throttles;
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;
/*
MainLog.Instance.Verbose("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 <= throttleOutboundMax)
{
// Sanity
// Making sure the client sends sane values
// This gives us a measure of control of the comms
// Check Max of Type
// Then Check Min of type
// Resend throttle
if (tResend <= ResendthrottleMAX)
ResendthrottleOutbound = tResend;
if (tResend < ResendthrottleMin)
ResendthrottleOutbound = ResendthrottleMin;
// Land throttle
if (tLand <= LandthrottleMax)
LandthrottleOutbound = tLand;
if (tLand < LandthrottleMin)
LandthrottleOutbound = LandthrottleMin;
// Wind throttle
if (tWind <= WindthrottleMax)
WindthrottleOutbound = tWind;
if (tWind < WindthrottleMin)
WindthrottleOutbound = WindthrottleMin;
// Cloud throttle
if (tCloud <= CloudthrottleMax)
CloudthrottleOutbound = tCloud;
if (tCloud < CloudthrottleMin)
CloudthrottleOutbound = CloudthrottleMin;
// Task throttle
if (tTask <= TaskthrottleMax)
TaskthrottleOutbound = tTask;
if (tTask < TaskthrottleMin)
TaskthrottleOutbound = TaskthrottleMin;
// Texture throttle
if (tTexture <= TexturethrottleMax)
TexturethrottleOutbound = tTexture;
if (tTexture < TexturethrottleMin)
TexturethrottleOutbound = TexturethrottleMin;
//Asset throttle
if (tAsset <= AssetthrottleMax)
AssetthrottleOutbound = tAsset;
if (tAsset < AssetthrottleMin)
AssetthrottleOutbound = AssetthrottleMin;
/* MainLog.Instance.Verbose("THROTTLE", "Using:resendbytes=" + ResendthrottleOutbound +
" landbytes=" + LandthrottleOutbound +
" windbytes=" + WindthrottleOutbound +
" cloudbytes=" + CloudthrottleOutbound +
" taskbytes=" + TaskthrottleOutbound +
" texturebytes=" + TexturethrottleOutbound +
" Assetbytes=" + AssetthrottleOutbound +
" Allbytes=" + tall);
*/
}
else
{
// The client didn't send acceptable values..
// so it's our job now to turn them into acceptable values
// We're going to first scale the values down
// After that we're going to check if the scaled values are sane
// We're going to be dividing by a user value.. so make sure
// we don't get a divide by zero error.
if (tall > 0)
{
// Find out the percentage of all communications
// the client requests for each type. We'll keep resend at
// it's client recommended level (won't scale it down)
// unless it's beyond sane values itself.
if (tResend <= ResendthrottleMAX)
{
// This is nexted because we only want to re-set the values
// the packet throttler uses once.
if (tResend >= ResendthrottleMin)
{
ResendthrottleOutbound = tResend;
}
else
{
ResendthrottleOutbound = ResendthrottleMin;
}
}
else
{
ResendthrottleOutbound = ResendthrottleMAX;
}
// Getting Percentages of communication for each type of data
float LandPercent = (float)(tLand / tall);
float WindPercent = (float)(tWind / tall);
float CloudPercent = (float)(tCloud / tall);
float TaskPercent = (float)(tTask / tall);
float TexturePercent = (float)(tTexture / tall);
float AssetPercent = (float)(tAsset / tall);
// Okay.. now we've got the percentages of total communication.
// Apply them to a new max total
int tLandResult = (int)(LandPercent * throttleOutboundMax);
int tWindResult = (int)(WindPercent * throttleOutboundMax);
int tCloudResult = (int)(CloudPercent * throttleOutboundMax);
int tTaskResult = (int)(TaskPercent * throttleOutboundMax);
int tTextureResult = (int)(TexturePercent * throttleOutboundMax);
int tAssetResult = (int)(AssetPercent * throttleOutboundMax);
// Now we have to check our scaled values for sanity
// Check Max of Type
// Then Check Min of type
// Land throttle
if (tLandResult <= LandthrottleMax)
LandthrottleOutbound = tLandResult;
if (tLandResult < LandthrottleMin)
LandthrottleOutbound = LandthrottleMin;
// Wind throttle
if (tWindResult <= WindthrottleMax)
WindthrottleOutbound = tWindResult;
if (tWindResult < WindthrottleMin)
WindthrottleOutbound = WindthrottleMin;
// Cloud throttle
if (tCloudResult <= CloudthrottleMax)
CloudthrottleOutbound = tCloudResult;
if (tCloudResult < CloudthrottleMin)
CloudthrottleOutbound = CloudthrottleMin;
// Task throttle
if (tTaskResult <= TaskthrottleMax)
TaskthrottleOutbound = tTaskResult;
if (tTaskResult < TaskthrottleMin)
TaskthrottleOutbound = TaskthrottleMin;
// Texture throttle
if (tTextureResult <= TexturethrottleMax)
TexturethrottleOutbound = tTextureResult;
if (tTextureResult < TexturethrottleMin)
TexturethrottleOutbound = TexturethrottleMin;
//Asset throttle
if (tAssetResult <= AssetthrottleMax)
AssetthrottleOutbound = tAssetResult;
if (tAssetResult < AssetthrottleMin)
AssetthrottleOutbound = AssetthrottleMin;
/* MainLog.Instance.Verbose("THROTTLE", "Using:resendbytes=" + ResendthrottleOutbound +
" landbytes=" + LandthrottleOutbound +
" windbytes=" + WindthrottleOutbound +
" cloudbytes=" + CloudthrottleOutbound +
" taskbytes=" + TaskthrottleOutbound +
" texturebytes=" + TexturethrottleOutbound +
" Assetbytes=" + AssetthrottleOutbound +
" Allbytes=" + tall);
*/
}
else
{
// The client sent a stupid value..
// We're going to set the throttles to the minimum possible
ResendthrottleOutbound = ResendthrottleMin;
LandthrottleOutbound = LandthrottleMin;
WindthrottleOutbound = WindthrottleMin;
CloudthrottleOutbound = CloudthrottleMin;
TaskthrottleOutbound = TaskthrottleMin;
TexturethrottleOutbound = TexturethrottleMin;
AssetthrottleOutbound = AssetthrottleMin;
MainLog.Instance.Verbose("THROTTLE", "ClientSentBadThrottle Using:resendbytes=" + ResendthrottleOutbound +
" landbytes=" + LandthrottleOutbound +
" windbytes=" + WindthrottleOutbound +
" cloudbytes=" + CloudthrottleOutbound +
" taskbytes=" + TaskthrottleOutbound +
" texturebytes=" + TexturethrottleOutbound +
" Assetbytes=" + AssetthrottleOutbound +
" Allbytes=" + tall);
}
}
// Reset Client Throttles
// This has the effect of 'wiggling the slider
// causes prim and stuck textures that didn't download to download
ResendBytesSent = 0;
LandBytesSent = 0;
WindBytesSent = 0;
CloudBytesSent = 0;
TaskBytesSent = 0;
AssetBytesSent = 0;
TextureBytesSent = 0;
//Yay, we've finally handled the agent Throttle packet!
break;
#endregion
#region unimplemented handlers
case PacketType.RequestGodlikePowers:
RequestGodlikePowersPacket rglpPack = (RequestGodlikePowersPacket) Pack;
RequestGodlikePowersPacket.RequestBlockBlock rblock = rglpPack.RequestBlock;
LLUUID token = rblock.Token;
RequestGodlikePowersPacket.AgentDataBlock ablock = rglpPack.AgentData;
OnRequestGodlikePowers(ablock.AgentID, ablock.SessionID, token, this);
break;
case PacketType.GodKickUser:
MainLog.Instance.Warn("CLIENT", "unhandled GodKickUser packet");
GodKickUserPacket gkupack = (GodKickUserPacket) Pack;
if (gkupack.UserInfo.GodSessionID == SessionId && this.AgentId == gkupack.UserInfo.GodID)
{
OnGodKickUser(gkupack.UserInfo.GodID, gkupack.UserInfo.GodSessionID, gkupack.UserInfo.AgentID, (uint) 0, gkupack.UserInfo.Reason);
}
else
{
SendAgentAlertMessage("Kick request denied", false);
}
//KickUserPacket kupack = new KickUserPacket();
//KickUserPacket.UserInfoBlock kupackib = kupack.UserInfo;
//kupack.UserInfo.AgentID = gkupack.UserInfo.AgentID;
//kupack.UserInfo.SessionID = gkupack.UserInfo.GodSessionID;
//kupack.TargetBlock.TargetIP = (uint)0;
//kupack.TargetBlock.TargetPort = (ushort)0;
//kupack.UserInfo.Reason = gkupack.UserInfo.Reason;
//OutPacket(kupack, ThrottleOutPacketType.Task);
break;
case PacketType.StartPingCheck:
// Send the client the ping response back
// Pass the same PingID in the matching packet
// Handled In the packet processing
MainLog.Instance.Debug("CLIENT", "possibly unhandled StartPingCheck packet");
break;
case PacketType.CompletePingCheck:
// Parhaps this should be processed on the Sim to determine whether or not to drop a dead client
// Dumping it to the verbose console until it's handled properly.
MainLog.Instance.Warn("CLIENT", "unhandled CompletePingCheck packet");
break;
case PacketType.ObjectScale:
// TODO: handle this packet
MainLog.Instance.Warn("CLIENT", "unhandled ObjectScale packet");
break;
case PacketType.ViewerStats:
// TODO: handle this packet
MainLog.Instance.Warn("CLIENT", "unhandled ViewerStats packet");
break;
case PacketType.EstateCovenantRequest:
// TODO: handle this packet
MainLog.Instance.Warn("CLIENT", "unhandled EstateCovenantRequest packet");
break;
case PacketType.CreateGroupRequest:
// TODO: handle this packet
MainLog.Instance.Warn("CLIENT", "unhandled CreateGroupRequest packet");
break;
case PacketType.GenericMessage:
// TODO: handle this packet
MainLog.Instance.Warn("CLIENT", "unhandled GenericMessage packet");
break;
case PacketType.MapItemRequest:
// TODO: handle this packet
MainLog.Instance.Warn("CLIENT", "unhandled MapItemRequest packet");
break;
case PacketType.AgentResume:
// TODO: handle this packet
MainLog.Instance.Warn("CLIENT", "unhandled AgentResume packet");
break;
case PacketType.AgentPause:
// TODO: handle this packet
MainLog.Instance.Warn("CLIENT", "unhandled AgentPause packet");
break;
case PacketType.TransferAbort:
// TODO: handle this packet
MainLog.Instance.Warn("CLIENT", "unhandled TransferAbort packet");
break;
case PacketType.MuteListRequest:
// TODO: handle this packet
MainLog.Instance.Warn("CLIENT", "unhandled MuteListRequest packet");
break;
case PacketType.AgentDataUpdateRequest:
// TODO: handle this packet
MainLog.Instance.Warn("CLIENT", "unhandled AgentDataUpdateRequest packet");
break;
case PacketType.ParcelAccessListRequest:
// TODO: handle this packet
MainLog.Instance.Warn("CLIENT", "unhandled ParcelAccessListRequest packet");
break;
case PacketType.ParcelDwellRequest:
// TODO: handle this packet
MainLog.Instance.Warn("CLIENT", "unhandled ParcelDwellRequest packet");
break;
case PacketType.UseCircuitCode:
// TODO: handle this packet
MainLog.Instance.Warn("CLIENT", "unhandled UseCircuitCode packet");
break;
case PacketType.EconomyDataRequest:
// TODO: handle this packet
MainLog.Instance.Warn("CLIENT", "unhandled EconomyDataRequest packet");
break;
case PacketType.AgentHeightWidth:
// TODO: handle this packet
MainLog.Instance.Warn("CLIENT", "unhandled AgentHeightWidth packet");
break;
case PacketType.ObjectSpinStop:
// TODO: handle this packet
MainLog.Instance.Warn("CLIENT", "unhandled ObjectSpinStop packet");
break;
default:
MainLog.Instance.Warn("CLIENT", "unhandled packet " + Pack.ToString());
break;
#endregion
}
}
}
private static PrimitiveBaseShape GetShapeFromAddPacket(ObjectAddPacket addPacket)
{
PrimitiveBaseShape shape = new PrimitiveBaseShape();
shape.PCode = addPacket.ObjectData.PCode;
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("00000000-0000-0000-9999-000000000005"));
shape.TextureEntry = ntex.ToBytes();
return shape;
}
public void SendLogoutPacket()
{
LogoutReplyPacket logReply = new LogoutReplyPacket();
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);
}
}
}