/*
* Copyright (c) 2006-2014, openmetaverse.org
* All rights reserved.
*
* - 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.
* - Neither the name of the openmetaverse.org 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR 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 OpenMetaverse.Packets;
namespace OpenMetaverse
{
///
/// Throttles the network traffic for various different traffic types.
/// Access this class through GridClient.Throttle
///
public class AgentThrottle
{
/// Maximum bits per second for resending unacknowledged packets
public float Resend
{
get { return resend; }
set
{
if (value > 150000.0f) resend = 150000.0f;
else if (value < 10000.0f) resend = 10000.0f;
else resend = value;
}
}
/// Maximum bits per second for LayerData terrain
public float Land
{
get { return land; }
set
{
if (value > 170000.0f) land = 170000.0f;
else if (value < 0.0f) land = 0.0f; // We don't have control of these so allow throttling to 0
else land = value;
}
}
/// Maximum bits per second for LayerData wind data
public float Wind
{
get { return wind; }
set
{
if (value > 34000.0f) wind = 34000.0f;
else if (value < 0.0f) wind = 0.0f; // We don't have control of these so allow throttling to 0
else wind = value;
}
}
/// Maximum bits per second for LayerData clouds
public float Cloud
{
get { return cloud; }
set
{
if (value > 34000.0f) cloud = 34000.0f;
else if (value < 0.0f) cloud = 0.0f; // We don't have control of these so allow throttling to 0
else cloud = value;
}
}
/// Unknown, includes object data
public float Task
{
get { return task; }
set
{
if (value > 446000.0f) task = 446000.0f;
else if (value < 4000.0f) task = 4000.0f;
else task = value;
}
}
/// Maximum bits per second for textures
public float Texture
{
get { return texture; }
set
{
if (value > 446000.0f) texture = 446000.0f;
else if (value < 4000.0f) texture = 4000.0f;
else texture = value;
}
}
/// Maximum bits per second for downloaded assets
public float Asset
{
get { return asset; }
set
{
if (value > 220000.0f) asset = 220000.0f;
else if (value < 10000.0f) asset = 10000.0f;
else asset = value;
}
}
/// Maximum bits per second the entire connection, divided up
/// between invidiual streams using default multipliers
public float Total
{
get { return Resend + Land + Wind + Cloud + Task + Texture + Asset; }
set
{
// Sane initial values
Resend = (value * 0.1f);
Land = (float)(value * 0.52f / 3f);
Wind = (float)(value * 0.05f);
Cloud = (float)(value * 0.05f);
Task = (float)(value * 0.704f / 3f);
Texture = (float)(value * 0.704f / 3f);
Asset = (float)(value * 0.484f / 3f);
}
}
private GridClient Client;
private float resend;
private float land;
private float wind;
private float cloud;
private float task;
private float texture;
private float asset;
///
/// Default constructor, uses a default high total of 1500 KBps (1536000)
///
public AgentThrottle(GridClient client)
{
Client = client;
Total = 1536000.0f;
}
///
/// Constructor that decodes an existing AgentThrottle packet in to
/// individual values
///
/// Reference to the throttle data in an AgentThrottle
/// packet
/// Offset position to start reading at in the
/// throttle data
/// This is generally not needed in clients as the server will
/// never send a throttle packet to the client
public AgentThrottle(byte[] data, int pos)
{
byte[] adjData;
if (!BitConverter.IsLittleEndian)
{
byte[] newData = new byte[7 * 4];
Buffer.BlockCopy(data, pos, newData, 0, 7 * 4);
for (int i = 0; i < 7; i++)
Array.Reverse(newData, i * 4, 4);
adjData = newData;
}
else
{
adjData = data;
}
Resend = BitConverter.ToSingle(adjData, pos); pos += 4;
Land = BitConverter.ToSingle(adjData, pos); pos += 4;
Wind = BitConverter.ToSingle(adjData, pos); pos += 4;
Cloud = BitConverter.ToSingle(adjData, pos); pos += 4;
Task = BitConverter.ToSingle(adjData, pos); pos += 4;
Texture = BitConverter.ToSingle(adjData, pos); pos += 4;
Asset = BitConverter.ToSingle(adjData, pos);
}
///
/// Send an AgentThrottle packet to the current server using the
/// current values
///
public void Set()
{
Set(Client.Network.CurrentSim);
}
///
/// Send an AgentThrottle packet to the specified server using the
/// current values
///
public void Set(Simulator simulator)
{
AgentThrottlePacket throttle = new AgentThrottlePacket();
throttle.AgentData.AgentID = Client.Self.AgentID;
throttle.AgentData.SessionID = Client.Self.SessionID;
throttle.AgentData.CircuitCode = Client.Network.CircuitCode;
throttle.Throttle.GenCounter = 0;
throttle.Throttle.Throttles = this.ToBytes();
Client.Network.SendPacket(throttle, simulator);
}
///
/// Convert the current throttle values to a byte array that can be put
/// in an AgentThrottle packet
///
/// Byte array containing all the throttle values
public byte[] ToBytes()
{
byte[] data = new byte[7 * 4];
int i = 0;
Buffer.BlockCopy(Utils.FloatToBytes(Resend), 0, data, i, 4); i += 4;
Buffer.BlockCopy(Utils.FloatToBytes(Land), 0, data, i, 4); i += 4;
Buffer.BlockCopy(Utils.FloatToBytes(Wind), 0, data, i, 4); i += 4;
Buffer.BlockCopy(Utils.FloatToBytes(Cloud), 0, data, i, 4); i += 4;
Buffer.BlockCopy(Utils.FloatToBytes(Task), 0, data, i, 4); i += 4;
Buffer.BlockCopy(Utils.FloatToBytes(Texture), 0, data, i, 4); i += 4;
Buffer.BlockCopy(Utils.FloatToBytes(Asset), 0, data, i, 4); i += 4;
return data;
}
}
}