started using BerkeleyDB as local database

standalone
MW 2007-02-16 16:06:40 +00:00
parent b8822e4340
commit 4be3f7c49b
24 changed files with 1549 additions and 248 deletions

View File

@ -26,24 +26,173 @@
*/
using System;
using System.Collections.Generic;
using libsecondlife;
using libsecondlife.Packets;
namespace OpenSimLite
namespace OpenSim
{
/// <summary>
/// Manages Agent details.
/// </summary>
public class AgentManager
{
public AgentManager()
public Dictionary<libsecondlife.LLUUID,AgentProfile> AgentList;
private uint _localNumber=0;
private Server _server;
public AgentManager(Server server)
{
_server=server;
this.AgentList = new Dictionary<LLUUID, AgentProfile>();
}
public AgentName GetAgentName(LLUUID AgentID)
{
AgentName name = new AgentName();
AgentName name;
if(AgentList.ContainsKey(AgentID))
{
name=AgentList[AgentID].Name;
}
else
{
name = new AgentName();
}
return(name);
}
public AgentProfile GetAgent(LLUUID id)
{
if(!this.AgentList.ContainsKey(id))
{
return null;
}
else
{
AgentProfile avatar = this.AgentList[id];
return avatar;
}
}
/// <summary>
///
/// </summary>
/// <param name="agent"></param>
public void AddAgent(AgentProfile agent)
{
this.AgentList.Add(agent.Avatar.FullID, agent);
}
/// <summary>
///
/// </summary>
/// <param name="userInfo"></param>
/// <param name="first"></param>
/// <param name="last"></param>
/// <param name="baseFolder"></param>
/// <param name="inventoryFolder"></param>
/// <returns></returns>
public bool NewAgent(NetworkInfo userInfo, string first, string last, LLUUID baseFolder, LLUUID inventoryFolder)
{
Console.WriteLine("new agent called");
AgentProfile agent = new AgentProfile();
agent.Avatar.FullID = userInfo.User.AgentID;
agent.Avatar.NetInfo = userInfo;
agent.Avatar.NetInfo.User.FirstName =first;
agent.Avatar.NetInfo.User.LastName = last;
agent.Avatar.Position = new LLVector3(100, 100, 22);
agent.Avatar.BaseFolder = baseFolder;
agent.Avatar.InventoryFolder = inventoryFolder;
agent.Avatar.LocalID = 8880000 + this._localNumber;
this._localNumber++;
this.AgentList.Add(agent.Avatar.FullID, agent);
//Create new Wearable Assets and place in Inventory
//this.assetManager.CreateNewInventorySet(ref agent, userInfo);
return(true);
}
/// <summary>
///
/// </summary>
/// <param name="UserInfo"></param>
public void RemoveAgent(NetworkInfo userInfo)
{
this.AgentList.Remove(userInfo.User.AgentID);
//tell other clients to delete this avatar
}
/// <summary>
///
/// </summary>
/// <param name="userInfo"></param>
public void AgentJoin(NetworkInfo userInfo)
{
//inform client of join comlete
libsecondlife.Packets.AgentMovementCompletePacket mov = new AgentMovementCompletePacket();
mov.AgentData.SessionID = userInfo.User.SessionID;
mov.AgentData.AgentID = userInfo.User.AgentID;
mov.Data.RegionHandle = Globals.Instance.RegionHandle;
mov.Data.Timestamp = 1169838966;
mov.Data.Position = new LLVector3(100f, 100f, 22f);
mov.Data.LookAt = new LLVector3(0.99f, 0.042f, 0);
_server.SendPacket(mov, true, userInfo);
}
public void RequestWearables(NetworkInfo userInfo)
{
AgentProfile Agent = this.AgentList[userInfo.User.AgentID];
AgentWearablesUpdatePacket aw = new AgentWearablesUpdatePacket();
aw.AgentData.AgentID = userInfo.User.AgentID;
aw.AgentData.SerialNum = 0;
aw.AgentData.SessionID = userInfo.User.SessionID;
aw.WearableData = new AgentWearablesUpdatePacket.WearableDataBlock[13];
AgentWearablesUpdatePacket.WearableDataBlock awb = null;
awb = new AgentWearablesUpdatePacket.WearableDataBlock();
awb.WearableType = (byte)0;
awb.AssetID = Agent.Avatar.Wearables[0].AssetID;
awb.ItemID = Agent.Avatar.Wearables[0].ItemID;
aw.WearableData[0] = awb;
awb = new AgentWearablesUpdatePacket.WearableDataBlock();
awb.WearableType =(byte)1;
awb.AssetID = Agent.Avatar.Wearables[1].AssetID;
awb.ItemID = Agent.Avatar.Wearables[1].ItemID;
aw.WearableData[1] = awb;
for(int i=2; i<13; i++)
{
awb = new AgentWearablesUpdatePacket.WearableDataBlock();
awb.WearableType = (byte)i;
awb.AssetID = new LLUUID("00000000-0000-0000-0000-000000000000");
awb.ItemID = new LLUUID("00000000-0000-0000-0000-000000000000");
aw.WearableData[i] = awb;
}
_server.SendPacket(aw, true, userInfo);
}
public void SendPacketToAllExcept(Packet packet, LLUUID exceptAgent)
{
foreach (KeyValuePair<libsecondlife.LLUUID, AgentProfile> kp in this.AgentList)
{
if(kp.Value.Avatar.NetInfo.User.AgentID != exceptAgent)
{
_server.SendPacket(packet, true, kp.Value.Avatar.NetInfo);
}
}
}
public void SendPacketToALL(Packet packet)
{
foreach (KeyValuePair<libsecondlife.LLUUID, AgentProfile> kp in this.AgentList)
{
_server.SendPacket(packet, true, kp.Value.Avatar.NetInfo);
}
}
}
public struct AgentName
@ -54,9 +203,74 @@ namespace OpenSimLite
public class AgentProfile
{
public AgentName Name;
public AvatarData Avatar;
//public AgentInventory Inventory;
public AgentProfile()
{
Name = new AgentName();
Avatar = new AvatarData();
}
}
public class AvatarData : Node
{
public NetworkInfo NetInfo;
public LLUUID FullID;
public uint LocalID;
//public LLQuaternion Rotation;
public bool Walk = false;
public bool Started = false;
//public TextureEntry TextureEntry;
public AvatarWearable[] Wearables;
public LLUUID InventoryFolder;
public LLUUID BaseFolder;
public AvatarParams VisParams;
public List<libsecondlife.Packets.ObjectUpdatePacket.ObjectDataBlock> ObjectUpdateList;
public List<libsecondlife.Packets.ImprovedTerseObjectUpdatePacket.ObjectDataBlock> TerseUpdateList;
public AvatarData()
{
Wearables=new AvatarWearable[2]; //should be 13
for(int i = 0; i < 2; i++)
{
Wearables[i] = new AvatarWearable();
}
this.SceneType = 1; //Avatar type
this.ObjectUpdateList = new List<libsecondlife.Packets.ObjectUpdatePacket.ObjectDataBlock>();
this.TerseUpdateList = new List<libsecondlife.Packets.ImprovedTerseObjectUpdatePacket.ObjectDataBlock>();
VisParams = new AvatarParams();
}
}
public class AvatarWearable
{
public LLUUID AssetID;
public LLUUID ItemID;
public AvatarWearable()
{
}
}
public class AvatarParams
{
public byte[] Params;
public AvatarParams()
{
Params = new byte [ 218];
for(int i = 0; i < 218; i++)
{
Params[i] = 100;
}
}
}
}

View File

@ -8,11 +8,11 @@ using System.Runtime.InteropServices;
// change them to the information which is associated with the assembly
// you compile.
[assembly: AssemblyTitle("OpenSimLite")]
[assembly: AssemblyTitle("OpenSim")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("OpenSim project")]
[assembly: AssemblyProduct("OpenSimLite")]
[assembly: AssemblyProduct("OpenSim")]
[assembly: AssemblyCopyright("(c) OpenSim project")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

View File

@ -30,23 +30,33 @@ using System.Collections.Generic;
using libsecondlife;
using libsecondlife.Packets;
namespace OpenSimLite
namespace OpenSim
{
/// <summary>
/// Manages local cache of assets and their sending to viewers.
/// </summary>
public class AssetManager
public class AssetManager : IAssetReceived
{
public Dictionary<libsecondlife.LLUUID, AssetInfo> Assets;
public Dictionary<libsecondlife.LLUUID, TextureImage> Textures;
public List<AssetRequest> AssetRequests = new List<AssetRequest>(); //assets ready to be sent to viewers
public List<TextureRequest> TextureRequests = new List<TextureRequest>(); //textures ready to be sent
public List<AssetRequest> RequestedAssets = new List<AssetRequest>(); //Assets requested from the asset server
public List<TextureRequest> RequestedTextures = new List<TextureRequest>(); //Textures requested from the asset server
private AssetServer _assetServer;
private Server _server;
/// <summary>
///
/// </summary>
public AssetManager(AssetServer assetServer)
public AssetManager(Server server, AssetServer assetServer)
{
_assetServer=assetServer;
_server = server;
_assetServer = assetServer;
_assetServer.SetReceiver(this);
}
/// <summary>
@ -54,15 +64,8 @@ namespace OpenSimLite
/// </summary>
private void RunAssetManager()
{
}
/// <summary>
///
/// </summary>
private void ProcessAssetQueue()
{
this.ProcessAssetQueue();
this.ProcessTextureQueue();
}
/// <summary>
@ -70,9 +73,97 @@ namespace OpenSimLite
/// </summary>
private void ProcessTextureQueue()
{
if(this.TextureRequests.Count == 0)
{
//no requests waiting
return;
}
int num;
//should be running in its own thread but for now is called by timer
if(this.TextureRequests.Count < 5)
{
//lower than 5 so do all of them
num = this.TextureRequests.Count;
}
else
{
num=5;
}
TextureRequest req;
for(int i = 0; i < num; i++)
{
req=(TextureRequest)this.TextureRequests[i];
if(req.PacketCounter == 0)
{
//first time for this request so send imagedata packet
if(req.NumPackets == 1)
{
//only one packet so send whole file
ImageDataPacket im = new ImageDataPacket();
im.ImageID.Packets = 1;
im.ImageID.ID = req.ImageInfo.FullID;
im.ImageID.Size = (uint)req.ImageInfo.Data.Length;
im.ImageData.Data = req.ImageInfo.Data;
im.ImageID.Codec = 2;
_server.SendPacket(im, true, req.RequestUser);
req.PacketCounter++;
//req.ImageInfo.l= time;
//System.Console.WriteLine("sent texture: "+req.image_info.FullID);
}
else
{
//more than one packet so split file up
ImageDataPacket im = new ImageDataPacket();
im.ImageID.Packets = (ushort)req.NumPackets;
im.ImageID.ID = req.ImageInfo.FullID;
im.ImageID.Size = (uint)req.ImageInfo.Data.Length;
im.ImageData.Data = new byte[600];
Array.Copy(req.ImageInfo.Data, 0, im.ImageData.Data, 0, 600);
im.ImageID.Codec = 2;
_server.SendPacket(im, true, req.RequestUser);
req.PacketCounter++;
//req.ImageInfo.last_used = time;
//System.Console.WriteLine("sent first packet of texture:
}
}
else
{
//send imagepacket
//more than one packet so split file up
ImagePacketPacket im = new ImagePacketPacket();
im.ImageID.Packet = (ushort)req.PacketCounter;
im.ImageID.ID = req.ImageInfo.FullID;
int size = req.ImageInfo.Data.Length - 600 - 1000*(req.PacketCounter - 1);
if(size > 1000) size = 1000;
im.ImageData.Data = new byte[size];
Array.Copy(req.ImageInfo.Data, 600 + 1000*(req.PacketCounter - 1), im.ImageData.Data, 0, size);
_server.SendPacket(im, true, req.RequestUser);
req.PacketCounter++;
//req.ImageInfo.last_used = time;
//System.Console.WriteLine("sent a packet of texture: "+req.image_info.FullID);
}
}
//remove requests that have been completed
for(int i = 0; i < num; i++)
{
req=(TextureRequest)this.TextureRequests[i];
if(req.PacketCounter == req.NumPackets)
{
this.TextureRequests.Remove(req);
}
}
}
public void AssetReceived(AssetBase asset)
{
//check if it is a texture or not
//then add to the correct cache list
//then check for waiting requests for this asset/texture (in the Requested lists)
//and move those requests into the Requests list.
}
#region Assets
/// <summary>
///
@ -81,8 +172,32 @@ namespace OpenSimLite
/// <param name="transferRequest"></param>
public void AddAssetRequest(NetworkInfo userInfo, TransferRequestPacket transferRequest)
{
LLUUID RequestID = new LLUUID(transferRequest.TransferInfo.Params, 0);
LLUUID requestID = new LLUUID(transferRequest.TransferInfo.Params, 0);
//check to see if asset is in local cache, if not we need to request it from asset server.
if(!this.Assets.ContainsKey(requestID))
{
//not found asset
// so request from asset server
AssetRequest request = new AssetRequest();
request.RequestUser = userInfo;
request.RequestImage = requestID;
this.AssetRequests.Add(request);
this._assetServer.RequestAsset(requestID);
return;
}
//it is in our cache
AssetInfo info = this.Assets[requestID];
//work out how many packets it should be sent in
// and add to the AssetRequests list
}
/// <summary>
///
/// </summary>
private void ProcessAssetQueue()
{
}
#endregion
@ -96,39 +211,72 @@ namespace OpenSimLite
public void AddTextureRequest(NetworkInfo userInfo, LLUUID imageID)
{
//check to see if texture is in local cache, if not request from asset server
if(!this.Textures.ContainsKey(imageID))
{
/*not found image so send back image not in data base message
ImageNotInDatabasePacket im_not = new ImageNotInDatabasePacket();
im_not.ImageID.ID=imageID;
_server.SendPacket(im_not, true, userInfo);*/
//not is cache so request from asset server
TextureRequest request = new TextureRequest();
request.RequestUser = userInfo;
request.RequestImage = imageID;
this.TextureRequests.Add(request);
this._assetServer.RequestAsset(imageID);
return;
}
TextureImage imag = this.Textures[imageID];
TextureRequest req = new TextureRequest();
req.RequestUser = userInfo;
req.RequestImage = imageID;
req.ImageInfo = imag;
if(imag.Data.LongLength>600)
{
//over 600 bytes so split up file
req.NumPackets = 1 + (int)(imag.Data.Length-600+999)/1000;
}
else
{
req.NumPackets = 1;
}
this.TextureRequests.Add(req);
}
#endregion
}
public class AssetBase
public class AssetRequest
{
public byte[] Data;
public LLUUID FullID;
public sbyte Type;
public sbyte InvType;
public string Name;
public string Description;
public string Filename;
public NetworkInfo RequestUser;
public LLUUID RequestImage;
public AssetInfo asset_inf;
public long data_pointer = 0;
public int num_packets = 0;
public int packet_counter = 0;
//public bool AssetInCache;
//public int TimeRequested;
public AssetBase()
public AssetRequest()
{
}
}
//needed?
public class TextureImage
public class TextureRequest
{
public TextureImage()
{
}
}
public class AssetInfo
{
public AssetInfo()
public NetworkInfo RequestUser;
public LLUUID RequestImage;
public TextureImage ImageInfo;
public long DataPointer = 0;
public int NumPackets = 0;
public int PacketCounter = 0;
//public bool TextureInCache;
//public int TimeRequested;
public TextureRequest()
{
}

View File

@ -26,14 +26,20 @@
*/
using System;
using libsecondlife;
using BerkeleyDb;
using Kds.Serialization;
using Kds.Serialization.Buffer;
namespace OpenSimLite
namespace OpenSim
{
/// <summary>
/// Handles connection to Asset Server.
/// </summary>
public class AssetServer
public class AssetServer : IAssetServer
{
private IAssetReceived _receiver;
public AssetServer()
{
}
@ -46,5 +52,71 @@ namespace OpenSimLite
}
}
public void SetReceiver(IAssetReceived receiver)
{
this._receiver = receiver;
}
public void RequestAsset(LLUUID assetID)
{
AssetBase asset = null;
byte[] dataBuffer = new byte[4096];
byte[] keyBuffer = new byte[256];
int index;
DbEntry keyEntry;
DbEntry dataEntry;
dataEntry = DbEntry.InOut(dataBuffer, 0, 4096);
index = 0;
BerkeleyDatabases.Instance.dbs.Formatter.Serialize<string>(assetID.ToStringHyphenated(), keyBuffer, ref index);
byte[] co= new byte[44];
Array.Copy(keyBuffer,co,44);
keyEntry = DbEntry.InOut(co, 0, 44);
ReadStatus status = BerkeleyDatabases.Instance.dbs.AssetDb.Get(null, ref keyEntry, ref dataEntry, DbFile.ReadFlags.None);
if (status != ReadStatus.Success)
{
throw new ApplicationException("Read failed");
}
index = 0;
BerkeleyDatabases.Instance.dbs.Formatter.Deserialize<AssetBase>(ref asset, dataEntry.Buffer, ref index);
this._receiver.AssetReceived( asset);
}
public void UpdateAsset(AssetBase asset)
{
//can we use UploadNewAsset to update as well?
this.UploadNewAsset(asset);
}
public void UploadNewAsset(AssetBase asset)
{
byte[] dataBuffer = new byte[4096];
byte[] keyBuffer = new byte[256];
int index;
DbEntry keyEntry;
DbEntry dataEntry;
index = 0;
BerkeleyDatabases.Instance.dbs.Formatter.Serialize<string>(asset.FullID.ToStringHyphenated(), keyBuffer, ref index);
byte[] co= new byte[44];
Array.Copy(keyBuffer,co,44);
keyEntry = DbEntry.InOut(co, 0, 44);
index = 0;
BerkeleyDatabases.Instance.dbs.Formatter.Serialize<AssetBase>(asset, dataBuffer, ref index);
dataEntry = DbEntry.InOut(dataBuffer, 0, index);
WriteStatus status = BerkeleyDatabases.Instance.dbs.AssetDb.Put(null, ref keyEntry, ref dataEntry, DbFile.WriteFlags.None);
if (status != WriteStatus.Success)
throw new ApplicationException("Put failed");
}
}
public interface IAssetServer
{
void SetReceiver(IAssetReceived receiver);
void RequestAsset(LLUUID assetID);
void UpdateAsset(AssetBase asset);
void UploadNewAsset(AssetBase asset);
}
// could change to delegate
public interface IAssetReceived
{
void AssetReceived(AssetBase asset);
}
}

105
Assets.cs Normal file
View File

@ -0,0 +1,105 @@
/*
* Copyright (c) OpenSim project, http://sim.opensecondlife.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 libsecondlife;
namespace OpenSim
{
/// <summary>
/// Description of Assets.
/// </summary>
public class AssetBase
{
public byte[] Data;
public LLUUID FullID;
public sbyte Type;
public sbyte InvType;
public string Name;
public string Description;
public string Filename;
public AssetBase()
{
}
}
public class PrimAsset: AssetBase
{
public PrimData PrimData;
public PrimAsset()
{
this.PrimData = new PrimData();
}
}
public class PrimData
{
public LLUUID OwnerID;
public byte PCode;
public byte PathBegin;
public byte PathEnd;
public byte PathScaleX;
public byte PathScaleY;
public byte PathShearX;
public byte PathShearY;
public sbyte PathSkew;
public byte ProfileBegin;
public byte ProfileEnd;
public LLVector3 Scale;
public byte PathCurve;
public byte ProfileCurve;
public uint ParentID=0;
public byte ProfileHollow;
//public bool DataBaseStorage=false;
public PrimData()
{
}
}
//a hangover from the old code, so is it needed for future use?
public class TextureImage: AssetBase
{
public TextureImage()
{
}
}
//a hangover from the old code, so is it needed for future use?
public class AssetInfo :AssetBase
{
public AssetInfo()
{
}
}
}

205
BerkeleyDatabase.cs Normal file
View File

@ -0,0 +1,205 @@
/*
* Copyright (c) OpenSim project, http://sim.opensecondlife.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 libsecondlife;
using BerkeleyDb;
using System.IO;
using Kds.Serialization;
using Kds.Serialization.Buffer;
namespace OpenSim
{
/// <summary>
/// Description of BerkeleyDatabase.
/// </summary>
public class BerkeleyDatabases
{
public const string primDbName = "prim.db";
public const string assetDbName = "asset.db";
// will be initialized on first access to static field in a thread-safe way
private static readonly BerkeleyDatabases instance = new BerkeleyDatabases();
private FileStream errStream;
private string dbDir;
private DbBTree primDb;
private DbBTree assetDb;
// used for key gnerator call-backs, not thread-safe
private BEFormatter formatter;
private byte[] keyBuffer = new byte[2048];
private BerkeleyDatabases() {
formatter = new BEFormatter();
formatter.RegisterField<PrimAsset>(new PrimAssetField(formatter));
formatter.RegisterField<AssetBase>(new AssetBaseField(formatter));
}
~BerkeleyDatabases()
{
this.Close();
}
public BerkeleyDatabases dbs;
// singleton
public static BerkeleyDatabases Instance {
get { return instance; }
}
public void Open(string dbDir, string appName, Stream errStream) {
this.dbDir = dbDir;
//Remove();
// open local prim database
Db db = new Db(DbCreateFlags.None);
db.ErrorPrefix = appName;
db.ErrorStream = errStream;
primDb = (DbBTree)db.Open(null, PrimDbName, null, DbType.BTree, Db.OpenFlags.Create, 0);
//open asset server database
db = new Db(DbCreateFlags.None);
db.ErrorPrefix = appName;
db.ErrorStream = errStream;
assetDb = (DbBTree)db.Open(null, AssetDbName, null, DbType.BTree, Db.OpenFlags.Create, 0);
}
public void Remove() {
try {
Db db = new Db(DbCreateFlags.None);
db.Remove(PrimDbName, null);
}
catch { }
try {
Db db = new Db(DbCreateFlags.None);
db.Remove(AssetDbName, null);
}
catch { }
}
public void Close() {
if (primDb != null) {
primDb.GetDb().Close();
primDb = null;
}
if (assetDb != null) {
assetDb.GetDb().Close();
assetDb = null;
}
}
public BEFormatter Formatter {
get { return formatter; }
}
public string PrimDbName {
get { return Path.Combine(dbDir, primDbName); }
}
public DbBTree PrimDb {
get { return primDb; }
}
public string AssetDbName {
get { return Path.Combine(dbDir, assetDbName); }
}
public DbBTree AssetDb {
get { return assetDb; }
}
public void Startup()
{
dbs = BerkeleyDatabases.Instance;
string dbPath = Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "Db");
string appName = Path.GetFileName(System.Reflection.Assembly.GetExecutingAssembly().CodeBase);
errStream = File.Open(Path.Combine(dbPath, "errors.txt"), FileMode.OpenOrCreate, FileAccess.Write);
dbs.Open(dbPath, appName, errStream);
}
}
public class PrimAssetField: ReferenceField<PrimAsset>
{
public PrimAssetField(Formatter formatter) : base(formatter) { }
protected override void SerializeValue(PrimAsset value) {
Formatter.Serialize<string>(value.Name);
Formatter.Serialize<string>(value.Description);
}
protected override void DeserializeInstance(ref PrimAsset instance) {
if (instance == null)
instance = new PrimAsset();
}
protected override void DeserializeMembers(PrimAsset instance) {
Formatter.Deserialize<string>(ref instance.Name);
Formatter.Deserialize<string>(ref instance.Description);
}
protected override void SkipValue() {
if (Formatter.Skip<string>())
Formatter.Skip<string>();
}
}
public class AssetBaseField: ReferenceField<AssetBase>
{
public AssetBaseField(Formatter formatter) : base(formatter) { }
protected override void SerializeValue(AssetBase value) {
Formatter.Serialize<string>(value.Name);
Formatter.Serialize<string>(value.Description);
}
protected override void DeserializeInstance(ref AssetBase instance) {
if (instance == null)
instance = new AssetBase();
}
protected override void DeserializeMembers(AssetBase instance) {
Formatter.Deserialize<string>(ref instance.Name);
Formatter.Deserialize<string>(ref instance.Description);
}
protected override void SkipValue() {
if (Formatter.Skip<string>())
Formatter.Skip<string>();
}
}
}

View File

@ -31,7 +31,7 @@ using System.Threading;
using libsecondlife;
using libsecondlife.Packets;
namespace OpenSimLite
namespace OpenSim
{
/// <summary>
/// Hanldes a single clients connection. Runs in own thread.
@ -40,6 +40,9 @@ namespace OpenSimLite
{
public static GridManager Grid;
public static SceneGraph Scene;
public static AgentManager AgentManager;
public static PrimManager PrimManager;
public byte ConnectionType=1;
private Thread _mthread;
@ -50,6 +53,7 @@ namespace OpenSimLite
public override void Start()
{
_mthread = new Thread(new ThreadStart(RunClientRead));
_mthread.IsBackground = true;
_mthread.Start();
}
@ -64,16 +68,45 @@ namespace OpenSimLite
switch(packet.Type)
{
case PacketType.UseCircuitCode:
//should be a new user joining
Console.WriteLine("new agent");
Console.WriteLine("new circuit");
//should be a new user/circuit joining
// add agents profile to agentmanager
string first = "",last ="";
LLUUID baseFolder = null, inventoryFolder =null;
//rather than use IncomingLogins list, the logon object could be passed to this connection on creation
lock(Globals.Instance.IncomingLogins)
{
for(int i = 0; i < Globals.Instance.IncomingLogins.Count; i++)
{
if(Globals.Instance.IncomingLogins[i].Agent == this.NetInfo.User.AgentID)
{
first = Globals.Instance.IncomingLogins[i].First;
last = Globals.Instance.IncomingLogins[i].Last;
baseFolder = Globals.Instance.IncomingLogins[i].BaseFolder;
inventoryFolder = Globals.Instance.IncomingLogins[i].InventoryFolder;
Globals.Instance.IncomingLogins.RemoveAt(i);
break;
}
}
}
if(first != "")
{
AgentManager.NewAgent(this.NetInfo, first, last, baseFolder, inventoryFolder);
}
break;
case PacketType.CompleteAgentMovement:
//Agent completing movement to region
// so send region handshake
Grid.SendRegionData(this.NetInfo);
// send movmentcomplete reply
Scene.AgentCompletingMove(this.NetInfo);
break;
case PacketType.RegionHandshakeReply:
Console.WriteLine("RegionHandshake reply");
Scene.SendTerrainData(this.NetInfo);
Scene.AddNewAvatar(AgentManager.GetAgent(this.NetInfo.User.AgentID).Avatar);
// send current avatars and prims data
break;
default:
break;
@ -82,7 +115,7 @@ namespace OpenSimLite
}
catch (Exception e)
{
Console.WriteLine(e.Message);
Console.WriteLine(e.Message + ", So die!");
}
}
}
@ -101,67 +134,5 @@ namespace OpenSimLite
{
}
}
public class BlockingQueue< T >
{
private Queue< T > _queue = new Queue< T >();
private object _queueSync = new object();
public void Enqueue(T value)
{
lock(_queueSync)
{
_queue.Enqueue(value);
Monitor.Pulse(_queueSync);
}
}
public T Dequeue()
{
lock(_queueSync)
{
if( _queue.Count < 1)
Monitor.Wait(_queueSync);
return _queue.Dequeue();
}
}
}
public class NonBlockingQueue< T >
{
private Queue< T > _queue = new Queue< T >();
private object _queueSync = new object();
public void Enqueue(T value)
{
lock(_queueSync)
{
_queue.Enqueue(value);
}
}
public T Dequeue()
{
T rValue = default(T);
lock(_queueSync)
{
if( _queue.Count > 0)
{
rValue = _queue.Dequeue();
}
}
return rValue;
}
public int Count
{
get
{
return(_queue.Count);
}
}
}
}
}

View File

@ -31,7 +31,7 @@ using System.Collections.Generic;
using libsecondlife;
using libsecondlife.Packets;
namespace OpenSimLite
namespace OpenSim
{
class Controller
{
@ -40,29 +40,47 @@ namespace OpenSimLite
private LoginServer _loginServer;
private GridManager _gridManager;
private AgentManager _agentManager;
private AssetManager _assetManager;
private SceneGraph _scene;
private PrimManager _primManager;
public static void Main(string[] args)
{
Controller c = new Controller();
while( true )
System.Threading.Thread.Sleep( 1000 );
bool Run=true;
while( Run )
{
string input = Console.ReadLine();
if(input == "Exit")
{
Run = false;
}
}
BerkeleyDatabases.Instance.Close();
}
public Controller()
{
_viewerServer = new Server();
_backboneServers = new BackboneServers();
_agentManager = new AgentManager();
_viewerServer = new Server(_backboneServers.UserServer);
_agentManager = new AgentManager(_viewerServer);
_gridManager = new GridManager(_viewerServer, _agentManager);
_scene = new SceneGraph(_viewerServer);
_scene = new SceneGraph(_viewerServer, _agentManager);
_assetManager = new AssetManager(_viewerServer, _backboneServers.AssetServer);
ClientConnection.Grid = _gridManager;
ClientConnection.Scene = _scene;
ClientConnection.AgentManager = _agentManager;
_viewerServer.Startup();
BerkeleyDatabases.Instance.Startup();
_primManager = new PrimManager();
if(Globals.Instance.StartLoginServer)
{
_loginServer = new LoginServer();
_loginServer = new LoginServer(_backboneServers.UserServer);
_loginServer.Startup();
}

View File

@ -29,7 +29,7 @@ using System;
using System.Collections.Generic;
using libsecondlife;
namespace OpenSimLite
namespace OpenSim
{
/// <summary>
/// Description of Globals.

View File

@ -32,7 +32,7 @@ using libsecondlife;
using libsecondlife.Packets;
using System.Collections.Generic;
namespace OpenSimLite
namespace OpenSim
{
/// <summary>
@ -213,7 +213,7 @@ namespace OpenSimLite
}
/// <summary>
///
/// most of this should be moved into the grid server class
/// </summary>
private void LoadGrid()
{

View File

@ -26,17 +26,33 @@
*/
using System;
using libsecondlife;
namespace OpenSimLite
namespace OpenSim
{
/// <summary>
/// Handles connection to Grid Servers.
/// also Sim to Sim connections?
/// </summary>
public class GridServer
public class GridServer //:IGridServer
{
public GridServer()
{
}
}
public interface IGridServer
{
bool RequestConnection(RegionInfo myRegion);
UUIDBlock RequestUUIDBlock();
RegionInfo[] RequestNeighbours();
}
public struct UUIDBlock
{
public LLUUID BlockStart;
public LLUUID BlockEnd;
}
}

View File

@ -27,7 +27,7 @@
using System;
namespace OpenSimLite
namespace OpenSim
{
/// <summary>
/// Description of InstantMessaging.

View File

@ -29,7 +29,7 @@ using System;
using System.Collections.Generic;
using libsecondlife;
namespace OpenSimLite
namespace OpenSim
{
/// <summary>
/// Local cache of Inventories

46
LocalAssetCache.cs Normal file
View File

@ -0,0 +1,46 @@
/*
* Copyright (c) OpenSim project, http://sim.opensecondlife.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;
namespace OpenSim
{
/// <summary>
/// Description of LocalAssetCache.
/// </summary>
public class LocalAssetCache
{
public LocalAssetCache()
{
}
}
public interface ILocalCacheStorage
{
void SaveAsset(AssetBase asset);
}
}

132
LocalStorageBase.cs Normal file
View File

@ -0,0 +1,132 @@
/*
* Copyright (c) OpenSim project, http://sim.opensecondlife.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 BerkeleyDb;
using Kds.Serialization;
using Kds.Serialization.Buffer;
using libsecondlife;
namespace OpenSim
{
/// <summary>
/// Description of LocalPrimDB.
/// </summary>
///
public class LocalPrimDb :ILocalPrimStorage
{
public LocalPrimDb()
{
}
public void LoadScene(IPrimReceiver receiver)
{
}
public void CreateNewPrimStorage(PrimAsset prim)
{
byte[] dataBuffer = new byte[4096];
byte[] keyBuffer = new byte[256];
int index;
DbEntry keyEntry;
DbEntry dataEntry;
index = 0;
BerkeleyDatabases.Instance.dbs.Formatter.Serialize<string>(prim.FullID.ToStringHyphenated(), keyBuffer, ref index);
byte[] co= new byte[44];
Array.Copy(keyBuffer,co,44);
keyEntry = DbEntry.InOut(co, 0, 44);
index = 0;
BerkeleyDatabases.Instance.dbs.Formatter.Serialize<PrimAsset>(prim, dataBuffer, ref index);
dataEntry = DbEntry.InOut(dataBuffer, 0, index);
WriteStatus status = BerkeleyDatabases.Instance.dbs.PrimDb.Put(null, ref keyEntry, ref dataEntry, DbFile.WriteFlags.None);
if (status != WriteStatus.Success)
throw new ApplicationException("Put failed");
}
public void UpdatePrimStorage(PrimAsset prim)
{
//can we just use CreateNewPrimStorage to update a prim?
this.CreateNewPrimStorage(prim);
}
public void RemovePrimStorage()
{
}
public PrimAsset GetPrimFromStroage(LLUUID primID)
{
PrimAsset prim = null;
byte[] dataBuffer = new byte[4096];
byte[] keyBuffer = new byte[256];
int index;
DbEntry keyEntry;
DbEntry dataEntry;
dataEntry = DbEntry.InOut(dataBuffer, 0, 4096);
index = 0;
BerkeleyDatabases.Instance.dbs.Formatter.Serialize<string>(primID.ToStringHyphenated(), keyBuffer, ref index);
byte[] co= new byte[44];
Array.Copy(keyBuffer,co,44);
keyEntry = DbEntry.InOut(co, 0, 44);
ReadStatus status = BerkeleyDatabases.Instance.dbs.PrimDb.Get(null, ref keyEntry, ref dataEntry, DbFile.ReadFlags.None);
if (status != ReadStatus.Success)
{
throw new ApplicationException("Read failed");
}
index = 0;
BerkeleyDatabases.Instance.dbs.Formatter.Deserialize<PrimAsset>(ref prim, dataEntry.Buffer, ref index);
return prim;
}
/// <summary>
/// test function
/// </summary>
public void ReadWholedatabase()
{
foreach (KeyDataPair entry in BerkeleyDatabases.Instance.dbs.PrimDb.OpenCursor(null, DbFileCursor.CreateFlags.None)) {
PrimAsset vendor = null;
int index = entry.Data.Start;
BerkeleyDatabases.Instance.dbs.Formatter.Deserialize<PrimAsset>(ref vendor, entry.Data.Buffer, ref index);
Console.WriteLine("prim found: "+vendor.Name + " "+ vendor.Description);
}
}
}
public interface ILocalPrimStorage
{
void LoadScene(IPrimReceiver receiver);
void CreateNewPrimStorage(PrimAsset prim);
void UpdatePrimStorage(PrimAsset prim);
void RemovePrimStorage();
PrimAsset GetPrimFromStroage(LLUUID primID);
}
//change to delegate?
public interface IPrimReceiver
{
void ReceivePrim(PrimAsset prim);
}
}

View File

@ -37,18 +37,19 @@ using System.Collections;
using System.Xml;
using libsecondlife;
namespace OpenSimLite
namespace OpenSim
{
/// <summary>
/// When running in local (default) mode , handles client logins.
/// </summary>
public class LoginServer
{
public LoginServer()
public LoginServer(UserServer userServer)
{
_userServer = userServer;
}
private Logon _login;
private UserServer _userServer;
private ushort _loginPort = Globals.Instance.LoginServerPort;
public IPAddress clientAddress = IPAddress.Loopback;
public IPAddress remoteAddress = IPAddress.Any;
@ -58,7 +59,7 @@ namespace OpenSimLite
private string _defaultResponse;
private string _mpasswd;
private bool _needPassswd=false;
private bool _needPasswd=false;
// InitializeLoginProxy: initialize the login proxy
private void InitializeLoginProxy() {
@ -66,7 +67,7 @@ namespace OpenSimLite
loginServer.Bind(new IPEndPoint(remoteAddress, _loginPort));
loginServer.Listen(1);
this._needPassswd=Globals.Instance.NeedPasswd;
this._needPasswd=Globals.Instance.NeedPasswd;
//read in default response string
StreamReader SR;
string lines;
@ -94,7 +95,7 @@ namespace OpenSimLite
private void RunLoginProxy()
{
Console.WriteLine("Starting Login Sever");
Console.WriteLine("Starting Login Server");
try
{
for (;;)
@ -145,7 +146,7 @@ namespace OpenSimLite
{
// read one line of the header
line = reader.ReadLine();
// check for premature EOF
if (line == null)
throw new Exception("EOF in client HTTP header");
@ -157,7 +158,6 @@ namespace OpenSimLite
} while (line != "");
// read the HTTP body into a buffer
this._login = new Logon();
char[] content = new char[contentLength];
reader.Read(content, 0, contentLength);
@ -180,6 +180,7 @@ namespace OpenSimLite
{
first = "test";
}
if(requestData.Contains("last"))
{
last = (string)requestData["last"];
@ -188,6 +189,7 @@ namespace OpenSimLite
{
last = "User"+NumClients.ToString();
}
if(requestData.Contains("passwd"))
{
passwd = (string)requestData["passwd"];
@ -235,6 +237,7 @@ namespace OpenSimLite
CustomiseLoginResponse( responseData, first, last );
this._login = new Logon();
//copy data to login object
_login.First = first;
_login.Last = last;
@ -243,9 +246,10 @@ namespace OpenSimLite
_login.BaseFolder = BaseFolderID;
_login.InventoryFolder = InventoryFolderID;
lock(Globals.Instance.IncomingLogins)
//working on local computer so lets add to the userserver's list of sessions
lock(this._userServer.Sessions)
{
Globals.Instance.IncomingLogins.Add(_login);
this._userServer.Sessions.Add(_login);
}
// forward the XML-RPC response to the client
@ -279,11 +283,11 @@ namespace OpenSimLite
protected virtual bool Authenticate(string first, string last, string passwd)
{
if(this._needPassswd)
if(this._needPasswd)
{
//every user needs the password to login
string encodedpass = passwd.Remove(0,3); //remove $1$
if(encodedpass == this._mpasswd)
string encodedPass = passwd.Remove(0,3); //remove $1$
if(encodedPass == this._mpasswd)
{
return true;
}
@ -294,7 +298,7 @@ namespace OpenSimLite
}
else
{
//not need password to login
//do not need password to login
return true;
}
}

View File

@ -1,8 +1,8 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<OutputType>Exe</OutputType>
<RootNamespace>OpenSimLite</RootNamespace>
<AssemblyName>OpenSimLite</AssemblyName>
<RootNamespace>OpenSim</RootNamespace>
<AssemblyName>OpenSim</AssemblyName>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{782CCAFD-7313-4638-ADAC-53703DF24DF0}</ProjectGuid>
@ -31,6 +31,14 @@
<HintPath>bin\Debug\libsecondlife.dll</HintPath>
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="libdb_dotNET43">
<HintPath>bin\Debug\libdb_dotNET43.dll</HintPath>
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="Kds.Serialization">
<HintPath>bin\Debug\Kds.Serialization.dll</HintPath>
<SpecificVersion>False</SpecificVersion>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Controller.cs" />
@ -52,6 +60,10 @@
<Compile Include="InstantMessaging.cs" />
<Compile Include="Globals.cs" />
<Compile Include="Utility.cs" />
<Compile Include="LocalStorageBase.cs" />
<Compile Include="Assets.cs" />
<Compile Include="LocalAssetCache.cs" />
<Compile Include="BerkeleyDatabase.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
</Project>

View File

@ -27,7 +27,7 @@
using System;
namespace OpenSimLite
namespace OpenSim
{
/// <summary>
/// Description of PhysicsManager.

View File

@ -26,16 +26,34 @@
*/
using System;
using libsecondlife;
namespace OpenSimLite
namespace OpenSim
{
/// <summary>
/// Manages and provides local cache of Prims.
/// </summary>
public class PrimManager
{
private LocalPrimDb _localPrimDB;
public PrimManager()
{
this._localPrimDB = new LocalPrimDb();
//database test
/*PrimAsset prim = new PrimAsset();
prim.Name="happy now";
prim.Description= "test";
prim.FullID = new LLUUID("00000000-0000-0000-0000-000000000008");
this._localPrimDB.CreateNewPrimStorage(prim);
PrimAsset prim1 = this._localPrimDB.GetPrimFromStroage( new LLUUID("00000000-0000-0000-0000-000000000008"));
Console.WriteLine("prim recieved : "+prim1.Name + " "+ prim1.Description);
*/
//this._localPrimDB.ReadWholedatabase();
}
}
}

View File

@ -32,7 +32,7 @@ using System.Threading;
using libsecondlife;
using libsecondlife.Packets;
namespace OpenSimLite
namespace OpenSim
{
/// <summary>
/// Manages prim and avatar sim positions and movements and updating clients
@ -45,7 +45,10 @@ namespace OpenSimLite
private Server _server;
private System.Text.Encoding _enc = System.Text.Encoding.ASCII;
private libsecondlife.Packets.ObjectUpdatePacket.ObjectDataBlock _avatarTemplate;
private int _objectCount=0;
private UpdateSender _updateSender;
private AgentManager _agentManager;
public NonBlockingQueue<UpdateCommand> Commands;
@ -54,21 +57,112 @@ namespace OpenSimLite
private object _sendTerrainSync = new object();
#endregion
public SceneGraph(Server server)
public SceneGraph(Server server, AgentManager agentManager)
{
_server = server;
RootNode = new Node();
_physics = new PhysicsManager(this);
Commands = new NonBlockingQueue<UpdateCommand>();
Terrain = new Terrain();
_updateSender = new UpdateSender(_server, agentManager);
_agentManager = agentManager;
//testing
this.SetupTemplate("objectupate168.dat");
_updateSender.Startup();
}
public void Update()
{
// run physics engine to update positions etc since last frame
// process command list
lock(this.Commands) //do we want to stop new commands being added while we process?
{
while(this.Commands.Count > 0)
{
UpdateCommand command = this.Commands.Dequeue();
switch(command.CommandType)
{
case 1:
break;
default:
break;
}
}
}
// check to see if any new avatars have joined since last frame
//if so send data to clients.
lock(this.RootNode)
{
for (int i = 0; i < this.RootNode.ChildrenCount; i++)
{
//for now we will limit avatars to being a child of the rootnode
if(this.RootNode.GetChild(i).SceneType == 1) //check it is a avatar node
{
AvatarData avatar =(AvatarData) this.RootNode.GetChild(i);
int updatemask = avatar.UpdateFlag & (128);
if(updatemask == 128) //is a new avatar?
{
this.SendAvatarDataToAll(avatar);
//should send a avatar appearance to other clients except the avatar's owner
//and send complete scene update to the new avatar's owner
this.SendCompleteSceneTo(avatar);
//reset new avatar flag
//avatar.UpdateFlag -= 128;
}
}
}
}
//send updates to clients
//might be better to do these updates reverse to how is done here
// ie.. loop through the avatars and find objects /other avatars in their range/vision
//instead of looping through all objects/avatars and then finding avatars in range
//but that would mean looping through all objects/avatar for each avatar,
//rather than looping through just the avatars for each object/avatar
lock(this.RootNode)
{
for (int i = 0; i < this.RootNode.ChildrenCount; i++)
{
if(this.RootNode.GetChild(i).SceneType == 1) //check it is a avatar node
{
AvatarData avatar =(AvatarData) this.RootNode.GetChild(i);
int updatemask = avatar.UpdateFlag & (1);
if(updatemask == 1)
{
//avatar has changed velocity
//check what avatars are in range and add to their update lists
//but for now we will say all avatars are in range
for (int n = 0; n < this.RootNode.ChildrenCount; n++)
{
if(this.RootNode.GetChild(n).SceneType == 1) //check it is a avatar node
{
AvatarData avatar2 =(AvatarData) this.RootNode.GetChild(i);
int newmask = avatar2.UpdateFlag & (128);
if(newmask != 128) //is a new avatar?
{
//no its not so let add to its updatelist
avatar2.TerseUpdateList.Add(this.CreateTerseBlock(avatar));
}
}
}
}
}
}
}
//now reset all update flags
lock(this.RootNode)
{
for (int i = 0; i < this.RootNode.ChildrenCount; i++)
{
this.RootNode.GetChild(i).UpdateFlag = 0;
}
}
}
#region send terrain data
@ -80,13 +174,15 @@ namespace OpenSimLite
{
lock(this._sendTerrainSync)
{
string data_path = System.AppDomain.CurrentDomain.BaseDirectory + @"\layer_data\";
string data_path = Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory ,"layer_data" );
//send layerdata
LayerDataPacket layerpack = new LayerDataPacket();
layerpack.LayerID.Type = 76;
this.SendLayerData(userInfo, layerpack, data_path+@"layerdata0.dat");
this.SendLayerData(userInfo, layerpack, Path.Combine(data_path,"layerdata0.dat"));
Console.WriteLine("Sent terrain data");
//test
this.SendAvatarData(userInfo);
}
}
@ -112,6 +208,32 @@ namespace OpenSimLite
}
#endregion
public void AgentCompletingMove(NetworkInfo userInfo)
{
libsecondlife.Packets.AgentMovementCompletePacket mov = new AgentMovementCompletePacket();
mov.AgentData.SessionID = userInfo.User.SessionID;
mov.AgentData.AgentID = userInfo.User.AgentID;
mov.Data.RegionHandle = Globals.Instance.RegionHandle;
mov.Data.Timestamp = 1169838966;
mov.Data.Position = new LLVector3(100f, 100f, 22f);
mov.Data.LookAt = new LLVector3(0.99f, 0.042f, 0);
_server.SendPacket(mov, true, userInfo);
}
public void AddNewAvatar(AvatarData avatar)
{
lock(this.RootNode)
{
avatar.SceneName = "Avatar" + this._objectCount.ToString("00000");
this._objectCount++;
this.RootNode.AddChild(avatar);
}
avatar.UpdateFlag = 128;
//add to new clients list?
}
#region testing
//test only
private void SendAvatarData(NetworkInfo userInfo)
@ -132,7 +254,7 @@ namespace OpenSimLite
//userInfo.User.FullName = "FirstName STRING RW SV " + userInfo.first_name + "\nLastName STRING RW SV " + userInfo.last_name + " \0";
libsecondlife.LLVector3 pos2 = new LLVector3(100f, 100.0f, 22.0f);
byte[] pb = pos2.GetBytes();
byte[] pb = pos2.GetBytes();
Array.Copy(pb, 0, objupdate.ObjectData[0].ObjectData, 16, pb.Length);
//this._localNumber++;
@ -142,7 +264,7 @@ namespace OpenSimLite
//test only
private void SetupTemplate(string name)
{
//should be replaced with completely code generated packets
int i = 0;
FileInfo fInfo = new FileInfo(name);
long numBytes = fInfo.Length;
@ -168,7 +290,44 @@ namespace OpenSimLite
}
#endregion
private void SendAvatarDataToAll(AvatarData avatar)
{
ObjectUpdatePacket objupdate = new ObjectUpdatePacket();
objupdate.RegionData.RegionHandle = Globals.Instance.RegionHandle;
objupdate.RegionData.TimeDilation = 0;
objupdate.ObjectData = new libsecondlife.Packets.ObjectUpdatePacket.ObjectDataBlock[1];
objupdate.ObjectData[0] = _avatarTemplate;
objupdate.ObjectData[0].ID = avatar.LocalID;
objupdate.ObjectData[0].FullID = avatar.NetInfo.User.AgentID;
objupdate.ObjectData[0].NameValue = _enc.GetBytes("FirstName STRING RW SV " + avatar.NetInfo.User.FirstName + "\nLastName STRING RW SV " + avatar.NetInfo.User.LastName + " \0");
libsecondlife.LLVector3 pos2 = new LLVector3(100f, 100.0f, 22.0f);
byte[] pb = pos2.GetBytes();
Array.Copy(pb, 0, objupdate.ObjectData[0].ObjectData, 16, pb.Length);
SendInfo send = new SendInfo();
send.Incr = true;
send.NetInfo = avatar.NetInfo;
send.Packet = objupdate;
send.SentTo = 1; //to all clients
this._updateSender.SendList.Enqueue(send);
}
public void SendCompleteSceneTo(AvatarData avatar)
{
}
public ImprovedTerseObjectUpdatePacket.ObjectDataBlock CreateTerseBlock(AvatarData avatar)
{
return(null);
}
public void SendAvatarAppearanceToAllExcept(AvatarData avatar)
{
}
}
//any need for separate nodes and sceneobjects?
@ -176,7 +335,12 @@ namespace OpenSimLite
public class Node
{
private List<Node> _children;
private List<SceneObject> _attached;
//private List<SceneObject> _attached;
public byte SceneType;
public string SceneName;
public LLVector3 Position;
public LLVector3 Velocity = new LLVector3(0,0,0);
public byte UpdateFlag;
public List<Node> ChildNodes
{
@ -186,6 +350,14 @@ namespace OpenSimLite
}
}
public int ChildrenCount
{
get
{
return(_children.Count);
}
}
/*
public List<SceneObject> AttachedObjexts
{
get
@ -193,13 +365,13 @@ namespace OpenSimLite
return(_attached);
}
}
*/
public Node()
{
_children = new List<Node>();
_attached = new List<SceneObject>();
//_attached = new List<SceneObject>();
}
/*
/// <summary>
///
/// </summary>
@ -252,6 +424,7 @@ namespace OpenSimLite
}
return(rValue);
}
*/
/// <summary>
///
@ -289,15 +462,18 @@ namespace OpenSimLite
}
}
/*
public class SceneObject
{
public byte SceneType;
public string SceneName;
public SceneObject()
{
}
}
}*/
public class Terrain
{
@ -326,7 +502,7 @@ namespace OpenSimLite
public class UpdateCommand
{
public byte CommandType;
public SceneObject SObject;
public Node SObject;
public LLVector3 Position;
public LLVector3 Velocity;
public LLQuaternion Rotation;
@ -341,29 +517,63 @@ namespace OpenSimLite
{
public BlockingQueue<SendInfo> SendList;
private Thread mthread;
private Server _server;
private AgentManager _agentManager;
public UpdateSender()
public UpdateSender(Server server, AgentManager agentManager)
{
SendList = new BlockingQueue<SendInfo>();
_server = server;
_agentManager = agentManager;
}
public void Startup()
{
mthread = new Thread(new System.Threading.ThreadStart(RunSender));
mthread.IsBackground = true;
mthread.Start();
}
private void RunSender()
{
//process SendList and send packets to clients
try
{
for(;;)
{
SendInfo sendInfo;
sendInfo = this.SendList.Dequeue();
switch(sendInfo.SentTo)
{
case 0:
this._server.SendPacket(sendInfo.Packet, sendInfo.Incr, sendInfo.NetInfo);
break;
case 1:
this._agentManager.SendPacketToALL(sendInfo.Packet);
break;
case 2:
this._agentManager.SendPacketToAllExcept(sendInfo.Packet, sendInfo.NetInfo.User.AgentID);
break;
default:
break;
}
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
public class SendInfo
{
public Packet Packet;
public bool Incr;
public bool Incr = true;
public NetworkInfo NetInfo;
public byte SentTo = 0; // 0 just this client, 1 to all clients, 2 to all except this client.
public SendInfo()
{

View File

@ -27,7 +27,7 @@
using System;
namespace OpenSimLite
namespace OpenSim
{
/// <summary>
/// Description of ScriptManager.
@ -39,10 +39,10 @@ namespace OpenSimLite
}
}
public interface ScriptPlugin
public interface IScriptPlugin
{
ScriptObject ICompileScript(string script);
bool IStart();
ScriptObject CompileScript(string script);
bool Start();
}
public interface ScriptObject

View File

@ -26,17 +26,21 @@
*/
using System;
using libsecondlife;
using System.Collections.Generic;
namespace OpenSimLite
namespace OpenSim
{
/// <summary>
/// Handles connection to User Servers
///
/// </summary>
public class UserServer
public class UserServer :IUserServer
{
public List<Logon> Sessions = new List<Logon>(); //should change to something other than logon classes?
public UserServer()
{
Sessions = new List<Logon>();
}
private void Initialise()
@ -47,5 +51,46 @@ namespace OpenSimLite
}
}
public AuthenticateResponse AuthenticateSession(LLUUID sessionID, LLUUID agentID, uint circuitCode)
{
//For Grid use:
//should check to see if it is a teleportation, if so then we should be expecting this session, agent. (?)
//if not check with User server/ login server that it is authorised.
//but for now we are running local
AuthenticateResponse user = new AuthenticateResponse();
lock(this.Sessions)
{
for(int i = 0; i < Sessions.Count; i++)
{
if((Sessions[i].Agent == agentID) && (Sessions[i].Session == sessionID))
{
user.Authorised = true;
user.LogonInfo = Sessions[i];
}
}
}
return(user);
}
}
public interface IUserServer
{
AuthenticateResponse AuthenticateSession(LLUUID sessionID, LLUUID agentID, uint circuitCode);
}
public class AuthenticateResponse
{
public bool Authorised;
public Logon LogonInfo;
public AuthenticateResponse()
{
}
}
}

View File

@ -27,10 +27,12 @@
using System;
using System.Text;
using System.Collections.Generic;
using System.Threading;
using System.Text.RegularExpressions;
using System.Security.Cryptography;
namespace OpenSimLite
namespace OpenSim
{
/// <summary>
/// Description of Utility.
@ -54,4 +56,65 @@ namespace OpenSimLite
return Regex.Replace(BitConverter.ToString(encodedBytes), "-", "").ToLower();
}
}
public class BlockingQueue< T >
{
private Queue< T > _queue = new Queue< T >();
private object _queueSync = new object();
public void Enqueue(T value)
{
lock(_queueSync)
{
_queue.Enqueue(value);
Monitor.Pulse(_queueSync);
}
}
public T Dequeue()
{
lock(_queueSync)
{
if( _queue.Count < 1)
Monitor.Wait(_queueSync);
return _queue.Dequeue();
}
}
}
public class NonBlockingQueue< T >
{
private Queue< T > _queue = new Queue< T >();
private object _queueSync = new object();
public void Enqueue(T value)
{
lock(_queueSync)
{
_queue.Enqueue(value);
}
}
public T Dequeue()
{
T rValue = default(T);
lock(_queueSync)
{
if( _queue.Count > 0)
{
rValue = _queue.Dequeue();
}
}
return rValue;
}
public int Count
{
get
{
return(_queue.Count);
}
}
}
}

View File

@ -35,7 +35,7 @@ using System.Net;
using System.Net.Sockets;
using System.Timers;
namespace OpenSimLite
namespace OpenSim
{
/// <summary>
/// Manages Viewer connections
@ -55,7 +55,7 @@ namespace OpenSimLite
}
}*/
//for now though, we will use a slightly adapted version of the server
//for now though, we will use a adapted version of the server
// class from version 0.1
public class Server
{
@ -66,6 +66,7 @@ namespace OpenSimLite
/// <summary>The Region class that this Simulator wraps</summary>
// public Region Region;
private object _sendPacketSync = new object();
/// <summary>
/// Used internally to track sim disconnections, do not modify this
/// variable
@ -116,13 +117,14 @@ namespace OpenSimLite
private System.Timers.Timer AckTimer;
private Server_Settings Settings=new Server_Settings();
public ArrayList User_agents=new ArrayList();
private IUserServer _userServer;
/// <summary>
///
/// </summary>
public Server()
public Server(IUserServer userServer)
{
this._userServer = userServer;
}
/// <summary>
@ -207,110 +209,113 @@ namespace OpenSimLite
/// <param name="incrementSequence">Increment sequence number?</param>
public void SendPacket(Packet packet, bool incrementSequence, NetworkInfo User_info)
{
byte[] buffer;
int bytes;
if (!connected && packet.Type != PacketType.UseCircuitCode)
lock(this._sendPacketSync)
{
// Client.Log("Trying to send a " + packet.Type.ToString() + " packet when the socket is closed",
// Helpers.LogLevel.Info);
byte[] buffer;
int bytes;
return;
}
if (packet.Header.AckList.Length > 0)
{
// Scrub any appended ACKs since all of the ACK handling is done here
packet.Header.AckList = new uint[0];
}
packet.Header.AppendedAcks = false;
// Keep track of when this packet was sent out
packet.TickCount = Environment.TickCount;
if (incrementSequence)
{
// Set the sequence number
lock (SequenceLock)
if (!connected && packet.Type != PacketType.UseCircuitCode)
{
if (Sequence > Settings.MAX_SEQUENCE)
Sequence = 1;
else
Sequence++;
packet.Header.Sequence = Sequence;
// Client.Log("Trying to send a " + packet.Type.ToString() + " packet when the socket is closed",
// Helpers.LogLevel.Info);
return;
}
if (packet.Header.Reliable)
if (packet.Header.AckList.Length > 0)
{
lock (User_info.NeedAck)
// Scrub any appended ACKs since all of the ACK handling is done here
packet.Header.AckList = new uint[0];
}
packet.Header.AppendedAcks = false;
// Keep track of when this packet was sent out
packet.TickCount = Environment.TickCount;
if (incrementSequence)
{
// Set the sequence number
lock (SequenceLock)
{
if (!User_info.NeedAck.ContainsKey(packet.Header.Sequence))
{
User_info.NeedAck.Add(packet.Header.Sequence, packet);
}
if (Sequence > Settings.MAX_SEQUENCE)
Sequence = 1;
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);
}
Sequence++;
packet.Header.Sequence = Sequence;
}
// Don't append ACKs to resent packets, in case that's what was causing the
// delivery to fail
if (!packet.Header.Resent)
if (packet.Header.Reliable)
{
// Append any ACKs that need to be sent out to this packet
lock (User_info.PendingAcks)
lock (User_info.NeedAck)
{
if (User_info.PendingAcks.Count > 0 && User_info.PendingAcks.Count < Settings.MAX_APPENDED_ACKS &&
packet.Type != PacketType.PacketAck &&
packet.Type != PacketType.LogoutRequest)
if (!User_info.NeedAck.ContainsKey(packet.Header.Sequence))
{
packet.Header.AckList = new uint[User_info.PendingAcks.Count];
int i = 0;
foreach (uint ack in User_info.PendingAcks.Values)
{
packet.Header.AckList[i] = ack;
i++;
}
User_info.NeedAck.Add(packet.Header.Sequence, packet);
}
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);
}
}
User_info.PendingAcks.Clear();
packet.Header.AppendedAcks = true;
// Don't append ACKs to resent packets, in case that's what was causing the
// delivery to fail
if (!packet.Header.Resent)
{
// Append any ACKs that need to be sent out to this packet
lock (User_info.PendingAcks)
{
if (User_info.PendingAcks.Count > 0 && User_info.PendingAcks.Count < Settings.MAX_APPENDED_ACKS &&
packet.Type != PacketType.PacketAck &&
packet.Type != PacketType.LogoutRequest)
{
packet.Header.AckList = new uint[User_info.PendingAcks.Count];
int i = 0;
foreach (uint ack in User_info.PendingAcks.Values)
{
packet.Header.AckList[i] = ack;
i++;
}
User_info.PendingAcks.Clear();
packet.Header.AppendedAcks = true;
}
}
}
}
}
}
// Serialize the packet
buffer = packet.ToBytes();
bytes = buffer.Length;
// Serialize the packet
buffer = packet.ToBytes();
bytes = buffer.Length;
try
{
// Zerocode if needed
if (packet.Header.Zerocoded)
try
{
lock (ZeroOutBuffer)
// Zerocode if needed
if (packet.Header.Zerocoded)
{
bytes = Helpers.ZeroEncode(buffer, bytes, ZeroOutBuffer);
Connection.SendTo(ZeroOutBuffer, bytes, SocketFlags.None,User_info.endpoint);
lock (ZeroOutBuffer)
{
bytes = Helpers.ZeroEncode(buffer, bytes, ZeroOutBuffer);
Connection.SendTo(ZeroOutBuffer, bytes, SocketFlags.None,User_info.endpoint);
}
}
else
{
Connection.SendTo(buffer, bytes, SocketFlags.None,User_info.endpoint);
}
}
else
catch (SocketException)
{
Connection.SendTo(buffer, bytes, SocketFlags.None,User_info.endpoint);
}
}
catch (SocketException)
{
//Client.Log("Tried to send a " + packet.Type.ToString() + " on a closed socket",
// Helpers.LogLevel.Warning);
//Client.Log("Tried to send a " + packet.Type.ToString() + " on a closed socket",
// Helpers.LogLevel.Warning);
Disconnect();
Disconnect();
}
}
}
@ -425,6 +430,23 @@ namespace OpenSimLite
{
//new connection
UseCircuitCodePacket cir_pack=(UseCircuitCodePacket)packet;
//should check that this session/circuit is authorised
AuthenticateResponse sessionInfo = this._userServer.AuthenticateSession(cir_pack.CircuitCode.SessionID, cir_pack.CircuitCode.ID, cir_pack.CircuitCode.Code);
if(!sessionInfo.Authorised)
{
//session/circuit not authorised
//so do something about it
}
else
{
//is authorised so add the logon object to the incominglogin list
//should be a better way of doing this now the login server connects to the user server
// like passing the logon object straight to the ClientConnection
lock(Globals.Instance.IncomingLogins)
{
Globals.Instance.IncomingLogins.Add(sessionInfo.LogonInfo);
}
}
NetworkInfo new_user=new NetworkInfo();
new_user.CircuitCode=cir_pack.CircuitCode.Code;
new_user.User.AgentID=cir_pack.CircuitCode.ID;