2007-03-22 10:11:15 +00:00
/ *
Copyright ( c ) OpenSim project , http : //osgrid.org/
*
* 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 < organization > 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 < copyright holder > ` ` 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 < copyright holder > 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 ;
using System.Collections.Generic ;
using libsecondlife ;
using libsecondlife.Packets ;
using System.Net ;
using System.Net.Sockets ;
using System.IO ;
using System.Threading ;
using System.Timers ;
using OpenSim.Framework.Interfaces ;
using OpenSim.Framework.Assets ;
using OpenSim.Framework.Inventory ;
using OpenSim.Framework.Utilities ;
using OpenSim.world ;
using OpenSim.Assets ;
namespace OpenSim
{
2007-03-31 21:18:05 +00:00
public delegate bool PacketMethod ( SimClient simClient , Packet packet ) ;
2007-03-22 10:11:15 +00:00
/// <summary>
/// Handles new client connections
/// Constructor takes a single Packet and authenticates everything
/// </summary>
public class SimClient
{
public LLUUID AgentID ;
public LLUUID SessionID ;
public LLUUID SecureSessionID = LLUUID . Zero ;
public uint CircuitCode ;
public world . Avatar ClientAvatar ;
private UseCircuitCodePacket cirpack ;
private Thread ClientThread ;
public EndPoint userEP ;
private BlockingQueue < QueItem > PacketQueue ;
private Dictionary < uint , uint > PendingAcks = new Dictionary < uint , uint > ( ) ;
private Dictionary < uint , Packet > NeedAck = new Dictionary < uint , Packet > ( ) ;
//private Dictionary<LLUUID, AssetBase> UploadedAssets = new Dictionary<LLUUID, AssetBase>();
private System . Timers . Timer AckTimer ;
private uint Sequence = 0 ;
private object SequenceLock = new object ( ) ;
private const int MAX_APPENDED_ACKS = 10 ;
private const int RESEND_TIMEOUT = 4000 ;
private const int MAX_SEQUENCE = 0xFFFFFF ;
2007-03-25 17:34:58 +00:00
private AgentAssetUpload UploadAssets ;
2007-03-22 10:11:15 +00:00
private LLUUID newAssetFolder = LLUUID . Zero ;
2007-03-30 15:51:38 +00:00
private bool debug = false ;
2007-03-27 21:42:14 +00:00
private World m_world ;
private Dictionary < uint , SimClient > m_clientThreads ;
private AssetCache m_assetCache ;
private IGridServer m_gridServer ;
2007-03-28 18:10:52 +00:00
private IUserServer m_userServer = null ;
2007-03-28 13:08:27 +00:00
private OpenSimNetworkHandler m_application ;
2007-03-27 21:42:14 +00:00
private InventoryCache m_inventoryCache ;
private bool m_sandboxMode ;
2007-03-30 12:12:33 +00:00
private int cachedtextureserial = 0 ;
2007-03-22 10:11:15 +00:00
2007-03-31 21:18:05 +00:00
// local packet handler list not currently used but is here so each client could have a different handler for a packet to another client
// this is so we could do such things as have multiple world objects in a sim (or multiple "sims" handled by one server and different clients in different worlds
// maybe not a very practicle example but there are various other things it could be used for.
// protected Dictionary<string, PacketMethod> m_packetHandlers = new Dictionary<string, PacketMethod>();
protected static Dictionary < PacketType , PacketMethod > PacketHandlers = new Dictionary < PacketType , PacketMethod > ( ) ;
2007-03-28 18:10:52 +00:00
public IUserServer UserServer
{
set
{
this . m_userServer = value ;
}
}
2007-03-31 21:18:05 +00:00
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 ;
}
protected virtual bool ProcessPacketMethod ( Packet packet )
{
bool result = false ;
bool found = false ;
PacketMethod method ;
lock ( PacketHandlers )
{
found = PacketHandlers . TryGetValue ( packet . Type , out method ) ;
}
if ( found )
{
result = method ( this , packet ) ;
}
return result ;
}
2007-03-22 10:11:15 +00:00
private void ack_pack ( Packet Pack )
{
//libsecondlife.Packets.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.ID;
//ack_it.Header.Reliable = false;
//OutPacket(ack_it);
if ( Pack . Header . Reliable )
{
lock ( PendingAcks )
{
uint sequence = ( uint ) Pack . Header . Sequence ;
if ( ! PendingAcks . ContainsKey ( sequence ) ) { PendingAcks [ sequence ] = sequence ; }
}
}
}
protected virtual void ProcessInPacket ( Packet Pack )
{
ack_pack ( Pack ) ;
if ( debug )
{
if ( Pack . Type ! = PacketType . AgentUpdate )
{
Console . WriteLine ( Pack . Type . ToString ( ) ) ;
}
}
2007-03-31 21:18:05 +00:00
if ( this . ProcessPacketMethod ( Pack ) )
2007-03-22 10:11:15 +00:00
{
2007-03-31 21:18:05 +00:00
return ;
}
else
{
System . Text . Encoding _enc = System . Text . Encoding . ASCII ;
switch ( Pack . Type )
{
case PacketType . CompleteAgentMovement :
ClientAvatar . CompleteMovement ( m_world ) ;
ClientAvatar . SendInitialPosition ( ) ;
break ;
case PacketType . RegionHandshakeReply :
m_world . SendLayerData ( this ) ;
break ;
case PacketType . AgentWearablesRequest :
ClientAvatar . SendInitialAppearance ( ) ;
foreach ( SimClient client in m_clientThreads . Values )
2007-03-22 10:11:15 +00:00
{
2007-03-31 21:18:05 +00:00
if ( client . AgentID ! = this . AgentID )
{
ObjectUpdatePacket objupdate = client . ClientAvatar . CreateUpdatePacket ( ) ;
this . OutPacket ( objupdate ) ;
client . ClientAvatar . SendAppearanceToOtherAgent ( this ) ;
}
2007-03-22 10:11:15 +00:00
}
2007-03-31 21:18:05 +00:00
m_world . GetInitialPrims ( this ) ;
break ;
case PacketType . AgentIsNowWearing :
AgentIsNowWearingPacket wear = ( AgentIsNowWearingPacket ) Pack ;
//Console.WriteLine(Pack.ToString());
break ;
case PacketType . AgentSetAppearance :
AgentSetAppearancePacket appear = ( AgentSetAppearancePacket ) Pack ;
// Console.WriteLine(appear.ToString());
this . ClientAvatar . SetAppearance ( appear ) ;
break ;
case PacketType . AgentCachedTexture :
Console . WriteLine ( Pack . ToString ( ) ) ;
AgentCachedTexturePacket chechedtex = ( AgentCachedTexturePacket ) Pack ;
AgentCachedTextureResponsePacket cachedresp = new AgentCachedTextureResponsePacket ( ) ;
cachedresp . AgentData . AgentID = this . AgentID ;
cachedresp . AgentData . SessionID = this . SessionID ;
cachedresp . AgentData . SerialNum = this . cachedtextureserial ;
this . 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 ] ;
}
this . OutPacket ( cachedresp ) ;
break ;
case PacketType . ObjectAdd :
m_world . AddNewPrim ( ( ObjectAddPacket ) Pack , this ) ;
break ;
case PacketType . ObjectLink :
OpenSim . Framework . Console . MainConsole . Instance . WriteLine ( Pack . ToString ( ) ) ;
break ;
case PacketType . ObjectScale :
OpenSim . Framework . Console . MainConsole . Instance . WriteLine ( Pack . ToString ( ) ) ;
break ;
case PacketType . ObjectShape :
ObjectShapePacket shape = ( ObjectShapePacket ) Pack ;
for ( int i = 0 ; i < shape . ObjectData . Length ; i + + )
2007-03-22 10:11:15 +00:00
{
2007-03-31 21:18:05 +00:00
foreach ( Entity ent in m_world . Entities . Values )
2007-03-22 10:11:15 +00:00
{
2007-03-31 21:18:05 +00:00
if ( ent . localid = = shape . ObjectData [ i ] . ObjectLocalID )
{
( ( OpenSim . world . Primitive ) ent ) . UpdateShape ( shape . ObjectData [ i ] ) ;
}
2007-03-22 10:11:15 +00:00
}
}
2007-03-31 21:18:05 +00:00
break ;
case PacketType . MultipleObjectUpdate :
MultipleObjectUpdatePacket multipleupdate = ( MultipleObjectUpdatePacket ) Pack ;
2007-03-22 10:11:15 +00:00
2007-03-31 21:18:05 +00:00
for ( int i = 0 ; i < multipleupdate . ObjectData . Length ; i + + )
2007-03-22 10:11:15 +00:00
{
2007-03-31 21:18:05 +00:00
if ( multipleupdate . ObjectData [ i ] . Type = = 9 ) //change position
2007-03-22 10:11:15 +00:00
{
2007-03-31 21:18:05 +00:00
libsecondlife . LLVector3 pos = new LLVector3 ( multipleupdate . ObjectData [ i ] . Data , 0 ) ;
foreach ( Entity ent in m_world . Entities . Values )
2007-03-22 10:11:15 +00:00
{
2007-03-31 21:18:05 +00:00
if ( ent . localid = = multipleupdate . ObjectData [ i ] . ObjectLocalID )
{
( ( OpenSim . world . Primitive ) ent ) . UpdatePosition ( pos ) ;
2007-03-22 10:11:15 +00:00
2007-03-31 21:18:05 +00:00
}
2007-03-22 10:11:15 +00:00
}
2007-03-31 21:18:05 +00:00
//should update stored position of the prim
}
else if ( multipleupdate . ObjectData [ i ] . Type = = 10 ) //rotation
2007-03-22 10:11:15 +00:00
{
2007-03-31 21:18:05 +00:00
libsecondlife . LLQuaternion rot = new LLQuaternion ( multipleupdate . ObjectData [ i ] . Data , 0 , true ) ;
foreach ( Entity ent in m_world . Entities . Values )
2007-03-22 10:11:15 +00:00
{
2007-03-31 21:18:05 +00:00
if ( ent . localid = = multipleupdate . ObjectData [ i ] . ObjectLocalID )
{
ent . rotation = new Axiom . MathLib . Quaternion ( rot . W , rot . X , rot . Y , rot . Z ) ;
( ( OpenSim . world . Primitive ) ent ) . UpdateFlag = true ;
}
2007-03-22 10:11:15 +00:00
}
}
2007-03-31 21:18:05 +00:00
else if ( multipleupdate . ObjectData [ i ] . Type = = 13 ) //scale
{
libsecondlife . LLVector3 scale = new LLVector3 ( multipleupdate . ObjectData [ i ] . Data , 12 ) ;
foreach ( Entity ent in m_world . Entities . Values )
{
if ( ent . localid = = multipleupdate . ObjectData [ i ] . ObjectLocalID )
{
( ( OpenSim . world . Primitive ) ent ) . Scale = scale ;
}
}
}
}
break ;
case PacketType . RequestImage :
RequestImagePacket imageRequest = ( RequestImagePacket ) Pack ;
for ( int i = 0 ; i < imageRequest . RequestImage . Length ; i + + )
{
m_assetCache . AddTextureRequest ( this , imageRequest . RequestImage [ i ] . Image ) ;
2007-03-22 10:11:15 +00:00
}
2007-03-31 21:18:05 +00:00
break ;
case PacketType . TransferRequest :
//Console.WriteLine("OpenSimClient.cs:ProcessInPacket() - Got transfer request");
TransferRequestPacket transfer = ( TransferRequestPacket ) Pack ;
m_assetCache . AddAssetRequest ( this , transfer ) ;
break ;
case PacketType . AgentUpdate :
ClientAvatar . HandleUpdate ( ( AgentUpdatePacket ) Pack ) ;
break ;
case PacketType . LogoutRequest :
OpenSim . Framework . Console . MainConsole . Instance . WriteLine ( "OpenSimClient.cs:ProcessInPacket() - Got a logout request" ) ;
//send reply to let the client logout
LogoutReplyPacket logReply = new LogoutReplyPacket ( ) ;
logReply . AgentData . AgentID = this . AgentID ;
logReply . AgentData . SessionID = this . SessionID ;
logReply . InventoryData = new LogoutReplyPacket . InventoryDataBlock [ 1 ] ;
logReply . InventoryData [ 0 ] = new LogoutReplyPacket . InventoryDataBlock ( ) ;
logReply . InventoryData [ 0 ] . ItemID = LLUUID . Zero ;
OutPacket ( logReply ) ;
//tell all clients to kill our object
KillObjectPacket kill = new KillObjectPacket ( ) ;
kill . ObjectData = new KillObjectPacket . ObjectDataBlock [ 1 ] ;
kill . ObjectData [ 0 ] = new KillObjectPacket . ObjectDataBlock ( ) ;
kill . ObjectData [ 0 ] . ID = this . ClientAvatar . localid ;
foreach ( SimClient client in m_clientThreads . Values )
2007-03-22 10:11:15 +00:00
{
2007-03-31 21:18:05 +00:00
client . OutPacket ( kill ) ;
}
if ( this . m_userServer ! = null )
{
this . m_inventoryCache . ClientLeaving ( this . AgentID , this . m_userServer ) ;
}
else
{
this . m_inventoryCache . ClientLeaving ( this . AgentID , null ) ;
}
2007-03-22 10:11:15 +00:00
2007-03-31 21:18:05 +00:00
m_gridServer . LogoutSession ( this . SessionID , this . AgentID , this . CircuitCode ) ;
lock ( m_world . Entities )
{
m_world . Entities . Remove ( this . AgentID ) ;
}
//need to do other cleaning up here too
m_clientThreads . Remove ( this . CircuitCode ) ; //this.userEP);
m_application . RemoveClientCircuit ( this . CircuitCode ) ;
this . ClientThread . Abort ( ) ;
break ;
case PacketType . ChatFromViewer :
ChatFromViewerPacket inchatpack = ( ChatFromViewerPacket ) Pack ;
if ( Helpers . FieldToString ( inchatpack . ChatData . Message ) = = "" ) break ;
libsecondlife . Packets . ChatFromSimulatorPacket reply = new ChatFromSimulatorPacket ( ) ;
reply . ChatData . Audible = 1 ;
reply . ChatData . Message = inchatpack . ChatData . Message ;
reply . ChatData . ChatType = 1 ;
reply . ChatData . SourceType = 1 ;
reply . ChatData . Position = this . ClientAvatar . position ;
reply . ChatData . FromName = _enc . GetBytes ( this . ClientAvatar . firstname + " " + this . ClientAvatar . lastname + "\0" ) ;
reply . ChatData . OwnerID = this . AgentID ;
reply . ChatData . SourceID = this . AgentID ;
foreach ( SimClient client in m_clientThreads . Values )
{
client . OutPacket ( reply ) ;
}
break ;
case PacketType . ObjectImage :
ObjectImagePacket imagePack = ( ObjectImagePacket ) Pack ;
for ( int i = 0 ; i < imagePack . ObjectData . Length ; i + + )
{
2007-03-27 21:42:14 +00:00
foreach ( Entity ent in m_world . Entities . Values )
2007-03-22 10:11:15 +00:00
{
2007-03-31 21:18:05 +00:00
if ( ent . localid = = imagePack . ObjectData [ i ] . ObjectLocalID )
2007-03-22 10:11:15 +00:00
{
2007-03-31 21:18:05 +00:00
( ( OpenSim . world . Primitive ) ent ) . UpdateTexture ( imagePack . ObjectData [ i ] . TextureEntry ) ;
2007-03-22 10:11:15 +00:00
}
}
}
2007-03-31 21:18:05 +00:00
break ;
case PacketType . ObjectFlagUpdate :
ObjectFlagUpdatePacket flags = ( ObjectFlagUpdatePacket ) Pack ;
2007-03-27 21:42:14 +00:00
foreach ( Entity ent in m_world . Entities . Values )
2007-03-22 10:11:15 +00:00
{
2007-03-31 21:18:05 +00:00
if ( ent . localid = = flags . AgentData . ObjectLocalID )
2007-03-22 10:11:15 +00:00
{
2007-03-31 21:18:05 +00:00
( ( OpenSim . world . Primitive ) ent ) . UpdateObjectFlags ( flags ) ;
2007-03-22 10:11:15 +00:00
}
}
2007-03-31 21:18:05 +00:00
break ;
case PacketType . AssetUploadRequest :
//this.debug = true;
AssetUploadRequestPacket request = ( AssetUploadRequestPacket ) Pack ;
// Console.WriteLine(Pack.ToString());
// if (request.AssetBlock.Type == 0)
// {
2007-03-25 20:23:06 +00:00
//this.UploadAssets.HandleUploadPacket(request, LLUUID.Random());
2007-03-31 21:18:05 +00:00
//}
//else
//{
2007-03-25 17:34:58 +00:00
this . UploadAssets . HandleUploadPacket ( request , request . AssetBlock . TransactionID . Combine ( this . SecureSessionID ) ) ;
2007-03-31 21:18:05 +00:00
//}
break ;
case PacketType . SendXferPacket :
Console . WriteLine ( Pack . ToString ( ) ) ;
this . UploadAssets . HandleXferPacket ( ( SendXferPacketPacket ) Pack ) ;
break ;
case PacketType . CreateInventoryFolder :
CreateInventoryFolderPacket invFolder = ( CreateInventoryFolderPacket ) Pack ;
m_inventoryCache . CreateNewInventoryFolder ( this , invFolder . FolderData . FolderID , ( ushort ) invFolder . FolderData . Type , Helpers . FieldToString ( invFolder . FolderData . Name ) , invFolder . FolderData . ParentID ) ;
Console . WriteLine ( Pack . ToString ( ) ) ;
break ;
case PacketType . CreateInventoryItem :
Console . WriteLine ( Pack . ToString ( ) ) ;
CreateInventoryItemPacket createItem = ( CreateInventoryItemPacket ) Pack ;
if ( createItem . InventoryBlock . TransactionID ! = LLUUID . Zero )
2007-03-25 17:34:58 +00:00
{
2007-03-31 21:18:05 +00:00
this . UploadAssets . CreateInventoryItem ( createItem ) ;
}
else
{
Console . Write ( Pack . ToString ( ) ) ;
this . CreateInventoryItem ( createItem ) ;
}
break ;
case PacketType . FetchInventory :
//Console.WriteLine("fetch item packet");
FetchInventoryPacket FetchInventory = ( FetchInventoryPacket ) Pack ;
m_inventoryCache . FetchInventory ( this , FetchInventory ) ;
break ;
case PacketType . FetchInventoryDescendents :
FetchInventoryDescendentsPacket Fetch = ( FetchInventoryDescendentsPacket ) Pack ;
m_inventoryCache . FetchInventoryDescendents ( this , Fetch ) ;
break ;
case PacketType . UpdateInventoryItem :
UpdateInventoryItemPacket update = ( UpdateInventoryItemPacket ) Pack ;
//Console.WriteLine(Pack.ToString());
for ( int i = 0 ; i < update . InventoryData . Length ; i + + )
{
if ( update . InventoryData [ i ] . TransactionID ! = LLUUID . Zero )
2007-03-26 16:51:50 +00:00
{
2007-03-31 21:18:05 +00:00
AssetBase asset = m_assetCache . GetAsset ( update . InventoryData [ i ] . TransactionID . Combine ( this . SecureSessionID ) ) ;
2007-03-26 16:51:50 +00:00
if ( asset ! = null )
{
2007-03-31 21:18:05 +00:00
Console . WriteLine ( "updating inventory item, found asset" + asset . FullID . ToStringHyphenated ( ) + " already in cache" ) ;
2007-03-29 20:55:44 +00:00
m_inventoryCache . UpdateInventoryItemAsset ( this , update . InventoryData [ i ] . ItemID , asset ) ;
2007-03-26 16:51:50 +00:00
}
2007-03-29 17:04:24 +00:00
else
{
2007-03-31 21:18:05 +00:00
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" ) ;
}
2007-03-29 17:04:24 +00:00
}
2007-03-26 16:51:50 +00:00
}
2007-03-31 21:18:05 +00:00
else
{
m_inventoryCache . UpdateInventoryItemDetails ( this , update . InventoryData [ i ] . ItemID , update . InventoryData [ i ] ) ; ;
}
2007-03-25 17:34:58 +00:00
}
2007-03-31 21:18:05 +00:00
break ;
case PacketType . ViewerEffect :
ViewerEffectPacket viewer = ( ViewerEffectPacket ) Pack ;
foreach ( SimClient client in m_clientThreads . Values )
2007-03-29 20:55:44 +00:00
{
2007-03-31 21:18:05 +00:00
if ( client . AgentID ! = this . AgentID )
{
viewer . AgentData . AgentID = client . AgentID ;
viewer . AgentData . SessionID = client . SessionID ;
client . OutPacket ( viewer ) ;
}
2007-03-29 20:55:44 +00:00
}
2007-03-31 21:18:05 +00:00
break ;
case PacketType . DeRezObject :
//OpenSim.Framework.Console.MainConsole.Instance.WriteLine("Received DeRezObject packet");
m_world . DeRezObject ( ( DeRezObjectPacket ) Pack , this ) ;
break ;
case PacketType . RezObject :
//Console.WriteLine(Pack.ToString());
m_world . RezObject ( this , ( RezObjectPacket ) Pack ) ;
break ;
case PacketType . ModifyLand :
ModifyLandPacket modify = ( ModifyLandPacket ) Pack ;
//Console.WriteLine("terraform: number of parcel data blocks" + modify.ParcelData.Length);
switch ( modify . ModifyBlock . Action )
2007-03-25 17:34:58 +00:00
{
2007-03-31 21:18:05 +00:00
case 1 :
if ( modify . ParcelData . Length > 0 )
{
int mody = ( int ) modify . ParcelData [ 0 ] . North ;
int modx = ( int ) modify . ParcelData [ 0 ] . West ;
// Console.WriteLine("height in packet is " + modify.ModifyBlock.Height.ToString());
// Console.WriteLine("current height at that point is " + this.m_world.LandMap[(mody * 256) + modx].ToString());
this . m_world . LandMap [ ( mody * 256 ) + modx - 1 ] + = 0.05f ;
this . m_world . LandMap [ ( mody * 256 ) + modx ] + = 0.1f ;
this . m_world . LandMap [ ( mody * 256 ) + modx + 1 ] + = 0.05f ;
this . m_world . LandMap [ ( ( mody + 1 ) * 256 ) + modx ] + = 0.05f ;
this . m_world . LandMap [ ( ( mody - 1 ) * 256 ) + modx ] + = 0.05f ;
m_world . RegenerateTerrain ( true , modx , mody ) ;
}
break ;
case 2 :
if ( modify . ParcelData . Length > 0 )
{
int mody = ( int ) modify . ParcelData [ 0 ] . North ;
int modx = ( int ) modify . ParcelData [ 0 ] . West ;
// Console.WriteLine("height in packet is " + modify.ModifyBlock.Height.ToString());
// Console.WriteLine("current height at that point is " + this.m_world.LandMap[(mody * 256) + modx].ToString());
this . m_world . LandMap [ ( mody * 256 ) + modx - 1 ] - = 0.05f ;
this . m_world . LandMap [ ( mody * 256 ) + modx ] - = 0.1f ;
this . m_world . LandMap [ ( mody * 256 ) + modx + 1 ] - = 0.05f ;
this . m_world . LandMap [ ( ( mody + 1 ) * 256 ) + modx ] - = 0.05f ;
this . m_world . LandMap [ ( ( mody - 1 ) * 256 ) + modx ] - = 0.05f ;
m_world . RegenerateTerrain ( true , modx , mody ) ;
}
break ;
2007-03-25 17:34:58 +00:00
}
2007-03-31 21:18:05 +00:00
break ;
case PacketType . RequestTaskInventory :
// Console.WriteLine(Pack.ToString());
RequestTaskInventoryPacket requesttask = ( RequestTaskInventoryPacket ) Pack ;
ReplyTaskInventoryPacket replytask = new ReplyTaskInventoryPacket ( ) ;
bool foundent = false ;
foreach ( Entity ent in m_world . Entities . Values )
{
if ( ent . localid = = requesttask . InventoryData . LocalID )
2007-03-30 16:50:19 +00:00
{
2007-03-31 21:18:05 +00:00
replytask . InventoryData . TaskID = ent . uuid ;
replytask . InventoryData . Serial = 0 ;
replytask . InventoryData . Filename = new byte [ 0 ] ;
foundent = true ;
2007-03-30 16:50:19 +00:00
}
2007-03-31 21:18:05 +00:00
}
if ( foundent )
2007-03-31 15:54:16 +00:00
{
2007-03-31 21:18:05 +00:00
this . OutPacket ( replytask ) ;
2007-03-31 15:54:16 +00:00
}
2007-03-31 21:18:05 +00:00
break ;
case PacketType . UUIDNameRequest :
//System.Text.Encoding _enc = System.Text.Encoding.ASCII;
Console . WriteLine ( Pack . ToString ( ) ) ;
UUIDNameRequestPacket nameRequest = ( UUIDNameRequestPacket ) Pack ;
UUIDNameReplyPacket nameReply = new UUIDNameReplyPacket ( ) ;
nameReply . UUIDNameBlock = new UUIDNameReplyPacket . UUIDNameBlockBlock [ nameRequest . UUIDNameBlock . Length ] ;
for ( int i = 0 ; i < nameRequest . UUIDNameBlock . Length ; i + + )
2007-03-31 15:54:16 +00:00
{
2007-03-31 21:18:05 +00:00
nameReply . UUIDNameBlock [ i ] = new UUIDNameReplyPacket . UUIDNameBlockBlock ( ) ;
nameReply . UUIDNameBlock [ i ] . ID = nameRequest . UUIDNameBlock [ i ] . ID ;
nameReply . UUIDNameBlock [ i ] . FirstName = _enc . GetBytes ( "Who\0" ) ; //for now send any name
nameReply . UUIDNameBlock [ i ] . LastName = _enc . GetBytes ( "Knows\0" ) ; //in future need to look it up
}
this . OutPacket ( nameReply ) ;
break ;
case PacketType . AgentAnimation :
//Console.WriteLine(Pack.ToString());
break ;
case PacketType . ObjectSelect :
ObjectSelectPacket incomingselect = ( ObjectSelectPacket ) Pack ;
for ( int i = 0 ; i < incomingselect . ObjectData . Length ; i + + )
{
foreach ( Entity ent in m_world . Entities . Values )
2007-03-31 15:54:16 +00:00
{
2007-03-31 21:18:05 +00:00
if ( ent . localid = = incomingselect . ObjectData [ i ] . ObjectLocalID )
{
( ( OpenSim . world . Primitive ) ent ) . GetProperites ( this ) ;
break ;
}
2007-03-31 15:54:16 +00:00
}
}
2007-03-31 21:18:05 +00:00
break ;
}
2007-03-22 10:11:15 +00:00
}
}
private void ResendUnacked ( )
{
int now = Environment . TickCount ;
lock ( NeedAck )
{
foreach ( Packet packet in NeedAck . Values )
{
if ( ( now - packet . TickCount > RESEND_TIMEOUT ) & & ( ! packet . Header . Resent ) )
{
OpenSim . Framework . Console . MainConsole . Instance . WriteLine ( "Resending " + packet . Type . ToString ( ) + " packet, " +
( now - packet . TickCount ) + "ms have passed" ) ;
packet . Header . Resent = true ;
OutPacket ( packet ) ;
}
}
}
}
private 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
OpenSim . Framework . Console . MainConsole . Instance . WriteLine ( "Too many ACKs queued up!" ) ;
return ;
}
OpenSim . Framework . Console . MainConsole . Instance . WriteLine ( "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 ) ;
PendingAcks . Clear ( ) ;
}
}
}
private void AckTimer_Elapsed ( object sender , ElapsedEventArgs ea )
{
SendAcks ( ) ;
ResendUnacked ( ) ;
}
protected virtual void ProcessOutPacket ( Packet Pack )
{
// Keep track of when this packet was sent out
Pack . TickCount = Environment . TickCount ;
if ( ! Pack . Header . Resent )
{
// Set the sequence number
lock ( SequenceLock )
{
if ( Sequence > = MAX_SEQUENCE )
Sequence = 1 ;
else
Sequence + + ;
Pack . Header . Sequence = Sequence ;
}
if ( Pack . Header . Reliable ) //DIRTY HACK
{
lock ( NeedAck )
{
if ( ! NeedAck . ContainsKey ( Pack . Header . Sequence ) )
{
NeedAck . Add ( Pack . Header . Sequence , Pack ) ;
}
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);
}
}
// Don't append ACKs to resent packets, in case that's what was causing the
// delivery to fail
if ( ! Pack . Header . Resent )
{
// Append any ACKs that need to be sent out to this packet
lock ( PendingAcks )
{
if ( PendingAcks . Count > 0 & & PendingAcks . Count < MAX_APPENDED_ACKS & &
Pack . Type ! = PacketType . PacketAck & &
Pack . Type ! = PacketType . LogoutRequest )
{
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 ;
}
}
}
}
}
2007-03-27 08:10:15 +00:00
//MainConsole.Instance.WriteLine("OUT: \n" + Pack.ToString());
2007-03-22 10:11:15 +00:00
byte [ ] ZeroOutBuffer = new byte [ 4096 ] ;
byte [ ] sendbuffer ;
sendbuffer = Pack . ToBytes ( ) ;
try
{
if ( Pack . Header . Zerocoded )
{
int packetsize = Helpers . ZeroEncode ( sendbuffer , sendbuffer . Length , ZeroOutBuffer ) ;
2007-03-27 21:42:14 +00:00
m_application . SendPacketTo ( ZeroOutBuffer , packetsize , SocketFlags . None , CircuitCode ) ; //userEP);
2007-03-22 10:11:15 +00:00
}
else
{
2007-03-27 21:42:14 +00:00
m_application . SendPacketTo ( sendbuffer , sendbuffer . Length , SocketFlags . None , CircuitCode ) ; //userEP);
2007-03-22 10:11:15 +00:00
}
}
catch ( Exception )
{
OpenSim . Framework . Console . MainConsole . Instance . WriteLine ( "OpenSimClient.cs:ProcessOutPacket() - WARNING: Socket exception occurred on connection " + userEP . ToString ( ) + " - killing thread" ) ;
ClientThread . Abort ( ) ;
}
}
2007-03-31 21:18:05 +00:00
public virtual void InPacket ( Packet NewPack )
2007-03-22 10:11:15 +00:00
{
// 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
libsecondlife . Packets . StartPingCheckPacket startPing = ( libsecondlife . Packets . StartPingCheckPacket ) NewPack ;
libsecondlife . Packets . CompletePingCheckPacket endPing = new CompletePingCheckPacket ( ) ;
endPing . PingID . PingID = startPing . PingID . PingID ;
OutPacket ( endPing ) ;
}
else
{
QueItem item = new QueItem ( ) ;
item . Packet = NewPack ;
item . Incoming = true ;
this . PacketQueue . Enqueue ( item ) ;
}
}
public virtual void OutPacket ( Packet NewPack )
{
QueItem item = new QueItem ( ) ;
item . Packet = NewPack ;
item . Incoming = false ;
this . PacketQueue . Enqueue ( item ) ;
}
2007-03-28 13:08:27 +00:00
public SimClient ( EndPoint remoteEP , UseCircuitCodePacket initialcirpack , World world , Dictionary < uint , SimClient > clientThreads , AssetCache assetCache , IGridServer gridServer , OpenSimNetworkHandler application , InventoryCache inventoryCache , bool sandboxMode )
2007-03-22 10:11:15 +00:00
{
2007-03-27 21:42:14 +00:00
m_world = world ;
m_clientThreads = clientThreads ;
m_assetCache = assetCache ;
m_gridServer = gridServer ;
m_application = application ;
m_inventoryCache = inventoryCache ;
m_sandboxMode = sandboxMode ;
2007-03-31 21:18:05 +00:00
2007-03-22 10:11:15 +00:00
OpenSim . Framework . Console . MainConsole . Instance . WriteLine ( "OpenSimClient.cs - Started up new client thread to handle incoming request" ) ;
cirpack = initialcirpack ;
userEP = remoteEP ;
PacketQueue = new BlockingQueue < QueItem > ( ) ;
2007-03-25 17:34:58 +00:00
2007-03-31 21:18:05 +00:00
this . UploadAssets = new AgentAssetUpload ( this , m_assetCache , m_inventoryCache ) ;
2007-03-22 10:11:15 +00:00
AckTimer = new System . Timers . Timer ( 500 ) ;
AckTimer . Elapsed + = new ElapsedEventHandler ( AckTimer_Elapsed ) ;
AckTimer . Start ( ) ;
ClientThread = new Thread ( new ThreadStart ( AuthUser ) ) ;
ClientThread . IsBackground = true ;
ClientThread . Start ( ) ;
}
protected virtual void ClientLoop ( )
{
OpenSim . Framework . Console . MainConsole . Instance . WriteLine ( "OpenSimClient.cs:ClientLoop() - Entered loop" ) ;
while ( true )
{
QueItem nextPacket = PacketQueue . Dequeue ( ) ;
if ( nextPacket . Incoming )
{
//is a incoming packet
ProcessInPacket ( nextPacket . Packet ) ;
}
else
{
//is a out going packet
ProcessOutPacket ( nextPacket . Packet ) ;
}
}
}
protected virtual void InitNewClient ( )
{
OpenSim . Framework . Console . MainConsole . Instance . WriteLine ( "OpenSimClient.cs:InitNewClient() - Adding viewer agent to world" ) ;
2007-03-31 21:18:05 +00:00
2007-03-27 21:42:14 +00:00
m_world . AddViewerAgent ( this ) ;
world . Entity tempent = m_world . Entities [ this . AgentID ] ;
2007-03-31 21:18:05 +00:00
2007-03-22 10:11:15 +00:00
this . ClientAvatar = ( world . Avatar ) tempent ;
}
protected virtual void AuthUser ( )
{
2007-03-27 21:42:14 +00:00
AuthenticateResponse sessionInfo = m_gridServer . AuthenticateSession ( cirpack . CircuitCode . SessionID , cirpack . CircuitCode . ID , cirpack . CircuitCode . Code ) ;
2007-03-22 10:11:15 +00:00
if ( ! sessionInfo . Authorised )
{
//session/circuit not authorised
OpenSim . Framework . Console . MainConsole . Instance . WriteLine ( "OpenSimClient.cs:AuthUser() - New user request denied to " + userEP . ToString ( ) ) ;
ClientThread . Abort ( ) ;
}
else
{
OpenSim . Framework . Console . MainConsole . Instance . WriteLine ( "OpenSimClient.cs:AuthUser() - Got authenticated connection from " + userEP . ToString ( ) ) ;
//session is authorised
this . AgentID = cirpack . CircuitCode . ID ;
this . SessionID = cirpack . CircuitCode . SessionID ;
this . CircuitCode = cirpack . CircuitCode . Code ;
InitNewClient ( ) ; //shouldn't be called here as we might be a child agent and not want a full avatar
this . ClientAvatar . firstname = sessionInfo . LoginInfo . First ;
this . ClientAvatar . lastname = sessionInfo . LoginInfo . Last ;
if ( sessionInfo . LoginInfo . SecureSession ! = LLUUID . Zero )
{
this . SecureSessionID = sessionInfo . LoginInfo . SecureSession ;
}
// Create Inventory, currently only works for sandbox mode
2007-03-27 21:42:14 +00:00
if ( m_sandboxMode )
2007-03-22 10:11:15 +00:00
{
2007-03-28 18:10:52 +00:00
AgentInventory inventory = null ;
2007-03-22 10:11:15 +00:00
if ( sessionInfo . LoginInfo . InventoryFolder ! = null )
{
2007-03-28 18:10:52 +00:00
inventory = this . CreateInventory ( sessionInfo . LoginInfo . InventoryFolder ) ;
2007-03-22 10:11:15 +00:00
if ( sessionInfo . LoginInfo . BaseFolder ! = null )
{
2007-03-28 18:10:52 +00:00
if ( ! inventory . HasFolder ( sessionInfo . LoginInfo . BaseFolder ) )
{
m_inventoryCache . CreateNewInventoryFolder ( this , sessionInfo . LoginInfo . BaseFolder ) ;
}
2007-03-22 10:11:15 +00:00
this . newAssetFolder = sessionInfo . LoginInfo . BaseFolder ;
2007-03-27 21:42:14 +00:00
AssetBase [ ] inventorySet = m_assetCache . CreateNewInventorySet ( this . AgentID ) ;
2007-03-22 10:11:15 +00:00
if ( inventorySet ! = null )
{
for ( int i = 0 ; i < inventorySet . Length ; i + + )
{
if ( inventorySet [ i ] ! = null )
{
2007-03-27 21:42:14 +00:00
m_inventoryCache . AddNewInventoryItem ( this , sessionInfo . LoginInfo . BaseFolder , inventorySet [ i ] ) ;
2007-03-22 10:11:15 +00:00
}
}
}
}
}
}
ClientLoop ( ) ;
}
}
2007-03-28 18:10:52 +00:00
private AgentInventory CreateInventory ( LLUUID baseFolder )
2007-03-22 10:11:15 +00:00
{
2007-03-28 18:10:52 +00:00
AgentInventory inventory = null ;
if ( this . m_userServer ! = null )
{
// a user server is set so request the inventory from it
2007-03-29 17:04:24 +00:00
Console . WriteLine ( "getting inventory from user server" ) ;
2007-03-28 18:10:52 +00:00
inventory = m_inventoryCache . FetchAgentsInventory ( this . AgentID , m_userServer ) ;
}
else
{
inventory = new AgentInventory ( ) ;
inventory . AgentID = this . AgentID ;
inventory . CreateRootFolder ( this . AgentID , false ) ;
m_inventoryCache . AddNewAgentsInventory ( inventory ) ;
m_inventoryCache . CreateNewInventoryFolder ( this , baseFolder ) ;
}
return inventory ;
2007-03-22 10:11:15 +00:00
}
2007-03-30 11:09:51 +00:00
private void CreateInventoryItem ( CreateInventoryItemPacket packet )
{
if ( packet . InventoryBlock . Type = = 7 )
{
//lets try this out with creating a notecard
AssetBase asset = new AssetBase ( ) ;
asset . Name = Helpers . FieldToString ( packet . InventoryBlock . Name ) ;
asset . Description = Helpers . FieldToString ( packet . InventoryBlock . Description ) ;
asset . InvType = packet . InventoryBlock . InvType ;
asset . Type = packet . InventoryBlock . Type ;
asset . FullID = LLUUID . Random ( ) ;
asset . Data = new byte [ 0 ] ;
2007-03-31 21:18:05 +00:00
2007-03-30 11:09:51 +00:00
m_assetCache . AddAsset ( asset ) ;
m_inventoryCache . AddNewInventoryItem ( this , packet . InventoryBlock . FolderID , asset ) ;
}
}
2007-03-22 10:11:15 +00:00
}
}