* Rex merge, region modules.

afrisby-3
Adam Frisby 2008-02-23 03:46:55 +00:00
parent 3dfb31a49c
commit db76041e4e
26 changed files with 6701 additions and 3671 deletions

View File

@ -0,0 +1,286 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSim Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
using System;
using System.Collections.Generic;
using System.Text;
using libsecondlife;
using Nini.Config;
using OpenSim.Framework;
using OpenSim.Region.Environment.Interfaces;
using OpenSim.Region.Environment.Scenes;
namespace OpenSim.Region.Environment.Modules
{
public class AgentAssetTransactionModule : IRegionModule, IAgentAssetTransactions
{
private Dictionary<LLUUID, Scene> RegisteredScenes = new Dictionary<LLUUID, Scene>();
private Scene m_scene = null;
private bool m_dumpAssetsToFile = false;
private AgentAssetTransactionsManager m_transactionManager;
public AgentAssetTransactionModule()
{
// System.Console.WriteLine("creating AgentAssetTransactionModule");
}
public void Initialise(Scene scene, IConfigSource config)
{
if (!RegisteredScenes.ContainsKey(scene.RegionInfo.RegionID))
{
// System.Console.WriteLine("initialising AgentAssetTransactionModule");
RegisteredScenes.Add(scene.RegionInfo.RegionID, scene);
scene.RegisterModuleInterface<IAgentAssetTransactions>(this);
scene.EventManager.OnNewClient += NewClient;
}
if (m_scene == null)
{
m_scene = scene;
if (config.Configs["StandAlone"] != null)
{
try
{
m_dumpAssetsToFile = config.Configs["StandAlone"].GetBoolean("dump_assets_to_file", false);
m_transactionManager = new AgentAssetTransactionsManager(m_scene, m_dumpAssetsToFile);
}
catch (Exception)
{
m_transactionManager = new AgentAssetTransactionsManager(m_scene, false);
}
}
else
{
m_transactionManager = new AgentAssetTransactionsManager(m_scene, false);
}
}
}
public void PostInitialise()
{
}
public void Close()
{
}
public string Name
{
get { return "AgentTransactionModule"; }
}
public bool IsSharedModule
{
get { return true; }
}
public void NewClient(IClientAPI client)
{
client.OnAssetUploadRequest += m_transactionManager.HandleUDPUploadRequest;
client.OnXferReceive += m_transactionManager.HandleXfer;
}
public void HandleItemCreationFromTransaction(IClientAPI remoteClient, LLUUID transactionID, LLUUID folderID,
uint callbackID, string description, string name, sbyte invType,
sbyte type, byte wearableType, uint nextOwnerMask)
{
m_transactionManager.HandleItemCreationFromTransaction(remoteClient, transactionID, folderID, callbackID, description, name, invType, type, wearableType, nextOwnerMask);
}
public void HandleItemUpdateFromTransaction(IClientAPI remoteClient, LLUUID transactionID,
InventoryItemBase item)
{
m_transactionManager.HandleItemUpdateFromTransaction(remoteClient, transactionID, item);
}
public void RemoveAgentAssetTransactions(LLUUID userID)
{
m_transactionManager.RemoveAgentAssetTransactions(userID);
}
}
//should merge this classes and clean up
public class AgentAssetTransactionsManager
{
private static readonly log4net.ILog m_log
= log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
// Fields
public Scene MyScene;
/// <summary>
/// Each agent has its own singleton collection of transactions
/// </summary>
private Dictionary<LLUUID, AgentAssetTransactions> AgentTransactions =
new Dictionary<LLUUID, AgentAssetTransactions>();
/// <summary>
/// Should we dump uploaded assets to the filesystem?
/// </summary>
private bool m_dumpAssetsToFile;
public AgentAssetTransactionsManager(Scene scene, bool dumpAssetsToFile)
{
MyScene = scene;
m_dumpAssetsToFile = dumpAssetsToFile;
}
/// <summary>
/// Get the collection of asset transactions for the given user. If one does not already exist, it
/// is created.
/// </summary>
/// <param name="userID"></param>
/// <returns></returns>
private AgentAssetTransactions GetUserTransactions(LLUUID userID)
{
lock (AgentTransactions)
{
if (!AgentTransactions.ContainsKey(userID))
{
AgentAssetTransactions transactions
= new AgentAssetTransactions(userID, this, m_dumpAssetsToFile);
AgentTransactions.Add(userID, transactions);
}
return AgentTransactions[userID];
}
}
/// <summary>
/// Remove the given agent asset transactions. This should be called when a client is departing
/// from a scene (and hence won't be making any more transactions here).
/// </summary>
/// <param name="userID"></param>
public void RemoveAgentAssetTransactions(LLUUID userID)
{
// m_log.DebugFormat("Removing agent asset transactions structure for agent {0}", userID);
lock (AgentTransactions)
{
AgentTransactions.Remove(userID);
}
}
/// <summary>
/// Create an inventory item from data that has been received through a transaction.
///
/// This is called when new clothing or body parts are created. It may also be called in other
/// situations.
/// </summary>
/// <param name="remoteClient"></param>
/// <param name="transactionID"></param>
/// <param name="folderID"></param>
/// <param name="callbackID"></param>
/// <param name="description"></param>
/// <param name="name"></param>
/// <param name="invType"></param>
/// <param name="type"></param>
/// <param name="wearableType"></param>
/// <param name="nextOwnerMask"></param>
public void HandleItemCreationFromTransaction(IClientAPI remoteClient, LLUUID transactionID, LLUUID folderID,
uint callbackID, string description, string name, sbyte invType,
sbyte type, byte wearableType, uint nextOwnerMask)
{
m_log.DebugFormat(
"[TRANSACTIONS MANAGER] Called HandleItemCreationFromTransaction with item {0}", name);
AgentAssetTransactions transactions = GetUserTransactions(remoteClient.AgentId);
transactions.RequestCreateInventoryItem(
remoteClient, transactionID, folderID, callbackID, description,
name, invType, type, wearableType, nextOwnerMask);
}
/// <summary>
/// Update an inventory item with data that has been received through a transaction.
///
/// This is called when clothing or body parts are updated (for instance, with new textures or
/// colours). It may also be called in other situations.
/// </summary>
/// <param name="remoteClient"></param>
/// <param name="transactionID"></param>
/// <param name="item"></param>
public void HandleItemUpdateFromTransaction(IClientAPI remoteClient, LLUUID transactionID,
InventoryItemBase item)
{
m_log.DebugFormat(
"[TRANSACTIONS MANAGER] Called HandleItemUpdateFromTransaction with item {0}",
item.inventoryName);
AgentAssetTransactions transactions
= GetUserTransactions(remoteClient.AgentId);
transactions.RequestUpdateInventoryItem(remoteClient, transactionID, item);
}
/// <summary>
/// Request that a client (agent) begin an asset transfer.
/// </summary>
/// <param name="remoteClient"></param>
/// <param name="assetID"></param>
/// <param name="transaction"></param>
/// <param name="type"></param>
/// <param name="data"></param></param>
/// <param name="tempFile"></param>
public void HandleUDPUploadRequest(IClientAPI remoteClient, LLUUID assetID, LLUUID transaction, sbyte type,
byte[] data, bool storeLocal, bool tempFile)
{
// Console.WriteLine("asset upload of " + assetID);
AgentAssetTransactions transactions = GetUserTransactions(remoteClient.AgentId);
AgentAssetTransactions.AssetXferUploader uploader = transactions.RequestXferUploader(transaction);
if (uploader != null)
{
if (uploader.Initialise(remoteClient, assetID, transaction, type, data, storeLocal, tempFile))
{
}
}
}
/// <summary>
/// Handle asset transfer data packets received in response to the asset upload request in
/// HandleUDPUploadRequest()
/// </summary>
/// <param name="remoteClient"></param>
/// <param name="xferID"></param>
/// <param name="packetID"></param>
/// <param name="data"></param>
public void HandleXfer(IClientAPI remoteClient, ulong xferID, uint packetID, byte[] data)
{
AgentAssetTransactions transactions = GetUserTransactions(remoteClient.AgentId);
transactions.HandleXfer(xferID, packetID, data);
}
}
}

View File

@ -0,0 +1,408 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSim Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using libsecondlife;
using libsecondlife.Packets;
using OpenSim.Framework.Servers;
using OpenSim.Framework;
using OpenSim.Framework.Communications.Cache;
namespace OpenSim.Region.Environment.Modules
{
/// <summary>
/// Manage asset transactions for a single agent.
/// </summary>
public class AgentAssetTransactions
{
//private static readonly log4net.ILog m_log
// = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
// Fields
public LLUUID UserID;
public Dictionary<LLUUID, AssetXferUploader> XferUploaders = new Dictionary<LLUUID, AssetXferUploader>();
public AgentAssetTransactionsManager Manager;
private bool m_dumpAssetsToFile;
// Methods
public AgentAssetTransactions(LLUUID agentID, AgentAssetTransactionsManager manager, bool dumpAssetsToFile)
{
UserID = agentID;
Manager = manager;
m_dumpAssetsToFile = dumpAssetsToFile;
}
public AssetXferUploader RequestXferUploader(LLUUID transactionID)
{
if (!XferUploaders.ContainsKey(transactionID))
{
AssetXferUploader uploader = new AssetXferUploader(this, m_dumpAssetsToFile);
lock (XferUploaders)
{
XferUploaders.Add(transactionID, uploader);
}
return uploader;
}
return null;
}
public void HandleXfer(ulong xferID, uint packetID, byte[] data)
{
// AssetXferUploader uploaderFound = null;
lock (XferUploaders)
{
foreach (AssetXferUploader uploader in XferUploaders.Values)
{
if (uploader.XferID == xferID)
{
uploader.HandleXferPacket(xferID, packetID, data);
break;
}
}
}
}
public void RequestCreateInventoryItem(IClientAPI remoteClient, LLUUID transactionID, LLUUID folderID,
uint callbackID, string description, string name, sbyte invType,
sbyte type, byte wearableType, uint nextOwnerMask)
{
if (XferUploaders.ContainsKey(transactionID))
{
XferUploaders[transactionID].RequestCreateInventoryItem(remoteClient, transactionID, folderID,
callbackID, description, name, invType, type,
wearableType, nextOwnerMask);
}
}
public void RequestUpdateInventoryItem(IClientAPI remoteClient, LLUUID transactionID,
InventoryItemBase item)
{
if (XferUploaders.ContainsKey(transactionID))
{
XferUploaders[transactionID].RequestUpdateInventoryItem(remoteClient, transactionID, item);
}
}
/// <summary>
/// Get an uploaded asset. If the data is successfully retrieved, the transaction will be removed.
/// </summary>
/// <param name="transactionID"></param>
/// <returns>The asset if the upload has completed, null if it has not.</returns>
public AssetBase GetTransactionAsset(LLUUID transactionID)
{
if (XferUploaders.ContainsKey(transactionID))
{
AssetXferUploader uploader = XferUploaders[transactionID];
AssetBase asset = uploader.GetAssetData();
lock (XferUploaders)
{
XferUploaders.Remove(transactionID);
}
return asset;
}
return null;
}
// Nested Types
public class AssetXferUploader
{
// Fields
public bool AddToInventory;
public AssetBase Asset;
public LLUUID InventFolder = LLUUID.Zero;
private IClientAPI ourClient;
public LLUUID TransactionID = LLUUID.Zero;
public bool UploadComplete;
public ulong XferID;
private string m_name = String.Empty;
private string m_description = String.Empty;
private sbyte type = 0;
private sbyte invType = 0;
private uint nextPerm = 0;
private bool m_finished = false;
private bool m_createItem = false;
private AgentAssetTransactions m_userTransactions;
private bool m_storeLocal;
private bool m_dumpAssetToFile;
public AssetXferUploader(AgentAssetTransactions transactions, bool dumpAssetToFile)
{
m_userTransactions = transactions;
m_dumpAssetToFile = dumpAssetToFile;
}
/// <summary>
/// Process transfer data received from the client.
/// </summary>
/// <param name="xferID"></param>
/// <param name="packetID"></param>
/// <param name="data"></param>
/// <returns>True if the transfer is complete, false otherwise or if the xferID was not valid</returns>
public bool HandleXferPacket(ulong xferID, uint packetID, byte[] data)
{
if (XferID == xferID)
{
if (Asset.Data.Length > 1)
{
byte[] destinationArray = new byte[Asset.Data.Length + data.Length];
Array.Copy(Asset.Data, 0, destinationArray, 0, Asset.Data.Length);
Array.Copy(data, 0, destinationArray, Asset.Data.Length, data.Length);
Asset.Data = destinationArray;
}
else
{
byte[] buffer2 = new byte[data.Length - 4];
Array.Copy(data, 4, buffer2, 0, data.Length - 4);
Asset.Data = buffer2;
}
ConfirmXferPacketPacket newPack = new ConfirmXferPacketPacket();
newPack.XferID.ID = xferID;
newPack.XferID.Packet = packetID;
ourClient.OutPacket(newPack, ThrottleOutPacketType.Asset);
if ((packetID & 0x80000000) != 0)
{
SendCompleteMessage();
return true;
}
}
return false;
}
/// <summary>
/// Initialise asset transfer from the client
/// </summary>
/// <param name="xferID"></param>
/// <param name="packetID"></param>
/// <param name="data"></param>
/// <returns>True if the transfer is complete, false otherwise</returns>
public bool Initialise(IClientAPI remoteClient, LLUUID assetID, LLUUID transaction, sbyte type, byte[] data,
bool storeLocal, bool tempFile)
{
ourClient = remoteClient;
Asset = new AssetBase();
Asset.FullID = assetID;
Asset.InvType = type;
Asset.Type = type;
Asset.Data = data;
Asset.Name = "blank";
Asset.Description = "empty";
Asset.Local = storeLocal;
Asset.Temporary = tempFile;
TransactionID = transaction;
m_storeLocal = storeLocal;
if (Asset.Data.Length > 2)
{
SendCompleteMessage();
return true;
}
else
{
RequestStartXfer();
}
return false;
}
protected void RequestStartXfer()
{
UploadComplete = false;
XferID = Util.GetNextXferID();
RequestXferPacket newPack = new RequestXferPacket();
newPack.XferID.ID = XferID;
newPack.XferID.VFileType = Asset.Type;
newPack.XferID.VFileID = Asset.FullID;
newPack.XferID.FilePath = 0;
newPack.XferID.Filename = new byte[0];
ourClient.OutPacket(newPack, ThrottleOutPacketType.Asset);
}
protected void SendCompleteMessage()
{
UploadComplete = true;
AssetUploadCompletePacket newPack = new AssetUploadCompletePacket();
newPack.AssetBlock.Type = Asset.Type;
newPack.AssetBlock.Success = true;
newPack.AssetBlock.UUID = Asset.FullID;
ourClient.OutPacket(newPack, ThrottleOutPacketType.Asset);
m_finished = true;
if (m_createItem)
{
DoCreateItem();
}
else if (m_storeLocal)
{
m_userTransactions.Manager.MyScene.CommsManager.AssetCache.AddAsset(Asset);
}
// Console.WriteLine("upload complete "+ this.TransactionID);
if (m_dumpAssetToFile)
{
DateTime now = DateTime.Now;
string filename =
String.Format("{6}_{7}_{0:d2}{1:d2}{2:d2}_{3:d2}{4:d2}{5:d2}.dat", now.Year, now.Month, now.Day,
now.Hour, now.Minute, now.Second, Asset.Name, Asset.Type);
SaveAssetToFile(filename, Asset.Data);
}
}
///Left this in and commented in case there are unforseen issues
//private void SaveAssetToFile(string filename, byte[] data)
//{
// FileStream fs = File.Create(filename);
// BinaryWriter bw = new BinaryWriter(fs);
// bw.Write(data);
// bw.Close();
// fs.Close();
//}
private void SaveAssetToFile(string filename, byte[] data)
{
string assetPath = "UserAssets";
if (!Directory.Exists(assetPath))
{
Directory.CreateDirectory(assetPath);
}
FileStream fs = File.Create(Path.Combine(assetPath, filename));
BinaryWriter bw = new BinaryWriter(fs);
bw.Write(data);
bw.Close();
fs.Close();
}
public void RequestCreateInventoryItem(IClientAPI remoteClient, LLUUID transactionID, LLUUID folderID,
uint callbackID, string description, string name, sbyte invType,
sbyte type, byte wearableType, uint nextOwnerMask)
{
if (TransactionID == transactionID)
{
InventFolder = folderID;
m_name = name;
m_description = description;
this.type = type;
this.invType = invType;
nextPerm = nextOwnerMask;
Asset.Name = name;
Asset.Description = description;
Asset.Type = type;
Asset.InvType = invType;
m_createItem = true;
if (m_finished)
{
DoCreateItem();
}
}
}
public void RequestUpdateInventoryItem(IClientAPI remoteClient, LLUUID transactionID,
InventoryItemBase item)
{
if (TransactionID == transactionID)
{
CachedUserInfo userInfo =
m_userTransactions.Manager.MyScene.CommsManager.UserProfileCacheService.GetUserDetails(
remoteClient.AgentId);
if (userInfo != null)
{
LLUUID assetID = LLUUID.Combine(transactionID, remoteClient.SecureSessionId);
AssetBase asset
= m_userTransactions.Manager.MyScene.CommsManager.AssetCache.GetAsset(
assetID, (item.assetType == (int) AssetType.Texture ? true : false));
if (asset == null)
{
asset = m_userTransactions.GetTransactionAsset(transactionID);
}
if (asset != null && asset.FullID == assetID)
{
asset.Name = item.inventoryName;
asset.Description = item.inventoryDescription;
asset.InvType = (sbyte) item.invType;
asset.Type = (sbyte) item.assetType;
item.assetID = asset.FullID;
m_userTransactions.Manager.MyScene.CommsManager.AssetCache.AddAsset(Asset);
}
userInfo.UpdateItem(remoteClient.AgentId, item);
}
}
}
private void DoCreateItem()
{
//really need to fix this call, if lbsa71 saw this he would die.
m_userTransactions.Manager.MyScene.CommsManager.AssetCache.AddAsset(Asset);
CachedUserInfo userInfo =
m_userTransactions.Manager.MyScene.CommsManager.UserProfileCacheService.GetUserDetails(ourClient.AgentId);
if (userInfo != null)
{
InventoryItemBase item = new InventoryItemBase();
item.avatarID = ourClient.AgentId;
item.creatorsID = ourClient.AgentId;
item.inventoryID = LLUUID.Random();
item.assetID = Asset.FullID;
item.inventoryDescription = m_description;
item.inventoryName = m_name;
item.assetType = type;
item.invType = invType;
item.parentFolderID = InventFolder;
item.inventoryBasePermissions = 2147483647;
item.inventoryCurrentPermissions = 2147483647;
item.inventoryNextPermissions = nextPerm;
userInfo.AddItem(ourClient.AgentId, item);
ourClient.SendInventoryItemCreateUpdate(item);
}
}
public AssetBase GetAssetData()
{
if (m_finished)
{
return Asset;
}
return null;
}
}
}
}

View File

@ -0,0 +1,244 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSim Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
using System;
using System.Collections.Generic;
using System.Text;
using OpenSim.Region.Environment.Scenes;
using OpenSim.Framework;
using TribalMedia.Framework.Data;
namespace OpenSim.Region.Environment.Modules
{
public class AppearanceRowMapper : BaseRowMapper<AvatarAppearance>
{
public AppearanceRowMapper(BaseSchema schema, AvatarAppearance obj)
: base(schema, obj)
{
}
}
public class AppearanceTableMapper : BaseTableMapper<AppearanceRowMapper, Guid>
{
public AppearanceTableMapper(BaseDatabaseConnector database, string tableName)
: base(database, tableName)
{
BaseSchema<AppearanceRowMapper> rowMapperSchema = new BaseSchema<AppearanceRowMapper>(this);
m_schema = rowMapperSchema;
m_keyFieldMapper = rowMapperSchema.AddMapping<Guid>("UUID",
delegate(AppearanceRowMapper mapper) { return mapper.Object.ScenePresenceID.UUID; },
delegate(AppearanceRowMapper mapper, Guid value) { mapper.Object.ScenePresenceID = new libsecondlife.LLUUID(value.ToString()); });
rowMapperSchema.AddMapping<uint>("Serial",
delegate(AppearanceRowMapper mapper) { return (uint)mapper.Object.WearablesSerial; },
delegate(AppearanceRowMapper mapper, uint value) { mapper.Object.WearablesSerial = (int)value; });
rowMapperSchema.AddMapping<Guid>("WearableItem0",
delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[0].ItemID.UUID; },
delegate(AppearanceRowMapper mapper, Guid value)
{
if (mapper.Object.Wearables == null)
{
mapper.Object.Wearables = new OpenSim.Framework.AvatarWearable[13];
for (int i = 0; i < 13; i++)
{
mapper.Object.Wearables[i] = new AvatarWearable();
}
}
mapper.Object.Wearables[0].ItemID = new libsecondlife.LLUUID(value.ToString());
});
rowMapperSchema.AddMapping<Guid>("WearableAsset0",
delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[0].AssetID.UUID; },
delegate(AppearanceRowMapper mapper, Guid value)
{ mapper.Object.Wearables[0].AssetID = new libsecondlife.LLUUID(value.ToString()); });
rowMapperSchema.AddMapping<Guid>("WearableItem1",
delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[1].ItemID.UUID; },
delegate(AppearanceRowMapper mapper, Guid value) { mapper.Object.Wearables[1].ItemID = new libsecondlife.LLUUID(value.ToString()); });
rowMapperSchema.AddMapping<Guid>("WearableAsset1",
delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[1].AssetID.UUID; },
delegate(AppearanceRowMapper mapper, Guid value)
{ mapper.Object.Wearables[1].AssetID = new libsecondlife.LLUUID(value.ToString()); });
rowMapperSchema.AddMapping<Guid>("WearableItem2",
delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[2].ItemID.UUID; },
delegate(AppearanceRowMapper mapper, Guid value) { mapper.Object.Wearables[2].ItemID = new libsecondlife.LLUUID(value.ToString()); });
rowMapperSchema.AddMapping<Guid>("WearableAsset2",
delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[2].AssetID.UUID; },
delegate(AppearanceRowMapper mapper, Guid value)
{ mapper.Object.Wearables[2].AssetID = new libsecondlife.LLUUID(value.ToString()); });
rowMapperSchema.AddMapping<Guid>("WearableItem3",
delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[3].ItemID.UUID; },
delegate(AppearanceRowMapper mapper, Guid value) { mapper.Object.Wearables[3].ItemID = new libsecondlife.LLUUID(value.ToString()); });
rowMapperSchema.AddMapping<Guid>("WearableAsset3",
delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[3].AssetID.UUID; },
delegate(AppearanceRowMapper mapper, Guid value)
{ mapper.Object.Wearables[3].AssetID = new libsecondlife.LLUUID(value.ToString()); });
rowMapperSchema.AddMapping<Guid>("WearableItem4",
delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[4].ItemID.UUID; },
delegate(AppearanceRowMapper mapper, Guid value) { mapper.Object.Wearables[4].ItemID = new libsecondlife.LLUUID(value.ToString()); });
rowMapperSchema.AddMapping<Guid>("WearableAsset4",
delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[4].AssetID.UUID; },
delegate(AppearanceRowMapper mapper, Guid value)
{ mapper.Object.Wearables[4].AssetID = new libsecondlife.LLUUID(value.ToString()); });
rowMapperSchema.AddMapping<Guid>("WearableItem5",
delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[5].ItemID.UUID; },
delegate(AppearanceRowMapper mapper, Guid value) { mapper.Object.Wearables[5].ItemID = new libsecondlife.LLUUID(value.ToString()); });
rowMapperSchema.AddMapping<Guid>("WearableAsset5",
delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[5].AssetID.UUID; },
delegate(AppearanceRowMapper mapper, Guid value)
{ mapper.Object.Wearables[5].AssetID = new libsecondlife.LLUUID(value.ToString()); });
rowMapperSchema.AddMapping<Guid>("WearableItem6",
delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[6].ItemID.UUID; },
delegate(AppearanceRowMapper mapper, Guid value) { mapper.Object.Wearables[6].ItemID = new libsecondlife.LLUUID(value.ToString()); });
rowMapperSchema.AddMapping<Guid>("WearableAsset6",
delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[6].AssetID.UUID; },
delegate(AppearanceRowMapper mapper, Guid value)
{ mapper.Object.Wearables[6].AssetID = new libsecondlife.LLUUID(value.ToString()); });
rowMapperSchema.AddMapping<Guid>("WearableItem7",
delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[7].ItemID.UUID; },
delegate(AppearanceRowMapper mapper, Guid value) { mapper.Object.Wearables[7].ItemID = new libsecondlife.LLUUID(value.ToString()); });
rowMapperSchema.AddMapping<Guid>("WearableAsset7",
delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[7].AssetID.UUID; },
delegate(AppearanceRowMapper mapper, Guid value)
{ mapper.Object.Wearables[7].AssetID = new libsecondlife.LLUUID(value.ToString()); });
rowMapperSchema.AddMapping<Guid>("WearableItem8",
delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[8].ItemID.UUID; },
delegate(AppearanceRowMapper mapper, Guid value) { mapper.Object.Wearables[8].ItemID = new libsecondlife.LLUUID(value.ToString()); });
rowMapperSchema.AddMapping<Guid>("WearableAsset8",
delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[8].AssetID.UUID; },
delegate(AppearanceRowMapper mapper, Guid value)
{ mapper.Object.Wearables[8].AssetID = new libsecondlife.LLUUID(value.ToString()); });
rowMapperSchema.AddMapping<Guid>("WearableItem9",
delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[9].ItemID.UUID; },
delegate(AppearanceRowMapper mapper, Guid value) { mapper.Object.Wearables[9].ItemID = new libsecondlife.LLUUID(value.ToString()); });
rowMapperSchema.AddMapping<Guid>("WearableAsset9",
delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[9].AssetID.UUID; },
delegate(AppearanceRowMapper mapper, Guid value)
{ mapper.Object.Wearables[9].AssetID = new libsecondlife.LLUUID(value.ToString()); });
rowMapperSchema.AddMapping<Guid>("WearableItem10",
delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[10].ItemID.UUID; },
delegate(AppearanceRowMapper mapper, Guid value) { mapper.Object.Wearables[10].ItemID = new libsecondlife.LLUUID(value.ToString()); });
rowMapperSchema.AddMapping<Guid>("WearableAsset10",
delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[10].AssetID.UUID; },
delegate(AppearanceRowMapper mapper, Guid value)
{ mapper.Object.Wearables[10].AssetID = new libsecondlife.LLUUID(value.ToString()); });
rowMapperSchema.AddMapping<Guid>("WearableItem11",
delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[11].ItemID.UUID; },
delegate(AppearanceRowMapper mapper, Guid value) { mapper.Object.Wearables[11].ItemID = new libsecondlife.LLUUID(value.ToString()); });
rowMapperSchema.AddMapping<Guid>("WearableAsset11",
delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[11].AssetID.UUID; },
delegate(AppearanceRowMapper mapper, Guid value)
{ mapper.Object.Wearables[11].AssetID = new libsecondlife.LLUUID(value.ToString()); });
rowMapperSchema.AddMapping<Guid>("WearableItem12",
delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[12].ItemID.UUID; },
delegate(AppearanceRowMapper mapper, Guid value) { mapper.Object.Wearables[12].ItemID = new libsecondlife.LLUUID(value.ToString()); });
rowMapperSchema.AddMapping<Guid>("WearableAsset12",
delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[12].AssetID.UUID; },
delegate(AppearanceRowMapper mapper, Guid value)
{ mapper.Object.Wearables[12].AssetID = new libsecondlife.LLUUID(value.ToString()); });
}
public bool Add(Guid userID, AvatarAppearance appearance)
{
AppearanceRowMapper mapper = CreateRowMapper(appearance);
return Add(mapper);
}
public bool Update(Guid userID, AvatarAppearance appearance)
{
AppearanceRowMapper mapper = CreateRowMapper(appearance);
return Update(appearance.ScenePresenceID.UUID, mapper);
}
protected AppearanceRowMapper CreateRowMapper(AvatarAppearance appearance)
{
return new AppearanceRowMapper(m_schema, appearance);
}
protected AppearanceRowMapper CreateRowMapper()
{
return CreateRowMapper(new AvatarAppearance());
}
protected AppearanceRowMapper FromReader(BaseDataReader reader, AvatarAppearance appearance)
{
AppearanceRowMapper mapper = CreateRowMapper(appearance);
mapper.FillObject(reader);
return mapper;
}
public override AppearanceRowMapper FromReader(BaseDataReader reader)
{
AppearanceRowMapper mapper = CreateRowMapper();
mapper.FillObject(reader);
return mapper;
}
public bool TryGetValue(Guid presenceID, out AvatarAppearance val)
{
AppearanceRowMapper mapper;
if (TryGetValue(presenceID, out mapper))
{
val = mapper.Object;
return true;
}
else
{
val = null;
return false;
}
}
}
}

View File

@ -13,7 +13,7 @@
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY

View File

@ -28,6 +28,7 @@
using System;
using System.Collections.Generic;
using System.Threading;
using libsecondlife;
using Nini.Config;
using OpenSim.Framework;
@ -35,37 +36,174 @@ using OpenSim.Framework.Communications.Cache;
using OpenSim.Framework.Console;
using OpenSim.Region.Environment.Interfaces;
using OpenSim.Region.Environment.Scenes;
using OpenSim.Framework.Data;
using TribalMedia.Framework.Data;
namespace OpenSim.Region.Environment.Modules
{
public class AvatarFactoryModule : IAvatarFactory
{
private Scene m_scene = null;
private Dictionary<LLUUID, AvatarAppearance> m_avatarsAppearance = new Dictionary<LLUUID, AvatarAppearance>();
private readonly Dictionary<LLUUID, AvatarAppearance> m_avatarsAppearance = new Dictionary<LLUUID, AvatarAppearance>();
private bool m_enablePersist = false;
private string m_connectionString;
private bool m_configured = false;
private BaseDatabaseConnector m_databaseMapper;
private AppearanceTableMapper m_appearanceMapper;
private Dictionary<LLUUID, EventWaitHandle> m_fetchesInProgress = new Dictionary<LLUUID, EventWaitHandle>();
private object m_syncLock = new object();
public bool TryGetAvatarAppearance(LLUUID avatarId, out AvatarAppearance appearance)
{
if (m_avatarsAppearance.ContainsKey(avatarId))
//should only let one thread at a time do this part
EventWaitHandle waitHandle = null;
bool fetchInProgress = false;
lock (m_syncLock)
{
appearance = m_avatarsAppearance[avatarId];
appearance = CheckCache(avatarId);
if (appearance != null)
{
return true;
}
//not in cache so check to see if another thread is already fetching it
if (m_fetchesInProgress.TryGetValue(avatarId, out waitHandle))
{
fetchInProgress = true;
}
else
{
fetchInProgress = false;
//no thread already fetching this appearance, so add a wait handle to list
//for any following threads that want the same appearance
waitHandle = new EventWaitHandle(false, EventResetMode.ManualReset);
m_fetchesInProgress.Add(avatarId, waitHandle);
}
}
if (fetchInProgress)
{
waitHandle.WaitOne();
appearance = CheckCache(avatarId);
if (appearance != null)
{
waitHandle = null;
return true;
}
else
{
waitHandle = null;
return false;
}
}
else
{
Thread.Sleep(5000);
//this is the first thread to request this appearance
//so let it check the db and if not found then create a default appearance
//and add that to the cache
appearance = CheckDatabase(avatarId);
if (appearance != null)
{
//appearance has now been added to cache so lets pulse any waiting threads
lock (m_syncLock)
{
m_fetchesInProgress.Remove(avatarId);
waitHandle.Set();
}
// waitHandle.Close();
waitHandle = null;
return true;
}
//not found a appearance for the user, so create a new default one
appearance = CreateDefault(avatarId);
if (appearance != null)
{
//update database
if (m_enablePersist)
{
m_appearanceMapper.Add(avatarId.UUID, appearance);
}
//add appearance to dictionary cache
lock (m_avatarsAppearance)
{
m_avatarsAppearance[avatarId] = appearance;
}
//appearance has now been added to cache so lets pulse any waiting threads
lock (m_syncLock)
{
m_fetchesInProgress.Remove(avatarId);
waitHandle.Set();
}
// waitHandle.Close();
waitHandle = null;
return true;
}
else
{
//something went wrong, so release the wait handle and remove it
//all waiting threads will fail to find cached appearance
//but its better for them to fail than wait for ever
lock (m_syncLock)
{
m_fetchesInProgress.Remove(avatarId);
waitHandle.Set();
}
//waitHandle.Close();
waitHandle = null;
return false;
}
}
}
private AvatarAppearance CreateDefault(LLUUID avatarId)
{
AvatarAppearance appearance = null;
AvatarWearable[] wearables;
byte[] visualParams;
GetDefaultAvatarAppearance(out wearables, out visualParams);
appearance = new AvatarAppearance(avatarId, wearables, visualParams);
try
return appearance;
}
private AvatarAppearance CheckDatabase(LLUUID avatarId)
{
AvatarAppearance appearance = null;
if (m_enablePersist)
{
if (m_appearanceMapper.TryGetValue(avatarId.UUID, out appearance))
{
appearance.VisualParams = GetDefaultVisualParams();
appearance.TextureEntry = AvatarAppearance.GetDefaultTextureEntry();
lock (m_avatarsAppearance)
{
m_avatarsAppearance[avatarId] = appearance;
}
catch (NullReferenceException)
}
}
return appearance;
}
private AvatarAppearance CheckCache(LLUUID avatarId)
{
MainLog.Instance.Error("AVATAR", "Unable to load appearance for uninitialized avatar");
AvatarAppearance appearance = null;
lock (m_avatarsAppearance)
{
if (m_avatarsAppearance.ContainsKey(avatarId))
{
appearance = m_avatarsAppearance[avatarId];
}
return true;
}
return appearance;
}
public void Initialise(Scene scene, IConfigSource source)
@ -77,6 +215,24 @@ namespace OpenSim.Region.Environment.Modules
{
m_scene = scene;
}
if (!m_configured)
{
m_configured = true;
try
{
m_enablePersist = source.Configs["Startup"].GetBoolean("appearance_persist", false);
m_connectionString = source.Configs["Startup"].GetString("appearance_connection_string", "");
}
catch (Exception)
{
}
if (m_enablePersist)
{
m_databaseMapper = new MySQLDatabaseMapper(m_connectionString);
m_appearanceMapper = new AppearanceTableMapper(m_databaseMapper, "AvatarAppearance");
}
}
}
public void PostInitialise()
@ -115,11 +271,26 @@ namespace OpenSim.Region.Environment.Modules
{
if (profile.RootFolder != null)
{
//Todo look up the assetid from the inventory cache for each itemId that is in AvatarWearingArgs
// then store assetid and itemId and wearable type in a database
if (m_avatarsAppearance.ContainsKey(clientView.AgentId))
{
AvatarAppearance avatAppearance = null;
lock (m_avatarsAppearance)
{
avatAppearance = m_avatarsAppearance[clientView.AgentId];
}
foreach (AvatarWearingArgs.Wearable wear in e.NowWearing)
{
if (wear.Type < 13)
{
if (wear.ItemID == LLUUID.Zero)
{
avatAppearance.Wearables[wear.Type].ItemID = LLUUID.Zero;
avatAppearance.Wearables[wear.Type].AssetID = LLUUID.Zero;
UpdateDatabase(clientView.AgentId, avatAppearance);
}
else
{
LLUUID assetId;
@ -127,13 +298,10 @@ namespace OpenSim.Region.Environment.Modules
if (baseItem != null)
{
assetId = baseItem.assetID;
//temporary dictionary storage. This should be storing to a database
if (m_avatarsAppearance.ContainsKey(clientView.AgentId))
{
AvatarAppearance avatAppearance = m_avatarsAppearance[clientView.AgentId];
avatAppearance.Wearables[wear.Type].AssetID = assetId;
avatAppearance.Wearables[wear.Type].ItemID = wear.ItemID;
UpdateDatabase(clientView.AgentId, avatAppearance);
}
}
}
@ -141,6 +309,15 @@ namespace OpenSim.Region.Environment.Modules
}
}
}
}
public void UpdateDatabase(LLUUID userID, AvatarAppearance avatAppearance)
{
if (m_enablePersist)
{
m_appearanceMapper.Update(userID.UUID, avatAppearance);
}
}
public static void GetDefaultAvatarAppearance(out AvatarWearable[] wearables, out byte[] visualParams)
{

View File

@ -13,7 +13,7 @@
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
@ -87,7 +87,7 @@ namespace OpenSim.Region.Environment.Modules
string bornOn = "Before now";
string flAbout = "First life? What is one of those? OpenSim is my life!";
LLUUID partner = new LLUUID("11111111-1111-0000-0000-000100bba000");
remoteClient.SendAvatarProperties(avatarID, about, bornOn, "", flAbout, 0, LLUUID.Zero, LLUUID.Zero, "",
remoteClient.SendAvatarProperties(avatarID, about, bornOn, System.String.Empty, flAbout, 0, LLUUID.Zero, LLUUID.Zero, System.String.Empty,
partner);
}
}

View File

@ -0,0 +1,318 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSim Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
using Nini.Config;
using System;
using System.Collections;
using System.Collections.Generic;
using OpenSim.Framework;
using OpenSim.Framework.Console;
using OpenSim.Region.Environment.Interfaces;
using OpenSim.Region.Environment.Scenes;
using libsecondlife;
using MoneyTransferArgs = OpenSim.Region.Environment.Scenes.EventManager.MoneyTransferArgs;
namespace OpenSim.Region.Environment.Modules
{
public class BetaGridLikeMoneyModule: IRegionModule
{
private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private Dictionary<ulong,Scene> m_scenel = new Dictionary<ulong,Scene>();
private IConfigSource m_gConfig;
private bool m_keepMoneyAcrossLogins = true;
private int m_minFundsBeforeRefresh = 100;
private int m_stipend = 1000;
private bool m_enabled = true;
private Dictionary<LLUUID, int> m_KnownClientFunds = new Dictionary<LLUUID, int>();
private bool gridmode = false;
public void Initialise(Scene scene, IConfigSource config)
{
m_gConfig = config;
ReadConfigAndPopulate();
if (m_enabled)
{
lock (m_scenel)
{
if (m_scenel.ContainsKey(scene.RegionInfo.RegionHandle))
{
m_scenel[scene.RegionInfo.RegionHandle] = scene;
}
else
{
m_scenel.Add(scene.RegionInfo.RegionHandle, scene);
}
}
scene.EventManager.OnNewClient += OnNewClient;
scene.EventManager.OnMoneyTransfer += MoneyTransferAction;
scene.EventManager.OnClientClosed += ClientClosed;
}
}
private void ReadConfigAndPopulate()
{
IConfig startupConfig = m_gConfig.Configs["Startup"];
gridmode = startupConfig.GetBoolean("gridmode", false);
m_enabled = (startupConfig.GetString("moneymodule", "BetaGridLikeMoneyModule") == "BetaGridLikeMoneyModule");
}
private void OnNewClient(IClientAPI client)
{
// Here we check if we're in grid mode
// I imagine that the 'check balance'
// function for the client should be here or shortly after
if (gridmode)
{
CheckExistAndRefreshFunds(client.AgentId);
}
else
{
CheckExistAndRefreshFunds(client.AgentId);
}
// Subscribe to Money messages
client.OnMoneyBalanceRequest += SendMoneyBalance;
client.OnLogout += ClientClosed;
}
public void ClientClosed(LLUUID AgentID)
{
lock (m_KnownClientFunds)
{
if (!m_keepMoneyAcrossLogins)
m_KnownClientFunds.Remove(AgentID);
}
}
private void MoneyTransferAction (Object osender, MoneyTransferArgs e)
{
IClientAPI sender = null;
IClientAPI receiver = null;
sender = LocateClientObject(e.sender);
if (sender != null)
{
receiver = LocateClientObject(e.reciever);
bool transactionresult = doMoneyTranfer(e.sender, e.reciever, e.amount);
if (e.sender != e.reciever)
{
if (sender != null)
{
sender.SendMoneyBalance(LLUUID.Random(), transactionresult, Helpers.StringToField(e.description), GetFundsForAgentID(e.sender));
}
}
if (receiver != null)
{
receiver.SendMoneyBalance(LLUUID.Random(), transactionresult, Helpers.StringToField(e.description), GetFundsForAgentID(e.reciever));
}
}
else
{
m_log.Warn("[MONEY]: Potential Fraud Warning, got money transfer request for avatar that isn't in this simulator - Details; Sender:" + e.sender.ToString() + " Reciver: " + e.reciever.ToString() + " Amount: " + e.amount.ToString());
}
}
private bool doMoneyTranfer(LLUUID Sender, LLUUID Receiver, int amount)
{
bool result = false;
if (amount >= 0)
{
lock (m_KnownClientFunds)
{
// If we don't know about the sender, then the sender can't
// actually be here and therefore this is likely fraud or outdated.
if (m_KnownClientFunds.ContainsKey(Sender))
{
// Does the sender have enough funds to give?
if (m_KnownClientFunds[Sender] >= amount)
{
// Subtract the funds from the senders account
m_KnownClientFunds[Sender] -= amount;
// do we know about the receiver?
if (!m_KnownClientFunds.ContainsKey(Receiver))
{
// Make a record for them so they get the updated balance when they login
CheckExistAndRefreshFunds(Receiver);
}
//Add the amount to the Receiver's funds
m_KnownClientFunds[Receiver] += amount;
result = true;
}
else
{
// These below are redundant to make this clearer to read
result = false;
}
}
else
{
result = false;
}
}
}
return result;
}
private IClientAPI LocateClientObject(LLUUID AgentID)
{
ScenePresence tPresence = null;
IClientAPI rclient = null;
lock (m_scenel)
{
foreach (Scene _scene in m_scenel.Values)
{
tPresence = _scene.GetScenePresence(AgentID);
if (tPresence != null)
{
if (!tPresence.IsChildAgent)
{
rclient = tPresence.ControllingClient;
}
}
if (rclient != null)
{
return rclient;
}
}
}
return null;
}
public void ClientClosed(IClientAPI client)
{
ClientClosed(client.AgentId);
}
public void SendMoneyBalance(IClientAPI client, LLUUID agentID, LLUUID SessionID, LLUUID TransactionID)
{
if (client.AgentId == agentID && client.SessionId == SessionID)
{
int returnfunds = 0;
try
{
returnfunds = GetFundsForAgentID(agentID);
}
catch (System.Exception e)
{
client.SendAlertMessage(e.Message + " ");
}
client.SendMoneyBalance(TransactionID, true, new byte[0], returnfunds);
}
else
{
client.SendAlertMessage("Unable to send your money balance to you!");
}
}
private void CheckExistAndRefreshFunds(LLUUID agentID)
{
lock (m_KnownClientFunds)
{
if (!m_KnownClientFunds.ContainsKey(agentID))
{
m_KnownClientFunds.Add(agentID, m_stipend);
}
else
{
if (m_KnownClientFunds[agentID] <= m_minFundsBeforeRefresh)
{
m_KnownClientFunds[agentID] = m_stipend;
}
}
}
}
private int GetFundsForAgentID(LLUUID AgentID)
{
int returnfunds = 0;
lock (m_KnownClientFunds)
{
if (m_KnownClientFunds.ContainsKey(AgentID))
{
returnfunds = m_KnownClientFunds[AgentID];
}
else
{
throw new Exception("Unable to get funds.");
}
}
return returnfunds;
}
public void PostInitialise()
{
}
public void Close()
{
}
public string Name
{
get { return "BetaGridLikeMoneyModule"; }
}
public bool IsSharedModule
{
get { return true; }
}
}
}

View File

@ -13,7 +13,7 @@
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
@ -43,8 +43,9 @@ namespace OpenSim.Region.Environment.Modules
{
public class ChatModule : IRegionModule, ISimChat
{
private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private List<Scene> m_scenes = new List<Scene>();
private LogBase m_log;
private int m_whisperdistance = 10;
private int m_saydistance = 30;
@ -52,12 +53,16 @@ namespace OpenSim.Region.Environment.Modules
private IRCChatModule m_irc = null;
public ChatModule()
{
m_log = MainLog.Instance;
}
private string m_last_new_user = null;
private string m_last_leaving_user = null;
private string m_defaultzone = null;
internal object m_syncInit = new object();
internal object m_syncLogout = new object();
private Thread m_irc_connector=null;
public void Initialise(Scene scene, IConfigSource config)
{
lock (m_syncInit)
{
// wrap this in a try block so that defaults will work if
// the config file doesn't specify otherwise.
@ -70,6 +75,13 @@ namespace OpenSim.Region.Environment.Modules
catch (Exception)
{
}
try
{
m_defaultzone = config.Configs["IRC"].GetString("nick","Sim");
}
catch (Exception)
{
}
if (!m_scenes.Contains(scene))
{
@ -79,14 +91,37 @@ namespace OpenSim.Region.Environment.Modules
}
// setup IRC Relay
m_irc = new IRCChatModule(config);
if (m_irc == null) { m_irc = new IRCChatModule(config); }
if (m_irc_connector == null) {
m_irc_connector = new Thread(IRCConnectRun);
m_irc_connector.Name = "IRCConnectorThread";
m_irc_connector.IsBackground = true;
}
}
}
public void PostInitialise()
{
if (m_irc.Enabled)
{
m_irc.Connect(m_scenes);
try
{
//m_irc.Connect(m_scenes);
if (m_irc_connector == null) {
m_irc_connector = new Thread(IRCConnectRun);
m_irc_connector.Name = "IRCConnectorThread";
m_irc_connector.IsBackground = true;
}
if (!m_irc_connector.IsAlive) {
m_irc_connector.Start();
OpenSim.Framework.ThreadTracker.Add(m_irc_connector);
}
}
catch (Exception ex)
{
}
}
}
@ -106,10 +141,63 @@ namespace OpenSim.Region.Environment.Modules
}
public void NewClient(IClientAPI client)
{
try
{
client.OnChatFromViewer += SimChat;
if ((m_irc.Enabled) && (m_irc.Connected))
{
string clientName = client.FirstName + " " + client.LastName;
// handles simple case. May not work for hundred connecting in per second.
// and the NewClients calles getting interleved
// but filters out multiple reports
if (clientName != m_last_new_user)
{
m_last_new_user = clientName;
string clientRegion = FindClientRegion(client.FirstName, client.LastName);
m_irc.PrivMsg(m_irc.Nick, "Sim", "notices " + clientName + " in "+clientRegion);
}
}
client.OnLogout += ClientLoggedOut;
client.OnConnectionClosed += ClientLoggedOut;
//client.OnDisconnectUser += ClientLoggedOut;
client.OnLogout += ClientLoggedOut;
}
catch (Exception ex)
{
m_log.Error("[IRC]: NewClient exception trap:" + ex.ToString());
}
}
public void ClientLoggedOut(IClientAPI client)
{
lock (m_syncLogout)
{
try
{
if ((m_irc.Enabled) && (m_irc.Connected))
{
string clientName = client.FirstName + " " + client.LastName;
string clientRegion = FindClientRegion(client.FirstName, client.LastName);
// handles simple case. May not work for hundred connecting in per second.
// and the NewClients calles getting interleved
// but filters out multiple reports
if (clientName != m_last_leaving_user)
{
m_last_leaving_user = clientName;
m_irc.PrivMsg(m_irc.Nick, "Sim", "notices " + clientName + " left " + clientRegion);
m_log.Info("[IRC]: IRC watcher notices " + clientName + " left " + clientRegion);
}
}
}
catch (Exception ex)
{
m_log.Error("[IRC]: ClientLoggedOut exception trap:" + ex.ToString());
}
}
}
private void TrySendChatMessage(ScenePresence presence, LLVector3 fromPos, LLVector3 regionPos,
LLUUID fromAgentID, string fromName, ChatTypeEnum type, string message)
{
@ -133,6 +221,8 @@ namespace OpenSim.Region.Environment.Modules
public void SimChat(Object sender, ChatFromViewerArgs e)
{
// FROM: Sim TO: IRC
ScenePresence avatar = null;
//TODO: Move ForEachScenePresence and others into IScene.
@ -144,7 +234,7 @@ namespace OpenSim.Region.Environment.Modules
// Filled in since it's easier than rewriting right now.
LLVector3 fromPos = e.Position;
LLVector3 regionPos = new LLVector3(scene.RegionInfo.RegionLocX*256, scene.RegionInfo.RegionLocY*256, 0);
LLVector3 regionPos = new LLVector3(scene.RegionInfo.RegionLocX * Constants.RegionSize, scene.RegionInfo.RegionLocY * Constants.RegionSize, 0);
string fromName = e.From;
string message = e.Message;
@ -158,11 +248,31 @@ namespace OpenSim.Region.Environment.Modules
if (avatar != null)
{
fromPos = avatar.AbsolutePosition;
regionPos = new LLVector3(scene.RegionInfo.RegionLocX*256, scene.RegionInfo.RegionLocY*256, 0);
regionPos = new LLVector3(scene.RegionInfo.RegionLocX * Constants.RegionSize, scene.RegionInfo.RegionLocY * Constants.RegionSize, 0);
fromName = avatar.Firstname + " " + avatar.Lastname;
fromAgentID = e.Sender.AgentId;
}
// Try to reconnect to server if not connected
if ((m_irc.Enabled)&&(!m_irc.Connected))
{
// In a non-blocking way. Eventually the connector will get it started
try
{
if (m_irc_connector == null) { m_irc_connector = new Thread(IRCConnectRun);
m_irc_connector.Name = "IRCConnectorThread";
m_irc_connector.IsBackground = true;
}
if (!m_irc_connector.IsAlive) {
m_irc_connector.Start();
OpenSim.Framework.ThreadTracker.Add(m_irc_connector);
}
}
catch (Exception ex)
{
}
}
if (e.Message.Length > 0)
{
if (m_irc.Connected && (avatar != null)) // this is to keep objects from talking to IRC
@ -183,15 +293,54 @@ namespace OpenSim.Region.Environment.Modules
}
}
}
// if IRC is enabled then just keep trying using a monitor thread
public void IRCConnectRun()
{
while(true)
{
if ((m_irc.Enabled)&&(!m_irc.Connected))
{
m_irc.Connect(m_scenes);
}
Thread.Sleep(15000);
}
}
public string FindClientRegion(string client_FirstName,string client_LastName)
{
string sourceRegion = null;
foreach (Scene s in m_scenes)
{
s.ForEachScenePresence(delegate(ScenePresence presence)
{
if ((presence.IsChildAgent==false)
&&(presence.Firstname==client_FirstName)
&&(presence.Lastname==client_LastName))
{
sourceRegion = presence.Scene.RegionInfo.RegionName;
//sourceRegion= s.RegionInfo.RegionName;
}
});
if (sourceRegion != null) return sourceRegion;
}
if (m_defaultzone == null) { m_defaultzone = "Sim"; }
return m_defaultzone;
}
}
internal class IRCChatModule
{
private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private string m_server = null;
private uint m_port = 6668;
private string m_user = "USER OpenSimBot 8 * :I'm a OpenSim to irc bot";
private string m_nick = null;
private string m_basenick = null;
private string m_channel = null;
private string m_privmsgformat = "PRIVMSG {0} :<{1} in {2}>: {3}";
private NetworkStream m_stream;
private TcpClient m_tcp;
@ -200,12 +349,13 @@ namespace OpenSim.Region.Environment.Modules
private Thread pingSender;
private Thread listener;
internal object m_syncConnect = new object();
private bool m_enabled = false;
private bool m_connected = false;
private List<Scene> m_scenes = null;
private LogBase m_log;
private List<Scene> m_last_scenes = null;
public IRCChatModule(IConfigSource config)
{
@ -214,43 +364,76 @@ namespace OpenSim.Region.Environment.Modules
m_writer = null;
m_reader = null;
// configuration in OpenSim.ini
// [IRC]
// server = chat.freenode.net
// nick = OSimBot_mysim
// ;username = USER OpenSimBot 8 * :I'm a OpenSim to irc bot
// ; username is the IRC command line sent
// ; USER <irc_user> <visible=8,invisible=0> * : <IRC_realname>
// channel = #opensim-regions
// port = 6667
// ;MSGformat fields : 0=botnick, 1=user, 2=region, 3=message
// ;for <bot>:<user in region> :<message>
// ;msgformat = "PRIVMSG {0} :<{1} in {2}>: {3}"
// ;for <bot>:<message> - <user of region> :
// ;msgformat = "PRIVMSG {0} : {3} - {1} of {2}"
// ;for <bot>:<message> - from <user> :
// ;msgformat = "PRIVMSG {0} : {3} - from {1}"
// Traps I/O disconnects so it does not crash the sim
// Trys to reconnect if disconnected and someone says something
// Tells IRC server "QUIT" when doing a close (just to be nice)
// Default port back to 6667
try
{
m_server = config.Configs["IRC"].GetString("server");
m_nick = config.Configs["IRC"].GetString("nick");
m_basenick = m_nick;
m_channel = config.Configs["IRC"].GetString("channel");
m_port = (uint) config.Configs["IRC"].GetInt("port", (int) m_port);
m_user = config.Configs["IRC"].GetString("username", m_user);
m_privmsgformat = config.Configs["IRC"].GetString("msgformat", m_privmsgformat);
if (m_server != null && m_nick != null && m_channel != null)
{
m_nick = m_nick + Util.RandomClass.Next(1, 99);
m_enabled = true;
}
}
catch (Exception)
{
MainLog.Instance.Verbose("CHAT", "No IRC config information, skipping IRC bridge configuration");
m_log.Info("[CHAT]: No IRC config information, skipping IRC bridge configuration");
}
m_log = MainLog.Instance;
}
public bool Connect(List<Scene> scenes)
{
lock (m_syncConnect)
{
try
{
if (m_connected) return true;
m_scenes = scenes;
if (m_last_scenes == null) { m_last_scenes = scenes; }
m_tcp = new TcpClient(m_server, (int)m_port);
m_log.Verbose("IRC", "Connecting...");
m_log.Info("[IRC]: Connecting...");
m_stream = m_tcp.GetStream();
m_log.Verbose("IRC", "Connected to " + m_server);
m_log.Info("[IRC]: Connected to " + m_server);
m_reader = new StreamReader(m_stream);
m_writer = new StreamWriter(m_stream);
pingSender = new Thread(new ThreadStart(PingRun));
pingSender.Name = "PingSenderThread";
pingSender.IsBackground = true;
pingSender.Start();
OpenSim.Framework.ThreadTracker.Add(pingSender);
listener = new Thread(new ThreadStart(ListenerRun));
listener.Name = "IRCChatModuleListenerThread";
listener.IsBackground = true;
listener.Start();
OpenSim.Framework.ThreadTracker.Add(listener);
m_writer.WriteLine(m_user);
m_writer.Flush();
@ -258,7 +441,7 @@ namespace OpenSim.Region.Environment.Modules
m_writer.Flush();
m_writer.WriteLine("JOIN " + m_channel);
m_writer.Flush();
m_log.Verbose("IRC", "Connection fully established");
m_log.Info("[IRC]: Connection fully established");
m_connected = true;
}
catch (Exception e)
@ -267,6 +450,7 @@ namespace OpenSim.Region.Environment.Modules
}
return m_connected;
}
}
public bool Enabled
{
@ -278,26 +462,60 @@ namespace OpenSim.Region.Environment.Modules
get { return m_connected; }
}
public string Nick
{
get { return m_nick; }
}
public void Reconnect()
{
m_connected = false;
listener.Abort();
pingSender.Abort();
m_writer.Close();
m_reader.Close();
m_tcp.Close();
if (m_enabled) { Connect(m_last_scenes); }
}
public void PrivMsg(string from, string region, string msg)
{
// One message to the IRC server
try
{
if (m_privmsgformat == null)
{
m_writer.WriteLine("PRIVMSG {0} :<{1} in {2}>: {3}", m_channel, from, region, msg);
}
else
{
m_writer.WriteLine(m_privmsgformat, m_channel, from, region, msg);
}
m_writer.Flush();
m_log.Info("[IRC]: PrivMsg " + from + " in " + region + " :" + msg);
}
catch (IOException)
{
m_log.Error("IRC", "Disconnected from IRC server.");
listener.Abort();
pingSender.Abort();
m_connected = false;
m_log.Error("[IRC]: Disconnected from IRC server.(PrivMsg)");
Reconnect();
}
catch (Exception ex)
{
m_log.Error("[IRC]: PrivMsg exception trap:" + ex.ToString());
}
}
private Dictionary<string, string> ExtractMsg(string input)
{
//examines IRC commands and extracts any private messages
// which will then be reboadcast in the Sim
m_log.Info("[IRC]: ExtractMsg: " + input);
Dictionary<string, string> result = null;
string regex = @":(?<nick>\w*)!~(?<user>\S*) PRIVMSG (?<channel>\S+) :(?<msg>.*)";
//string regex = @":(?<nick>\w*)!~(?<user>\S*) PRIVMSG (?<channel>\S+) :(?<msg>.*)";
string regex = @":(?<nick>\w*)!(?<user>\S*) PRIVMSG (?<channel>\S+) :(?<msg>.*)";
Regex RE = new Regex(regex, RegexOptions.Multiline);
MatchCollection matches = RE.Matches(input);
// Get some direct matches $1 $4 is a
@ -311,10 +529,10 @@ namespace OpenSim.Region.Environment.Modules
}
else
{
m_log.Verbose("IRC", "Number of matches: " + matches.Count);
m_log.Info("[IRC]: Number of matches: " + matches.Count);
if (matches.Count > 0)
{
m_log.Verbose("IRC", "Number of groups: " + matches[0].Groups.Count);
m_log.Info("[IRC]: Number of groups: " + matches[0].Groups.Count);
}
}
return result;
@ -322,13 +540,30 @@ namespace OpenSim.Region.Environment.Modules
public void PingRun()
{
// IRC keep alive thread
// send PING ever 15 seconds
while (true)
{
try
{
if (m_connected == true)
{
m_writer.WriteLine("PING :" + m_server);
m_writer.Flush();
Thread.Sleep(15000);
}
}
catch (IOException)
{
m_log.Error("[IRC]: Disconnected from IRC server.(PingRun)");
Reconnect();
}
catch (Exception ex)
{
m_log.Error("[IRC]: PingRun exception trap:" + ex.ToString() + "\n" + ex.StackTrace);
}
}
}
public void ListenerRun()
{
@ -336,12 +571,15 @@ namespace OpenSim.Region.Environment.Modules
LLVector3 pos = new LLVector3(128, 128, 20);
while (true)
{
while ((inputLine = m_reader.ReadLine()) != null)
try
{
while ((m_connected == true) && ((inputLine = m_reader.ReadLine()) != null))
{
// Console.WriteLine(inputLine);
if (inputLine.Contains(m_channel))
{
Dictionary<string, string> data = ExtractMsg(inputLine);
// Any chat ???
if (data != null)
{
foreach (Scene m_scene in m_scenes)
@ -357,15 +595,239 @@ namespace OpenSim.Region.Environment.Modules
}
});
}
}
else
{
// Was an command from the IRC server
ProcessIRCCommand(inputLine);
}
}
else
{
// Was an command from the IRC server
ProcessIRCCommand(inputLine);
}
Thread.Sleep(150);
}
}
catch (IOException)
{
m_log.Error("[IRC]: ListenerRun IOException. Disconnected from IRC server ??? (ListenerRun)");
Reconnect();
}
catch (Exception ex)
{
m_log.Error("[IRC]: ListenerRun exception trap:" + ex.ToString() + "\n" + ex.StackTrace);
}
Thread.Sleep(50);
}
}
public void BroadcastSim(string message,string sender)
{
LLVector3 pos = new LLVector3(128, 128, 20);
try
{
foreach (Scene m_scene in m_scenes)
{
m_scene.ForEachScenePresence(delegate(ScenePresence avatar)
{
if (!avatar.IsChildAgent)
{
avatar.ControllingClient.SendChatMessage(
Helpers.StringToField(message), 255,
pos, sender,
LLUUID.Zero);
}
});
}
}
catch (Exception ex) // IRC gate should not crash Sim
{
m_log.Error("[IRC]: BroadcastSim Exception Trap:" + ex.ToString() + "\n" + ex.StackTrace);
}
}
public enum ErrorReplies
{
NotRegistered = 451, // ":You have not registered"
NicknameInUse = 433 // "<nick> :Nickname is already in use"
}
public enum Replies
{
MotdStart = 375, // ":- <server> Message of the day - "
Motd = 372, // ":- <text>"
EndOfMotd = 376 // ":End of /MOTD command"
}
public void ProcessIRCCommand(string command)
{
//m_log.Info("[IRC]: ProcessIRCCommand:" + command);
string[] commArgs = new string[command.Split(' ').Length];
string c_server = m_server;
commArgs = command.Split(' ');
if (commArgs[0].Substring(0, 1) == ":")
{
commArgs[0] = commArgs[0].Remove(0, 1);
}
if (commArgs[1] == "002")
{
// fetch the correct servername
// ex: irc.freenode.net -> brown.freenode.net/kornbluth.freenode.net/...
// irc.bluewin.ch -> irc1.bluewin.ch/irc2.bluewin.ch
c_server = (commArgs[6].Split('['))[0];
m_server = c_server;
}
if (commArgs[0] == "ERROR")
{
m_log.Error("[IRC]: IRC SERVER ERROR:" + command);
}
if (commArgs[0] == "PING")
{
string p_reply = "";
for (int i = 1; i < commArgs.Length; i++)
{
p_reply += commArgs[i] + " ";
}
m_writer.WriteLine("PONG " + p_reply);
m_writer.Flush();
}
else if (commArgs[0] == c_server)
{
// server message
try
{
Int32 commandCode = Int32.Parse(commArgs[1]);
switch (commandCode)
{
case (int)ErrorReplies.NicknameInUse:
// Gen a new name
m_nick = m_basenick + Util.RandomClass.Next(1, 99);
m_log.Error("[IRC]: IRC SERVER reports NicknameInUse, trying " + m_nick);
// Retry
m_writer.WriteLine("NICK " + m_nick);
m_writer.Flush();
m_writer.WriteLine("JOIN " + m_channel);
m_writer.Flush();
break;
case (int)ErrorReplies.NotRegistered:
break;
case (int)Replies.EndOfMotd:
break;
}
}
catch (Exception ex)
{
}
}
else
{
// Normal message
string commAct = commArgs[1];
switch (commAct)
{
case "JOIN": eventIrcJoin(commArgs); break;
case "PART": eventIrcPart(commArgs); break;
case "MODE": eventIrcMode(commArgs); break;
case "NICK": eventIrcNickChange(commArgs); break;
case "KICK": eventIrcKick(commArgs); break;
case "QUIT": eventIrcQuit(commArgs); break;
case "PONG": break; // that's nice
}
}
}
public void eventIrcJoin(string[] commArgs)
{
string IrcChannel = commArgs[2];
string IrcUser = commArgs[0].Split('!')[0];
BroadcastSim(IrcUser + " is joining " + IrcChannel, m_nick);
}
public void eventIrcPart(string[] commArgs)
{
string IrcChannel = commArgs[2];
string IrcUser = commArgs[0].Split('!')[0];
BroadcastSim(IrcUser + " is parting " + IrcChannel, m_nick);
}
public void eventIrcMode(string[] commArgs)
{
string IrcChannel = commArgs[2];
string IrcUser = commArgs[0].Split('!')[0];
string UserMode = "";
for (int i = 3; i < commArgs.Length; i++)
{
UserMode += commArgs[i] + " ";
}
if (UserMode.Substring(0, 1) == ":")
{
UserMode = UserMode.Remove(0, 1);
}
}
public void eventIrcNickChange(string[] commArgs)
{
string UserOldNick = commArgs[0].Split('!')[0];
string UserNewNick = commArgs[2].Remove(0, 1);
BroadcastSim(UserOldNick + " changed their nick to " + UserNewNick, m_nick);
}
public void eventIrcKick(string[] commArgs)
{
string UserKicker = commArgs[0].Split('!')[0];
string UserKicked = commArgs[3];
string IrcChannel = commArgs[2];
string KickMessage = "";
for (int i = 4; i < commArgs.Length; i++)
{
KickMessage += commArgs[i] + " ";
}
BroadcastSim(UserKicker + " kicked " + UserKicked +" on "+IrcChannel+" saying "+KickMessage, m_nick);
if (UserKicked == m_nick)
{
BroadcastSim("Hey, that was me!!!", m_nick);
}
}
public void eventIrcQuit(string[] commArgs)
{
string IrcUser = commArgs[0].Split('!')[0];
string QuitMessage = "";
for (int i = 2; i < commArgs.Length; i++)
{
QuitMessage += commArgs[i] + " ";
}
BroadcastSim(IrcUser + " quits saying " + QuitMessage, m_nick);
}
public void Close()
{
m_connected = false;
m_writer.WriteLine("QUIT :" + m_nick + " to " + m_channel + " wormhole with " + m_server + " closing");
m_writer.Flush();
listener.Abort();
pingSender.Abort();
m_writer.Close();

View File

@ -13,7 +13,7 @@
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
@ -176,7 +176,7 @@ namespace OpenSim.Region.Environment.Modules
asset.Type = 0;
asset.Description = "dynamic image";
asset.Local = false;
asset.Temporary = false;
asset.Temporary = true;
scene.AssetCache.AddAsset(asset);
LastAssetID = asset.FullID;

View File

@ -13,7 +13,7 @@
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY

View File

@ -13,7 +13,7 @@
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
@ -40,8 +40,7 @@ namespace OpenSim.Region.Environment.Modules
{
public class FriendsModule : IRegionModule
{
private LogBase m_log;
private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private Scene m_scene;
@ -49,7 +48,6 @@ namespace OpenSim.Region.Environment.Modules
public void Initialise(Scene scene, IConfigSource config)
{
m_log = MainLog.Instance;
m_scene = scene;
scene.EventManager.OnNewClient += OnNewClient;
scene.EventManager.OnGridInstantMessageToFriendsModule += OnGridInstantMessage;
@ -72,6 +70,7 @@ namespace OpenSim.Region.Environment.Modules
}
private void OnInstantMessage(IClientAPI client,LLUUID fromAgentID,
LLUUID fromAgentSession, LLUUID toAgentID,
LLUUID imSessionID, uint timestamp, string fromAgentName,
@ -89,13 +88,13 @@ namespace OpenSim.Region.Environment.Modules
m_pendingFriendRequests.Add(friendTransactionID, fromAgentID);
m_log.Verbose("FRIEND", "38 - From:" + fromAgentID.ToString() + " To: " + toAgentID.ToString() + " Session:" + imSessionID.ToString() + " Message:" + message);
m_log.Info("[FRIEND]: 38 - From:" + fromAgentID.ToString() + " To: " + toAgentID.ToString() + " Session:" + imSessionID.ToString() + " Message:" + message);
GridInstantMessage msg = new GridInstantMessage();
msg.fromAgentID = fromAgentID.UUID;
msg.fromAgentSession = fromAgentSession.UUID;
msg.toAgentID = toAgentID.UUID;
msg.imSessionID = friendTransactionID.UUID; // This is the item we're mucking with here
m_log.Verbose("FRIEND","Filling Session: " + msg.imSessionID.ToString());
m_log.Info("[FRIEND]: Filling Session: " + msg.imSessionID.ToString());
msg.timestamp = timestamp;
if (client != null)
{
@ -115,20 +114,18 @@ namespace OpenSim.Region.Environment.Modules
msg.binaryBucket = binaryBucket;
m_scene.TriggerGridInstantMessage(msg, InstantMessageReceiver.IMModule);
}
if (dialog == (byte)39)
{
m_log.Verbose("FRIEND", "38 - From:" + fromAgentID.ToString() + " To: " + toAgentID.ToString() + " Session:" + imSessionID.ToString() + " Message:" + message);
}
if (dialog == (byte)40)
{
m_log.Verbose("FRIEND", "38 - From:" + fromAgentID.ToString() + " To: " + toAgentID.ToString() + " Session:" + imSessionID.ToString() + " Message:" + message);
}
// 39 == Accept Friendship
if (dialog == (byte)39)
{
m_log.Info("[FRIEND]: 39 - From:" + fromAgentID.ToString() + " To: " + toAgentID.ToString() + " Session:" + imSessionID.ToString() + " Message:" + message);
}
// 40 == Decline Friendship
if (dialog == (byte)40)
{
m_log.Info("[FRIEND]: 40 - From:" + fromAgentID.ToString() + " To: " + toAgentID.ToString() + " Session:" + imSessionID.ToString() + " Message:" + message);
}
}
private void OnApprovedFriendRequest(IClientAPI client, LLUUID agentID, LLUUID transactionID, List<LLUUID> callingCardFolders)
@ -160,6 +157,7 @@ namespace OpenSim.Region.Environment.Modules
// TODO: Inform agent that the friend is online
}
}
private void OnDenyFriendRequest(IClientAPI client, LLUUID agentID, LLUUID transactionID, List<LLUUID> callingCardFolders)
{
if (m_pendingFriendRequests.ContainsKey(transactionID))
@ -184,20 +182,15 @@ namespace OpenSim.Region.Environment.Modules
msg.binaryBucket = new byte[0];
m_scene.TriggerGridInstantMessage(msg, InstantMessageReceiver.IMModule);
m_pendingFriendRequests.Remove(transactionID);
}
}
private void OnTerminateFriendship(IClientAPI client, LLUUID agent, LLUUID exfriendID)
{
m_scene.StoreRemoveFriendship(agent, exfriendID);
// TODO: Inform the client that the ExFriend is offline
}
private void OnGridInstantMessage(GridInstantMessage msg)
{
// Trigger the above event handler
@ -206,16 +199,12 @@ namespace OpenSim.Region.Environment.Modules
msg.message, msg.dialog, msg.fromGroup, msg.offline, msg.ParentEstateID,
new LLVector3(msg.Position.x, msg.Position.y, msg.Position.z), new LLUUID(msg.RegionID),
msg.binaryBucket);
}
public void PostInitialise()
{
}
public void Close()
{
}

View File

@ -13,7 +13,7 @@
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
@ -27,18 +27,182 @@
*/
using Nini.Config;
using System;
using System.Collections;
using System.Collections.Generic;
using OpenSim.Framework;
using OpenSim.Framework.Console;
using OpenSim.Region.Environment.Interfaces;
using OpenSim.Region.Environment.Scenes;
using libsecondlife;
namespace OpenSim.Region.Environment.Modules
{
public class GroupsModule : IRegionModule
{
private Scene m_scene;
private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private List<Scene> m_scene = new List<Scene>();
private Dictionary<LLUUID, IClientAPI> m_iclientmap = new Dictionary<LLUUID, IClientAPI>();
private Dictionary<LLUUID, GroupData> m_groupmap = new Dictionary<LLUUID, GroupData>();
private Dictionary<LLUUID, GroupList> m_grouplistmap = new Dictionary<LLUUID, GroupList>();
public void Initialise(Scene scene, IConfigSource config)
{
m_scene = scene;
lock (m_scene)
{
m_scene.Add(scene);
}
scene.EventManager.OnNewClient += OnNewClient;
scene.EventManager.OnClientClosed += OnClientClosed;
scene.EventManager.OnGridInstantMessageToGroupsModule += OnGridInstantMessage;
//scene.EventManager.
}
private void OnNewClient(IClientAPI client)
{
// All friends establishment protocol goes over instant message
// There's no way to send a message from the sim
// to a user to 'add a friend' without causing dialog box spam
//
// The base set of friends are added when the user signs on in their XMLRPC response
// Generated by LoginService. The friends are retreived from the database by the UserManager
// Subscribe to instant messages
client.OnInstantMessage += OnInstantMessage;
client.OnAgentDataUpdateRequest += OnAgentDataUpdateRequest;
lock (m_iclientmap)
{
if (!m_iclientmap.ContainsKey(client.AgentId))
{
m_iclientmap.Add(client.AgentId, client);
}
}
GroupData OpenSimulatorGroup = new GroupData();
OpenSimulatorGroup.ActiveGroupTitle = "OpenSimulator Tester";
OpenSimulatorGroup.GroupID = new LLUUID("00000000-68f9-1111-024e-222222111120");
OpenSimulatorGroup.GroupMembers.Add(client.AgentId);
OpenSimulatorGroup.groupName = "OpenSimulator Testing";
OpenSimulatorGroup.ActiveGroupPowers = GroupPowers.LandAllowSetHome;
OpenSimulatorGroup.GroupTitles.Add("OpenSimulator Tester");
lock (m_groupmap)
{
if (!m_groupmap.ContainsKey(client.AgentId))
{
m_groupmap.Add(client.AgentId, OpenSimulatorGroup);
}
}
GroupList testGroupList = new GroupList();
testGroupList.m_GroupList.Add(new LLUUID("00000000-68f9-1111-024e-222222111120"));
lock (m_grouplistmap)
{
if (!m_grouplistmap.ContainsKey(client.AgentId))
{
m_grouplistmap.Add(client.AgentId, testGroupList);
}
}
m_log.Info("[GROUP]: Adding " + client.FirstName + " " + client.LastName + " to OpenSimulator Tester group");
}
private void OnAgentDataUpdateRequest(IClientAPI remoteClient, LLUUID AgentID, LLUUID SessionID)
{
string firstname = remoteClient.FirstName;
string lastname = remoteClient.LastName;
LLUUID ActiveGroupID = LLUUID.Zero;
uint ActiveGroupPowers = 0;
string ActiveGroupName = "";
string ActiveGroupTitle = "";
bool foundUser = false;
lock (m_iclientmap)
{
if (m_iclientmap.ContainsKey(remoteClient.AgentId))
{
foundUser = true;
}
}
if (foundUser)
{
lock (m_groupmap)
{
if (m_groupmap.ContainsKey(remoteClient.AgentId))
{
GroupData grp = m_groupmap[remoteClient.AgentId];
if (grp != null)
{
ActiveGroupID = grp.GroupID;
ActiveGroupName = grp.groupName;
ActiveGroupPowers = grp.groupPowers;
ActiveGroupTitle = grp.ActiveGroupTitle;
}
//remoteClient.SendAgentDataUpdate(AgentID, ActiveGroupID, firstname, lastname, ActiveGroupPowers, ActiveGroupName, ActiveGroupTitle);
}
}
}
}
private void OnInstantMessage(IClientAPI client, LLUUID fromAgentID,
LLUUID fromAgentSession, LLUUID toAgentID,
LLUUID imSessionID, uint timestamp, string fromAgentName,
string message, byte dialog, bool fromGroup, byte offline,
uint ParentEstateID, LLVector3 Position, LLUUID RegionID,
byte[] binaryBucket)
{
}
private void OnGridInstantMessage(GridInstantMessage msg)
{
// Trigger the above event handler
OnInstantMessage(null, new LLUUID(msg.fromAgentID), new LLUUID(msg.fromAgentSession),
new LLUUID(msg.toAgentID), new LLUUID(msg.imSessionID), msg.timestamp, msg.fromAgentName,
msg.message, msg.dialog, msg.fromGroup, msg.offline, msg.ParentEstateID,
new LLVector3(msg.Position.x, msg.Position.y, msg.Position.z), new LLUUID(msg.RegionID),
msg.binaryBucket);
}
private void OnClientClosed(LLUUID agentID)
{
lock (m_iclientmap)
{
if (m_iclientmap.ContainsKey(agentID))
{
IClientAPI cli = m_iclientmap[agentID];
if (cli != null)
{
m_log.Info("[GROUP]: Removing all reference to groups for " + cli.FirstName + " " + cli.LastName);
}
else
{
m_log.Info("[GROUP]: Removing all reference to groups for " + agentID.ToString());
}
m_iclientmap.Remove(agentID);
}
}
lock (m_groupmap)
{
if (m_groupmap.ContainsKey(agentID))
{
m_groupmap.Remove(agentID);
}
}
lock (m_grouplistmap)
{
if (m_grouplistmap.ContainsKey(agentID))
{
m_grouplistmap.Remove(agentID);
}
}
GC.Collect();
}
public void PostInitialise()
@ -47,6 +211,22 @@ namespace OpenSim.Region.Environment.Modules
public void Close()
{
m_log.Info("[GROUP]: Shutting down group module.");
lock (m_iclientmap)
{
m_iclientmap.Clear();
}
lock (m_groupmap)
{
m_groupmap.Clear();
}
lock (m_grouplistmap)
{
m_grouplistmap.Clear();
}
GC.Collect();
}
public string Name
@ -56,7 +236,44 @@ namespace OpenSim.Region.Environment.Modules
public bool IsSharedModule
{
get { return false; }
get { return true; }
}
}
public class GroupData
{
public LLUUID GroupID;
public string groupName;
public string ActiveGroupTitle;
public List<string> GroupTitles;
public List<LLUUID> GroupMembers;
public uint groupPowers = (uint)(GroupPowers.LandAllowLandmark | GroupPowers.LandAllowSetHome);
public GroupPowers ActiveGroupPowers
{
set
{
groupPowers = (uint) value;
}
get
{
return (GroupPowers)groupPowers;
}
}
public GroupData()
{
GroupTitles = new List<string>();
GroupMembers = new List<LLUUID>();
}
}
public class GroupList
{
public List<LLUUID> m_GroupList;
public GroupList()
{
m_GroupList = new List<LLUUID>();
}
}
}

View File

@ -13,7 +13,7 @@
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
@ -39,12 +39,6 @@ namespace OpenSim.Region.Environment.Modules
public class InstantMessageModule : IRegionModule
{
private List<Scene> m_scenes = new List<Scene>();
private LogBase m_log;
public InstantMessageModule()
{
m_log = MainLog.Instance;
}
public void Initialise(Scene scene, IConfigSource config)
{
@ -68,7 +62,6 @@ namespace OpenSim.Region.Environment.Modules
uint ParentEstateID, LLVector3 Position, LLUUID RegionID,
byte[] binaryBucket)
{
bool FriendDialog = ((dialog == (byte)38) || (dialog == (byte)39) || (dialog == (byte)40));
// IM dialogs need to be pre-processed and have their sessionID filled by the server

View File

@ -13,7 +13,7 @@
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY

View File

@ -126,7 +126,35 @@ namespace OpenSim.Region.Environment.Modules
if (response.StatusCode == HttpStatusCode.OK)
{
Bitmap image = new Bitmap(response.GetResponseStream());
Bitmap resize = new Bitmap(image, new Size(512, 512));
Size newsize;
// TODO: make this a bit less hard coded
if ((image.Height < 64) && (image.Width < 64))
{
newsize = new Size(32, 32);
}
else if ((image.Height < 128) && (image.Width < 128))
{
newsize = new Size(64, 64);
}
else if ((image.Height <256) && (image.Width < 256))
{
newsize = new Size(128, 128);
}
else if ((image.Height < 512 && image.Width < 512))
{
newsize = new Size(256, 256);
}
else if ((image.Height < 1024 && image.Width < 1024))
{
newsize = new Size(512, 512);
}
else
{
newsize = new Size(1024,1024);
}
Bitmap resize = new Bitmap(image, newsize);
byte[] imageJ2000 = OpenJPEG.EncodeFromImage(resize, true);
m_textureManager.ReturnData(state.RequestID, imageJ2000);

View File

@ -13,7 +13,7 @@
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
@ -88,7 +88,7 @@ namespace OpenSim.Region.Environment.Modules
private Queue<HttpRequestClass> rpcQueue = new Queue<HttpRequestClass>();
private object HttpListLock = new object();
private string m_name = "HttpScriptRequests";
private int httpTimeout = 300;
private int httpTimeout = 30000;
// <request id, HttpRequestClass>
private Dictionary<LLUUID, HttpRequestClass> m_pendingRequests;
@ -184,6 +184,7 @@ namespace OpenSim.Region.Environment.Modules
public void StopHttpRequest(uint m_localID, LLUUID m_itemID)
{
if(m_pendingRequests != null) {
lock (HttpListLock)
{
HttpRequestClass tmpReq;
@ -194,6 +195,7 @@ namespace OpenSim.Region.Environment.Modules
}
}
}
}
/*
* TODO
@ -216,7 +218,6 @@ namespace OpenSim.Region.Environment.Modules
{
if (tmpReq.finished)
{
m_pendingRequests.Remove(luid);
return tmpReq;
}
}
@ -224,6 +225,21 @@ namespace OpenSim.Region.Environment.Modules
}
return null;
}
public void RemoveCompletedRequest(LLUUID id)
{
lock (HttpListLock)
{
HttpRequestClass tmpReq;
if (m_pendingRequests.TryGetValue(id, out tmpReq))
{
tmpReq.Stop();
tmpReq = null;
m_pendingRequests.Remove(id);
}
}
}
}
//
@ -269,7 +285,9 @@ namespace OpenSim.Region.Environment.Modules
httpThread.Name = "HttpRequestThread";
httpThread.Priority = ThreadPriority.BelowNormal;
httpThread.IsBackground = true;
finished = false;
httpThread.Start();
OpenSim.Framework.ThreadTracker.Add(httpThread);
}
/*

View File

@ -13,7 +13,7 @@
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
@ -39,6 +39,8 @@ namespace OpenSim.Region.Environment.Modules
{
public class SunModule : IRegionModule
{
//private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private const double m_real_day = 24.0;
private const int m_default_frame = 100;
private int m_frame_mod;
@ -48,7 +50,6 @@ namespace OpenSim.Region.Environment.Modules
private long m_start;
private Scene m_scene;
private LogBase m_log;
public void Initialise(Scene scene, IConfigSource config)
{
@ -69,7 +70,6 @@ namespace OpenSim.Region.Environment.Modules
m_dilation = (int) (m_real_day/m_day_length);
m_scene = scene;
m_log = MainLog.Instance;
scene.EventManager.OnFrame += SunUpdate;
scene.EventManager.OnNewClient += SunToClient;
}
@ -104,7 +104,7 @@ namespace OpenSim.Region.Environment.Modules
m_frame++;
return;
}
// m_log.Verbose("SUN","I've got an update {0} => {1}", m_scene.RegionsInfo.RegionName, HourOfTheDay());
// m_log.InfoFormat("[SUN]: I've got an update {0} => {1}", m_scene.RegionsInfo.RegionName, HourOfTheDay());
List<ScenePresence> avatars = m_scene.GetAvatars();
foreach (ScenePresence avatar in avatars)
{

View File

@ -13,7 +13,7 @@
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY

View File

@ -0,0 +1,126 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSim Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
using Nini.Config;
using System;
using System.Collections;
using System.Collections.Generic;
using OpenSim.Framework;
using OpenSim.Framework.Console;
using OpenSim.Region.Environment.Modules;
using OpenSim.Region.Environment.Interfaces;
using OpenSim.Region.Environment.Scenes;
using libsecondlife;
namespace OpenSim.Region.Environment.Modules.Terrain
{
/// <summary>
/// A new version of the old Channel class, simplified
/// </summary>
public class TerrainChannel : ITerrainChannel
{
private double[,] map;
public int Width
{
get { return map.GetLength(0); }
}
public int Height
{
get { return map.GetLength(1); }
}
public TerrainChannel Copy()
{
TerrainChannel copy = new TerrainChannel(false);
copy.map = (double[,])this.map.Clone();
return copy;
}
public double this[int x, int y]
{
get
{
return map[x, y];
}
set
{
map[x, y] = value;
}
}
public TerrainChannel()
{
map = new double[Constants.RegionSize, Constants.RegionSize];
}
public TerrainChannel(bool createMap)
{
if (createMap)
map = new double[Constants.RegionSize, Constants.RegionSize];
}
public TerrainChannel(int w, int h)
{
map = new double[w, h];
}
}
public class TerrainModule : IRegionModule
{
Scene m_scene;
private IConfigSource m_gConfig;
public void Initialise(Scene scene, IConfigSource config)
{
m_scene = scene;
m_gConfig = config;
}
public void Close()
{
}
public string Name
{
get { return "TerrainModule"; }
}
public bool IsSharedModule
{
get { return false; }
}
public void PostInitialise()
{
}
}
}

View File

@ -13,7 +13,7 @@
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
@ -41,14 +41,22 @@ namespace OpenSim.Region.Environment.Modules
//this is a first attempt, to start breaking the mess thats called the assetcache up.
// basically this should be the texture sending (to clients) code moved out of assetcache
//and some small clean up
// but on first tests it didn't seem to work very well so is currently not in use.
public class TextureDownloadModule : IRegionModule
{
//private static readonly log4net.ILog m_log
// = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private Scene m_scene;
private List<Scene> m_scenes = new List<Scene>();
/// <summary>
/// There is one queue for all textures waiting to be sent, regardless of the requesting user.
/// </summary>
private readonly BlockingQueue<TextureSender> m_queueSenders = new BlockingQueue<TextureSender>();
/// <summary>
/// Each user has their own texture download service.
/// </summary>
private readonly Dictionary<LLUUID, UserTextureDownloadService> m_userTextureServices =
new Dictionary<LLUUID, UserTextureDownloadService>();
@ -64,8 +72,10 @@ namespace OpenSim.Region.Environment.Modules
{
//Console.WriteLine("Creating Texture download module");
m_thread = new Thread(new ThreadStart(ProcessTextureSenders));
m_thread.Name = "ProcessTextureSenderThread";
m_thread.IsBackground = true;
m_thread.Start();
OpenSim.Framework.ThreadTracker.Add(m_thread);
}
if (!m_scenes.Contains(scene))
@ -77,6 +87,10 @@ namespace OpenSim.Region.Environment.Modules
}
}
/// <summary>
/// Cleanup the texture service related objects for the removed presence.
/// </summary>
/// <param name="agentId"> </param>
private void EventManager_OnRemovePresence(LLUUID agentId)
{
UserTextureDownloadService textureService;
@ -115,6 +129,12 @@ namespace OpenSim.Region.Environment.Modules
client.OnRequestTexture += TextureRequest;
}
/// <summary>
/// Does this user have a registered texture download service?
/// </summary>
/// <param name="userID"></param>
/// <param name="textureService"></param>
/// <returns>Always returns true, since a service is created if one does not already exist</returns>
private bool TryGetUserTextureService(LLUUID userID, out UserTextureDownloadService textureService)
{
lock (m_userTextureServices)
@ -130,6 +150,11 @@ namespace OpenSim.Region.Environment.Modules
}
}
/// <summary>
/// Start the process of requesting a given texture.
/// </summary>
/// <param name="sender"> </param>
/// <param name="e"></param>
public void TextureRequest(Object sender, TextureRequestArgs e)
{
IClientAPI client = (IClientAPI) sender;
@ -140,11 +165,17 @@ namespace OpenSim.Region.Environment.Modules
}
}
/// <summary>
/// Entry point for the thread dedicated to processing the texture queue.
/// </summary>
public void ProcessTextureSenders()
{
TextureSender sender = null;
while (true)
{
TextureSender sender = m_queueSenders.Dequeue();
sender = m_queueSenders.Dequeue();
if (sender.Cancel)
{
TextureSent(sender);
@ -163,12 +194,23 @@ namespace OpenSim.Region.Environment.Modules
m_queueSenders.Enqueue(sender);
}
}
// Make sure that any sender we currently have can get garbage collected
sender = null;
//m_log.InfoFormat("[TEXTURE DOWNLOAD] Texture sender queue size: {0}", m_queueSenders.Count());
}
}
/// <summary>
/// Called when the texture has finished sending.
/// </summary>
/// <param name="sender"></param>
private void TextureSent(TextureSender sender)
{
sender.Sending = false;
//m_log.DebugFormat("[TEXTURE DOWNLOAD]: Removing download stat for {0}", sender.assetID);
m_scene.AddPendingDownloads(-1);
}
}
}

View File

@ -1,3 +1,31 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSim Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
using System;
using libsecondlife;
using libsecondlife.Packets;
@ -6,33 +34,61 @@ using OpenSim.Framework.Console;
namespace OpenSim.Region.Environment.Modules
{
/// <summary>
/// A TextureSender handles the process of receiving a texture requested by the client from the
/// AssetCache, and then sending that texture back to the client.
/// </summary>
public class TextureSender
{
private static readonly log4net.ILog m_log
= log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
/// <summary>
/// Records the number of times texture send has been called.
/// </summary>
public int counter = 0;
/// <summary>
/// Holds the texture asset to send.
/// </summary>
private AssetBase m_asset;
public long DataPointer = 0;
public int NumPackets = 0;
public int PacketCounter = 0;
//public LLUUID assetID { get { return m_asset.FullID; } }
/// <summary>
/// This is actually the number of extra packets required to send the texture data! We always assume
/// at least one is required.
/// </summary>
private int NumPackets = 0;
/// <summary>
/// Holds the packet number to send next. In this case, each packet is 1000 bytes long and starts
/// at the 600th byte (0th indexed).
/// </summary>
private int PacketCounter = 0;
public bool Cancel = false;
public bool ImageLoaded = false;
public bool Sending = false;
public IClientAPI RequestUser;
public LLUUID RequestedAssetID;
public int RequestedDiscardLevel = -1;
public uint StartPacketNumber = 0;
private IClientAPI RequestUser;
// private int m_sentDiscardLevel = -1;
private int RequestedDiscardLevel = -1;
private uint StartPacketNumber = 0;
public TextureSender(IClientAPI client, LLUUID textureID, int discardLevel, uint packetNumber)
public TextureSender(IClientAPI client, int discardLevel, uint packetNumber)
{
RequestUser = client;
RequestedAssetID = textureID;
RequestedDiscardLevel = discardLevel;
StartPacketNumber = packetNumber;
}
/// <summary>
/// Load up the texture data to send.
/// </summary>
/// <param name="asset">
/// A <see cref="AssetBase"/>
/// </param>
public void TextureReceived(AssetBase asset)
{
m_asset = asset;
@ -48,6 +104,10 @@ namespace OpenSim.Region.Environment.Modules
PacketCounter = (int) StartPacketNumber;
}
/// <summary>
/// Send a texture packet to the client.
/// </summary>
/// <returns>True if the last packet has been sent, false otherwise.</returns>
public bool SendTexturePacket()
{
SendPacket();
@ -60,6 +120,9 @@ namespace OpenSim.Region.Environment.Modules
return false;
}
/// <summary>
/// Sends a texture packet to the client.
/// </summary>
private void SendPacket()
{
if (PacketCounter <= NumPackets)
@ -107,8 +170,7 @@ namespace OpenSim.Region.Environment.Modules
}
catch (ArgumentOutOfRangeException)
{
MainLog.Instance.Error("TEXTURE",
"Unable to separate texture into multiple packets: Array bounds failure on asset:" +
m_log.Error("[TEXTURE]: Unable to separate texture into multiple packets: Array bounds failure on asset:" +
m_asset.FullID.ToString() );
return;
}
@ -118,6 +180,12 @@ namespace OpenSim.Region.Environment.Modules
}
}
/// <summary>
/// Calculate the number of packets that will be required to send the texture loaded into this sender
/// This is actually the number of 1000 byte packets not including an initial 600 byte packet...
/// </summary>
/// <param name="length"></param>
/// <returns></returns>
private int CalculateNumPackets(int length)
{
int numPackets = 0;

View File

@ -0,0 +1,246 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSim Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
using System;
using System.Collections.Generic;
using libsecondlife;
using Nini.Config;
using OpenSim.Framework;
using OpenSim.Framework.Console;
using OpenSim.Region.Environment.Interfaces;
using OpenSim.Region.Environment.Scenes;
namespace OpenSim.Region.Environment.Modules
{
/// <summary>
/// Version 2.0 - Very hacky compared to the original. Will fix original and release as 0.3 later.
/// </summary>
public class TreePopulatorModule : IRegionModule
{
private Scene m_scene;
private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private List<LLUUID> m_trees;
public double m_tree_density = 50.0; // Aim for this many per region
public double m_tree_updates = 1000.0; // MS between updates
public void Initialise(Scene scene, IConfigSource config)
{
try
{
m_tree_density = config.Configs["Trees"].GetDouble("tree_density", m_tree_density);
}
catch (Exception)
{ }
m_trees = new List<LLUUID>();
m_scene = scene;
m_scene.EventManager.OnPluginConsole += new EventManager.OnPluginConsoleDelegate(EventManager_OnPluginConsole);
System.Timers.Timer CalculateTrees = new System.Timers.Timer(m_tree_updates);
CalculateTrees.Elapsed += new System.Timers.ElapsedEventHandler(CalculateTrees_Elapsed);
CalculateTrees.Start();
m_log.Debug("[TREES]: Initialised tree module");
}
void EventManager_OnPluginConsole(string[] args)
{
if (args[0] == "tree")
{
m_log.Debug("[TREES]: New tree planting");
CreateTree(new LLVector3(128.0f, 128.0f, 0.0f));
}
}
void growTrees()
{
foreach (LLUUID tree in m_trees)
{
if (m_scene.Entities.ContainsKey(tree))
{
SceneObjectPart s_tree = ((SceneObjectGroup)m_scene.Entities[tree]).RootPart;
// 100 seconds to grow 1m
s_tree.Scale += new LLVector3(0.1f, 0.1f, 0.1f);
s_tree.SendFullUpdateToAllClients();
//s_tree.ScheduleTerseUpdate();
}
else
{
m_trees.Remove(tree);
}
}
}
void seedTrees()
{
foreach (LLUUID tree in m_trees)
{
if (m_scene.Entities.ContainsKey(tree))
{
SceneObjectPart s_tree = ((SceneObjectGroup)m_scene.Entities[tree]).RootPart;
if (s_tree.Scale.X > 0.5)
{
if (Util.RandomClass.NextDouble() > 0.75)
{
SpawnChild(s_tree);
}
}
}
else
{
m_trees.Remove(tree);
}
}
}
void killTrees()
{
foreach (LLUUID tree in m_trees)
{
double killLikelyhood = 0.0;
if (m_scene.Entities.ContainsKey(tree))
{
SceneObjectPart selectedTree = ((SceneObjectGroup)m_scene.Entities[tree]).RootPart;
double selectedTreeScale = Math.Sqrt(Math.Pow(selectedTree.Scale.X, 2) +
Math.Pow(selectedTree.Scale.Y, 2) +
Math.Pow(selectedTree.Scale.Z, 2));
foreach (LLUUID picktree in m_trees)
{
if (picktree != tree)
{
SceneObjectPart pickedTree = ((SceneObjectGroup)m_scene.Entities[picktree]).RootPart;
double pickedTreeScale = Math.Sqrt(Math.Pow(pickedTree.Scale.X, 2) +
Math.Pow(pickedTree.Scale.Y, 2) +
Math.Pow(pickedTree.Scale.Z, 2));
double pickedTreeDistance = Math.Sqrt(Math.Pow(Math.Abs(pickedTree.AbsolutePosition.X - selectedTree.AbsolutePosition.X), 2) +
Math.Pow(Math.Abs(pickedTree.AbsolutePosition.Y - selectedTree.AbsolutePosition.Y), 2) +
Math.Pow(Math.Abs(pickedTree.AbsolutePosition.Z - selectedTree.AbsolutePosition.Z), 2));
killLikelyhood += (selectedTreeScale / (pickedTreeScale * pickedTreeDistance)) * 0.1;
}
}
if (Util.RandomClass.NextDouble() < killLikelyhood)
{
m_scene.RemoveEntity(selectedTree.ParentGroup);
m_trees.Remove(selectedTree.ParentGroup.UUID);
m_scene.ForEachClient(delegate(IClientAPI controller)
{
controller.SendKillObject(m_scene.RegionInfo.RegionHandle,
selectedTree.LocalID);
});
break;
}
else
{
selectedTree.SetText(killLikelyhood.ToString(), new Axiom.Math.Vector3(1.0f, 1.0f, 1.0f), 1.0);
}
}
else
{
m_trees.Remove(tree);
}
}
}
private void SpawnChild(SceneObjectPart s_tree)
{
LLVector3 position = new LLVector3();
position.X = s_tree.AbsolutePosition.X + (1 * (-1 * Util.RandomClass.Next(1)));
if (position.X > 255)
position.X = 255;
if (position.X < 0)
position.X = 0;
position.Y = s_tree.AbsolutePosition.Y + (1 * (-1 * Util.RandomClass.Next(1)));
if (position.Y > 255)
position.Y = 255;
if (position.Y < 0)
position.Y = 0;
double randX = ((Util.RandomClass.NextDouble() * 2.0) - 1.0) * (s_tree.Scale.X * 3);
double randY = ((Util.RandomClass.NextDouble() * 2.0) - 1.0) * (s_tree.Scale.X * 3);
position.X += (float)randX;
position.Y += (float)randY;
CreateTree(position);
}
private void CreateTree(LLVector3 position)
{
position.Z = (float)m_scene.Terrain.heightmap.Get((int)position.X, (int)position.Y);
SceneObjectGroup tree =
m_scene.AddTree(new LLVector3(0.1f, 0.1f, 0.1f),
LLQuaternion.Identity,
position,
Tree.Cypress1,
false);
m_trees.Add(tree.UUID);
tree.SendGroupFullUpdate();
}
void CalculateTrees_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
growTrees();
seedTrees();
killTrees();
}
public void PostInitialise()
{
}
public void Close()
{
}
public string Name
{
get { return "TreePopulatorModule"; }
}
public bool IsSharedModule
{
get { return false; }
}
}
}

View File

@ -1,3 +1,31 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSim Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
using System;
using System.Collections.Generic;
using libsecondlife;
@ -7,10 +35,27 @@ using OpenSim.Region.Environment.Scenes;
namespace OpenSim.Region.Environment.Modules
{
/// <summary>
/// This module sets up texture senders in response to client texture requests, and places them on a
/// processing queue once those senders have the appropriate data (i.e. a texture retrieved from the
/// asset cache).
/// </summary>
public class UserTextureDownloadService
{
private static readonly log4net.ILog m_log
= log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
/// <summary>
/// Holds texture senders before they have received the appropriate texture from the asset cache.
/// </summary>
private readonly Dictionary<LLUUID, TextureSender> m_textureSenders = new Dictionary<LLUUID, TextureSender>();
/// <summary>
/// Texture Senders are placed in this queue once they have received their texture from the asset
/// cache. Another module actually invokes the send.
/// </summary>
private readonly BlockingQueue<TextureSender> m_sharedSendersQueue;
private readonly Scene m_scene;
public UserTextureDownloadService(Scene scene, BlockingQueue<TextureSender> sharedQueue)
@ -19,6 +64,12 @@ namespace OpenSim.Region.Environment.Modules
m_sharedSendersQueue = sharedQueue;
}
/// <summary>
/// Handle a texture request. This involves creating a texture sender and placing it on the
/// previously passed in shared queue.
/// </summary>
/// <param name="client"> </param>
/// <param name="e"></param>
public void HandleTextureRequest(IClientAPI client, TextureRequestArgs e)
{
TextureSender textureSender;
@ -30,20 +81,20 @@ namespace OpenSim.Region.Environment.Modules
{
if (m_textureSenders.TryGetValue(e.RequestedAssetID, out textureSender))
{
// If we've received new non UUID information for this request and it hasn't dispatched
// yet, then update the request accordingly.
textureSender.UpdateRequest(e.DiscardLevel, e.PacketNumber);
if ((textureSender.ImageLoaded) &&
(textureSender.Sending == false))
{
EnqueueTextureSender(textureSender);
}
}
else
{
//m_log.DebugFormat("[USER TEXTURE DOWNLOAD]: Adding download stat {0}", e.RequestedAssetID);
m_scene.AddPendingDownloads(1);
TextureSender requestHandler =
new TextureSender(client, e.RequestedAssetID, e.DiscardLevel, e.PacketNumber);
new TextureSender(client, e.DiscardLevel, e.PacketNumber);
m_textureSenders.Add(e.RequestedAssetID, requestHandler);
m_scene.AssetCache.GetAsset(e.RequestedAssetID, TextureCallback);
m_scene.AssetCache.GetAsset(e.RequestedAssetID, TextureCallback, true);
}
}
}
@ -59,28 +110,56 @@ namespace OpenSim.Region.Environment.Modules
}
}
public void TextureCallback(LLUUID textureID, AssetBase asset)
/// <summary>
/// The callback for the asset cache when a texture has been retrieved. This method queues the
/// texture sender for processing.
/// </summary>
/// <param name="textureID"></param>
/// <param name="asset"></param>
public void TextureCallback(LLUUID textureID, AssetBase texture)
{
lock (m_textureSenders)
{
TextureSender textureSender;
if (m_textureSenders.TryGetValue(textureID, out textureSender))
{
if (null != texture)
{
if (!textureSender.ImageLoaded)
{
textureSender.TextureReceived(asset);
textureSender.TextureReceived(texture);
EnqueueTextureSender(textureSender);
}
}
else
{
throw new Exception("Got a texture with no sender object to handle it, this shouldn't happen");
// Right now, leaving it up to lower level asset server code to post the fact that
// this texture could not be found
// TODO Send packet back to the client telling it not to expect the texture
//m_log.DebugFormat("[USER TEXTURE DOWNLOAD]: Removing download stat for {0}", textureID);
m_scene.AddPendingDownloads(-1);
}
//m_log.InfoFormat("[TEXTURE SENDER] Removing texture sender with uuid {0}", textureID);
m_textureSenders.Remove(textureID);
//m_log.InfoFormat("[TEXTURE SENDER] Current texture senders in dictionary: {0}", m_textureSenders.Count);
}
else
{
m_log.WarnFormat(
"Got a texture uuid {0} with no sender object to handle it, this shouldn't happen",
textureID);
}
}
}
/// <summary>
/// Place a ready texture sender on the processing queue.
/// </summary>
/// <param name="textureSender"></param>
private void EnqueueTextureSender(TextureSender textureSender)
{
textureSender.Cancel = false;
@ -93,6 +172,9 @@ namespace OpenSim.Region.Environment.Modules
}
}
/// <summary>
/// Close this module.
/// </summary>
internal void Close()
{
lock (m_textureSenders)

View File

@ -13,7 +13,7 @@
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
@ -70,6 +70,7 @@ namespace OpenSim.Region.Environment.Modules
{
private Scene m_scene;
private object CommListLock = new object();
private object ListLock = new object();
private string m_name = "WorldCommModule";
private ListenerManager m_listenerManager;
private Queue<ListenerInfo> m_pending;
@ -83,8 +84,8 @@ namespace OpenSim.Region.Environment.Modules
m_scene = scene;
m_scene.RegisterModuleInterface<IWorldComm>(this);
m_listenerManager = new ListenerManager();
m_pending = new Queue<ListenerInfo>();
m_scene.EventManager.OnNewClient += NewClient;
m_pending = new Queue<ListenerInfo>();
}
public void PostInitialise()
@ -136,6 +137,18 @@ namespace OpenSim.Region.Environment.Modules
m_listenerManager.Remove(handle);
}
public void DeleteListener(LLUUID itemID)
{
if (m_listenerManager != null)
{
lock (ListLock)
{
m_listenerManager.DeleteListener(itemID);
}
}
}
// This method scans nearby objects and determines if they are listeners,
// and if so if this message fits the filter. If it does, then
// enqueue the message for delivery to the objects listen event handler.
@ -157,16 +170,16 @@ namespace OpenSim.Region.Environment.Modules
// If they are in proximity, then if they are
// listeners, if so add them to the pending queue
lock (m_scene.Entities)
foreach (ListenerInfo li in m_listenerManager.GetListeners())
{
foreach (LLUUID eb in m_scene.Entities.Keys)
{
EntityBase sPart;
m_scene.Entities.TryGetValue(eb, out sPart);
m_scene.Entities.TryGetValue(li.GetHostID(), out sPart);
// Dont process if this message is from itself!
if (eb.ToString().Equals(sourceItemID) ||
if (li.GetHostID().ToString().Equals(sourceItemID) ||
sPart.UUID.ToString().Equals(sourceItemID))
continue;
@ -183,10 +196,7 @@ namespace OpenSim.Region.Environment.Modules
if ((dis < 10) && (dis > -10))
{
ListenerInfo isListener = m_listenerManager.IsListenerMatch(
sourceItemID, sPart.UUID, channel, name, msg
);
if (isListener != null)
lock (CommListLock)
{
m_pending.Enqueue(isListener);
}
@ -197,10 +207,7 @@ namespace OpenSim.Region.Environment.Modules
if ((dis < 30) && (dis > -30))
{
ListenerInfo isListener = m_listenerManager.IsListenerMatch(
sourceItemID, sPart.UUID, channel, name, msg
);
if (isListener != null)
lock (CommListLock)
{
m_pending.Enqueue(isListener);
}
@ -210,10 +217,7 @@ namespace OpenSim.Region.Environment.Modules
case ChatTypeEnum.Shout:
if ((dis < 100) && (dis > -100))
{
ListenerInfo isListener = m_listenerManager.IsListenerMatch(
sourceItemID, sPart.UUID, channel, name, msg
);
if (isListener != null)
lock (CommListLock)
{
m_pending.Enqueue(isListener);
}
@ -222,13 +226,15 @@ namespace OpenSim.Region.Environment.Modules
case ChatTypeEnum.Broadcast:
ListenerInfo isListen =
m_listenerManager.IsListenerMatch(sourceItemID, eb, channel, name, msg);
m_listenerManager.IsListenerMatch(sourceItemID, li.GetItemID(), channel, name, msg);
if (isListen != null)
{
ListenerInfo isListener = m_listenerManager.IsListenerMatch(
sourceItemID, sPart.UUID, channel, name, msg
);
if (isListener != null)
{
lock (CommListLock)
{
m_pending.Enqueue(isListener);
}
@ -242,7 +248,10 @@ namespace OpenSim.Region.Environment.Modules
public bool HasMessages()
{
if (m_pending != null)
return (m_pending.Count > 0);
else
return false;
}
public ListenerInfo GetNextMessage()
@ -256,6 +265,17 @@ namespace OpenSim.Region.Environment.Modules
return li;
}
public uint PeekNextMessageLocalID()
{
return m_pending.Peek().GetLocalID();
}
public LLUUID PeekNextMessageItemID()
{
return m_pending.Peek().GetItemID();
}
}
// hostID: the ID of the ScenePart
@ -272,8 +292,7 @@ namespace OpenSim.Region.Environment.Modules
m_listeners = new Dictionary<int, ListenerInfo>();
}
public int AddListener(uint localID, LLUUID itemID, LLUUID hostID, int channel, string name, string id,
string msg)
public int AddListener(uint localID, LLUUID itemID, LLUUID hostID, int channel, string name, string id, string msg)
{
if (m_listeners.Count < m_MaxListeners)
{
@ -305,6 +324,18 @@ namespace OpenSim.Region.Environment.Modules
m_listeners.Remove(handle);
}
public void DeleteListener(LLUUID itemID)
{
foreach (ListenerInfo li in m_listeners.Values)
{
if (li.GetItemID().Equals(itemID))
{
Remove(li.GetHandle());
return;
}
}
}
private int GetNewHandle()
{
for (int i = 0; i < int.MaxValue - 1; i++)
@ -390,6 +421,11 @@ namespace OpenSim.Region.Environment.Modules
}
return null;
}
public Dictionary<int, ListenerInfo>.ValueCollection GetListeners()
{
return m_listeners.Values;
}
}
public class ListenerInfo
@ -405,8 +441,7 @@ namespace OpenSim.Region.Environment.Modules
private string m_message; // The message
private bool m_active; // Listener is active or not
public ListenerInfo(uint localID, int handle, LLUUID ItemID, LLUUID hostID, int channel, string name, LLUUID id,
string message)
public ListenerInfo(uint localID, int handle, LLUUID ItemID, LLUUID hostID, int channel, string name, LLUUID id, string message)
{
Initialise(localID, handle, ItemID, hostID, channel, name, id, message);
}
@ -491,5 +526,6 @@ namespace OpenSim.Region.Environment.Modules
{
return m_id;
}
}
}

View File

@ -13,7 +13,7 @@
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
@ -75,26 +75,23 @@ namespace OpenSim.Region.Environment.Modules
{
public class XMLRPCModule : IRegionModule, IXMLRPC
{
private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private Scene m_scene;
private Queue<RPCRequestInfo> rpcQueue = new Queue<RPCRequestInfo>();
private object XMLRPCListLock = new object();
private string m_name = "XMLRPCModule";
private int RemoteReplyScriptWait = 300;
private int RemoteReplyScriptTimeout = 900;
private int RemoteReplyScriptTimeout = 9000;
private int m_remoteDataPort = 0;
private List<Scene> m_scenes = new List<Scene>();
private LogBase m_log;
// <channel id, RPCChannelInfo>
private Dictionary<LLUUID, RPCChannelInfo> m_openChannels;
// <channel id, RPCRequestInfo>
private Dictionary<LLUUID, RPCRequestInfo> m_pendingResponse;
private Dictionary<LLUUID, RPCRequestInfo> m_rpcPending;
private Dictionary<LLUUID, RPCRequestInfo> m_rpcPendingResponses;
public XMLRPCModule()
{
m_log = MainLog.Instance;
}
private Dictionary<LLUUID, SendRemoteDataRequest> m_pendingSRDResponses;
public void Initialise(Scene scene, IConfigSource config)
{
@ -119,11 +116,13 @@ namespace OpenSim.Region.Environment.Modules
if (IsEnabled())
{
m_openChannels = new Dictionary<LLUUID, RPCChannelInfo>();
m_pendingResponse = new Dictionary<LLUUID, RPCRequestInfo>();
m_rpcPending = new Dictionary<LLUUID, RPCRequestInfo>();
m_rpcPendingResponses = new Dictionary<LLUUID, RPCRequestInfo>();
m_pendingSRDResponses = new Dictionary<LLUUID, SendRemoteDataRequest>();
// Start http server
// Attach xmlrpc handlers
m_log.Verbose("REMOTE_DATA",
m_log.Info("[REMOTE_DATA]: " +
"Starting XMLRPC Server on port " + m_remoteDataPort + " for llRemoteData commands.");
BaseHttpServer httpServer = new BaseHttpServer((uint)m_remoteDataPort);
httpServer.AddXmlRPCHandler("llRemoteData", XmlRpcRemoteData);
@ -192,6 +191,34 @@ namespace OpenSim.Region.Environment.Modules
return channel;
}
// Delete channels based on itemID
// for when a script is deleted
public void DeleteChannels(LLUUID itemID)
{
if (m_openChannels != null)
{
ArrayList tmp = new ArrayList();
lock (XMLRPCListLock)
{
foreach (RPCChannelInfo li in m_openChannels.Values)
{
if (li.GetItemID().Equals(itemID))
{
tmp.Add(itemID);
}
}
System.Collections.IEnumerator tmpEnumerator = tmp.GetEnumerator();
while ( tmpEnumerator.MoveNext() )
m_openChannels.Remove((LLUUID)tmpEnumerator.Current);
}
}
}
/**********************************************
* Remote Data Reply
*
@ -204,15 +231,12 @@ namespace OpenSim.Region.Environment.Modules
RPCRequestInfo rpcInfo;
LLUUID message_key = new LLUUID(message_id);
if (m_pendingResponse.TryGetValue(message_key, out rpcInfo))
if (m_rpcPendingResponses.TryGetValue(message_key, out rpcInfo))
{
rpcInfo.SetRetval(sdata);
rpcInfo.SetStrRetval(sdata);
rpcInfo.SetIntRetval(idata);
rpcInfo.SetProcessed(true);
lock (XMLRPCListLock)
{
m_pendingResponse.Remove(message_key);
}
m_rpcPendingResponses.Remove(message_key);
}
}
@ -254,7 +278,7 @@ namespace OpenSim.Region.Environment.Modules
rpcInfo =
new RPCRequestInfo(rpcChanInfo.GetLocalID(), rpcChanInfo.GetItemID(), channel, strVal,
intVal);
rpcQueue.Enqueue(rpcInfo);
m_rpcPending.Add(rpcInfo.GetMessageID(), rpcInfo);
}
int timeoutCtr = 0;
@ -266,16 +290,20 @@ namespace OpenSim.Region.Environment.Modules
}
if (rpcInfo.IsProcessed())
{
response.Value = rpcInfo.GetRetval();
Hashtable param = new Hashtable();
param["StringValue"] = rpcInfo.GetStrRetval();
param["IntValue"] = Convert.ToString(rpcInfo.GetIntRetval());
ArrayList parameters = new ArrayList();
parameters.Add(param);
response.Value = parameters;
rpcInfo = null;
}
else
{
response.SetFault(-1, "Script timeout");
lock (XMLRPCListLock)
{
m_pendingResponse.Remove(rpcInfo.GetMessageID());
}
rpcInfo = null;
}
}
else
@ -289,20 +317,112 @@ namespace OpenSim.Region.Environment.Modules
public bool hasRequests()
{
return (rpcQueue.Count > 0);
lock (XMLRPCListLock)
{
if (m_rpcPending != null)
return (m_rpcPending.Count > 0);
else
return false;
}
}
public RPCRequestInfo GetNextRequest()
public RPCRequestInfo GetNextCompletedRequest()
{
if (m_rpcPending != null)
{
lock (XMLRPCListLock)
{
RPCRequestInfo rpcInfo = rpcQueue.Dequeue();
m_pendingResponse.Add(rpcInfo.GetMessageID(), rpcInfo);
return rpcInfo;
foreach (LLUUID luid in m_rpcPending.Keys)
{
RPCRequestInfo tmpReq;
if (m_rpcPending.TryGetValue(luid, out tmpReq))
{
if (!tmpReq.IsProcessed()) return tmpReq;
}
}
}
}
return null;
}
public void RemoveCompletedRequest(LLUUID id)
{
lock (XMLRPCListLock)
{
RPCRequestInfo tmp;
if (m_rpcPending.TryGetValue(id, out tmp))
{
m_rpcPending.Remove(id);
m_rpcPendingResponses.Add(id, tmp);
}
else
{
Console.WriteLine("UNABLE TO REMOVE COMPLETED REQUEST");
}
}
}
public LLUUID SendRemoteData(uint localID, LLUUID itemID, string channel, string dest, int idata, string sdata)
{
SendRemoteDataRequest req = new SendRemoteDataRequest(
localID, itemID, channel, dest, idata, sdata
);
m_pendingSRDResponses.Add(req.GetReqID(), req);
return req.process();
}
public SendRemoteDataRequest GetNextCompletedSRDRequest()
{
if (m_pendingSRDResponses != null)
{
lock (XMLRPCListLock)
{
foreach (LLUUID luid in m_pendingSRDResponses.Keys)
{
SendRemoteDataRequest tmpReq;
if (m_pendingSRDResponses.TryGetValue(luid, out tmpReq))
{
if (tmpReq.finished)
return tmpReq;
}
}
}
}
return null;
}
public void RemoveCompletedSRDRequest(LLUUID id)
{
lock (XMLRPCListLock)
{
SendRemoteDataRequest tmpReq;
if (m_pendingSRDResponses.TryGetValue(id, out tmpReq))
{
m_pendingSRDResponses.Remove(id);
}
}
}
public void CancelSRDRequests(LLUUID itemID)
{
if (m_pendingSRDResponses != null)
{
lock (XMLRPCListLock)
{
foreach (SendRemoteDataRequest li in m_pendingSRDResponses.Values)
{
if (li.m_itemID.Equals(itemID))
m_pendingSRDResponses.Remove(li.GetReqID());
}
}
}
}
}
/**************************************************************
*
* Class RPCRequestInfo
@ -316,7 +436,8 @@ namespace OpenSim.Region.Environment.Modules
private string m_StrVal;
private string m_IntVal;
private bool m_processed;
private string m_resp;
private string m_respStr;
private int m_respInt;
private uint m_localID;
private LLUUID m_ItemID;
private LLUUID m_MessageID;
@ -331,7 +452,8 @@ namespace OpenSim.Region.Environment.Modules
m_ChannelKey = channelKey;
m_MessageID = LLUUID.Random();
m_processed = false;
m_resp = "";
m_respStr = String.Empty;
m_respInt = 0;
}
public bool IsProcessed()
@ -349,16 +471,24 @@ namespace OpenSim.Region.Environment.Modules
m_processed = processed;
}
public void SetRetval(string resp)
public void SetStrRetval(string resp)
{
m_resp = resp;
m_respStr = resp;
}
public string GetRetval()
public string GetStrRetval()
{
return m_resp;
return m_respStr;
}
public void SetIntRetval(int resp)
{
m_respInt = resp;
}
public int GetIntRetval()
{
return m_respInt;
}
public uint GetLocalID()
{
return m_localID;
@ -412,5 +542,141 @@ namespace OpenSim.Region.Environment.Modules
{
return m_localID;
}
}
public class SendRemoteDataRequest
{
public LLUUID reqID;
public string destURL;
public string channel;
public string sdata;
public int idata;
public bool finished;
public string response_sdata;
public int response_idata;
public XmlRpcRequest request;
private Thread httpThread;
public LLUUID m_itemID;
public uint m_localID;
private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
public SendRemoteDataRequest(uint localID, LLUUID itemID, string channel, string dest, int idata, string sdata)
{
this.channel = channel;
this.destURL = dest;
this.idata = idata;
this.sdata = sdata;
m_itemID = itemID;
m_localID = localID;
reqID = LLUUID.Random();
}
public LLUUID process()
{
httpThread = new Thread(SendRequest);
httpThread.Name = "HttpRequestThread";
httpThread.Priority = ThreadPriority.BelowNormal;
httpThread.IsBackground = true;
finished = false;
httpThread.Start();
OpenSim.Framework.ThreadTracker.Add(httpThread);
return reqID;
}
/*
* TODO: More work on the response codes. Right now
* returning 200 for success or 499 for exception
*/
public void SendRequest()
{
Hashtable param = new Hashtable();
// Check if channel is an LLUUID
// if not, use as method name
LLUUID parseUID;
string mName = "llRemoteData";
if( (channel != null) && (channel != "") )
if( !LLUUID.TryParse(channel, out parseUID) )
mName = channel;
else
param["Channel"] = channel;
param["StringValue"] = sdata;
param["IntValue"] = Convert.ToString(idata);
ArrayList parameters = new ArrayList();
parameters.Add(param);
XmlRpcRequest req = new XmlRpcRequest(mName, parameters);
try
{
XmlRpcResponse resp = req.Send(destURL, 30000);
if (resp != null)
{
Hashtable respParms;
if(resp.Value.GetType().Equals(Type.GetType("System.Collections.Hashtable"))) {
respParms = (Hashtable)resp.Value;
}
else {
ArrayList respData = (ArrayList)resp.Value;
respParms = (Hashtable)respData[0];
}
if (respParms != null)
{
if (respParms.Contains("StringValue"))
{
sdata = (string)respParms["StringValue"];
}
if (respParms.Contains("IntValue"))
{
idata = Convert.ToInt32((string)respParms["IntValue"]);
}
if (respParms.Contains("faultString"))
{
sdata = (string)respParms["faultString"];
}
if (respParms.Contains("faultCode"))
{
idata = Convert.ToInt32(respParms["faultCode"]);
}
}
}
}
catch (System.Net.WebException we)
{
sdata = we.Message;
m_log.Warn("[SendRemoteDataRequest]: Request failed");
m_log.Warn(we.StackTrace);
}
finished = true;
}
public void Stop()
{
try
{
httpThread.Abort();
}
catch (Exception)
{
}
}
public LLUUID GetReqID()
{
return reqID;
}
}
}

View File

@ -13,7 +13,7 @@
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
@ -97,7 +97,11 @@ namespace OpenSim.Region.Environment.Modules
XferDownLoad transaction = new XferDownLoad(fileName, fileData, xferID, remoteClient);
Transfers.Add(xferID, transaction);
NewFiles.Remove(fileName);
transaction.StartSend();
if (transaction.StartSend())
{
Transfers.Remove(xferID);
}
}
}
}
@ -107,7 +111,12 @@ namespace OpenSim.Region.Environment.Modules
{
if (Transfers.ContainsKey(xferID))
{
Transfers[xferID].AckPacket(packet);
if (Transfers[xferID].AckPacket(packet))
{
{
Transfers.Remove(xferID);
}
}
}
}
@ -131,13 +140,13 @@ namespace OpenSim.Region.Environment.Modules
public class XferDownLoad
{
public byte[] Data = new byte[0];
public string FileName = "";
public string FileName = String.Empty;
public ulong XferID = 0;
public int DataPointer = 0;
public uint Packet = 0;
public IClientAPI Client;
public uint Serial = 1;
private bool complete = false;
private bool complete;
public XferDownLoad(string fileName, byte[] data, ulong xferID, IClientAPI client)
{
@ -151,7 +160,11 @@ namespace OpenSim.Region.Environment.Modules
{
}
public void StartSend()
/// <summary>
/// Start a transfer
/// </summary>
/// <returns>True if the transfer is complete, false if not</returns>
public bool StartSend()
{
if (Data.Length < 1000)
{
@ -160,6 +173,7 @@ namespace OpenSim.Region.Environment.Modules
Array.Copy(Helpers.IntToBytes(Data.Length), 0, transferData, 0, 4);
Array.Copy(Data, 0, transferData, 4, Data.Length);
Client.SendXferPacket(XferID, 0 + 0x80000000, transferData);
complete = true;
}
else
@ -171,9 +185,16 @@ namespace OpenSim.Region.Environment.Modules
Packet++;
DataPointer = 1000;
}
return complete;
}
public void AckPacket(uint packet)
/// <summary>
/// Respond to an ack packet from the client
/// </summary>
/// <param name="packet"></param>
/// <returns>True if the transfer is complete, false otherwise</returns>
public bool AckPacket(uint packet)
{
if (!complete)
{
@ -193,9 +214,12 @@ namespace OpenSim.Region.Environment.Modules
Client.SendXferPacket(XferID, endPacket, transferData);
Packet++;
DataPointer += (Data.Length - DataPointer);
complete = true;
}
}
return complete;
}
}
}