// * Modified by Fumi.Iseki for Unix/Linix http://www.nsl.tuis.ac.jp
// *
// * Copyright (c) Contributors, http://opensimulator.org/, http://www.nsl.tuis.ac.jp/
// * 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;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using log4net;
using Nini.Config;
using Nwc.XmlRpc;
using Mono.Addins;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Framework.Servers;
using OpenSim.Framework.Servers.HttpServer;
using OpenSim.Services.Interfaces;
using OpenSim.Region.Framework;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
using NSL.Certificate.Tools;
using NSL.Network.XmlRpc;
[assembly: Addin("DTLNSLMoneyModule", "1.0")]
[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)]
namespace OpenSim.Modules.Currency
{
//
public enum TransactionType : int
{
// One-Time Charges
GroupCreate = 1002,
GroupJoin = 1004,
UploadCharge = 1101,
LandAuction = 1102,
ClassifiedCharge= 1103,
// Recurrent Charges
ParcelDirFee = 2003,
ClassifiedRenew = 2005,
ScheduledFee = 2900,
// Inventory Transactions
GiveInventory = 3000,
// Transfers Between Users
ObjectSale = 5000,
Gift = 5001,
LandSale = 5002,
ReferBonus = 5003,
InvntorySale = 5004,
RefundPurchase = 5005,
LandPassSale = 5006,
DwellBonus = 5007,
PayObject = 5008,
ObjectPays = 5009,
BuyMoney = 5010,
MoveMoney = 5011,
// Group Transactions
GroupLiability = 6003,
GroupDividend = 6004,
// Stipend Credits
StipendPayment = 10000
}
/*
public enum OpenMetaverse.MoneyTransactionType : int
{
None = 0,
FailSimulatorTimeout = 1,
FailDataserverTimeout = 2,
ObjectClaim = 1000,
LandClaim = 1001,
GroupCreate = 1002,
ObjectPublicClaim = 1003,
GroupJoin = 1004,
TeleportCharge = 1100,
UploadCharge = 1101,
LandAuction = 1102,
ClassifiedCharge = 1103,
ObjectTax = 2000,
LandTax = 2001,
LightTax = 2002,
ParcelDirFee = 2003,
GroupTax = 2004,
ClassifiedRenew = 2005,
GiveInventory = 3000,
ObjectSale = 5000,
Gift = 5001,
LandSale = 5002,
ReferBonus = 5003,
InventorySale = 5004,
RefundPurchase = 5005,
LandPassSale = 5006,
DwellBonus = 5007,
PayObject = 5008,
ObjectPays = 5009,
GroupLandDeed = 6001,
GroupObjectDeed = 6002,
GroupLiability = 6003,
GroupDividend = 6004,
GroupMembershipDues = 6005,
ObjectRelease = 8000,
LandRelease = 8001,
ObjectDelete = 8002,
ObjectPublicDecay = 8003,
ObjectPublicDelete = 8004,
LindenAdjustment = 9000,
LindenGrant = 9001,
LindenPenalty = 9002,
EventFee = 9003,
EventPrize = 9004,
StipendBasic = 10000,
StipendDeveloper = 10001,
StipendAlways = 10002,
StipendDaily = 10003,
StipendRating = 10004,
StipendDelta = 10005
}
*/
//
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DTLNSLMoneyModule")]
public class DTLNSLMoneyModule : IMoneyModule, ISharedRegionModule
{
#region Constant numbers and members.
// Constant memebers
private const int MONEYMODULE_REQUEST_TIMEOUT = 10000;
// Private data members.
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private bool m_enabled = true;
private bool m_sellEnabled = false;
private bool m_enable_server = true; // enable Money Server
private IConfigSource m_config;
private string m_moneyServURL = string.Empty;
public BaseHttpServer HttpServer;
private string m_certFilename = "";
private string m_certPassword = "";
private bool m_checkServerCert = false;
private string m_cacertFilename = "";
private X509Certificate2 m_cert = null;
//
private bool m_use_web_settle = false;
private string m_settle_url = "";
private string m_settle_message = "";
private bool m_settle_user = false;
private NSLCertificateVerify m_certVerify = new NSLCertificateVerify(); // サーバ認証用
///
/// Scene dictionary indexed by Region Handle
///
private Dictionary m_sceneList = new Dictionary();
///
/// To cache the balance data while the money server is not available.
///
private Dictionary m_moneyServer = new Dictionary();
// Events
public event ObjectPaid OnObjectPaid;
// Price
private int ObjectCount = 0;
private int PriceEnergyUnit = 0;
private int PriceGroupCreate = 0;
private int PriceObjectClaim = 0;
private float PriceObjectRent = 0f;
private float PriceObjectScaleFactor = 0f;
private int PriceParcelClaim = 0;
private int PriceParcelRent = 0;
private float PriceParcelClaimFactor = 0f;
private int PricePublicObjectDecay = 0;
private int PricePublicObjectDelete = 0;
private int PriceRentLight = 0;
private int PriceUpload = 0;
private int TeleportMinPrice = 0;
private float TeleportPriceExponent = 0f;
private float EnergyEfficiency = 0f;
#endregion
//
public void Initialise(Scene scene, IConfigSource source)
{
Initialise(source);
if (string.IsNullOrEmpty(m_moneyServURL)) m_enable_server = false;
//
AddRegion(scene);
}
#region ISharedRegionModule interface
public void Initialise(IConfigSource source)
{
//m_log.InfoFormat("[MONEY]: Initialise:");
// Handle the parameters errors.
if (source==null) return;
try
{
m_config = source;
// [Economy] section
IConfig economyConfig = m_config.Configs["Economy"];
if (economyConfig.GetString("EconomyModule")!=Name)
{
m_enabled = false;
m_log.InfoFormat("[MONEY]: The DTL/NSL MoneyModule is disabled");
return;
}
else
{
m_log.InfoFormat("[MONEY]: The DTL/NSL MoneyModule is enabled");
}
m_sellEnabled = economyConfig.GetBoolean("SellEnabled", false);
m_moneyServURL = economyConfig.GetString("CurrencyServer");
// クライアント証明書
m_certFilename = economyConfig.GetString("ClientCertFilename", "");
m_certPassword = economyConfig.GetString("ClientCertPassword", "");
if (m_certFilename!="") {
m_cert = new X509Certificate2(m_certFilename, m_certPassword);
m_log.InfoFormat("[MONEY]: Issue Authentication of Client. Cert File is " + m_certFilename);
}
// サーバ認証
string checkcert = economyConfig.GetString("CheckServerCert", "false");
if (checkcert.ToLower()=="true") m_checkServerCert = true;
m_cacertFilename = economyConfig.GetString("CACertFilename", "");
if (m_cacertFilename!="") {
m_certVerify.SetPrivateCA(m_cacertFilename);
m_log.InfoFormat("[MONEY]: Execute Authentication of Server. CA Cert File is " + m_cacertFilename);
}
else {
m_checkServerCert = false;
}
ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(m_certVerify.ValidateServerCertificate);
// Settlement
m_use_web_settle = economyConfig.GetBoolean("SettlementByWeb", false);
m_settle_url = economyConfig.GetString ("SettlementURL", "");
m_settle_message = economyConfig.GetString ("SettlementMessage", "");
// Price
PriceEnergyUnit = economyConfig.GetInt ("PriceEnergyUnit", 100);
PriceObjectClaim = economyConfig.GetInt ("PriceObjectClaim", 10);
PricePublicObjectDecay = economyConfig.GetInt ("PricePublicObjectDecay", 4);
PricePublicObjectDelete = economyConfig.GetInt ("PricePublicObjectDelete", 4);
PriceParcelClaim = economyConfig.GetInt ("PriceParcelClaim", 1);
PriceParcelClaimFactor = economyConfig.GetFloat("PriceParcelClaimFactor", 1f);
PriceUpload = economyConfig.GetInt ("PriceUpload", 0);
PriceRentLight = economyConfig.GetInt ("PriceRentLight", 5);
PriceObjectRent = economyConfig.GetFloat("PriceObjectRent", 1);
PriceObjectScaleFactor = economyConfig.GetFloat("PriceObjectScaleFactor", 10);
PriceParcelRent = economyConfig.GetInt ("PriceParcelRent", 1);
PriceGroupCreate = economyConfig.GetInt ("PriceGroupCreate", 0);
TeleportMinPrice = economyConfig.GetInt ("TeleportMinPrice", 2);
TeleportPriceExponent = economyConfig.GetFloat("TeleportPriceExponent", 2f);
EnergyEfficiency = economyConfig.GetFloat("EnergyEfficiency", 1);
}
catch
{
m_log.ErrorFormat("[MONEY]: Initialise: Faile to read configuration file");
}
}
public void AddRegion(Scene scene)
{
//m_log.InfoFormat("[MONEY]: AddRegion:");
if (scene==null) return;
scene.RegisterModuleInterface(this); // 競合するモジュールの排除
lock (m_sceneList)
{
if (m_sceneList.Count==0)
{
if (m_enable_server)
{
HttpServer = new BaseHttpServer(9000);
HttpServer.AddStreamHandler(new Region.Framework.Scenes.RegionStatsHandler(scene.RegionInfo));
HttpServer.AddXmlRPCHandler("OnMoneyTransfered", OnMoneyTransferedHandler);
HttpServer.AddXmlRPCHandler("UpdateBalance", BalanceUpdateHandler);
HttpServer.AddXmlRPCHandler("UserAlert", UserAlertHandler);
HttpServer.AddXmlRPCHandler("GetBalance", GetBalanceHandler); // added
HttpServer.AddXmlRPCHandler("AddBankerMoney", AddBankerMoneyHandler); // added
HttpServer.AddXmlRPCHandler("SendMoneyBalance", SendMoneyBalanceHandler); // added
//HttpServer.AddXmlRPCHandler("UploadCovered", UploadCoveredHandler); // added for Aurora-Sim
//HttpServer.AddXmlRPCHandler("UploadCharge", UploadChargeHandler); // added for Aurora-Sim
MainServer.Instance.AddXmlRPCHandler("OnMoneyTransfered", OnMoneyTransferedHandler);
MainServer.Instance.AddXmlRPCHandler("UpdateBalance", BalanceUpdateHandler);
MainServer.Instance.AddXmlRPCHandler("UserAlert", UserAlertHandler);
MainServer.Instance.AddXmlRPCHandler("GetBalance", GetBalanceHandler); // added
MainServer.Instance.AddXmlRPCHandler("AddBankerMoney", AddBankerMoneyHandler); // added
MainServer.Instance.AddXmlRPCHandler("SendMoneyBalance", SendMoneyBalanceHandler); // added
//MainServer.Instance.AddXmlRPCHandler("UploadCovered", UploadCoveredHandler); // added for Aurora-Sim
//MainServer.Instance.AddXmlRPCHandler("UploadCharge", UploadChargeHandler); // added for Aurora-Sim
}
}
if (m_sceneList.ContainsKey(scene.RegionInfo.RegionHandle))
{
m_sceneList[scene.RegionInfo.RegionHandle] = scene;
}
else
{
m_sceneList.Add(scene.RegionInfo.RegionHandle, scene);
}
}
scene.EventManager.OnNewClient += OnNewClient;
scene.EventManager.OnMakeRootAgent += OnMakeRootAgent;
scene.EventManager.OnMakeChildAgent += MakeChildAgent;
// for OpenSim
scene.EventManager.OnMoneyTransfer += MoneyTransferAction;
scene.EventManager.OnValidateLandBuy += ValidateLandBuy;
scene.EventManager.OnLandBuy += processLandBuy;
}
public void RemoveRegion(Scene scene)
{
}
public void RegionLoaded(Scene scene)
{
}
public Type ReplaceableInterface
{
//get { return typeof(IMoneyModule); }
get { return null; }
}
public bool IsSharedModule
{
get { return true; }
}
public string Name
{
get { return "DTLNSLMoneyModule"; }
}
public void PostInitialise()
{
}
public void Close()
{
}
#endregion
#region IMoneyModule interface.
// for LSL llGiveMoney() function
public bool ObjectGiveMoney(UUID objectID, UUID fromID, UUID toID, int amount)
{
//m_log.InfoFormat("[MONEY]: ObjectGiveMoney: LSL ObjectGiveMoney. UUID = {0}", objectID.ToString());
if (!m_sellEnabled) return false;
string objName = string.Empty;
string avatarName = string.Empty;
SceneObjectPart sceneObj = GetLocatePrim(objectID);
if (sceneObj!=null)
{
objName = sceneObj.Name;
}
Scene scene = GetLocateScene(toID);
if (scene!=null)
{
UserAccount account = scene.UserAccountService.GetUserAccount(scene.RegionInfo.ScopeID, toID);
if (account!=null)
{
avatarName = account.FirstName + " " + account.LastName;
}
}
bool ret = false;
string description = String.Format("Object {0} pays {1}", objName, avatarName);
if (sceneObj.OwnerID==fromID)
{
ulong regionHandle = sceneObj.RegionHandle;
if (GetLocateClient(fromID)!=null)
{
ret = TransferMoney(fromID, toID, amount, (int)MoneyTransactionType.ObjectPays, objectID, regionHandle, description);
}
else
{
ret = ForceTransferMoney(fromID, toID, amount, (int)MoneyTransactionType.ObjectPays, objectID, regionHandle, description);
}
}
return ret;
}
//
public int UploadCharge
{
get { return PriceUpload; }
}
//
public int GroupCreationCharge
{
get { return PriceGroupCreate; }
}
public int GetBalance(UUID agentID)
{
IClientAPI client = GetLocateClient(agentID);
return QueryBalanceFromMoneyServer(client);
}
public bool UploadCovered(UUID agentID, int amount)
{
IClientAPI client = GetLocateClient(agentID);
int balance = QueryBalanceFromMoneyServer(client);
if (balance= landBuyEvent.parcelPrice)
{
lock(landBuyEvent)
{
landBuyEvent.economyValidated = true;
}
}
}
}
/**/
// for LandBuy even
// For Aurora-Sim, OnParcelBuy event function is already defined
// in OpenSim/Region/CoreModules/World/Land/ParcelManagementModule.cs
private void processLandBuy(Object sender, EventManager.LandBuyArgs landBuyEvent)
{
//m_log.InfoFormat("[MONEY]: processLandBuy:");
if (!m_sellEnabled) return;
lock(landBuyEvent)
{
if (landBuyEvent.economyValidated==true && landBuyEvent.transactionID==0)
{
landBuyEvent.transactionID = Util.UnixTimeSinceEpoch();
ulong parcelID = (ulong)landBuyEvent.parcelLocalID;
UUID regionID = UUID.Zero;
if (sender is Scene) regionID = ((Scene)sender).RegionInfo.RegionID;
if (TransferMoney(landBuyEvent.agentId, landBuyEvent.parcelOwnerID,
landBuyEvent.parcelPrice, (int)MoneyTransactionType.LandSale, regionID, parcelID, "Land Purchase"))
{
landBuyEvent.amountDebited = landBuyEvent.parcelPrice;
}
}
}
}
/**/
// for OnObjectBuy event
// For Aurora-Sim, OnObjectBuy event function is already defined
// in OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs
public void OnObjectBuy(IClientAPI remoteClient, UUID agentID, UUID sessionID,
UUID groupID, UUID categoryID, uint localID, byte saleType, int salePrice)
{
//m_log.InfoFormat("[MONEY]: OnObjectBuy: agent = {0}, {1}", agentID, remoteClient.AgentId);
// Handle the parameters error.
if (!m_sellEnabled) return;
if (remoteClient==null || salePrice<0) return; // for L$0 Sell
// Get the balance from money server.
int balance = QueryBalanceFromMoneyServer(remoteClient);
if (balance();
if (mod!=null)
{
UUID receiverId = sceneObj.OwnerID;
ulong regionHandle = sceneObj.RegionHandle;
bool ret = true;
if (salePrice>0) {
ret = TransferMoney(remoteClient.AgentId, receiverId, salePrice,
(int)MoneyTransactionType.PayObject, sceneObj.UUID, regionHandle, "Object Buy");
}
if (ret)
{
mod.BuyObject(remoteClient, categoryID, localID, saleType, salePrice);
}
}
}
else
{
remoteClient.SendAgentAlertMessage("Unable to buy now. The object was not found", false);
return;
}
}
}
///
/// Sends the the stored money balance to the client
///
///
///
///
///
private void OnMoneyBalanceRequest(IClientAPI client, UUID agentID, UUID SessionID, UUID TransactionID)
{
//m_log.InfoFormat("[MONEY]: OnMoneyBalanceRequest:");
if (client.AgentId==agentID && client.SessionId==SessionID)
{
int balance = 0;
//
if (m_enable_server)
{
balance = QueryBalanceFromMoneyServer(client);
}
client.SendMoneyBalance(TransactionID, true, new byte[0], balance, 0, UUID.Zero, false, UUID.Zero, false, 0, String.Empty);
}
else
{
client.SendAlertMessage("Unable to send your money balance");
}
}
private void OnRequestPayPrice(IClientAPI client, UUID objectID)
{
//m_log.InfoFormat("[MONEY]: OnRequestPayPrice:");
Scene scene = GetLocateScene(client.AgentId);
if (scene==null) return;
SceneObjectPart sceneObj = scene.GetSceneObjectPart(objectID);
if (sceneObj==null) return;
SceneObjectGroup group = sceneObj.ParentGroup;
SceneObjectPart root = group.RootPart;
client.SendPayPrice(objectID, root.PayPrice);
}
//
//private void OnEconomyDataRequest(UUID agentId)
private void OnEconomyDataRequest(IClientAPI user)
{
//m_log.InfoFormat("[MONEY]: OnEconomyDataRequest:");
//IClientAPI user = GetLocateClient(agentId);
if (user!=null)
{
//Scene s = GetLocateScene(user.AgentId);
Scene s = (Scene)user.Scene;
user.SendEconomyData(EnergyEfficiency, s.RegionInfo.ObjectCapacity, ObjectCount, PriceEnergyUnit, PriceGroupCreate,
PriceObjectClaim, PriceObjectRent, PriceObjectScaleFactor, PriceParcelClaim, PriceParcelClaimFactor,
PriceParcelRent, PricePublicObjectDecay, PricePublicObjectDelete, PriceRentLight, PriceUpload,
TeleportMinPrice, TeleportPriceExponent);
}
}
#endregion
#region MoneyModule XML-RPC Handler
// "OnMoneyTransfered" RPC from MoneyServer
public XmlRpcResponse OnMoneyTransferedHandler(XmlRpcRequest request, IPEndPoint remoteClient)
{
//m_log.InfoFormat("[MONEY]: OnMoneyTransferedHandler:");
bool ret = false;
if (request.Params.Count>0)
{
Hashtable requestParam = (Hashtable)request.Params[0];
if (requestParam.Contains("clientUUID") &&
//requestParam.Contains("receiverUUID") &&
requestParam.Contains("clientSessionID") &&
requestParam.Contains("clientSecureSessionID"))
{
UUID clientUUID = UUID.Zero;
UUID.TryParse((string)requestParam["clientUUID"], out clientUUID);
//UUID receiverUUID = UUID.Zero;
//UUID.TryParse((string)requestParam["receiverUUID"], out receiverUUID);
if (clientUUID!=UUID.Zero)
{
IClientAPI client = GetLocateClient(clientUUID);
if (client!=null &&
client.SessionId.ToString()==(string)requestParam["clientSessionID"] &&
client.SecureSessionId.ToString()==(string)requestParam["clientSecureSessionID"])
{
if (requestParam.Contains("transactionType") &&
requestParam.Contains("objectID") &&
requestParam.Contains("amount"))
{
//m_log.InfoFormat("[MONEY]: OnMoneyTransferedHandler: type = {0}", requestParam["transactionType"]);
if ((int)requestParam["transactionType"]==(int)MoneyTransactionType.PayObject) // Pay for the object.
{
// Send notify to the client(viewer) for Money Event Trigger.
ObjectPaid handlerOnObjectPaid = OnObjectPaid;
if (handlerOnObjectPaid!=null)
{
UUID objectID = UUID.Zero;
UUID.TryParse((string)requestParam["objectID"], out objectID);
handlerOnObjectPaid(objectID, clientUUID, (int)requestParam["amount"]); // call Script Engine for LSL money()
}
ret = true;
}
}
}
}
}
}
// Send the response to money server.
XmlRpcResponse resp = new XmlRpcResponse();
Hashtable paramTable = new Hashtable();
paramTable["success"] = ret;
if (!ret)
{
m_log.ErrorFormat("[MONEY]: OnMoneyTransferedHandler: Transaction is failed. MoneyServer will rollback");
}
resp.Value = paramTable;
return resp;
}
// "UpdateBalance" RPC from MoneyServer or Script
public XmlRpcResponse BalanceUpdateHandler(XmlRpcRequest request, IPEndPoint remoteClient)
{
//m_log.InfoFormat("[MONEY]: BalanceUpdateHandler:");
bool ret = false;
#region Update the balance from money server.
if (request.Params.Count>0)
{
Hashtable requestParam = (Hashtable)request.Params[0];
if (requestParam.Contains("clientUUID") &&
requestParam.Contains("clientSessionID") && // unable for Aurora-Sim
requestParam.Contains("clientSecureSessionID"))
{
UUID clientUUID = UUID.Zero;
UUID.TryParse((string)requestParam["clientUUID"], out clientUUID);
if (clientUUID!=UUID.Zero)
{
IClientAPI client = GetLocateClient(clientUUID);
if (client!=null &&
client.SessionId.ToString()==(string)requestParam["clientSessionID"] && // unable for Aurora-Sim
client.SecureSessionId.ToString()==(string)requestParam["clientSecureSessionID"])
{
if (requestParam.Contains("Balance"))
{
// Send notify to the client.
string msg = "";
if (requestParam.Contains("Message")) msg = (string)requestParam["Message"];
//client.SendMoneyBalance(UUID.Random(), true, Utils.StringToBytes(msg), (int)requestParam["Balance"]);
client.SendMoneyBalance(UUID.Random(), true, Utils.StringToBytes(msg), (int)requestParam["Balance"],
0, UUID.Zero, false, UUID.Zero, false, 0, String.Empty);
ret = true;
}
}
}
}
}
#endregion
// Send the response to money server.
XmlRpcResponse resp = new XmlRpcResponse();
Hashtable paramTable = new Hashtable();
paramTable["success"] = ret;
if (!ret)
{
m_log.ErrorFormat("[MONEY]: BalanceUpdateHandler: Cannot update client balance from MoneyServer");
}
resp.Value = paramTable;
return resp;
}
// "UserAlert" RPC from Script
public XmlRpcResponse UserAlertHandler(XmlRpcRequest request, IPEndPoint remoteClient)
{
//m_log.InfoFormat("[MONEY]: UserAlertHandler:");
bool ret = false;
#region confirm the request and show the notice from money server.
if (request.Params.Count>0)
{
Hashtable requestParam = (Hashtable)request.Params[0];
if (requestParam.Contains("clientUUID") &&
requestParam.Contains("clientSessionID") && // unable for Aurora-Sim
requestParam.Contains("clientSecureSessionID"))
{
UUID clientUUID = UUID.Zero;
UUID.TryParse((string)requestParam["clientUUID"], out clientUUID);
if (clientUUID!=UUID.Zero)
{
IClientAPI client = GetLocateClient(clientUUID);
if (client!=null &&
client.SessionId.ToString()==(string)requestParam["clientSessionID"] && // unable for Aurora-Sim
client.SecureSessionId.ToString()==(string)requestParam["clientSecureSessionID"])
{
if (requestParam.Contains("Description"))
{
string description = (string)requestParam["Description"];
// Show the notice dialog with money server message.
GridInstantMessage gridMsg = new GridInstantMessage(null, UUID.Zero, "MonyServer", new UUID(clientUUID.ToString()),
(byte)InstantMessageDialog.MessageFromAgent, description, false, new Vector3());
client.SendInstantMessage(gridMsg);
ret = true;
}
}
}
}
}
//
#endregion
// Send the response to money server.
XmlRpcResponse resp = new XmlRpcResponse();
Hashtable paramTable = new Hashtable();
paramTable["success"] = ret;
resp.Value = paramTable;
return resp;
}
// "GetBalance" RPC from Script
public XmlRpcResponse GetBalanceHandler(XmlRpcRequest request, IPEndPoint remoteClient)
{
//m_log.InfoFormat("[MONEY]: GetBalanceHandler:");
bool ret = false;
int balance = -1;
if (request.Params.Count>0)
{
Hashtable requestParam = (Hashtable)request.Params[0];
if (requestParam.Contains("clientUUID") &&
requestParam.Contains("clientSessionID") && // unable for Aurora-Sim
requestParam.Contains("clientSecureSessionID"))
{
UUID clientUUID = UUID.Zero;
UUID.TryParse((string)requestParam["clientUUID"], out clientUUID);
if (clientUUID!=UUID.Zero)
{
IClientAPI client = GetLocateClient(clientUUID);
if (client!=null &&
client.SessionId.ToString()==(string)requestParam["clientSessionID"] && // unable for Aurora-Sim
client.SecureSessionId.ToString()==(string)requestParam["clientSecureSessionID"])
{
balance = QueryBalanceFromMoneyServer(client);
}
}
}
}
// Send the response to caller.
if (balance<0)
{
m_log.ErrorFormat("[MONEY]: GetBalanceHandler: GetBalance transaction is failed");
ret = false;
}
XmlRpcResponse resp = new XmlRpcResponse();
Hashtable paramTable = new Hashtable();
paramTable["success"] = ret;
paramTable["balance"] = balance;
resp.Value = paramTable;
return resp;
}
// "AddBankerMoney" RPC from Script
public XmlRpcResponse AddBankerMoneyHandler(XmlRpcRequest request, IPEndPoint remoteClient)
{
//m_log.InfoFormat("[MONEY]: AddBankerMoneyHandler:");
bool ret = false;
if (request.Params.Count>0)
{
Hashtable requestParam = (Hashtable)request.Params[0];
if (requestParam.Contains("clientUUID") &&
requestParam.Contains("clientSessionID") && // unable for Aurora-Sim
requestParam.Contains("clientSecureSessionID"))
{
UUID bankerUUID = UUID.Zero;
UUID.TryParse((string)requestParam["clientUUID"], out bankerUUID);
if (bankerUUID!=UUID.Zero)
{
IClientAPI client = GetLocateClient(bankerUUID);
if (client!=null &&
client.SessionId.ToString()==(string)requestParam["clientSessionID"] && // unable for Aurora-Sim
client.SecureSessionId.ToString()==(string)requestParam["clientSecureSessionID"])
{
if (requestParam.Contains("amount"))
{
Scene scene = (Scene)client.Scene;
int amount = (int)requestParam["amount"];
ret = AddBankerMoney(bankerUUID, amount, scene.RegionInfo.RegionHandle);
if (m_use_web_settle && m_settle_user)
{
ret = true;
IDialogModule dlg = scene.RequestModuleInterface();
if (dlg!=null) {
dlg.SendUrlToUser(bankerUUID, "SYSTEM", UUID.Zero, UUID.Zero, false, m_settle_message, m_settle_url);
}
}
}
}
}
}
}
if (!ret) m_log.ErrorFormat("[MONEY]: AddBankerMoneyHandler: Add Banker Money transaction is failed");
// Send the response to caller.
XmlRpcResponse resp = new XmlRpcResponse();
Hashtable paramTable = new Hashtable();
paramTable["settle"] = false;
paramTable["success"] = ret;
if (m_use_web_settle && m_settle_user) paramTable["settle"] = true;
resp.Value = paramTable;
return resp;
}
// "SendMoneyBalance" RPC from Script
public XmlRpcResponse SendMoneyBalanceHandler(XmlRpcRequest request, IPEndPoint remoteClient)
{
//m_log.InfoFormat("[MONEY]: SendMoneyBalanceHandler:");
bool ret = false;
if (request.Params.Count>0)
{
Hashtable requestParam = (Hashtable)request.Params[0];
if (requestParam.Contains("clientUUID") &&
requestParam.Contains("secretAccessCode"))
{
UUID clientUUID = UUID.Zero;
UUID.TryParse((string)requestParam["clientUUID"], out clientUUID);
if (clientUUID!=UUID.Zero)
{
if (requestParam.Contains("amount"))
{
int amount = (int)requestParam["amount"];
string secretCode = (string)requestParam["secretAccessCode"];
string scriptIP = remoteClient.Address.ToString();
MD5 md5 = MD5.Create();
byte[] code = md5.ComputeHash(ASCIIEncoding.Default.GetBytes(secretCode + "_" + scriptIP));
string hash = BitConverter.ToString(code).ToLower().Replace("-","");
//m_log.InfoFormat("[MONEY]: SendMoneyBalanceHandler: SecretCode: {0} + {1} = {2}", secretCode, scriptIP, hash);
ret = SendMoneyBalance(clientUUID, amount, hash);
}
}
else {
m_log.ErrorFormat("[MONEY]: SendMoneyBalanceHandler: amount is missed");
}
}
else {
if (!requestParam.Contains("clientUUID")) {
m_log.ErrorFormat("[MONEY]: SendMoneyBalanceHandler: clientUUID is missed");
}
if (!requestParam.Contains("secretAccessCode")) {
m_log.ErrorFormat("[MONEY]: SendMoneyBalanceHandler: secretAccessCode is missed");
}
}
}
else {
m_log.ErrorFormat("[MONEY]: SendMoneyBalanceHandler: Count is under 0");
}
if (!ret) m_log.ErrorFormat("[MONEY]: SendMoneyBalanceHandler: Send Money transaction is failed");
// Send the response to caller.
XmlRpcResponse resp = new XmlRpcResponse();
Hashtable paramTable = new Hashtable();
paramTable["success"] = ret;
resp.Value = paramTable;
return resp;
}
/*
// "UploadCovered" RPC for Aurora-Sim
public XmlRpcResponse UploadCoveredHandler(XmlRpcRequest request, IPEndPoint remoteClient)
{
//m_log.InfoFormat("[MONEY]: UploadCoveredHandler:");
bool ret = false;
if (request.Params.Count>0)
{
Hashtable requestParam = (Hashtable)request.Params[0];
if (requestParam.Contains("clientUUID") &&
requestParam.Contains("clientSessionID") &&
requestParam.Contains("clientSecureSessionID"))
{
UUID clientUUID = UUID.Zero;
UUID.TryParse((string)requestParam["clientUUID"], out clientUUID);
if (clientUUID!=UUID.Zero)
{
IClientAPI client = GetLocateClient(clientUUID);
if (client!=null &&
client.SessionId.ToString()==(string)requestParam["clientSessionID"] &&
client.SecureSessionId.ToString()==(string)requestParam["clientSecureSessionID"])
{
ret = UploadCovered(client, UploadCharge);
}
}
}
}
// Send the response to caller.
XmlRpcResponse resp = new XmlRpcResponse();
Hashtable paramTable = new Hashtable();
paramTable["success"] = ret;
resp.Value = paramTable;
return resp;
}
*/
/*
// "UploadCovered" RPC for Aurora-Sim
public XmlRpcResponse UploadChargeHandler(XmlRpcRequest request, IPEndPoint remoteClient)
{
//m_log.InfoFormat("[MONEY]: UploadChargeHandler:");
bool ret = false;
if (request.Params.Count>0)
{
Hashtable requestParam = (Hashtable)request.Params[0];
if (requestParam.Contains("clientUUID") &&
requestParam.Contains("clientSessionID") &&
requestParam.Contains("clientSecureSessionID"))
{
UUID clientUUID = UUID.Zero;
UUID.TryParse((string)requestParam["clientUUID"], out clientUUID);
if (clientUUID!=UUID.Zero)
{
IClientAPI client = GetLocateClient(clientUUID);
if (client!=null &&
client.SessionId.ToString()==(string)requestParam["clientSessionID"] &&
client.SecureSessionId.ToString()==(string)requestParam["clientSecureSessionID"])
{
ApplyUploadCharge(clientUUID, UploadCharge, "Upload Asset");
ret = true;
}
}
}
}
// Send the response to caller.
XmlRpcResponse resp = new XmlRpcResponse();
Hashtable paramTable = new Hashtable();
paramTable["success"] = ret;
resp.Value = paramTable;
return resp;
}
*/
#endregion
#region MoneyModule private help functions
///
/// Transfer the money from one user to another. Need to notify money server to update.
///
///
/// The amount of money.
///
///
/// return true, if successfully.
///
private bool TransferMoney(UUID sender, UUID receiver, int amount, int type, UUID objectID, ulong regionHandle, string description)
{
//m_log.InfoFormat("[MONEY]: TransferMoney:");
bool ret = false;
IClientAPI senderClient = GetLocateClient(sender);
// Handle the illegal transaction.
if (senderClient==null) // receiverClient could be null.
{
m_log.InfoFormat("[MONEY]: TransferMoney: Client {0} not found", sender.ToString());
return false;
}
if (QueryBalanceFromMoneyServer(senderClient)
/// Force transfer the money from one user to another.
/// This function does not check sender login.
/// Need to notify money server to update.
///
///
/// The amount of money.
///
///
/// return true, if successfully.
///
private bool ForceTransferMoney(UUID sender, UUID receiver, int amount, int type, UUID objectID, ulong regionHandle, string description)
{
//m_log.InfoFormat("[MONEY]: ForceTransferMoney:");
bool ret = false;
#region Force send transaction request to money server and parse the resultes.
if (m_enable_server)
{
// Fill parameters for money transfer XML-RPC.
Hashtable paramTable = new Hashtable();
paramTable["senderID"] = sender.ToString();
paramTable["receiverID"] = receiver.ToString();
paramTable["transactionType"] = type;
paramTable["objectID"] = objectID.ToString();
paramTable["regionHandle"] = regionHandle.ToString();
paramTable["amount"] = amount;
paramTable["description"] = description;
// Generate the request for transfer.
Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "ForceTransferMoney");
// Handle the return values from Money Server.
if (resultTable!=null && resultTable.Contains("success"))
{
if ((bool)resultTable["success"]==true)
{
ret = true;
}
}
else m_log.ErrorFormat("[MONEY]: ForceTransferMoney: Can not money force transfer request from [{0}] to [{1}]", sender.ToString(), receiver.ToString());
}
//else m_log.ErrorFormat("[MONEY]: ForceTransferMoney: Money Server is not available!!");
#endregion
return ret;
}
///
/// Add the money to banker avatar. Need to notify money server to update.
///
///
/// The amount of money.
///
///
/// return true, if successfully.
///
private bool AddBankerMoney(UUID bankerID, int amount, ulong regionHandle)
{
//m_log.InfoFormat("[MONEY]: AddBankerMoney:");
bool ret = false;
m_settle_user = false;
if (m_enable_server)
{
// Fill parameters for money transfer XML-RPC.
Hashtable paramTable = new Hashtable();
paramTable["bankerID"] = bankerID.ToString();
paramTable["transactionType"] = (int)TransactionType.BuyMoney;
paramTable["amount"] = amount;
paramTable["regionHandle"] = regionHandle.ToString();
paramTable["description"] = "Add Money to Avatar";
// Generate the request for transfer.
Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "AddBankerMoney");
// Handle the return values from Money Server.
if (resultTable!=null)
{
if (resultTable.Contains("success") && (bool)resultTable["success"]==true)
{
ret = true;
}
else
{
if (resultTable.Contains("banker"))
{
m_settle_user = !(bool)resultTable["banker"]; // If avatar is not banker, Web Settlement is used.
if (m_settle_user && m_use_web_settle) m_log.ErrorFormat("[MONEY]: AddBankerMoney: Avatar is not Banker. Web Settlemrnt is used.");
}
else m_log.ErrorFormat("[MONEY]: AddBankerMoney: Fail Message {0}", resultTable["message"]);
}
}
else m_log.ErrorFormat("[MONEY]: AddBankerMoney: Money Server is not responce");
}
//else m_log.ErrorFormat("[MONEY]: AddBankerMoney: Money Server is not available!!");
return ret;
}
///
/// Send the money to avatar. Need to notify money server to update.
///
///
/// The amount of money.
///
///
/// return true, if successfully.
///
private bool SendMoneyBalance(UUID avatarID, int amount, string secretCode)
{
//m_log.InfoFormat("[MONEY]: SendMoneyBalance:");
bool ret = false;
if (m_enable_server)
{
// Fill parameters for money transfer XML-RPC.
Hashtable paramTable = new Hashtable();
paramTable["avatarID"] = avatarID.ToString();
paramTable["transactionType"] = (int)MoneyTransactionType.ReferBonus;
paramTable["amount"] = amount;
paramTable["secretAccessCode"] = secretCode;
paramTable["description"] = "Bonus to Avatar";
// Generate the request for transfer.
Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "SendMoneyBalance");
// Handle the return values from Money Server.
if (resultTable!=null && resultTable.Contains("success"))
{
if ((bool)resultTable["success"]==true)
{
ret = true;
}
else m_log.ErrorFormat("[MONEY]: SendMoneyBalance: Fail Message is {0}", resultTable["message"]);
}
else m_log.ErrorFormat("[MONEY]: SendMoneyBalance: Money Server is not responce");
}
//else m_log.ErrorFormat("[MONEY]: SendMoneyBalance: Money Server is not available!!");
return ret;
}
///
/// Pay the money of charge.
///
///
/// The amount of money.
///
///
/// return true, if successfully.
///
private bool PayMoneyCharge(UUID sender, int amount, int type, ulong regionHandle, string description)
{
//m_log.InfoFormat("[MONEY]: PayMoneyCharge:");
bool ret = false;
IClientAPI senderClient = GetLocateClient(sender);
// Handle the illegal transaction.
if (senderClient==null) // receiverClient could be null.
{
m_log.InfoFormat("[MONEY]: PayMoneyCharge: Client {0} is not found", sender.ToString());
return false;
}
if (QueryBalanceFromMoneyServer(senderClient)
/// Login the money server when the new client login.
///
///
/// Indicate user ID of the new client.
///
///
/// return true, if successfully.
///
private bool LoginMoneyServer(IClientAPI client, out int balance)
{
//m_log.InfoFormat("[MONEY]: LoginMoneyServer:");
bool ret = false;
balance = 0;
#region Send money server the client info for login.
Scene scene = (Scene)client.Scene;
string userName = string.Empty;
if (!string.IsNullOrEmpty(m_moneyServURL))
{
// Get the username for the login user.
if (client.Scene is Scene)
{
if (scene!=null)
{
UserAccount account = scene.UserAccountService.GetUserAccount(scene.RegionInfo.ScopeID, client.AgentId);
if (account!=null)
{
userName = account.FirstName + " " + account.LastName;
}
}
}
// Login the Money Server.
Hashtable paramTable = new Hashtable();
paramTable["openSimServIP"] = scene.RegionInfo.ServerURI.Replace(scene.RegionInfo.InternalEndPoint.Port.ToString(),
scene.RegionInfo.HttpPort.ToString());
paramTable["userName"] = userName;
paramTable["clientUUID"] = client.AgentId.ToString();
paramTable["clientSessionID"] = client.SessionId.ToString();
paramTable["clientSecureSessionID"] = client.SecureSessionId.ToString();
// Generate the request for transfer.
Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "ClientLogin");
// Handle the return result
if (resultTable!=null && resultTable.Contains("success"))
{
if ((bool)resultTable["success"]==true)
{
balance = (int)resultTable["clientBalance"];
m_log.InfoFormat("[MONEY]: LoginMoneyServer: Client [{0}] login Money Server {1}", client.AgentId.ToString(), m_moneyServURL);
ret = true;
}
}
else m_log.ErrorFormat("[MONEY]: LoginMoneyServer: Unable to login Money Server {0} for client [{1}]", m_moneyServURL, client.AgentId.ToString());
}
else m_log.ErrorFormat("[MONEY]: LoginMoneyServer: Money Server is not available!!");
#endregion
// Viewerへ設定を通知する.
OnEconomyDataRequest(client);
return ret;
}
///
/// Log off from the money server.
///
///
/// Indicate user ID of the new client.
///
///
/// return true, if successfully.
///
private bool LogoffMoneyServer(IClientAPI client)
{
//m_log.InfoFormat("[MONEY]: LogoffMoneyServer:");
bool ret = false;
if (!string.IsNullOrEmpty(m_moneyServURL))
{
// Log off from the Money Server.
Hashtable paramTable = new Hashtable();
paramTable["clientUUID"] = client.AgentId.ToString();
paramTable["clientSessionID"] = client.SessionId.ToString();
paramTable["clientSecureSessionID"] = client.SecureSessionId.ToString();
// Generate the request for transfer.
Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "ClientLogout");
// Handle the return result
if (resultTable!=null && resultTable.Contains("success"))
{
if ((bool)resultTable["success"]==true)
{
ret = true;
}
}
}
return ret;
}
///
/// Generic XMLRPC client abstraction
///
/// Hashtable containing parameters to the method
/// Method to invoke
/// Hashtable with success=>bool and other values
private Hashtable genericCurrencyXMLRPCRequest(Hashtable reqParams, string method)
{
//m_log.InfoFormat("[MONEY]: genericCurrencyXMLRPCRequest:");
if (reqParams.Count<=0 || string.IsNullOrEmpty(method)) return null;
if (m_checkServerCert)
{
if (!m_moneyServURL.StartsWith("https://"))
{
m_log.InfoFormat("[MONEY]: genericCurrencyXMLRPCRequest: CheckServerCert is true, but protocol is not HTTPS. Please check INI file");
//return null;
}
}
else
{
if (!m_moneyServURL.StartsWith("https://") && !m_moneyServURL.StartsWith("http://"))
{
m_log.ErrorFormat("[MONEY]: genericCurrencyXMLRPCRequest: Invalid Money Server URL: {0}", m_moneyServURL);
return null;
}
}
ArrayList arrayParams = new ArrayList();
arrayParams.Add(reqParams);
XmlRpcResponse moneyServResp = null;
try
{
NSLXmlRpcRequest moneyModuleReq = new NSLXmlRpcRequest(method, arrayParams);
moneyServResp = moneyModuleReq.certSend(m_moneyServURL, m_cert, m_checkServerCert, MONEYMODULE_REQUEST_TIMEOUT);
}
catch (Exception ex)
{
m_log.ErrorFormat("[MONEY]: genericCurrencyXMLRPCRequest: Unable to connect to Money Server {0}", m_moneyServURL);
m_log.ErrorFormat("[MONEY]: genericCurrencyXMLRPCRequest: {0}", ex);
Hashtable ErrorHash = new Hashtable();
ErrorHash["success"] = false;
ErrorHash["errorMessage"] = "Unable to manage your money at this time. Purchases may be unavailable";
ErrorHash["errorURI"] = "";
return ErrorHash;
}
if (moneyServResp.IsFault)
{
Hashtable ErrorHash = new Hashtable();
ErrorHash["success"] = false;
ErrorHash["errorMessage"] = "Unable to manage your money at this time. Purchases may be unavailable";
ErrorHash["errorURI"] = "";
return ErrorHash;
}
Hashtable moneyRespData = (Hashtable)moneyServResp.Value;
return moneyRespData;
}
private int QueryBalanceFromMoneyServer(IClientAPI client)
{
//m_log.InfoFormat("[MONEY]: QueryBalanceFromMoneyServer:");
int balance = 0;
#region Send the request to get the balance from money server for cilent.
if (client!=null)
{
if (m_enable_server)
{
Hashtable paramTable = new Hashtable();
paramTable["clientUUID"] = client.AgentId.ToString();
paramTable["clientSessionID"] = client.SessionId.ToString();
paramTable["clientSecureSessionID"] = client.SecureSessionId.ToString();
// Generate the request for transfer.
Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "GetBalance");
// Handle the return result
if (resultTable!=null && resultTable.Contains("success"))
{
if ((bool)resultTable["success"]==true)
{
balance = (int)resultTable["clientBalance"];
}
}
}
else
{
if (m_moneyServer.ContainsKey(client.AgentId))
{
balance = m_moneyServer[client.AgentId];
}
}
}
#endregion
return balance;
}
//
private EventManager.MoneyTransferArgs GetTransactionInfo(IClientAPI client, string transactionID)
{
//m_log.InfoFormat("[MONEY]: GetTransactionInfo:");
EventManager.MoneyTransferArgs args = null;
if (m_enable_server)
{
Hashtable paramTable = new Hashtable();
paramTable["clientUUID"] = client.AgentId.ToString();
paramTable["clientSessionID"] = client.SessionId.ToString();
paramTable["clientSecureSessionID"] = client.SecureSessionId.ToString();
paramTable["transactionID"] = transactionID;
// Generate the request for transfer.
Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "GetTransaction");
// Handle the return result
if (resultTable!=null && resultTable.Contains("success"))
{
if ((bool)resultTable["success"]==true)
{
int amount = (int)resultTable["amount"];
int type = (int)resultTable["type"];
string desc = (string)resultTable["description"];
UUID sender = UUID.Zero;
UUID recver = UUID.Zero;
UUID.TryParse((string)resultTable["sender"], out sender);
UUID.TryParse((string)resultTable["receiver"], out recver);
args = new EventManager.MoneyTransferArgs(sender, recver, amount, type, desc);
}
else
{
m_log.ErrorFormat("[MONEY]: GetTransactionInfo: GetTransactionInfo: Fail to Request. {0}", (string)resultTable["description"]);
}
}
else
{
m_log.ErrorFormat("[MONEY]: GetTransactionInfo: Invalid Response");
}
}
else
{
m_log.ErrorFormat("[MONEY]: GetTransactionInfo: Invalid Money Server URL");
}
return args;
}
/// Locates a IClientAPI for the client specified
///
///
///
private IClientAPI GetLocateClient(UUID AgentID)
{
IClientAPI client = null;
lock (m_sceneList)
{
if (m_sceneList.Count>0)
{
foreach (Scene _scene in m_sceneList.Values)
{
ScenePresence tPresence = (ScenePresence)_scene.GetScenePresence(AgentID);
if (tPresence!=null && !tPresence.IsChildAgent)
{
IClientAPI rclient = tPresence.ControllingClient;
if (rclient!=null)
{
client = rclient;
break;
}
}
}
}
}
return client;
}
private Scene GetLocateScene(UUID AgentId)
{
Scene scene = null;
lock (m_sceneList)
{
if (m_sceneList.Count>0)
{
foreach (Scene _scene in m_sceneList.Values)
{
ScenePresence tPresence = (ScenePresence)_scene.GetScenePresence(AgentId);
if (tPresence!=null && !tPresence.IsChildAgent)
{
scene = _scene;
break;
}
}
}
}
return scene;
}
private SceneObjectPart GetLocatePrim(UUID objectID)
{
SceneObjectPart sceneObj = null;
lock (m_sceneList)
{
if (m_sceneList.Count>0)
{
foreach (Scene _scene in m_sceneList.Values)
{
SceneObjectPart part = (SceneObjectPart)_scene.GetSceneObjectPart(objectID);
if (part!=null)
{
sceneObj = part;
break;
}
}
}
}
return sceneObj;
}
#endregion
}
}