diff --git a/OpenSim/Framework/AgentCircuitData.cs b/OpenSim/Framework/AgentCircuitData.cs index 65a072f056..b8eb9fc449 100644 --- a/OpenSim/Framework/AgentCircuitData.cs +++ b/OpenSim/Framework/AgentCircuitData.cs @@ -49,6 +49,7 @@ namespace OpenSim.Framework InventoryFolder = new LLUUID(cAgent.InventoryFolder); BaseFolder = new LLUUID(cAgent.BaseFolder); CapsPath = cAgent.CapsPath; + ClientVersion = cAgent.ClientVersion; //rex } public LLUUID AgentID; @@ -62,6 +63,9 @@ namespace OpenSim.Framework public LLUUID InventoryFolder; public LLUUID BaseFolder; public string CapsPath = ""; + public string ClientVersion = "not set"; //rex + public string authenticationAddr; + public string asAddress = ""; } [Serializable] @@ -86,6 +90,7 @@ namespace OpenSim.Framework InventoryFolder = cAgent.InventoryFolder.UUID; BaseFolder = cAgent.BaseFolder.UUID; CapsPath = cAgent.CapsPath; + ClientVersion = cAgent.ClientVersion; //rex } public Guid AgentID; @@ -101,5 +106,6 @@ namespace OpenSim.Framework public Guid InventoryFolder; public Guid BaseFolder; public string CapsPath = ""; + public string ClientVersion = "not set"; //rex } } \ No newline at end of file diff --git a/OpenSim/Framework/AgentCircuitManager.cs b/OpenSim/Framework/AgentCircuitManager.cs index 938dce8db9..b6cd4d25a0 100644 --- a/OpenSim/Framework/AgentCircuitManager.cs +++ b/OpenSim/Framework/AgentCircuitManager.cs @@ -64,6 +64,7 @@ namespace OpenSim.Framework user.LoginInfo.Last = validcircuit.lastname; user.LoginInfo.InventoryFolder = validcircuit.InventoryFolder; user.LoginInfo.BaseFolder = validcircuit.BaseFolder; + user.LoginInfo.ClientVersion = validcircuit.ClientVersion;//rex } else { diff --git a/OpenSim/Framework/AssetBase.cs b/OpenSim/Framework/AssetBase.cs index 2bef61b0e8..c6aa2c1ced 100644 --- a/OpenSim/Framework/AssetBase.cs +++ b/OpenSim/Framework/AssetBase.cs @@ -39,6 +39,7 @@ namespace OpenSim.Framework public sbyte InvType; public string Name = ""; public string Description = ""; + public string MediaURL = "";//rex public bool Local = false; public bool Temporary = false; diff --git a/OpenSim/Framework/AssetLandmark.cs b/OpenSim/Framework/AssetLandmark.cs index 050b80f27f..c9fa763e64 100644 --- a/OpenSim/Framework/AssetLandmark.cs +++ b/OpenSim/Framework/AssetLandmark.cs @@ -44,6 +44,7 @@ namespace OpenSim.Framework InvType = a.InvType; Name = a.Name; Description = a.Description; + MediaURL = a.MediaURL; //rex InternData(); } diff --git a/OpenSim/Framework/Communications/Cache/AssetCache.cs b/OpenSim/Framework/Communications/Cache/AssetCache.cs index bd3437bde7..3c1215ada8 100644 --- a/OpenSim/Framework/Communications/Cache/AssetCache.cs +++ b/OpenSim/Framework/Communications/Cache/AssetCache.cs @@ -202,6 +202,18 @@ namespace OpenSim.Framework.Communications.Cache return null; } + // rex, new function + public List GetAssetList(int vAssetType) + { + return m_assetServer.GetAssetList(vAssetType); + } + + // rex, new function + public AssetBase FetchAsset(LLUUID assetID) + { + return m_assetServer.FetchAsset(assetID); + } + /// /// Add an asset to both the persistent store and the cache. /// @@ -259,6 +271,106 @@ namespace OpenSim.Framework.Communications.Cache m_log.Verbose("ASSETCACHE", "Adding {0} {1} [{2}]: {3}.", temporary, type, asset.FullID, result); } + // rex, new function for "replace asset" functionality + public void ReplaceAsset(AssetBase asset) + { + string temporary = asset.Temporary ? "temporary" : ""; + string type = asset.Type == 0 ? "texture" : "asset"; + + string result = "Ignored"; + + if (asset.Type == 0) + { + if (Textures.ContainsKey(asset.FullID)) + { + Textures.Remove(asset.FullID); + } + + TextureImage textur = new TextureImage(asset); + Textures.Add(textur.FullID, textur); + + if (asset.Temporary) + { + result = "Replaced old asset in cache"; + } + else + { + m_assetServer.UpdateAsset(asset); + result = "Replaced old asset on server"; + } + } + else + { + if (Assets.ContainsKey(asset.FullID)) + { + Assets.Remove(asset.FullID); + } + + AssetInfo assetInf = new AssetInfo(asset); + Assets.Add(assetInf.FullID, assetInf); + + if (asset.Temporary) + { + result = "Replaced old asset in cache"; + } + else + { + m_assetServer.UpdateAsset(asset); + result = "Replaced old asset on server"; + } + } + + m_log.Verbose("ASSETCACHE", "Adding {0} {1} [{2}]: {3}.", temporary, type, asset.FullID, result); + } + + // rex new function + public bool ExistsAsset(LLUUID assetID) + { + if (Textures.ContainsKey(assetID)) + return true; + if (Assets.ContainsKey(assetID)) + return true; + return m_assetServer.ExistsAsset(assetID); + } + + // rex new function for "replace asset" functionality + public LLUUID ExistsAsset(sbyte type, string name) + { + // First check locally cached assets + // Texture or other asset? + if (type == 0) + { + foreach (KeyValuePair kvp in Textures) + { + TextureImage t = kvp.Value; + if (t != null) + { + if ((t.Name == name) && (t.Type == type)) + { + return t.FullID; + } + } + } + } + else + { + foreach (KeyValuePair kvp in Assets) + { + AssetInfo a = kvp.Value; + if (a != null) + { + if ((a.Name == name) && (a.Type == type)) + { + return a.FullID; + } + } + } + } + + // Then have to check asset server + return m_assetServer.ExistsAsset(type, name); + } + public void DeleteAsset(LLUUID assetID) { // this.m_assetServer.DeleteAsset(assetID); @@ -564,6 +676,7 @@ namespace OpenSim.Framework.Communications.Cache InvType = aBase.InvType; Name = aBase.Name; Description = aBase.Description; + MediaURL = aBase.MediaURL; //rex } } @@ -581,6 +694,7 @@ namespace OpenSim.Framework.Communications.Cache InvType = aBase.InvType; Name = aBase.Name; Description = aBase.Description; + MediaURL = aBase.MediaURL; //rex } } diff --git a/OpenSim/Framework/Communications/Cache/AssetServer.cs b/OpenSim/Framework/Communications/Cache/AssetServer.cs index 575e80a2d4..8fa20f49a0 100644 --- a/OpenSim/Framework/Communications/Cache/AssetServer.cs +++ b/OpenSim/Framework/Communications/Cache/AssetServer.cs @@ -72,6 +72,60 @@ namespace OpenSim.Framework.Communications.Cache } } + // rex new function for "replace assets" functionality + public override LLUUID ExistsAsset(sbyte assetType, string name) + { + IObjectSet result = db.Query(new AssetTypeNameQuery(assetType, name)); + AssetStorage foundAsset = null; + if (result.Count > 0) + { + foundAsset = (AssetStorage)result.Next(); + return foundAsset.UUID; + } + return LLUUID.Zero; + } + + // rex new function + public override bool ExistsAsset(LLUUID assetID) + { + IObjectSet result = db.Query(new AssetUUIDQuery(assetID)); + if (result.Count > 0) + return true; + else + return false; + } + + // rex new function + public override AssetBase FetchAsset(LLUUID assetID) + { + byte[] idata = null; + bool found = false; + AssetStorage foundAsset = null; + IObjectSet result = db.Query(new AssetUUIDQuery(assetID)); + if (result.Count > 0) + { + foundAsset = (AssetStorage)result.Next(); + found = true; + } + + AssetBase asset = new AssetBase(); + if (found) + { + asset.FullID = foundAsset.UUID; + asset.Type = foundAsset.Type; + asset.InvType = foundAsset.Type; + asset.Name = foundAsset.Name; + idata = foundAsset.Data; + asset.Data = idata; + + return asset; + } + else + { + return null; + } + } + protected override AssetBase GetAsset(AssetRequest req) { byte[] idata = null; @@ -113,6 +167,25 @@ namespace OpenSim.Framework.Communications.Cache CommitAssets(); } + // rex overrided function for "replace assets" functionality to work with local assetserver + public override void UpdateAsset(AssetBase asset) + { + lock (m_syncLock) + { + IObjectSet result = db.Query(new AssetUUIDQuery(asset.FullID)); + AssetStorage foundAsset = null; + + int i; + for (i = 0; i < result.Count; i++) + { + foundAsset = (AssetStorage)result.Next(); + db.Delete(foundAsset); + } + + StoreAsset(asset); + } + } + protected override void CommitAssets() { db.Commit(); @@ -140,4 +213,22 @@ namespace OpenSim.Framework.Communications.Cache return (asset.UUID == _findID); } } + + // rex new class for "replace assets" functionality + public class AssetTypeNameQuery : Predicate + { + private sbyte _findType; + private string _findName; + + public AssetTypeNameQuery(sbyte type, string name) + { + _findType = type; + _findName = name; + } + + public bool Match(AssetStorage asset) + { + return ((asset.Type == _findType) && (asset.Name == _findName)); + } + } } \ No newline at end of file diff --git a/OpenSim/Framework/Communications/Cache/AssetServerBase.cs b/OpenSim/Framework/Communications/Cache/AssetServerBase.cs index 09f8a0c102..75eb3f79a3 100644 --- a/OpenSim/Framework/Communications/Cache/AssetServerBase.cs +++ b/OpenSim/Framework/Communications/Cache/AssetServerBase.cs @@ -49,6 +49,8 @@ namespace OpenSim.Framework.Communications.Cache protected abstract void StoreAsset(AssetBase asset); protected abstract void CommitAssets(); + public abstract LLUUID ExistsAsset(sbyte assetType, string name); // rex new function for "replace assets" functionality + /// /// This method must be implemented by a subclass to retrieve the asset named in the /// AssetRequest. If the asset is not found, null should be returned. @@ -68,8 +70,8 @@ namespace OpenSim.Framework.Communications.Cache if (asset != null) { - //MainLog.Instance.Verbose( - // "ASSET", "Asset {0} received from asset server", req.AssetID); + MainLog.Instance.Verbose( + "ASSET", "Asset {0} received from asset server", req.AssetID); m_receiver.AssetReceived(asset, req.IsTexture); } @@ -152,6 +154,33 @@ namespace OpenSim.Framework.Communications.Cache } } + // rex, new function + public List GetAssetList(int vAssetType) + { + lock (m_syncLock) + { + return m_assetProvider.GetAssetList(vAssetType); + } + } + + // rex, new function + public virtual AssetBase FetchAsset(LLUUID assetID) + { + lock (m_syncLock) + { + return m_assetProvider.FetchAsset(assetID); + } + } + + // rex, new function + public virtual bool ExistsAsset(LLUUID assetID) + { + lock (m_syncLock) + { + return m_assetProvider.ExistsAsset(assetID); + } + } + public virtual void Close() { m_localAssetServerThread.Abort(); diff --git a/OpenSim/Framework/Communications/Cache/GridAssetClient.cs b/OpenSim/Framework/Communications/Cache/GridAssetClient.cs index cf54fa4484..fc223a7467 100644 --- a/OpenSim/Framework/Communications/Cache/GridAssetClient.cs +++ b/OpenSim/Framework/Communications/Cache/GridAssetClient.cs @@ -116,6 +116,13 @@ namespace OpenSim.Framework.Communications.Cache throw new Exception("The method or operation is not implemented."); } + // rex new function for "replace assets" functionality + // TODO: implementation by someone + public override libsecondlife.LLUUID ExistsAsset(sbyte assetType, string name) + { + throw new Exception("The method or operation is not implemented."); + } + #endregion } } \ No newline at end of file diff --git a/OpenSim/Framework/Communications/Cache/InventoryFolderImpl.cs b/OpenSim/Framework/Communications/Cache/InventoryFolderImpl.cs index a1e79b22b5..d50836ba8d 100644 --- a/OpenSim/Framework/Communications/Cache/InventoryFolderImpl.cs +++ b/OpenSim/Framework/Communications/Cache/InventoryFolderImpl.cs @@ -152,5 +152,33 @@ namespace OpenSim.Framework.Communications.Cache } return folderList; } + + // rex, new function + public void ClearFolder() + { + Items.Clear(); + SubFolders.Clear(); + } + + // rex, new function + public bool HasAssetID(LLUUID assetID) + { + foreach (InventoryItemBase item in Items.Values) + { + if (item.assetID == assetID) + return true; + } + + foreach (InventoryFolderImpl folder in SubFolders.Values) + { + if (folder.name != "World Library") + { + if (folder.HasAssetID(assetID)) + return true; + } + } + + return false; + } } } \ No newline at end of file diff --git a/OpenSim/Framework/Communications/Cache/RexWorldAssetsFolder.cs b/OpenSim/Framework/Communications/Cache/RexWorldAssetsFolder.cs new file mode 100644 index 0000000000..278a56701a --- /dev/null +++ b/OpenSim/Framework/Communications/Cache/RexWorldAssetsFolder.cs @@ -0,0 +1,86 @@ +// Rex, new file +using System.Collections.Generic; +using System.IO; +using System.Xml; +using libsecondlife; +using Nini.Config; + +using OpenSim.Framework.Console; + +namespace OpenSim.Framework.Communications.Cache +{ + // Rex, new class implementing the world assets folder + public class RexWorldAssetsFolder : InventoryFolderImpl + { + private LLUUID libOwner = new LLUUID("11111111-1111-0000-0000-000100bba001"); + private InventoryFolderImpl m_WorldTexturesFolder; + private InventoryFolderImpl m_World3DModelsFolder; + private AssetCache AssetCache; + + public RexWorldAssetsFolder(AssetCache vAssetCache) + { + MainLog.Instance.Verbose("LIBRARYINVENTORY", "Creating World library folder"); + AssetCache = vAssetCache; + + agentID = libOwner; + folderID = new LLUUID("00000112-000f-0000-0000-000100bba005"); + name = "World Library"; + parentID = new LLUUID("00000112-000f-0000-0000-000100bba000"); + type = (short)8; + version = (ushort)1; + + CreateNewSubFolder(new LLUUID("00000112-000f-0000-0000-000100bba006"), "Textures", (ushort)8); + m_WorldTexturesFolder = HasSubFolder("00000112-000f-0000-0000-000100bba006"); + + CreateNewSubFolder(new LLUUID("00000112-000f-0000-0000-000100bba007"), "3D Models", (ushort)8); + m_World3DModelsFolder = HasSubFolder("00000112-000f-0000-0000-000100bba007"); + } + + public InventoryItemBase CreateItem(LLUUID inventoryID, LLUUID assetID, string name, string description, + int assetType, int invType, LLUUID parentFolderID) + { + InventoryItemBase item = new InventoryItemBase(); + item.avatarID = libOwner; + item.creatorsID = libOwner; + item.inventoryID = inventoryID; + item.assetID = assetID; + item.inventoryDescription = description; + item.inventoryName = name; + item.assetType = assetType; + item.invType = invType; + item.parentFolderID = parentFolderID; + item.inventoryBasePermissions = 0x7FFFFFFF; + item.inventoryEveryOnePermissions = 0x7FFFFFFF; + item.inventoryCurrentPermissions = 0x7FFFFFFF; + item.inventoryNextPermissions = 0x7FFFFFFF; + return item; + } + + // Rex, function added. + public void UpdateWorldAssetFolders() + { + // Textures + List allTex = AssetCache.GetAssetList(0); + m_WorldTexturesFolder.ClearFolder(); + + InventoryItemBase item; + foreach (AssetBase asset in allTex) + { + item = CreateItem(LLUUID.Random(), asset.FullID, asset.Name, asset.Description, (int)AssetType.Texture, (int)InventoryType.Texture, m_WorldTexturesFolder.folderID); + m_WorldTexturesFolder.Items.Add(item.inventoryID, item); + } + + // 3D Models + List allModels = AssetCache.GetAssetList(6); + m_World3DModelsFolder.ClearFolder(); + foreach (AssetBase asset in allModels) + { + if (asset.Name != "Primitive") + { + item = CreateItem(LLUUID.Random(), asset.FullID, asset.Name, asset.Description, 43, 6, m_World3DModelsFolder.folderID); + m_World3DModelsFolder.Items.Add(item.inventoryID, item); + } + } + } + } +} diff --git a/OpenSim/Framework/Communications/Cache/SQLAssetServer.cs b/OpenSim/Framework/Communications/Cache/SQLAssetServer.cs index 0a141c3629..431be8115f 100644 --- a/OpenSim/Framework/Communications/Cache/SQLAssetServer.cs +++ b/OpenSim/Framework/Communications/Cache/SQLAssetServer.cs @@ -77,6 +77,12 @@ namespace OpenSim.Framework.Communications.Cache m_assetProvider.CommitAssets(); } + // rex new function for "replace assets" functionality + public override libsecondlife.LLUUID ExistsAsset(sbyte assetType, string name) + { + return m_assetProvider.ExistsAsset(assetType, name); + } + protected override AssetBase GetAsset(AssetRequest req) { AssetBase asset; diff --git a/OpenSim/Framework/Communications/Cache/UserProfileCacheService.cs b/OpenSim/Framework/Communications/Cache/UserProfileCacheService.cs index 14670fda5c..4a32148179 100644 --- a/OpenSim/Framework/Communications/Cache/UserProfileCacheService.cs +++ b/OpenSim/Framework/Communications/Cache/UserProfileCacheService.cs @@ -38,11 +38,19 @@ namespace OpenSim.Framework.Communications.Cache private readonly Dictionary m_userProfiles = new Dictionary(); public LibraryRootFolder libraryRoot = new LibraryRootFolder(); + public RexWorldAssetsFolder worldlibraryRoot = null; // rex added // Methods public UserProfileCacheService(CommunicationsManager parent) { m_parent = parent; + // rex, added worldlibrary + if (GlobalSettings.Instance.ConfigSource.Configs["Startup"].GetBoolean("worldlibraryfolder", true)) + { + worldlibraryRoot = new RexWorldAssetsFolder(m_parent.AssetCache); + libraryRoot.CreateNewSubFolder(new LLUUID("00000112-000f-0000-0000-000100bba005"), "World Library", (ushort)8); + } + // rexend } /// @@ -58,7 +66,7 @@ namespace OpenSim.Framework.Communications.Cache if (!m_userProfiles.ContainsKey(userID)) { CachedUserInfo userInfo = new CachedUserInfo(m_parent); - userInfo.UserProfile = m_parent.UserService.GetUserProfile(userID); + userInfo.UserProfile = m_parent.UserService.GetUserProfile(userID, ""); if (userInfo.UserProfile != null) { @@ -75,6 +83,39 @@ namespace OpenSim.Framework.Communications.Cache } } + //Rex mode + /// + /// A new user has moved into a region in this instance + /// so get info from servers + /// + /// + public void AddNewUser(LLUUID userID, string authAddr) + { + // Potential fix - Multithreading issue. + lock (m_userProfiles) + { + if (!m_userProfiles.ContainsKey(userID)) + { + CachedUserInfo userInfo = new CachedUserInfo(m_parent); + userInfo.UserProfile = m_parent.UserService.GetUserProfile(userID, authAddr); + + if (userInfo.UserProfile != null) + { + //RequestInventoryForUser(userID, userInfo); + // The request itself will occur when the agent finishes logging on to the region + // so there's no need to do it here. + //RequestInventoryForUser(userID, userInfo); + m_userProfiles.Add(userID, userInfo); + } + else + { + System.Console.WriteLine("CACHE", "User profile for user not found"); + } + } + } + } + + public void UpdateUserInventory(LLUUID userID) { CachedUserInfo userInfo = GetUserDetails(userID); @@ -183,6 +224,29 @@ namespace OpenSim.Framework.Communications.Cache // XXX We're not handling sortOrder yet! InventoryFolderImpl fold = null; + + // rex, added worldassetfolder + if (worldlibraryRoot != null) + { + if (folderID == worldlibraryRoot.folderID) + { + remoteClient.SendInventoryFolderDetails( + worldlibraryRoot.agentID, worldlibraryRoot.folderID, worldlibraryRoot.RequestListOfItems(), + worldlibraryRoot.RequestListOfFolders(), fetchFolders, fetchItems); + return; + } + if ((fold = worldlibraryRoot.HasSubFolder(folderID)) != null) + { + worldlibraryRoot.UpdateWorldAssetFolders(); + remoteClient.SendInventoryFolderDetails( + worldlibraryRoot.agentID, folderID, fold.RequestListOfItems(), + fold.RequestListOfFolders(), fetchFolders, fetchItems); + + return; + } + } + // rex-end + if (folderID == libraryRoot.folderID) { remoteClient.SendInventoryFolderDetails( diff --git a/OpenSim/Framework/Communications/Capabilities/Caps.cs b/OpenSim/Framework/Communications/Capabilities/Caps.cs index 74d81253b9..92ece7644b 100644 --- a/OpenSim/Framework/Communications/Capabilities/Caps.cs +++ b/OpenSim/Framework/Communications/Capabilities/Caps.cs @@ -47,6 +47,9 @@ namespace OpenSim.Region.Capabilities public delegate void NewInventoryItem(LLUUID userID, InventoryItemBase item); + // rex, added for asset replace functionality + public delegate bool InventoryAssetCheck(LLUUID userID, LLUUID assetID); + public delegate LLUUID ItemUpdatedCallback(LLUUID userID, LLUUID itemID, byte[] data); public delegate void TaskScriptUpdatedCallback(LLUUID userID, LLUUID itemID, LLUUID primID, @@ -72,10 +75,12 @@ namespace OpenSim.Region.Capabilities private int m_eventQueueCount = 1; private Queue m_capsEventQueue = new Queue(); private bool m_dumpAssetsToFile; + private bool m_replaceAssets; // These are callbacks which will be setup by the scene so that we can update scene data when we // receive capability calls public NewInventoryItem AddNewInventoryItem = null; + public InventoryAssetCheck CheckInventoryForAsset = null; public ItemUpdatedCallback ItemUpdatedCall = null; public TaskScriptUpdatedCallback TaskScriptUpdatedCall = null; @@ -89,6 +94,8 @@ namespace OpenSim.Region.Capabilities m_httpListenPort = httpPort; m_agentID = agent; m_dumpAssetsToFile = dumpAssetsToFile; + + m_replaceAssets = (GlobalSettings.Instance.ConfigSource.Configs["Startup"].GetBoolean("replace_assets", true)); } /// @@ -374,6 +381,28 @@ namespace OpenSim.Region.Capabilities LLUUID parentFolder = llsdRequest.folder_id; string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000"); + // rex, modified for "replace assets" functionality + if (m_replaceAssets) + { + // Check for asset replace upload + sbyte assType = 0; + sbyte inType = 0; + ParseAssetAndInventoryType(llsdRequest.asset_type, llsdRequest.inventory_type, out assType, out inType); + LLUUID dupID = m_assetCache.ExistsAsset(assType, llsdRequest.name); + if (dupID != LLUUID.Zero) + { + // If duplicate (same name and same assettype) found, use old asset UUID + newAsset = dupID; + // If user already has this asset in inventory, create no item + if (CheckInventoryForAsset != null) + { + if (CheckInventoryForAsset(m_agentID, dupID)) + newInvItem = LLUUID.Zero; + } + } + } + // rexend + AssetUploader uploader = new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type, llsdRequest.asset_type, capsBase + uploaderPath, m_httpListener, m_dumpAssetsToFile); @@ -402,6 +431,57 @@ namespace OpenSim.Region.Capabilities sbyte assType = 0; sbyte inType = 0; + // rex, modified to use extracted method, because needed in multiple places + ParseAssetAndInventoryType(assetType, inventoryType, out assType, out inType); + + AssetBase asset; + asset = new AssetBase(); + asset.FullID = assetID; + asset.Type = assType; + asset.InvType = inType; + asset.Name = assetName; + asset.Data = data; + + // rex, modified for "replace assets" functionality + bool replace = (m_assetCache.ExistsAsset(assetID)); + if (replace) + { + m_assetCache.ReplaceAsset(asset); + } + else + { + m_assetCache.AddAsset(asset); + } + + if (inventoryItem != LLUUID.Zero) + { + InventoryItemBase item = new InventoryItemBase(); + item.avatarID = m_agentID; + item.creatorsID = m_agentID; + item.inventoryID = inventoryItem; + item.assetID = asset.FullID; + item.inventoryDescription = assetDescription; + item.inventoryName = assetName; + item.assetType = assType; + item.invType = inType; + item.parentFolderID = parentFolder; + item.inventoryCurrentPermissions = 2147483647; + item.inventoryNextPermissions = 2147483647; + + if (AddNewInventoryItem != null) + { + AddNewInventoryItem(m_agentID, item); + } + } + // rexend + } + + // rex, new function (extracted method) with added Ogre asset support + private void ParseAssetAndInventoryType(string assetType, string inventoryType, out sbyte assType, out sbyte inType) + { + inType = 0; + assType = 0; + if (inventoryType == "sound") { inType = 1; @@ -413,34 +493,20 @@ namespace OpenSim.Region.Capabilities assType = 20; } - AssetBase asset; - asset = new AssetBase(); - asset.FullID = assetID; - asset.Type = assType; - asset.InvType = inType; - asset.Name = assetName; - asset.Data = data; - m_assetCache.AddAsset(asset); - - InventoryItemBase item = new InventoryItemBase(); - item.avatarID = m_agentID; - item.creatorsID = m_agentID; - item.inventoryID = inventoryItem; - item.assetID = asset.FullID; - item.inventoryDescription = assetDescription; - item.inventoryName = assetName; - item.assetType = assType; - item.invType = inType; - item.parentFolderID = parentFolder; - item.inventoryCurrentPermissions = 2147483647; - item.inventoryNextPermissions = 2147483647; - - if (AddNewInventoryItem != null) + if (assetType == "ogremesh") { - AddNewInventoryItem(m_agentID, item); + inType = 6; + assType = 43; + } + + if (assetType == "ogrepart") + { + inType = 41; + assType = 47; } } + /// /// Called when new asset data for an agent inventory item update has been uploaded. /// diff --git a/OpenSim/Framework/Communications/CommunicationsManager.cs b/OpenSim/Framework/Communications/CommunicationsManager.cs index 0c6d53f4b7..4412726e3f 100644 --- a/OpenSim/Framework/Communications/CommunicationsManager.cs +++ b/OpenSim/Framework/Communications/CommunicationsManager.cs @@ -139,7 +139,7 @@ namespace OpenSim.Framework.Communications string md5PasswdHash = Util.Md5Hash(Util.Md5Hash(password) + ":" + ""); m_userService.AddUserProfile(firstName, lastName, md5PasswdHash, regX, regY); - UserProfileData userProf = UserService.GetUserProfile(firstName, lastName); + UserProfileData userProf = UserService.GetUserProfile(firstName, lastName, ""); if (userProf == null) { return LLUUID.Zero; @@ -205,7 +205,7 @@ namespace OpenSim.Framework.Communications } else { - UserProfileData profileData = m_userService.GetUserProfile(uuid); + UserProfileData profileData = m_userService.GetUserProfile(uuid, ""); if (profileData != null) { LLUUID profileId = profileData.UUID; diff --git a/OpenSim/Framework/Communications/LoginResponse.cs b/OpenSim/Framework/Communications/LoginResponse.cs index 2239a9cc49..71a1299bc5 100644 --- a/OpenSim/Framework/Communications/LoginResponse.cs +++ b/OpenSim/Framework/Communications/LoginResponse.cs @@ -82,6 +82,9 @@ namespace OpenSim.Framework.UserManagement private string firstname; private string lastname; + // REX (client version string) + private string clientVersion = "not set"; + // Global Textures private string sunTexture; private string cloudTexture; @@ -158,6 +161,8 @@ namespace OpenSim.Framework.UserManagement RegionX = (uint) 255232; RegionY = (uint) 254976; + clientVersion = "not set"; //rex + // Classifieds; AddClassifiedCategory((Int32) 1, "Shopping"); AddClassifiedCategory((Int32) 2, "Land Rental"); @@ -348,6 +353,8 @@ namespace OpenSim.Framework.UserManagement responseData["region_x"] = (Int32) RegionX*256; responseData["region_y"] = (Int32) RegionY*256; + responseData["version"] = clientVersion; //rex + //responseData["inventory-lib-root"] = new ArrayList(); // todo if (m_buddyList != null) @@ -450,6 +457,8 @@ namespace OpenSim.Framework.UserManagement map["region_x"] = LLSD.FromInteger(RegionX * 256); map["region_y"] = LLSD.FromInteger(RegionY * 256); + map["version"] = LLSD.FromString(clientVersion); //rex + if (m_buddyList != null) { //map["buddy-list"] = m_buddyList.ToArray(); @@ -606,6 +615,12 @@ namespace OpenSim.Framework.UserManagement set { lastname = value; } } // Lastname + public string ClientVersion + { + get { return clientVersion; } + set { clientVersion = value; } + } //REX ClientVersion + public string AgentAccess { get { return agentAccess; } diff --git a/OpenSim/Framework/Communications/LoginService.cs b/OpenSim/Framework/Communications/LoginService.cs index 9cfac1c285..68b994700e 100644 --- a/OpenSim/Framework/Communications/LoginService.cs +++ b/OpenSim/Framework/Communications/LoginService.cs @@ -44,6 +44,9 @@ namespace OpenSim.Framework.UserManagement protected string m_welcomeMessage = "Welcome to OpenSim"; protected UserManagerBase m_userManager = null; protected Mutex m_loginMutex = new Mutex(false); + protected Boolean m_rexMode; + protected RexLoginHandler m_rexLoginHandler; + /// /// Used during login to send the skeleton of the OpenSim Library to the client. @@ -51,11 +54,15 @@ namespace OpenSim.Framework.UserManagement protected LibraryRootFolder m_libraryRootFolder; public LoginService( - UserManagerBase userManager, LibraryRootFolder libraryRootFolder, string welcomeMess) + UserManagerBase userManager, LibraryRootFolder libraryRootFolder, string welcomeMess, Boolean rexMode) { m_userManager = userManager; m_libraryRootFolder = libraryRootFolder; - + m_rexMode = rexMode; + m_userManager.RexMode = rexMode; + if (m_rexMode) + m_rexLoginHandler = new RexLoginHandler(this, m_userManager); + if (welcomeMess != "") { m_welcomeMessage = welcomeMess; @@ -73,125 +80,138 @@ namespace OpenSim.Framework.UserManagement m_loginMutex.WaitOne(); try { - //CFK: CustomizeResponse contains sufficient strings to alleviate the need for this. - //CKF: MainLog.Instance.Verbose("LOGIN", "Attempting login now..."); - XmlRpcResponse response = new XmlRpcResponse(); - Hashtable requestData = (Hashtable) request.Params[0]; - - bool GoodXML = (requestData.Contains("first") && requestData.Contains("last") && - requestData.Contains("passwd")); - bool GoodLogin = false; - - UserProfileData userProfile; - LoginResponse logResponse = new LoginResponse(); - - if (GoodXML) + if (!m_rexMode) { - string firstname = (string) requestData["first"]; - string lastname = (string) requestData["last"]; - string passwd = (string) requestData["passwd"]; + //CFK: CustomizeResponse contains sufficient strings to alleviate the need for this. + //CKF: MainLog.Instance.Verbose("LOGIN", "Attempting login now..."); + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable requestData = (Hashtable) request.Params[0]; - userProfile = GetTheUser(firstname, lastname); - if (userProfile == null) + bool GoodXML = (requestData.Contains("first") && requestData.Contains("last") && + requestData.Contains("passwd")); + bool GoodLogin = false; + + UserProfileData userProfile; + LoginResponse logResponse = new LoginResponse(); + + if (GoodXML) { - MainLog.Instance.Verbose( - "LOGIN", - "Could not find a profile for " + firstname + " " + lastname); + string firstname = (string) requestData["first"]; + string lastname = (string) requestData["last"]; + string passwd = (string) requestData["passwd"]; + userProfile = GetTheUser(firstname, lastname, ""); + if (userProfile == null) + { + MainLog.Instance.Verbose( + "LOGIN", + "Could not find a profile for " + firstname + " " + lastname); + + return logResponse.CreateLoginFailedResponse(); + } + + GoodLogin = AuthenticateUser(userProfile, passwd); + } + else + { + return logResponse.CreateGridErrorResponse(); + } + + if (!GoodLogin) + { return logResponse.CreateLoginFailedResponse(); } - - GoodLogin = AuthenticateUser(userProfile, passwd); - } - else - { - return logResponse.CreateGridErrorResponse(); - } - - if (!GoodLogin) - { - return logResponse.CreateLoginFailedResponse(); - } - else - { - // If we already have a session... - - if (userProfile.currentAgent != null && userProfile.currentAgent.agentOnline) + else { - userProfile.currentAgent = null; - m_userManager.CommitAgent(ref userProfile); + // If we already have a session... - // Reject the login - return logResponse.CreateAlreadyLoggedInResponse(); - } - // Otherwise... - // Create a new agent session - CreateAgent(userProfile, request); + if (userProfile.currentAgent != null && userProfile.currentAgent.agentOnline) + { + userProfile.currentAgent = null; + m_userManager.CommitAgent(ref userProfile); - try - { - LLUUID agentID = userProfile.UUID; - - // Inventory Library Section - InventoryData inventData = CreateInventoryData(agentID); - ArrayList AgentInventoryArray = inventData.InventoryArray; - - Hashtable InventoryRootHash = new Hashtable(); - InventoryRootHash["folder_id"] = inventData.RootFolderID.ToString(); - ArrayList InventoryRoot = new ArrayList(); - InventoryRoot.Add(InventoryRootHash); - userProfile.rootInventoryFolderID = inventData.RootFolderID; - - // Circuit Code - uint circode = (uint) (Util.RandomClass.Next()); - - logResponse.Lastname = userProfile.surname; - logResponse.Firstname = userProfile.username; - logResponse.AgentID = agentID.ToString(); - logResponse.SessionID = userProfile.currentAgent.sessionID.ToString(); - logResponse.SecureSessionID = userProfile.currentAgent.secureSessionID.ToString(); - logResponse.InventoryRoot = InventoryRoot; - logResponse.InventorySkeleton = AgentInventoryArray; - logResponse.InventoryLibrary = GetInventoryLibrary(); - - Hashtable InventoryLibRootHash = new Hashtable(); - InventoryLibRootHash["folder_id"] = "00000112-000f-0000-0000-000100bba000"; - ArrayList InventoryLibRoot = new ArrayList(); - InventoryLibRoot.Add(InventoryLibRootHash); - logResponse.InventoryLibRoot = InventoryLibRoot; - - logResponse.InventoryLibraryOwner = GetLibraryOwner(); - logResponse.CircuitCode = (Int32) circode; - //logResponse.RegionX = 0; //overwritten - //logResponse.RegionY = 0; //overwritten - logResponse.Home = "!!null temporary value {home}!!"; // Overwritten - //logResponse.LookAt = "\n[r" + TheUser.homeLookAt.X.ToString() + ",r" + TheUser.homeLookAt.Y.ToString() + ",r" + TheUser.homeLookAt.Z.ToString() + "]\n"; - //logResponse.SimAddress = "127.0.0.1"; //overwritten - //logResponse.SimPort = 0; //overwritten - logResponse.Message = GetMessage(); - logResponse.BuddList = ConvertFriendListItem(m_userManager.GetUserFriendList(agentID)); + // Reject the login + return logResponse.CreateAlreadyLoggedInResponse(); + } + // Otherwise... + // Create a new agent session + CreateAgent(userProfile, request); try { - CustomiseResponse(logResponse, userProfile); - } - catch (Exception e) - { - MainLog.Instance.Verbose("LOGIN", e.ToString()); - return logResponse.CreateDeadRegionResponse(); - //return logResponse.ToXmlRpcResponse(); - } - CommitAgent(ref userProfile); - return logResponse.ToXmlRpcResponse(); - } + LLUUID agentID = userProfile.UUID; - catch (Exception E) - { - MainLog.Instance.Verbose("LOGIN", E.ToString()); + // Inventory Library Section + InventoryData inventData = CreateInventoryData(agentID); + ArrayList AgentInventoryArray = inventData.InventoryArray; + + Hashtable InventoryRootHash = new Hashtable(); + InventoryRootHash["folder_id"] = inventData.RootFolderID.ToString(); + ArrayList InventoryRoot = new ArrayList(); + InventoryRoot.Add(InventoryRootHash); + userProfile.rootInventoryFolderID = inventData.RootFolderID; + + // Circuit Code + uint circode = (uint) (Util.RandomClass.Next()); + + //REX: Get client version + if (requestData.ContainsKey("version")) + { + logResponse.ClientVersion = (string)requestData["version"]; + } + + logResponse.Lastname = userProfile.surname; + logResponse.Firstname = userProfile.username; + logResponse.AgentID = agentID.ToString(); + logResponse.SessionID = userProfile.currentAgent.sessionID.ToString(); + logResponse.SecureSessionID = userProfile.currentAgent.secureSessionID.ToString(); + logResponse.InventoryRoot = InventoryRoot; + logResponse.InventorySkeleton = AgentInventoryArray; + logResponse.InventoryLibrary = GetInventoryLibrary(); + + Hashtable InventoryLibRootHash = new Hashtable(); + InventoryLibRootHash["folder_id"] = "00000112-000f-0000-0000-000100bba000"; + ArrayList InventoryLibRoot = new ArrayList(); + InventoryLibRoot.Add(InventoryLibRootHash); + logResponse.InventoryLibRoot = InventoryLibRoot; + + logResponse.InventoryLibraryOwner = GetLibraryOwner(); + logResponse.CircuitCode = (Int32) circode; + //logResponse.RegionX = 0; //overwritten + //logResponse.RegionY = 0; //overwritten + logResponse.Home = "!!null temporary value {home}!!"; // Overwritten + //logResponse.LookAt = "\n[r" + TheUser.homeLookAt.X.ToString() + ",r" + TheUser.homeLookAt.Y.ToString() + ",r" + TheUser.homeLookAt.Z.ToString() + "]\n"; + //logResponse.SimAddress = "127.0.0.1"; //overwritten + //logResponse.SimPort = 0; //overwritten + logResponse.Message = GetMessage(); + logResponse.BuddList = ConvertFriendListItem(m_userManager.GetUserFriendList(agentID)); + + try + { + CustomiseResponse(logResponse, userProfile, null); + } + catch (Exception e) + { + MainLog.Instance.Verbose("LOGIN", e.ToString()); + return logResponse.CreateDeadRegionResponse(); + //return logResponse.ToXmlRpcResponse(); + } + CommitAgent(ref userProfile); + return logResponse.ToXmlRpcResponse(); + } + + catch (Exception E) + { + MainLog.Instance.Verbose("LOGIN", E.ToString()); + } + //} } - //} + return response; + } + else + { + return m_rexLoginHandler.XmlRpcLoginMethod(request); } - return response; } finally { @@ -201,139 +221,232 @@ namespace OpenSim.Framework.UserManagement public LLSD LLSDLoginMethod(LLSD request) { + // Temporary fix m_loginMutex.WaitOne(); try { - bool GoodLogin = false; - - UserProfileData userProfile = null; - LoginResponse logResponse = new LoginResponse(); - - if (request.Type == LLSDType.Map) + if (!m_rexMode) { - LLSDMap map = (LLSDMap)request; + bool GoodLogin = false; + string clientVersion = "not set"; //rex - if (map.ContainsKey("first") && map.ContainsKey("last") && map.ContainsKey("passwd")) + UserProfileData userProfile = null; + LoginResponse logResponse = new LoginResponse(); + + if (request.Type == LLSDType.Map) { - string firstname = map["first"].AsString(); - string lastname = map["last"].AsString(); - string passwd = map["passwd"].AsString(); + LLSDMap map = (LLSDMap)request; - userProfile = GetTheUser(firstname, lastname); - if (userProfile == null) + if (map.ContainsKey("first") && map.ContainsKey("last") && map.ContainsKey("passwd")) { - MainLog.Instance.Verbose( - "LOGIN", - "Could not find a profile for " + firstname + " " + lastname); + string firstname = map["first"].AsString(); + string lastname = map["last"].AsString(); + string passwd = map["passwd"].AsString(); - return logResponse.CreateLoginFailedResponseLLSD(); + //REX: Client version + if (map.ContainsKey("version")) + { + clientVersion = map["version"].AsString(); + } + + userProfile = GetTheUser(firstname, lastname, ""); + if (userProfile == null) + { + MainLog.Instance.Verbose( + "LOGIN", + "Could not find a profile for " + firstname + " " + lastname); + + return logResponse.CreateLoginFailedResponseLLSD(); + } + + GoodLogin = AuthenticateUser(userProfile, passwd); + } + } + + if (!GoodLogin) + { + return logResponse.CreateLoginFailedResponseLLSD(); + } + else + { + // If we already have a session... + if (userProfile.currentAgent != null && userProfile.currentAgent.agentOnline) + { + userProfile.currentAgent = null; + m_userManager.CommitAgent(ref userProfile); + + // Reject the login + return logResponse.CreateAlreadyLoggedInResponseLLSD(); } - GoodLogin = AuthenticateUser(userProfile, passwd); - } - } - - if (!GoodLogin) - { - return logResponse.CreateLoginFailedResponseLLSD(); - } - else - { - // If we already have a session... - if (userProfile.currentAgent != null && userProfile.currentAgent.agentOnline) - { - userProfile.currentAgent = null; - m_userManager.CommitAgent(ref userProfile); - - // Reject the login - return logResponse.CreateAlreadyLoggedInResponseLLSD(); - } - - // Otherwise... - // Create a new agent session - CreateAgent(userProfile, request); - - try - { - LLUUID agentID = userProfile.UUID; - - // Inventory Library Section - InventoryData inventData = CreateInventoryData(agentID); - ArrayList AgentInventoryArray = inventData.InventoryArray; - - Hashtable InventoryRootHash = new Hashtable(); - InventoryRootHash["folder_id"] = inventData.RootFolderID.ToString(); - ArrayList InventoryRoot = new ArrayList(); - InventoryRoot.Add(InventoryRootHash); - userProfile.rootInventoryFolderID = inventData.RootFolderID; - - // Circuit Code - uint circode = (uint)(Util.RandomClass.Next()); - - logResponse.Lastname = userProfile.surname; - logResponse.Firstname = userProfile.username; - logResponse.AgentID = agentID.ToString(); - logResponse.SessionID = userProfile.currentAgent.sessionID.ToString(); - logResponse.SecureSessionID = userProfile.currentAgent.secureSessionID.ToString(); - logResponse.InventoryRoot = InventoryRoot; - logResponse.InventorySkeleton = AgentInventoryArray; - logResponse.InventoryLibrary = GetInventoryLibrary(); - - Hashtable InventoryLibRootHash = new Hashtable(); - InventoryLibRootHash["folder_id"] = "00000112-000f-0000-0000-000100bba000"; - ArrayList InventoryLibRoot = new ArrayList(); - InventoryLibRoot.Add(InventoryLibRootHash); - logResponse.InventoryLibRoot = InventoryLibRoot; - - logResponse.InventoryLibraryOwner = GetLibraryOwner(); - logResponse.CircuitCode = (Int32)circode; - //logResponse.RegionX = 0; //overwritten - //logResponse.RegionY = 0; //overwritten - logResponse.Home = "!!null temporary value {home}!!"; // Overwritten - //logResponse.LookAt = "\n[r" + TheUser.homeLookAt.X.ToString() + ",r" + TheUser.homeLookAt.Y.ToString() + ",r" + TheUser.homeLookAt.Z.ToString() + "]\n"; - //logResponse.SimAddress = "127.0.0.1"; //overwritten - //logResponse.SimPort = 0; //overwritten - logResponse.Message = GetMessage(); - logResponse.BuddList = ConvertFriendListItem(m_userManager.GetUserFriendList(agentID)); + // Otherwise... + // Create a new agent session + CreateAgent(userProfile, request); try { - CustomiseResponse(logResponse, userProfile); + LLUUID agentID = userProfile.UUID; + + // Inventory Library Section + InventoryData inventData = CreateInventoryData(agentID); + ArrayList AgentInventoryArray = inventData.InventoryArray; + + Hashtable InventoryRootHash = new Hashtable(); + InventoryRootHash["folder_id"] = inventData.RootFolderID.ToString(); + ArrayList InventoryRoot = new ArrayList(); + InventoryRoot.Add(InventoryRootHash); + userProfile.rootInventoryFolderID = inventData.RootFolderID; + + // Circuit Code + uint circode = (uint)(Util.RandomClass.Next()); + + // REX: Set client version + logResponse.ClientVersion = clientVersion; + + logResponse.Lastname = userProfile.surname; + logResponse.Firstname = userProfile.username; + logResponse.AgentID = agentID.ToString(); + logResponse.SessionID = userProfile.currentAgent.sessionID.ToString(); + logResponse.SecureSessionID = userProfile.currentAgent.secureSessionID.ToString(); + logResponse.InventoryRoot = InventoryRoot; + logResponse.InventorySkeleton = AgentInventoryArray; + logResponse.InventoryLibrary = GetInventoryLibrary(); + + Hashtable InventoryLibRootHash = new Hashtable(); + InventoryLibRootHash["folder_id"] = "00000112-000f-0000-0000-000100bba000"; + ArrayList InventoryLibRoot = new ArrayList(); + InventoryLibRoot.Add(InventoryLibRootHash); + logResponse.InventoryLibRoot = InventoryLibRoot; + + logResponse.InventoryLibraryOwner = GetLibraryOwner(); + logResponse.CircuitCode = (Int32)circode; + //logResponse.RegionX = 0; //overwritten + //logResponse.RegionY = 0; //overwritten + logResponse.Home = "!!null temporary value {home}!!"; // Overwritten + //logResponse.LookAt = "\n[r" + TheUser.homeLookAt.X.ToString() + ",r" + TheUser.homeLookAt.Y.ToString() + ",r" + TheUser.homeLookAt.Z.ToString() + "]\n"; + //logResponse.SimAddress = "127.0.0.1"; //overwritten + //logResponse.SimPort = 0; //overwritten + logResponse.Message = GetMessage(); + logResponse.BuddList = ConvertFriendListItem(m_userManager.GetUserFriendList(agentID)); + + try + { + CustomiseResponse(logResponse, userProfile, null); + } + catch (Exception ex) + { + MainLog.Instance.Verbose("LOGIN", ex.ToString()); + return logResponse.CreateDeadRegionResponseLLSD(); + } + + CommitAgent(ref userProfile); + + return logResponse.ToLLSDResponse(); } catch (Exception ex) { MainLog.Instance.Verbose("LOGIN", ex.ToString()); - return logResponse.CreateDeadRegionResponseLLSD(); + return logResponse.CreateFailedResponseLLSD(); } - - CommitAgent(ref userProfile); - - return logResponse.ToLLSDResponse(); - } - catch (Exception ex) - { - MainLog.Instance.Verbose("LOGIN", ex.ToString()); - return logResponse.CreateFailedResponseLLSD(); } } - } + else + { + return m_rexLoginHandler.LLSDLoginMethod(request); + } + + } finally { m_loginMutex.ReleaseMutex(); } } + /* + /// + /// Remove agent + /// + /// The XMLRPC request + /// The response to send + public XmlRpcResponse XmlRpcRemoveAgentMethod(XmlRpcRequest request) + { + // Temporary fix + m_loginMutex.WaitOne(); + try + { + MainLog.Instance.Verbose("REMOVE AGENT", "Attempting to remove agent..."); + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable requestData = (Hashtable)request.Params[0]; + + bool parametersValid = (requestData.Contains("agentID")); + + UserProfileData user; + LoginResponse logResponse = new LoginResponse(); + + if (parametersValid) + { + string agentID = (string)requestData["agentID"]; + user = GetTheUser((libsecondlife.LLUUID)agentID); + + if (user == null) + { + MainLog.Instance.Verbose("REMOVE AGENT", "Failed. UserProfile not found."); + return logResponse.CreateAgentRemoveFailedResponse(); + } + + if (user != null) + { + ClearUserAgent(ref user, user.authenticationAddr); + MainLog.Instance.Verbose("REMOVE AGENT", "Success. Agent removed from database. UUID = " + user.UUID); + return logResponse.GenerateAgentRemoveSuccessResponse(); + + } + } + + MainLog.Instance.Verbose("REMOVE AGENT", "Failed. Parameters invalid."); + return logResponse.CreateAgentRemoveFailedResponse(); + + } + finally + { + m_loginMutex.ReleaseMutex(); + } + + return null; + + }//*/ + + public void ClearUserAgent(ref UserProfileData profile, string authAddr) + { + m_userManager.clearUserAgent(profile.UUID, authAddr); + + } + + /// /// Customises the login response and fills in missing values. /// /// The existing response /// The user profile - public virtual void CustomiseResponse(LoginResponse response, UserProfileData theUser) + public virtual void CustomiseResponse(LoginResponse response, UserProfileData theUser, string ASaddress) { } + /// + /// Saves a target agent to the database + /// + /// The users profile + /// Successful? + public void UpdateAgent(UserAgentData agent, string authAddr) + { + // Saves the agent to database + //return true; + m_userManager.UpdateUserAgentData(agent.UUID, agent.agentOnline, agent.currentPos, agent.logoutTime, authAddr); + } + + /// /// Saves a target agent to the database /// @@ -384,9 +497,29 @@ namespace OpenSim.Framework.UserManagement /// /// /// - public virtual UserProfileData GetTheUser(string firstname, string lastname) + public virtual UserProfileData GetTheUser(string firstname, string lastname, string authAddr) { - return m_userManager.GetUserProfile(firstname, lastname); + return m_userManager.GetUserProfile(firstname, lastname, authAddr); + } + + /// + /// Get user according to uid + /// + /// + /// + public virtual UserProfileData GetTheUser(LLUUID userUID) + { + return this.m_userManager.GetUserProfile(userUID, ""); + } + + /// + /// Get user according to account + /// + /// + /// + public virtual UserProfileData GetTheUserByAccount(string account) + { + return this.m_userManager.GetUserProfileByAccount(account); } /// @@ -417,7 +550,7 @@ namespace OpenSim.Framework.UserManagement /// Converts the inventory library skeleton into the form required by the rpc request. /// /// - protected virtual ArrayList GetInventoryLibrary() + protected internal virtual ArrayList GetInventoryLibrary() { Dictionary rootFolders = m_libraryRootFolder.RequestSelfAndDescendentFolders(); @@ -441,7 +574,7 @@ namespace OpenSim.Framework.UserManagement /// /// /// - protected virtual ArrayList GetLibraryOwner() + protected internal virtual ArrayList GetLibraryOwner() { //for now create random inventory library owner Hashtable TempHash = new Hashtable(); @@ -451,7 +584,7 @@ namespace OpenSim.Framework.UserManagement return inventoryLibOwner; } - protected virtual InventoryData CreateInventoryData(LLUUID userID) + protected internal virtual InventoryData CreateInventoryData(LLUUID userID) { AgentInventory userInventory = new AgentInventory(); userInventory.CreateRootFolder(userID, false); diff --git a/OpenSim/Framework/Communications/RexLoginHandler.cs b/OpenSim/Framework/Communications/RexLoginHandler.cs new file mode 100644 index 0000000000..5cbc03379e --- /dev/null +++ b/OpenSim/Framework/Communications/RexLoginHandler.cs @@ -0,0 +1,377 @@ +using System; +using System.Collections; +using System.Threading; +using libsecondlife.StructuredData; +using libsecondlife; +using Nwc.XmlRpc; +using OpenSim.Framework.Console; + + + +namespace OpenSim.Framework.UserManagement +{ + public class RexLoginHandler + { + private LoginService m_ls; + protected UserManagerBase m_userManager = null; + + public RexLoginHandler(LoginService loginservice, UserManagerBase userManager) + { + m_ls = loginservice; + m_userManager = userManager; + } + + public LLSD LLSDLoginMethod(LLSD request) + { + string clientVersion = "not set"; //rex + + LoginResponse logResponse = new LoginResponse(); + + string account = ""; + string sessionhash = ""; + string AuthenticationAddress = ""; + + if (request.Type == LLSDType.Map) + { + LLSDMap map = (LLSDMap)request; + + if (map.ContainsKey("account") && map.ContainsKey("sessionhash") && + map.ContainsKey("AuthenticationAddress")) + { + account = map["account"].AsString(); + sessionhash = map["sessionhash"].AsString(); + AuthenticationAddress = map["AuthenticationAddress"].AsString(); + + if (map.ContainsKey("version")) + { + clientVersion = map["version"].AsString(); + } + } + else { + return logResponse.CreateLoginFailedResponseLLSD(); + } + return (LLSD)CommonLoginProcess(account, sessionhash, AuthenticationAddress, clientVersion, true); + } + return logResponse.CreateLoginFailedResponseLLSD(); + } + + public XmlRpcResponse XmlRpcLoginMethod(XmlRpcRequest request) + { + MainLog.Instance.Verbose("LOGIN", "Attempting login to rexmode sim now..."); + LoginResponse logResponse = new LoginResponse(); + + Hashtable requestData = (Hashtable)request.Params[0]; + + bool GoodXML = (//requestData.Contains("first") && requestData.Contains("last") && + requestData.Contains("account") && requestData.Contains("sessionhash") && + requestData.Contains("AuthenticationAddress")); + + + + + + #region GoodXML // authentication and getting UserProfileData + if (GoodXML) + { + string account = (string)requestData["account"]; + string sessionhash = (string)requestData["sessionhash"]; + string AuthenticationAddress = (string)requestData["AuthenticationAddress"]; + string clientVersion = "not set"; + if (requestData.ContainsKey("version")) + { + clientVersion = (string)requestData["version"]; + } + + return (XmlRpcResponse) CommonLoginProcess(account, sessionhash, AuthenticationAddress, + clientVersion, false); + } + else { + return logResponse.CreateGridErrorResponse(); + } + } + + + private object CommonLoginProcess(string account, string sessionhash, string AuthenticationAddress, + string clientVersion, bool useLLSD) + { + string asAddress; + UserProfileData userProfile; + bool GoodLogin = false; + XmlRpcResponse response = new XmlRpcResponse(); + + LoginResponse logResponse = new LoginResponse(); + + // in rex mode first thing to do is authenticate + GoodLogin = AuthenticateUser(account, ref sessionhash, AuthenticationAddress); + + if (!GoodLogin) + return logResponse.CreateLoginFailedResponse(); + + userProfile = GetTheUser(account, sessionhash, AuthenticationAddress, out asAddress); + + + if (userProfile == null) + { + if (!useLLSD) + return logResponse.CreateLoginFailedResponse(); + else + return logResponse.CreateAlreadyLoggedInResponseLLSD(); + } + + // Set at least here if not filled elsewhere later... + userProfile.authenticationAddr = AuthenticationAddress; + + #endregion + + #region GoodLogin // Agent storing issues + if (!GoodLogin) + { + return logResponse.CreateLoginFailedResponse(); + } + else + { + // If we already have a session... + //if (userProfile.currentAgent != null && userProfile.currentAgent.agentOnline) + //{ + // userProfile.currentAgent = null; + + //m_userManager.CommitAgent(ref userProfile);// not needed + // Reject the login + // return logResponse.CreateAlreadyLoggedInResponse(); + //} + // Otherwise... + // TODO: Actually this is needed at least for now as otherwise crashes to agent being null + //m_ls.CreateAgent(userProfile, request); // not needed + + #endregion + + #region AllTheRest + // All the rest in this method goes like in LoginServices method + + try + { + LLUUID agentID = userProfile.UUID; + + // Inventory Library Section + + OpenSim.Framework.UserManagement.LoginService.InventoryData inventData = m_ls.CreateInventoryData(agentID); + ArrayList AgentInventoryArray = inventData.InventoryArray; + + Hashtable InventoryRootHash = new Hashtable(); + InventoryRootHash["folder_id"] = inventData.RootFolderID.ToString(); + ArrayList InventoryRoot = new ArrayList(); + InventoryRoot.Add(InventoryRootHash); + userProfile.rootInventoryFolderID = inventData.RootFolderID; + + // Circuit Code + uint circode = (uint)(Util.RandomClass.Next()); + + logResponse.Lastname = userProfile.surname; + logResponse.Firstname = userProfile.username; + logResponse.AgentID = agentID.ToString(); + // TODO: Authentication server does not send these, so use random generated defaults! (at least for now) + logResponse.SessionID = userProfile.currentAgent.sessionID.ToString(); + logResponse.SecureSessionID = userProfile.currentAgent.secureSessionID.ToString(); + logResponse.InventoryRoot = InventoryRoot; + logResponse.InventorySkeleton = AgentInventoryArray; + logResponse.InventoryLibrary = m_ls.GetInventoryLibrary(); + logResponse.ClientVersion = clientVersion; + + Hashtable InventoryLibRootHash = new Hashtable(); + InventoryLibRootHash["folder_id"] = "00000112-000f-0000-0000-000100bba000"; + ArrayList InventoryLibRoot = new ArrayList(); + InventoryLibRoot.Add(InventoryLibRootHash); + logResponse.InventoryLibRoot = InventoryLibRoot; + + logResponse.InventoryLibraryOwner = m_ls.GetLibraryOwner(); + logResponse.CircuitCode = (Int32)circode; + //logResponse.RegionX = 0; //overwritten + //logResponse.RegionY = 0; //overwritten + logResponse.Home = "!!null temporary value {home}!!"; // Overwritten + //logResponse.LookAt = "\n[r" + TheUser.homeLookAt.X.ToString() + ",r" + TheUser.homeLookAt.Y.ToString() + ",r" + TheUser.homeLookAt.Z.ToString() + "]\n"; + //logResponse.SimAddress = "127.0.0.1"; //overwritten + //logResponse.SimPort = 0; //overwritten + logResponse.Message = m_ls.GetMessage(); + + try + { + m_ls.CustomiseResponse(logResponse, userProfile, asAddress); + } + catch (Exception e) + { + MainLog.Instance.Verbose("LOGIN", e.ToString()); + if (!useLLSD) + return logResponse.CreateDeadRegionResponse(); + else + return logResponse.CreateDeadRegionResponseLLSD(); + //return logResponse.ToXmlRpcResponse(); + } + //m_ls.CommitAgent(ref userProfile); + if (!useLLSD) + return logResponse.ToXmlRpcResponse(); + else + return logResponse.ToLLSDResponse(); + + } + catch (Exception E) + { + MainLog.Instance.Verbose("LOGIN", E.ToString()); + } + #endregion + } + if (!useLLSD) + return response; + else + return logResponse.CreateFailedResponseLLSD(); + } + + + /// + /// Does authentication to Authentication server + /// + /// + /// + /// new sessionhash ? + public bool AuthenticateUser(string account, ref string loginSessionHash, string authenticationAddr) + { + Hashtable requestParams = new Hashtable(); + requestParams.Add("account", account); + requestParams.Add("sessionhash", loginSessionHash); + XmlRpcResponse res = doRequest("SimAuthenticationAccount", requestParams, authenticationAddr); + + if ((string)((Hashtable)res.Value)["login"] == "success") + { + loginSessionHash = (string)((Hashtable)res.Value)["sessionHash"]; + return true; + } + else + { + return false; + } + } + + public virtual UserProfileData GetTheUser(string account, string sessionhash, string authenticationAddr, + out string asAddress) + { + Hashtable requestParams = new Hashtable(); + requestParams.Add("avatar_account", account); + requestParams.Add("sessionhash", sessionhash); + XmlRpcResponse res = doRequest("get_user_by_account", requestParams, authenticationAddr); + + // should do better check + if ((string)((Hashtable)res.Value)["uuid"] != null) + { + if ((string)((Hashtable)res.Value)["as_address"] != null) + asAddress = (string)((Hashtable)res.Value)["as_address"]; + else + asAddress = ""; + + return HashtableToUserProfileData((Hashtable)res.Value); + } + asAddress = ""; + return null; + } + + + protected XmlRpcResponse doRequest(string method, + Hashtable requestParams, + string authenticationAddr) + { + ArrayList SendParams = new ArrayList(); + SendParams.Add(requestParams); + XmlRpcRequest req = new XmlRpcRequest(method, SendParams); + if (!authenticationAddr.StartsWith("http://")) + authenticationAddr = "http://" + authenticationAddr; + return req.Send(authenticationAddr, 300000); + + } + + static public UserProfileData HashtableToUserProfileData(Hashtable responseData) + { + UserProfileData profile = new UserProfileData(); + // Account information + profile.username = (string)responseData["firstname"]; + profile.surname = (string)responseData["lastname"]; + + profile.UUID = LLUUID.Parse((string)responseData["uuid"]); + // Server Information + profile.userInventoryURI = (string)responseData["server_inventory"]; + profile.userAssetURI = (string)responseData["server_asset"]; + // Profile Information + profile.profileAboutText = (string)responseData["profile_about"]; + profile.profileFirstText = (string)responseData["profile_firstlife_about"]; + profile.profileFirstImage = LLUUID.Parse((string)responseData["profile_firstlife_image"]); + + profile.profileCanDoMask = uint.Parse((string)responseData["profile_can_do"]); + profile.profileWantDoMask = uint.Parse((string)responseData["profile_want_do"]); + + profile.profileImage = LLUUID.Parse((string)responseData["profile_image"]); + + profile.created = int.Parse((string)responseData["profile_created"]); + profile.lastLogin = int.Parse((string)responseData["profile_lastlogin"]); + // Home region information + profile.homeLocation = new LLVector3(float.Parse((string)responseData["home_coordinates_x"]), + float.Parse((string)responseData["home_coordinates_y"]), + float.Parse((string)responseData["home_coordinates_z"])); + + profile.homeRegion = ulong.Parse((string)responseData["home_region"]); + + profile.homeLookAt = new LLVector3(float.Parse((string)responseData["home_look_x"]), + float.Parse((string)responseData["home_look_y"]), + float.Parse((string)responseData["home_look_z"])); + + Hashtable UADtable = (Hashtable)responseData["currentAgent"]; + if (UADtable != null) + { + profile.currentAgent = new UserAgentData(); + HashtableToAgentData(ref UADtable, ref profile.currentAgent); + } + else + { + System.Console.WriteLine("No currentAgent in response!"); + } + + return profile; + } + + static public void HashtableToAgentData(ref Hashtable h, ref UserAgentData uad) + { + + uad.UUID = LLUUID.Parse((string)h["UUID"]); + + uad.agentIP = (string)h["agentIP"]; + + uad.agentPort = uint.Parse((string)h["agentPort"]); + + uad.agentOnline = Boolean.Parse((string)h["agentOnline"]); + + uad.sessionID = LLUUID.Parse((string)h["sessionID"]); + + uad.secureSessionID = LLUUID.Parse((string)h["secureSessionID"]); + + uad.regionID = LLUUID.Parse((string)h["regionID"]); + + uad.loginTime = int.Parse((string)h["loginTime"]); + + uad.logoutTime = int.Parse((string)h["logoutTime"]); + + uad.currentRegion = LLUUID.Parse((string)h["currentRegion"]); + + uad.currentHandle = ulong.Parse((string)h["currentHandle"]); + + try + { + string pos1 = (string)h["currentPos"];//<123,3132,3123> + string pos2 = pos1.Substring(1, pos1.Length - 2); // remove < & > + string[] vals = pos2.Split(','); + uad.currentPos = new LLVector3(float.Parse(vals[0]), float.Parse(vals[1]), float.Parse(vals[2])); + } + catch (Exception) + { + uad.currentPos = new LLVector3(); + } + } + + + } +} diff --git a/OpenSim/Framework/Communications/UserManagerBase.cs b/OpenSim/Framework/Communications/UserManagerBase.cs index bea56ea0e7..f317d05fe4 100644 --- a/OpenSim/Framework/Communications/UserManagerBase.cs +++ b/OpenSim/Framework/Communications/UserManagerBase.cs @@ -44,6 +44,7 @@ namespace OpenSim.Framework.UserManagement { public UserConfig _config; private Dictionary _plugins = new Dictionary(); + public bool RexMode = false; // _config is not initiated in local mode /// /// Adds a new user server plugin - user servers will be requested in the order they were loaded. @@ -88,22 +89,86 @@ namespace OpenSim.Framework.UserManagement /// /// The target UUID /// A user profile. Returns null if no user profile is found. - public UserProfileData GetUserProfile(LLUUID uuid) + public UserProfileData GetUserProfile(LLUUID uuid, string authAddr) + { + if (!RexMode) + { + foreach (KeyValuePair plugin in _plugins) + { + try + { + UserProfileData profile = plugin.Value.GetUserByUUID(uuid); + if (null != profile) + { + profile.currentAgent = getUserAgent(profile.UUID); + return profile; + } + } + catch (Exception e) + { + MainLog.Instance.Verbose("USERSTORAGE", "Unable to find user via " + plugin.Key + "(" + e.ToString() + ")"); + } + } + return null; + } + else + { + try + { + UserProfileData userpd = null; + System.Collections.Hashtable param = new System.Collections.Hashtable(); + param["avatar_uuid"] = uuid.ToString(); + param["AuthenticationAddress"] = authAddr; + System.Collections.Hashtable resp = MakeCommonRequest("get_user_by_uuid", param, authAddr, 3000); + userpd = RexLoginHandler.HashtableToUserProfileData(resp); + return userpd; + } + catch (Exception e) + { + System.Console.WriteLine("Error when trying to fetch profile data by uuid from remote authentication server: " + + e.Message); + } + return null; + } + } + + public System.Collections.Hashtable MakeCommonRequest(string method, System.Collections.Hashtable param, string addr, int timeout)//rex + { + System.Collections.IList parameters = new System.Collections.ArrayList(); + parameters.Add(param); + XmlRpcRequest req = new XmlRpcRequest(method, parameters); + if (!addr.StartsWith("http://")) + addr = "http://" + addr; + XmlRpcResponse resp = req.Send(addr, timeout); + return (System.Collections.Hashtable)resp.Value; + } + + + /// + /// Loads a user profile by name + /// + /// The target name + /// A user profile + public UserProfileData GetUserProfileByAccount(string account) { foreach (KeyValuePair plugin in _plugins) { - UserProfileData profile = plugin.Value.GetUserByUUID(uuid); - - if (null != profile) + try { + UserProfileData profile = plugin.Value.GetUserByAccount(account); profile.currentAgent = getUserAgent(profile.UUID); return profile; } + catch (Exception e) + { + MainLog.Instance.Verbose("USERSTORAGE", "Unable to find user by account via " + plugin.Key + "(" + e.ToString() + ")"); + } } return null; } + public List GenerateAgentPickerRequestResponse(LLUUID queryID, string query) { List pickerlist = new List(); @@ -129,16 +194,51 @@ namespace OpenSim.Framework.UserManagement /// First name /// Last name /// A user profile. Returns null if no profile is found - public UserProfileData GetUserProfile(string fname, string lname) + public UserProfileData GetUserProfile(string fname, string lname, string authAddr) { - foreach (KeyValuePair plugin in _plugins) + if (!RexMode) { - UserProfileData profile = plugin.Value.GetUserByName(fname, lname); - - if (profile != null) + foreach (KeyValuePair plugin in _plugins) { - profile.currentAgent = getUserAgent(profile.UUID); - return profile; + try + { + UserProfileData profile = plugin.Value.GetUserByName(fname, lname); + + if (profile != null) + { + profile.currentAgent = getUserAgent(profile.UUID); + return profile; + } + } + catch (Exception e) + { + MainLog.Instance.Verbose("USERSTORAGE", "Unable to find user via " + plugin.Key + "(" + e.ToString() + ")"); + } + } + } + else + { + try + { + UserProfileData userpd = null; + System.Collections.Hashtable param = new System.Collections.Hashtable(); + param["avatar_name"] = fname + " "+lname; + param["AuthenticationAddress"] = authAddr; + System.Collections.Hashtable resp = MakeCommonRequest("get_user_by_name", param, authAddr, 3000); + if (resp.Contains("error_type")) + { + return null; + } + else + { + userpd = RexLoginHandler.HashtableToUserProfileData(resp); + return userpd; + } + } + catch (Exception e) + { + System.Console.WriteLine("Error when trying to fetch profile data by firstname, lastname from remote authentication server: " + + e.Message); } } @@ -295,12 +395,36 @@ namespace OpenSim.Framework.UserManagement } // TODO: document - public void clearUserAgent(LLUUID agentID) + public void clearUserAgent(LLUUID agentID, string authAddr) { - UserProfileData profile = GetUserProfile(agentID); - profile.currentAgent = null; - - setUserProfile(profile); + UserProfileData profile = GetUserProfile(agentID, authAddr); + if (profile != null) + { + profile.currentAgent = null; + if (!RexMode) + { + setUserProfile(profile); + } + else + { + try + { + System.Collections.Hashtable param = new System.Collections.Hashtable(); + param["agentID"] = profile.UUID.ToString(); + System.Collections.Hashtable resp = MakeCommonRequest("remove_user_agent", param, authAddr, 3000); + } + catch (Exception e) + { + System.Console.WriteLine("Error when trying to fetch agent data by uuid from remote authentication server: " + + e.Message); + } + } + + } + else + { + MainLog.Instance.Verbose("USERSTORAGE", "Unable to clear user agent with agentID : " + agentID); + } } /// @@ -461,6 +585,7 @@ namespace OpenSim.Framework.UserManagement user.homeRegionX = regX; user.homeRegionY = regY; + foreach (KeyValuePair plugin in _plugins) { try @@ -480,5 +605,97 @@ namespace OpenSim.Framework.UserManagement public abstract UserProfileData SetupMasterUser(string firstName, string lastName); public abstract UserProfileData SetupMasterUser(string firstName, string lastName, string password); public abstract UserProfileData SetupMasterUser(LLUUID uuid); + + + public bool AuthenticateUser(LLUUID agentId, string sessionhash, out String avatarstorage) + { + avatarstorage = ""; + return true; + } + + /// + /// Loads a user profile by name + /// + /// The target name + /// A user profile + public UserProfileData GetUserProfile(string name, string authAddr) + { + foreach (KeyValuePair plugin in _plugins) + { + try + { + UserProfileData profile = plugin.Value.GetUserByName(name, authAddr); + profile.currentAgent = getUserAgent(profile.UUID); + return profile; + } + catch (Exception e) + { + MainLog.Instance.Verbose("USERSTORAGE", "Unable to find user via " + plugin.Key + "(" + e.ToString() + ")"); + } + } + + return null; + } + + public void UpdateUserAgentData(LLUUID agentId, bool agentOnline, LLVector3 currentPos, int logoutTime, string authAddr) + { + // Saves the agent to database + //return true; + if (!RexMode) + { + foreach (KeyValuePair plugin in _plugins) + { + try + { + UserAgentData agent = plugin.Value.GetAgentByUUID(agentId); + if (agent != null) + { + agent.agentOnline = agentOnline; + agent.logoutTime = logoutTime; + agent.currentPos = currentPos; + agent.currentPos = new LLVector3( + Convert.ToSingle(currentPos.X), + Convert.ToSingle(currentPos.Y), + Convert.ToSingle(currentPos.Z)); + plugin.Value.AddNewUserAgent(agent); + MainLog.Instance.Verbose("USERSTORAGE", "Agent updated UUID = " + agent.UUID.ToString()); + } + else + { + MainLog.Instance.Verbose("USERSTORAGE", "Agent update, agent not found with UUID = " + agentId); + } + + } + catch (Exception e) + { + MainLog.Instance.Verbose("USERSTORAGE", "Unable to add or update agent via " + plugin.Key + "(" + e.ToString() + ")"); + } + } + } + else + { + + try + { + System.Collections.Hashtable param = new System.Collections.Hashtable(); + param["agentID"] = agentId.ToString(); + param["agentOnline"] = agentOnline.ToString(); + param["logoutTime"] = logoutTime.ToString(); + param["agent_currentPosX"] = Convert.ToSingle(currentPos.X).ToString(); + param["agent_currentPosY"] = Convert.ToSingle(currentPos.Y).ToString(); + param["agent_currentPosZ"] = Convert.ToSingle(currentPos.Z).ToString(); + param["AuthenticationAddress"] = authAddr; + System.Collections.Hashtable resp = MakeCommonRequest("update_user_agent", param, authAddr, 3000); + } + catch (Exception e) + { + System.Console.WriteLine("Error when trying to update user agent data to remote authentication server: " + + e.Message); + } + + } + + } + } } diff --git a/OpenSim/Framework/Data.DB4o/DB4oUserData.cs b/OpenSim/Framework/Data.DB4o/DB4oUserData.cs index c6ac5265a1..b99c09b422 100644 --- a/OpenSim/Framework/Data.DB4o/DB4oUserData.cs +++ b/OpenSim/Framework/Data.DB4o/DB4oUserData.cs @@ -62,6 +62,18 @@ namespace OpenSim.Framework.Data.DB4o return null; } + /// + /// Loads a specified user profile from a account + /// + /// The users account + /// A user profile + public UserProfileData GetUserByAccount(string account) + { + if (manager.userProfiles.ContainsKey(account)) + return manager.userProfiles[account]; + return null; + } + /// /// Returns a user by searching for its name /// diff --git a/OpenSim/Framework/Data.MSSQL/MSSQLAssetData.cs b/OpenSim/Framework/Data.MSSQL/MSSQLAssetData.cs index 08fbef07dd..98996ded85 100644 --- a/OpenSim/Framework/Data.MSSQL/MSSQLAssetData.cs +++ b/OpenSim/Framework/Data.MSSQL/MSSQLAssetData.cs @@ -92,9 +92,9 @@ namespace OpenSim.Framework.Data.MSSQL SqlCommand cmd = new SqlCommand( - "INSERT INTO assets ([id], [name], [description], [assetType], [invType], [local], [temporary], [data])" + + "INSERT INTO assets ([id], [name], [mediaUrl], [description], [assetType], [invType], [local], [temporary], [data])" + " VALUES " + - "(@id, @name, @description, @assetType, @invType, @local, @temporary, @data)", + "(@id, @name, @mediaUrl, @description, @assetType, @invType, @local, @temporary, @data)", database.getConnection()); using (cmd) @@ -103,6 +103,7 @@ namespace OpenSim.Framework.Data.MSSQL //p.Value = asset.FullID.ToString(); cmd.Parameters.AddWithValue("id", asset.FullID.ToString()); cmd.Parameters.AddWithValue("name", asset.Name); + cmd.Parameters.AddWithValue("mediaUrl", asset.MediaURL); cmd.Parameters.AddWithValue("description", asset.Description); SqlParameter e = cmd.Parameters.Add("assetType", SqlDbType.TinyInt); e.Value = asset.Type; @@ -132,6 +133,7 @@ namespace OpenSim.Framework.Data.MSSQL { SqlCommand command = new SqlCommand("UPDATE assets set id = @id, " + "name = @name, " + + "mediaUrl = @mediaUrl, "+ "description = @description," + "assetType = @assetType," + "invType = @invType," + @@ -141,13 +143,14 @@ namespace OpenSim.Framework.Data.MSSQL "id = @keyId;", database.getConnection()); SqlParameter param1 = new SqlParameter("@id", asset.FullID.ToString()); SqlParameter param2 = new SqlParameter("@name", asset.Name); - SqlParameter param3 = new SqlParameter("@description", asset.Description); - SqlParameter param4 = new SqlParameter("@assetType", asset.Type); - SqlParameter param5 = new SqlParameter("@invType", asset.InvType); - SqlParameter param6 = new SqlParameter("@local", asset.Local); - SqlParameter param7 = new SqlParameter("@temporary", asset.Temporary); - SqlParameter param8 = new SqlParameter("@data", asset.Data); - SqlParameter param9 = new SqlParameter("@keyId", asset.FullID.ToString()); + SqlParameter param3 = new SqlParameter("@mediaUrl", asset.MediaURL); + SqlParameter param4 = new SqlParameter("@description", asset.Description); + SqlParameter param5 = new SqlParameter("@assetType", Convert.ToBoolean(asset.Type)); + SqlParameter param6 = new SqlParameter("@invType", Convert.ToBoolean(asset.InvType)); + SqlParameter param7 = new SqlParameter("@local", asset.Local); + SqlParameter param8 = new SqlParameter("@temporary", asset.Temporary); + SqlParameter param9 = new SqlParameter("@data", asset.Data); + SqlParameter param10 = new SqlParameter("@keyId", asset.FullID.ToString()); command.Parameters.Add(param1); command.Parameters.Add(param2); command.Parameters.Add(param3); @@ -157,6 +160,7 @@ namespace OpenSim.Framework.Data.MSSQL command.Parameters.Add(param7); command.Parameters.Add(param8); command.Parameters.Add(param9); + command.Parameters.Add(param10); try { @@ -177,6 +181,14 @@ namespace OpenSim.Framework.Data.MSSQL return false; } + // rex, new function, fixme not implemented + public List GetAssetList(int vAssetType) + { + List retvals = new List(); + return retvals; + } + + /// /// All writes are immediately commited to the database, so this is a no-op /// @@ -184,6 +196,14 @@ namespace OpenSim.Framework.Data.MSSQL { } + // rex new function for "replace assets" functionality + // TODO: actual implementation by someone, should return LLUUID of an asset + // with matching type & name, or zero if not in DB + public LLUUID ExistsAsset(sbyte type, string name) + { + return LLUUID.Zero; + } + #endregion #region IPlugin Members diff --git a/OpenSim/Framework/Data.MSSQL/MSSQLManager.cs b/OpenSim/Framework/Data.MSSQL/MSSQLManager.cs index bf57492ce4..348018b976 100644 --- a/OpenSim/Framework/Data.MSSQL/MSSQLManager.cs +++ b/OpenSim/Framework/Data.MSSQL/MSSQLManager.cs @@ -69,7 +69,8 @@ namespace OpenSim.Framework.Data.MSSQL ";Persist Security Info=" + persistSecurityInfo + ";User ID=" + userId + ";Password=" + password + ";"; dbcon = new SqlConnection(connectionString); - TestTables(dbcon); + TestTables(dbcon); + //System.Threading.Thread.Sleep(3000); dbcon.Open(); } catch (Exception e) @@ -105,8 +106,9 @@ namespace OpenSim.Framework.Data.MSSQL } catch (Exception) { + conn.Close(); conn.Open(); - cmd = Query("alter table users add column [webLoginKey] varchar(36) default NULL", new Dictionary()); + cmd = Query("alter table users add [webLoginKey] varchar(36) default NULL", new Dictionary()); cmd.ExecuteNonQuery(); cmd.Dispose(); conn.Close(); @@ -452,6 +454,7 @@ namespace OpenSim.Framework.Data.MSSQL asset = new AssetBase(); asset.Data = (byte[]) reader["data"]; asset.Description = (string) reader["description"]; + asset.MediaURL = (string)reader["mediaUrl"]; asset.FullID = new LLUUID((string) reader["id"]); asset.InvType = Convert.ToSByte(reader["invType"]); asset.Local = Convert.ToBoolean(reader["local"]); // ((sbyte)reader["local"]) != 0 ? true : false; diff --git a/OpenSim/Framework/Data.MSSQL/MSSQLUserData.cs b/OpenSim/Framework/Data.MSSQL/MSSQLUserData.cs index db3c1d624d..426cc30cc8 100644 --- a/OpenSim/Framework/Data.MSSQL/MSSQLUserData.cs +++ b/OpenSim/Framework/Data.MSSQL/MSSQLUserData.cs @@ -243,6 +243,48 @@ namespace OpenSim.Framework.Data.MSSQL } } + /// + /// Searches the database for a specified user profile by account + /// + /// The account + /// The users profile + public UserProfileData GetUserByAccount(string account) + { + try + { + lock (database) + { + Dictionary param = new Dictionary(); + param["account"] = account; + + IDbCommand result = database.Query("SELECT * FROM users WHERE account = @account", param); + IDataReader reader = result.ExecuteReader(); + + UserProfileData row = database.readUserRow(reader); + + reader.Close(); + result.Dispose(); + + if (row != null) + { + UserAgentData agentData = GetAgentByUUID(row.UUID); + if (agentData != null) + { + row.currentAgent = agentData; + } + } + + return row; + } + } + catch (Exception e) + { + database.Reconnect(); + MainLog.Instance.Error(e.ToString()); + return null; + } + } + /// /// Returns a user session searching by name /// diff --git a/OpenSim/Framework/Data.MSSQL/Resources/CreateAssetsTable.sql b/OpenSim/Framework/Data.MSSQL/Resources/CreateAssetsTable.sql index c7cb21adf5..83629c4439 100644 --- a/OpenSim/Framework/Data.MSSQL/Resources/CreateAssetsTable.sql +++ b/OpenSim/Framework/Data.MSSQL/Resources/CreateAssetsTable.sql @@ -5,6 +5,7 @@ CREATE TABLE [assets] ( [id] [varchar](36) NOT NULL, [name] [varchar](64) NOT NULL, [description] [varchar](64) NOT NULL, + [mediaURL] [varchar](255) NOT NULL, [assetType] [tinyint] NOT NULL, [invType] [tinyint] NOT NULL, [local] [tinyint] NOT NULL, diff --git a/OpenSim/Framework/Data.MySQL/MySQLAssetData.cs b/OpenSim/Framework/Data.MySQL/MySQLAssetData.cs index b20c54e557..27e895efce 100644 --- a/OpenSim/Framework/Data.MySQL/MySQLAssetData.cs +++ b/OpenSim/Framework/Data.MySQL/MySQLAssetData.cs @@ -138,6 +138,13 @@ namespace OpenSim.Framework.Data.MySQL throw new Exception("The method or operation is not implemented."); } + // rex, new function, fixme not implemented + public List GetAssetList(int vAssetType) + { + List retvals = new List(); + return retvals; + } + /// /// All writes are immediately commited to the database, so this is a no-op /// @@ -145,6 +152,14 @@ namespace OpenSim.Framework.Data.MySQL { } + // rex new function for "replace assets" functionality + // TODO: actual implementation by someone, should return LLUUID of an asset + // with matching type & name, or zero if not in DB + public LLUUID ExistsAsset(sbyte type, string name) + { + return LLUUID.Zero; + } + #endregion #region IPlugin Members diff --git a/OpenSim/Framework/Data.MySQL/MySQLManager.cs b/OpenSim/Framework/Data.MySQL/MySQLManager.cs index 223d902a1d..92aba9ee75 100644 --- a/OpenSim/Framework/Data.MySQL/MySQLManager.cs +++ b/OpenSim/Framework/Data.MySQL/MySQLManager.cs @@ -295,7 +295,8 @@ namespace OpenSim.Framework.Data.MySQL retval.regionDataURI = (string) reader["regionDataURI"]; retval.regionOnline = false; // Needs to be pinged before this can be set. retval.serverIP = (string) reader["serverIP"]; - retval.serverPort = (uint) reader["serverPort"]; + retval.serverPort = uint.Parse(reader["serverPort"].ToString()); + //retval.serverPort = (uint) reader["serverPort"]; // this caused exceptions retval.serverURI = (string) reader["serverURI"]; retval.httpPort = Convert.ToUInt32(reader["serverHttpPort"].ToString()); retval.remotingPort = Convert.ToUInt32(reader["serverRemotingPort"].ToString()); diff --git a/OpenSim/Framework/Data.MySQL/MySQLUserData.cs b/OpenSim/Framework/Data.MySQL/MySQLUserData.cs index e53ab189bd..533c35a010 100644 --- a/OpenSim/Framework/Data.MySQL/MySQLUserData.cs +++ b/OpenSim/Framework/Data.MySQL/MySQLUserData.cs @@ -446,6 +446,39 @@ namespace OpenSim.Framework.Data.MySQL } } + /// + /// Searches the database for a specified user profile by account + /// + /// The account + /// The users profile + public UserProfileData GetUserByAccount(string account) + { + try + { + lock (database) + { + Dictionary param = new Dictionary(); + param["?account"] = account; + + IDbCommand result = database.Query("SELECT * FROM users WHERE account = ?account", param); + IDataReader reader = result.ExecuteReader(); + + UserProfileData row = database.readUserRow(reader); + + reader.Close(); + result.Dispose(); + + return row; + } + } + catch (Exception e) + { + database.Reconnect(); + MainLog.Instance.Error(e.ToString()); + return null; + } + } + /// /// Returns a user session searching by name /// diff --git a/OpenSim/Framework/Data.SQLite/SQLiteAssetData.cs b/OpenSim/Framework/Data.SQLite/SQLiteAssetData.cs index 462c4336f9..a97b4f048e 100644 --- a/OpenSim/Framework/Data.SQLite/SQLiteAssetData.cs +++ b/OpenSim/Framework/Data.SQLite/SQLiteAssetData.cs @@ -31,6 +31,7 @@ using System.Reflection; using libsecondlife; using Mono.Data.SqliteClient; using OpenSim.Framework.Console; +using System.Collections.Generic; // rex added namespace OpenSim.Framework.Data.SQLite { @@ -117,6 +118,24 @@ namespace OpenSim.Framework.Data.SQLite } } + // rex new function for "replace assets" functionality + public LLUUID ExistsAsset(sbyte type, string name) + { + LLUUID retVal = LLUUID.Zero; + + lock (ds) + { + string selectExp = "Type = '" + type.ToString() + "' AND Name = '" + name + "'"; + DataRow[] match = ds.Tables["assets"].Select(selectExp); + if (match.Length > 0) + { + retVal = new LLUUID((String)match[0]["UUID"]); + } + } + + return retVal; + } + private void LogAssetLoad(AssetBase asset) { string temporary = asset.Temporary ? "Temporary" : "Stored"; @@ -134,6 +153,32 @@ namespace OpenSim.Framework.Data.SQLite return (row != null); } + // rex, new function + public List GetAssetList(int vAssetType) + { + List retvals = new List(); + lock (ds) + { + string selectExp = "InvType = '" + vAssetType.ToString() + "'"; + DataRow[] allAssets = ds.Tables["assets"].Select(selectExp); + foreach (DataRow row in allAssets) + { + // Do not use buildAsset(row) because we don't want to return the asset.data - Tuco + AssetBase asset = new AssetBase(); + asset.FullID = new LLUUID((String)row["UUID"]); + asset.Name = (String)row["Name"]; + asset.Description = (String)row["Description"]; + asset.Type = Convert.ToSByte(row["Type"]); + asset.InvType = Convert.ToSByte(row["InvType"]); + asset.Local = Convert.ToBoolean(row["Local"]); + asset.Temporary = Convert.ToBoolean(row["Temporary"]); + retvals.Add(asset); + } + } + return retvals; + } + + public void DeleteAsset(LLUUID uuid) { lock (ds) @@ -171,6 +216,7 @@ namespace OpenSim.Framework.Data.SQLite createCol(assets, "UUID", typeof (String)); createCol(assets, "Name", typeof (String)); createCol(assets, "Description", typeof (String)); + createCol(assets, "MediaURL", typeof(String));//rex mediaurl createCol(assets, "Type", typeof (Int32)); createCol(assets, "InvType", typeof (Int32)); createCol(assets, "Local", typeof (Boolean)); @@ -199,6 +245,14 @@ namespace OpenSim.Framework.Data.SQLite asset.FullID = new LLUUID((String) row["UUID"]); asset.Name = (String) row["Name"]; asset.Description = (String) row["Description"]; + try + { + asset.MediaURL = (String) row["MediaURL"];//rex mediaurl + } + catch (Exception) + { + asset.MediaURL = ""; // fixme, the row returns null which can't be cast to string, happens with old dbs right now. - Tuco + } asset.Type = Convert.ToSByte(row["Type"]); asset.InvType = Convert.ToSByte(row["InvType"]); asset.Local = Convert.ToBoolean(row["Local"]); @@ -220,6 +274,15 @@ namespace OpenSim.Framework.Data.SQLite { row["Description"] = " "; } + + if (asset.MediaURL != null) //rex mediaurl + { + row["MediaURL"] = asset.MediaURL; + } + else + { + row["MediaURL"] = " "; + } row["Type"] = asset.Type; row["InvType"] = asset.InvType; row["Local"] = asset.Local; diff --git a/OpenSim/Framework/Data.SQLite/SQLiteUserData.cs b/OpenSim/Framework/Data.SQLite/SQLiteUserData.cs index cbbb3491a7..b384272813 100644 --- a/OpenSim/Framework/Data.SQLite/SQLiteUserData.cs +++ b/OpenSim/Framework/Data.SQLite/SQLiteUserData.cs @@ -114,6 +114,33 @@ namespace OpenSim.Framework.Data.SQLite } } + /// + /// Loads a specified user profile from a account + /// + /// The users account + /// A user profile + public UserProfileData GetUserByAccount(string account) + { + lock (ds) + { + DataRow row = ds.Tables["users"].Rows.Find(account); + if (row != null) + { + UserProfileData user = buildUserProfile(row); + row = ds.Tables["useragents"].Rows.Find(user.UUID); + if (row != null) + { + user.currentAgent = buildUserAgent(row); + } + return user; + } + else + { + return null; + } + } + } + // see IUserData public UserProfileData GetUserByName(string fname, string lname) { diff --git a/OpenSim/Framework/IAssetProvider.cs b/OpenSim/Framework/IAssetProvider.cs index ad1cf6654c..7758641d58 100644 --- a/OpenSim/Framework/IAssetProvider.cs +++ b/OpenSim/Framework/IAssetProvider.cs @@ -27,6 +27,7 @@ */ using libsecondlife; +using System.Collections.Generic; // rex added namespace OpenSim.Framework { @@ -37,5 +38,7 @@ namespace OpenSim.Framework void UpdateAsset(AssetBase asset); bool ExistsAsset(LLUUID uuid); void CommitAssets(); // force a sync to the database + LLUUID ExistsAsset(sbyte type, string name); // rex new function for "replace asset" functionality + List GetAssetList(int vAssetType); // rex, added } } \ No newline at end of file diff --git a/OpenSim/Framework/IAssetServer.cs b/OpenSim/Framework/IAssetServer.cs index df36623785..0fd4e482dd 100644 --- a/OpenSim/Framework/IAssetServer.cs +++ b/OpenSim/Framework/IAssetServer.cs @@ -41,6 +41,10 @@ namespace OpenSim.Framework void UpdateAsset(AssetBase asset); void StoreAndCommitAsset(AssetBase asset); void Close(); + LLUUID ExistsAsset(sbyte type, string name); // rex new function for "replace asset" functionality + bool ExistsAsset(LLUUID assetID); // rex added + List GetAssetList(int vAssetType); // rex added + AssetBase FetchAsset(LLUUID assetID); // rex added } // could change to delegate? diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs index 039526ba9e..407a2bf1d7 100644 --- a/OpenSim/Framework/IClientAPI.cs +++ b/OpenSim/Framework/IClientAPI.cs @@ -379,6 +379,9 @@ namespace OpenSim.Framework public delegate void MoveInventoryItem( IClientAPI remoteClient, LLUUID folderID, LLUUID itemID, int length, string newName); + public delegate void RemoveInventoryItem( + IClientAPI remoteClient, LLUUID itemID); // rex + public delegate void RezScript(IClientAPI remoteClient, LLUUID itemID, uint localID); public delegate void UpdateTaskInventory(IClientAPI remoteClient, LLUUID itemID, LLUUID folderID, uint localID); @@ -398,10 +401,24 @@ namespace OpenSim.Framework public delegate void FriendActionDelegate(IClientAPI remoteClient,LLUUID agentID,LLUUID transactionID,List callingCardFolders); public delegate void FriendshipTermination(IClientAPI remoteClient,LLUUID agentID, LLUUID ExID); - - - + public delegate void ReceiveRexClientScriptCmd(IClientAPI remoteClient,LLUUID agentID,List vParams); // rex + + //Attachments + public delegate void RezSingleAttachmentFromInv(IClientAPI remoteClient, LLUUID itemID, LLUUID ownerID, + uint itemFlags, byte attachPoint); + public delegate void ObjectAttach(IClientAPI remoteClient, uint localID, LLQuaternion rotation, byte attachPoint); + public delegate void ObjectDetach(IClientAPI remoteClient, uint localID); + + + // REX + public delegate void UpdateAssetMediaURL(IClientAPI remoteClient, LLUUID itemID, string mediaUrl); + + // REX + public delegate void ObjectClickAction(IClientAPI remoteClient, uint objectLocalId, byte clickAction); + + public delegate void TriggerSound(IClientAPI remoteClient, LLUUID soundID, LLUUID ownerID, LLUUID objectID, LLUUID parentID, ulong handle, LLVector3 position, float gain); + public delegate void ObjectPermissions( IClientAPI remoteClinet, LLUUID AgentID, LLUUID SessionID, @@ -468,7 +485,7 @@ namespace OpenSim.Framework event CreateNewInventoryItem OnCreateNewInventoryItem; event CreateInventoryFolder OnCreateNewInventoryFolder; event UpdateInventoryFolder OnUpdateInventoryFolder; - event MoveInventoryFolder OnMoveInventoryFolder; + event MoveInventoryFolder OnMoveInventoryFolder; event FetchInventoryDescendents OnFetchInventoryDescendents; event PurgeInventoryDescendents OnPurgeInventoryDescendents; event FetchInventory OnFetchInventory; @@ -476,6 +493,7 @@ namespace OpenSim.Framework event UpdateInventoryItem OnUpdateInventoryItem; event CopyInventoryItem OnCopyInventoryItem; event MoveInventoryItem OnMoveInventoryItem; + event RemoveInventoryItem OnRemoveInventoryItem; // rex event UDPAssetUploadRequest OnAssetUploadRequest; event XferReceive OnXferReceive; event RequestXfer OnRequestXfer; @@ -484,6 +502,10 @@ namespace OpenSim.Framework event UpdateTaskInventory OnUpdateTaskInventory; event RemoveTaskInventory OnRemoveTaskItem; + event RezSingleAttachmentFromInv OnRezSingleAttachmentFromInv; + event ObjectAttach OnObjectAttach; + event ObjectDetach OnObjectDetach; + event UUIDNameRequest OnNameFromUUIDRequest; event ParcelAccessListRequest OnParcelAccessListRequest; @@ -502,7 +524,11 @@ namespace OpenSim.Framework event FriendActionDelegate OnDenyFriendRequest; event FriendshipTermination OnTerminateFriendship; - + event ReceiveRexClientScriptCmd OnReceiveRexClientScriptCmd; // rex + event ObjectClickAction OnObjectClickAction; // rex + event UpdateAssetMediaURL OnUpdateAssetMediaURL; // rex + event TriggerSound OnTriggerSound; + LLVector3 StartPos { get; set; } LLUUID AgentId { get; } @@ -527,6 +553,8 @@ namespace OpenSim.Framework void OutPacket(Packet newPack, ThrottleOutPacketType packType); void SendWearables(AvatarWearable[] wearables, int serial); void SendAppearance(LLUUID agentID, byte[] visualParams, byte[] textureEntry); + void SendRexAppearance(LLUUID agentID, string avatarAddress); // rex + void SendRexScriptCommand(string vUnit,string vCommand, string vCmdParams); // rex void SendStartPingCheck(byte seq); void SendKillObject(ulong regionHandle, uint localID); void SendAnimations(LLUUID[] animID, int[] seqs, LLUUID sourceAgentId); @@ -539,6 +567,9 @@ namespace OpenSim.Framework void SendLayerData(float[] map); void SendLayerData(int px, int py, float[] map); + + void SendMediaURL(LLUUID assetId, string mediaURL); //rex + void MoveAgentIntoRegion(RegionInfo regInfo, LLVector3 pos, LLVector3 look); void InformClientOfNeighbour(ulong neighbourHandle, IPEndPoint neighbourExternalEndPoint); AgentCircuitData RequestClientInfo(); @@ -596,12 +627,14 @@ namespace OpenSim.Framework void SendPreLoadSound(LLUUID objectID, LLUUID ownerID, LLUUID soundID); void SendPlayAttachedSound(LLUUID soundID, LLUUID objectID, LLUUID ownerID, float gain, byte flags); + void SendTriggeredSound(LLUUID soundID, LLUUID ownerID, LLUUID objectID, LLUUID parentID, ulong handle, LLVector3 position, float gain); void SendNameReply(LLUUID profileId, string firstname, string lastname); void SendAlertMessage(string message); void SendAgentAlertMessage(string message, bool modal); void SendLoadURL(string objectname, LLUUID objectID, LLUUID ownerID, bool groupOwned, string message, string url); + void SendDialog(string objectname, LLUUID objectID, LLUUID ownerID, string msg, LLUUID textureID, int ch, string[] buttonlabels); bool AddMoney(int debit); void SendSunPos(LLVector3 sunPos, LLVector3 sunVel); @@ -610,6 +643,8 @@ namespace OpenSim.Framework void SendAvatarProperties(LLUUID avatarID, string aboutText, string bornOn, string charterMember, string flAbout, uint flags, LLUUID flImageID, LLUUID imageID, string profileURL, LLUUID partnerID); + void SendScriptTeleportRequest(string objectName, string simName, LLVector3 simPosition, LLVector3 lookAt); + void SetDebug(int newDebug); void InPacket(Packet NewPack); void Close(bool ShutdownCircuit); @@ -623,4 +658,4 @@ namespace OpenSim.Framework void SendLogoutPacket(); } -} \ No newline at end of file +} diff --git a/OpenSim/Framework/IScene.cs b/OpenSim/Framework/IScene.cs index 96cb21eb55..ac2b592deb 100644 --- a/OpenSim/Framework/IScene.cs +++ b/OpenSim/Framework/IScene.cs @@ -47,6 +47,7 @@ namespace OpenSim.Framework void AddNewClient(IClientAPI client, bool child); void RemoveClient(LLUUID agentID); + void RemoveClient(LLUUID agentID, uint circuitCode); void CloseAllAgents(uint circuitcode); void Restart(int seconds); @@ -60,5 +61,7 @@ namespace OpenSim.Framework RegionStatus Region_Status { get; set; } ClientManager ClientManager { get; } + + bool RexMode { get; set; }//rex } } \ No newline at end of file diff --git a/OpenSim/Framework/IUserData.cs b/OpenSim/Framework/IUserData.cs index eba2329dbb..96fc0112db 100644 --- a/OpenSim/Framework/IUserData.cs +++ b/OpenSim/Framework/IUserData.cs @@ -42,6 +42,13 @@ namespace OpenSim.Framework /// The user data profile. Returns null if no user is found UserProfileData GetUserByUUID(LLUUID user); + /// + /// Returns a user profile from a database via their account + /// + /// The account + /// The user data profile + UserProfileData GetUserByAccount(string account); + /// /// Returns a users profile by searching their username parts /// diff --git a/OpenSim/Framework/IUserService.cs b/OpenSim/Framework/IUserService.cs index 2b59c25ba2..5c3f0cf3db 100644 --- a/OpenSim/Framework/IUserService.cs +++ b/OpenSim/Framework/IUserService.cs @@ -32,16 +32,23 @@ namespace OpenSim.Framework { public interface IUserService { - UserProfileData GetUserProfile(string firstName, string lastName); + UserProfileData GetUserProfile(string firstName, string lastName, string authAddr); + UserProfileData GetUserProfile(string firstName, string authAddr); // must differentiate this from GetUserProfile call //UserProfileData GetUserProfile(string name); - UserProfileData GetUserProfile(LLUUID userId); - void clearUserAgent(LLUUID avatarID); + UserProfileData GetUserProfileByAccount(string account); + UserProfileData GetUserProfile(LLUUID userId, string authAddr); + void clearUserAgent(LLUUID avatarID, string authAddr); + void UpdateUserAgentData(LLUUID agentId, bool agentOnline, LLVector3 currentPos, int logoutTime, string authAddr); + + List GenerateAgentPickerRequestResponse(LLUUID QueryID, string Query); UserProfileData SetupMasterUser(string firstName, string lastName); UserProfileData SetupMasterUser(string firstName, string lastName, string password); UserProfileData SetupMasterUser(LLUUID userId); + bool AuthenticateUser(LLUUID agentID, string sessionhash, out string asAddress);//rex + /// /// /// diff --git a/OpenSim/Framework/Login.cs b/OpenSim/Framework/Login.cs index 5228fe9ed6..a7bc38a5a4 100644 --- a/OpenSim/Framework/Login.cs +++ b/OpenSim/Framework/Login.cs @@ -33,6 +33,7 @@ namespace OpenSim.Framework { public string First = "Test"; public string Last = "User"; + public string ClientVersion = "not set"; //rex public LLUUID Agent; public LLUUID Session; public LLUUID SecureSession = LLUUID.Zero; @@ -42,6 +43,10 @@ namespace OpenSim.Framework public string CapsPath = ""; public LLVector3 StartPos; + public string AuthAddr = ""; + public string asAddress = ""; + + public Login() { StartPos = new LLVector3(128, 128, 70); diff --git a/OpenSim/Framework/Pair.cs b/OpenSim/Framework/Pair.cs new file mode 100644 index 0000000000..025f8a6ab5 --- /dev/null +++ b/OpenSim/Framework/Pair.cs @@ -0,0 +1,14 @@ +namespace OpenSim.Framework +{ + public class Pair + { + public Pair(T1 t1, T2 t2) + { + First = t1; + Second = t2; + } + + public T1 First; + public T2 Second; + } +} diff --git a/OpenSim/Framework/PrimitiveBaseShape.cs b/OpenSim/Framework/PrimitiveBaseShape.cs index abdd570930..1424395829 100644 --- a/OpenSim/Framework/PrimitiveBaseShape.cs +++ b/OpenSim/Framework/PrimitiveBaseShape.cs @@ -227,17 +227,5 @@ namespace OpenSim.Framework return shape; } - - public void SetPathRange( LLVector3 pathRange ) - { - PathBegin = LLObject.PackBeginCut(pathRange.X); - PathEnd = LLObject.PackEndCut(pathRange.Y); - } - - public void SetProfileRange( LLVector3 profileRange ) - { - ProfileBegin = LLObject.PackBeginCut(profileRange.X); - ProfileEnd = LLObject.PackEndCut(profileRange.Y); - } } } diff --git a/OpenSim/Framework/PrioritizedQueue.cs b/OpenSim/Framework/PrioritizedQueue.cs new file mode 100644 index 0000000000..cd4694e8e5 --- /dev/null +++ b/OpenSim/Framework/PrioritizedQueue.cs @@ -0,0 +1,123 @@ +using System; +using System.Threading; +using System.Collections.Generic; + +namespace OpenSim.Framework +{ + public class PrioritizedQueue + { + public delegate void AppendDelegate(LinkedList> list, T item, int priority); + public delegate int DeterminePriorityDelegate(T item); + + public AppendDelegate Appender { set { Append = value; } get { return Append; } } + private AppendDelegate Append; + + DeterminePriorityDelegate DeterminePriority; + public DeterminePriorityDelegate PriorityDeterminer + { + set { DeterminePriority = value; } + get { return DeterminePriority; } + } + + private LinkedList> List; + private object _queueSync = new object(); + + public PrioritizedQueue() + { + Append = new AppendDelegate(this.DefaultAppend); + List = new LinkedList>(); + } + + /// + /// Enqueues the given item and uses DeterminePriority to determine priority + /// + public void Enqueue(T item) + { + Enqueue(item, DeterminePriority(item)); + } + + /// + /// Enqueues the given item with given priority + /// + public void Enqueue(T item, int priority) + { + lock (_queueSync) + { + Append(List, item, priority); + Monitor.Pulse(_queueSync); + } + } + + /// + /// Enqueues the given item with given priority + /// + public void AddFirst(T item, int priority) + { + lock (_queueSync) + { + List.AddFirst(new Pair(item, priority)); + Monitor.Pulse(_queueSync); + } + } + + /// + /// Dequeues an item from the queue + /// + /// + /// Blocks until an item is available for dequeueing + /// + public T Dequeue() + { + lock (_queueSync) + { + if (List.First == null) + { + Monitor.Wait(_queueSync); + } + + T item = List.First.Value.First; + List.RemoveFirst(); + + return item; + } + } + + public int Count() + { + return List.Count; + } + + public bool HasQueuedItems() + { + return (List.First != null); + } + + /// + /// Default appending implementation + /// + private void DefaultAppend(LinkedList> list, T item, int priority) + { + LinkedListNode> node = list.Last; + + if (node == null) + { + list.AddFirst(new Pair(item, priority)); + return; + } + + while (node.Value.Second < priority) + { + node.Value.Second++; + + node = node.Previous; + if (node == null) + { + list.AddFirst(new Pair(item, priority)); + return; + } + } + + list.AddAfter(node, new Pair(item, priority)); + } + } +} \ No newline at end of file diff --git a/OpenSim/Framework/RegionInfo.cs b/OpenSim/Framework/RegionInfo.cs index 3c4fcbaacb..13d3f23c5c 100644 --- a/OpenSim/Framework/RegionInfo.cs +++ b/OpenSim/Framework/RegionInfo.cs @@ -169,6 +169,13 @@ namespace OpenSim.Framework public string MasterAvatarLastName = ""; public string MasterAvatarSandboxPassword = ""; + public LLUUID SkyboxFront = null; + public LLUUID SkyboxBack = null; + public LLUUID SkyboxLeft = null; + public LLUUID SkyboxRight = null; + public LLUUID SkyboxTop = null; + public LLUUID SkyboxBottom = null; + // Apparently, we're applying the same estatesettings regardless of whether it's local or remote. private static EstateSettings m_estateSettings; diff --git a/OpenSim/Framework/RexScriptAccess.cs b/OpenSim/Framework/RexScriptAccess.cs new file mode 100644 index 0000000000..e2ca8e8042 --- /dev/null +++ b/OpenSim/Framework/RexScriptAccess.cs @@ -0,0 +1,35 @@ +// Rex, new file +using System; +using System.Collections.Generic; +using System.Text; +using libsecondlife; + +namespace OpenSim.Framework +{ + // Interface for script engine. + public interface RexScriptAccessInterface + { + bool GetAvatarStartLocation(out LLVector3 vLoc, out LLVector3 vLookAt); + } + + + // Static class used for getting values from the script to server .net code. + // At the moment supports only one engine -> static. + public class RexScriptAccess + { + public static RexScriptAccessInterface MyScriptAccess = null; + + public static bool GetAvatarStartLocation(out LLVector3 vLoc, out LLVector3 vLookAt) + { + vLoc = new LLVector3(0,0,0); + vLookAt = new LLVector3(0, 0, 0); + + if (MyScriptAccess != null) + return MyScriptAccess.GetAvatarStartLocation(out vLoc, out vLookAt); + else + return false; + } + } + + +} diff --git a/OpenSim/Framework/ServerStatus/ServerStatus.cs b/OpenSim/Framework/ServerStatus/ServerStatus.cs new file mode 100644 index 0000000000..20f42cfae8 --- /dev/null +++ b/OpenSim/Framework/ServerStatus/ServerStatus.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using System.Diagnostics; +using System.Web; + +namespace OpenSim.Framework.ServerStatus +{ + public class ServerStatus + { + static StatusWindow m_window = null; + static Thread m_thread = null; + + static public void ReportOutPacketUdp(int size, bool resent) + { + StatusWindow.ReportOutPacketUdp(size, resent); + } + + static public void ReportInPacketUdp(int size) + { + StatusWindow.ReportInPacketUdp(size); + } + + static public void ReportOutPacketTcp(int size) + { + StatusWindow.ReportOutPacketTcp(size); + } + + static public void ReportInPacketTcp(int size) + { + StatusWindow.ReportInPacketTcp(size); + } + + static public void ReportProcessedInPacket(string name, int size) + { + if (m_window != null) + StatusWindow.ReportProcessedInPacket(name, size); + } + + static public void ReportProcessedOutPacket(string name, int size, bool resent) + { + if (m_window != null) + StatusWindow.ReportProcessedOutPacket(name, size, resent); + } + + static public void ReportThreadName(string name) + { + StatusWindow.ReportThreadName(AppDomain.GetCurrentThreadId(), name); + } + + static public void ShowWindow() + { + if (m_window == null) + { + m_window = new StatusWindow(); + + m_thread = new Thread(new ThreadStart(run)); + m_thread.IsBackground = true; + m_thread.Start(); + } + else + { + m_window.Show(); + } + } + + static void run() + { + ReportThreadName("ServerStatus"); + m_window.ShowDialog(); + m_window.CloseStatusWindow(); + m_window = null; + m_thread = null; + } + } +} diff --git a/OpenSim/Framework/ServerStatus/StatusWindow.Designer.cs b/OpenSim/Framework/ServerStatus/StatusWindow.Designer.cs new file mode 100644 index 0000000000..6e955bfebf --- /dev/null +++ b/OpenSim/Framework/ServerStatus/StatusWindow.Designer.cs @@ -0,0 +1,514 @@ +namespace OpenSim.Framework.ServerStatus +{ + partial class StatusWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.panel1 = new System.Windows.Forms.Panel(); + this.tabControl1 = new System.Windows.Forms.TabControl(); + this.tabThreads = new System.Windows.Forms.TabPage(); + this.tabNetwork = new System.Windows.Forms.TabPage(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.groupBox4 = new System.Windows.Forms.GroupBox(); + this.m_outTotalTraffic = new System.Windows.Forms.Label(); + this.m_inTotalTraffic = new System.Windows.Forms.Label(); + this.label11 = new System.Windows.Forms.Label(); + this.label12 = new System.Windows.Forms.Label(); + this.groupBox3 = new System.Windows.Forms.GroupBox(); + this.m_outTcpTraffic = new System.Windows.Forms.Label(); + this.m_inTcpTraffic = new System.Windows.Forms.Label(); + this.label7 = new System.Windows.Forms.Label(); + this.label8 = new System.Windows.Forms.Label(); + this.groupBox2 = new System.Windows.Forms.GroupBox(); + this.m_outUdpTraffic = new System.Windows.Forms.Label(); + this.m_inUdpTraffic = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.label1 = new System.Windows.Forms.Label(); + this.m_networkDrawing = new System.Windows.Forms.PictureBox(); + this.tabMemory = new System.Windows.Forms.TabPage(); + this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel(); + this.m_memStats = new System.Windows.Forms.PictureBox(); + this.groupBox5 = new System.Windows.Forms.GroupBox(); + this.m_availableMem = new System.Windows.Forms.Label(); + this.m_commitSize = new System.Windows.Forms.Label(); + this.label4 = new System.Windows.Forms.Label(); + this.label3 = new System.Windows.Forms.Label(); + this.tabCpu = new System.Windows.Forms.TabPage(); + this.tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel(); + this.m_cpuDrawing = new System.Windows.Forms.PictureBox(); + this.tabPackets = new System.Windows.Forms.TabPage(); + this.panel1.SuspendLayout(); + this.tabControl1.SuspendLayout(); + this.tabNetwork.SuspendLayout(); + this.tableLayoutPanel1.SuspendLayout(); + this.groupBox1.SuspendLayout(); + this.groupBox4.SuspendLayout(); + this.groupBox3.SuspendLayout(); + this.groupBox2.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.m_networkDrawing)).BeginInit(); + this.tabMemory.SuspendLayout(); + this.tableLayoutPanel2.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.m_memStats)).BeginInit(); + this.groupBox5.SuspendLayout(); + this.tabCpu.SuspendLayout(); + this.tableLayoutPanel3.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.m_cpuDrawing)).BeginInit(); + this.SuspendLayout(); + // + // panel1 + // + this.panel1.Controls.Add(this.tabControl1); + this.panel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.panel1.Location = new System.Drawing.Point(0, 0); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(604, 550); + this.panel1.TabIndex = 0; + // + // tabControl1 + // + this.tabControl1.Controls.Add(this.tabThreads); + this.tabControl1.Controls.Add(this.tabNetwork); + this.tabControl1.Controls.Add(this.tabMemory); + this.tabControl1.Controls.Add(this.tabCpu); + this.tabControl1.Controls.Add(this.tabPackets); + this.tabControl1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tabControl1.Location = new System.Drawing.Point(0, 0); + this.tabControl1.Name = "tabControl1"; + this.tabControl1.SelectedIndex = 0; + this.tabControl1.Size = new System.Drawing.Size(604, 550); + this.tabControl1.TabIndex = 0; + // + // tabThreads + // + this.tabThreads.Location = new System.Drawing.Point(4, 22); + this.tabThreads.Name = "tabThreads"; + this.tabThreads.Padding = new System.Windows.Forms.Padding(3); + this.tabThreads.Size = new System.Drawing.Size(596, 524); + this.tabThreads.TabIndex = 0; + this.tabThreads.Text = "Threads"; + this.tabThreads.UseVisualStyleBackColor = true; + // + // tabNetwork + // + this.tabNetwork.Controls.Add(this.tableLayoutPanel1); + this.tabNetwork.Location = new System.Drawing.Point(4, 22); + this.tabNetwork.Name = "tabNetwork"; + this.tabNetwork.Padding = new System.Windows.Forms.Padding(3); + this.tabNetwork.Size = new System.Drawing.Size(596, 524); + this.tabNetwork.TabIndex = 1; + this.tabNetwork.Text = "Network"; + this.tabNetwork.UseVisualStyleBackColor = true; + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 1; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.Controls.Add(this.groupBox1, 0, 1); + this.tableLayoutPanel1.Controls.Add(this.m_networkDrawing, 0, 0); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(3, 3); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 2; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 94F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(590, 518); + this.tableLayoutPanel1.TabIndex = 0; + // + // groupBox1 + // + this.groupBox1.Controls.Add(this.groupBox4); + this.groupBox1.Controls.Add(this.groupBox3); + this.groupBox1.Controls.Add(this.groupBox2); + this.groupBox1.Dock = System.Windows.Forms.DockStyle.Fill; + this.groupBox1.Location = new System.Drawing.Point(3, 427); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(584, 88); + this.groupBox1.TabIndex = 0; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "Traffic"; + // + // groupBox4 + // + this.groupBox4.Controls.Add(this.m_outTotalTraffic); + this.groupBox4.Controls.Add(this.m_inTotalTraffic); + this.groupBox4.Controls.Add(this.label11); + this.groupBox4.Controls.Add(this.label12); + this.groupBox4.Location = new System.Drawing.Point(319, 20); + this.groupBox4.Name = "groupBox4"; + this.groupBox4.Size = new System.Drawing.Size(148, 55); + this.groupBox4.TabIndex = 0; + this.groupBox4.TabStop = false; + this.groupBox4.Text = "Total"; + // + // m_outTotalTraffic + // + this.m_outTotalTraffic.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; + this.m_outTotalTraffic.Location = new System.Drawing.Point(43, 29); + this.m_outTotalTraffic.Name = "m_outTotalTraffic"; + this.m_outTotalTraffic.Size = new System.Drawing.Size(90, 13); + this.m_outTotalTraffic.TabIndex = 1; + this.m_outTotalTraffic.Text = "0,00 kB/s"; + // + // m_inTotalTraffic + // + this.m_inTotalTraffic.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; + this.m_inTotalTraffic.Location = new System.Drawing.Point(43, 16); + this.m_inTotalTraffic.Name = "m_inTotalTraffic"; + this.m_inTotalTraffic.Size = new System.Drawing.Size(90, 13); + this.m_inTotalTraffic.TabIndex = 1; + this.m_inTotalTraffic.Text = "0,00 kB/s"; + // + // label11 + // + this.label11.AutoSize = true; + this.label11.Location = new System.Drawing.Point(10, 29); + this.label11.Name = "label11"; + this.label11.Size = new System.Drawing.Size(27, 13); + this.label11.TabIndex = 0; + this.label11.Text = "Out:"; + // + // label12 + // + this.label12.AutoSize = true; + this.label12.Location = new System.Drawing.Point(10, 16); + this.label12.Name = "label12"; + this.label12.Size = new System.Drawing.Size(19, 13); + this.label12.TabIndex = 0; + this.label12.Text = "In:"; + // + // groupBox3 + // + this.groupBox3.Controls.Add(this.m_outTcpTraffic); + this.groupBox3.Controls.Add(this.m_inTcpTraffic); + this.groupBox3.Controls.Add(this.label7); + this.groupBox3.Controls.Add(this.label8); + this.groupBox3.Location = new System.Drawing.Point(165, 20); + this.groupBox3.Name = "groupBox3"; + this.groupBox3.Size = new System.Drawing.Size(148, 55); + this.groupBox3.TabIndex = 0; + this.groupBox3.TabStop = false; + this.groupBox3.Text = "Tcp"; + // + // m_outTcpTraffic + // + this.m_outTcpTraffic.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; + this.m_outTcpTraffic.Location = new System.Drawing.Point(43, 29); + this.m_outTcpTraffic.Name = "m_outTcpTraffic"; + this.m_outTcpTraffic.Size = new System.Drawing.Size(90, 13); + this.m_outTcpTraffic.TabIndex = 1; + this.m_outTcpTraffic.Text = "0,00 kB/s"; + // + // m_inTcpTraffic + // + this.m_inTcpTraffic.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; + this.m_inTcpTraffic.Location = new System.Drawing.Point(43, 16); + this.m_inTcpTraffic.Name = "m_inTcpTraffic"; + this.m_inTcpTraffic.Size = new System.Drawing.Size(90, 13); + this.m_inTcpTraffic.TabIndex = 1; + this.m_inTcpTraffic.Text = "0,00 kB/s"; + // + // label7 + // + this.label7.AutoSize = true; + this.label7.Location = new System.Drawing.Point(10, 29); + this.label7.Name = "label7"; + this.label7.Size = new System.Drawing.Size(27, 13); + this.label7.TabIndex = 0; + this.label7.Text = "Out:"; + // + // label8 + // + this.label8.AutoSize = true; + this.label8.Location = new System.Drawing.Point(10, 16); + this.label8.Name = "label8"; + this.label8.Size = new System.Drawing.Size(19, 13); + this.label8.TabIndex = 0; + this.label8.Text = "In:"; + // + // groupBox2 + // + this.groupBox2.Controls.Add(this.m_outUdpTraffic); + this.groupBox2.Controls.Add(this.m_inUdpTraffic); + this.groupBox2.Controls.Add(this.label2); + this.groupBox2.Controls.Add(this.label1); + this.groupBox2.Location = new System.Drawing.Point(11, 20); + this.groupBox2.Name = "groupBox2"; + this.groupBox2.Size = new System.Drawing.Size(148, 55); + this.groupBox2.TabIndex = 0; + this.groupBox2.TabStop = false; + this.groupBox2.Text = "Udp"; + // + // m_outUdpTraffic + // + this.m_outUdpTraffic.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; + this.m_outUdpTraffic.Location = new System.Drawing.Point(43, 29); + this.m_outUdpTraffic.Name = "m_outUdpTraffic"; + this.m_outUdpTraffic.Size = new System.Drawing.Size(90, 13); + this.m_outUdpTraffic.TabIndex = 1; + this.m_outUdpTraffic.Text = "0,00 kB/s"; + // + // m_inUdpTraffic + // + this.m_inUdpTraffic.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; + this.m_inUdpTraffic.Location = new System.Drawing.Point(43, 16); + this.m_inUdpTraffic.Name = "m_inUdpTraffic"; + this.m_inUdpTraffic.Size = new System.Drawing.Size(90, 13); + this.m_inUdpTraffic.TabIndex = 1; + this.m_inUdpTraffic.Text = "0,00 kB/s"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(10, 29); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(27, 13); + this.label2.TabIndex = 0; + this.label2.Text = "Out:"; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(10, 16); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(19, 13); + this.label1.TabIndex = 0; + this.label1.Text = "In:"; + // + // m_networkDrawing + // + this.m_networkDrawing.Dock = System.Windows.Forms.DockStyle.Fill; + this.m_networkDrawing.Location = new System.Drawing.Point(3, 3); + this.m_networkDrawing.Name = "m_networkDrawing"; + this.m_networkDrawing.Size = new System.Drawing.Size(584, 418); + this.m_networkDrawing.TabIndex = 1; + this.m_networkDrawing.TabStop = false; + // + // tabMemory + // + this.tabMemory.Controls.Add(this.tableLayoutPanel2); + this.tabMemory.Location = new System.Drawing.Point(4, 22); + this.tabMemory.Name = "tabMemory"; + this.tabMemory.Padding = new System.Windows.Forms.Padding(3); + this.tabMemory.Size = new System.Drawing.Size(596, 524); + this.tabMemory.TabIndex = 2; + this.tabMemory.Text = "Memory"; + this.tabMemory.UseVisualStyleBackColor = true; + // + // tableLayoutPanel2 + // + this.tableLayoutPanel2.ColumnCount = 1; + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel2.Controls.Add(this.m_memStats, 0, 0); + this.tableLayoutPanel2.Controls.Add(this.groupBox5, 0, 1); + this.tableLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel2.Location = new System.Drawing.Point(3, 3); + this.tableLayoutPanel2.Name = "tableLayoutPanel2"; + this.tableLayoutPanel2.RowCount = 2; + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 72F)); + this.tableLayoutPanel2.Size = new System.Drawing.Size(590, 518); + this.tableLayoutPanel2.TabIndex = 0; + // + // m_memStats + // + this.m_memStats.Dock = System.Windows.Forms.DockStyle.Fill; + this.m_memStats.Location = new System.Drawing.Point(3, 3); + this.m_memStats.Name = "m_memStats"; + this.m_memStats.Size = new System.Drawing.Size(584, 440); + this.m_memStats.TabIndex = 2; + this.m_memStats.TabStop = false; + // + // groupBox5 + // + this.groupBox5.Controls.Add(this.m_availableMem); + this.groupBox5.Controls.Add(this.m_commitSize); + this.groupBox5.Controls.Add(this.label4); + this.groupBox5.Controls.Add(this.label3); + this.groupBox5.Dock = System.Windows.Forms.DockStyle.Fill; + this.groupBox5.Location = new System.Drawing.Point(3, 449); + this.groupBox5.Name = "groupBox5"; + this.groupBox5.Size = new System.Drawing.Size(584, 66); + this.groupBox5.TabIndex = 3; + this.groupBox5.TabStop = false; + this.groupBox5.Text = "Current memory usage"; + // + // m_availableMem + // + this.m_availableMem.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; + this.m_availableMem.Location = new System.Drawing.Point(90, 38); + this.m_availableMem.Name = "m_availableMem"; + this.m_availableMem.Size = new System.Drawing.Size(100, 15); + this.m_availableMem.TabIndex = 1; + this.m_availableMem.Text = "0,00 mb"; + // + // m_commitSize + // + this.m_commitSize.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; + this.m_commitSize.Location = new System.Drawing.Point(90, 20); + this.m_commitSize.Name = "m_commitSize"; + this.m_commitSize.Size = new System.Drawing.Size(100, 15); + this.m_commitSize.TabIndex = 1; + this.m_commitSize.Text = "0,00 mb"; + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(31, 39); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(53, 13); + this.label4.TabIndex = 0; + this.label4.Text = "Available:"; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(19, 21); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(65, 13); + this.label3.TabIndex = 0; + this.label3.Text = "Commit size:"; + // + // tabCpu + // + this.tabCpu.Controls.Add(this.tableLayoutPanel3); + this.tabCpu.Location = new System.Drawing.Point(4, 22); + this.tabCpu.Name = "tabCpu"; + this.tabCpu.Padding = new System.Windows.Forms.Padding(3); + this.tabCpu.Size = new System.Drawing.Size(596, 524); + this.tabCpu.TabIndex = 3; + this.tabCpu.Text = "Cpu"; + this.tabCpu.UseVisualStyleBackColor = true; + // + // tableLayoutPanel3 + // + this.tableLayoutPanel3.ColumnCount = 1; + this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel3.Controls.Add(this.m_cpuDrawing, 0, 0); + this.tableLayoutPanel3.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel3.Location = new System.Drawing.Point(3, 3); + this.tableLayoutPanel3.Name = "tableLayoutPanel3"; + this.tableLayoutPanel3.RowCount = 2; + this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); + this.tableLayoutPanel3.Size = new System.Drawing.Size(590, 518); + this.tableLayoutPanel3.TabIndex = 0; + // + // m_cpuDrawing + // + this.m_cpuDrawing.Dock = System.Windows.Forms.DockStyle.Fill; + this.m_cpuDrawing.Location = new System.Drawing.Point(3, 3); + this.m_cpuDrawing.Name = "m_cpuDrawing"; + this.m_cpuDrawing.Size = new System.Drawing.Size(584, 492); + this.m_cpuDrawing.TabIndex = 0; + this.m_cpuDrawing.TabStop = false; + // + // tabPackets + // + this.tabPackets.Location = new System.Drawing.Point(4, 22); + this.tabPackets.Name = "tabPackets"; + this.tabPackets.Padding = new System.Windows.Forms.Padding(3); + this.tabPackets.Size = new System.Drawing.Size(596, 524); + this.tabPackets.TabIndex = 4; + this.tabPackets.Text = "Packets"; + this.tabPackets.UseVisualStyleBackColor = true; + // + // StatusWindow + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + //AutoSizeMode didn't work with mono + //this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.ClientSize = new System.Drawing.Size(604, 550); + this.Controls.Add(this.panel1); + this.Name = "StatusWindow"; + this.Text = "realXtend server status"; + this.panel1.ResumeLayout(false); + this.tabControl1.ResumeLayout(false); + this.tabNetwork.ResumeLayout(false); + this.tableLayoutPanel1.ResumeLayout(false); + this.groupBox1.ResumeLayout(false); + this.groupBox4.ResumeLayout(false); + this.groupBox4.PerformLayout(); + this.groupBox3.ResumeLayout(false); + this.groupBox3.PerformLayout(); + this.groupBox2.ResumeLayout(false); + this.groupBox2.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.m_networkDrawing)).EndInit(); + this.tabMemory.ResumeLayout(false); + this.tableLayoutPanel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.m_memStats)).EndInit(); + this.groupBox5.ResumeLayout(false); + this.groupBox5.PerformLayout(); + this.tabCpu.ResumeLayout(false); + this.tableLayoutPanel3.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.m_cpuDrawing)).EndInit(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Panel panel1; + private System.Windows.Forms.TabControl tabControl1; + private System.Windows.Forms.TabPage tabThreads; + private System.Windows.Forms.TabPage tabNetwork; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.GroupBox groupBox4; + private System.Windows.Forms.Label m_outTotalTraffic; + private System.Windows.Forms.Label m_inTotalTraffic; + private System.Windows.Forms.Label label11; + private System.Windows.Forms.Label label12; + private System.Windows.Forms.GroupBox groupBox3; + private System.Windows.Forms.Label m_outTcpTraffic; + private System.Windows.Forms.Label m_inTcpTraffic; + private System.Windows.Forms.Label label7; + private System.Windows.Forms.Label label8; + private System.Windows.Forms.GroupBox groupBox2; + private System.Windows.Forms.Label m_outUdpTraffic; + private System.Windows.Forms.Label m_inUdpTraffic; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.PictureBox m_networkDrawing; + private System.Windows.Forms.TabPage tabMemory; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2; + private System.Windows.Forms.PictureBox m_memStats; + private System.Windows.Forms.GroupBox groupBox5; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.Label m_availableMem; + private System.Windows.Forms.Label m_commitSize; + private System.Windows.Forms.TabPage tabCpu; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel3; + private System.Windows.Forms.PictureBox m_cpuDrawing; + private System.Windows.Forms.TabPage tabPackets; + + + + } +} \ No newline at end of file diff --git a/OpenSim/Framework/ServerStatus/StatusWindow.cs b/OpenSim/Framework/ServerStatus/StatusWindow.cs new file mode 100644 index 0000000000..fa9ff005ac --- /dev/null +++ b/OpenSim/Framework/ServerStatus/StatusWindow.cs @@ -0,0 +1,884 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Text; +using System.Windows.Forms; +using System.Timers; +using System.Diagnostics; +using System.Runtime.InteropServices; + +namespace OpenSim.Framework.ServerStatus +{ + public partial class StatusWindow : Form + { + System.Timers.Timer m_updateTimer; + static Dictionary m_threadItems = new Dictionary(); + static Dictionary m_idToName = new Dictionary(); + static int m_nCoreCount = System.Environment.ProcessorCount; + + PerformanceCounter m_pcAvailRam = null; + + class TrafficHistory { + public float outUdpBytes = 0; + public float inUdpBytes = 0; + public float outTcpBytes = 0; + public float inTcpBytes = 0; + public float outTotalBytes = 0; + public float inTotalBytes = 0; + public float resentBytes = 0; + } + + class MemoryHistory { + public float nonpagedSystemMemory; + public float pagedMemory; + public float pagedSystemMemory; + public float gcReportedMem; + public float workingSet; + } + + class CpuHistory { + public float[] cpuUsage = new float[m_nCoreCount]; + public float totalUsage = 0; + } + + class PacketItem + { + public long m_bytesOut = 0; + public long m_packetsOut = 0; + public long m_bytesIn = 0; + public long m_packetsIn = 0; + public long m_resent = 0; + + public bool m_addedToList = false; + public ListViewItem.ListViewSubItem m_listBytesOut = null; + public ListViewItem.ListViewSubItem m_listPacketsOut = null; + public ListViewItem.ListViewSubItem m_listBytesIn = null; + public ListViewItem.ListViewSubItem m_listPacketsIn = null; + public ListViewItem.ListViewSubItem m_listResent = null; + } + + static float m_fNetworkHistoryScale; + static float m_fMemoryHistoryScale; + + static Dictionary m_packets = new Dictionary(); + static LinkedList m_trafficHistory = new LinkedList(); + static LinkedList m_memoryHistory = new LinkedList(); + static LinkedList m_cpuHistory = new LinkedList(); + + PerformanceCounter[] m_pcCpu = new PerformanceCounter[System.Environment.ProcessorCount]; + PerformanceCounter m_pcCpuTotal = null; + + static volatile int outUdpBytes = 0; + static volatile int inUdpBytes = 0; + static volatile int outTcpBytes = 0; + static volatile int inTcpBytes = 0; + static volatile int outResent = 0; + + BufferedListView m_threads; + BufferedListView m_listPackets; + + #region BufferedListView + /** + * Flicker minimized listview + **/ + public class BufferedListView : ListView + { + #region WM - Window Messages + public enum WM + { + WM_NULL = 0x0000, + WM_CREATE = 0x0001, + WM_DESTROY = 0x0002, + WM_MOVE = 0x0003, + WM_SIZE = 0x0005, + WM_ACTIVATE = 0x0006, + WM_SETFOCUS = 0x0007, + WM_KILLFOCUS = 0x0008, + WM_ENABLE = 0x000A, + WM_SETREDRAW = 0x000B, + WM_SETTEXT = 0x000C, + WM_GETTEXT = 0x000D, + WM_GETTEXTLENGTH = 0x000E, + WM_PAINT = 0x000F, + WM_CLOSE = 0x0010, + WM_QUERYENDSESSION = 0x0011, + WM_QUIT = 0x0012, + WM_QUERYOPEN = 0x0013, + WM_ERASEBKGND = 0x0014, + + } + #endregion + + #region RECT + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] + public struct RECT + { + public int left; + public int top; + public int right; + public int bottom; + } + #endregion + + #region Imported User32.DLL functions + [DllImport("user32.dll", CharSet = CharSet.Auto)] + static public extern bool ValidateRect(IntPtr handle, ref RECT rect); + #endregion + + #region GetWindowRECT + // Get the listview's rectangle and return it as a RECT structure + private RECT GetWindowRECT() + { + RECT rect = new RECT(); + rect.left = this.Left; + rect.right = this.Right; + rect.top = this.Top; + rect.bottom = this.Bottom; + return rect; + } + #endregion + + volatile public bool updating = false; + + public BufferedListView() + { + } + + + protected override void OnPaintBackground(PaintEventArgs pea) + { + // do nothing here since this event is now handled by OnPaint + } + + + protected override void OnPaint(PaintEventArgs pea) + { + base.OnPaint(pea); + } + + protected override void WndProc(ref Message messg) + { + if (updating) + { + if ((int)WM.WM_ERASEBKGND == messg.Msg) + { + return; + } + else if ((int)WM.WM_PAINT == messg.Msg) + { + RECT vrect = this.GetWindowRECT(); + // validate the entire window + ValidateRect(this.Handle, ref vrect); + } + + } + base.WndProc(ref messg); + } + } + #endregion + + #region ThreadItem + /** + * Represents a single thread item in the listview control + **/ + class ThreadItem + { + public ListViewItem listItem; + public ListViewItem.ListViewSubItem name; + public ListViewItem.ListViewSubItem cpu; + } + #endregion + + + public static void ReportOutPacketUdp(int size, bool resent) + { + if (resent) + { + outResent += size += 8; + } + outUdpBytes += size + 8; + } + + public static void ReportInPacketUdp(int size) { inUdpBytes += size + 8; } + + public static void ReportOutPacketTcp(int size) { outTcpBytes += size + 20; } + public static void ReportInPacketTcp(int size) { inTcpBytes += size + 20; } + + public static void ReportProcessedOutPacket(string name, int size, bool resent) + { + PacketItem item = null; + if (m_packets.ContainsKey(name)) + { + item = m_packets[name]; + } + else + { + item = new PacketItem(); + m_packets[name] = item; + } + + if (resent) + { + item.m_resent += size; + } + item.m_bytesOut += size; + item.m_packetsOut++; + } + + public static void ReportProcessedInPacket(string name, int size) + { + PacketItem item = null; + if (m_packets.ContainsKey(name)) + { + item = m_packets[name]; + } + else + { + item = new PacketItem(); + m_packets[name] = item; + } + + item.m_bytesIn += size; + item.m_packetsIn++; + } + + + public StatusWindow() + { + m_pcAvailRam = new PerformanceCounter("Memory", "Available MBytes"); + m_packets = new Dictionary(); + + InitializeComponent(); + + m_listPackets = new BufferedListView(); + m_listPackets.Dock = System.Windows.Forms.DockStyle.Fill; + m_listPackets.GridLines = true; + m_listPackets.Location = new System.Drawing.Point(3, 3); + m_listPackets.MultiSelect = false; + m_listPackets.Name = "m_listPackets"; + m_listPackets.Size = new System.Drawing.Size(500, 400); + m_listPackets.TabIndex = 0; + m_listPackets.View = System.Windows.Forms.View.Details; + + tabPackets.Controls.Add(m_listPackets); + + m_listPackets.Columns.Add("Packet").Width = 260; + m_listPackets.Columns.Add("In count").Width = 80; + m_listPackets.Columns.Add("In bytes").Width = 80; + m_listPackets.Columns.Add("Out count").Width = 80; + m_listPackets.Columns.Add("Out bytes").Width = 80; + m_listPackets.Columns.Add("Resent").Width = 80; + + + m_threads = new BufferedListView(); + m_threads.Dock = System.Windows.Forms.DockStyle.Fill; + m_threads.GridLines = true; + m_threads.Location = new System.Drawing.Point(3, 3); + m_threads.MultiSelect = false; + m_threads.Name = "m_threads"; + m_threads.Size = new System.Drawing.Size(500, 400); + m_threads.TabIndex = 0; + m_threads.View = System.Windows.Forms.View.Details; + + tabThreads.Controls.Add(m_threads); + + m_threads.Columns.Add("ID"); + m_threads.Columns.Add("Name").Width = 260; + m_threads.Columns.Add("CPU Time").Width=100; + + m_updateTimer = new System.Timers.Timer(2000); + m_updateTimer.Elapsed += new ElapsedEventHandler(UpdateTimer); + outUdpBytes = 0; + inUdpBytes = 0; + outTcpBytes = 0; + inTcpBytes = 0; + outResent = 0; + m_updateTimer.Start(); + + for(int i = 0; i < m_nCoreCount; i++) + { + m_pcCpu[i] = new PerformanceCounter("Processor", "% Processor Time", i.ToString(), true); + m_pcCpu[i].MachineName = "."; + } + m_pcCpuTotal = new PerformanceCounter("Processor", "% Processor Time", "_Total", true); + } + + public void CloseStatusWindow() { + Close(); + m_updateTimer.Stop(); + m_threadItems.Clear(); + + m_pcAvailRam.Close(); + m_pcAvailRam = null; + + for (int i = 0; i < m_nCoreCount; i++) + { + m_pcCpu[i].Close(); + m_pcCpu[i] = null; + } + + foreach(PacketItem item in m_packets.Values) + { + item.m_addedToList = false; + } + + m_packets = null; + + m_pcCpuTotal.Close(); + m_pcCpuTotal = null; + } + + public static void ReportThreadName(int id, string name) + { + lock (m_threadItems) + { + m_idToName[id] = name; + } + } + + delegate void UpdateControlsDelegate(); + + TrafficHistory UpdateNetworkHistory() + { + TrafficHistory item = new TrafficHistory(); + + item.inUdpBytes = ((float)inUdpBytes) / 1024.0f / 2.0f; + item.outUdpBytes = ((float)outUdpBytes) / 1024.0f / 2.0f; + item.inTcpBytes = ((float)inTcpBytes) / 1024.0f / 2.0f; + item.outTcpBytes = ((float)outTcpBytes) / 1024.0f / 2.0f; + item.resentBytes = ((float)outResent) / 1024.0f / 2.0f; + item.inTotalBytes = item.inUdpBytes + item.inTcpBytes; + item.outTotalBytes = item.outUdpBytes + item.outTcpBytes; + inUdpBytes = 0; + outUdpBytes = 0; + inTcpBytes = 0; + outTcpBytes = 0; + outResent = 0; + + m_trafficHistory.AddFirst(item); + if (m_trafficHistory.Count > 500) + { + m_trafficHistory.RemoveLast(); + } + + return item; + } + + MemoryHistory UpdateMemoryHistory(Process proc) + { + MemoryHistory item = new MemoryHistory(); + + item.gcReportedMem = ((float)System.GC.GetTotalMemory(false)) / 1024.0f / 1024.0f; + item.workingSet = ((float)proc.WorkingSet64) / 1024.0f / 1024.0f; + item.nonpagedSystemMemory = ((float)proc.NonpagedSystemMemorySize64) / 1024.0f / 1024.0f; + item.pagedSystemMemory = ((float)proc.PagedMemorySize64) / 1024.0f / 1024.0f; + item.pagedSystemMemory = ((float)proc.PagedSystemMemorySize64) / 1024.0f / 1024.0f; + + m_memoryHistory.AddFirst(item); + if (m_memoryHistory.Count > 500) + { + m_memoryHistory.RemoveLast(); + } + + return item; + } + + void UpdateCpuHistory() { + CpuHistory item = new CpuHistory(); + + for( int i = 0; i < m_nCoreCount; i++) + { + item.cpuUsage[i] = m_pcCpu[i].NextValue(); + } + + item.totalUsage = m_pcCpuTotal.NextValue(); + + m_cpuHistory.AddFirst(item); + if (m_cpuHistory.Count > 500) + { + m_cpuHistory.RemoveLast(); + } + } + + string FormatDataSize(long byteCount) + { + double fCount = (double)byteCount; + if (byteCount > 1024 * 1024 * 1024) + { + fCount/=(1024.0*1024.0*1024.0); + return fCount.ToString("##0.00") + "GB"; + } + else if (byteCount > 1024*1024*10) + { + fCount/=(1024.0*1024.0); + return fCount.ToString("##0.00") + "MB"; + } + else if (byteCount > 1024*10) + { + fCount/=1024.0; + return fCount.ToString("##0.00") + "KB"; + } + else + { + return byteCount.ToString() +"B"; + } + } + + void UpdatePacketView() + { + foreach(KeyValuePair item in m_packets) + { + if (item.Value.m_addedToList) + { + item.Value.m_listPacketsIn.Text = item.Value.m_packetsIn.ToString(); + item.Value.m_listBytesIn.Text = FormatDataSize(item.Value.m_bytesIn); + item.Value.m_listPacketsOut.Text = item.Value.m_packetsOut.ToString(); + item.Value.m_listBytesOut.Text = FormatDataSize(item.Value.m_bytesOut); + item.Value.m_listResent.Text = FormatDataSize(item.Value.m_resent); + } + else + { + ListViewItem listItem = m_listPackets.Items.Add(item.Key); + item.Value.m_listPacketsIn = listItem.SubItems.Add(item.Value.m_packetsIn.ToString()); + item.Value.m_listBytesIn = listItem.SubItems.Add(FormatDataSize(item.Value.m_bytesIn)); + item.Value.m_listPacketsOut = listItem.SubItems.Add(item.Value.m_packetsOut.ToString()); + item.Value.m_listBytesOut = listItem.SubItems.Add(FormatDataSize(item.Value.m_bytesOut)); + item.Value.m_listResent = listItem.SubItems.Add(FormatDataSize(item.Value.m_resent)); + item.Value.m_addedToList = true; + } + + } + } + + void UpdateControls() + { + Process proc = Process.GetCurrentProcess(); + + TrafficHistory netItem = UpdateNetworkHistory(); + MemoryHistory memItem = UpdateMemoryHistory(proc); + + UpdateCpuHistory(); + + if (tabControl1.SelectedIndex == 0) + { + m_threads.updating = true; + UpdateThreadList(); + m_threads.updating = false; + m_threads.Invalidate(); + } + else if (tabControl1.SelectedIndex == 1) + { + RefreshNetworkStats(netItem); + PaintNetworkHistory(); + } + else if (tabControl1.SelectedIndex == 2) + { + m_availableMem.Text = m_pcAvailRam.NextValue().ToString("##0.00") + " MB"; + m_commitSize.Text = memItem.workingSet.ToString("##0.00") + " MB"; + PaintMemoryHistory(); + } + else if (tabControl1.SelectedIndex == 3) + { + PaintCpuHistory(); + } + else if (tabControl1.SelectedIndex == 4) + { + m_listPackets.updating = true; + UpdatePacketView(); + m_listPackets.updating = false; + m_listPackets.Invalidate(); + } + } + + protected void PaintCpuHistory() + { + Pen[] pens = { Pens.Yellow, Pens.Blue, Pens.Green, Pens.Red, + Pens.White, Pens.Turquoise, Pens.Linen, Pens.Gray, + Pens.Purple, Pens.Pink, Pens.LightBlue, Pens.LightSalmon}; + + Pen penLine = Pens.DarkSlateGray; + + Graphics screenGfx = m_cpuDrawing.CreateGraphics(); + Bitmap backBuffer = new Bitmap(m_cpuDrawing.Width, m_cpuDrawing.Height); + Graphics gfx = Graphics.FromImage(backBuffer); + + gfx.Clear(Color.Black); + + float fMax = 105.0f; + for (int i = 0; i < m_cpuDrawing.Height - 10; i += 30) + { + float yPos = m_cpuDrawing.Height - i - 15; + float fPos = ((float)(i)) / ((float)m_cpuDrawing.Height); + gfx.DrawLine(penLine, 0, yPos, m_cpuDrawing.Width, yPos); + } + + //Size of second in pixels + float fSecondStep = 2.5f; //120 seconds + float fTotalSeconds = (1 / fSecondStep) * (m_cpuDrawing.Width - 90); + for (int i = 0; i < m_cpuDrawing.Width - 90; i += 50) + { + float xPos = 90 + i; + float fTime = fTotalSeconds - (((float)(i)) / fSecondStep); + + gfx.DrawLine(penLine, xPos, 0, xPos, m_cpuDrawing.Height - 15); + string strText = fTime.ToString("##0"); + gfx.DrawString(strText, SystemFonts.DialogFont, Brushes.CadetBlue, + xPos - 4 * strText.Length, m_cpuDrawing.Height - 15); + } + + + float nXPos = m_cpuDrawing.Width; + float fHeightMul = m_cpuDrawing.Height - 15; + float fYStart = m_cpuDrawing.Height - 15; + CpuHistory lastItem = null; + + foreach (CpuHistory item in m_cpuHistory) + { + if (lastItem != null) + { + nXPos -= fSecondStep * 2; + + for (int i = 0; i < m_nCoreCount; i++) + { + gfx.DrawLine(pens[i+1], nXPos, fYStart - (item.cpuUsage[i] / fMax) * fHeightMul, + nXPos + fSecondStep * 2, fYStart - (lastItem.cpuUsage[i] / fMax) * fHeightMul); + } + + gfx.DrawLine(pens[0], nXPos, fYStart - (item.totalUsage / fMax) * fHeightMul, + nXPos + fSecondStep * 2, fYStart - (lastItem.totalUsage / fMax) * fHeightMul); + + if (nXPos < 0) + break; + } + + lastItem = item; + } + + for (int i = 0; i < m_cpuDrawing.Height - 10; i += 30) + { + float yPos = m_cpuDrawing.Height - i - 15; + float fPos = ((float)(i)) / ((float)m_cpuDrawing.Height); + gfx.DrawString((fPos * fMax).ToString("##0.00") + "%", + SystemFonts.DialogFont, Brushes.CadetBlue, 3, yPos); + } + + int nPosX = m_cpuDrawing.Width - 50; + + + gfx.DrawString("Total", SystemFonts.DialogFont, pens[0].Brush, nPosX, 10); + for (int i = 0; i < m_nCoreCount; i++ ) + { + gfx.DrawString("Core " + i, SystemFonts.DialogFont, pens[i+1].Brush, nPosX, 22 + i * 12); + } + + screenGfx.DrawImageUnscaled(backBuffer, 0, 0); + } + + protected void PaintNetworkHistory() + { + Pen penUdpOut = Pens.SkyBlue; + Pen penUdpIn = Pens.Blue; + Pen penTcpOut = Pens.Red; + Pen penTcpIn = Pens.Pink; + Pen penTotalOut = Pens.Green; + Pen penTotalIn = Pens.LimeGreen; + Pen penResent = Pens.Orange; + + Pen penLine = Pens.DarkSlateGray; + + + Graphics screenGfx = m_networkDrawing.CreateGraphics(); + Bitmap backBuffer = new Bitmap(m_networkDrawing.Width, m_networkDrawing.Height); + Graphics gfx = Graphics.FromImage(backBuffer); + + gfx.Clear(Color.Black); + + float fMax = m_fNetworkHistoryScale; + if (fMax < 12.0f) + fMax = 12.0f; + for( int i = 0; i < m_networkDrawing.Height-10; i+= 30) + { + float yPos = m_networkDrawing.Height - i-15; + float fPos = ((float)(i)) / ((float)m_networkDrawing.Height); + gfx.DrawLine(penLine, 0, yPos, m_networkDrawing.Width, yPos); + } + + //Size of second in pixels + float fSecondStep = 1.5f; //120 seconds + float fTotalSeconds = (1/fSecondStep) * (m_networkDrawing.Width - 90); + for( int i = 0; i < m_networkDrawing.Width-90; i+= 50) + { + float xPos = 90 + i; + float fTime = fTotalSeconds - (((float)(i)) / fSecondStep); + + gfx.DrawLine(penLine, xPos, 0, xPos, m_networkDrawing.Height - 15); + string strText = fTime.ToString("##0"); + gfx.DrawString(strText, SystemFonts.DialogFont, Brushes.CadetBlue, + xPos - 4 * strText.Length, m_networkDrawing.Height - 15); + } + + + float nXPos = m_networkDrawing.Width; + float fHeightMul = m_networkDrawing.Height - 15; + float fYStart = m_networkDrawing.Height - 15; + TrafficHistory lastItem = null; + + float fHighestRate = 0; + foreach(TrafficHistory item in m_trafficHistory) { + if (lastItem != null) + { + nXPos -= fSecondStep * 2; + + gfx.DrawLine(penUdpIn, nXPos, fYStart - (item.inUdpBytes / fMax) * fHeightMul, + nXPos + fSecondStep * 2, fYStart - (lastItem.inUdpBytes / fMax) * fHeightMul); + gfx.DrawLine(penUdpOut, nXPos, fYStart - (item.outUdpBytes / fMax) * fHeightMul, + nXPos + fSecondStep * 2, fYStart - (lastItem.outUdpBytes / fMax) * fHeightMul); + + gfx.DrawLine(penTcpIn, nXPos, fYStart - (item.inTcpBytes / fMax) * fHeightMul, + nXPos + fSecondStep * 2, fYStart - (lastItem.inTcpBytes / fMax) * fHeightMul); + gfx.DrawLine(penTcpOut, nXPos, fYStart - (item.outTcpBytes / fMax) * fHeightMul, + nXPos + fSecondStep * 2, fYStart - (lastItem.outTcpBytes / fMax) * fHeightMul); + + gfx.DrawLine(penTotalIn, nXPos, fYStart - (item.inTotalBytes / fMax) * fHeightMul, + nXPos + fSecondStep * 2, fYStart - (lastItem.inTotalBytes / fMax) * fHeightMul); + gfx.DrawLine(penTotalOut, nXPos, fYStart - (item.outTotalBytes / fMax) * fHeightMul, + nXPos + fSecondStep * 2, fYStart - (lastItem.outTotalBytes / fMax) * fHeightMul); + + gfx.DrawLine(penResent, nXPos, fYStart - (item.resentBytes / fMax) * fHeightMul, + nXPos + fSecondStep * 2, fYStart - (lastItem.resentBytes / fMax) * fHeightMul); + + if (nXPos < 0) + break; + } + lastItem = item; + if (item.inTotalBytes > fHighestRate) + fHighestRate = item.inTotalBytes; + if (item.outTotalBytes > fHighestRate) + fHighestRate = item.outTotalBytes; + } + + for (int i = 0; i < m_networkDrawing.Height - 10; i += 30) + { + float yPos = m_networkDrawing.Height - i - 15; + float fPos = ((float)(i)) / ((float)m_networkDrawing.Height); + gfx.DrawString((fPos * fMax).ToString("##0.00") + " KB/s", + SystemFonts.DialogFont, Brushes.CadetBlue, 3, yPos); + } + + int nPosX = m_networkDrawing.Width-60; + gfx.DrawString("Udp in", SystemFonts.DialogFont, penUdpIn.Brush, nPosX, 10); + gfx.DrawString("Udp out", SystemFonts.DialogFont, penUdpOut.Brush, nPosX, 22); + gfx.DrawString("Tcp in", SystemFonts.DialogFont, penTcpIn.Brush, nPosX, 34); + gfx.DrawString("Tcp out", SystemFonts.DialogFont, penTcpOut.Brush, nPosX, 46); + gfx.DrawString("Total in", SystemFonts.DialogFont, penTotalIn.Brush, nPosX, 58); + gfx.DrawString("Total out", SystemFonts.DialogFont, penTotalOut.Brush, nPosX, 70); + gfx.DrawString("Resent", SystemFonts.DialogFont, penResent.Brush, nPosX, 82); + + screenGfx.DrawImageUnscaled(backBuffer, 0, 0); + + m_fNetworkHistoryScale = fHighestRate + 10; + } + + protected void PaintMemoryHistory() + { + Pen penPagedMemory = Pens.Gray; + Pen penPagedSystemMemory = Pens.Orange; + Pen penNonPagedMemory = Pens.LawnGreen; + Pen penWorkingSet = Pens.HotPink; + Pen penGcReported = Pens.Red; + + + Pen penLine = Pens.DarkSlateGray; + + Graphics screenGfx = m_memStats.CreateGraphics(); + Bitmap backBuffer = new Bitmap(m_memStats.Width, m_memStats.Height); + Graphics gfx = Graphics.FromImage(backBuffer); + + gfx.Clear(Color.Black); + + float fMax = m_fMemoryHistoryScale; + if (fMax < 12.0f) + fMax = 12.0f; + for (int i = 0; i < m_memStats.Height - 10; i += 30) + { + float yPos = m_memStats.Height - i - 15; + float fPos = ((float)(i)) / ((float)m_memStats.Height); + gfx.DrawLine(penLine, 0, yPos, m_memStats.Width, yPos); + } + + //Size of second in pixels + float fSecondStep = 1.5f; //120 seconds + float fTotalSeconds = (1 / fSecondStep) * (m_memStats.Width - 90); + for (int i = 0; i < m_memStats.Width - 90; i += 50) + { + float xPos = 90 + i; + float fTime = fTotalSeconds - (((float)(i)) / fSecondStep); + + gfx.DrawLine(penLine, xPos, 0, xPos, m_memStats.Height - 15); + string strText = fTime.ToString("##0"); + gfx.DrawString(strText, SystemFonts.DialogFont, Brushes.CadetBlue, + xPos - 4 * strText.Length, m_memStats.Height - 15); + } + + + float nXPos = m_memStats.Width; + float fHeightMul = m_memStats.Height - 15; + float fYStart = m_memStats.Height - 15; + MemoryHistory lastItem = null; + + float fHighestRate = 0; + foreach (MemoryHistory item in m_memoryHistory) + { + if (lastItem != null) + { + + nXPos -= fSecondStep * 2; + + gfx.DrawLine(penPagedMemory, nXPos, fYStart - (item.pagedMemory / fMax) * fHeightMul, + nXPos + fSecondStep * 2, fYStart - (lastItem.pagedMemory / fMax) * fHeightMul); + + gfx.DrawLine(penPagedSystemMemory, nXPos, fYStart - (item.pagedSystemMemory / fMax) * fHeightMul, + nXPos + fSecondStep * 2, fYStart - (lastItem.pagedSystemMemory / fMax) * fHeightMul); + + gfx.DrawLine(penNonPagedMemory, nXPos, fYStart - (item.nonpagedSystemMemory / fMax) * fHeightMul, + nXPos + fSecondStep * 2, fYStart - (lastItem.nonpagedSystemMemory / fMax) * fHeightMul); + + gfx.DrawLine(penWorkingSet, nXPos, fYStart - (item.workingSet / fMax) * fHeightMul, + nXPos + fSecondStep * 2, fYStart - (lastItem.workingSet / fMax) * fHeightMul); + + gfx.DrawLine(penGcReported, nXPos, fYStart - (item.gcReportedMem / fMax) * fHeightMul, + nXPos + fSecondStep * 2, fYStart - (lastItem.gcReportedMem / fMax) * fHeightMul); + + if (nXPos < 0) + break; + } + + lastItem = item; + if (item.nonpagedSystemMemory > fHighestRate) + fHighestRate = item.nonpagedSystemMemory; + if (item.pagedMemory > fHighestRate) + fHighestRate = item.pagedMemory; + if (item.pagedSystemMemory > fHighestRate) + fHighestRate = item.pagedSystemMemory; + if (item.workingSet > fHighestRate) + fHighestRate = item.workingSet; + if (item.gcReportedMem > fHighestRate) + fHighestRate = item.gcReportedMem; + } + + for (int i = 0; i < m_memStats.Height - 10; i += 30) + { + float yPos = m_memStats.Height - i - 15; + float fPos = ((float)(i)) / ((float)m_memStats.Height); + gfx.DrawString((fPos * fMax).ToString("##0.00") + " MB", + SystemFonts.DialogFont, Brushes.CadetBlue, 3, yPos); + } + + int nPosX = m_memStats.Width - 120; + + gfx.DrawString("Working set", SystemFonts.DialogFont, penWorkingSet.Brush, nPosX, 10); + gfx.DrawString("GC Reported mem.", SystemFonts.DialogFont, penGcReported.Brush, nPosX, 22); + gfx.DrawString("Paged mem.", SystemFonts.DialogFont, penPagedMemory.Brush, nPosX, 34); + gfx.DrawString("Paged system mem.", SystemFonts.DialogFont, penPagedSystemMemory.Brush, nPosX, 46); + gfx.DrawString("Nonpaged mem.", SystemFonts.DialogFont, penNonPagedMemory.Brush, nPosX, 58); + + screenGfx.DrawImageUnscaled(backBuffer, 0, 0); + + m_fMemoryHistoryScale = fHighestRate + 10; + } + + void RefreshNetworkStats(TrafficHistory item) + { + m_inUdpTraffic.Text = item.inUdpBytes.ToString("##0.00") + " KB/s"; + m_outUdpTraffic.Text = item.outUdpBytes.ToString("##0.00") + " KB/s"; + m_inTcpTraffic.Text = item.inTcpBytes.ToString("##0.00") + " KB/s"; + m_outTcpTraffic.Text = item.outTcpBytes.ToString("##0.00") + " KB/s"; + m_inTotalTraffic.Text = item.inTotalBytes.ToString("##0.00") + " KB/s"; + m_outTotalTraffic.Text = item.outTotalBytes.ToString("##0.00") + " KB/s"; + } + + protected void UpdateTimer(object sender, ElapsedEventArgs ea) + { + if (m_threads.InvokeRequired) + { + m_threads.Invoke(new UpdateControlsDelegate(UpdateControls)); + } + else + { + UpdateControls(); + } + } + + + #region Thread items access + void UpdateThreadItem(ProcessThread pt) + { + if (m_threadItems.ContainsKey(pt.Id)) + { + ThreadItem item = m_threadItems[pt.Id]; + + item.cpu.Text = pt.TotalProcessorTime.ToString(); + if (m_idToName.ContainsKey(pt.Id)) + { + item.name.Text = m_idToName[pt.Id]; + } + } + else + { + ThreadItem item = new ThreadItem(); + item.listItem = m_threads.Items.Add(pt.Id.ToString()); + string name = "[n/a]"; + if (m_idToName.ContainsKey(pt.Id)) + { + name = m_idToName[pt.Id]; + } + item.name = item.listItem.SubItems.Add(name); + item.cpu = item.listItem.SubItems.Add(pt.TotalProcessorTime.ToString()); + + m_threadItems[pt.Id] = item; + } + } + + void RemoveThreadItems(List removed) + { + foreach (int id in removed) + { + m_threads.Items.Remove(m_threadItems[id].listItem); + m_threadItems.Remove(id); + m_idToName.Remove(id); + } + } + + private void UpdateThreadList() + { + ProcessThreadCollection threads = Process.GetCurrentProcess().Threads; + + lock (m_threadItems) + { + Dictionary runningThreads = new Dictionary(); + + foreach (ProcessThread pt in threads) + { + runningThreads[pt.Id] = 0; + + UpdateThreadItem(pt); + } + + List removed = new List(); + foreach (int id in m_threadItems.Keys) + { + if (!runningThreads.ContainsKey(id)) + { + removed.Add(id); + } + } + + RemoveThreadItems(removed); + } + } + + #endregion + } +} \ No newline at end of file diff --git a/OpenSim/Framework/ServerStatus/StatusWindow.resx b/OpenSim/Framework/ServerStatus/StatusWindow.resx new file mode 100644 index 0000000000..ff31a6db56 --- /dev/null +++ b/OpenSim/Framework/ServerStatus/StatusWindow.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/OpenSim/Framework/Servers/BaseHttpServer.cs b/OpenSim/Framework/Servers/BaseHttpServer.cs index 32d65af243..35553d8528 100644 --- a/OpenSim/Framework/Servers/BaseHttpServer.cs +++ b/OpenSim/Framework/Servers/BaseHttpServer.cs @@ -300,7 +300,15 @@ namespace OpenSim.Framework.Servers } finally { - response.OutputStream.Close(); + try + { + response.OutputStream.Flush(); + response.OutputStream.Close(); + } + catch (Exception ex) + { + MainLog.Instance.Warn("HTTPD", "Error closing - " + ex.Message); + } } } @@ -352,7 +360,15 @@ namespace OpenSim.Framework.Servers } finally { - response.OutputStream.Close(); + try + { + response.OutputStream.Flush(); + response.OutputStream.Close(); + } + catch (Exception ex) + { + MainLog.Instance.Warn("HTTPD", "Error closing - " + ex.Message); + } } } diff --git a/OpenSim/Framework/UserConfig.cs b/OpenSim/Framework/UserConfig.cs index c9957efadd..dc05ab5a84 100644 --- a/OpenSim/Framework/UserConfig.cs +++ b/OpenSim/Framework/UserConfig.cs @@ -48,6 +48,7 @@ namespace OpenSim.Framework public bool HttpSSL = DefaultHttpSSL; public uint DefaultX = 1000; public uint DefaultY = 1000; + public bool RexMode = false; private ConfigurationMember configMember; @@ -89,6 +90,8 @@ namespace OpenSim.Framework "Known good region X", "1000", false); configMember.addConfigurationOption("default_Y", ConfigurationOption.ConfigurationTypes.TYPE_UINT32, "Known good region Y", "1000", false); + configMember.addConfigurationOption("rex_mode", ConfigurationOption.ConfigurationTypes.TYPE_BOOLEAN, + "Run in realXtend mode? true/false", "false", false); } public bool handleIncomingConfiguration(string configuration_key, object configuration_result) @@ -125,6 +128,9 @@ namespace OpenSim.Framework case "default_Y": DefaultY = (uint) configuration_result; break; + case "rex_mode": + RexMode = (bool)configuration_result; + break; } return true; diff --git a/OpenSim/Framework/UserProfileData.cs b/OpenSim/Framework/UserProfileData.cs index de44a0d3ef..86c3510207 100644 --- a/OpenSim/Framework/UserProfileData.cs +++ b/OpenSim/Framework/UserProfileData.cs @@ -147,6 +147,12 @@ namespace OpenSim.Framework /// The users last registered agent (filled in on the user server) /// public UserAgentData currentAgent; + + /// + /// Authentication address (used in rex mode) + /// + public string authenticationAddr; + } /// diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 0f413800ef..4611cd961f 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -39,6 +39,39 @@ using Nini.Config; namespace OpenSim.Framework { + // rex, new class + // Adds a way to get to the main ini file settings from anywhere + public sealed class GlobalSettings + { + private static volatile GlobalSettings instance; + private static object syncRoot = new Object(); + + public IniConfigSource ConfigSource; + + public bool m_3d_collision_models = false; + + public static GlobalSettings Instance + { + get + { + if (instance == null) + { + lock (syncRoot) + { + if (instance == null) + instance = new GlobalSettings(); + } + } + return instance; + } + } + + public GlobalSettings() + { } + } + // rex, end class + + public class Util { private static Random randomClass = new Random(); diff --git a/OpenSim/Grid/ScriptServer/RemotingObject.cs b/OpenSim/Grid/ScriptServer/RemotingObject.cs index 54aff7af8f..915d0207ee 100644 --- a/OpenSim/Grid/ScriptServer/RemotingObject.cs +++ b/OpenSim/Grid/ScriptServer/RemotingObject.cs @@ -10,10 +10,18 @@ namespace OpenSim.Grid.ScriptServer { // This object will be exposed over remoting. It is a singleton, so it exists only in as one instance. + // Expose ScriptEngine directly for now ... this is not very secure :) + // NOTE! CURRENTLY JUST HARDWIRED DOTNETENGINE! + //private OpenSim.Region.ScriptEngine.DotNetEngine.ScriptEngine SE = + // new OpenSim.Region.ScriptEngine.DotNetEngine.ScriptEngine(); + //public OpenSim.Region.ScriptEngine.Common.ScriptServerInterfaces.RemoteEvents Events = + // (OpenSim.Region.ScriptEngine.Common.ScriptServerInterfaces.RemoteEvents)SE.m_EventManager; + + //private ScriptServerInterfaces.RemoteEvents _events = new abc; ScriptServerInterfaces.RemoteEvents ScriptServerInterfaces.ServerRemotingObject.Events() { - return ScriptServerMain.Engine.EventManager(); + return null; } } } diff --git a/OpenSim/Grid/ScriptServer/RemotingServer.cs b/OpenSim/Grid/ScriptServer/RemotingServer.cs index eb29740444..33d8dc884e 100644 --- a/OpenSim/Grid/ScriptServer/RemotingServer.cs +++ b/OpenSim/Grid/ScriptServer/RemotingServer.cs @@ -4,18 +4,17 @@ using System.Text; using System.Runtime.Remoting; using System.Runtime.Remoting.Channels; using System.Runtime.Remoting.Channels.Tcp; -using OpenSim.Region.ScriptEngine.Common; namespace OpenSim.Grid.ScriptServer { class RemotingServer { - TcpChannel channel; - public RemotingServer(int port, string instanceName) + + public void CreateServer(int port, string instanceName) { // Create an instance of a channel - channel = new TcpChannel(port); + TcpChannel channel = new TcpChannel(port); ChannelServices.RegisterChannel(channel, true); // Register as an available service with the name HelloWorld diff --git a/OpenSim/Grid/ScriptServer/ScriptServer/ScriptEngineManager/ScriptEngineInterface.cs b/OpenSim/Grid/ScriptServer/ScriptServer/ScriptEngineManager/ScriptEngineInterface.cs new file mode 100644 index 0000000000..3a9714d927 --- /dev/null +++ b/OpenSim/Grid/ScriptServer/ScriptServer/ScriptEngineManager/ScriptEngineInterface.cs @@ -0,0 +1,38 @@ +/* +* 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 OpenSim.Framework.Console; + +namespace OpenSim.Grid.ScriptServer +{ + public interface ScriptEngineInterface + { + void InitializeEngine(RegionConnectionManager Region, LogBase logger); + void Shutdown(); +// void StartScript(string ScriptID, IScriptHost ObjectID); + } +} \ No newline at end of file diff --git a/OpenSim/Grid/ScriptServer/ScriptServer/ScriptEngineManager/ScriptEngineLoader.cs b/OpenSim/Grid/ScriptServer/ScriptServer/ScriptEngineManager/ScriptEngineLoader.cs new file mode 100644 index 0000000000..8eb455a7c7 --- /dev/null +++ b/OpenSim/Grid/ScriptServer/ScriptServer/ScriptEngineManager/ScriptEngineLoader.cs @@ -0,0 +1,124 @@ +/* +* 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.IO; +using System.Reflection; +using OpenSim.Framework.Console; + +namespace OpenSim.Grid.ScriptServer +{ + internal class ScriptEngineLoader + { + private LogBase m_log; + + + public ScriptEngineLoader(LogBase logger) + { + m_log = logger; + } + + public ScriptEngineInterface LoadScriptEngine(string EngineName) + { + ScriptEngineInterface ret = null; + try + { + ret = + LoadAndInitAssembly( + Path.Combine("ScriptEngines", "OpenSim.Region.ScriptEngine." + EngineName + ".dll"), + "OpenSim.Region.ScriptEngine." + EngineName + ".ScriptEngine"); + } + catch (Exception e) + { + m_log.Error("ScriptEngine", + "Error loading assembly \"" + EngineName + "\": " + e.Message + ", " + + e.StackTrace.ToString()); + } + return ret; + } + + /// + /// Does actual loading and initialization of script Assembly + /// + /// AppDomain to load script into + /// FileName of script assembly (.dll) + /// + private ScriptEngineInterface LoadAndInitAssembly(string FileName, string NameSpace) + { + //Common.SendToDebug("Loading ScriptEngine Assembly " + FileName); + // Load .Net Assembly (.dll) + // Initialize and return it + + // TODO: Add error handling + + Assembly a; + //try + //{ + + + // Load to default appdomain (temporary) + a = Assembly.LoadFrom(FileName); + // Load to specified appdomain + // TODO: Insert security + //a = FreeAppDomain.Load(FileName); + //} + //catch (Exception e) + //{ + // m_log.Error("ScriptEngine", "Error loading assembly \"" + FileName + "\": " + e.ToString()); + //} + + + //Console.WriteLine("Loading: " + FileName); + //foreach (Type _t in a.GetTypes()) + //{ + // Console.WriteLine("Type: " + _t.ToString()); + //} + + Type t; + //try + //{ + t = a.GetType(NameSpace, true); + //} + //catch (Exception e) + //{ + // m_log.Error("ScriptEngine", "Error initializing type \"" + NameSpace + "\" from \"" + FileName + "\": " + e.ToString()); + //} + + ScriptEngineInterface ret; + //try + //{ + ret = (ScriptEngineInterface) Activator.CreateInstance(t); + //} + //catch (Exception e) + //{ + // m_log.Error("ScriptEngine", "Error initializing type \"" + NameSpace + "\" from \"" + FileName + "\": " + e.ToString()); + //} + + return ret; + } + } +} \ No newline at end of file diff --git a/OpenSim/Grid/ScriptServer/ScriptServer/ScriptEnginesManager.cs b/OpenSim/Grid/ScriptServer/ScriptServer/ScriptEnginesManager.cs index 3bfca87ab1..7b49127d73 100644 --- a/OpenSim/Grid/ScriptServer/ScriptServer/ScriptEnginesManager.cs +++ b/OpenSim/Grid/ScriptServer/ScriptServer/ScriptEnginesManager.cs @@ -28,15 +28,14 @@ using System.Collections.Generic; using OpenSim.Framework.Console; -using OpenSim.Region.ScriptEngine.Common; -namespace OpenSim.Grid.ScriptServer.ScriptServer +namespace OpenSim.Grid.ScriptServer { internal class ScriptEngineManager { private LogBase m_log; private ScriptEngineLoader ScriptEngineLoader; - private List scriptEngines = new List(); + private List scriptEngines = new List(); private ScriptServerMain m_ScriptServerMain; // Initialize @@ -45,21 +44,23 @@ namespace OpenSim.Grid.ScriptServer.ScriptServer m_ScriptServerMain = scm; m_log = logger; ScriptEngineLoader = new ScriptEngineLoader(m_log); + + // Temp - we should not load during initialize... Loading should be done later. + LoadEngine("DotNetScriptEngine"); } ~ScriptEngineManager() { } - public ScriptServerInterfaces.ScriptEngine LoadEngine(string engineName) + public void LoadEngine(string engineName) { // Load and add to list of ScriptEngines - ScriptServerInterfaces.ScriptEngine sei = ScriptEngineLoader.LoadScriptEngine(engineName); + ScriptEngineInterface sei = ScriptEngineLoader.LoadScriptEngine(engineName); if (sei != null) { scriptEngines.Add(sei); } - return sei; } } } \ No newline at end of file diff --git a/OpenSim/Grid/ScriptServer/ScriptServerMain.cs b/OpenSim/Grid/ScriptServer/ScriptServerMain.cs index 568c12b738..884a09eff6 100644 --- a/OpenSim/Grid/ScriptServer/ScriptServerMain.cs +++ b/OpenSim/Grid/ScriptServer/ScriptServerMain.cs @@ -29,8 +29,6 @@ using System.IO; using OpenSim.Framework; using OpenSim.Framework.Console; -using OpenSim.Grid.ScriptServer.ScriptServer; -using OpenSim.Region.ScriptEngine.Common; namespace OpenSim.Grid.ScriptServer { @@ -43,26 +41,19 @@ namespace OpenSim.Grid.ScriptServer private readonly string m_logFilename = ("region-console.log"); private LogBase m_log; - // TEMP - public static ScriptServerInterfaces.ScriptEngine Engine; - // Objects we use internal RegionCommManager RegionScriptDaemon; // Listen for incoming from region - internal ScriptEngineManager ScriptEngines; // Loads scriptengines + //internal ScriptEngineManager ScriptEngines; // Loads scriptengines internal RemotingServer m_RemotingServer; public ScriptServerMain() { m_log = CreateLog(); - // Set up script engine mananger - ScriptEngines = new ScriptEngineManager(this, m_log); - - // Load DotNetEngine - Engine = ScriptEngines.LoadEngine("DotNetEngine"); - - // Set up server - m_RemotingServer = new RemotingServer(listenPort, "DotNetEngine"); + RegionScriptDaemon = new RegionCommManager(this, m_log); + //ScriptEngines = new ScriptEngineManager(this, m_log); + m_RemotingServer = new RemotingServer(); + m_RemotingServer.CreateServer(listenPort, "DotNetEngine"); System.Console.ReadLine(); } @@ -77,7 +68,7 @@ namespace OpenSim.Grid.ScriptServer Directory.CreateDirectory(Util.logDir()); } - return new LogBase((Path.Combine(Util.logDir(), m_logFilename)), "ScriptServer", this, true); + return new LogBase((Path.Combine(Util.logDir(), m_logFilename)), "Region", this, true); } public void RunCmd(string command, string[] cmdparams) diff --git a/OpenSim/Grid/UserServer/Main.cs b/OpenSim/Grid/UserServer/Main.cs index 02ca385eb3..28e6f531af 100644 --- a/OpenSim/Grid/UserServer/Main.cs +++ b/OpenSim/Grid/UserServer/Main.cs @@ -28,12 +28,14 @@ using System; using System.Collections.Generic; +using System.Collections; using System.IO; using libsecondlife; using OpenSim.Framework; using OpenSim.Framework.Communications.Cache; using OpenSim.Framework.Console; using OpenSim.Framework.Servers; +using Nwc.XmlRpc; namespace OpenSim.Grid.UserServer { @@ -51,6 +53,8 @@ namespace OpenSim.Grid.UserServer private LogBase m_console; private LLUUID m_lastCreatedUser = LLUUID.Random(); + private Boolean m_rexMode; + [STAThread] public static void Main(string[] args) { @@ -94,6 +98,7 @@ namespace OpenSim.Grid.UserServer m_loginService = new UserLoginService( m_userManager, new LibraryRootFolder(), Cfg, Cfg.DefaultStartupMsg); + m_rexMode = Cfg.RexMode; m_messagesService = new MessageServersConnector(MainLog.Instance); @@ -106,19 +111,34 @@ namespace OpenSim.Grid.UserServer httpServer.SetLLSDHandler(m_loginService.LLSDLoginMethod); - httpServer.AddXmlRPCHandler("get_user_by_name", m_userManager.XmlRPCGetUserMethodName); - httpServer.AddXmlRPCHandler("get_user_by_uuid", m_userManager.XmlRPCGetUserMethodUUID); - httpServer.AddXmlRPCHandler("get_avatar_picker_avatar", m_userManager.XmlRPCGetAvatarPickerAvatar); - httpServer.AddXmlRPCHandler("add_new_user_friend", m_userManager.XmlRpcResponseXmlRPCAddUserFriend); - httpServer.AddXmlRPCHandler("remove_user_friend", m_userManager.XmlRpcResponseXmlRPCRemoveUserFriend); - httpServer.AddXmlRPCHandler("update_user_friend_perms", m_userManager.XmlRpcResponseXmlRPCUpdateUserFriendPerms); - httpServer.AddXmlRPCHandler("get_user_friend_list", m_userManager.XmlRpcResponseXmlRPCGetUserFriendList); - - // Message Server ---> User Server - httpServer.AddXmlRPCHandler("register_messageserver", m_messagesService.XmlRPCRegisterMessageServer); - httpServer.AddXmlRPCHandler("agent_change_region", m_messagesService.XmlRPCUserMovedtoRegion); - httpServer.AddXmlRPCHandler("deregister_messageserver", m_messagesService.XmlRPCDeRegisterMessageServer); + if (!m_rexMode) { + httpServer.AddXmlRPCHandler("get_user_by_name", m_userManager.XmlRPCGetUserMethodName); + httpServer.AddXmlRPCHandler("get_user_by_uuid", m_userManager.XmlRPCGetUserMethodUUID); + httpServer.AddXmlRPCHandler("get_avatar_picker_avatar", m_userManager.XmlRPCGetAvatarPickerAvatar); + httpServer.AddXmlRPCHandler("add_new_user_friend", m_userManager.XmlRpcResponseXmlRPCAddUserFriend); + httpServer.AddXmlRPCHandler("remove_user_friend", m_userManager.XmlRpcResponseXmlRPCRemoveUserFriend); + httpServer.AddXmlRPCHandler("update_user_friend_perms", m_userManager.XmlRpcResponseXmlRPCUpdateUserFriendPerms); + httpServer.AddXmlRPCHandler("get_user_friend_list", m_userManager.XmlRpcResponseXmlRPCGetUserFriendList); + // Message Server ---> User Server + httpServer.AddXmlRPCHandler("register_messageserver", m_messagesService.XmlRPCRegisterMessageServer); + httpServer.AddXmlRPCHandler("agent_change_region", m_messagesService.XmlRPCUserMovedtoRegion); + httpServer.AddXmlRPCHandler("deregister_messageserver", m_messagesService.XmlRPCDeRegisterMessageServer); + } + else { + httpServer.AddXmlRPCHandler("get_user_by_name", new RexRemoteHandler("get_user_by_name").rexRemoteXmlRPCHandler); + httpServer.AddXmlRPCHandler("get_user_by_uuid", new RexRemoteHandler("get_user_by_uuid").rexRemoteXmlRPCHandler); + httpServer.AddXmlRPCHandler("get_avatar_picker_avatar", new RexRemoteHandler("get_avatar_picker_avatar").rexRemoteXmlRPCHandler); + httpServer.AddXmlRPCHandler("add_new_user_friend", new RexRemoteHandler("add_new_user_friend").rexRemoteXmlRPCHandler); + httpServer.AddXmlRPCHandler("remove_user_friend", new RexRemoteHandler("remove_user_friend").rexRemoteXmlRPCHandler); + httpServer.AddXmlRPCHandler("update_user_friend_perms", new RexRemoteHandler("update_user_friend_perms").rexRemoteXmlRPCHandler); + httpServer.AddXmlRPCHandler("get_user_friend_list", new RexRemoteHandler("get_user_friend_list").rexRemoteXmlRPCHandler); + + // Message Server ---> User Server + httpServer.AddXmlRPCHandler("register_messageserver", new RexRemoteHandler("register_messageserver").rexRemoteXmlRPCHandler); + httpServer.AddXmlRPCHandler("agent_change_region", new RexRemoteHandler("agent_change_region").rexRemoteXmlRPCHandler); + httpServer.AddXmlRPCHandler("deregister_messageserver", new RexRemoteHandler("deregister_messageserver").rexRemoteXmlRPCHandler); + } httpServer.AddStreamHandler( new RestStreamHandler("DELETE", "/usersessions/", m_userManager.RestDeleteUserSessionMethod)); @@ -241,4 +261,55 @@ namespace OpenSim.Grid.UserServer { } } + + /// + /// for forwarding some requests to authentication server + /// + class RexRemoteHandler + { + private string methodName; + + public RexRemoteHandler(String method) + { + methodName = method; + } + + public XmlRpcResponse rexRemoteXmlRPCHandler(XmlRpcRequest request) + { + Hashtable requestData = (Hashtable)request.Params[0]; + string authAddr; + if (requestData.Contains("AuthenticationAddress") && requestData["AuthenticationAddress"] != null) + { + authAddr = (string)requestData["AuthenticationAddress"]; + } + else + { + return CreateErrorResponse("unknown_authentication", + "Request did not contain authentication address"); + } + + ArrayList SendParams = new ArrayList(); + foreach (Object obj in request.Params) + { + SendParams.Add(obj); + } + XmlRpcRequest req = new XmlRpcRequest(methodName, SendParams); + if(!authAddr.StartsWith("http://")) + authAddr = "http://"+ authAddr; + XmlRpcResponse res = req.Send(authAddr, 30000); + return res; + } + + public XmlRpcResponse CreateErrorResponse(string type, string desc) + { + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + responseData["error_type"] = type; + responseData["error_desc"] = desc; + + response.Value = responseData; + return response; + } + } + } diff --git a/OpenSim/Grid/UserServer/UserLoginService.cs b/OpenSim/Grid/UserServer/UserLoginService.cs index 98d19f7fe1..b09a831a15 100644 --- a/OpenSim/Grid/UserServer/UserLoginService.cs +++ b/OpenSim/Grid/UserServer/UserLoginService.cs @@ -54,7 +54,7 @@ namespace OpenSim.Grid.UserServer public UserLoginService( UserManagerBase userManager, LibraryRootFolder libraryRootFolder, UserConfig config, string welcomeMess) - : base(userManager, libraryRootFolder, welcomeMess) + : base(userManager, libraryRootFolder, welcomeMess, config.RexMode) { m_config = config; } @@ -64,7 +64,7 @@ namespace OpenSim.Grid.UserServer /// /// The existing response /// The user profile - public override void CustomiseResponse(LoginResponse response, UserProfileData theUser) + public override void CustomiseResponse(LoginResponse response, UserProfileData theUser, string ASaddress) { bool tryDefault = false; //CFK: Since the try is always "tried", the "Home Location" message should always appear, so comment this one. @@ -119,6 +119,12 @@ namespace OpenSim.Grid.UserServer SimParams["startpos_z"] = theUser.currentAgent.currentPos.Z.ToString(); SimParams["regionhandle"] = theUser.currentAgent.currentHandle.ToString(); SimParams["caps_path"] = capsPath; + if (m_rexMode) + { + SimParams["auth_addr"] = theUser.authenticationAddr; + SimParams["as_addr"] = ASaddress; + } + ArrayList SendParams = new ArrayList(); SendParams.Add(SimParams); @@ -196,6 +202,12 @@ namespace OpenSim.Grid.UserServer SimParams["startpos_z"] = theUser.currentAgent.currentPos.Z.ToString(); SimParams["regionhandle"] = theUser.currentAgent.currentHandle.ToString(); SimParams["caps_path"] = capsPath; + if (m_rexMode) + { + SimParams["auth_addr"] = theUser.authenticationAddr; + SimParams["as_addr"] = ASaddress; + } + ArrayList SendParams = new ArrayList(); SendParams.Add(SimParams); diff --git a/OpenSim/Grid/UserServer/UserManager.cs b/OpenSim/Grid/UserServer/UserManager.cs index 03b1fbc242..82997192f5 100644 --- a/OpenSim/Grid/UserServer/UserManager.cs +++ b/OpenSim/Grid/UserServer/UserManager.cs @@ -263,7 +263,7 @@ namespace OpenSim.Grid.UserServer if (querysplit.Length == 2) { - userProfile = GetUserProfile(querysplit[0], querysplit[1]); + userProfile = GetUserProfile(querysplit[0], querysplit[1], ""); if (userProfile == null) { return CreateUnknownUserErrorResponse(); @@ -291,17 +291,28 @@ namespace OpenSim.Grid.UserServer //CFK: Console.WriteLine("METHOD BY UUID CALLED"); if (requestData.Contains("avatar_uuid")) { + LLUUID guess = new LLUUID(); try { - guess = new LLUUID((string) requestData["avatar_uuid"]); - - userProfile = GetUserProfile(guess); + guess = new LLUUID((string)requestData["avatar_uuid"]); + //userProfile = GetUserProfile(guess); + string authAddr; + if (requestData["AuthenticationAddress"] == null) + authAddr = ""; + else + authAddr = requestData["AuthenticationAddress"].ToString(); + userProfile = GetUserProfile(guess, authAddr); } catch (FormatException) { return CreateUnknownUserErrorResponse(); } + catch (NullReferenceException) + { + Console.WriteLine("NullReferenceException occured"); + return CreateUnknownUserErrorResponse(); + } if (userProfile == null) { diff --git a/OpenSim/Region/Application/OpenSimMain.cs b/OpenSim/Region/Application/OpenSimMain.cs index c653192340..1bf681a8a9 100644 --- a/OpenSim/Region/Application/OpenSimMain.cs +++ b/OpenSim/Region/Application/OpenSimMain.cs @@ -93,6 +93,8 @@ namespace OpenSim public ConsoleCommand CreateAccount = null; private bool m_dumpAssetsToFile; + private bool m_rexMode = false; //rex + private List m_plugins = new List(); private IniConfigSource m_config; @@ -153,6 +155,9 @@ namespace OpenSim } ReadConfigSettings(); + // rex, added globalconfig for easy access to config values outside OpenSimMain without using parameters. + GlobalSettings.Instance.ConfigSource = m_config; + GlobalSettings.Instance.m_3d_collision_models = m_config.Configs["Startup"].GetBoolean("3d_collision_models", true); // endrex } public static IConfigSource DefaultConfig() @@ -175,6 +180,10 @@ namespace OpenSim config.Set("shutdown_console_commands_file", ""); config.Set("script_engine", "OpenSim.Region.ScriptEngine.DotNetEngine.dll"); config.Set("asset_database", "sqlite"); + config.Set("worldlibraryfolder", true); // rex, added + config.Set("replace_assets", true); // rex, added + config.Set("rex_mode", false); //rex + config.Set("3d_collision_models", true); //rex } if (DefaultConfig.Configs["StandAlone"] == null) @@ -251,6 +260,7 @@ namespace OpenSim m_assetStorage = startupConfig.GetString("asset_database", "sqlite"); m_timedScript = startupConfig.GetString("timer_Script", "disabled"); + m_rexMode = startupConfig.GetBoolean("rex_mode", false);//rex } IConfig standaloneConfig = m_config.Configs["StandAlone"]; @@ -320,10 +330,11 @@ namespace OpenSim m_loginService = new LocalLoginService(userService, m_standaloneWelcomeMessage, localComms, m_networkServersInfo, - m_standaloneAuthenticate); + m_standaloneAuthenticate, m_rexMode); m_loginService.OnLoginToRegion += backendService.AddNewSession; m_httpServer.AddXmlRPCHandler("login_to_simulator", m_loginService.XmlRpcLoginMethod); + m_httpServer.SetLLSDHandler(m_loginService.LLSDLoginMethod); if (m_standaloneAuthenticate) @@ -432,7 +443,9 @@ namespace OpenSim //m_moduleLoader.PickupModules(scene, "ScriptEngines"); //m_moduleLoader.LoadRegionModules(Path.Combine("ScriptEngines", m_scriptEngine), scene); MainLog.Instance.Verbose("MODULES", "Loading scripting engine modules"); - m_moduleLoader.LoadRegionModules(Path.Combine("ScriptEngines", m_scriptEngine), scene); + m_moduleLoader.LoadRegionModules(Path.Combine("ScriptEngines", m_scriptEngine), scene); + + m_moduleLoader.LoadRegionModules(Path.Combine("ScriptEngines", "OpenSim.Region.RexScriptModule.dll"), scene); // rex m_moduleLoader.InitialiseSharedModules(scene); scene.SetModuleInterfaces(); @@ -476,7 +489,8 @@ namespace OpenSim return new Scene(regionInfo, circuitManager, permissionManager, m_commsManager, sceneGridService, m_assetCache, storageManager, m_httpServer, - m_moduleLoader, m_dumpAssetsToFile, m_physicalPrim, m_SendChildAgentTaskData); + m_moduleLoader, m_dumpAssetsToFile, m_physicalPrim, m_SendChildAgentTaskData, + m_rexMode); } @@ -682,6 +696,7 @@ namespace OpenSim m_log.Error("show uptime - show simulator startup and uptime."); m_log.Error("show users - show info about connected users."); m_log.Error("show modules - shows info aboutloaded modules."); + m_log.Error("status - show status window"); //rex m_log.Error("shutdown - disconnect all clients and shutdown."); m_log.Error("terrain help - show help for terrain commands."); break; @@ -863,6 +878,22 @@ namespace OpenSim } break; + // rex, new console command. + case "save-db": + MainLog.Instance.Verbose("COMMANDFILE", "Forced database save started..."); + m_sceneManager.ForcedBackupCurrentScene(); + MainLog.Instance.Verbose("COMMANDFILE", "Forced database save ended..."); + break; + // rex, new console command. + case "python": + m_sceneManager.SendPythonScriptCommand(cmdparams); + break; + + //rex + case "status": + OpenSim.Framework.ServerStatus.ServerStatus.ShowWindow(); + break; + default: m_log.Error("Unknown command"); break; diff --git a/OpenSim/Region/ClientStack/ClientView.cs b/OpenSim/Region/ClientStack/ClientView.cs index 23160cd957..bfcb884827 100644 --- a/OpenSim/Region/ClientStack/ClientView.cs +++ b/OpenSim/Region/ClientStack/ClientView.cs @@ -55,6 +55,7 @@ namespace OpenSim.Region.ClientStack public static TerrainManager TerrainManager; /* private variables */ + private bool m_running = true; private readonly LLUUID m_sessionId; private LLUUID m_secureSessionId = LLUUID.Zero; //private AgentAssetUpload UploadAssets; @@ -73,6 +74,12 @@ namespace OpenSim.Region.ClientStack private readonly uint m_circuitCode; private int m_moneyBalance; + private string m_clientVersion = "not set"; //rex + private bool m_rexClient = false; //rex + + //Rex: Used to identify which materials have already been processed for mediaurl + private Dictionary m_sentMediaUrls; + private readonly byte[] m_channelVersion = new byte[] { 0x00 }; // Dummy value needed by libSL /* protected variables */ @@ -85,7 +92,7 @@ namespace OpenSim.Region.ClientStack protected IScene m_scene; protected AgentCircuitManager m_authenticateSessionsHandler; - protected PacketQueue m_packetQueue; + protected RexPacketQueue m_packetQueue; protected Dictionary m_pendingAcks = new Dictionary(); protected Dictionary m_needAck = new Dictionary(); @@ -182,6 +189,8 @@ namespace OpenSim.Region.ClientStack { m_moneyBalance = 1000; + m_sentMediaUrls = new Dictionary(); //rex + m_scene = scene; m_assetCache = assetCache; @@ -189,8 +198,6 @@ namespace OpenSim.Region.ClientStack // m_inventoryCache = inventoryCache; m_authenticateSessionsHandler = authenSessions; - MainLog.Instance.Verbose("CLIENT", "Started up new client thread to handle incoming request"); - m_agentId = agentId; m_sessionId = sessionId; m_circuitCode = circuitCode; @@ -204,7 +211,21 @@ namespace OpenSim.Region.ClientStack // in it to process. It's an on-purpose threadlock though because // without it, the clientloop will suck up all sim resources. - m_packetQueue = new PacketQueue(); + //REX: Get options from ini, otherwise run on LAN bandwidth settings + if (GlobalSettings.Instance.ConfigSource.Configs["Startup"].Contains("bandwidth_start") && + GlobalSettings.Instance.ConfigSource.Configs["Startup"].Contains("bandwidth_max") && + GlobalSettings.Instance.ConfigSource.Configs["Startup"].Contains("bandwidth_min")) + { + m_packetQueue = new RexPacketQueue( + GlobalSettings.Instance.ConfigSource.Configs["Network"].GetInt("bandwidth_start"), + GlobalSettings.Instance.ConfigSource.Configs["Network"].GetInt("bandwidth_max"), + GlobalSettings.Instance.ConfigSource.Configs["Network"].GetInt("bandwidth_min")); + } + else + { + //Default to very large values (LAN) + m_packetQueue = new RexPacketQueue(10000000, 10000000, 100000); + } RegisterLocalPacketHandlers(); @@ -222,7 +243,17 @@ namespace OpenSim.Region.ClientStack private void CloseCleanup() { - m_scene.RemoveClient(AgentId); + + if (!m_scene.RexMode) + { + m_scene.RemoveClient(AgentId); + } + else + { + m_scene.RemoveClient(AgentId, m_circuitCode); + } + //m_scene.RemoveClient(AgentId); + // Send the STOP packet DisableSimulatorPacket disable = (DisableSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.DisableSimulator); OutPacket(disable, ThrottleOutPacketType.Task); @@ -368,9 +399,65 @@ namespace OpenSim.Region.ClientStack } } + protected void SendSkyboxInformation() + { + RexSkyboxInfoPacket packet = new RexSkyboxInfoPacket(); + + string skyboxFront = GlobalSettings.Instance.ConfigSource.Configs["Startup"]. + GetString("skybox_front", "00000000-0000-0000-0000-000000000000"); + string skyboxBack = GlobalSettings.Instance.ConfigSource.Configs["Startup"]. + GetString("skybox_back", "00000000-0000-0000-0000-000000000000"); + string skyboxLeft = GlobalSettings.Instance.ConfigSource.Configs["Startup"]. + GetString("skybox_left", "00000000-0000-0000-0000-000000000000"); + string skyboxRight = GlobalSettings.Instance.ConfigSource.Configs["Startup"]. + GetString("skybox_right", "00000000-0000-0000-0000-000000000000"); + string skyboxTop = GlobalSettings.Instance.ConfigSource.Configs["Startup"]. + GetString("skybox_top", "00000000-0000-0000-0000-000000000000"); + string skyboxBottom = GlobalSettings.Instance.ConfigSource.Configs["Startup"]. + GetString("skybox_bottom", "00000000-0000-0000-0000-000000000000"); + + + //Make sure the skybox textures are actually all set before sending the packet + if (skyboxFront == "00000000-0000-0000-0000-000000000000" || + skyboxBack == "00000000-0000-0000-0000-000000000000" || + skyboxLeft == "00000000-0000-0000-0000-000000000000" || + skyboxRight == "00000000-0000-0000-0000-000000000000" || + skyboxTop == "00000000-0000-0000-0000-000000000000" || + skyboxBottom == "00000000-0000-0000-0000-000000000000") + { + //No textures set, don't send + MainLog.Instance.Warn("CLIENT", "Some of the skybox textures were not set"); + return; + } + MainLog.Instance.Verbose("CLIENT", "REX: Sending skybox data"); + + packet.Textures.FrontTextureID = new LLUUID(skyboxFront); + packet.Textures.BackTextureID = new LLUUID(skyboxBack); + packet.Textures.LeftTextureID = new LLUUID(skyboxLeft); + packet.Textures.RightTextureID = new LLUUID(skyboxRight); + packet.Textures.TopTextureID = new LLUUID(skyboxTop); + packet.Textures.BottomTextureID = new LLUUID(skyboxBottom); + packet.Header.Reliable = true; + + OutPacket(packet, ThrottleOutPacketType.Asset); + } + + protected void SendRexInformation() + { + MainLog.Instance.Verbose("CLIENT", "REX: Sending rexregion information"); + SendSkyboxInformation(); + } + protected virtual void ClientLoop() { MainLog.Instance.Verbose("CLIENT", "Entered loop"); + + //REX: Send all rexregion related information + if (m_rexClient) + { + SendRexInformation(); + } + while (true) { QueItem nextPacket = m_packetQueue.Dequeue(); @@ -434,7 +521,13 @@ namespace OpenSim.Region.ClientStack m_clientPingTimer.Elapsed += new ElapsedEventHandler(CheckClientConnectivity); m_clientPingTimer.Enabled = true; - MainLog.Instance.Verbose("CLIENT", "Adding viewer agent to scene"); + MainLog.Instance.Verbose("CLIENT", "Adding viewer agent to scene (version: " + m_clientVersion + ")"); + + if (m_clientVersion != null && m_clientVersion.Contains("realXtend")) + { + m_rexClient = true; + } + m_scene.AddNewClient(this, true); } @@ -462,6 +555,9 @@ namespace OpenSim.Region.ClientStack { m_secureSessionId = sessionInfo.LoginInfo.SecureSession; } + + m_clientVersion = sessionInfo.LoginInfo.ClientVersion; //rex + // This sets up all the timers InitNewClient(); @@ -540,6 +636,7 @@ namespace OpenSim.Region.ClientStack public event UpdateInventoryItem OnUpdateInventoryItem; public event CopyInventoryItem OnCopyInventoryItem; public event MoveInventoryItem OnMoveInventoryItem; + public event RemoveInventoryItem OnRemoveInventoryItem; // rex public event UDPAssetUploadRequest OnAssetUploadRequest; public event XferReceive OnXferReceive; public event RequestXfer OnRequestXfer; @@ -548,6 +645,11 @@ namespace OpenSim.Region.ClientStack public event UpdateTaskInventory OnUpdateTaskInventory; public event RemoveTaskInventory OnRemoveTaskItem; + //REX: Attachments + public event RezSingleAttachmentFromInv OnRezSingleAttachmentFromInv; + public event ObjectAttach OnObjectAttach; + public event ObjectDetach OnObjectDetach; + public event UUIDNameRequest OnNameFromUUIDRequest; public event ParcelAccessListRequest OnParcelAccessListRequest; @@ -566,6 +668,11 @@ namespace OpenSim.Region.ClientStack public event FriendActionDelegate OnDenyFriendRequest; public event FriendshipTermination OnTerminateFriendship; + public event ReceiveRexClientScriptCmd OnReceiveRexClientScriptCmd; // rex + public event ObjectClickAction OnObjectClickAction; // rex + public event UpdateAssetMediaURL OnUpdateAssetMediaURL; // rex + public event TriggerSound OnTriggerSound; + #region Scene/Avatar to Client /// @@ -981,6 +1088,13 @@ namespace OpenSim.Region.ClientStack i = 0; foreach (InventoryItemBase item in items) { + //REX: Send also media url for the item if it has a one + if (!m_sentMediaUrls.ContainsKey(item.assetID)) + { + //Start a request for material + m_assetCache.GetAsset(item.assetID, MediaURLAssetRequest); + } + descend.ItemData[i] = new InventoryDescendentsPacket.ItemDataBlock(); descend.ItemData[i].ItemID = item.inventoryID; descend.ItemData[i].AssetID = item.assetID; @@ -1276,6 +1390,25 @@ namespace OpenSim.Region.ClientStack OutPacket(loadURL, ThrottleOutPacketType.Task); } + public void SendDialog(string objectname, LLUUID objectID, LLUUID ownerID, string msg, LLUUID textureID, int ch, string[] buttonlabels) + { + ScriptDialogPacket dialog = (ScriptDialogPacket)PacketPool.Instance.GetPacket(PacketType.ScriptDialog); + dialog.Data.ObjectID = objectID; + dialog.Data.ObjectName = Helpers.StringToField(objectname); + dialog.Data.FirstName = Helpers.StringToField(this.FirstName); + dialog.Data.LastName = Helpers.StringToField(this.LastName); + dialog.Data.Message = Helpers.StringToField(msg); + dialog.Data.ImageID = textureID; + dialog.Data.ChatChannel = ch; + ScriptDialogPacket.ButtonsBlock[] buttons = new ScriptDialogPacket.ButtonsBlock[buttonlabels.Length]; + for (int i = 0; i < buttonlabels.Length; i++) + { + buttons[i] = new ScriptDialogPacket.ButtonsBlock(); + buttons[i].ButtonLabel = Helpers.StringToField(buttonlabels[i]); + } + dialog.Buttons = buttons; + OutPacket(dialog, ThrottleOutPacketType.Task); + } public void SendPreLoadSound(LLUUID objectID, LLUUID ownerID, LLUUID soundID) { @@ -1301,6 +1434,20 @@ namespace OpenSim.Region.ClientStack OutPacket(sound, ThrottleOutPacketType.Task); } + public void SendTriggeredSound(LLUUID soundID, LLUUID ownerID, LLUUID objectID, LLUUID parentID, ulong handle, LLVector3 position, float gain) + { + SoundTriggerPacket sound = (SoundTriggerPacket)PacketPool.Instance.GetPacket(PacketType.SoundTrigger); + sound.SoundData.SoundID = soundID; + sound.SoundData.OwnerID = ownerID; + sound.SoundData.ObjectID = objectID; + sound.SoundData.ParentID = parentID; + sound.SoundData.Handle = handle; + sound.SoundData.Position = position; + sound.SoundData.Gain = gain; + + OutPacket(sound, ThrottleOutPacketType.Task); + } + public void SendSunPos(LLVector3 sunPos, LLVector3 sunVel) { SimulatorViewerTimeMessagePacket viewertime = (SimulatorViewerTimeMessagePacket)PacketPool.Instance.GetPacket(PacketType.SimulatorViewerTimeMessage); @@ -1377,6 +1524,17 @@ namespace OpenSim.Region.ClientStack OutPacket(avatarReply, ThrottleOutPacketType.Task); } + //rex + public void SendScriptTeleportRequest(string objectName, string simName, LLVector3 simPosition, LLVector3 lookAt) + { + ScriptTeleportRequestPacket teleportRequest = (ScriptTeleportRequestPacket)PacketPool.Instance.GetPacket(PacketType.ScriptTeleportRequest); + teleportRequest.Data.ObjectName = Helpers.StringToField(objectName); + teleportRequest.Data.SimName = Helpers.StringToField(simName); + teleportRequest.Data.SimPosition = simPosition; + teleportRequest.Data.LookAt = lookAt; + OutPacket(teleportRequest, ThrottleOutPacketType.Task); + } + #endregion #region Appearance/ Wearables Methods @@ -1433,6 +1591,23 @@ namespace OpenSim.Region.ClientStack OutPacket(avp, ThrottleOutPacketType.Task); } + /// + /// Used in rex mode instead of SendAppearance for sending appearance storage address + /// + /// + /// + public void SendRexAppearance(LLUUID agentID, string avatarAddress) //rex + { + GenericMessagePacket gmp = new GenericMessagePacket(); + gmp.MethodData.Method = Helpers.StringToField("RexAppearance"); + gmp.ParamList = new GenericMessagePacket.ParamListBlock[2]; + gmp.ParamList[0] = new GenericMessagePacket.ParamListBlock(); + gmp.ParamList[0].Parameter = Helpers.StringToField(avatarAddress); + gmp.ParamList[1] = new GenericMessagePacket.ParamListBlock(); + gmp.ParamList[1].Parameter = Helpers.StringToField(agentID.ToString()); + OutPacket(gmp, ThrottleOutPacketType.Task); + } + public void SendAnimations(LLUUID[] animations, int[] seqs, LLUUID sourceAgentId) { AvatarAnimationPacket ani = (AvatarAnimationPacket)PacketPool.Instance.GetPacket(PacketType.AvatarAnimation); @@ -1595,10 +1770,70 @@ namespace OpenSim.Region.ClientStack byte[] rot = rotation.GetBytes(); Array.Copy(rot, 0, outPacket.ObjectData[0].ObjectData, 36, rot.Length); + + //REX: Check if the material has media url and send it if necessary + try + { + if (m_rexClient && primShape.TextureEntry != null) + { + LLObject.TextureEntry tex = new LLObject.TextureEntry(primShape.TextureEntry, 0, primShape.TextureEntry.Length); + foreach (LLObject.TextureEntryFace face in tex.FaceTextures) + { + if (face != null && face.TextureID != null) + { + if (!m_sentMediaUrls.ContainsKey(face.TextureID)) + { + //Start a request for material + m_assetCache.GetAsset(face.TextureID, MediaURLAssetRequest); + } + } + } + } + } + catch (IndexOutOfRangeException) + { + // If primShape.TextureEntry length is 44, throws exception. Bug in libsl or Opensim? + MainLog.Instance.Warn("CLIENT", "Error processing " + objectID + " texture data"); + } OutPacket(outPacket, ThrottleOutPacketType.Task); } + //REX + public void MediaURLAssetRequest(LLUUID assetID, AssetBase asset) + { + if (asset != null) + { + if (asset.MediaURL != String.Empty) + { + SendMediaURL(assetID, asset.MediaURL); + } + else + { + //Media url not set, just set empty string to avoid further queries + m_sentMediaUrls[assetID] = string.Empty; + } + } + else + { + MainLog.Instance.Warn("CLIENT", "Could not get asset: " + assetID); + } + } + + //REX + public void SendMediaURL(LLUUID assetID, string mediaURL) + { + if (m_rexClient && (!m_sentMediaUrls.ContainsKey(assetID) || m_sentMediaUrls[assetID] != mediaURL)) + { + RexImageInfoPacket rexImgInfoPacket = new RexImageInfoPacket(); + rexImgInfoPacket.Header.Reliable = true; + rexImgInfoPacket.ImageInfo.MediaURL = Helpers.StringToField(mediaURL); + rexImgInfoPacket.ImageInfo.ImageID = assetID; + OutPacket(rexImgInfoPacket, ThrottleOutPacketType.Task); + m_sentMediaUrls[assetID] = mediaURL; + } + } + /// /// /// @@ -1635,6 +1870,30 @@ namespace OpenSim.Region.ClientStack OutPacket(terse, ThrottleOutPacketType.Task); } + + // Rex, send script command to client + public void SendRexScriptCommand(string vUnit, string vCommand, string vCmdParams) //rex + { + GenericMessagePacket gmp = new GenericMessagePacket(); + gmp.MethodData.Method = Helpers.StringToField("RexScr"); + + if (vCmdParams.Length > 0) + gmp.ParamList = new GenericMessagePacket.ParamListBlock[3]; + else + gmp.ParamList = new GenericMessagePacket.ParamListBlock[2]; + + gmp.ParamList[0] = new GenericMessagePacket.ParamListBlock(); + gmp.ParamList[0].Parameter = Helpers.StringToField(vUnit); + gmp.ParamList[1] = new GenericMessagePacket.ParamListBlock(); + gmp.ParamList[1].Parameter = Helpers.StringToField(vCommand); + if (vCmdParams.Length > 0) + { + gmp.ParamList[2] = new GenericMessagePacket.ParamListBlock(); + gmp.ParamList[2].Parameter = Helpers.StringToField(vCmdParams); + } + OutPacket(gmp, ThrottleOutPacketType.Task); + } + #endregion #region Helper Methods @@ -2312,10 +2571,16 @@ namespace OpenSim.Region.ClientStack { int packetsize = Helpers.ZeroEncode(sendbuffer, sendbuffer.Length, ZeroOutBuffer); m_networkServer.SendPacketTo(ZeroOutBuffer, packetsize, SocketFlags.None, m_circuitCode); + OpenSim.Framework.ServerStatus.ServerStatus.ReportOutPacketUdp(packetsize, Pack.Header.Resent);//rex + OpenSim.Framework.ServerStatus.ServerStatus. + ReportProcessedOutPacket(Pack.GetType().ToString(), packetsize, Pack.Header.Resent); //rex } else { m_networkServer.SendPacketTo(sendbuffer, sendbuffer.Length, SocketFlags.None, m_circuitCode); + OpenSim.Framework.ServerStatus.ServerStatus.ReportOutPacketUdp(sendbuffer.Length, Pack.Header.Resent);//rex + OpenSim.Framework.ServerStatus.ServerStatus. + ReportProcessedOutPacket(Pack.GetType().ToString(), sendbuffer.Length, Pack.Header.Resent);//rex } } catch (Exception e) @@ -2326,6 +2591,12 @@ namespace OpenSim.Region.ClientStack MainLog.Instance.Error(e.ToString()); Close(true); } + + if (Pack.Header.Resent) + { + //Allow for later resending + Pack.Header.Resent = false; + } } public virtual void InPacket(Packet NewPack) @@ -2421,8 +2692,8 @@ namespace OpenSim.Region.ClientStack { if ((now - packet.TickCount > RESEND_TIMEOUT) && (!packet.Header.Resent)) { - MainLog.Instance.Verbose("NETWORK", "Resending " + packet.Type.ToString() + " packet, " + - (now - packet.TickCount) + "ms have passed"); + /*MainLog.Instance.Verbose("NETWORK", "Resending " + packet.Type.ToString() + " packet, " + + (now - packet.TickCount) + "ms have passed");*/ packet.Header.Resent = true; OutPacket(packet, ThrottleOutPacketType.Resend); @@ -2492,6 +2763,8 @@ namespace OpenSim.Region.ClientStack protected void ProcessInPacket(Packet Pack) { + OpenSim.Framework.ServerStatus.ServerStatus.ReportProcessedInPacket(Pack.GetType().ToString(), Pack.ToBytes().Length); + ack_pack(Pack); if (ProcessPacketMethod(Pack)) @@ -2740,6 +3013,20 @@ namespace OpenSim.Region.ClientStack } break; + // rex, added handling of genericmessage for rexscr method + case PacketType.GenericMessage: + GenericMessagePacket gmpacket = (GenericMessagePacket)Pack; + string sMethod = Helpers.FieldToUTF8String(gmpacket.MethodData.Method); + + if (sMethod == "rexscr" && OnReceiveRexClientScriptCmd != null) + { + List tmplist = new List(); + for (int i=0;i Priorities; + + public PacketPrioritizer() + { + Priorities = new Dictionary(); + + //High priority packets + /*Priorities[PacketType.StartPingCheck] = 60000; + Priorities[PacketType.PacketAck] = 60000;*/ + + //Very low priority packets + Priorities[PacketType.ObjectImage] = 1; + Priorities[PacketType.ImageData] = 1; + Priorities[PacketType.ImagePacket] = 1; + } + + public void Bind(PrioritizedQueue queue) + { + queue.PriorityDeterminer = new PrioritizedQueue.DeterminePriorityDelegate(this.DeterminePriority); + } + + public int DeterminePriority(QueItem item) + { + Packet packet = item.Packet; + if (Priorities.ContainsKey(packet.Type)) + return Priorities[packet.Type]; + + //Default priority is 20 + return 50; + } + } +} diff --git a/OpenSim/Region/ClientStack/RegionApplicationBase.cs b/OpenSim/Region/ClientStack/RegionApplicationBase.cs index e9331e9db8..488b9f0dd8 100644 --- a/OpenSim/Region/ClientStack/RegionApplicationBase.cs +++ b/OpenSim/Region/ClientStack/RegionApplicationBase.cs @@ -37,6 +37,7 @@ using OpenSim.Framework.Servers; using OpenSim.Region.Environment; using OpenSim.Region.Environment.Scenes; using OpenSim.Region.Physics.Manager; +using OpenSim.Region.Communications.VoiceChat; namespace OpenSim.Region.ClientStack { @@ -58,6 +59,8 @@ namespace OpenSim.Region.ClientStack protected StorageManager m_storageManager; protected string m_storageConnectionString; + protected VoiceChatServer m_voiceChatServer; + public SceneManager SceneManager { get { return m_sceneManager; } @@ -108,6 +111,7 @@ namespace OpenSim.Region.ClientStack udpServer = new UDPServer((uint) regionInfo.InternalEndPoint.Port, m_assetCache, m_log, circuitManager); Scene scene = CreateScene(regionInfo, m_storageManager, circuitManager); + m_voiceChatServer = new VoiceChatServer(scene); udpServer.LocalScene = scene; @@ -129,6 +133,7 @@ namespace OpenSim.Region.ClientStack m_commsManager.UserService.SetupMasterUser(scene.RegionInfo.MasterAvatarFirstName, scene.RegionInfo.MasterAvatarLastName, scene.RegionInfo.MasterAvatarSandboxPassword); + } if (masterAvatar != null) diff --git a/OpenSim/Region/ClientStack/RexPacketQueue.cs b/OpenSim/Region/ClientStack/RexPacketQueue.cs new file mode 100644 index 0000000000..ca5f21d26d --- /dev/null +++ b/OpenSim/Region/ClientStack/RexPacketQueue.cs @@ -0,0 +1,206 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using System.Timers; +using Timer = System.Timers.Timer; + +using OpenSim.Framework; +using libsecondlife.Packets; + +namespace OpenSim.Region.ClientStack +{ + public class RexPacketQueue + { + //Object for syncing enqueue / dequeue + private object m_queueSync = new object(); + + LinkedList m_incoming; //Non throttled packets (highpr. and incoming) + LinkedList m_nonThrottled; //Non throttled packets (highpr. and incoming) + PrioritizedQueue m_queue; //Normally prioritized to be sent packets + + PacketPrioritizer m_prioritizer; + Timer m_throttleUpdater; + + const int m_throttleAdjustInterval = 1000; //Adjust throttle every 5 seconds + int m_throttleAdjustTimeLeft = m_throttleAdjustInterval; + + const int m_throttleRefreshRate = 200; //200ms + int m_throttleOutboundMin = (5000 * m_throttleRefreshRate)/1000; //5KB/sec + int m_throttleOutboundMax = (200000 * m_throttleRefreshRate)/1000; //200KB/sec + + + //200KB/sec (attempt to start at full speed) + int m_throttleOutbound = (200000 * m_throttleRefreshRate)/1000; + + int m_sentBytes = 0; //Amount of bytes sent currently + + + int m_resentBytes = 0; //Amount of resent bytes + int m_resendQueued = 0; //Amount of queued resend packets + + public RexPacketQueue(int startTraffic, int maxTraffic, int minTraffic) + { + m_throttleOutboundMin = (minTraffic * m_throttleRefreshRate) / 1000; //5KB/sec + m_throttleOutboundMax = (maxTraffic * m_throttleRefreshRate) / 1000; //200KB/sec + + //200KB/sec (attempt to start at full speed) + m_throttleOutbound = (startTraffic * m_throttleRefreshRate) / 1000; + + m_queue = new PrioritizedQueue(); + m_incoming = new LinkedList(); + m_nonThrottled = new LinkedList(); + m_prioritizer = new PacketPrioritizer(); + m_prioritizer.Bind(m_queue); + + m_throttleUpdater = new Timer(m_throttleRefreshRate); + m_throttleUpdater.Elapsed += new ElapsedEventHandler(ThrottleRefresh); + m_throttleUpdater.Start(); + } + + public void Enqueue(QueItem item) + { + lock (m_queueSync) + { + if (item.throttleType == ThrottleOutPacketType.Resend) + m_resendQueued++; + + if (item.Incoming) + { + m_incoming.AddLast(item); + } + else + { + if (item.Packet.Type == PacketType.ImprovedTerseObjectUpdate || + item.Packet.Type == PacketType.CoarseLocationUpdate || + item.Packet.Type == PacketType.AvatarAnimation || + item.Packet.Type == PacketType.StartPingCheck || + item.Packet.Type == PacketType.CompletePingCheck || + item.Packet.Type == PacketType.PacketAck) + { + m_nonThrottled.AddLast(item); + } + else + { + m_queue.Enqueue(item); + } + if (item.Packet.Header.Resent) + { + m_resentBytes += item.Packet.ToBytes().Length; + } + } + Monitor.Pulse(m_queueSync); + } + } + + public QueItem Dequeue() + { + while (true) + { + lock (m_queueSync) + { + QueItem item = null; + + //Immediately process incoming packets + if (m_incoming.First != null) + { + item = m_incoming.First.Value; + m_incoming.RemoveFirst(); + } + //Then try to pick a super-high-priority packet first + else if (m_nonThrottled.First != null) + { + item = m_nonThrottled.First.Value; + m_nonThrottled.RemoveFirst(); + } + //Then check for other packets + else if (m_sentBytes < m_throttleOutbound && m_queue.HasQueuedItems()) + { + item = m_queue.Dequeue(); + } + + if (item != null) + { + if (!item.Incoming) + { + m_sentBytes += item.Packet.ToBytes().Length; + } + + if (item.throttleType == ThrottleOutPacketType.Resend) + m_resendQueued--; + + return item; + } + + Monitor.Wait(m_queueSync); + } + } + } + + public void Close() + { + m_throttleUpdater.Stop(); + } + + public void Flush() + { + //not implemented + } + + public void SetThrottleFromClient(byte[] data) + { + //not implemented + } + + void ThrottleRefresh(object sender, ElapsedEventArgs e) + { + //Handle throttle adjusting + m_throttleAdjustTimeLeft -= m_throttleRefreshRate; + if (m_throttleAdjustTimeLeft <= 0) + { + AdjustThrottle(); + m_resentBytes = 0; + m_throttleAdjustTimeLeft += m_throttleAdjustInterval; + } + + //Lock to cause wait abort as we can send now more data + lock (m_queueSync) + { + m_sentBytes = 0; + } + } + + void AdjustThrottle() + { + if (m_resentBytes == 0) + { + //Increase out traffic by 5% if we're trying to send data more than current max + if (m_sentBytes >= m_throttleOutbound) + { + m_throttleOutbound = (m_throttleOutbound * 105) / 100; + } + } + else + { + //Determine proper traffic level + int resentPerPeriod = (m_resentBytes * m_throttleRefreshRate) / m_throttleAdjustInterval; + m_throttleOutbound -= resentPerPeriod; + } + + //Limit throttle + if (m_throttleOutbound > m_throttleOutboundMax) + { + m_throttleOutbound = m_throttleOutboundMax; + } + else if (m_throttleOutbound < m_throttleOutboundMin) + { + m_throttleOutbound = m_throttleOutboundMin; + } + } + + private bool IsHighestPriority(PacketType type) + { + return false; + } + } +} diff --git a/OpenSim/Region/ClientStack/UDPServer.cs b/OpenSim/Region/ClientStack/UDPServer.cs index 4e4a0aac93..930b3ab43d 100644 --- a/OpenSim/Region/ClientStack/UDPServer.cs +++ b/OpenSim/Region/ClientStack/UDPServer.cs @@ -107,6 +107,9 @@ namespace OpenSim.Region.ClientStack try { numBytes = Server.EndReceiveFrom(result, ref epSender); + + //Report byte count to rex statuswindow + OpenSim.Framework.ServerStatus.ServerStatus.ReportInPacketUdp(numBytes); } catch (SocketException e) { @@ -272,7 +275,28 @@ namespace OpenSim.Region.ClientStack if (clientCircuits_reverse.TryGetValue(circuitcode, out sendto)) { //we found the endpoint so send the packet to it - Server.SendTo(buffer, size, flags, sendto); + while (true) + { + try + { + Server.SendTo(buffer, size, flags, sendto); + return; + } + catch (SocketException e) + { + if (e.ErrorCode == 10055) + { + //Send buffer full, halt for half second and retry + MainLog.Instance.Warn("SERVER", "Socket send buffer was full, halting for 200ms"); + System.Threading.Thread.Sleep(200); + } + else + { + //Rethrow + throw e; + } + } + } } } diff --git a/OpenSim/Region/Communications/Local/LocalBackEndServices.cs b/OpenSim/Region/Communications/Local/LocalBackEndServices.cs index 4dec8846b2..9ae0dc0f99 100644 --- a/OpenSim/Region/Communications/Local/LocalBackEndServices.cs +++ b/OpenSim/Region/Communications/Local/LocalBackEndServices.cs @@ -361,8 +361,13 @@ namespace OpenSim.Region.Communications.Local agent.InventoryFolder = loginData.InventoryFolder; agent.startpos = loginData.StartPos; + agent.ClientVersion = loginData.ClientVersion; //rex + agent.CapsPath = loginData.CapsPath; + agent.authenticationAddr = loginData.AuthAddr; + agent.asAddress = loginData.asAddress; + TriggerExpectUser(regionHandle, agent); } diff --git a/OpenSim/Region/Communications/Local/LocalLoginService.cs b/OpenSim/Region/Communications/Local/LocalLoginService.cs index 2c924918c7..701c250682 100644 --- a/OpenSim/Region/Communications/Local/LocalLoginService.cs +++ b/OpenSim/Region/Communications/Local/LocalLoginService.cs @@ -53,8 +53,8 @@ namespace OpenSim.Region.Communications.Local public event LoginToRegionEvent OnLoginToRegion; public LocalLoginService(UserManagerBase userManager, string welcomeMess, CommunicationsLocal parent, - NetworkServersInfo serversInfo, bool authenticate) - : base(userManager, parent.UserProfileCacheService.libraryRoot, welcomeMess) + NetworkServersInfo serversInfo, bool authenticate, bool rexMode) + : base(userManager, parent.UserProfileCacheService.libraryRoot, welcomeMess, rexMode) { m_Parent = parent; this.serversInfo = serversInfo; @@ -64,9 +64,9 @@ namespace OpenSim.Region.Communications.Local } - public override UserProfileData GetTheUser(string firstname, string lastname) + public override UserProfileData GetTheUser(string firstname, string lastname, string authAddr) { - UserProfileData profile = m_userManager.GetUserProfile(firstname, lastname); + UserProfileData profile = m_userManager.GetUserProfile(firstname, lastname, authAddr); if (profile != null) { return profile; @@ -79,7 +79,7 @@ namespace OpenSim.Region.Communications.Local m_userManager.AddUserProfile(firstname, lastname, "test", defaultHomeX, defaultHomeY); - profile = m_userManager.GetUserProfile(firstname, lastname); + profile = m_userManager.GetUserProfile(firstname, lastname, ""); if (profile != null) { m_Parent.InventoryService.CreateNewUserInventory(profile.UUID); @@ -112,19 +112,29 @@ namespace OpenSim.Region.Communications.Local } } - public override void CustomiseResponse(LoginResponse response, UserProfileData theUser) + public override void CustomiseResponse(LoginResponse response, UserProfileData theUser, string ASaddress) { ulong currentRegion = theUser.currentAgent.currentHandle; RegionInfo reg = m_Parent.GridService.RequestNeighbourInfo(currentRegion); if (reg != null) { + // rex, start + LLVector3 StartLoc,StartLookAt; + bool bCustomStartLoc = true; + if (!RexScriptAccess.GetAvatarStartLocation(out StartLoc, out StartLookAt)) + { + StartLoc = theUser.homeLocation; + StartLookAt = theUser.homeLocation; + bCustomStartLoc = false; + } + response.Home = "{'region_handle':[r" + (reg.RegionLocX*256).ToString() + ",r" + (reg.RegionLocY*256).ToString() + "], " + - "'position':[r" + theUser.homeLocation.X.ToString() + ",r" + - theUser.homeLocation.Y.ToString() + ",r" + theUser.homeLocation.Z.ToString() + "], " + - "'look_at':[r" + theUser.homeLocation.X.ToString() + ",r" + - theUser.homeLocation.Y.ToString() + ",r" + theUser.homeLocation.Z.ToString() + "]}"; + "'position':[r" + StartLoc.X.ToString() + ",r" + + StartLoc.Y.ToString() + ",r" + StartLoc.Z.ToString() + "], " + + "'look_at':[r" + StartLoc.X.ToString() + ",r" + + StartLoc.Y.ToString() + ",r" + StartLoc.Z.ToString() + "]}"; // rex end string capsPath = Util.GetRandomCapsPath(); response.SimAddress = reg.ExternalEndPoint.Address.ToString(); response.SimPort = (uint) reg.ExternalEndPoint.Port; @@ -149,9 +159,19 @@ namespace OpenSim.Region.Communications.Local _login.Session = response.SessionID; _login.SecureSession = response.SecureSessionID; _login.CircuitCode = (uint) response.CircuitCode; - _login.StartPos = new LLVector3(128, 128, 70); + if(bCustomStartLoc) // rex + _login.StartPos = StartLoc; + else + _login.StartPos = theUser.currentAgent.currentPos; _login.CapsPath = capsPath; + _login.ClientVersion = response.ClientVersion; //rex + if (m_rexMode) + { + _login.AuthAddr = theUser.authenticationAddr; + _login.asAddress = ASaddress; + } + if (OnLoginToRegion != null) { OnLoginToRegion(currentRegion, _login); @@ -181,46 +201,61 @@ namespace OpenSim.Region.Communications.Local List folders = m_Parent.InventoryService.RequestFirstLevelFolders(userID); if (folders.Count > 0) { - LLUUID rootID = LLUUID.Zero; - ArrayList AgentInventoryArray = new ArrayList(); - Hashtable TempHash; - foreach (InventoryFolderBase InvFolder in folders) + return GetInventoryData(folders); + } + else { + if (!m_rexMode) { - if (InvFolder.parentID == LLUUID.Zero) + AgentInventory userInventory = new AgentInventory(); + userInventory.CreateRootFolder(userID, false); + + ArrayList AgentInventoryArray = new ArrayList(); + Hashtable TempHash; + foreach (InventoryFolder InvFolder in userInventory.InventoryFolders.Values) { - rootID = InvFolder.folderID; + TempHash = new Hashtable(); + TempHash["name"] = InvFolder.FolderName; + TempHash["parent_id"] = InvFolder.ParentID.ToString(); + TempHash["version"] = (Int32) InvFolder.Version; + TempHash["type_default"] = (Int32) InvFolder.DefaultType; + TempHash["folder_id"] = InvFolder.FolderID.ToString(); + AgentInventoryArray.Add(TempHash); } - TempHash = new Hashtable(); - TempHash["name"] = InvFolder.name; - TempHash["parent_id"] = InvFolder.parentID.ToString(); - TempHash["version"] = (Int32) InvFolder.version; - TempHash["type_default"] = (Int32) InvFolder.type; - TempHash["folder_id"] = InvFolder.folderID.ToString(); - AgentInventoryArray.Add(TempHash); + + return new InventoryData(AgentInventoryArray, userInventory.InventoryRoot.FolderID); } - return new InventoryData(AgentInventoryArray, rootID); + else { // in rex mode users are created at the authentication server and folders must be created at + // first login to db + m_Parent.InventoryService.CreateNewUserInventory(userID); + + folders = m_Parent.InventoryService.RequestFirstLevelFolders(userID); + return GetInventoryData(folders); + } + + } - else + } + + private InventoryData GetInventoryData(List folders) + { + LLUUID rootID = LLUUID.Zero; + ArrayList AgentInventoryArray = new ArrayList(); + Hashtable TempHash; + foreach (InventoryFolderBase InvFolder in folders) { - AgentInventory userInventory = new AgentInventory(); - userInventory.CreateRootFolder(userID, false); - - ArrayList AgentInventoryArray = new ArrayList(); - Hashtable TempHash; - foreach (InventoryFolder InvFolder in userInventory.InventoryFolders.Values) + if (InvFolder.parentID == LLUUID.Zero) { - TempHash = new Hashtable(); - TempHash["name"] = InvFolder.FolderName; - TempHash["parent_id"] = InvFolder.ParentID.ToString(); - TempHash["version"] = (Int32) InvFolder.Version; - TempHash["type_default"] = (Int32) InvFolder.DefaultType; - TempHash["folder_id"] = InvFolder.FolderID.ToString(); - AgentInventoryArray.Add(TempHash); + rootID = InvFolder.folderID; } - - return new InventoryData(AgentInventoryArray, userInventory.InventoryRoot.FolderID); + TempHash = new Hashtable(); + TempHash["name"] = InvFolder.name; + TempHash["parent_id"] = InvFolder.parentID.ToString(); + TempHash["version"] = (Int32)InvFolder.version; + TempHash["type_default"] = (Int32)InvFolder.type; + TempHash["folder_id"] = InvFolder.folderID.ToString(); + AgentInventoryArray.Add(TempHash); } - + return new InventoryData(AgentInventoryArray, rootID); } } } \ No newline at end of file diff --git a/OpenSim/Region/Communications/Local/LocalUserServices.cs b/OpenSim/Region/Communications/Local/LocalUserServices.cs index 6269565aae..8b09029637 100644 --- a/OpenSim/Region/Communications/Local/LocalUserServices.cs +++ b/OpenSim/Region/Communications/Local/LocalUserServices.cs @@ -60,7 +60,7 @@ namespace OpenSim.Region.Communications.Local public override UserProfileData SetupMasterUser(string firstName, string lastName, string password) { - UserProfileData profile = GetUserProfile(firstName, lastName); + UserProfileData profile = GetUserProfile(firstName, lastName, ""); if (profile != null) { return profile; @@ -69,7 +69,7 @@ namespace OpenSim.Region.Communications.Local Console.WriteLine("Unknown Master User. Sandbox Mode: Creating Account"); AddUserProfile(firstName, lastName, password, m_defaultHomeX, m_defaultHomeY); - profile = GetUserProfile(firstName, lastName); + profile = GetUserProfile(firstName, lastName, ""); if (profile == null) { @@ -85,7 +85,7 @@ namespace OpenSim.Region.Communications.Local public override UserProfileData SetupMasterUser(LLUUID uuid) { - UserProfileData data = GetUserProfile(uuid); + UserProfileData data = GetUserProfile(uuid, ""); if (data == null) { throw new Exception("Unknown master user UUID"); diff --git a/OpenSim/Region/Communications/OGS1/OGS1GridServices.cs b/OpenSim/Region/Communications/OGS1/OGS1GridServices.cs index 653139d14d..c00cbf4c5c 100644 --- a/OpenSim/Region/Communications/OGS1/OGS1GridServices.cs +++ b/OpenSim/Region/Communications/OGS1/OGS1GridServices.cs @@ -444,6 +444,14 @@ namespace OpenSim.Region.Communications.OGS1 agentData.AgentID = new LLUUID((string) requestData["agent_id"]); agentData.circuitcode = Convert.ToUInt32(requestData["circuit_code"]); agentData.CapsPath = (string) requestData["caps_path"]; + agentData.ClientVersion = (string)requestData["version"]; //rex + + if (requestData.ContainsKey("auth_addr")) { + agentData.authenticationAddr = (string)requestData["auth_addr"]; + } + if (requestData.ContainsKey("as_addr")) { + agentData.asAddress = (string)requestData["as_addr"]; + } if (requestData.ContainsKey("child_agent") && requestData["child_agent"].Equals("1")) { diff --git a/OpenSim/Region/Communications/OGS1/OGS1UserServices.cs b/OpenSim/Region/Communications/OGS1/OGS1UserServices.cs index e64507401c..cacf2b272e 100644 --- a/OpenSim/Region/Communications/OGS1/OGS1UserServices.cs +++ b/OpenSim/Region/Communications/OGS1/OGS1UserServices.cs @@ -47,6 +47,38 @@ namespace OpenSim.Region.Communications.OGS1 m_parent = parent; } + public void UpdateUserAgentData(LLUUID agentId, bool agentOnline, LLVector3 currentPos, int logoutTime, string authAddr) + { + try + { + Hashtable param = new Hashtable(); + param["agentID"] = agentId.ToString(); + param["agentOnline"] = agentOnline.ToString(); + param["logoutTime"] = logoutTime.ToString(); + param["agent_currentPosX"] = Convert.ToSingle(currentPos.X).ToString(); + param["agent_currentPosY"] = Convert.ToSingle(currentPos.Y).ToString(); + param["agent_currentPosZ"] = Convert.ToSingle(currentPos.Z).ToString(); + param["AuthenticationAddress"] = authAddr; + IList parameters = new ArrayList(); + parameters.Add(param); + XmlRpcRequest req = new XmlRpcRequest("update_user_agent", parameters); + XmlRpcResponse resp = req.Send(m_parent.NetworkServersInfo.UserURL, 3000); + Hashtable respData = (Hashtable)resp.Value; + + if ("success" == (string)respData["update"]) + { + MainLog.Instance.Verbose("INTERGRID", "Agent updated with agentID : " + agentId); + } + + } + catch (WebException e) + { + MainLog.Instance.Warn("Error when trying to fetch profile data by name from remote user server: " + + e.Message); + } + } + + public UserProfileData ConvertXMLRPCDataToUserProfile(Hashtable data) { if (data.Contains("error_type")) @@ -130,12 +162,36 @@ namespace OpenSim.Region.Communications.OGS1 return buddylist; } - - public UserProfileData GetUserProfile(string firstName, string lastName) + + public UserProfileData GetUserProfile(string firstName, string lastName, string authAddr) { - return GetUserProfile(firstName + " " + lastName); + return GetUserProfile(firstName + " " + lastName, authAddr); } + public UserProfileData GetUserProfile(string name, string authAddr) + { + try + { + Hashtable param = new Hashtable(); + param["avatar_name"] = name; + param["AuthenticationAddress"] = authAddr; + IList parameters = new ArrayList(); + parameters.Add(param); + XmlRpcRequest req = new XmlRpcRequest("get_user_by_name", parameters); + XmlRpcResponse resp = req.Send(m_parent.NetworkServersInfo.UserURL, 3000); + Hashtable respData = (Hashtable)resp.Value; + + return ConvertXMLRPCDataToUserProfile(respData); + } + catch (WebException e) + { + MainLog.Instance.Warn("Error when trying to fetch profile data by name from remote user server: " + + e.Message); + } + return null; + } + + public List GenerateAgentPickerRequestResponse(LLUUID queryID, string query) { List pickerlist = new List(); @@ -161,34 +217,14 @@ namespace OpenSim.Region.Communications.OGS1 return pickerlist; } - public UserProfileData GetUserProfile(string name) - { - try - { - Hashtable param = new Hashtable(); - param["avatar_name"] = name; - IList parameters = new ArrayList(); - parameters.Add(param); - XmlRpcRequest req = new XmlRpcRequest("get_user_by_name", parameters); - XmlRpcResponse resp = req.Send(m_parent.NetworkServersInfo.UserURL, 3000); - Hashtable respData = (Hashtable) resp.Value; - return ConvertXMLRPCDataToUserProfile(respData); - } - catch (WebException e) - { - MainLog.Instance.Warn("Error when trying to fetch profile data by name from remote user server: " + - e.Message); - } - return null; - } - - public UserProfileData GetUserProfile(LLUUID avatarID) + public UserProfileData GetUserProfile(LLUUID avatarID, string authAddr) { try { Hashtable param = new Hashtable(); param["avatar_uuid"] = avatarID.ToString(); + param["AuthenticationAddress"] = authAddr; IList parameters = new ArrayList(); parameters.Add(param); XmlRpcRequest req = new XmlRpcRequest("get_user_by_uuid", parameters); @@ -205,9 +241,35 @@ namespace OpenSim.Region.Communications.OGS1 return null; } - public void clearUserAgent(LLUUID avatarID) + public UserProfileData GetUserProfileByAccount(string account) { - // TODO: implement + return null; + } + + public void clearUserAgent(LLUUID avatarID, string authAddr) + { + try + { + Hashtable param = new Hashtable(); + param["agentID"] = avatarID.ToString(); + param["AuthenticationAddress"] = authAddr; + IList parameters = new ArrayList(); + parameters.Add(param); + XmlRpcRequest req = new XmlRpcRequest("remove_user_agent", parameters); + XmlRpcResponse resp = req.Send(m_parent.NetworkServersInfo.UserURL, 3000); + Hashtable respData = (Hashtable)resp.Value; + + Hashtable resh = (Hashtable)resp.Value; + if ("success" == (string)resh["remove"]) + { + MainLog.Instance.Verbose("INTERGRID", "Agent removed with agentID : " + avatarID); + } + } + catch (Exception e) + { + Console.WriteLine("Error when trying to remove agent data by uuid from remote user server: " + + e.Message); + } } public UserProfileData SetupMasterUser(string firstName, string lastName) @@ -217,13 +279,13 @@ namespace OpenSim.Region.Communications.OGS1 public UserProfileData SetupMasterUser(string firstName, string lastName, string password) { - UserProfileData profile = GetUserProfile(firstName, lastName); + UserProfileData profile = GetUserProfile(firstName, lastName, ""); return profile; } public UserProfileData SetupMasterUser(LLUUID uuid) { - UserProfileData data = GetUserProfile(uuid); + UserProfileData data = GetUserProfile(uuid, ""); if (data == null) { throw new Exception("Unknown master user UUID"); @@ -429,5 +491,12 @@ namespace OpenSim.Region.Communications.OGS1 } #endregion + + public virtual bool AuthenticateUser(LLUUID agentId, String sessionhash, out String avatarstorage) + { + avatarstorage = ""; + return true; + } + } } \ No newline at end of file diff --git a/OpenSim/Region/Communications/VoiceChat/VoiceChatServer.cs b/OpenSim/Region/Communications/VoiceChat/VoiceChatServer.cs new file mode 100644 index 0000000000..089c8ea09f --- /dev/null +++ b/OpenSim/Region/Communications/VoiceChat/VoiceChatServer.cs @@ -0,0 +1,284 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using System.Net.Sockets; +using System.Net; +using OpenSim.Region.Environment.Scenes; +using OpenSim.Framework.Console; +using OpenSim.Framework.ServerStatus; +using OpenSim.Framework; +using libsecondlife; + +namespace OpenSim.Region.Communications.VoiceChat +{ + public class VoiceChatServer + { + Thread m_listenerThread; + Thread m_mainThread; + Scene m_scene; + Socket m_server; + Socket m_selectCancel; + + Dictionary m_clients; + Dictionary m_uuidToClient; + + + public VoiceChatServer(Scene scene) + { + m_clients = new Dictionary(); + m_uuidToClient = new Dictionary(); + m_scene = scene; + + m_scene.EventManager.OnNewPresence += NewPresence; + m_scene.EventManager.OnRemovePresence += RemovePresence; + + try + { + CreateListeningSocket(); + } + catch (Exception e) + { + MainLog.Instance.Error("VOICECHAT", "Unable to start listening"); + return; + } + + m_listenerThread = new Thread(new ThreadStart(ListenIncomingConnections)); + m_listenerThread.IsBackground = true; + m_listenerThread.Start(); + + m_mainThread = new Thread(new ThreadStart(RunVoiceChat)); + m_mainThread.IsBackground = true; + m_mainThread.Start(); + + Thread.Sleep(200); + m_selectCancel = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + m_selectCancel.Connect("localhost", 59214); + } + + public void NewPresence(ScenePresence presence) + { + MainLog.Instance.Verbose("VOICECHAT", "New scene presence: " + presence.UUID); + lock (m_uuidToClient) + { + m_uuidToClient[presence.UUID] = null; + } + } + + public void RemovePresence(LLUUID uuid) + { + lock (m_uuidToClient) + { + if (m_uuidToClient.ContainsKey(uuid)) + { + if (m_uuidToClient[uuid] != null) + { + RemoveClient(m_uuidToClient[uuid].m_socket); + } + m_uuidToClient.Remove(uuid); + } + else + { + MainLog.Instance.Error("VOICECHAT", "Presence not found on RemovePresence: " + uuid); + } + } + } + + public bool AddClient(VoiceClient client, LLUUID uuid) + { + lock (m_uuidToClient) + { + if (m_uuidToClient.ContainsKey(uuid)) + { + if (m_uuidToClient[uuid] != null) { + MainLog.Instance.Warn("VOICECHAT", "Multiple login attempts for " + uuid); + return false; + } + m_uuidToClient[uuid] = client; + return true; + } + } + return false; + } + + public void RemoveClient(Socket socket) + { + MainLog.Instance.Verbose("VOICECHAT", "Removing client"); + lock(m_clients) + { + VoiceClient client = m_clients[socket]; + + lock(m_uuidToClient) + { + if (m_uuidToClient.ContainsKey(client.m_clientId)) + { + m_uuidToClient[client.m_clientId] = null; + } + } + + m_clients.Remove(socket); + client.m_socket.Close(); + } + } + + protected void CreateListeningSocket() + { + IPEndPoint listenEndPoint = new IPEndPoint(IPAddress.Parse("0.0.0.0"), 12000); + m_server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + m_server.Bind(listenEndPoint); + m_server.Listen(50); + } + + void ListenIncomingConnections() + { + MainLog.Instance.Verbose("VOICECHAT", "Listening connections..."); + ServerStatus.ReportThreadName("VoiceChat: Connection listener"); + + byte[] dummyBuffer = new byte[1]; + + while (true) + { + try + { + Socket connection = m_server.Accept(); + lock (m_clients) + { + m_clients[connection] = new VoiceClient(connection, this); + m_selectCancel.Send(dummyBuffer); + MainLog.Instance.Verbose("VOICECHAT", "Voicechat connection from " + connection.RemoteEndPoint.ToString()); + } + } + catch (SocketException e) + { + MainLog.Instance.Error("VOICECHAT", "During accept: " + e.ToString()); + } + } + } + + Socket ListenLoopbackSocket() + { + IPEndPoint listenEndPoint = new IPEndPoint(IPAddress.Parse("0.0.0.0"), 59214); + Socket dummyListener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + dummyListener.Bind(listenEndPoint); + dummyListener.Listen(1); + Socket socket = dummyListener.Accept(); + dummyListener.Close(); + return socket; + } + + void RunVoiceChat() + { + MainLog.Instance.Verbose("VOICECHAT", "Connection handler started..."); + ServerStatus.ReportThreadName("VoiceChat: Connection handler"); + + //Listen a loopback socket for aborting select call + Socket dummySocket = ListenLoopbackSocket(); + + MainLog.Instance.Verbose("VOICECHAT", "Got select abort socket..."); + + List sockets = new List(); + byte[] buffer = new byte[65536]; + + while (true) + { + if (m_clients.Count == 0) + { + Thread.Sleep(100); + continue; + } + + lock (m_clients) + { + foreach (Socket s in m_clients.Keys) + { + sockets.Add(s); + } + } + sockets.Add(dummySocket); + + Socket.Select(sockets, null, null, 200000); + + foreach (Socket s in sockets) + { + try + { + if (s.RemoteEndPoint != dummySocket.RemoteEndPoint) + { + ReceiveFromSocket(s, buffer); + } + else + { + if (s.Receive(buffer) <= 0) { + MainLog.Instance.Error("VOICECHAT", "Socket closed"); + } else + { + MainLog.Instance.Verbose("VOICECHAT", "Select aborted"); + } + } + } + catch(ObjectDisposedException e) + { + MainLog.Instance.Warn("VOICECHAT", "Connection has been already closed"); + } + catch (Exception e) + { + MainLog.Instance.Error("VOICECHAT", "Exception: " + e.Message); + + RemoveClient(s); + } + } + + sockets.Clear(); + } + } + + private void ReceiveFromSocket( Socket s, byte[] buffer ) + { + int byteCount = s.Receive(buffer); + if (byteCount <= 0) + { + MainLog.Instance.Verbose("VOICECHAT", "Connection lost to " + s.RemoteEndPoint); + lock (m_clients) + { + RemoveClient(s); + } + } + else + { + ServerStatus.ReportInPacketTcp(byteCount); + lock (m_clients) + { + if (m_clients.ContainsKey(s)) + { + m_clients[s].OnDataReceived(buffer, byteCount); + } + else + { + MainLog.Instance.Warn("VOICECHAT", "Got data from " + s.RemoteEndPoint + + ", but it's not registered as a voice client"); + } + } + } + } + + public void BroadcastVoice(VoicePacket packet) + { + libsecondlife.LLVector3 origPos = m_scene.GetScenePresence(packet.m_clientId).AbsolutePosition; + + byte[] bytes = packet.GetBytes(); + foreach (VoiceClient client in m_clients.Values) + { + if (client.IsEnabled() && client.m_clientId != packet.m_clientId && + client.m_authenticated && client.IsCodecSupported(packet.m_codec)) + { + ScenePresence presence = m_scene.GetScenePresence(client.m_clientId); + + if (presence != null && Util.GetDistanceTo(presence.AbsolutePosition, origPos) < 20) + { + client.SendTo(bytes); + } + } + } + } + } +} diff --git a/OpenSim/Region/Communications/VoiceChat/VoiceClient.cs b/OpenSim/Region/Communications/VoiceChat/VoiceClient.cs new file mode 100644 index 0000000000..5bf5b159a1 --- /dev/null +++ b/OpenSim/Region/Communications/VoiceChat/VoiceClient.cs @@ -0,0 +1,175 @@ +using System; +using System.IO; +using System.Collections.Generic; +using System.Text; +using System.Net.Sockets; +using OpenSim.Framework.Console; +using OpenSim.Framework.ServerStatus; +using OpenSim.Region.Environment.Scenes; +using libsecondlife; + +namespace OpenSim.Region.Communications.VoiceChat +{ + /** + * Represents a single voiceclient instance + **/ + public class VoiceClient + { + public Socket m_socket; + public LLUUID m_clientId; + public bool m_authenticated = false; + + protected VoicePacketHeader m_header = null; + protected int m_headerBytesReceived = 0; + + protected int m_offset = 0; + protected int m_supportedCodecs = 0; + + protected byte[] m_buffer = null; + protected byte[] m_headerBytes = new byte[5]; + + protected bool m_enabled = true; + + protected VoiceChatServer m_server; + + public VoiceClient(Socket socket, VoiceChatServer server) + { + m_socket = socket; + m_server = server; + } + + public void OnDataReceived(byte[] data, int byteCount) + { + /* Console.WriteLine("Got data:"); + for ( int i = 0; i < byteCount; i++) + { + Console.Write(data[i] + ", "); + }*/ + + int offset = 0; + while (offset < byteCount) + { + if (m_header == null) + { + if (m_headerBytesReceived < 5) + { + m_headerBytes[m_headerBytesReceived++] = data[offset++]; + } + else if (m_headerBytesReceived == 5) + { + m_header = new VoicePacketHeader(); + m_header.Parse(m_headerBytes); + if (m_header.length > 65535) + { + throw new Exception("Packet size " + m_header.length + " > 65535"); + } + + m_buffer = new byte[m_header.length]; + m_offset = 0; + m_headerBytesReceived = 0; + } + } + else + { + int bytesToCopy = m_header.length-m_offset; + if (bytesToCopy > byteCount - offset) + bytesToCopy = byteCount - offset; + + Buffer.BlockCopy(data, offset, m_buffer, m_offset, bytesToCopy); + + offset += bytesToCopy; + m_offset += bytesToCopy; + + if (m_offset == m_header.length) + { + ParsePacket(m_header.type, m_buffer); + m_header = null; + } + } + } + } + + void ParsePacket(byte type, byte[] data) + { + switch (type) + { + case 0: //LOGIN + ParseLogin(data); + break; + + case 1: //AUDIODATA + if (m_authenticated) + { + VoicePacket packet = new VoicePacket(data); + packet.m_clientId = m_clientId; + m_server.BroadcastVoice(packet); + } + else + { + MainLog.Instance.Warn("VOICECHAT", "Got unauthorized audio data from " + + m_socket.RemoteEndPoint.ToString()); + m_socket.Close(); + } + break; + + case 3: //ENABLEVOIP + if (data[0] == 0) + { + MainLog.Instance.Warn("VOICECHAT", "VoiceChat has been disabled for " + m_clientId); + m_enabled = false; + } + else + { + MainLog.Instance.Warn("VOICECHAT", "VoiceChat has been enabled for " + m_clientId); + m_enabled = true; + } + break; + + + default: + throw new Exception("Invalid packet received"); + } + } + + void ParseLogin(byte[] data) + { + m_clientId = new LLUUID(data, 0); + + m_supportedCodecs = data[16]; + m_supportedCodecs |= data[17] << 8; + m_supportedCodecs |= data[18] << 16; + m_supportedCodecs |= data[19] << 24; + + if (m_server.AddClient(this, m_clientId)) + { + MainLog.Instance.Verbose("VOICECHAT", "Client authenticated succesfully: " + m_clientId); + m_authenticated = true; + } + else + { + throw new Exception("Unable to authenticate with id " + m_clientId); + } + } + + public bool IsEnabled() + { + return m_enabled; + } + + public bool IsCodecSupported(int codec) + { + if ((m_supportedCodecs & codec) != 0) + return true; + + return false; + } + + public void SendTo(byte[] data) + { + if (m_authenticated) + { + ServerStatus.ReportOutPacketTcp(m_socket.Send(data)); + } + } + } +} diff --git a/OpenSim/Region/Communications/VoiceChat/VoicePacket.cs b/OpenSim/Region/Communications/VoiceChat/VoicePacket.cs new file mode 100644 index 0000000000..2d0308816b --- /dev/null +++ b/OpenSim/Region/Communications/VoiceChat/VoicePacket.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Text; +using libsecondlife; + +namespace OpenSim.Region.Communications.VoiceChat +{ + public enum VoiceCodec + { + None = 0, + PCM8 = 1 << 0, + PCM16 = 1 << 1, + PCM32 = 1 << 2, + Speex = 1 << 3, + } + + public class VoicePacket + { + public LLUUID m_clientId; + byte[] m_audioData; + public int m_codec; + + public VoicePacket(byte[] data) + { + int pos = 0; + m_codec = data[pos++]; + m_codec |= data[pos++] << 8; + m_codec |= data[pos++] << 16; + m_codec |= data[pos++] << 24; + + m_audioData = new byte[data.Length - pos]; + Buffer.BlockCopy(data, pos, m_audioData, 0, data.Length - pos); + } + + public byte[] GetBytes() + { + VoicePacketHeader header = new VoicePacketHeader(); + byte[] bytes = new byte[5+16+4+m_audioData.Length]; + + header.length = bytes.Length-5; + + //ToClient packets are type 2 + header.type = 2; + + int pos = 0; + header.CopyTo(bytes, pos); pos += 5; + m_clientId.GetBytes().CopyTo(bytes, pos); pos += 16; + + bytes[pos++] = (byte)((m_codec) % 256); + bytes[pos++] = (byte)((m_codec << 8) % 256); + bytes[pos++] = (byte)((m_codec << 16) % 256); + bytes[pos++] = (byte)((m_codec << 24) % 256); + + m_audioData.CopyTo(bytes, pos); + return bytes; + } + } +} diff --git a/OpenSim/Region/Communications/VoiceChat/VoicePacketHeader.cs b/OpenSim/Region/Communications/VoiceChat/VoicePacketHeader.cs new file mode 100644 index 0000000000..d8f5d1b4d3 --- /dev/null +++ b/OpenSim/Region/Communications/VoiceChat/VoicePacketHeader.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenSim.Region.Communications.VoiceChat +{ + public class VoicePacketHeader + { + public byte type; + public int length; + + public void Parse(byte[] data) + { + int offset = 0; + type = data[offset++]; + + length = data[offset++]; + length |= data[offset++] << 8; + length |= data[offset++] << 16; + length |= data[offset++] << 24; + } + + public void CopyTo(byte[] data, int offset) + { + data[offset + 0] = type; + + data[offset + 1] = (byte)(length & 0x000000FF); + data[offset + 2] = (byte)((length & 0x0000FF00) >> 8); + data[offset + 3] = (byte)((length & 0x00FF0000) >> 16); + data[offset + 4] = (byte)((length & 0xFF000000) >> 24); + } + + public int GetLength() + { + return 5; + } + } +} diff --git a/OpenSim/Region/Environment/EstateManager.cs b/OpenSim/Region/Environment/EstateManager.cs index 64b9d782b2..41dcbfaa26 100644 --- a/OpenSim/Region/Environment/EstateManager.cs +++ b/OpenSim/Region/Environment/EstateManager.cs @@ -449,8 +449,8 @@ namespace OpenSim.Region.Environment if (splitField.Length == 3) { Int16 corner = Convert.ToInt16(splitField[0]); - float lowValue = (float) Convert.ToDecimal(splitField[1]); - float highValue = (float) Convert.ToDecimal(splitField[2]); + float lowValue = (float) Convert.ToDouble(splitField[1].Replace('.', ',')); + float highValue = (float) Convert.ToDouble(splitField[2].Replace('.', ',')); setEstateTextureRange(corner, lowValue, highValue); } diff --git a/OpenSim/Region/Environment/Modules/WorldCommModule.cs b/OpenSim/Region/Environment/Modules/WorldCommModule.cs index 6b9ae46283..cfe71b9eb2 100644 --- a/OpenSim/Region/Environment/Modules/WorldCommModule.cs +++ b/OpenSim/Region/Environment/Modules/WorldCommModule.cs @@ -157,84 +157,86 @@ namespace OpenSim.Region.Environment.Modules // If they are in proximity, then if they are // listeners, if so add them to the pending queue - foreach (LLUUID eb in m_scene.Entities.Keys) + lock (m_scene.Entities) { - EntityBase sPart; - - m_scene.Entities.TryGetValue(eb, out sPart); - - // Dont process if this message is from itself! - if (eb.ToString().Equals(sourceItemID) || - sPart.UUID.ToString().Equals(sourceItemID)) - continue; - - double dis = 0; - - if (source != null) - dis = Util.GetDistanceTo(sPart.AbsolutePosition, source.AbsolutePosition); - else - dis = Util.GetDistanceTo(sPart.AbsolutePosition, avatar.AbsolutePosition); - - switch (type) + foreach (LLUUID eb in m_scene.Entities.Keys) { - case ChatTypeEnum.Whisper: + EntityBase sPart; - if ((dis < 10) && (dis > -10)) - { - ListenerInfo isListener = m_listenerManager.IsListenerMatch( - sourceItemID, sPart.UUID, channel, name, msg - ); - if (isListener != null) + m_scene.Entities.TryGetValue(eb, out sPart); + + // Dont process if this message is from itself! + if (eb.ToString().Equals(sourceItemID) || + sPart.UUID.ToString().Equals(sourceItemID)) + continue; + + double dis = 0; + + if (source != null) + dis = Util.GetDistanceTo(sPart.AbsolutePosition, source.AbsolutePosition); + else + dis = Util.GetDistanceTo(sPart.AbsolutePosition, avatar.AbsolutePosition); + + switch (type) + { + case ChatTypeEnum.Whisper: + + if ((dis < 10) && (dis > -10)) { - m_pending.Enqueue(isListener); + ListenerInfo isListener = m_listenerManager.IsListenerMatch( + sourceItemID, sPart.UUID, channel, name, msg + ); + if (isListener != null) + { + m_pending.Enqueue(isListener); + } } - } - break; + break; - case ChatTypeEnum.Say: + case ChatTypeEnum.Say: - if ((dis < 30) && (dis > -30)) - { - ListenerInfo isListener = m_listenerManager.IsListenerMatch( - sourceItemID, sPart.UUID, channel, name, msg - ); - if (isListener != null) + if ((dis < 30) && (dis > -30)) { - m_pending.Enqueue(isListener); + ListenerInfo isListener = m_listenerManager.IsListenerMatch( + sourceItemID, sPart.UUID, channel, name, msg + ); + if (isListener != null) + { + m_pending.Enqueue(isListener); + } } - } - break; + break; - case ChatTypeEnum.Shout: - if ((dis < 100) && (dis > -100)) - { - ListenerInfo isListener = m_listenerManager.IsListenerMatch( - sourceItemID, sPart.UUID, channel, name, msg - ); - if (isListener != null) + case ChatTypeEnum.Shout: + if ((dis < 100) && (dis > -100)) { - m_pending.Enqueue(isListener); + ListenerInfo isListener = m_listenerManager.IsListenerMatch( + sourceItemID, sPart.UUID, channel, name, msg + ); + if (isListener != null) + { + m_pending.Enqueue(isListener); + } } - } - break; + break; - case ChatTypeEnum.Broadcast: - ListenerInfo isListen = - m_listenerManager.IsListenerMatch(sourceItemID, eb, channel, name, msg); - if (isListen != null) - { - ListenerInfo isListener = m_listenerManager.IsListenerMatch( - sourceItemID, sPart.UUID, channel, name, msg - ); - if (isListener != null) + case ChatTypeEnum.Broadcast: + ListenerInfo isListen = + m_listenerManager.IsListenerMatch(sourceItemID, eb, channel, name, msg); + if (isListen != null) { - m_pending.Enqueue(isListener); + ListenerInfo isListener = m_listenerManager.IsListenerMatch( + sourceItemID, sPart.UUID, channel, name, msg + ); + if (isListener != null) + { + m_pending.Enqueue(isListener); + } } - } - break; + break; + } } } - ; } } diff --git a/OpenSim/Region/Environment/PermissionManager.cs b/OpenSim/Region/Environment/PermissionManager.cs index db1cac51d2..72342695d3 100644 --- a/OpenSim/Region/Environment/PermissionManager.cs +++ b/OpenSim/Region/Environment/PermissionManager.cs @@ -178,6 +178,10 @@ namespace OpenSim.Region.Environment if (m_bypassPermissions) return OwnerMask; + else //rex + { + EveryoneMask &= ~(uint)LLObject.ObjectFlags.ObjectModify; + } // Object owners should be able to edit their own content if (user == objectOwner) diff --git a/OpenSim/Region/Environment/Scenes/AvatarAppearance.cs b/OpenSim/Region/Environment/Scenes/AvatarAppearance.cs index 1583124b8c..365aefb4b5 100644 --- a/OpenSim/Region/Environment/Scenes/AvatarAppearance.cs +++ b/OpenSim/Region/Environment/Scenes/AvatarAppearance.cs @@ -37,6 +37,10 @@ namespace OpenSim.Region.Environment.Scenes protected LLUUID m_scenePresenceID; protected int m_wearablesSerial = 1; + protected bool m_rexmode; //rex + protected string m_avatarStorageAddr; + + protected byte[] m_visualParams; public byte[] VisualParams @@ -82,6 +86,19 @@ namespace OpenSim.Region.Environment.Scenes m_textureEntry = GetDefaultTextureEntry(); } + /// + /// AvatarAppearance for rexmode, using avatarstorage address for describing avatar + /// + /// + /// + public AvatarAppearance(LLUUID avatarID, string avatarStorage)//rex + { + m_scenePresenceID = avatarID; + m_avatarStorageAddr = avatarStorage; + m_rexmode = true; + m_textureEntry = GetDefaultTextureEntry(); // rex mode fix against nullpointer in SendInitialData() + } + /// /// /// @@ -110,19 +127,35 @@ namespace OpenSim.Region.Environment.Scenes /// public void SendAppearanceToOtherAgent(ScenePresence avatar) { - avatar.ControllingClient.SendAppearance(m_scenePresenceID, m_visualParams, + if (!m_rexmode) { + avatar.ControllingClient.SendAppearance(m_scenePresenceID, m_visualParams, m_textureEntry.ToBytes()); + } + else { //rex mode appearance sending + avatar.ControllingClient.SendRexAppearance(m_scenePresenceID, m_avatarStorageAddr); + } } public void SetWearable(IClientAPI client, int wearableId, AvatarWearable wearable) { - m_wearables[wearableId] = wearable; - SendOwnWearables(client); + if (m_wearables != null) // rex mode fix, wearables may be null + { + m_wearables[wearableId] = wearable; + SendOwnWearables(client); + } } public void SendOwnWearables(IClientAPI ourClient) { - ourClient.SendWearables(m_wearables, m_wearablesSerial++); + if (m_wearables != null) // rex mode fix, wearables may be null + { + ourClient.SendWearables(m_wearables, m_wearablesSerial++); + } + + if (m_rexmode) // rex mode addition, send also for the agent itself + { + ourClient.SendRexAppearance(m_scenePresenceID, m_avatarStorageAddr); + } } public static LLObject.TextureEntry GetDefaultTextureEntry() diff --git a/OpenSim/Region/Environment/Scenes/EntityBase.cs b/OpenSim/Region/Environment/Scenes/EntityBase.cs index 82f829d9a4..53762f3e3f 100644 --- a/OpenSim/Region/Environment/Scenes/EntityBase.cs +++ b/OpenSim/Region/Environment/Scenes/EntityBase.cs @@ -101,6 +101,9 @@ namespace OpenSim.Region.Environment.Scenes set { m_localId = value; } } + // rex, added + public bool DeleteMe = false; + /// /// Creates a new Entity (should not occur on it's own) /// @@ -174,4 +177,4 @@ namespace OpenSim.Region.Environment.Scenes HitTF = _HitTF; } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/Environment/Scenes/InnerScene.cs b/OpenSim/Region/Environment/Scenes/InnerScene.cs index 8c0ba3c3df..4d014addc2 100644 --- a/OpenSim/Region/Environment/Scenes/InnerScene.cs +++ b/OpenSim/Region/Environment/Scenes/InnerScene.cs @@ -433,7 +433,7 @@ namespace OpenSim.Region.Environment.Scenes } } return returnResult; - } + } public SceneObjectPart GetSceneObjectPart(uint localID) { @@ -933,6 +933,7 @@ namespace OpenSim.Region.Environment.Scenes } m_numPrim++; copy.ScheduleGroupForFullUpdate(); + m_parentScene.EventManager.TriggerOnAddEntity(copy.RootPart.LocalID); // rex, added } } else diff --git a/OpenSim/Region/Environment/Scenes/Scene.Inventory.cs b/OpenSim/Region/Environment/Scenes/Scene.Inventory.cs index db3da4869c..91f2a76181 100644 --- a/OpenSim/Region/Environment/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Environment/Scenes/Scene.Inventory.cs @@ -32,6 +32,8 @@ using libsecondlife.Packets; using OpenSim.Framework; using OpenSim.Framework.Communications.Cache; using OpenSim.Framework.Console; +using System; +using Axiom.Math; namespace OpenSim.Region.Environment.Scenes { @@ -58,9 +60,7 @@ namespace OpenSim.Region.Environment.Scenes /// in which the item is to be placed. public void AddInventoryItem(IClientAPI remoteClient, InventoryItemBase item) { - CachedUserInfo userInfo - = CommsManager.UserProfileCacheService.GetUserDetails(remoteClient.AgentId); - + CachedUserInfo userInfo = CommsManager.UserProfileCacheService.GetUserDetails(remoteClient.AgentId); if (userInfo != null) { userInfo.AddItem(remoteClient.AgentId, item); @@ -88,6 +88,30 @@ namespace OpenSim.Region.Environment.Scenes AddInventoryItem(avatar.ControllingClient, item); } + // rex, new function related to asset replace + public bool CheckInventoryForAsset(LLUUID avatarId, LLUUID assetID) + { + ScenePresence avatar; + + if (!TryGetAvatar(avatarId, out avatar)) + { + MainLog.Instance.Error( + "AGENTINVENTORY", "Could not find avatar {0} to check inventory item for asset", avatarId); + return false; + } + + CachedUserInfo userInfo = CommsManager.UserProfileCacheService.GetUserDetails(avatar.ControllingClient.AgentId); + if (userInfo != null) + { + if (userInfo.RootFolder != null) + { + return userInfo.RootFolder.HasAssetID(assetID); + } + } + + return false; + } + /// /// Capability originating call to update the asset of an item in an agent's inventory /// @@ -159,47 +183,28 @@ namespace OpenSim.Region.Environment.Scenes /// /// The prim which contains the item to update /// Indicates whether the script to update is currently running - /// + /// + /// Asset LLUID created public void CapsUpdateTaskInventoryScriptAsset(IClientAPI remoteClient, LLUUID itemId, LLUUID primId, bool isScriptRunning, byte[] data) { - // Retrieve group - SceneObjectPart part = GetSceneObjectPart(primId); - SceneObjectGroup group = part.ParentGroup; - if (null == group) - { - MainLog.Instance.Error( - "PRIMINVENTORY", - "Prim inventory update requested for item ID {0} in prim ID {1} but this prim does not exist", - itemId, primId); + // TODO Not currently doing anything with the isScriptRunning bool - return; - } - + MainLog.Instance.Verbose( + "PRIMINVENTORY", + "Prim inventory script save functionality not yet implemented." + + " remoteClient: {0}, itemID: {1}, primID: {2}, isScriptRunning: {3}", + remoteClient, itemId, primId, isScriptRunning); + + // TODO + // Retrieve client LLUID + // Retrieve sog containing primID // Retrieve item - TaskInventoryItem item = group.GetInventoryItem(part.LocalID, itemId); - if (null == item) - { - return; - } - - // Create new asset - // XXX Hardcoding the numbers is a temporary measure - need an enumeration for this - AssetBase asset = - CreateAsset(item.name, item.desc, 10, 10, data); - AssetCache.AddAsset(asset); - + // Create new asset and add to cache // Update item with new asset - item.asset_id = asset.FullID; - group.UpdateInventoryItem(item); - group.GetProperites(remoteClient); - - // Trigger rerunning of script (use TriggerRezScript event, see RezScript) - if (isScriptRunning) - { - group.StopScript(part.LocalID, item.item_id); - group.StartScript(part.LocalID, item.item_id); - } + // Trigger SOG update (see RezScript) + // Trigger rerunning of script (use TriggerRezScript event, see RezScript) + // return new asset id } /// @@ -289,14 +294,14 @@ namespace OpenSim.Region.Environment.Scenes } else { - MainLog.Instance.Error( + MainLog.Instance.Warn( "AGENTINVENTORY", "Item ID " + itemID + " not found for an inventory item update."); } } else { - MainLog.Instance.Error( + MainLog.Instance.Warn( "AGENTINVENTORY", "Agent ID " + remoteClient.AgentId + " not found for an inventory item update."); } @@ -311,7 +316,7 @@ namespace OpenSim.Region.Environment.Scenes CachedUserInfo userInfo = CommsManager.UserProfileCacheService.GetUserDetails(oldAgentID); if (userInfo == null) { - MainLog.Instance.Error("AGENTINVENTORY", "Failed to find user " + oldAgentID.ToString()); + MainLog.Instance.Warn("AGENTINVENTORY", "Failed to find user " + oldAgentID.ToString()); return; } @@ -320,13 +325,13 @@ namespace OpenSim.Region.Environment.Scenes item = userInfo.RootFolder.HasItem(oldItemID); if (item == null) { - MainLog.Instance.Error("AGENTINVENTORY", "Failed to find item " + oldItemID.ToString()); + MainLog.Instance.Warn("AGENTINVENTORY", "Failed to find item " + oldItemID.ToString()); return; } } else { - MainLog.Instance.Error("AGENTINVENTORY", "Failed to find item " + oldItemID.ToString()); + MainLog.Instance.Warn("AGENTINVENTORY", "Failed to find item " + oldItemID.ToString()); return; } } @@ -357,6 +362,30 @@ namespace OpenSim.Region.Environment.Scenes return asset; } + // rex, added function + public void RemoveInventoryItem(IClientAPI remoteClient, LLUUID itemID) + { + MainLog.Instance.Verbose( + "AGENTINVENTORY", + "Deleting item for " + remoteClient.AgentId.ToString()); + + CachedUserInfo userInfo = CommsManager.UserProfileCacheService.GetUserDetails(remoteClient.AgentId); + if (userInfo == null) + { + MainLog.Instance.Warn("AGENTINVENTORY", "Failed to find user " + remoteClient.AgentId.ToString()); + return; + } + + if (userInfo.RootFolder != null) + { + InventoryItemBase item = userInfo.RootFolder.HasItem(itemID); + if (item != null) + { + userInfo.DeleteItem(remoteClient.AgentId, item); + } + } + } + public void MoveInventoryItem(IClientAPI remoteClient, LLUUID folderID, LLUUID itemID, int length, string newName) { @@ -367,7 +396,7 @@ namespace OpenSim.Region.Environment.Scenes CachedUserInfo userInfo = CommsManager.UserProfileCacheService.GetUserDetails(remoteClient.AgentId); if (userInfo == null) { - MainLog.Instance.Error("AGENTINVENTORY", "Failed to find user " + remoteClient.AgentId.ToString()); + MainLog.Instance.Warn("AGENTINVENTORY", "Failed to find user " + remoteClient.AgentId.ToString()); return; } @@ -388,13 +417,13 @@ namespace OpenSim.Region.Environment.Scenes } else { - MainLog.Instance.Error("AGENTINVENTORY", "Failed to find item " + itemID.ToString()); + MainLog.Instance.Warn("AGENTINVENTORY", "Failed to find item " + itemID.ToString()); return; } } else { - MainLog.Instance.Error("AGENTINVENTORY", "Failed to find item " + itemID.ToString() + ", no root folder"); + MainLog.Instance.Warn("AGENTINVENTORY", "Failed to find item " + itemID.ToString() + ", no root folder"); return; } } @@ -497,7 +526,7 @@ namespace OpenSim.Region.Environment.Scenes } else { - MainLog.Instance.Error( + MainLog.Instance.Warn( "PRIMINVENTORY", "Inventory requested of prim {0} which doesn't exist", primLocalID); } } @@ -505,8 +534,7 @@ namespace OpenSim.Region.Environment.Scenes /// /// Remove an item from a prim (task) inventory /// - /// Unused at the moment but retained since the avatar ID might - /// be necessary for a permissions check at some stage. + /// /// /// public void RemoveTaskInventory(IClientAPI remoteClient, LLUUID itemID, uint localID) @@ -514,7 +542,7 @@ namespace OpenSim.Region.Environment.Scenes SceneObjectGroup group = GetGroupByPrim(localID); if (group != null) { - int type = group.RemoveInventoryItem(localID, itemID); + int type = group.RemoveInventoryItem(remoteClient, localID, itemID); group.GetProperites(remoteClient); if (type == 10) { @@ -523,7 +551,7 @@ namespace OpenSim.Region.Environment.Scenes } else { - MainLog.Instance.Error( + MainLog.Instance.Warn( "PRIMINVENTORY", "Removal of item {0} requested of prim {1} but this prim does not exist", itemID, @@ -686,6 +714,7 @@ namespace OpenSim.Region.Environment.Scenes public void DeleteSceneObjectGroup(SceneObjectGroup group) { + EventManager.TriggerOnRemoveEntity(group.LocalId); // rex, added SceneObjectPart rootPart = (group).GetChildPart(group.UUID); if (rootPart.PhysActor != null) { @@ -747,6 +776,87 @@ namespace OpenSim.Region.Environment.Scenes } } + protected void ObjectAttach(IClientAPI remoteClient, uint localID, LLQuaternion rotation, byte attachPoint) + { + System.Console.WriteLine("Attaching object " + localID + " to " + attachPoint); + SceneObjectPart p = GetSceneObjectPart(localID); + ScenePresence av = null; + if (TryGetAvatar(remoteClient.AgentId, out av)) + { + p.AttachToAvatar(remoteClient.AgentId, av, attachPoint, rotation, m_regInfo); + } + } + + protected void ObjectDetach(IClientAPI remoteClient, uint localID) + { + ScenePresence av = null; + if (TryGetAvatar(remoteClient.AgentId, out av)) + { + SceneObjectPart p = GetSceneObjectPart(localID); + + //Place the object in front of the avatar + Vector3 vecDir = new Vector3(1, 0, 0); + float dist = p.Scale.X + 0.1f; + vecDir = (av.Rotation * vecDir) * dist; + + p.ParentGroup.AbsolutePosition = av.AbsolutePosition + new LLVector3(vecDir.x, vecDir.y, vecDir.z); + p.RotationOffset = new LLQuaternion(av.Rotation.x, av.Rotation.y, av.Rotation.z, av.Rotation.w); + p.Detach(); + } + else + { + MainLog.Instance.Warn("SCENE", "Object detach - Unable to find avatar " + remoteClient.FirstName + " " + remoteClient.LastName); + } + } + + protected void SingleAttachmentFromInv(IClientAPI remoteClient, LLUUID itemID, LLUUID ownerID, + uint itemFlags, byte attachPoint) + { + MainLog.Instance.Verbose("SCENE", "SingleAttachmentFromInv for " + remoteClient.FirstName + " " + remoteClient.LastName + ": " + + "itemID=" + itemID + " ownerID=" + ownerID + " itemFlags=" + itemFlags+ + "attachPoint=" + attachPoint); + CachedUserInfo userInfo = CommsManager.UserProfileCacheService.GetUserDetails(remoteClient.AgentId); + if (userInfo != null) + { + if (userInfo.RootFolder != null) + { + InventoryItemBase item = userInfo.RootFolder.HasItem(itemID); + if (item != null) + { + AssetBase rezAsset = AssetCache.GetAsset(item.assetID, false); + if (rezAsset != null) + { + MainLog.Instance.Verbose("SCENE", "Adding inventory item to scene"); + ScenePresence presence = GetScenePresence(remoteClient.AgentId); + + SceneObjectGroup group = new SceneObjectGroup(this, m_regionHandle, Helpers.FieldToUTF8String(rezAsset.Data)); + group.GenerateNewIDs(); + AddEntity(group); + + group.AbsolutePosition = presence.AbsolutePosition; + SceneObjectPart rootPart = group.GetChildPart(group.UUID); + rootPart.RotationOffset = new LLQuaternion(presence.Rotation.x, presence.Rotation.y, presence.Rotation.z, presence.Rotation.w); + rootPart.ApplySanePermissions(); + MainLog.Instance.Verbose("SCENE", "Attaching it to a scene presence"); + rootPart.AttachToAvatar(remoteClient.AgentId, presence, attachPoint, new LLQuaternion(0, 0, 0, 1), m_regInfo); + } + } + else + { + MainLog.Instance.Warn("SCENE", "RezAttach - Item not found from folder"); + } + } + else + { + MainLog.Instance.Warn("SCENE", "RezAttach - No root folder found"); + } + } + else + { + MainLog.Instance.Warn("SCENE", "RezAttach - Unable to get userInfo for " + remoteClient.FirstName + " " + remoteClient.LastName); + } + } + private void AddRezObject(string xmlData, LLVector3 pos) { SceneObjectGroup group = new SceneObjectGroup(this, m_regionHandle, xmlData); diff --git a/OpenSim/Region/Environment/Scenes/Scene.PacketHandlers.cs b/OpenSim/Region/Environment/Scenes/Scene.PacketHandlers.cs index 5a7d4decf4..891b1d29ca 100644 --- a/OpenSim/Region/Environment/Scenes/Scene.PacketHandlers.cs +++ b/OpenSim/Region/Environment/Scenes/Scene.PacketHandlers.cs @@ -176,7 +176,7 @@ namespace OpenSim.Region.Environment.Scenes agentData.AgentID = avatarID; agentData.QueryID = RequestID; replyPacket.AgentData = agentData; - //byte[] bytes = new byte[AvatarResponses.Count*32]; + byte[] bytes = new byte[AvatarResponses.Count*32]; int i = 0; foreach (AvatarPickerAvatar item in AvatarResponses) @@ -195,5 +195,12 @@ namespace OpenSim.Region.Environment.Scenes replyPacket.Data = searchData; client.SendAvatarPickerReply(replyPacket); } + + // rex, added + public void ProcessRexClientScriptCommand(IClientAPI remoteClient,LLUUID agentID,List vParams) + { + EventManager.TriggerOnRexClientScriptCommand(GetScenePresence(agentID), vParams); + } + } } diff --git a/OpenSim/Region/Environment/Scenes/Scene.cs b/OpenSim/Region/Environment/Scenes/Scene.cs index d8733f42df..25cc5955b8 100644 --- a/OpenSim/Region/Environment/Scenes/Scene.cs +++ b/OpenSim/Region/Environment/Scenes/Scene.cs @@ -78,6 +78,7 @@ namespace OpenSim.Region.Environment.Scenes private readonly Mutex updateLock; public bool m_physicalPrim; public bool m_sendTasksToChild; + public bool m_rexMode;//rex private int m_RestartTimerCounter; private readonly Timer m_restartTimer = new Timer(15000); // Wait before firing private int m_incrementsof15seconds = 0; @@ -127,6 +128,51 @@ namespace OpenSim.Region.Environment.Scenes #endregion + #region realXtend + //REX + public void UpdateAssetMediaURL(IClientAPI remoteClient, LLUUID itemID, string mediaUrl) + { + + + AssetRequestCallback callback = delegate(LLUUID id, AssetBase asset) + { + UpdateAssetMediaURLRequest(id, asset, mediaUrl); + }; + + AssetCache.GetAsset(itemID, callback); + } + + public void UpdateAssetMediaURLRequest(LLUUID id, AssetBase asset, string mediaUrl) + { + if (asset != null) + { + asset.MediaURL = mediaUrl; + AssetCache.ReplaceAsset(asset); + + //Send it to all clients + ClientManager.ForEachClient(delegate(IClientAPI client) + { + client.SendMediaURL(id, mediaUrl); + } + ); + } + else + { + MainLog.Instance.Verbose("INVENTORY", "Unable to set MediaURL for " + id + ": texture/asset not found"); + } + } + #endregion + + public void ClientTriggeredSound(IClientAPI remoteClient, LLUUID soundID, LLUUID ownerID, LLUUID objectID, LLUUID parentID, ulong handle, LLVector3 position, float gain) + { + ClientManager.ForEachClient(delegate(IClientAPI client) + { + // TODO: some filtering by distance of avatar + client.SendTriggeredSound(soundID, ownerID, objectID, parentID, handle, position, gain); + } + ); + } + #region Properties public AgentCircuitManager AuthenticateHandler @@ -211,8 +257,10 @@ namespace OpenSim.Region.Environment.Scenes public Scene(RegionInfo regInfo, AgentCircuitManager authen, PermissionManager permissionManager, CommunicationsManager commsMan, SceneCommunicationService sceneGridService, AssetCache assetCach, StorageManager storeManager, BaseHttpServer httpServer, - ModuleLoader moduleLoader, bool dumpAssetsToFile, bool physicalPrim, bool SendTasksToChild) + ModuleLoader moduleLoader, bool dumpAssetsToFile, bool physicalPrim, bool SendTasksToChild, + bool rexMode)//rex { + m_rexMode = rexMode;//rex updateLock = new Mutex(false); m_moduleLoader = moduleLoader; @@ -722,6 +770,20 @@ namespace OpenSim.Region.Environment.Scenes return true; } + // rex, new function + public bool ForcedBackup() + { + List EntitiesList = GetEntities(); + foreach (EntityBase ent in EntitiesList) + { + if (ent is SceneObjectGroup) + { + ((SceneObjectGroup)ent).HasChanged = true; + } + } + return Backup(); + } + #endregion #region Load Terrain @@ -907,8 +969,11 @@ namespace OpenSim.Region.Environment.Scenes rootPart.AbsolutePosition.Z), new PhysicsVector(rootPart.Scale.X, rootPart.Scale.Y, rootPart.Scale.Z), new Quaternion(rootPart.RotationOffset.W, rootPart.RotationOffset.X, - rootPart.RotationOffset.Y, rootPart.RotationOffset.Z), UsePhysics); + rootPart.RotationOffset.Y, rootPart.RotationOffset.Z), UsePhysics, rootPart.LocalID); rootPart.DoPhysicsPropertyUpdate(UsePhysics, true); + // rex added, load 3d collision model. + rootPart.GetRexParameters(); + rootPart.RexUpdateCollisionMesh(); } MainLog.Instance.Verbose("SCENE", "Loaded " + PrimsFromDB.Count.ToString() + " SceneObject(s)"); @@ -1053,14 +1118,58 @@ namespace OpenSim.Region.Environment.Scenes rootPart.Shape, new PhysicsVector(pos.X, pos.Y, pos.Z), new PhysicsVector(shape.Scale.X, shape.Scale.Y, shape.Scale.Z), - new Quaternion(), UsePhysics); + new Quaternion(rootPart.RotationOffset.W, rootPart.RotationOffset.X, + rootPart.RotationOffset.Y, rootPart.RotationOffset.Z), UsePhysics, rootPart.LocalID); // rex, use rootPart.RotationOffset as rotation // subscribe to physics events. rootPart.DoPhysicsPropertyUpdate(UsePhysics, true); + // rex added, load 3d collision model + rootPart.GetRexParameters(); + rootPart.RexUpdateCollisionMesh(); } + EventManager.TriggerOnAddEntity(rootPart.LocalID); // rex, added } + // rex, new function + public uint AddNewPrimReturningId(LLUUID ownerID, LLVector3 pos, LLQuaternion rot, PrimitiveBaseShape shape, bool vbTemp, string vPyClass) + { + SceneObjectGroup sceneOb = + new SceneObjectGroup(this, m_regionHandle, ownerID, PrimIDAllocate(), pos, rot, shape, vbTemp, vPyClass); + AddEntity(sceneOb); + SceneObjectPart rootPart = sceneOb.GetChildPart(sceneOb.UUID); + // if grass or tree, make phantom + //rootPart.ApplySanePermissions(); + if ((rootPart.Shape.PCode == 95) || (rootPart.Shape.PCode == 255) || (rootPart.Shape.PCode == 111)) + { + rootPart.AddFlag(LLObject.ObjectFlags.Phantom); + //rootPart.ObjectFlags += (uint)LLObject.ObjectFlags.Phantom; + } + // if not phantom, add to physics + bool UsePhysics = (((rootPart.ObjectFlags & (uint)LLObject.ObjectFlags.Physics) > 0) && m_physicalPrim); + if ((rootPart.ObjectFlags & (uint)LLObject.ObjectFlags.Phantom) == 0) + { + rootPart.PhysActor = + PhysicsScene.AddPrimShape( + rootPart.Name, + rootPart.Shape, + new PhysicsVector(pos.X, pos.Y, pos.Z), + new PhysicsVector(shape.Scale.X, shape.Scale.Y, shape.Scale.Z), + new Quaternion(rootPart.RotationOffset.W, rootPart.RotationOffset.X, + rootPart.RotationOffset.Y, rootPart.RotationOffset.Z), UsePhysics, rootPart.LocalID); // rex, use rootPart.RotationOffset as rotation + // subscribe to physics events. + rootPart.DoPhysicsPropertyUpdate(UsePhysics, true); + // rex added, load 3d collision model + rootPart.GetRexParameters(); + rootPart.RexUpdateCollisionMesh(); + } + EventManager.TriggerOnAddEntity(rootPart.LocalID); // rex, added + return rootPart.LocalID; + } + + + + public void AddTree(LLVector3 scale, LLQuaternion rotation, LLVector3 position, - Tree treeType, bool newTree) + libsecondlife.Tree treeType, bool newTree) { PrimitiveBaseShape treeShape = new PrimitiveBaseShape(); treeShape.PathCurve = 16; @@ -1137,15 +1246,65 @@ namespace OpenSim.Region.Environment.Scenes /// public override void AddNewClient(IClientAPI client, bool child) { + /* + String storageaddress; + + if (!CommsManager.UserService.AuthenticateUser(client.AgentId, client.SessionId.ToString(), out storageaddress)) { + client.Kick("User authentication failed."); + } + else { // first authenticate and then do inits //rex + SubscribeToClientEvents(client); + m_estateManager.sendRegionHandshake(client); + if (!m_rexMode) { + CreateAndAddScenePresence(client, child); + } + else { + CreateAndAddRexScenePresence(client, child, storageaddress); + } + m_LandManager.sendParcelOverlay(client); + string authAddr = m_authenticateHandler.AgentCircuits[client.CircuitCode].authenticationAddr; + + if (m_rexMode) + { + CommsManager.UserProfileCacheService.AddNewUser(client.AgentId, authAddr); + } + else + { + CommsManager.UserProfileCacheService.AddNewUser(client.AgentId); + } + + CommsManager.TransactionsManager.AddUser(client.AgentId); + }/*/ SubscribeToClientEvents(client); - m_estateManager.sendRegionHandshake(client); - - CreateAndAddScenePresence(client, child); - + if (!m_rexMode) + { + CreateAndAddScenePresence(client, child); + } + else + { + if (!m_authenticateHandler.AgentCircuits.ContainsKey(client.CircuitCode)) + { + client.Kick("User login failed. No circuit code."); + } + else + { + CreateAndAddRexScenePresence(client, child, m_authenticateHandler.AgentCircuits[client.CircuitCode].asAddress); + } + } m_LandManager.sendParcelOverlay(client); - CommsManager.UserProfileCacheService.AddNewUser(client.AgentId); + string authAddr = m_authenticateHandler.AgentCircuits[client.CircuitCode].authenticationAddr; + if (m_rexMode) + { + CommsManager.UserProfileCacheService.AddNewUser(client.AgentId, authAddr); + } + else + { + CommsManager.UserProfileCacheService.AddNewUser(client.AgentId); + } + CommsManager.TransactionsManager.AddUser(client.AgentId); + //*/ } protected virtual void SubscribeToClientEvents(IClientAPI client) @@ -1208,10 +1367,15 @@ namespace OpenSim.Region.Environment.Scenes client.OnUpdateInventoryItem += UpdateInventoryItemAsset; client.OnCopyInventoryItem += CopyInventoryItem; client.OnMoveInventoryItem += MoveInventoryItem; + client.OnRemoveInventoryItem += RemoveInventoryItem; // rex client.OnAssetUploadRequest += CommsManager.TransactionsManager.HandleUDPUploadRequest; client.OnXferReceive += CommsManager.TransactionsManager.HandleXfer; client.OnRezScript += RezScript; + client.OnRezSingleAttachmentFromInv += SingleAttachmentFromInv; + client.OnObjectAttach += ObjectAttach; + client.OnObjectDetach += ObjectDetach; + client.OnRequestTaskInventory += RequestTaskInventory; client.OnRemoveTaskItem += RemoveTaskInventory; client.OnUpdateTaskInventory += UpdateTaskInventory; @@ -1219,23 +1383,38 @@ namespace OpenSim.Region.Environment.Scenes client.OnGrabObject += ProcessObjectGrab; client.OnAvatarPickerRequest += ProcessAvatarPickerRequest; + client.OnReceiveRexClientScriptCmd += ProcessRexClientScriptCommand; // rex + client.OnObjectClickAction += HandleObjectClickAction; // rex + client.OnUpdateAssetMediaURL += UpdateAssetMediaURL; // rex + + client.OnTriggerSound += ClientTriggeredSound; + EventManager.TriggerOnNewClient(client); } protected virtual ScenePresence CreateAndAddScenePresence(IClientAPI client, bool child) { - ScenePresence avatar = null; - AvatarAppearance appearance; GetAvatarAppearance(client, out appearance); + return CreateAndAddScenePresenceCommon(client, child, appearance); + } + protected virtual ScenePresence CreateAndAddRexScenePresence(IClientAPI client, bool child, string avatarstorage) //rex + { + AvatarAppearance appearance; + appearance = new AvatarAppearance(client.AgentId, avatarstorage); + return CreateAndAddScenePresenceCommon(client, child, appearance); + } + + private ScenePresence CreateAndAddScenePresenceCommon(IClientAPI client, bool child, AvatarAppearance appearance) + { + ScenePresence avatar = null; avatar = m_innerScene.CreateAndAddScenePresence(client, child, appearance); - if (avatar.IsChildAgent) { avatar.OnSignificantClientMovement += m_LandManager.handleSignificantClientMovement; } - + EventManager.TriggerOnNewPresence(avatar);//rex return avatar; } @@ -1257,8 +1436,51 @@ namespace OpenSim.Region.Environment.Scenes /// /// public override void RemoveClient(LLUUID agentID) + { + CommonRemoveClient(agentID); + // Remove client agent from profile, so new logins will work + + } + + /// + /// Called in rex mode + /// + /// + /// + public override void RemoveClient(LLUUID agentID, uint circuitCode) { ScenePresence avatar = GetScenePresence(agentID); + string authAddr = m_authenticateHandler.AgentCircuits[circuitCode].authenticationAddr; + try + { + + float x = Convert.ToSingle(Math.Round(avatar.AbsolutePosition.X)); + float y = Convert.ToSingle(Math.Round(avatar.AbsolutePosition.Y)); + float z = Convert.ToSingle(Math.Round(avatar.AbsolutePosition.Z)); + LLVector3 currentPos = new LLVector3(x, y, z); + + if (authAddr != null) + { + CommsManager.UserService.UpdateUserAgentData(agentID, false, currentPos, Util.UnixTimeSinceEpoch(), authAddr); + } + else + { + CommsManager.UserService.UpdateUserAgentData(agentID, false, currentPos, Util.UnixTimeSinceEpoch(), ""); + } + } + catch (Exception e) + { + Console.WriteLine(e.ToString()); + } + CommonRemoveClient(agentID); + CommsManager.UserService.clearUserAgent(agentID, authAddr); + + } + + private void CommonRemoveClient(LLUUID agentID) + { + ScenePresence avatar = GetScenePresence(agentID); + try { if (avatar.IsChildAgent) @@ -1314,10 +1536,10 @@ namespace OpenSim.Region.Environment.Scenes MainLog.Instance.Error("Scene.cs:RemoveClient exception: " + e.ToString()); } - // Remove client agent from profile, so new logins will work - CommsManager.UserService.clearUserAgent(agentID); } + + public override void CloseAllAgents(uint circuitcode) { // Called by ClientView to kill all circuit codes @@ -1413,6 +1635,7 @@ namespace OpenSim.Region.Environment.Scenes } cap.AddNewInventoryItem = AddInventoryItem; + cap.CheckInventoryForAsset = CheckInventoryForAsset; cap.ItemUpdatedCall = CapsUpdateInventoryItemAsset; cap.TaskScriptUpdatedCall = CapsUpdateTaskInventoryScriptAsset; @@ -1669,6 +1892,14 @@ namespace OpenSim.Region.Environment.Scenes } } + public void SendDialogToUser(LLUUID avatarID, string objectName, LLUUID objectID, LLUUID ownerID, string message, LLUUID TextureID, int ch, string[] buttonlabels) + { + if (m_scenePresences.ContainsKey(avatarID)) + { + m_scenePresences[avatarID].ControllingClient.SendDialog(objectName, objectID, ownerID, message, TextureID, ch, buttonlabels); + } + } + /// /// /// @@ -1953,6 +2184,22 @@ namespace OpenSim.Region.Environment.Scenes } } + //REX + public void HandleObjectClickAction(IClientAPI controller, uint objId, byte clickAction) + { + SceneObjectPart objectPart = GetSceneObjectPart(objId); + if (objectPart != null && PermissionsMngr.CanEditObject(controller.AgentId, objectPart.UUID)) + { + objectPart.ClickAction = clickAction; + MainLog.Instance.Verbose("SCENE", "Updating clickaction"); + } + else + { + MainLog.Instance.Verbose("SCENE", "Tried updating clickaction, but object was not found or incorrect permission"); + } + } + + /// /// /// @@ -2163,6 +2410,7 @@ namespace OpenSim.Region.Environment.Scenes #region InnerScene wrapper methods + /// /// /// diff --git a/OpenSim/Region/Environment/Scenes/SceneBase.cs b/OpenSim/Region/Environment/Scenes/SceneBase.cs index d4a4bb071e..8ec4eb51a0 100644 --- a/OpenSim/Region/Environment/Scenes/SceneBase.cs +++ b/OpenSim/Region/Environment/Scenes/SceneBase.cs @@ -84,6 +84,14 @@ namespace OpenSim.Region.Environment.Scenes set { m_regStatus = value; } } + public bool RexMode + { + get { return m_rexMode; } + set { m_rexMode = value; } + } + public bool m_rexMode; + + #endregion #region Update Methods @@ -128,6 +136,7 @@ namespace OpenSim.Region.Environment.Scenes /// /// public abstract void RemoveClient(LLUUID agentID); + public abstract void RemoveClient(LLUUID agentID, uint circuitCode); public abstract void CloseAllAgents(uint circuitcode); diff --git a/OpenSim/Region/Environment/Scenes/SceneEvents.cs b/OpenSim/Region/Environment/Scenes/SceneEvents.cs index 739f86d6ad..6d2f4557fd 100644 --- a/OpenSim/Region/Environment/Scenes/SceneEvents.cs +++ b/OpenSim/Region/Environment/Scenes/SceneEvents.cs @@ -28,6 +28,7 @@ using libsecondlife; using System; +using System.Collections.Generic; using OpenSim.Framework; using OpenSim.Region.Environment.Interfaces; using OpenSim.Region.Environment.LandManagement; @@ -125,7 +126,25 @@ namespace OpenSim.Region.Environment.Scenes public event NewGridInstantMessage OnGridInstantMessageToGroupsModule; + // rex, new events + public delegate void OnAddEntityDelegate(uint localID); + public event OnAddEntityDelegate OnAddEntity; + public delegate void OnRemoveEntityDelegate(uint localID); + public event OnRemoveEntityDelegate OnRemoveEntity; + + public delegate void OnPythonScriptCommandDelegate(string vCommand); + public event OnPythonScriptCommandDelegate OnPythonScriptCommand; + + public delegate void OnChangePythonClassDelegate(uint localID); + public event OnChangePythonClassDelegate OnPythonClassChange; + + public delegate void OnRexScriptCommandDelegate(ScenePresence avatar,List vCommands); + public event OnRexScriptCommandDelegate OnRexClientScriptCommand; + + public delegate void OnPrimVolumeCollisionDelegate(uint ownID, uint colliderID); + public event OnPrimVolumeCollisionDelegate OnPrimVolumeCollision; + // rex-end public void TriggerOnClientMovement(ScenePresence avatar) { @@ -301,5 +320,48 @@ namespace OpenSim.Region.Environment.Scenes } } + // rex, new function + public void TriggerOnAddEntity(uint localID) + { + if (OnAddEntity != null) + OnAddEntity(localID); + } + + // rex, new function + public void TriggerOnRemoveEntity(uint localID) + { + if (OnRemoveEntity != null) + OnRemoveEntity(localID); + } + + // rex, new function + public void TriggerOnPythonScriptCommand(string vCommand) + { + if (OnPythonScriptCommand != null) + OnPythonScriptCommand(vCommand); + } + + // rex, new function + public void TriggerOnChangePythonClass(uint localID) + { + if (OnPythonClassChange != null) + OnPythonClassChange(localID); + } + + // rex, new function + public void TriggerOnRexClientScriptCommand(ScenePresence avatar, List vCommands) + { + if (OnRexClientScriptCommand != null) + OnRexClientScriptCommand(avatar, vCommands); + } + + // rex, new function + public void TriggerOnPrimVolumeCollision(uint ownID,uint colliderID) + { + if (OnPrimVolumeCollision != null) + OnPrimVolumeCollision(ownID, colliderID); + } + + } } \ No newline at end of file diff --git a/OpenSim/Region/Environment/Scenes/SceneManager.cs b/OpenSim/Region/Environment/Scenes/SceneManager.cs index 1eac61bbc9..be811afb90 100644 --- a/OpenSim/Region/Environment/Scenes/SceneManager.cs +++ b/OpenSim/Region/Environment/Scenes/SceneManager.cs @@ -196,6 +196,12 @@ namespace OpenSim.Region.Environment.Scenes ForEachCurrentScene(delegate(Scene scene) { scene.SendCommandToPlugins(cmdparams); }); } + // rex new function + public void SendPythonScriptCommand(string[] cmdparams) + { + ForEachCurrentScene(delegate(Scene scene) { scene.EventManager.TriggerOnPythonScriptCommand(cmdparams[0]); }); + } + public void SetBypassPermissionsOnCurrentScene(bool bypassPermissions) { ForEachCurrentScene(delegate(Scene scene) { scene.PermissionsMngr.BypassPermissions = bypassPermissions; }); @@ -223,6 +229,12 @@ namespace OpenSim.Region.Environment.Scenes ForEachCurrentScene(delegate(Scene scene) { scene.Backup(); }); } + // rex, new function + public void ForcedBackupCurrentScene() + { + ForEachCurrentScene(delegate(Scene scene) { scene.ForcedBackup(); }); + } + public void HandleAlertCommandOnCurrentScene(string[] cmdparams) { ForEachCurrentScene(delegate(Scene scene) { scene.HandleAlertCommand(cmdparams); }); diff --git a/OpenSim/Region/Environment/Scenes/SceneObjectGroup.Inventory.cs b/OpenSim/Region/Environment/Scenes/SceneObjectGroup.Inventory.cs index 4d25b5d952..b72d743564 100644 --- a/OpenSim/Region/Environment/Scenes/SceneObjectGroup.Inventory.cs +++ b/OpenSim/Region/Environment/Scenes/SceneObjectGroup.Inventory.cs @@ -60,27 +60,6 @@ namespace OpenSim.Region.Environment.Scenes } } -// /// Start a given script. -// /// -// /// -// /// A -// /// -// public void StartScript(LLUUID partID, LLUUID itemID) -// { -// SceneObjectPart part = GetChildPart(partID); -// if (part != null) -// { -// part.StartScript(itemID); -// } -// else -// { -// MainLog.Instance.Error( -// "PRIMINVENTORY", -// "Couldn't find part {0} in object group {1}, {2} to start script with ID {3}", -// localID, Name, UUID, itemID); -// } -// } - /// /// Start the scripts contained in all the prims in this group. /// @@ -92,27 +71,6 @@ namespace OpenSim.Region.Environment.Scenes } } - /// Start a given script. - /// - /// - /// A - /// - public void StopScript(uint partID, LLUUID itemID) - { - SceneObjectPart part = GetChildPart(partID); - if (part != null) - { - part.StopScript(itemID); - } - else - { - MainLog.Instance.Error( - "PRIMINVENTORY", - "Couldn't find part {0} in object group {1}, {2} to stop script with ID {3}", - partID, Name, UUID, itemID); - } - } - /// /// /// @@ -198,63 +156,13 @@ namespace OpenSim.Region.Environment.Scenes return false; } - - /// - /// Returns an existing inventory item. Returns the original, so any changes will be live. - /// - /// - /// - /// null if the item does not exist - public TaskInventoryItem GetInventoryItem(uint primID, LLUUID itemID) - { - SceneObjectPart part = GetChildPart(primID); - if (part != null) - { - return part.GetInventoryItem(itemID); - } - else - { - MainLog.Instance.Error( - "PRIMINVENTORY", - "Couldn't find prim local ID {0} in prim {1}, {2} to get inventory item ID {3}", - primID, part.Name, part.UUID, itemID); - } - - return null; - } - - /// - /// Update an existing inventory item. - /// - /// The updated item. An item with the same id must already exist - /// in this prim's inventory - /// false if the item did not exist, true if the update occurred succesfully - public bool UpdateInventoryItem(TaskInventoryItem item) - { - SceneObjectPart part = GetChildPart(item.ParentPartID); - if (part != null) - { - part.UpdateInventoryItem(item); - - return true; - } - else - { - MainLog.Instance.Error( - "PRIMINVENTORY", - "Couldn't find prim ID {0} to update item {1}, {2}", - item.ParentPartID, item.name, item.item_id); - } - - return false; - } - public int RemoveInventoryItem(uint localID, LLUUID itemID) + public int RemoveInventoryItem(IClientAPI remoteClient, uint localID, LLUUID itemID) { SceneObjectPart part = GetChildPart(localID); if (part != null) { - int type = part.RemoveInventoryItem(itemID); + int type = part.RemoveInventoryItem(remoteClient, localID, itemID); // It might seem somewhat crude to update the whole group for a single prim inventory change, // but it's possible that other prim inventory changes will take place before the region @@ -269,4 +177,4 @@ namespace OpenSim.Region.Environment.Scenes return -1; } } -} +} \ No newline at end of file diff --git a/OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs index c623e5568e..93ae607f27 100644 --- a/OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs @@ -56,6 +56,7 @@ namespace OpenSim.Region.Environment.Scenes public event PrimCountTaintedDelegate OnPrimCountTainted; public bool HasChanged = false; + public bool TemporaryPrim = false; // rex private LLVector3 lastPhysGroupPos; private LLQuaternion lastPhysGroupRot; @@ -375,9 +376,8 @@ namespace OpenSim.Region.Environment.Scenes foreach (SceneObjectPart part in m_parts.Values) { - // Temporary commented to stop compiler warning - //Vector3 partPosition = - // new Vector3(part.AbsolutePosition.X, part.AbsolutePosition.Y, part.AbsolutePosition.Z); + Vector3 partPosition = + new Vector3(part.AbsolutePosition.X, part.AbsolutePosition.Y, part.AbsolutePosition.Z); Quaternion parentrotation = new Quaternion(GroupRotation.W, GroupRotation.X, GroupRotation.Y, GroupRotation.Z); @@ -446,6 +446,15 @@ namespace OpenSim.Region.Environment.Scenes { } + // Rex, new constructor + public SceneObjectGroup(Scene scene, ulong regionHandle, LLUUID ownerID, uint localID, LLVector3 pos, + LLQuaternion rot, PrimitiveBaseShape shape, bool vbTempPrim, string vPyClass) + : this(scene, regionHandle, ownerID, localID, pos, rot, shape) + { + TemporaryPrim = vbTempPrim; + m_rootPart.m_RexClassName = vPyClass; + } + #endregion public string ToXmlString() @@ -543,7 +552,7 @@ namespace OpenSim.Region.Environment.Scenes new PhysicsVector(dupe.RootPart.Scale.X, dupe.RootPart.Scale.Y, dupe.RootPart.Scale.Z), new Quaternion(dupe.RootPart.RotationOffset.W, dupe.RootPart.RotationOffset.X, dupe.RootPart.RotationOffset.Y, dupe.RootPart.RotationOffset.Z), - dupe.RootPart.PhysActor.IsPhysical); + dupe.RootPart.PhysActor.IsPhysical, dupe.LocalId); dupe.RootPart.DoPhysicsPropertyUpdate(dupe.RootPart.PhysActor.IsPhysical, true); } // Now we've made a copy that replaces this one, we need to @@ -678,6 +687,11 @@ namespace OpenSim.Region.Environment.Scenes /// public override void Update() { + if (DeleteMe) // rex, added + { + m_scene.DeleteSceneObjectGroup(this); + return; + } if (Util.GetDistanceTo(lastPhysGroupPos, AbsolutePosition) > 0.02) { foreach (SceneObjectPart part in m_parts.Values) @@ -828,8 +842,10 @@ namespace OpenSim.Region.Environment.Scenes /// public bool HasChildPrim(LLUUID primID) { + SceneObjectPart childPart = null; if (m_parts.ContainsKey(primID)) { + childPart = m_parts[primID]; return true; } return false; @@ -969,7 +985,7 @@ namespace OpenSim.Region.Environment.Scenes new PhysicsVector(linkPart.Scale.X, linkPart.Scale.Y, linkPart.Scale.Z), new Quaternion(linkPart.RotationOffset.W, linkPart.RotationOffset.X, linkPart.RotationOffset.Y, linkPart.RotationOffset.Z), - m_rootPart.PhysActor.IsPhysical); + m_rootPart.PhysActor.IsPhysical, linkPart.LocalID); m_rootPart.DoPhysicsPropertyUpdate(m_rootPart.PhysActor.IsPhysical, true); } @@ -1206,7 +1222,7 @@ namespace OpenSim.Region.Environment.Scenes new PhysicsVector(m_rootPart.Scale.X, m_rootPart.Scale.Y, m_rootPart.Scale.Z), new Quaternion(m_rootPart.RotationOffset.W, m_rootPart.RotationOffset.X, m_rootPart.RotationOffset.Y, m_rootPart.RotationOffset.Z), - m_rootPart.PhysActor.IsPhysical); + m_rootPart.PhysActor.IsPhysical, m_rootPart.LocalID); bool UsePhysics = ((m_rootPart.ObjectFlags & (uint) LLObject.ObjectFlags.Physics) != 0); m_rootPart.DoPhysicsPropertyUpdate(UsePhysics, true); @@ -1461,6 +1477,12 @@ namespace OpenSim.Region.Environment.Scenes /// public void ProcessBackup(IRegionDataStore datastore) { + // Rex, temporary prims not saved to database! + if (TemporaryPrim) + { + HasChanged = false; + return; + } if (HasChanged) { datastore.StoreObject(this, m_scene.RegionInfo.RegionID); diff --git a/OpenSim/Region/Environment/Scenes/SceneObjectPart.Inventory.cs b/OpenSim/Region/Environment/Scenes/SceneObjectPart.Inventory.cs index 5d197e3e4d..9e2c256956 100644 --- a/OpenSim/Region/Environment/Scenes/SceneObjectPart.Inventory.cs +++ b/OpenSim/Region/Environment/Scenes/SceneObjectPart.Inventory.cs @@ -144,26 +144,7 @@ namespace OpenSim.Region.Environment.Scenes itemId, Name, UUID); } - } - - /// - /// Stop a script which is in this prim's inventory. - /// - /// - public void StopScript(LLUUID itemId) - { - if (m_taskInventory.ContainsKey(itemId)) - { - m_parentGroup.Scene.EventManager.TriggerRemoveScript(LocalID, itemId); - } - else - { - MainLog.Instance.Error( - "PRIMINVENTORY", - "Couldn't stop script with ID {0} since it couldn't be found for prim {1}, {2}", - itemId, Name, UUID); - } - } + } /// /// Add an item to this prim's inventory. @@ -192,85 +173,33 @@ namespace OpenSim.Region.Environment.Scenes m_inventorySerial++; } - - /// - /// Returns an existing inventory item. Returns the original, so any changes will be live. - /// - /// - /// null if the item does not exist - public TaskInventoryItem GetInventoryItem(LLUUID itemID) - { - if (m_taskInventory.ContainsKey(itemID)) - { - return m_taskInventory[itemID]; - } - else - { - MainLog.Instance.Error( - "PRIMINVENTORY", - "Tried to retrieve item ID {0} from prim {1}, {2} but the item does not exist in this inventory", - itemID, Name, UUID); - } - - return null; - } - - /// - /// Update an existing inventory item. - /// - /// The updated item. An item with the same id must already exist - /// in this prim's inventory. - /// false if the item did not exist, true if the update occurred succesfully - public bool UpdateInventoryItem(TaskInventoryItem item) - { - if (m_taskInventory.ContainsKey(item.item_id)) - { - m_taskInventory[item.item_id] = item; - m_inventorySerial++; - - return true; - } - else - { - MainLog.Instance.Error( - "PRIMINVENTORY", - "Tried to retrieve item ID {0} from prim {1}, {2} but the item does not exist in this inventory", - item.item_id, Name, UUID); - } - - return false; - } /// /// Remove an item from this prim's inventory /// + /// + /// /// - /// Numeric asset type of the item removed. Returns -1 if the item did not exist - /// in this prim's inventory. - public int RemoveInventoryItem(LLUUID itemID) + /// Numeric asset type of the item removed. + public int RemoveInventoryItem(IClientAPI remoteClient, uint localID, LLUUID itemID) { - if (m_taskInventory.ContainsKey(itemID)) + if (localID == LocalID) { - string type = m_taskInventory[itemID].inv_type; - m_taskInventory.Remove(itemID); - m_inventorySerial++; - if (type == "lsltext") + if (m_taskInventory.ContainsKey(itemID)) { - return 10; - } - else - { - return 0; + string type = m_taskInventory[itemID].inv_type; + m_taskInventory.Remove(itemID); + m_inventorySerial++; + if (type == "lsltext") + { + return 10; + } + else + { + return 0; + } } } - else - { - MainLog.Instance.Error( - "PRIMINVENTORY", - "Tried to remove item ID {0} from prim {1}, {2} but the item does not exist in this inventory", - itemID, Name, UUID); - } - return -1; } diff --git a/OpenSim/Region/Environment/Scenes/SceneObjectPart.cs b/OpenSim/Region/Environment/Scenes/SceneObjectPart.cs index 5a02ad4c32..49e4137e72 100644 --- a/OpenSim/Region/Environment/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Environment/Scenes/SceneObjectPart.cs @@ -27,6 +27,7 @@ */ using System; +using System.Text; // rex, StringBuilder needed using System.Collections.Generic; using System.Drawing; using System.Xml; @@ -93,6 +94,46 @@ namespace OpenSim.Region.Environment.Scenes /// private byte m_updateFlag; + // rex, extra parameters & their definitions + + // reX extra block parameters in easily readable format + public string m_RexClassName = ""; + public byte m_RexFlags = 0; + public byte m_RexCollisionType = 0; + public float m_RexDrawDistance = 0.0F; + public float m_RexLOD = 0.0F; + public LLUUID m_RexMeshUUID = LLUUID.Zero; + public LLUUID m_RexCollisionMeshUUID = LLUUID.Zero; + public List m_RexMaterialUUID = new List(); + public byte m_RexFixedMaterial = 0; + public LLUUID m_RexParticleScriptUUID = LLUUID.Zero; + + // reX extra parameter block defines + public const int PARAMS_REX = 0x0100; + + // Bit values for flags + public const int REXFLAGS_ISMESH = 0x01; + public const int REXFLAGS_ISVISIBLE = 0x02; + public const int REXFLAGS_CASTSHADOWS = 0x04; + public const int REXFLAGS_SHOWTEXT = 0x08; + public const int REXFLAGS_SCALEMESH = 0x10; + public const int REXFLAGS_SOLIDALPHA = 0x20; + public const int REXFLAGS_ISBILLBOARD = 0x40; + public const int REXFLAGS_USEPARTICLESCRIPT = 0x80; + + // Collision type enumeration (still unused :)) + public const int REXCOLLISION_VOLUME = 0x01; + public const int REXCOLLISION_TRIMESH = 0x02; + + // Attachment parameters + private ScenePresence m_attachPresence = null; + private byte m_attachPt; + private LLQuaternion m_attachRot; + private RegionInfo m_attachRegInfo; + private LLUUID m_attachAgentId; + + // rexend + #region Properties public LLUUID CreatorID; @@ -362,6 +403,22 @@ namespace OpenSim.Region.Environment.Scenes private string m_touchName = ""; + //rex (hack) + private LLUUID touchedBy = LLUUID.Zero; + + //rex (hack) + public LLUUID TouchedBy + { + set + { + touchedBy = value; + } + get + { + return touchedBy; + } + } + public string TouchName { get { return m_touchName; } @@ -574,7 +631,7 @@ namespace OpenSim.Region.Environment.Scenes AbsolutePosition.Z), new PhysicsVector(Scale.X, Scale.Y, Scale.Z), new Quaternion(RotationOffset.W, RotationOffset.X, - RotationOffset.Y, RotationOffset.Z), usePhysics); + RotationOffset.Y, RotationOffset.Z), usePhysics,LocalID); } DoPhysicsPropertyUpdate(usePhysics, true); @@ -663,6 +720,8 @@ namespace OpenSim.Region.Environment.Scenes EveryoneMask &= ~(uint) LLObject.ObjectFlags.CastShadows; EveryoneMask &= ~(uint) LLObject.ObjectFlags.InventoryEmpty; EveryoneMask &= ~(uint) LLObject.ObjectFlags.CreateSelected; + EveryoneMask &= ~(uint)LLObject.ObjectFlags.ObjectYouOfficer; + EveryoneMask &= ~(uint)LLObject.ObjectFlags.ObjectModify; // These are some flags that ObjectFlags (m_flags) should never have @@ -1051,11 +1110,17 @@ namespace OpenSim.Region.Environment.Scenes bool wasUsingPhysics = ((ObjectFlags & (uint) LLObject.ObjectFlags.Physics) != 0); //bool IsLocked = false; int i = 0; - + //rex + LLUUID AgentID = LLUUID.Zero, SessionID = LLUUID.Zero; + uint ObjectLocalID; try { - i += 46; + //rex + i += 10; + AgentID = new LLUUID(data, i); i += 16; + SessionID = new LLUUID(data, i); i += 16; + ObjectLocalID = (uint)(data[i++] + (data[i++] << 8) + (data[i++] << 16) + (data[i++] << 24)); //IsLocked = (data[i++] != 0) ? true : false; usePhysics = ((data[i++] != 0) && m_parentGroup.Scene.m_physicalPrim) ? true : false; //System.Console.WriteLine("U" + packet.ToBytes().Length.ToString()); @@ -1069,6 +1134,17 @@ namespace OpenSim.Region.Environment.Scenes //Silently ignore it - TODO: FIXME Quick } + #region rex added flags + if (AgentID == this.OwnerID) + { + AddFlag(LLObject.ObjectFlags.ObjectYouOwner); + } + else + { + RemFlag(LLObject.ObjectFlags.ObjectYouOwner); + } + #endregion + if (usePhysics) { AddFlag(LLObject.ObjectFlags.Physics); @@ -1109,7 +1185,7 @@ namespace OpenSim.Region.Environment.Scenes AbsolutePosition.Z), new PhysicsVector(Scale.X, Scale.Y, Scale.Z), new Quaternion(RotationOffset.W, RotationOffset.X, - RotationOffset.Y, RotationOffset.Z), usePhysics); + RotationOffset.Y, RotationOffset.Z), usePhysics, LocalID); DoPhysicsPropertyUpdate(usePhysics, true); } else @@ -1178,22 +1254,301 @@ namespace OpenSim.Region.Environment.Scenes public void UpdateExtraParam(ushort type, bool inUse, byte[] data) { - m_shape.ExtraParams = new byte[data.Length + 7]; - int i = 0; - uint length = (uint) data.Length; - m_shape.ExtraParams[i++] = 1; - m_shape.ExtraParams[i++] = (byte) (type%256); - m_shape.ExtraParams[i++] = (byte) ((type >> 8)%256); + // rex, function fixed for handling multiple parameter blocks and disabling them - m_shape.ExtraParams[i++] = (byte) (length%256); - m_shape.ExtraParams[i++] = (byte) ((length >> 8)%256); - m_shape.ExtraParams[i++] = (byte) ((length >> 16)%256); - m_shape.ExtraParams[i++] = (byte) ((length >> 24)%256); - Array.Copy(data, 0, m_shape.ExtraParams, i, data.Length); + //m_shape.ExtraParams = new byte[data.Length + 7]; + //int i = 0; + //uint length = (uint) data.Length; + //m_shape.ExtraParams[i++] = 1; + //m_shape.ExtraParams[i++] = (byte) (type%256); + //m_shape.ExtraParams[i++] = (byte) ((type >> 8)%256); + + //m_shape.ExtraParams[i++] = (byte) (length%256); + //m_shape.ExtraParams[i++] = (byte) ((length >> 8)%256); + //m_shape.ExtraParams[i++] = (byte) ((length >> 16)%256); + //m_shape.ExtraParams[i++] = (byte) ((length >> 24)%256); + //Array.Copy(data, 0, m_shape.ExtraParams, i, data.Length); + + // Amount of param blocks in new & old extra params + int numOld = 0; + int numNew = 0; + + // If old param block exists, take its length & amount of param blocks in it + int totalSizeOld = 0; + int idxOld = 0; + if (m_shape.ExtraParams != null) + { + numOld = m_shape.ExtraParams[idxOld++]; + totalSizeOld = m_shape.ExtraParams.Length; + } + + // New extra params: maximum size = old extra params + size of new data + possible new param block header + num of blocks + byte[] newExtraParams = new byte[totalSizeOld + data.Length + 6 + 1]; + + int idxNew = 1; // Don't know the amount of new param blocks yet, fill it later + bool isNewBlock = true; + + // Go through each of the old params, and see if this new update disables or changes it + for (int i = 0; i < numOld; i++) + { + int typeOld = m_shape.ExtraParams[idxOld++] | (m_shape.ExtraParams[idxOld++] << 8); + int lengthOld = m_shape.ExtraParams[idxOld++] | (m_shape.ExtraParams[idxOld++] << 8) | + (m_shape.ExtraParams[idxOld++] << 16) | (m_shape.ExtraParams[idxOld++] << 24); + + // Not changed, copy verbatim + if (typeOld != type) + { + newExtraParams[idxNew++] = (byte)(typeOld % 256); + newExtraParams[idxNew++] = (byte)((typeOld >> 8) % 256); + newExtraParams[idxNew++] = (byte)(lengthOld % 256); + newExtraParams[idxNew++] = (byte)((lengthOld >> 8) % 256); + newExtraParams[idxNew++] = (byte)((lengthOld >> 16) % 256); + newExtraParams[idxNew++] = (byte)((lengthOld >> 24) % 256); + Array.Copy(m_shape.ExtraParams, idxOld, newExtraParams, idxNew, lengthOld); + + idxNew += lengthOld; + numNew++; + } + else + { + isNewBlock = false; + + // Old parameter updated, check if still in use, or if should remove + if (inUse) + { + newExtraParams[idxNew++] = (byte)(type % 256); + newExtraParams[idxNew++] = (byte)((type >> 8) % 256); + newExtraParams[idxNew++] = (byte)(data.Length % 256); + newExtraParams[idxNew++] = (byte)((data.Length >> 8) % 256); + newExtraParams[idxNew++] = (byte)((data.Length >> 16) % 256); + newExtraParams[idxNew++] = (byte)((data.Length >> 24) % 256); + Array.Copy(data, 0, newExtraParams, idxNew, data.Length); + + idxNew += data.Length; + numNew++; + } + } + idxOld += lengthOld; + } + // If type was not listed, create new block + if ((isNewBlock) && (inUse)) + { + newExtraParams[idxNew++] = (byte)(type % 256); + newExtraParams[idxNew++] = (byte)((type >> 8) % 256); + newExtraParams[idxNew++] = (byte)(data.Length % 256); + newExtraParams[idxNew++] = (byte)((data.Length >> 8) % 256); + newExtraParams[idxNew++] = (byte)((data.Length >> 16) % 256); + newExtraParams[idxNew++] = (byte)((data.Length >> 24) % 256); + Array.Copy(data, 0, newExtraParams, idxNew, data.Length); + + idxNew += data.Length; + numNew++; + } + + // Now we know final size and number of param blocks + newExtraParams[0] = (byte)numNew; + m_shape.ExtraParams = new byte[idxNew]; + Array.Copy(newExtraParams, m_shape.ExtraParams, idxNew); + + string OldPythonClass = m_RexClassName; + LLUUID OldColMesh = m_RexCollisionMeshUUID; + bool OldMeshScaling = ((m_RexFlags & REXFLAGS_SCALEMESH) != 0); + + GetRexParameters(); + + if (m_RexClassName != OldPythonClass) + m_parentGroup.Scene.EventManager.TriggerOnChangePythonClass(LocalID); + + if (GlobalSettings.Instance.m_3d_collision_models) + { + if (m_RexCollisionMeshUUID != OldColMesh && PhysActor != null) + { + if (m_RexCollisionMeshUUID != LLUUID.Zero) + RexUpdateCollisionMesh(); + else + PhysActor.SetCollisionMesh(null, "", false); + } + + bool NewMeshScaling = ((m_RexFlags & REXFLAGS_SCALEMESH) != 0); + if (NewMeshScaling != OldMeshScaling && PhysActor != null) + { + PhysActor.SetBoundsScaling(NewMeshScaling); + m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(PhysActor); + } + } + // rexend ScheduleFullUpdate(); } + // rex, new function, compiles / sends rex parameters after serverside modification + public void UpdateRexParameters() + { + // Compile reX member variables into an extraparam-block + int size = m_RexClassName.Length + 1 // Name + endzero + + 1 + 1 + 4 + 4 // Flags, collisiontype, drawdistance, lod + + 16 + 16 // Mesh UUID & collisionmesh UUID + + 2 + m_RexMaterialUUID.Count * 16 // Material count and UUID's + + 1 // Fixed material + + 16; // Particle script UUID + + byte[] buffer = new byte[size]; + int idx = 0; + + for (int i = 0; i < m_RexClassName.Length; i++) + { + buffer[idx++] = (byte)m_RexClassName[i]; + } + buffer[idx++] = 0; + + buffer[idx++] = m_RexFlags; + + buffer[idx++] = m_RexCollisionType; + + System.BitConverter.GetBytes(m_RexDrawDistance).CopyTo(buffer, idx); + idx += 4; + + System.BitConverter.GetBytes(m_RexLOD).CopyTo(buffer, idx); + idx += 4; + + m_RexMeshUUID.GetBytes().CopyTo(buffer, idx); + idx += 16; + + m_RexCollisionMeshUUID.GetBytes().CopyTo(buffer, idx); + idx += 16; + + System.BitConverter.GetBytes((short)m_RexMaterialUUID.Count).CopyTo(buffer, idx); + idx += 2; + for (int i = 0; i < m_RexMaterialUUID.Count; i++) + { + m_RexMaterialUUID[i].GetBytes().CopyTo(buffer, idx); + idx += 16; + } + + buffer[idx++] = m_RexFixedMaterial; + + m_RexParticleScriptUUID.GetBytes().CopyTo(buffer, idx); + idx += 16; + + UpdateExtraParam(PARAMS_REX, true, buffer); + } + + // rex, new function, extract reX parameters from the parameter block + public void GetRexParameters() + { + if (m_shape.ExtraParams == null) return; + + int idx = 0; + int numParams = m_shape.ExtraParams[idx++]; + + for (int i = 0; i < numParams; i++) + { + // Is this the reX parameter block? + int type = m_shape.ExtraParams[idx++] | (m_shape.ExtraParams[idx++] << 8); + int length = m_shape.ExtraParams[idx++] | (m_shape.ExtraParams[idx++] << 8) | + (m_shape.ExtraParams[idx++] << 16) | (m_shape.ExtraParams[idx++] << 24); + int start = idx; + + if (type == PARAMS_REX) + { + // Class name + StringBuilder buffer = new StringBuilder(); + while ((idx < (length + start)) && (m_shape.ExtraParams[idx] != 0)) + { + char c = (char)m_shape.ExtraParams[idx++]; + buffer.Append(c); + } + m_RexClassName = buffer.ToString(); + idx++; + + // Rex flags + if (idx < (length + start)) + { + m_RexFlags = m_shape.ExtraParams[idx++]; + } + + // Collision type + if (idx < (length + start)) + { + m_RexCollisionType = m_shape.ExtraParams[idx++]; + } + + // Draw distance + if (idx < (length + start - 3)) + { + m_RexDrawDistance = System.BitConverter.ToSingle(m_shape.ExtraParams, idx); + idx += 4; + } + + // Mesh LOD + if (idx < (length + start - 3)) + { + m_RexLOD = System.BitConverter.ToSingle(m_shape.ExtraParams, idx); + idx += 4; + } + + // Mesh UUID + if (idx < (length + start - 15)) + { + m_RexMeshUUID = new LLUUID(m_shape.ExtraParams, idx); + idx += 16; + } + + // Collision mesh UUID + if (idx < (length + start - 15)) + { + m_RexCollisionMeshUUID = new LLUUID(m_shape.ExtraParams, idx); + idx += 16; + } + + // Number of materials + if (idx < (length + start - 1)) + { + short rexMaterials = System.BitConverter.ToInt16(m_shape.ExtraParams, idx); + idx += 2; + m_RexMaterialUUID = new List(); + + for (short j = 0; j < rexMaterials; j++) + { + if (idx < (length + start - 15)) + { + m_RexMaterialUUID.Add(new LLUUID(m_shape.ExtraParams, idx)); + idx += 16; + } + else break; + } + } + // Fixed material + if (idx < (length + start)) + { + m_RexFixedMaterial = m_shape.ExtraParams[idx++]; + } + // Particle script UUID + if (idx < (length + start - 15)) + { + m_RexParticleScriptUUID = new LLUUID(m_shape.ExtraParams, idx); + idx += 16; + } + + //System.Console.WriteLine("Rex parameters of an object updated"); + //System.Console.WriteLine("Rex class name: " + m_RexClassName); + //System.Console.WriteLine("Rex flags: " + (short)m_RexFlags); + //System.Console.WriteLine("Rex collision type: " + (short)m_RexCollisionType); + //System.Console.WriteLine("Rex draw distance: " + m_RexDrawDistance); + //System.Console.WriteLine("Rex LOD: " + m_RexLOD); + //System.Console.WriteLine("Rex mesh UUID: " + m_RexMeshUUID); + //System.Console.WriteLine("Rex collisionmesh UUID: " + m_RexCollisionMeshUUID); + //System.Console.WriteLine("Rex material count: " + m_RexMaterialUUID.Count); + //for (int j = 0; j < m_RexMaterialUUID.Count; j++) + //{ + // System.Console.WriteLine("Rex material UUID " + j + ": " + m_RexMaterialUUID[j]); + //} + break; + } + else idx += length; + } + } + #endregion #region Physics @@ -1210,6 +1565,71 @@ namespace OpenSim.Region.Environment.Scenes } } + // rex, added + public void SetMass(float vValue) + { + if (PhysActor != null) + { + // PhysActor.Mass = vValue; + } + } + + // rex, added + public bool GetUsePrimVolumeCollision() + { + if (PhysActor != null) + return (PhysActor.PhysicsActorType == 4); + else + return false; + } + + // rex, added + public void SetUsePrimVolumeCollision(bool vUseVolumeCollision) + { + if (PhysActor != null) + { + if (vUseVolumeCollision) + { + if (PhysActor.PhysicsActorType != 4) + PhysActor.OnCollisionUpdate += PhysicsCollisionUpdate; + PhysActor.PhysicsActorType = 4; + } + else + { + if (PhysActor.PhysicsActorType == 4) + PhysActor.OnCollisionUpdate -= PhysicsCollisionUpdate; + + PhysActor.PhysicsActorType = 2; + } + } + } + + // rex, added + private void PhysicsCollisionUpdate(EventArgs e) + { + if (PhysActor != null && PhysActor.PhysicsActorType == 4) + m_parentGroup.Scene.EventManager.TriggerOnPrimVolumeCollision(LocalID, (e as CollisionEventUpdate).m_LocalID); + } + + + + // rex, added + public void RexUpdateCollisionMesh() + { + if (!GlobalSettings.Instance.m_3d_collision_models) + return; + + if (m_RexCollisionMeshUUID != LLUUID.Zero && PhysActor != null) + { + bool ScaleMesh = ((m_RexFlags & REXFLAGS_SCALEMESH) != 0); + AssetBase tempmodel = m_parentGroup.Scene.AssetCache.FetchAsset(m_RexCollisionMeshUUID); + if (tempmodel != null) + PhysActor.SetCollisionMesh(tempmodel.Data, tempmodel.Name, ScaleMesh); + } + } + + + public LLVector3 GetGeometricCenter() { if (PhysActor != null) @@ -1276,6 +1696,25 @@ namespace OpenSim.Region.Environment.Scenes #region Position + public void AttachToAvatar(LLUUID agentId, ScenePresence presence, byte attachPt, LLQuaternion rotation, RegionInfo regionInfo) + { + m_attachAgentId = agentId; + m_attachPresence = presence; + m_attachPt = attachPt; + m_attachRot = rotation; + m_attachRegInfo = regionInfo; + + RotationOffset = new LLQuaternion(0, 0, 0, 1); + + ScheduleFullUpdate(); + } + + public void Detach() + { + m_attachPresence = null; + ScheduleFullUpdate(); + } + /// /// /// @@ -1414,6 +1853,137 @@ namespace OpenSim.Region.Environment.Scenes SendFullUpdateToClient(remoteClient, lPos, clientflags); } + public void SendAttachedUpdateToClient(IClientAPI remoteClient, LLVector3 lPos, uint clientFlags) + { + MainLog.Instance.Verbose("OBJECTPART", "Sending as attached object to " + remoteClient.FirstName + " " + remoteClient.LastName); + ObjectUpdatePacket objupdate = new ObjectUpdatePacket(); + objupdate.RegionData.RegionHandle = m_attachRegInfo.RegionHandle; + objupdate.RegionData.TimeDilation = 64096; + objupdate.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[2]; + + // avatar stuff - horrible group copypaste + objupdate.ObjectData[0] = new ObjectUpdatePacket.ObjectDataBlock(); + objupdate.ObjectData[0].PSBlock = new byte[0]; + objupdate.ObjectData[0].ExtraParams = new byte[1]; + objupdate.ObjectData[0].MediaURL = new byte[0]; + objupdate.ObjectData[0].NameValue = new byte[0]; + objupdate.ObjectData[0].Text = new byte[0]; + objupdate.ObjectData[0].TextColor = new byte[4]; + objupdate.ObjectData[0].JointAxisOrAnchor = new LLVector3(0, 0, 0); + objupdate.ObjectData[0].JointPivot = new LLVector3(0, 0, 0); + objupdate.ObjectData[0].Material = 4; + objupdate.ObjectData[0].TextureAnim = new byte[0]; + objupdate.ObjectData[0].Sound = LLUUID.Zero; + + objupdate.ObjectData[0].State = 0; + objupdate.ObjectData[0].Data = new byte[0]; + + objupdate.ObjectData[0].ObjectData = new byte[76]; + objupdate.ObjectData[0].ObjectData[15] = 128; + objupdate.ObjectData[0].ObjectData[16] = 63; + objupdate.ObjectData[0].ObjectData[56] = 128; + objupdate.ObjectData[0].ObjectData[61] = 102; + objupdate.ObjectData[0].ObjectData[62] = 40; + objupdate.ObjectData[0].ObjectData[63] = 61; + objupdate.ObjectData[0].ObjectData[64] = 189; + + + objupdate.ObjectData[0].UpdateFlags = 61 + (9 << 8) + (130 << 16) + (16 << 24); + objupdate.ObjectData[0].PathCurve = 16; + objupdate.ObjectData[0].ProfileCurve = 1; + objupdate.ObjectData[0].PathScaleX = 100; + objupdate.ObjectData[0].PathScaleY = 100; + objupdate.ObjectData[0].ParentID = 0; + objupdate.ObjectData[0].OwnerID = LLUUID.Zero; + objupdate.ObjectData[0].Scale = new LLVector3(1, 1, 1); + objupdate.ObjectData[0].PCode = 47; + objupdate.ObjectData[0].TextureEntry = ScenePresence.DefaultTexture; + + objupdate.ObjectData[0].ID = m_attachPresence.LocalId; + objupdate.ObjectData[0].FullID = m_attachAgentId; + objupdate.ObjectData[0].ParentID = 0; + objupdate.ObjectData[0].NameValue = + Helpers.StringToField("FirstName STRING RW SV " + m_attachPresence.Firstname + "\nLastName STRING RW SV " + m_attachPresence.Lastname); + LLVector3 pos2 = m_attachPresence.AbsolutePosition; + // new LLVector3((float) Pos.X, (float) Pos.Y, (float) Pos.Z); + byte[] pb = pos2.GetBytes(); + Array.Copy(pb, 0, objupdate.ObjectData[0].ObjectData, 16, pb.Length); + + + // primitive part + objupdate.ObjectData[1] = new ObjectUpdatePacket.ObjectDataBlock(); + // SetDefaultPrimPacketValues + objupdate.ObjectData[1].PSBlock = new byte[0]; + objupdate.ObjectData[1].ExtraParams = new byte[1]; + objupdate.ObjectData[1].MediaURL = new byte[0]; + objupdate.ObjectData[1].NameValue = new byte[0]; + objupdate.ObjectData[1].Text = new byte[0]; + objupdate.ObjectData[1].TextColor = new byte[4]; + objupdate.ObjectData[1].JointAxisOrAnchor = new LLVector3(0, 0, 0); + objupdate.ObjectData[1].JointPivot = new LLVector3(0, 0, 0); + objupdate.ObjectData[1].Material = 3; + objupdate.ObjectData[1].TextureAnim = new byte[0]; + objupdate.ObjectData[1].Sound = LLUUID.Zero; + objupdate.ObjectData[1].State = 0; + objupdate.ObjectData[1].Data = new byte[0]; + + objupdate.ObjectData[1].ObjectData = new byte[60]; + objupdate.ObjectData[1].ObjectData[46] = 128; + objupdate.ObjectData[1].ObjectData[47] = 63; + + // SetPrimPacketShapeData + PrimitiveBaseShape primData = Shape; + + objupdate.ObjectData[1].TextureEntry = primData.TextureEntry; + objupdate.ObjectData[1].PCode = primData.PCode; + objupdate.ObjectData[1].State = (byte)(((byte)m_attachPt) << 4); + objupdate.ObjectData[1].PathBegin = primData.PathBegin; + objupdate.ObjectData[1].PathEnd = primData.PathEnd; + objupdate.ObjectData[1].PathScaleX = primData.PathScaleX; + objupdate.ObjectData[1].PathScaleY = primData.PathScaleY; + objupdate.ObjectData[1].PathShearX = primData.PathShearX; + objupdate.ObjectData[1].PathShearY = primData.PathShearY; + objupdate.ObjectData[1].PathSkew = primData.PathSkew; + objupdate.ObjectData[1].ProfileBegin = primData.ProfileBegin; + objupdate.ObjectData[1].ProfileEnd = primData.ProfileEnd; + objupdate.ObjectData[1].Scale = primData.Scale; + objupdate.ObjectData[1].PathCurve = primData.PathCurve; + objupdate.ObjectData[1].ProfileCurve = primData.ProfileCurve; + objupdate.ObjectData[1].ProfileHollow = primData.ProfileHollow; + objupdate.ObjectData[1].PathRadiusOffset = primData.PathRadiusOffset; + objupdate.ObjectData[1].PathRevolutions = primData.PathRevolutions; + objupdate.ObjectData[1].PathTaperX = primData.PathTaperX; + objupdate.ObjectData[1].PathTaperY = primData.PathTaperY; + objupdate.ObjectData[1].PathTwist = primData.PathTwist; + objupdate.ObjectData[1].PathTwistBegin = primData.PathTwistBegin; + objupdate.ObjectData[1].ExtraParams = primData.ExtraParams; + + objupdate.ObjectData[1].UpdateFlags = 276957500; // flags; // ?? + objupdate.ObjectData[1].ID = LocalID; + objupdate.ObjectData[1].FullID = UUID; + objupdate.ObjectData[1].OwnerID = OwnerID; + objupdate.ObjectData[1].Text = Helpers.StringToField(Text); + objupdate.ObjectData[1].TextColor[0] = 255; + objupdate.ObjectData[1].TextColor[1] = 255; + objupdate.ObjectData[1].TextColor[2] = 255; + objupdate.ObjectData[1].TextColor[3] = 128; + objupdate.ObjectData[1].ParentID = objupdate.ObjectData[0].ID; + //objupdate.ObjectData[1].PSBlock = particleSystem; + //objupdate.ObjectData[1].ClickAction = clickAction; + objupdate.ObjectData[1].Radius = 20; + objupdate.ObjectData[1].NameValue = + Helpers.StringToField("AttachItemID STRING RW SV " + UUID); + LLVector3 pos = new LLVector3((float)0.0, (float)0.0, (float)0.0); + + pb = pos.GetBytes(); + Array.Copy(pb, 0, objupdate.ObjectData[1].ObjectData, 0, pb.Length); + + byte[] brot = m_attachRot.GetBytes(); + Array.Copy(brot, 0, objupdate.ObjectData[1].ObjectData, 36, brot.Length); + + remoteClient.OutPacket(objupdate, ThrottleOutPacketType.Task); + } + /// /// /// @@ -1421,6 +1991,12 @@ namespace OpenSim.Region.Environment.Scenes /// public void SendFullUpdateToClient(IClientAPI remoteClient, LLVector3 lPos, uint clientFlags) { + if (m_attachPresence != null) + { + SendAttachedUpdateToClient(remoteClient, lPos, clientFlags); + return; + } + LLQuaternion lRot; lRot = RotationOffset; clientFlags &= ~(uint) LLObject.ObjectFlags.CreateSelected; diff --git a/OpenSim/Region/Environment/Scenes/ScenePresence.cs b/OpenSim/Region/Environment/Scenes/ScenePresence.cs index a8042d4690..56c743b100 100644 --- a/OpenSim/Region/Environment/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Environment/Scenes/ScenePresence.cs @@ -39,13 +39,15 @@ namespace OpenSim.Region.Environment.Scenes { public class ScenePresence : EntityBase { - public static AvatarAnimations Animations; + public static AvatarAnimations Animations = null; public static byte[] DefaultTexture; public LLUUID currentParcelUUID = LLUUID.Zero; private List m_animations = new List(); private List m_animationSeqs = new List(); public Vector3 lastKnownAllowedPosition = new Vector3(); public bool sentMessageAboutRestrictedParcelFlyingDown = false; + public float MovementSpeedMod = 1.0f; // rex + private bool m_updateflag = false; private byte m_movementflag = 0; @@ -315,8 +317,11 @@ namespace OpenSim.Region.Environment.Scenes AbsolutePosition = m_controllingClient.StartPos; - Animations = new AvatarAnimations(); - Animations.LoadAnims(); + if (Animations == null) + { + Animations = new AvatarAnimations(); + Animations.LoadAnims(); + } // TODO: m_animations and m_animationSeqs should always be of the same length. // Move them into an object to (hopefully) avoid threading issues. @@ -385,7 +390,7 @@ namespace OpenSim.Region.Environment.Scenes //{ lock (m_partsUpdateQueue) { - m_partsUpdateQueue.Enqueue(part); + m_partsUpdateQueue.ObjectUpdated(part); } // } } @@ -397,11 +402,6 @@ namespace OpenSim.Region.Environment.Scenes public void SendPrimUpdates() { - // if (m_scene.QuadTree.GetNodeID(this.AbsolutePosition.X, this.AbsolutePosition.Y) != m_currentQuadNode) - //{ - // this.UpdateQuadTreeNode(); - //this.RefreshQuadObject(); - //} if (!m_gotAllObjectsInScene) { if (!m_isChildAgent || m_scene.m_sendTasksToChild) @@ -410,59 +410,55 @@ namespace OpenSim.Region.Environment.Scenes m_gotAllObjectsInScene = true; } } - if (m_partsUpdateQueue.Count > 0) + + //Report avatar position to let queue sort objects (rex) + m_partsUpdateQueue.UpdateAvatarPosition(AbsolutePosition); + + int updateCount = 0; + while (m_partsUpdateQueue.HasUpdates() && updateCount < 8) { - bool runUpdate = true; - int updateCount = 0; - while (runUpdate) + SceneObjectPart part = m_partsUpdateQueue.GetClosestUpdate(); + if (part != null && m_updateTimes.ContainsKey(part.UUID)) { - SceneObjectPart part = m_partsUpdateQueue.Dequeue(); - if (m_updateTimes.ContainsKey(part.UUID)) + ScenePartUpdate update = m_updateTimes[part.UUID]; + + // Two updates can occur with the same timestamp (especially + // since our timestamp resolution is to the nearest second). The first + // could have been sent in the last update - we still need to send the + // second here. + + + if (update.LastFullUpdateTime < part.TimeStampFull) { - ScenePartUpdate update = m_updateTimes[part.UUID]; - - // Two updates can occur with the same timestamp (especially - // since our timestamp resolution is to the nearest second). The first - // could have been sent in the last update - we still need to send the - // second here. - - if (update.LastFullUpdateTime < part.TimeStampFull) - { - //need to do a full update - part.SendFullUpdate(ControllingClient, GenerateClientFlags(part.UUID)); - - // We'll update to the part's timestamp rather than the current to - // avoid the race condition whereby the next tick occurs while we are - // doing this update. If this happened, then subsequent updates which occurred - // on the same tick or the next tick of the last update would be ignored. - update.LastFullUpdateTime = part.TimeStampFull; - - updateCount++; - } - else if (update.LastTerseUpdateTime <= part.TimeStampTerse) - { - part.SendTerseUpdate(ControllingClient); - - update.LastTerseUpdateTime = part.TimeStampTerse; - updateCount++; - } - } - else - { - //never been sent to client before so do full update + //need to do a full update part.SendFullUpdate(ControllingClient, GenerateClientFlags(part.UUID)); - ScenePartUpdate update = new ScenePartUpdate(); - update.FullID = part.UUID; + + // We'll update to the part's timestamp rather than the current to + // avoid the race condition whereby the next tick occurs while we are + // doing this update. If this happened, then subsequent updates which occurred + // on the same tick or the next tick of the last update would be ignored. update.LastFullUpdateTime = part.TimeStampFull; - m_updateTimes.Add(part.UUID, update); + updateCount++; } - - if (m_partsUpdateQueue.Count < 1 || updateCount > 60) + else if (update.LastTerseUpdateTime <= part.TimeStampTerse) { - runUpdate = false; + part.SendTerseUpdate(ControllingClient); + + update.LastTerseUpdateTime = part.TimeStampTerse; + updateCount++; } } + else + { + //never been sent to client before so do full update + part.SendFullUpdate(ControllingClient, GenerateClientFlags(part.UUID)); + ScenePartUpdate update = new ScenePartUpdate(); + update.FullID = part.UUID; + update.LastFullUpdateTime = part.TimeStampFull; + m_updateTimes.Add(part.UUID, update); + updateCount++; + } } } @@ -752,7 +748,7 @@ namespace OpenSim.Region.Environment.Scenes } } } - if ((update_movementflag) || (update_rotation && DCFlagKeyPressed)) + if ((update_movementflag) || (update_rotation)) // rex, DCFlagKeyPressed removed from update_rotation check, allows turning in place { AddNewMovement(agent_control_v3, q); UpdateMovementAnimations(update_movementflag); @@ -1096,7 +1092,7 @@ namespace OpenSim.Region.Environment.Scenes Vector3 direc = rotation*vec; direc.Normalize(); - direc *= 0.03f*128f; + direc *= 0.03f * 128f * MovementSpeedMod; // rex, MovementSpeedMod added if (m_physicsActor.Flying) { direc *= 4; @@ -1570,7 +1566,7 @@ namespace OpenSim.Region.Environment.Scenes new PhysicsVector(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z); - m_physicsActor = scene.AddAvatar(Firstname + "." + Lastname, pVec); + m_physicsActor = scene.AddAvatar(Firstname + "." + Lastname, pVec,LocalId); // rex, LocalId added m_physicsActor.OnRequestTerseUpdate += SendTerseUpdateToAllClients; m_physicsActor.OnCollisionUpdate += PhysicsCollisionUpdate; } @@ -1587,4 +1583,4 @@ namespace OpenSim.Region.Environment.Scenes RemoveFromPhysicalScene(); } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/Environment/Scenes/SceneXmlLoader.cs b/OpenSim/Region/Environment/Scenes/SceneXmlLoader.cs index 8c4a9516cd..17d7c1b065 100644 --- a/OpenSim/Region/Environment/Scenes/SceneXmlLoader.cs +++ b/OpenSim/Region/Environment/Scenes/SceneXmlLoader.cs @@ -89,7 +89,7 @@ namespace OpenSim.Region.Environment.Scenes rootPart.AbsolutePosition.Z + loadOffset.Z), new PhysicsVector(rootPart.Scale.X, rootPart.Scale.Y, rootPart.Scale.Z), new Quaternion(rootPart.RotationOffset.W, rootPart.RotationOffset.X, - rootPart.RotationOffset.Y, rootPart.RotationOffset.Z), UsePhysics); + rootPart.RotationOffset.Y, rootPart.RotationOffset.Z), UsePhysics, rootPart.LocalID); rootPart.DoPhysicsPropertyUpdate(UsePhysics, true); } primCount++; @@ -162,7 +162,7 @@ namespace OpenSim.Region.Environment.Scenes rootPart.AbsolutePosition.Z), new PhysicsVector(rootPart.Scale.X, rootPart.Scale.Y, rootPart.Scale.Z), new Quaternion(rootPart.RotationOffset.W, rootPart.RotationOffset.X, - rootPart.RotationOffset.Y, rootPart.RotationOffset.Z), UsePhysics); + rootPart.RotationOffset.Y, rootPart.RotationOffset.Z), UsePhysics, rootPart.LocalID); rootPart.DoPhysicsPropertyUpdate(UsePhysics, true); } } diff --git a/OpenSim/Region/Environment/Types/UpdateQueue.cs b/OpenSim/Region/Environment/Types/UpdateQueue.cs index 0648476be2..de9ca92b6b 100644 --- a/OpenSim/Region/Environment/Types/UpdateQueue.cs +++ b/OpenSim/Region/Environment/Types/UpdateQueue.cs @@ -27,53 +27,133 @@ */ using System.Collections.Generic; +using System; using libsecondlife; using OpenSim.Region.Environment.Scenes; + namespace OpenSim.Region.Environment.Types { public class UpdateQueue { - private Queue m_queue; - - private List m_ids; - - public int Count + class SceneObject { - get { return m_queue.Count; } - } + //The distance after to include object size as a priority factor + static float m_maxSortDistance = 90 * 90; - public UpdateQueue() - { - m_queue = new Queue(); - m_ids = new List(); - } + public SceneObjectPart m_part; + public float m_priority; - public void Enqueue(SceneObjectPart part) - { - lock (m_ids) + public SceneObject(SceneObjectPart part) { - if (!m_ids.Contains(part.UUID)) + m_part = part; + } + + + public void DeterminePriority(LLVector3 pos) + { + m_priority = LLVector3.MagSquared(pos - m_part.AbsolutePosition); + m_priority -= LLVector3.MagSquared(m_part.Scale) * 12; + if (m_priority < 0) { - m_ids.Add(part.UUID); - m_queue.Enqueue(part); + m_priority = 0; + } + else if (m_priority > m_maxSortDistance) + { + m_priority = m_maxSortDistance; } } } - public SceneObjectPart Dequeue() + class SceneObjectComparer : IComparer { - SceneObjectPart part = null; - if (m_queue.Count > 0) + int IComparer.Compare(SceneObject a, SceneObject b) { - part = m_queue.Dequeue(); - lock (m_ids) + if (a.m_priority > b.m_priority) + return 1; + + if (a.m_priority < b.m_priority) + return -1; + + return 0; + } + } + + private List m_queue; + private Dictionary> m_ids; + + float m_objectResortDistance = 15 * 15; + + LLVector3 m_playerSpherePos = LLVector3.Zero; + + DateTime m_forceRefreshTime; + bool m_forceRefreshTimeSet = false; + + public UpdateQueue() + { + m_queue = new List(); + m_ids = new Dictionary>(); + } + + public bool HasUpdates() + { + if (m_queue.Count > 0) + return true; + + return false; + } + + public void ObjectUpdated(SceneObjectPart part) + { + lock (m_ids) + { + if (!m_ids.ContainsKey(part.UUID)) { - m_ids.Remove(part.UUID); + m_queue.Add(new SceneObject(part)); + m_ids[part.UUID] = null; } + else if (!m_forceRefreshTimeSet) + { + m_forceRefreshTime = DateTime.Now; + m_forceRefreshTime.AddSeconds(1); + m_forceRefreshTimeSet = true; + } + } + } + + public void UpdateAvatarPosition(LLVector3 avatarPosition) + { + if (LLVector3.MagSquared(m_playerSpherePos - avatarPosition) > m_objectResortDistance) + { + m_playerSpherePos = avatarPosition; + CollectNearestItems(); + } + else if (m_forceRefreshTimeSet && m_forceRefreshTime < DateTime.Now) + { + m_playerSpherePos = avatarPosition; + CollectNearestItems(); + } + } + + public SceneObjectPart GetClosestUpdate() + { + SceneObjectPart part = m_queue[0].m_part; + + lock (m_ids) + { + m_queue.RemoveAt(0); + m_ids.Remove(part.UUID); } return part; } + + protected void CollectNearestItems() + { + m_queue.ForEach(delegate(SceneObject obj) { obj.DeterminePriority(m_playerSpherePos); }); + m_queue.Sort(new SceneObjectComparer()); + + m_forceRefreshTimeSet = false; + } } } \ No newline at end of file diff --git a/OpenSim/Region/Examples/SimpleApp/MyNpcCharacter.cs b/OpenSim/Region/Examples/SimpleApp/MyNpcCharacter.cs index 809a13b02b..9796518742 100644 --- a/OpenSim/Region/Examples/SimpleApp/MyNpcCharacter.cs +++ b/OpenSim/Region/Examples/SimpleApp/MyNpcCharacter.cs @@ -115,6 +115,7 @@ namespace SimpleApp public event UpdateInventoryItem OnUpdateInventoryItem; public event CopyInventoryItem OnCopyInventoryItem; public event MoveInventoryItem OnMoveInventoryItem; + public event RemoveInventoryItem OnRemoveInventoryItem; // rex public event UDPAssetUploadRequest OnAssetUploadRequest; public event XferReceive OnXferReceive; public event RequestXfer OnRequestXfer; @@ -123,6 +124,10 @@ namespace SimpleApp public event UpdateTaskInventory OnUpdateTaskInventory; public event RemoveTaskInventory OnRemoveTaskItem; + public event RezSingleAttachmentFromInv OnRezSingleAttachmentFromInv; + public event ObjectAttach OnObjectAttach; + public event ObjectDetach OnObjectDetach; + public event UUIDNameRequest OnNameFromUUIDRequest; public event ParcelPropertiesRequest OnParcelPropertiesRequest; @@ -143,6 +148,11 @@ namespace SimpleApp public event FriendActionDelegate OnDenyFriendRequest; public event FriendshipTermination OnTerminateFriendship; + public event ReceiveRexClientScriptCmd OnReceiveRexClientScriptCmd; // rex + public event ObjectClickAction OnObjectClickAction; // rex + public event UpdateAssetMediaURL OnUpdateAssetMediaURL; // rex + public event TriggerSound OnTriggerSound; + #pragma warning restore 67 private LLUUID myID = LLUUID.Random(); @@ -206,6 +216,14 @@ namespace SimpleApp { } + public virtual void SendRexAppearance(LLUUID agentID, string avatarAddress) // rex + { + } + + public virtual void SendRexScriptCommand(string vUnit, string vCommand, string vCmdParams) // rex + { + } + public virtual void Kick(string message) { } @@ -253,6 +271,11 @@ namespace SimpleApp { } + //rex + public virtual void SendMediaURL(LLUUID assetId, string mediaURL) + { + } + public virtual void MoveAgentIntoRegion(RegionInfo regInfo, LLVector3 pos, LLVector3 look) { } @@ -374,6 +397,11 @@ namespace SimpleApp { } + public void SendTriggeredSound(LLUUID soundID, LLUUID ownerID, LLUUID objectID, LLUUID parentID, ulong handle, LLVector3 position, float gain) + { + } + + public void SendAlertMessage(string message) { } @@ -391,6 +419,10 @@ namespace SimpleApp { } + public void SendDialog(string objectname, LLUUID objectID, LLUUID ownerID, string msg, LLUUID textureID, int ch, string[] buttonlabels) + { + } + public virtual void SendRegionHandshake(RegionInfo regionInfo) { if (OnRegionHandShakeReply != null) @@ -500,5 +532,7 @@ namespace SimpleApp public void SendLogoutPacket() { } + + public void SendScriptTeleportRequest(string objectName, string simName, LLVector3 simPosition, LLVector3 lookAt) { } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/Examples/SimpleApp/MyWorld.cs b/OpenSim/Region/Examples/SimpleApp/MyWorld.cs index 4c12b3f730..94271859d8 100644 --- a/OpenSim/Region/Examples/SimpleApp/MyWorld.cs +++ b/OpenSim/Region/Examples/SimpleApp/MyWorld.cs @@ -47,7 +47,7 @@ namespace SimpleApp ModuleLoader moduleLoader, bool physicalPrim, bool ChildGetTasks) : base( regionInfo, authen, permissionManager, commsMan, sceneGridService, assetCach, storeMan, httpServer, - moduleLoader, false, true, false) + moduleLoader, false, true, false, false) { m_avatars = new List(); } diff --git a/OpenSim/Region/Examples/SimpleApp/Program.cs b/OpenSim/Region/Examples/SimpleApp/Program.cs index d872bf64e0..4d1fc22e3d 100644 --- a/OpenSim/Region/Examples/SimpleApp/Program.cs +++ b/OpenSim/Region/Examples/SimpleApp/Program.cs @@ -88,7 +88,7 @@ namespace SimpleApp m_commsManager = localComms; LocalLoginService loginService = - new LocalLoginService(userService, "", localComms, m_networkServersInfo, false); + new LocalLoginService(userService, "", localComms, m_networkServersInfo, false, false); loginService.OnLoginToRegion += backendService.AddNewSession; m_httpServer.AddXmlRPCHandler("login_to_simulator", loginService.XmlRpcLoginMethod); diff --git a/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsPlugin.cs b/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsPlugin.cs index 636cf1a98d..a0ac8c509d 100644 --- a/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsPlugin.cs +++ b/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsPlugin.cs @@ -75,7 +75,7 @@ namespace OpenSim.Region.Physics.BasicPhysicsPlugin // Does nothing right now } - public override PhysicsActor AddAvatar(string avName, PhysicsVector position) + public override PhysicsActor AddAvatar(string avName, PhysicsVector position, uint localID) { BasicActor act = new BasicActor(); act.Position = position; @@ -104,13 +104,13 @@ namespace OpenSim.Region.Physics.BasicPhysicsPlugin */ public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, PhysicsVector position, - PhysicsVector size, Quaternion rotation) + PhysicsVector size, Quaternion rotation, uint LocalID) { - return AddPrimShape(primName, pbs, position, size, rotation, false); + return AddPrimShape(primName, pbs, position, size, rotation, false, LocalID); } public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, PhysicsVector position, - PhysicsVector size, Quaternion rotation, bool isPhysical) + PhysicsVector size, Quaternion rotation, bool isPhysical, uint localID) // rex, modified { return null; } diff --git a/OpenSim/Region/Physics/BulletXPlugin/BulletXPlugin.cs b/OpenSim/Region/Physics/BulletXPlugin/BulletXPlugin.cs index a88299e274..59d3a603cf 100644 --- a/OpenSim/Region/Physics/BulletXPlugin/BulletXPlugin.cs +++ b/OpenSim/Region/Physics/BulletXPlugin/BulletXPlugin.cs @@ -408,7 +408,7 @@ namespace OpenSim.Region.Physics.BulletXPlugin } - public override PhysicsActor AddAvatar(string avName, PhysicsVector position) + public override PhysicsActor AddAvatar(string avName, PhysicsVector position, uint localID) { PhysicsVector pos = new PhysicsVector(); pos.X = position.X; @@ -446,13 +446,13 @@ namespace OpenSim.Region.Physics.BulletXPlugin } public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, PhysicsVector position, - PhysicsVector size, AxiomQuaternion rotation) + PhysicsVector size, AxiomQuaternion rotation, uint localID) { - return AddPrimShape(primName, pbs, position, size, rotation, false); + return AddPrimShape(primName, pbs, position, size, rotation, false,localID); } public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, PhysicsVector position, - PhysicsVector size, AxiomQuaternion rotation, bool isPhysical) + PhysicsVector size, AxiomQuaternion rotation, bool isPhysical, uint LocalID) { PhysicsActor result; @@ -462,17 +462,17 @@ namespace OpenSim.Region.Physics.BulletXPlugin /// support simple box & hollow box now; later, more shapes if (pbs.ProfileHollow == 0) { - result = AddPrim(primName, position, size, rotation, null, null, isPhysical); + result = AddPrim(primName, position, size, rotation, null, null, isPhysical, LocalID); } else { IMesh mesh = mesher.CreateMesh(primName, pbs, size); - result = AddPrim(primName, position, size, rotation, mesh, pbs, isPhysical); + result = AddPrim(primName, position, size, rotation, mesh, pbs, isPhysical, LocalID); } break; default: - result = AddPrim(primName, position, size, rotation, null, null, isPhysical); + result = AddPrim(primName, position, size, rotation, null, null, isPhysical, LocalID); break; } @@ -480,7 +480,7 @@ namespace OpenSim.Region.Physics.BulletXPlugin } public PhysicsActor AddPrim(String name, PhysicsVector position, PhysicsVector size, AxiomQuaternion rotation, - IMesh mesh, PrimitiveBaseShape pbs, bool isPhysical) + IMesh mesh, PrimitiveBaseShape pbs, bool isPhysical, uint localID) { BulletXPrim newPrim = null; lock (BulletXLock) diff --git a/OpenSim/Region/Physics/Manager/PhysicsActor.cs b/OpenSim/Region/Physics/Manager/PhysicsActor.cs index d393b624a5..356dae063c 100644 --- a/OpenSim/Region/Physics/Manager/PhysicsActor.cs +++ b/OpenSim/Region/Physics/Manager/PhysicsActor.cs @@ -43,21 +43,21 @@ namespace OpenSim.Region.Physics.Manager Unknown = 0, Agent = 1, Prim = 2, - Ground = 3 + Ground = 3, + PrimVolume = 4 // rex } public class CollisionEventUpdate : EventArgs { // Raising the event on the object, so don't need to provide location.. further up the tree knows that info. - - public int m_colliderType; public bool m_startOrEnd; - //public uint m_LocalID; + public uint m_LocalID; // rex public List m_objCollisionList; public CollisionEventUpdate(uint localID, int colliderType, bool startOrEnd, List objCollisionList) { + m_LocalID = localID; // rex m_colliderType = colliderType; m_startOrEnd = startOrEnd; m_objCollisionList = objCollisionList; @@ -148,11 +148,9 @@ namespace OpenSim.Region.Physics.Manager public virtual void SendCollisionUpdate(EventArgs e) { - CollisionUpdate handler = OnCollisionUpdate; - if (handler != null) - { - OnCollisionUpdate(e); - } + // CollisionUpdate handler = OnCollisionUpdate; + if (OnCollisionUpdate != null) + OnCollisionUpdate(e); } @@ -190,6 +188,11 @@ namespace OpenSim.Region.Physics.Manager public abstract void AddForce(PhysicsVector force); public abstract void SetMomentum(PhysicsVector momentum); + + public virtual void SetCollisionMesh(byte[] vData, string MeshName, bool vbScaleMesh) { } // rex + public virtual void SetBoundsScaling(bool vbScaleMesh) { } // rex + public int NextPrimVolumeTime = 0; // rex + public uint m_localID; // rex } public class NullPhysicsActor : PhysicsActor diff --git a/OpenSim/Region/Physics/Manager/PhysicsPluginManager.cs b/OpenSim/Region/Physics/Manager/PhysicsPluginManager.cs index a4ac54f504..00db30b4fb 100644 --- a/OpenSim/Region/Physics/Manager/PhysicsPluginManager.cs +++ b/OpenSim/Region/Physics/Manager/PhysicsPluginManager.cs @@ -104,42 +104,49 @@ namespace OpenSim.Region.Physics.Manager private void AddPlugin(string FileName) { - Assembly pluginAssembly = Assembly.LoadFrom(FileName); - - foreach (Type pluginType in pluginAssembly.GetTypes()) + try { - if (pluginType.IsPublic) + Assembly pluginAssembly = Assembly.LoadFrom(FileName); + + foreach (Type pluginType in pluginAssembly.GetTypes()) { - if (!pluginType.IsAbstract) + if (pluginType.IsPublic) { - Type physTypeInterface = pluginType.GetInterface("IPhysicsPlugin", true); - - if (physTypeInterface != null) + if (!pluginType.IsAbstract) { - IPhysicsPlugin plug = - (IPhysicsPlugin) Activator.CreateInstance(pluginAssembly.GetType(pluginType.ToString())); - plug.Init(); - _PhysPlugins.Add(plug.GetName(), plug); - MainLog.Instance.Verbose("PHYSICS", "Added physics engine: " + plug.GetName()); + Type physTypeInterface = pluginType.GetInterface("IPhysicsPlugin", true); + + if (physTypeInterface != null) + { + IPhysicsPlugin plug = + (IPhysicsPlugin)Activator.CreateInstance(pluginAssembly.GetType(pluginType.ToString())); + plug.Init(); + _PhysPlugins.Add(plug.GetName(), plug); + MainLog.Instance.Verbose("PHYSICS", "Added physics engine: " + plug.GetName()); + } + + Type meshTypeInterface = pluginType.GetInterface("IMeshingPlugin", true); + + if (meshTypeInterface != null) + { + IMeshingPlugin plug = + (IMeshingPlugin)Activator.CreateInstance(pluginAssembly.GetType(pluginType.ToString())); + _MeshPlugins.Add(plug.GetName(), plug); + MainLog.Instance.Verbose("PHYSICS", "Added meshing engine: " + plug.GetName()); + } + + physTypeInterface = null; + meshTypeInterface = null; } - - Type meshTypeInterface = pluginType.GetInterface("IMeshingPlugin", true); - - if (meshTypeInterface != null) - { - IMeshingPlugin plug = - (IMeshingPlugin) Activator.CreateInstance(pluginAssembly.GetType(pluginType.ToString())); - _MeshPlugins.Add(plug.GetName(), plug); - MainLog.Instance.Verbose("PHYSICS", "Added meshing engine: " + plug.GetName()); - } - - physTypeInterface = null; - meshTypeInterface = null; } } - } - pluginAssembly = null; + pluginAssembly = null; + } + catch (Exception e) + { + MainLog.Instance.Warn("PHYSICS", "Error loading plugin " + FileName + ": " + e.Message); + } } //--- diff --git a/OpenSim/Region/Physics/Manager/PhysicsScene.cs b/OpenSim/Region/Physics/Manager/PhysicsScene.cs index 37481f166e..b76059ebf8 100644 --- a/OpenSim/Region/Physics/Manager/PhysicsScene.cs +++ b/OpenSim/Region/Physics/Manager/PhysicsScene.cs @@ -57,16 +57,16 @@ namespace OpenSim.Region.Physics.Manager public abstract void Initialise(IMesher meshmerizer); - public abstract PhysicsActor AddAvatar(string avName, PhysicsVector position); + public abstract PhysicsActor AddAvatar(string avName, PhysicsVector position, uint localID); // rex, localID added public abstract void RemoveAvatar(PhysicsActor actor); public abstract void RemovePrim(PhysicsActor prim); public abstract PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, PhysicsVector position, - PhysicsVector size, Quaternion rotation); //To be removed + PhysicsVector size, Quaternion rotation, uint localID); //To be removed, rex, localID added public abstract PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, PhysicsVector position, - PhysicsVector size, Quaternion rotation, bool isPhysical); + PhysicsVector size, Quaternion rotation, bool isPhysical, uint localID); // rex, localID added public abstract void AddPhysicsActorTaint(PhysicsActor prim); @@ -90,7 +90,7 @@ namespace OpenSim.Region.Physics.Manager // Does nothing right now } - public override PhysicsActor AddAvatar(string avName, PhysicsVector position) + public override PhysicsActor AddAvatar(string avName, PhysicsVector position, uint localID) { MainLog.Instance.Verbose("PHYSICS", "NullPhysicsScene : AddAvatar({0})", position); return PhysicsActor.Null; @@ -113,13 +113,13 @@ namespace OpenSim.Region.Physics.Manager */ public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, PhysicsVector position, - PhysicsVector size, Quaternion rotation) //To be removed + PhysicsVector size, Quaternion rotation, uint localID) //To be removed { - return AddPrimShape(primName, pbs, position, size, rotation, false); + return AddPrimShape(primName, pbs, position, size, rotation, false, localID); } public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, PhysicsVector position, - PhysicsVector size, Quaternion rotation, bool isPhysical) + PhysicsVector size, Quaternion rotation, bool isPhysical, uint localID) { MainLog.Instance.Verbose("PHYSICS", "NullPhysicsScene : AddPrim({0},{1})", position, size); return PhysicsActor.Null; diff --git a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs index 8e9217128e..2e4336a234 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs @@ -31,6 +31,7 @@ using Axiom.Math; using Ode.NET; using OpenSim.Framework; using OpenSim.Region.Physics.Manager; +using System.Runtime.InteropServices; // rex namespace OpenSim.Region.Physics.OdePlugin { @@ -71,14 +72,19 @@ namespace OpenSim.Region.Physics.OdePlugin private bool jumping = false; //private float gravityAccel; public IntPtr Body; + private GCHandle gchBody; // rex + private OdeScene _parent_scene; public IntPtr Shell; + private GCHandle gchShell; // rex + public IntPtr Amotor; public d.Mass ShellMass; public bool collidelock = false; - public OdeCharacter(String avName, OdeScene parent_scene, PhysicsVector pos) + public OdeCharacter(String avName, OdeScene parent_scene, PhysicsVector pos, uint localID) // rex, localID added { + m_localID = localID; // rex _velocity = new PhysicsVector(); _target_velocity = new PhysicsVector(); _position = pos; @@ -98,8 +104,12 @@ namespace OpenSim.Region.Physics.OdePlugin { int dAMotorEuler = 1; Shell = d.CreateCapsule(parent_scene.space, CAPSULE_RADIUS, CAPSULE_LENGTH); + gchShell = GCHandle.Alloc(Shell, GCHandleType.Pinned); // rex + d.MassSetCapsule(out ShellMass, m_density, 3, CAPSULE_RADIUS, CAPSULE_LENGTH); Body = d.BodyCreate(parent_scene.world); + gchBody = GCHandle.Alloc(Body, GCHandleType.Pinned); // rex + d.BodySetMass(Body, ref ShellMass); d.BodySetPosition(Body, pos.X, pos.Y, pos.Z); d.GeomSetBody(Shell, Body); @@ -308,11 +318,15 @@ namespace OpenSim.Region.Physics.OdePlugin CAPSULE_LENGTH = (SetSize.Z - ((SetSize.Z*0.43f))); // subtract 43% of the size d.BodyDestroy(Body); + gchBody.Free(); // rex d.GeomDestroy(Shell); + gchShell.Free(); // rex //MainLog.Instance.Verbose("PHYSICS", "Set Avatar Height To: " + (CAPSULE_RADIUS + CAPSULE_LENGTH)); Shell = d.CreateCapsule(_parent_scene.space, capsuleradius, CAPSULE_LENGTH); + gchShell = GCHandle.Alloc(Shell, GCHandleType.Pinned); // rex d.MassSetCapsule(out ShellMass, m_density, 3, CAPSULE_RADIUS, CAPSULE_LENGTH); Body = d.BodyCreate(_parent_scene.world); + gchBody = GCHandle.Alloc(Body, GCHandleType.Pinned); // rex d.BodySetMass(Body, ref ShellMass); d.BodySetPosition(Body, _position.X, _position.Y, _position.Z + Math.Abs(CAPSULE_LENGTH - prevCapsule)); diff --git a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs index 5fef47dafb..701592b66c 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs @@ -32,8 +32,66 @@ using Ode.NET; using OpenSim.Framework; using OpenSim.Region.Physics.Manager; +using System.Collections.Generic; // rex +using System.Runtime.InteropServices; // rex +using RexDotMeshLoader; // rex +using OpenSim.Framework.Console; // rex +using libsecondlife; // rex + namespace OpenSim.Region.Physics.OdePlugin { + + // rex, new class + public class OdeCollisionMesh : IMesh + { + public float[] vertexListOrig; + public int[] indexListOrig; + + public float[] vertexList; + public int[] indexList; + public GCHandle gchVertexList; + public GCHandle gchIndexList; + + public LLVector3 BoundsMin = new LLVector3(); + public LLVector3 BoundsMax = new LLVector3(); + public bool m_BoundsScaling; + + public OdeCollisionMesh(int vVertexCount, int vIndexCount) + { + vertexList = new float[vVertexCount]; + gchVertexList = GCHandle.Alloc(vertexList, GCHandleType.Pinned); + vertexListOrig = new float[vVertexCount]; + + indexList = new int[vIndexCount]; + gchIndexList = GCHandle.Alloc(indexList, GCHandleType.Pinned); + indexListOrig = new int[vIndexCount]; + } + + public void FreeLists() + { + gchVertexList.Free(); + gchIndexList.Free(); + } + + public List getVertexList() + { + return null; + } + public int[] getIndexListAsInt() + { + return indexList; + } + public int[] getIndexListAsIntLocked() + { + return indexList; + } + public float[] getVertexListAsFloatLocked() + { + return vertexList; + } + } + + public class OdePrim : PhysicsActor { public PhysicsVector _position; @@ -74,10 +132,14 @@ namespace OpenSim.Region.Physics.OdePlugin public d.Mass pMass; private int debugcounter = 0; + private bool m_DotMeshCollision = false; // rex + public bool m_BoundsScalingUpdate = false; // rex + private bool m_PrimVolume = false; // rex public OdePrim(String primName, OdeScene parent_scene, IntPtr targetSpace, PhysicsVector pos, PhysicsVector size, - Quaternion rotation, IMesh mesh, PrimitiveBaseShape pbs, bool pisPhysical) + Quaternion rotation, IMesh mesh, PrimitiveBaseShape pbs, bool pisPhysical, uint localID) { + m_localID = localID; // rex _velocity = new PhysicsVector(); _position = pos; m_taintposition = pos; @@ -152,10 +214,23 @@ namespace OpenSim.Region.Physics.OdePlugin } } + // rex, modified function, m_PrimVolume added public override int PhysicsActorType { - get { return (int) ActorTypes.Prim; } - set { return; } + get + { + if (m_PrimVolume) + return (int)ActorTypes.PrimVolume; + else + return (int)ActorTypes.Prim; + } + set + { + if (value == (int)ActorTypes.PrimVolume) + m_PrimVolume = true; + else + m_PrimVolume = false; + } } public override bool SetAlwaysRun @@ -320,6 +395,11 @@ namespace OpenSim.Region.Physics.OdePlugin int VertexCount = vertexList.GetLength(0)/3; int IndexCount = indexList.GetLength(0); + // rex, del old trimeshdata + if (_triMeshData != (IntPtr)0) + d.GeomTriMeshDataDestroy(_triMeshData); + _mesh = mesh; // rex, end + _triMeshData = d.GeomTriMeshDataCreate(); d.GeomTriMeshDataBuildSimple(_triMeshData, vertexList, 3*sizeof (float), VertexCount, indexList, IndexCount, @@ -350,6 +430,9 @@ namespace OpenSim.Region.Physics.OdePlugin if (m_taintsize != _size) changesize(timestep); + + if (m_BoundsScalingUpdate) // rex + changesize(timestep); // if (m_taintshape) @@ -381,14 +464,34 @@ namespace OpenSim.Region.Physics.OdePlugin m_taintposition = _position; } + // rex, function changed public void rotate(float timestep) { d.Quaternion myrot = new d.Quaternion(); - myrot.W = _orientation.w; - myrot.X = _orientation.x; - myrot.Y = _orientation.y; - myrot.Z = _orientation.z; - d.GeomSetQuaternion(prim_geom, ref myrot); + + if (m_DotMeshCollision && _mesh != null) // rex, setting rot for collision 3d model + { + d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z); + + Quaternion meshRotA = Quaternion.FromAngleAxis((float)(Math.PI * 0.5), new Vector3(1, 0, 0)); + Quaternion meshRotB = Quaternion.FromAngleAxis((float)(Math.PI), new Vector3(0, 1, 0)); + Quaternion mytemprot = _orientation * meshRotA * meshRotB; + + myrot.W = mytemprot.w; + myrot.X = mytemprot.x; + myrot.Y = mytemprot.y; + myrot.Z = mytemprot.z; + d.GeomSetQuaternion(prim_geom, ref myrot); + } + else + { + myrot.W = _orientation.w; + myrot.X = _orientation.x; + myrot.Y = _orientation.y; + myrot.Z = _orientation.z; + d.GeomSetQuaternion(prim_geom, ref myrot); + } + if (m_isphysical && Body != (IntPtr) 0) { d.BodySetQuaternion(Body, ref myrot); @@ -418,6 +521,7 @@ namespace OpenSim.Region.Physics.OdePlugin m_taintPhysics = m_isphysical; } + // rex, function changed public void changesize(float timestamp) { string oldname = _parent_scene.geom_name_map[prim_geom]; @@ -440,8 +544,63 @@ namespace OpenSim.Region.Physics.OdePlugin // we don't need to do space calculation because the client sends a position update also. + if (m_DotMeshCollision && _mesh != null) // rex, scaling dotmesh models + { + float[] scalefactor = new float[3]; + int vertindex = 0; + OdeCollisionMesh mesh = _mesh as OdeCollisionMesh; + + LLVector3 scalingvector = new LLVector3(_size.X, _size.Y, _size.Z); + if (mesh.m_BoundsScaling) + { + LLVector3 boundssize = mesh.BoundsMax - mesh.BoundsMin; + if (boundssize.X != 0) + scalingvector.X /= boundssize.X; + if (boundssize.Y != 0) + scalingvector.Z /= boundssize.Y; + if (boundssize.Z != 0) + scalingvector.Y /= boundssize.Z; + } + scalefactor[0] = scalingvector.X; + scalefactor[1] = scalingvector.Z; + scalefactor[2] = scalingvector.Y; + + for (int i = 0; i < mesh.vertexList.GetLength(0); i++) + { + mesh.vertexList[i] = mesh.vertexListOrig[i] * scalefactor[vertindex]; + vertindex++; + if (vertindex > 2) + vertindex = 0; + } + + for (int i = 0; i < mesh.indexList.GetLength(0); i++) + mesh.indexList[i] = mesh.indexListOrig[i]; + + setMesh(_parent_scene, mesh); + + d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z); + + Quaternion meshRotA = Quaternion.FromAngleAxis((float)(Math.PI * 0.5), new Vector3(1, 0, 0)); + Quaternion meshRotB = Quaternion.FromAngleAxis((float)(Math.PI), new Vector3(0, 1, 0)); + Quaternion mytemprot = _orientation * meshRotA * meshRotB; + + d.Quaternion myrot = new d.Quaternion(); + myrot.W = mytemprot.w; + myrot.X = mytemprot.x; + myrot.Y = mytemprot.y; + myrot.Z = mytemprot.z; + d.GeomSetQuaternion(prim_geom, ref myrot); + + if (IsPhysical && Body == (IntPtr)0) + { + // Re creates body on size. + // EnableBody also does setMass() + enableBody(); + d.BodyEnable(Body); + } + } // rex, end scaling // Construction of new prim - if (_parent_scene.needsMeshing(_pbs)) + else if (_parent_scene.needsMeshing(_pbs)) { // Don't need to re-enable body.. it's done in SetMesh IMesh mesh = _parent_scene.mesher.CreateMesh(oldname, _pbs, _size); @@ -487,6 +646,7 @@ namespace OpenSim.Region.Physics.OdePlugin _parent_scene.geom_name_map[prim_geom] = oldname; m_taintsize = _size; + m_BoundsScalingUpdate = false; // rex } public void changeshape(float timestamp) @@ -797,5 +957,211 @@ namespace OpenSim.Region.Physics.OdePlugin public override void SetMomentum(PhysicsVector momentum) { } + + + // rex, new function. + // This function should be called only outside of simulation loop -> OdeLock used. + public override void SetCollisionMesh(byte[] vData, string MeshName, bool vbScaleMesh) + { + float[] tempVertexList; + float[] tempBounds; + int[] tempIndexList; + string errorMessage; + float[] scalefactor = new float[3]; + int vertindex = 0; + + lock (OdeScene.OdeLock) + { + // 1. Get rid of old mesh + m_DotMeshCollision = false; + if (_mesh != null) + { + if ((OdeCollisionMesh)_mesh != null) + (_mesh as OdeCollisionMesh).FreeLists(); + + _mesh = null; + } + + // 2. Try to load new colmesh + OdeCollisionMesh mesh = null; + if (vData != null) + { + DotMeshLoader.ReadDotMeshModel(vData, out tempVertexList, out tempIndexList, out tempBounds, out errorMessage); + + if (tempVertexList != null && tempIndexList != null) + { + mesh = new OdeCollisionMesh(tempVertexList.GetLength(0), tempIndexList.GetLength(0)); + mesh.m_BoundsScaling = vbScaleMesh; + mesh.BoundsMin.X = tempBounds[0]; + mesh.BoundsMin.Y = tempBounds[1]; + mesh.BoundsMin.Z = tempBounds[2]; + mesh.BoundsMax.X = tempBounds[3]; + mesh.BoundsMax.Y = tempBounds[4]; + mesh.BoundsMax.Z = tempBounds[5]; + + LLVector3 scalingvector = new LLVector3(_size.X, _size.Y, _size.Z); + if (vbScaleMesh) + { + LLVector3 boundssize = mesh.BoundsMax - mesh.BoundsMin; + if (boundssize.X != 0) + scalingvector.X /= boundssize.X; + if (boundssize.Y != 0) + scalingvector.Z /= boundssize.Y; + if (boundssize.Z != 0) + scalingvector.Y /= boundssize.Z; + } + + scalefactor[0] = scalingvector.X; + scalefactor[1] = scalingvector.Z; + scalefactor[2] = scalingvector.Y; + for (int i = 0; i < tempVertexList.GetLength(0); i++) + { + mesh.vertexListOrig[i] = tempVertexList[i]; + mesh.vertexList[i] = tempVertexList[i] * scalefactor[vertindex]; + + vertindex++; + if (vertindex > 2) + vertindex = 0; + } + + for (int i = 0; i < tempIndexList.GetLength(0); i++) + { + mesh.indexListOrig[i] = tempIndexList[i]; + mesh.indexList[i] = tempIndexList[i]; + } + + + } + else + MainLog.Instance.Error("PHYSICS", "Error importing mesh:" + MeshName + ", " + errorMessage); + } + + // 3. If mesh is null, must create the default collisionbox + if (mesh == null) + { + CreateDefaultCollision(); + return; + } + + // 4. If mesh loaded, use it + string oldname = _parent_scene.geom_name_map[prim_geom]; + m_DotMeshCollision = true; + + if (IsPhysical && Body != (IntPtr)0) + disableBody(); + + if (prim_geom != (IntPtr)0) + { + if (d.SpaceQuery(m_targetSpace, prim_geom)) + { + d.SpaceRemove(m_targetSpace, prim_geom); + } + d.GeomDestroy(prim_geom); + } + + setMesh(_parent_scene, mesh); + + d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z); + + Quaternion meshRotA = Quaternion.FromAngleAxis((float)(Math.PI * 0.5), new Vector3(1, 0, 0)); + Quaternion meshRotB = Quaternion.FromAngleAxis((float)(Math.PI), new Vector3(0, 1, 0)); + Quaternion mytemprot = _orientation * meshRotA * meshRotB; + + d.Quaternion myrot = new d.Quaternion(); + myrot.W = mytemprot.w; + myrot.X = mytemprot.x; + myrot.Y = mytemprot.y; + myrot.Z = mytemprot.z; + d.GeomSetQuaternion(prim_geom, ref myrot); + + _parent_scene.geom_name_map[prim_geom] = oldname; + } + } + + + + + + // rex, function added + private void CreateDefaultCollision() + { + string oldname = _parent_scene.geom_name_map[prim_geom]; + + // Cleanup of old prim geometry + if (_mesh != null) + { + // Cleanup meshing here + } + //kill body to rebuild + if (IsPhysical && Body != (IntPtr)0) + { + disableBody(); + } + if (d.SpaceQuery(m_targetSpace, prim_geom)) + { + d.SpaceRemove(m_targetSpace, prim_geom); + } + d.GeomDestroy(prim_geom); + + // we don't need to do space calculation because the client sends a position update also. + // Construction of new prim + if (_parent_scene.needsMeshing(_pbs)) + { + // Don't need to re-enable body.. it's done in SetMesh + IMesh mesh = _parent_scene.mesher.CreateMesh(oldname, _pbs, _size); + // createmesh returns null when it's a shape that isn't a cube. + if (mesh != null) + { + setMesh(_parent_scene, mesh); + } + else + { + prim_geom = d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z); + d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z); + d.Quaternion myrot = new d.Quaternion(); + myrot.W = _orientation.w; + myrot.X = _orientation.x; + myrot.Y = _orientation.y; + myrot.Z = _orientation.z; + d.GeomSetQuaternion(prim_geom, ref myrot); + } + } + else + { + prim_geom = d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z); + d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z); + d.Quaternion myrot = new d.Quaternion(); + myrot.W = _orientation.w; + myrot.X = _orientation.x; + myrot.Y = _orientation.y; + myrot.Z = _orientation.z; + d.GeomSetQuaternion(prim_geom, ref myrot); + + + //d.GeomBoxSetLengths(prim_geom, _size.X, _size.Y, _size.Z); + if (IsPhysical && Body == (IntPtr)0) + { + // Re creates body on size. + // EnableBody also does setMass() + enableBody(); + d.BodyEnable(Body); + } + } + _parent_scene.geom_name_map[prim_geom] = oldname; + } + + // rex, new function + public override void SetBoundsScaling(bool vbScaleMesh) + { + if (m_DotMeshCollision && _mesh != null) + { + (_mesh as OdeCollisionMesh).m_BoundsScaling = vbScaleMesh; + m_BoundsScalingUpdate = true; + } + } + + + + } } \ No newline at end of file diff --git a/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs b/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs index f8ab8e7d9d..e30dd90614 100644 --- a/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs +++ b/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs @@ -86,6 +86,7 @@ namespace OpenSim.Region.Physics.OdePlugin private IntPtr contactgroup; private IntPtr LandGeom = (IntPtr) 0; private double[] _heightmap; + private GCHandle gchHeightMap; // rex private d.NearCallback nearCallback; public d.TriCallback triCallback; public d.TriArrayCallback triArrayCallback; @@ -161,6 +162,7 @@ namespace OpenSim.Region.Physics.OdePlugin } _heightmap = new double[514*514]; + gchHeightMap = GCHandle.Alloc(_heightmap, GCHandleType.Pinned); // rex for (int i = 0; i < staticPrimspace.GetLength(0); i++) { @@ -263,7 +265,7 @@ namespace OpenSim.Region.Physics.OdePlugin // We only need to test p2 for 'jump crouch purposes' p2.IsColliding = true; - + switch (p1.PhysicsActorType) { @@ -277,11 +279,17 @@ namespace OpenSim.Region.Physics.OdePlugin case (int) ActorTypes.Unknown: p2.CollidingGround = true; break; + case (int)ActorTypes.PrimVolume: // rex, added primvolume + if (Util.UnixTimeSinceEpoch() > p2.NextPrimVolumeTime) + { + p2.NextPrimVolumeTime = Util.UnixTimeSinceEpoch() + 1; + p1.SendCollisionUpdate(new CollisionEventUpdate(p2.m_localID,0,true,null)); + } + return; default: p2.CollidingGround = true; break; } - // we don't want prim or avatar to explode #region InterPenetration Handling - Unintended physics explosions @@ -475,14 +483,15 @@ namespace OpenSim.Region.Physics.OdePlugin } } - public override PhysicsActor AddAvatar(string avName, PhysicsVector position) + public override PhysicsActor AddAvatar(string avName, PhysicsVector position, uint localID) // rex, localid { PhysicsVector pos = new PhysicsVector(); pos.X = position.X; pos.Y = position.Y; pos.Z = position.Z; - OdeCharacter newAv = new OdeCharacter(avName, this, pos); + OdeCharacter newAv = new OdeCharacter(avName, this, pos, localID); // rex, localid _characters.Add(newAv); + return newAv; } @@ -746,7 +755,7 @@ namespace OpenSim.Region.Physics.OdePlugin } private PhysicsActor AddPrim(String name, PhysicsVector position, PhysicsVector size, Quaternion rotation, - IMesh mesh, PrimitiveBaseShape pbs, bool isphysical) + IMesh mesh, PrimitiveBaseShape pbs, bool isphysical, uint localID) // rex, localid { PhysicsVector pos = new PhysicsVector(); pos.X = position.X; @@ -772,7 +781,7 @@ namespace OpenSim.Region.Physics.OdePlugin OdePrim newPrim; lock (OdeLock) { - newPrim = new OdePrim(name, this, targetspace, pos, siz, rot, mesh, pbs, isphysical); + newPrim = new OdePrim(name, this, targetspace, pos, siz, rot, mesh, pbs, isphysical, localID); // rex, localid _prims.Add(newPrim); } @@ -850,13 +859,13 @@ namespace OpenSim.Region.Physics.OdePlugin } public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, PhysicsVector position, - PhysicsVector size, Quaternion rotation) //To be removed + PhysicsVector size, Quaternion rotation, uint localID) //To be removed rex, localid { - return AddPrimShape(primName, pbs, position, size, rotation, false); + return AddPrimShape(primName, pbs, position, size, rotation, false,localID); } public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, PhysicsVector position, - PhysicsVector size, Quaternion rotation, bool isPhysical) + PhysicsVector size, Quaternion rotation, bool isPhysical, uint localID) // rex, localid { PhysicsActor result; IMesh mesh = null; @@ -873,7 +882,7 @@ namespace OpenSim.Region.Physics.OdePlugin break; } - result = AddPrim(primName, position, size, rotation, mesh, pbs, isPhysical); + result = AddPrim(primName, position, size, rotation, mesh, pbs, isPhysical, localID); // rex, localid return result; diff --git a/OpenSim/Region/Physics/POSPlugin/POSPlugin.cs b/OpenSim/Region/Physics/POSPlugin/POSPlugin.cs index 1bc34901a0..71adb3ccf0 100644 --- a/OpenSim/Region/Physics/POSPlugin/POSPlugin.cs +++ b/OpenSim/Region/Physics/POSPlugin/POSPlugin.cs @@ -78,7 +78,7 @@ namespace OpenSim.Region.Physics.POSPlugin // Does nothing right now } - public override PhysicsActor AddAvatar(string avName, PhysicsVector position) + public override PhysicsActor AddAvatar(string avName, PhysicsVector position, uint localID) { POSCharacter act = new POSCharacter(); act.Position = position; @@ -112,13 +112,13 @@ namespace OpenSim.Region.Physics.POSPlugin */ public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, PhysicsVector position, - PhysicsVector size, Quaternion rotation) + PhysicsVector size, Quaternion rotation, uint localID) { - return AddPrimShape(primName, pbs, position, size, rotation, false); + return AddPrimShape(primName, pbs, position, size, rotation, false,localID); } public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, PhysicsVector position, - PhysicsVector size, Quaternion rotation, bool isPhysical) + PhysicsVector size, Quaternion rotation, bool isPhysical, uint localID) { POSPrim prim = new POSPrim(); prim.Position = position; diff --git a/OpenSim/Region/Physics/PhysXPlugin/PhysXPlugin.cs b/OpenSim/Region/Physics/PhysXPlugin/PhysXPlugin.cs index 20bf358825..9ca961aeae 100644 --- a/OpenSim/Region/Physics/PhysXPlugin/PhysXPlugin.cs +++ b/OpenSim/Region/Physics/PhysXPlugin/PhysXPlugin.cs @@ -90,7 +90,7 @@ namespace OpenSim.Region.Physics.PhysXPlugin } - public override PhysicsActor AddAvatar(string avName, PhysicsVector position) + public override PhysicsActor AddAvatar(string avName, PhysicsVector position, uint localID) { Vec3 pos = new Vec3(); pos.X = position.X; @@ -110,7 +110,7 @@ namespace OpenSim.Region.Physics.PhysXPlugin { } - private PhysicsActor AddPrim(PhysicsVector position, PhysicsVector size, Quaternion rotation) + private PhysicsActor AddPrim(PhysicsVector position, PhysicsVector size, Quaternion rotation, uint localID) { Vec3 pos = new Vec3(); pos.X = position.X; @@ -126,15 +126,15 @@ namespace OpenSim.Region.Physics.PhysXPlugin } public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, PhysicsVector position, - PhysicsVector size, Quaternion rotation) //To be removed + PhysicsVector size, Quaternion rotation, uint localID) //To be removed { - return AddPrimShape(primName, pbs, position, size, rotation, false); + return AddPrimShape(primName, pbs, position, size, rotation, false,localID); } public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, PhysicsVector position, - PhysicsVector size, Quaternion rotation, bool isPhysical) + PhysicsVector size, Quaternion rotation, bool isPhysical, uint localID) { - return AddPrim(position, size, rotation); + return AddPrim(position, size, rotation,localID); } public override void AddPhysicsActorTaint(PhysicsActor prim) diff --git a/OpenSim/Region/RexScriptModule/Properties/AssemblyInfo.cs b/OpenSim/Region/RexScriptModule/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..8c7a9eeefc --- /dev/null +++ b/OpenSim/Region/RexScriptModule/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("OpenSim.Region.RexScriptModule")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("OpenSim.Region.RexScriptModule")] +[assembly: AssemblyCopyright("Copyright © 2007")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("4e14be29-a007-48f1-a7db-7dff49b27320")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/OpenSim/Region/RexScriptModule/RexEventManager.cs b/OpenSim/Region/RexScriptModule/RexEventManager.cs new file mode 100644 index 0000000000..8d4ae8b7e9 --- /dev/null +++ b/OpenSim/Region/RexScriptModule/RexEventManager.cs @@ -0,0 +1,190 @@ +using System; +using System.Collections.Generic; +using System.Text; +using libsecondlife; +using OpenSim.Framework; +using OpenSim.Region.Environment.Scenes; + +namespace OpenSim.Region.RexScriptModule +{ + [Serializable] + class RexEventManager + { + private RexScriptEngine myScriptEngine; + + // tuco fixme, is there a better way to do this search??? + private EntityBase GetEntityBase(uint vId) + { + SceneObjectPart part = myScriptEngine.World.GetSceneObjectPart(vId); + if (part != null && (EntityBase)(part.ParentGroup) != null) + return (EntityBase)(part.ParentGroup); + else + return null; + } + + public RexEventManager(RexScriptEngine vScriptEngine) + { + myScriptEngine = vScriptEngine; + myScriptEngine.Log.Verbose("RexScriptEngine", "Hooking up to server events"); + myScriptEngine.World.EventManager.OnObjectGrab += touch_start; + // myScriptEngine.World.EventManager.OnRezScript += OnRezScript; + // myScriptEngine.World.EventManager.OnRemoveScript += OnRemoveScript; + // myScriptEngine.World.EventManager.OnFrame += OnFrame; + // myScriptEngine.World.EventManager.OnNewClient += OnNewClient; + myScriptEngine.World.EventManager.OnNewPresence += OnNewPresence; + myScriptEngine.World.EventManager.OnRemovePresence += OnRemovePresence; + myScriptEngine.World.EventManager.OnShutdown += OnShutDown; + myScriptEngine.World.EventManager.OnAddEntity += OnAddEntity; + myScriptEngine.World.EventManager.OnRemoveEntity += OnRemoveEntity; + myScriptEngine.World.EventManager.OnPythonScriptCommand += OnPythonScriptCommand; + myScriptEngine.World.EventManager.OnPythonClassChange += OnPythonClassChange; + myScriptEngine.World.EventManager.OnRexClientScriptCommand += OnRexClientScriptCommand; + myScriptEngine.World.EventManager.OnPrimVolumeCollision += OnPrimVolumeCollision; + } + + public void touch_start(uint localID, LLVector3 offsetPos, IClientAPI remoteClient) + { + string EventParams = "\"touch_start\"," + localID.ToString() + "," + "\"" + remoteClient.AgentId.ToString() + "\""; + myScriptEngine.ExecutePythonCommand("CreateEventWithName(" + EventParams + ")"); + } + + /* + public void OnRezScript(uint localID, LLUUID itemID, string script) + { + + } + public void OnRemoveScript(uint localID, LLUUID itemID) + { + + } + + public void OnFrame() + { + + } + + public void OnNewClient(IClientAPI vClient) + { + string EventParams = "\"new_client\"," + "\"" + vClient.AgentId.ToString() + "\""; + myScriptEngine.ExecutePythonCommand("CreateEventWithName(" + EventParams + ")"); + } + */ + + public void OnNewPresence(ScenePresence vPresence) + { + string EventParams = "\"add_presence\"," + vPresence.LocalId.ToString() + "," + "\"" + vPresence.m_uuid.ToString() + "\""; + myScriptEngine.ExecutePythonCommand("CreateEventWithName(" + EventParams + ")"); + } + + public void OnRemovePresence(LLUUID uuid) + { + string EventParams = "\"remove_presence\"," + "\"" + uuid.ToString() + "\""; + myScriptEngine.ExecutePythonCommand("CreateEventWithName(" + EventParams + ")"); + } + + public void OnShutDown() + { + Console.WriteLine("REX OnShutDown"); + } + + public void OnAddEntity(uint localID) + { + string PythonClassName = "rxactor.Actor"; + string PythonTag = ""; + + SceneObjectGroup tempobj = (SceneObjectGroup)GetEntityBase(localID); + if (tempobj != null && tempobj.RootPart != null && tempobj.RootPart.m_RexClassName.Length > 0) + PythonClassName = tempobj.RootPart.m_RexClassName; + + // Create the actor directly without using an event. + myScriptEngine.CreateActorToPython(localID.ToString(), PythonClassName, PythonTag); + } + + public void OnRemoveEntity(uint localID) + { + string EventParams = "\"remove_entity\"," + "\"" + localID.ToString() + "\""; + myScriptEngine.ExecutePythonCommand("CreateEventWithName(" + EventParams + ")"); + } + + public void OnPythonScriptCommand(string vCommand) + { + if (vCommand.ToLower() == "restart") + myScriptEngine.RestartPythonEngine(); + else + Console.WriteLine("Unknown PythonScriptEngine command:"+vCommand); + } + + public void OnPythonClassChange(uint localID) + { + string PythonClassName = ""; + string PythonTag = ""; + + SceneObjectGroup tempobj = (SceneObjectGroup)GetEntityBase(localID); + if (tempobj != null && tempobj.RootPart != null && tempobj.RootPart.m_RexClassName.Length > 0) + PythonClassName = tempobj.RootPart.m_RexClassName; + + if (myScriptEngine.IsEngineStarted) + myScriptEngine.CreateActorToPython(localID.ToString(), PythonClassName, PythonTag); + } + + public void OnRexClientScriptCommand(ScenePresence avatar, List vCommands) + { + string Paramlist = ""; + foreach (string s in vCommands) + Paramlist = Paramlist + "," + "\"" + s + "\""; + + string EventParams = "\"client_event\",\"" + avatar.m_uuid.ToString() + "\"" + Paramlist; + myScriptEngine.ExecutePythonCommand("CreateEventWithName(" + EventParams + ")"); + } + + public void OnPrimVolumeCollision(uint ownID, uint colliderID) + { + string EventParams = "\"primvol_col\"," + ownID.ToString() + "," + "\"" + colliderID.ToString() + "\""; + myScriptEngine.ExecutePythonCommand("CreateEventWithName(" + EventParams + ")"); + } + + + + + // TODO: Replace placeholders below + // These needs to be hooked up to OpenSim during init of this class. + // When queued in EventQueueManager they need to be LSL compatible (name and params) + + //public void state_entry() { } // + public void state_exit() { } + //public void touch_start() { } + public void touch() { } + public void touch_end() { } + public void collision_start() { } + public void collision() { } + public void collision_end() { } + public void land_collision_start() { } + public void land_collision() { } + public void land_collision_end() { } + public void timer() { } + public void listen() { } + public void on_rez() { } + public void sensor() { } + public void no_sensor() { } + public void control() { } + public void money() { } + public void email() { } + public void at_target() { } + public void not_at_target() { } + public void at_rot_target() { } + public void not_at_rot_target() { } + public void run_time_permissions() { } + public void changed() { } + public void attach() { } + public void dataserver() { } + public void link_message() { } + public void moving_start() { } + public void moving_end() { } + public void object_rez() { } + public void remote_data() { } + public void http_response() { } + + } + + +} diff --git a/OpenSim/Region/RexScriptModule/RexPythonScriptAccessImpl.cs b/OpenSim/Region/RexScriptModule/RexPythonScriptAccessImpl.cs new file mode 100644 index 0000000000..3e2d64d971 --- /dev/null +++ b/OpenSim/Region/RexScriptModule/RexPythonScriptAccessImpl.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Text; +using OpenSim.Framework; +using System.Globalization; +using OpenSim.Region.ScriptEngine.Common; +using libsecondlife; + +namespace OpenSim.Region.RexScriptModule +{ + public class RexPythonScriptAccessImpl : RexScriptAccessInterface + { + private RexScriptEngine myScriptEngine; + + public RexPythonScriptAccessImpl(RexScriptEngine vEngine) + { + myScriptEngine = vEngine; + } + + public bool GetAvatarStartLocation(out LLVector3 vLoc, out LLVector3 vLookAt) + { + vLoc = new LLVector3(0, 0, 0); + vLookAt = new LLVector3(0, 0, 0); + + try + { + string str = "GetAvatarStartLocation()"; + object resultobj = myScriptEngine.EvalutePythonCommand(str); + + if (resultobj != null) + { + List templist = resultobj as List; + if (templist != null) + { + vLoc.X = (float)templist[0].x; + vLoc.Y = (float)templist[0].y; + vLoc.Z = (float)templist[0].z; + vLookAt.X = (float)templist[1].x; + vLookAt.Y = (float)templist[1].y; + vLookAt.Z = (float)templist[1].z; + } + return true; + } + } + catch (Exception e) + { + Console.WriteLine("GetAvatarStartLocation exception " + e.ToString()); + } + return false; + } + + + private bool GetFloatFromString(string vString,out float floatResult) + { + floatResult = 0; + return (float.TryParse(vString, NumberStyles.AllowDecimalPoint, Culture.NumberFormatInfo, out floatResult)); + } + } +} diff --git a/OpenSim/Region/RexScriptModule/RexScriptEngine.cs b/OpenSim/Region/RexScriptModule/RexScriptEngine.cs new file mode 100644 index 0000000000..6928cfd92b --- /dev/null +++ b/OpenSim/Region/RexScriptModule/RexScriptEngine.cs @@ -0,0 +1,366 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.IO; +using OpenSim.Framework; +using OpenSim.Framework.Console; +using OpenSim.Region.Environment.Scenes; +using OpenSim.Region.Environment.Scenes.Scripting; +using OpenSim.Region.Environment.Interfaces; +using libsecondlife; +using Nini.Config; + +namespace OpenSim.Region.RexScriptModule +{ + public class RexScriptEngine : IRegionModule + { + public OpenSim.Region.RexScriptModule.RexScriptInterface mCSharp; + + internal Scene World; + internal RexEventManager m_EventManager; + + private LogBase m_log; + private IronPython.Hosting.PythonEngine mPython = null; + private bool m_PythonEnabled; + private bool m_EngineStarted; + + public RexScriptEngine() + { + } + + public LogBase Log + { + get { return m_log; } + } + + public bool IsSharedModule + { + get { return false; } + } + + public bool IsPythonEnabled + { + get { return m_PythonEnabled; } + } + + public bool IsEngineStarted + { + get { return m_EngineStarted; } + } + + + public void Initialise(Scene scene, IConfigSource config) + { + try + { + m_PythonEnabled = config.Configs["Startup"].GetBoolean("python_enabled", true); + } + catch (Exception) + { + m_PythonEnabled = true; + } + + InitializeEngine(scene, MainLog.Instance); + } + + public void PostInitialise() + { + + } + + public void CloseDown() + { + } + + public string GetName() + { + return "RexPythonScriptModule"; + } + + public void InitializeEngine(Scene Sceneworld, LogBase logger) + { + World = Sceneworld; + m_log = logger; + + if (m_PythonEnabled) + { + Log.Verbose("RexScriptEngine", "Rex PythonScriptEngine initializing"); + + RexScriptAccess.MyScriptAccess = new RexPythonScriptAccessImpl(this); + m_EventManager = new RexEventManager(this); + mCSharp = new RexScriptInterface(null, null, 0, LLUUID.Zero, this); + StartPythonEngine(); + } + else + Log.Verbose("RexScriptEngine", "Rex PythonScriptEngine disabled"); + } + + public void StartPythonEngine() + { + try + { + Log.Verbose("RexScriptEngine","IronPython init"); + m_EngineStarted = false; + bool bNewEngine = true; + + if (mPython == null) + { + IronPython.Hosting.EngineOptions engineOptions = new IronPython.Hosting.EngineOptions(); + engineOptions.ClrDebuggingEnabled = false; + IronPython.Compiler.Options.Verbose = false; + IronPython.Compiler.Options.GenerateModulesAsSnippets = true; + mPython = new IronPython.Hosting.PythonEngine(engineOptions); + } + else + bNewEngine = false; + + // Add script folder paths to python path + mPython.AddToPath(AppDomain.CurrentDomain.BaseDirectory); + + string rexdlldir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "ScriptEngines"); + mPython.AddToPath(rexdlldir); + + string PytProjectPath = Path.Combine(rexdlldir, "PythonScript"); + mPython.AddToPath(PytProjectPath); + + DirectoryInfo TempDirInfo = new DirectoryInfo(@PytProjectPath); + DirectoryInfo[] dirs = TempDirInfo.GetDirectories("*.*"); + string TempPath = ""; + foreach (DirectoryInfo dir in dirs) + { + TempPath = Path.Combine(PytProjectPath, dir.Name); + mPython.AddToPath(TempPath); + } + String PytLibPath = Path.Combine(rexdlldir, "Lib"); + mPython.AddToPath(PytLibPath); + + // Import Core and init + mPython.Execute("from RXCore import *"); + if (!bNewEngine) + { + ExecutePythonStartCommand("reload(rxlslobject)"); + ExecutePythonStartCommand("reload(rxactor)"); + ExecutePythonStartCommand("reload(rxavatar)"); + ExecutePythonStartCommand("reload(rxevent)"); + ExecutePythonStartCommand("reload(rxeventmanager)"); + ExecutePythonStartCommand("reload(rxworld)"); + } + mPython.Globals.Add("objCSharp", mCSharp); + mPython.ExecuteFile(PytProjectPath + "/RXCore/rxmain.py"); // tucofixme, possible error with path??? + + // Import other packages + foreach (DirectoryInfo dir in dirs) + { + if (dir.Name.IndexOf(".") != -1) + continue; + else if (dir.Name.Length >= 6 && dir.Name.Substring(0, 6).ToLower() == "rxcore") + continue; + else + { + mPython.Execute("from " + dir.Name + " import *"); + if (!bNewEngine) + { + FileInfo[] files = dir.GetFiles("*.py"); + foreach (FileInfo file in files) + { + if (file.Name.ToLower() == "__init__.py") + continue; + else + ExecutePythonStartCommand("reload(" + file.Name.Substring(0, file.Name.Length - 3) + ")"); + } + } + } + } + + // Create objects + string PythonClassName = ""; + string PythonTag = ""; + string PyText = ""; + int tagindex = 0; + + List EntityList = World.GetEntities(); + foreach (EntityBase ent in EntityList) + { + if (ent is SceneObjectGroup) + { + PythonClassName = "rxactor.Actor"; + PythonTag = ""; + + SceneObjectPart part = ((SceneObjectGroup)ent).GetChildPart(((SceneObjectGroup)ent).UUID); + if (part != null) + { + part.GetRexParameters(); + + // First check m_RexClassName, then description of object + if (part.m_RexClassName.Length > 0) + { + tagindex = part.m_RexClassName.IndexOf("?", 0); + if (tagindex > -1) + { + PythonClassName = part.m_RexClassName.Substring(0, tagindex); + PythonTag = part.m_RexClassName.Substring(tagindex + 1); + } + else + PythonClassName = part.m_RexClassName; + } + else if (part.Description.Length > 9 && part.Description.Substring(0, 4).ToLower() == "") + { + tagindex = part.Description.IndexOf("", 4); + if (tagindex > -1) + PyText = part.Description.Substring(4, tagindex - 4); + else + continue; + + tagindex = PyText.IndexOf("?", 0); + if (tagindex > -1) + { + PythonClassName = PyText.Substring(0, tagindex); + PythonTag = PyText.Substring(tagindex + 1); + } + else + PythonClassName = PyText; + } + } + CreateActorToPython(ent.LocalId.ToString(), PythonClassName, PythonTag); + } + } + + + // Create avatars + string PParams = ""; + List ScenePresencesList = World.GetScenePresences(); + foreach (ScenePresence avatar in ScenePresencesList) + { + PParams = "\"add_presence\"," + avatar.LocalId.ToString() + "," + "\"" + avatar.m_uuid.ToString() + "\""; + ExecutePythonStartCommand("CreateEventWithName(" + PParams + ")"); + } + + // start script thread + m_EngineStarted = true; + mPython.Execute("StartMainThread()"); + } + catch (Exception e) + { + Log.Verbose("RexScriptEngine", "Python init exception: " + e.ToString()); + } + } + + + public void RestartPythonEngine() + { + if (!m_PythonEnabled) + { + Log.Verbose("RexScriptEngine", "Rex PythonScriptEngine disabled"); + return; + } + + try + { + Log.Verbose("RexScriptEngine", "Restart"); + // ShutDownPythonEngine(); + mPython.Execute("StopMainThread()"); + GC.Collect(); + GC.WaitForPendingFinalizers(); // tucofixme, blocking??? + StartPythonEngine(); + } + catch (Exception e) + { + Log.Verbose("RexScriptEngine", "restart exception: " + e.ToString()); + } + + } + + + public void ExecutePythonCommand(string vCommand) + { + if (!m_EngineStarted) + return; + try + { + mPython.Execute(vCommand); + } + catch (Exception e) + { + Log.Verbose("RexScriptEngine", "ExecutePythonCommand exception " + e.ToString()); + } + } + + public void ExecutePythonStartCommand(string vCommand) + { + try + { + mPython.Execute(vCommand); + } + catch (Exception e) + { + Log.Verbose("RexScriptEngine", "ExecutePythonStartCommand exception " + e.ToString()); + } + } + + + public object EvalutePythonCommand(string vCommand) + { + try + { + return mPython.Evaluate(vCommand); + } + catch (Exception e) + { + Log.Verbose("RexScriptEngine", "ExecutePythonStartCommand exception " + e.ToString()); + } + return null; + } + + + + + + public void CreateActorToPython(string vLocalId, string vPythonClassName, string vPythonTag) + { + try + { + mPython.Execute("CreateActorOfClass(" + vLocalId + "," + vPythonClassName + ",\"" + vPythonTag + "\")"); + } + catch (Exception) + { + try + { + if (vPythonClassName.Length > 0) + Log.Verbose("RexScriptEngine", "Could not load class:" + vPythonClassName); + mPython.Execute("CreateActorOfClass(" + vLocalId + ",rxactor.Actor,\"\")"); + } + catch (Exception) + { + } + } + } + + public void Shutdown() + { + ShutDownPythonEngine(); + // We are shutting down + } + + public void Close() + { + ShutDownPythonEngine(); + // We are shutting down + } + + private void ShutDownPythonEngine() + { + if (mPython != null) + { + mPython.Execute("StopMainThread()"); + mPython.Shutdown(); + mPython.Dispose(); + mPython = null; + } + } + + public string Name + { + get { return "RexPythonScriptModule"; } + } + } +} diff --git a/OpenSim/Region/RexScriptModule/RexScriptInterface.cs b/OpenSim/Region/RexScriptModule/RexScriptInterface.cs new file mode 100644 index 0000000000..21cae1e343 --- /dev/null +++ b/OpenSim/Region/RexScriptModule/RexScriptInterface.cs @@ -0,0 +1,588 @@ +using Axiom.Math; +using System; +using System.Collections.Generic; +using System.Text; +using System.IO; + +using OpenSim.Framework; +using OpenSim.Framework.Console; +using OpenSim.Framework.Communications.Cache; + +using OpenSim.Region.Environment.Scenes; +using OpenSim.Region.Environment.Scenes.Scripting; +using OpenSim.Region.Environment.Interfaces; +using OpenSim.Region.ScriptEngine.Common; +using OpenSim.Region.ScriptEngine.DotNetEngine; +using OpenSim.Region.ScriptEngine.DotNetEngine.Compiler; +using libsecondlife; + +namespace OpenSim.Region.RexScriptModule +{ + public class RexScriptInterface : LSL_BuiltIn_Commands + { + private RexScriptEngine myScriptEngine; + + public RexScriptInterface(OpenSim.Region.ScriptEngine.DotNetEngine.ScriptEngine ScriptEngine, SceneObjectPart host, uint localID, LLUUID itemID, RexScriptEngine vScriptEngine) + : base(ScriptEngine, host, localID, itemID) + { + myScriptEngine = vScriptEngine; + m_ScriptEngine = new OpenSim.Region.ScriptEngine.DotNetEngine.ScriptEngine(); + m_ScriptEngine.World = myScriptEngine.World; + } + + private EntityBase GetEntityBase(uint vId) + { + SceneObjectPart part = myScriptEngine.World.GetSceneObjectPart(vId); + if (part != null && (EntityBase)(part.ParentGroup) != null) + return (EntityBase)(part.ParentGroup); + else + return null; + } + + // Functions exposed to Python! + // ********************************* + public bool SetScriptRunner(string vId) + { + uint id = System.Convert.ToUInt32(vId, 10); + + SceneObjectPart tempobj = myScriptEngine.World.GetSceneObjectPart(id); + if (tempobj != null) + { + m_host = tempobj; + m_localID = tempobj.LocalID; + m_itemID = tempobj.UUID; + return true; + } + else + return false; + } + + public void CommandToClient(string vPresenceId, string vUnit, string vCommand, string vCmdParams) + { + LLUUID TempId = new LLUUID(vPresenceId); + ScenePresence temppre = myScriptEngine.World.GetScenePresence(TempId); + if (temppre != null) + temppre.ControllingClient.SendRexScriptCommand(vUnit,vCommand,vCmdParams); + } + + public bool GetPhysics(string vId) + { + SceneObjectPart tempobj = myScriptEngine.World.GetSceneObjectPart(System.Convert.ToUInt32(vId, 10)); + if (tempobj != null) + return ((tempobj.ObjectFlags & (uint)LLObject.ObjectFlags.Physics) != 0); + else + return false; + } + + public void SetPhysics(string vId, bool vbUsePhysics) + { + SceneObjectPart tempobj = myScriptEngine.World.GetSceneObjectPart(System.Convert.ToUInt32(vId, 10)); + if (tempobj != null) + { + if (vbUsePhysics) + tempobj.AddFlag(LLObject.ObjectFlags.Physics); + else + tempobj.RemFlag(LLObject.ObjectFlags.Physics); + + tempobj.DoPhysicsPropertyUpdate(vbUsePhysics, false); + tempobj.ScheduleFullUpdate(); + } + else + myScriptEngine.Log.Verbose("PythonScript", "SetPhysics for nonexisting object:" + vId); + } + + + + public void SetMass(string vId, float vMass) + { + SceneObjectPart tempobj = myScriptEngine.World.GetSceneObjectPart(System.Convert.ToUInt32(vId, 10)); + if (tempobj != null) + tempobj.SetMass(vMass); + else + myScriptEngine.Log.Verbose("PythonScript", "SetMass for nonexisting object:" + vId); + + } + + public void SetVelocity(string vId, LSL_Types.Vector3 vVelocity) + { + SceneObjectPart tempobj = myScriptEngine.World.GetSceneObjectPart(System.Convert.ToUInt32(vId, 10)); + if (((SceneObjectPart)tempobj) != null) + { + LLVector3 tempvel = new LLVector3((float)vVelocity.x, (float)vVelocity.y, (float)vVelocity.z); + tempobj.Velocity = tempvel; + } + } + + public bool GetUsePrimVolumeCollision(string vId) + { + SceneObjectPart tempobj = myScriptEngine.World.GetSceneObjectPart(System.Convert.ToUInt32(vId, 10)); + if (tempobj != null) + return tempobj.GetUsePrimVolumeCollision(); + else + return false; + } + + public void SetUsePrimVolumeCollision(string vId, bool vUseVolumeCollision) + { + SceneObjectPart tempobj = myScriptEngine.World.GetSceneObjectPart(System.Convert.ToUInt32(vId, 10)); + if (tempobj != null) + tempobj.SetUsePrimVolumeCollision(vUseVolumeCollision); + else + myScriptEngine.Log.Verbose("PythonScript", "SetPrimVolumeCollision for nonexisting object:" + vId); + } + + + + + + + + + // text messaging + // ****************************** + public void SendGeneralAlertAll(string vId, string vMessage) + { + myScriptEngine.World.SendGeneralAlert(vMessage); + } + + public void SendAlertToAvatar(string vId,string vPresenceId, string vMessage, bool vbModal) + { + LLUUID TempId = new LLUUID(vPresenceId); + ScenePresence temppre = myScriptEngine.World.GetScenePresence(TempId); + if (temppre != null) + { + temppre.ControllingClient.SendAgentAlertMessage(vMessage, vbModal); + } + } + + + + // Actor finding. + public List GetRadiusActors(string vId,float vRadius) + { + List TempList = new List(); + EntityBase tempobj = GetEntityBase(System.Convert.ToUInt32(vId, 10)); + if (tempobj != null) + { + List EntitiesList = myScriptEngine.World.GetEntities(); + foreach (EntityBase ent in EntitiesList) + { + if (ent is SceneObjectGroup || ent is ScenePresence) + { + if (Util.GetDistanceTo(ent.AbsolutePosition, tempobj.AbsolutePosition) < vRadius) + TempList.Add(ent.LocalId.ToString()); + } + } + } + return TempList; + } + + public List GetRadiusAvatars(string vId, float vRadius) + { + List TempList = new List(); + EntityBase tempobj = GetEntityBase(System.Convert.ToUInt32(vId, 10)); + if (tempobj != null) + { + List EntitiesList = myScriptEngine.World.GetEntities(); + foreach (EntityBase ent in EntitiesList) + { + if (ent is ScenePresence) + { + if (Util.GetDistanceTo(ent.AbsolutePosition, tempobj.AbsolutePosition) < vRadius) + TempList.Add(ent.LocalId.ToString()); + } + } + } + return TempList; + } + + + + public string SpawnActor(LSL_Types.Vector3 vLoc, int vShape, bool vbTemporary, string vPyClass) + { + LLUUID TempID = myScriptEngine.World.RegionInfo.MasterAvatarAssignedUUID; + LLVector3 pos = new LLVector3((float)vLoc.x, (float)vLoc.y, (float)vLoc.z); + LLQuaternion rot = new LLQuaternion(0.0f, 0.0f, 0.0f, 1.0f); + + uint AddResult = myScriptEngine.World.AddNewPrimReturningId(TempID, pos, rot, GetShape(vShape),vbTemporary,vPyClass); + return AddResult.ToString(); + } + + public bool DestroyActor(string vId) + { + + EntityBase tempobj = GetEntityBase(System.Convert.ToUInt32(vId, 10)); + if (((SceneObjectGroup)tempobj) != null) + { + ((SceneObjectGroup)tempobj).DeleteMe = true; // Do not call DeleteSceneObjectGroup for deleting directly + return true; + } + else + return false; + } + + public bool SetMesh(string vId,string vsName) + { + try + { + SceneObjectPart tempobj = myScriptEngine.World.GetSceneObjectPart(System.Convert.ToUInt32(vId, 10)); + if (tempobj != null) + { + if (vsName.Length > 0) + { + LLUUID tempid = myScriptEngine.World.AssetCache.ExistsAsset(43, vsName); + if (tempid != LLUUID.Zero) + { + tempobj.m_RexFlags |= SceneObjectPart.REXFLAGS_ISMESH | SceneObjectPart.REXFLAGS_ISVISIBLE; + tempobj.m_RexMeshUUID = tempid; + tempobj.UpdateRexParameters(); + return true; + } + } + else + { + tempobj.m_RexFlags &= SceneObjectPart.REXFLAGS_ISMESH & SceneObjectPart.REXFLAGS_ISVISIBLE; + tempobj.UpdateRexParameters(); + return true; + } + } + } + catch (Exception e) + { + myScriptEngine.Log.Verbose("RexScriptEngine", "SetMeshByLLUUID exception:" + e.ToString()); + } + return false; + } + + public bool SetMeshByLLUUID(string vId, string vsLLUUID) + { + try + { + SceneObjectPart tempobj = myScriptEngine.World.GetSceneObjectPart(System.Convert.ToUInt32(vId, 10)); + if (tempobj != null) + { + if (vsLLUUID.Length > 0) + { + tempobj.m_RexFlags |= SceneObjectPart.REXFLAGS_ISMESH | SceneObjectPart.REXFLAGS_ISVISIBLE; + tempobj.m_RexMeshUUID = new LLUUID(vsLLUUID); + tempobj.UpdateRexParameters(); + return true; + } + else + { + tempobj.m_RexFlags &= SceneObjectPart.REXFLAGS_ISMESH & SceneObjectPart.REXFLAGS_ISVISIBLE; + tempobj.UpdateRexParameters(); + return true; + } + } + } + catch (Exception e) + { + myScriptEngine.Log.Verbose("RexScriptEngine", "SetMeshByLLUUID exception:" + e.ToString()); + } + return false; + } + + + public bool SetMaterial(string vId,int vIndex,string vsName) + { + try + { + SceneObjectPart tempobj = myScriptEngine.World.GetSceneObjectPart(System.Convert.ToUInt32(vId, 10)); + if (tempobj != null) + { + if (vsName.Length > 0) + { + LLUUID tempid = myScriptEngine.World.AssetCache.ExistsAsset(0, vsName); + if (tempid != LLUUID.Zero) + { + if (vIndex < tempobj.m_RexMaterialUUID.Count) + { + tempobj.m_RexMaterialUUID[vIndex] = tempid; + } + else + { + for (int i = tempobj.m_RexMaterialUUID.Count; i < (vIndex + 1); i++) + tempobj.m_RexMaterialUUID.Add(LLUUID.Zero); + + tempobj.m_RexMaterialUUID[vIndex] = tempid; + } + tempobj.UpdateRexParameters(); + return true; + } + } + else + { + tempobj.UpdateRexParameters(); + return true; + } + } + } + catch (Exception e) + { + myScriptEngine.Log.Verbose("RexScriptEngine", "SetMaterial exception:" + e.ToString()); + } + return false; + } + + + + + private static PrimitiveBaseShape GetShape(int vShape) + { + PrimitiveBaseShape shape = new PrimitiveBaseShape(); + + shape.PCode = 9; + shape.PathBegin = 0; + shape.PathEnd = 0; + shape.PathScaleX = 100; + shape.PathScaleY = 100; + shape.PathShearX = 0; + shape.PathShearY = 0; + shape.PathSkew = 0; + shape.ProfileBegin = 0; + shape.ProfileEnd = 0; + shape.Scale.X = shape.Scale.Y = shape.Scale.Z = 0.5f; + shape.PathCurve = 16; + shape.ProfileCurve = 1; + shape.ProfileHollow = 0; + shape.PathRadiusOffset = 0; + shape.PathRevolutions = 0; + shape.PathTaperX = 0; + shape.PathTaperY = 0; + shape.PathTwist = 0; + shape.PathTwistBegin = 0; + LLObject.TextureEntry ntex = new LLObject.TextureEntry(new LLUUID("00000000-0000-1111-9999-000000000005")); + shape.TextureEntry = ntex.ToBytes(); + return shape; + } + + + + + + + + + // Scenepresence related + public string SPGetFullName(string vPresenceId) + { + LLUUID TempId = new LLUUID(vPresenceId); + ScenePresence temppre = myScriptEngine.World.GetScenePresence(TempId); + if (temppre != null) + { + string TempString = temppre.Firstname + " " + temppre.Lastname; + return TempString; + } + else + return ""; + } + public string SPGetFirstName(string vPresenceId) + { + LLUUID TempId = new LLUUID(vPresenceId); + ScenePresence temppre = myScriptEngine.World.GetScenePresence(TempId); + if (temppre != null) + return temppre.Firstname; + else + return ""; + } + public string SPGetLastName(string vPresenceId) + { + LLUUID TempId = new LLUUID(vPresenceId); + ScenePresence temppre = myScriptEngine.World.GetScenePresence(TempId); + if (temppre != null) + return temppre.Lastname; + else + return ""; + } + + public void SPDoLocalTeleport(string vPresenceId, LSL_Types.Vector3 vLocation) + { + LLUUID TempId = new LLUUID(vPresenceId); + ScenePresence temppre = myScriptEngine.World.GetScenePresence(TempId); + if (temppre != null) + { + LLVector3 position = new LLVector3((float)vLocation.x, (float)vLocation.y, (float)vLocation.z); + LLVector3 lookAt = new LLVector3(0,0,0); + temppre.ControllingClient.SendTeleportLocationStart(); + temppre.ControllingClient.SendLocalTeleport(position, lookAt,0); + temppre.Teleport(position); + } + } + + public float SPGetMovementModifier(string vPresenceId) + { + LLUUID TempId = new LLUUID(vPresenceId); + ScenePresence temppre = myScriptEngine.World.GetScenePresence(TempId); + if (temppre != null) + return temppre.MovementSpeedMod; + else + return 0.0f; + } + + public void SPSetMovementModifier(string vPresenceId,float vSpeedModifier) + { + + LLUUID TempId = new LLUUID(vPresenceId); + ScenePresence temppre = myScriptEngine.World.GetScenePresence(TempId); + if (temppre != null) + temppre.MovementSpeedMod = vSpeedModifier; + } + + public LSL_Types.Vector3 SPGetPos(string vPresenceId) + { + LSL_Types.Vector3 loc = new LSL_Types.Vector3(0, 0, 0); + + LLUUID TempId = new LLUUID(vPresenceId); + ScenePresence temppre = myScriptEngine.World.GetScenePresence(TempId); + if (temppre != null) + { + loc.x = temppre.AbsolutePosition.X; + loc.y = temppre.AbsolutePosition.Y; + loc.z = temppre.AbsolutePosition.Z; + } + return loc; + } + + public LSL_Types.Quaternion SPGetRot(string vPresenceId) + { + LSL_Types.Quaternion rot = new LSL_Types.Quaternion(0, 0, 0, 1); + + LLUUID TempId = new LLUUID(vPresenceId); + ScenePresence temppre = myScriptEngine.World.GetScenePresence(TempId); + if (temppre != null) + { + rot.x = temppre.Rotation.x; + rot.y = temppre.Rotation.y; + rot.z = temppre.Rotation.y; + rot.s = temppre.Rotation.w; + } + return rot; + } + + public void SPSetRot(string vPresenceId,LSL_Types.Quaternion vRot, bool vbRelative) + { + LLUUID TempId = new LLUUID(vPresenceId); + ScenePresence temppre = myScriptEngine.World.GetScenePresence(TempId); + if (temppre != null) + { + string sparams = vRot.x.ToString() + " " + vRot.y.ToString() + " " + vRot.z.ToString() + " " + vRot.s.ToString(); + sparams = sparams.Replace(",", "."); + if (vbRelative) + temppre.ControllingClient.SendRexScriptCommand("client", "setrelrot", sparams); + else + temppre.ControllingClient.SendRexScriptCommand("client", "setrot", sparams); + } + } + + + + // Functions not supported at the moment. + /* + public bool GetFreezed(string vId) + { + tucofixme + EntityBase tempobj = GetEntityBase(System.Convert.ToUInt32(vId, 10)); + if (tempobj != null) + { + return tempobj.IsFreezed; + } + else + { + return false; + } + + return false; + } + + public void SetFreezed(string vId, bool vbFreeze) + { + tucofixme + EntityBase tempobj = GetEntityBase(System.Convert.ToUInt32(vId, 10)); + if (tempobj != null) + { + tempobj.IsFreezed = vbFreeze; + if (tempobj is ScenePresence && vbFreeze) + ((ScenePresence)tempobj).rxStopAvatarMovement(); + } + + } */ + + /* + public int GetPhysicsMode(string vId) + { + // tucofixme + SceneObjectPart tempobj = myScriptEngine.World.GetSceneObjectPart(System.Convert.ToUInt32(vId, 10)); + if (tempobj != null) + return tempobj.GetPhysicsMode(); + else + return 0; + + return 0; + } + + public void SetPhysicsMode(string vId, int vPhysicsMode) + { + // tucofixme + SceneObjectPart tempobj = myScriptEngine.World.GetSceneObjectPart(System.Convert.ToUInt32(vId, 10)); + if (tempobj != null) + { + tempobj.SetPhysicsMode(vPhysicsMode); + } + else + myScriptEngine.Log.Verbose("PythonScript", "SetPhysicsMode for nonexisting object:" + vId); + } + */ + + + /* + public bool GetUseGravity(string vId) + { + // tucofixme + SceneObjectPart tempobj = myScriptEngine.World.GetSceneObjectPart(System.Convert.ToUInt32(vId, 10)); + if (tempobj != null) + return tempobj.GetUseGravity(); + else + return false; + + return false; + } + + public void SetUseGravity(string vId, bool vbUseGravity) + { + // tucofixme + SceneObjectPart tempobj = myScriptEngine.World.GetSceneObjectPart(System.Convert.ToUInt32(vId, 10)); + if (tempobj != null) + tempobj.SetUseGravity(vbUseGravity); + else + myScriptEngine.Log.Verbose("PythonScript", "SetUseGravity for nonexisting object:" + vId); + } + */ + + /* + public void SetLocationFast(string vId,rxVector vLoc) + { + EntityBase tempobj = GetEntityBase(System.Convert.ToUInt32(vId, 10)); + if (((SceneObjectGroup)tempobj) != null) + { + bool hasPrim = ((SceneObjectGroup)tempobj).HasChildPrim(tempobj.UUID); + if (hasPrim != false) + { + LLVector3 TempLoc = new LLVector3((float)vLoc.x, (float)vLoc.y, (float)vLoc.z); + LLVector3 TempOffset = new LLVector3(0, 0, 0); + ((SceneObjectGroup)tempobj).GrabMovement(TempOffset, TempLoc, null); // tucofixme, might break some day, because sending null remoteClient parameter + } + } + } + */ + } +} + + + + + + + + + diff --git a/OpenSim/Region/ScriptEngine/Common/LSL_Types.cs b/OpenSim/Region/ScriptEngine/Common/LSL_Types.cs index 0ae7a0adf3..7edccea217 100644 --- a/OpenSim/Region/ScriptEngine/Common/LSL_Types.cs +++ b/OpenSim/Region/ScriptEngine/Common/LSL_Types.cs @@ -227,7 +227,7 @@ namespace OpenSim.Region.ScriptEngine.Common public static float Mag(Vector3 v) { - return (float)Math.Sqrt(v.x * v.y + v.y * v.y + v.z * v.z); + return (float)Math.Sqrt(v.x * v.x + v.y * v.y + v.z * v.z); } public static Vector3 Norm(Vector3 vector) diff --git a/OpenSim/Region/ScriptEngine/Common/ScriptServerInterfaces.cs b/OpenSim/Region/ScriptEngine/Common/ScriptServerInterfaces.cs index 14b97b8b0f..6ac7c65e36 100644 --- a/OpenSim/Region/ScriptEngine/Common/ScriptServerInterfaces.cs +++ b/OpenSim/Region/ScriptEngine/Common/ScriptServerInterfaces.cs @@ -47,10 +47,6 @@ namespace OpenSim.Region.ScriptEngine.Common { RemoteEvents Events(); } - public interface ScriptEngine - { - RemoteEvents EventManager(); - } } } diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/Server_API/LSL_BuiltIn_Commands.cs b/OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/Server_API/LSL_BuiltIn_Commands.cs index 0ad10cc050..9d7e12bd76 100644 --- a/OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/Server_API/LSL_BuiltIn_Commands.cs +++ b/OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/Server_API/LSL_BuiltIn_Commands.cs @@ -34,6 +34,7 @@ using System.Threading; using Axiom.Math; using libsecondlife; using OpenSim.Framework; +using OpenSim.Framework.Communications.Cache; using OpenSim.Region.Environment.Interfaces; using OpenSim.Region.Environment.Scenes; using OpenSim.Region.ScriptEngine.Common; @@ -59,12 +60,19 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler public class LSL_BuiltIn_Commands : MarshalByRefObject, LSL_BuiltIn_Commands_Interface { private ASCIIEncoding enc = new ASCIIEncoding(); - private ScriptEngine m_ScriptEngine; - private SceneObjectPart m_host; - private uint m_localID; - private LLUUID m_itemID; + protected ScriptEngine m_ScriptEngine; + protected SceneObjectPart m_host; + protected uint m_localID; + protected LLUUID m_itemID; private bool throwErrorOnNotImplemented = true; + /// + /// + /// + /// + /// + /// Item's local id + /// Item's LLUUID public LSL_BuiltIn_Commands(ScriptEngine ScriptEngine, SceneObjectPart host, uint localID, LLUUID itemID) { m_ScriptEngine = ScriptEngine; @@ -255,17 +263,17 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler public LSL_Types.Vector3 llRot2Fwd(LSL_Types.Quaternion r) { - return new LSL_Types.Vector3(); + return (new LSL_Types.Vector3(1, 0, 0) * r); } public LSL_Types.Vector3 llRot2Left(LSL_Types.Quaternion r) { - return new LSL_Types.Vector3(); + return (new LSL_Types.Vector3(0, 1, 0) * r); } public LSL_Types.Vector3 llRot2Up(LSL_Types.Quaternion r) { - return new LSL_Types.Vector3(); + return (new LSL_Types.Vector3(0, 0, 1) * r); } public LSL_Types.Quaternion llRotBetween(LSL_Types.Vector3 a, LSL_Types.Vector3 b) { @@ -875,12 +883,45 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler public void llSound() { - NotImplemented("llSound"); + // This function has been deprecated + // see http://www.lslwiki.net/lslwiki/wakka.php?wakka=llSound } public void llPlaySound(string sound, double volume) { - NotImplemented("llPlaySound"); + if (volume > 1) + volume = 1; + if (volume < 0) + volume = 0; + + LLUUID ownerID = m_host.OwnerID; + LLUUID objectID = m_host.UUID; + LLUUID soundID; + byte flags = 0; + + if (!LLUUID.TryParse(sound, out soundID)) + { + soundID = World.AssetCache.ExistsAsset(LSL_BaseClass.INVENTORY_SOUND, sound); // hack + + // search sound file from inventory + SceneObjectPart op = World.GetSceneObjectPart(objectID); + foreach (KeyValuePair item in op.TaskInventory) + { + string test = item.Value.type; + if (item.Value.name == sound) + { + soundID = item.Value.item_id; + break; + } + } + } + + List avatarts = World.GetAvatars(); + foreach (ScenePresence p in avatarts) + { + // TODO: some filtering by distance of avatar + p.ControllingClient.SendPlayAttachedSound(soundID, objectID, ownerID, (float)volume, flags); + } } public void llLoopSound(string sound, double volume) @@ -905,7 +946,41 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler public void llTriggerSound(string sound, double volume) { - NotImplemented("llTriggerSound"); + if (volume > 1) + volume = 1; + if (volume < 0) + volume = 0; + + LLUUID ownerID = m_host.OwnerID; + LLUUID objectID = m_host.UUID; + LLUUID parentID = this.m_host.GetRootPartUUID(); + LLUUID soundID; + LLVector3 position = this.m_host.AbsolutePosition; // region local + ulong regionHandle = World.RegionInfo.RegionHandle; + + if (!LLUUID.TryParse(sound, out soundID)) + { + soundID = World.AssetCache.ExistsAsset(LSL_BaseClass.INVENTORY_SOUND, sound); // hack + + // search sound file from inventory + SceneObjectPart op = World.GetSceneObjectPart(objectID); + foreach (KeyValuePair item in op.TaskInventory) + { + string test = item.Value.type; + if (item.Value.name == sound) + { + soundID = item.Value.item_id; + break; + } + } + } + + List avatarts = World.GetAvatars(); + foreach (ScenePresence p in avatarts) + { + // TODO: some filtering by distance of avatar + p.ControllingClient.SendTriggeredSound(soundID, ownerID, objectID, parentID, regionHandle, position, (float)volume); + } } public void llStopSound() @@ -915,7 +990,33 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler public void llPreloadSound(string sound) { - NotImplemented("llPreloadSound"); + LLUUID ownerID = m_host.OwnerID; + LLUUID objectID = m_host.UUID; + LLUUID soundID; + + if (!LLUUID.TryParse(sound, out soundID)) + { + soundID = World.AssetCache.ExistsAsset(LSL_BaseClass.INVENTORY_SOUND, sound); // hack + + // search sound file from inventory + SceneObjectPart op = World.GetSceneObjectPart(objectID); + foreach (KeyValuePair item in op.TaskInventory) + { + string test = item.Value.type; + if (item.Value.name == sound) + { + soundID = item.Value.item_id; + break; + } + } + } + + List avatarts = World.GetAvatars(); + foreach (ScenePresence p in avatarts) + { + // TODO: some filtering by distance of avatar + p.ControllingClient.SendPreLoadSound(objectID, objectID, soundID ); + } } public string llGetSubString(string src, int start, int end) @@ -2231,7 +2332,19 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler public void llDialog(string avatar, string message, LSL_Types.list buttons, int chat_channel) { - NotImplemented("llDialog"); + LLUUID av = new LLUUID(); + if (!LLUUID.TryParse(avatar, out av)) + { + LSLError("First parameter to llDialog needs to be a key"); + return; + } + string[] buts = new string[buttons.Length]; + for (int i = 0; i < buttons.Length; i++) + { + buts[i] = buttons.Data[i].ToString(); + } + World.SendDialogToUser(av, m_host.Name, m_host.UUID, m_host.OwnerID, message, new LLUUID("00000000-0000-2222-3333-100000001000"), chat_channel, buts); + //NotImplemented("llDialog"); } public void llVolumeDetect(int detect) @@ -2699,7 +2812,10 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler public void llMapDestination(string simname, LSL_Types.Vector3 pos, LSL_Types.Vector3 look_at) { - NotImplemented("llMapDestination"); + libsecondlife.LLVector3 position = new LLVector3((float)pos.x, (float)pos.y, (float)pos.z); + libsecondlife.LLVector3 lookAt = new LLVector3((float)look_at.x, (float)look_at.y, (float)look_at.z); + ScenePresence user = this.World.GetScenePresence(this.m_host.TouchedBy); + user.ControllingClient.SendScriptTeleportRequest(this.m_host.Name, simname, position, lookAt); } public void llAddToLandBanList(string avatar, double hours) diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/EventManager.cs b/OpenSim/Region/ScriptEngine/DotNetEngine/EventManager.cs index ad29feb51d..bc0b11dbc8 100644 --- a/OpenSim/Region/ScriptEngine/DotNetEngine/EventManager.cs +++ b/OpenSim/Region/ScriptEngine/DotNetEngine/EventManager.cs @@ -74,6 +74,8 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine // Add to queue for all scripts in ObjectID object //myScriptEngine.m_logger.Verbose("ScriptEngine", "EventManager Event: touch_start"); //Console.WriteLine("touch_start localID: " + localID); + OpenSim.Region.Environment.Scenes.SceneObjectPart sop = this.myScriptEngine.World.GetSceneObjectPart(localID); + sop.TouchedBy = remoteClient.AgentId; myScriptEngine.m_EventQueueManager.AddToObjectQueue(localID, "touch_start", new object[] {(int) 1}); } diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptEngine.cs b/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptEngine.cs index 604a5f30cf..11419be2eb 100644 --- a/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptEngine.cs +++ b/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptEngine.cs @@ -31,7 +31,6 @@ using Nini.Config; using OpenSim.Framework.Console; using OpenSim.Region.Environment.Interfaces; using OpenSim.Region.Environment.Scenes; -using OpenSim.Region.ScriptEngine.Common; namespace OpenSim.Region.ScriptEngine.DotNetEngine { @@ -40,7 +39,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine /// /// [Serializable] - public class ScriptEngine : IRegionModule, OpenSim.Region.ScriptEngine.Common.ScriptServerInterfaces.ScriptEngine + public class ScriptEngine : IRegionModule { public Scene World; public EventManager m_EventManager; // Handles and queues incoming events from OpenSim @@ -87,10 +86,6 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine // We are shutting down } - ScriptServerInterfaces.RemoteEvents ScriptServerInterfaces.ScriptEngine.EventManager() - { - return this.m_EventManager; - } #region IRegionModule @@ -119,6 +114,5 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine } #endregion - } } \ No newline at end of file diff --git a/OpenSim/Region/Storage/OpenSim.DataStore.MonoSqlite/MonoSqliteDataStore.cs b/OpenSim/Region/Storage/OpenSim.DataStore.MonoSqlite/MonoSqliteDataStore.cs new file mode 100644 index 0000000000..bd09eae4d1 --- /dev/null +++ b/OpenSim/Region/Storage/OpenSim.DataStore.MonoSqlite/MonoSqliteDataStore.cs @@ -0,0 +1,1774 @@ +/* +* 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.Data; +using System.IO; +using libsecondlife; +using Mono.Data.SqliteClient; +using OpenSim.Framework; +using OpenSim.Framework.Console; +using OpenSim.Region.Environment.Interfaces; +using OpenSim.Region.Environment.LandManagement; +using OpenSim.Region.Environment.Scenes; + +namespace OpenSim.DataStore.MonoSqlite +{ + public class MonoSqliteDataStore : IRegionDataStore + { + private const string primSelect = "select * from prims"; + private const string shapeSelect = "select * from primshapes"; + private const string itemsSelect = "select * from primitems"; + private const string terrainSelect = "select * from terrain limit 1"; + private const string landSelect = "select * from land"; + private const string landAccessListSelect = "select * from landaccesslist"; + + private DataSet ds; + private SqliteDataAdapter primDa; + private SqliteDataAdapter shapeDa; + private SqliteDataAdapter itemsDa; + private SqliteDataAdapter terrainDa; + private SqliteDataAdapter landDa; + private SqliteDataAdapter landAccessListDa; + + private SqliteConnection m_conn; + + private String m_connectionString; + + private bool persistPrimInventories; + + /*********************************************************************** + * + * Public Interface Functions + * + **********************************************************************/ + + // see IRegionDataStore + public void Initialise(string connectionString, bool persistPrimInventories) + { + m_connectionString = connectionString; + this.persistPrimInventories = persistPrimInventories; + + ds = new DataSet(); + + MainLog.Instance.Verbose("DATASTORE", "Sqlite - connecting: " + connectionString); + SqliteConnection conn = new SqliteConnection(m_connectionString); + + // Arg! Hate databases.. + m_conn = conn; + + SqliteCommand primSelectCmd = new SqliteCommand(primSelect, conn); + primDa = new SqliteDataAdapter(primSelectCmd); + // SqliteCommandBuilder primCb = new SqliteCommandBuilder(primDa); + + SqliteCommand shapeSelectCmd = new SqliteCommand(shapeSelect, conn); + shapeDa = new SqliteDataAdapter(shapeSelectCmd); + // SqliteCommandBuilder shapeCb = new SqliteCommandBuilder(shapeDa); + + SqliteCommand itemsSelectCmd = new SqliteCommand(itemsSelect, conn); + itemsDa = new SqliteDataAdapter(itemsSelectCmd); + + SqliteCommand terrainSelectCmd = new SqliteCommand(terrainSelect, conn); + terrainDa = new SqliteDataAdapter(terrainSelectCmd); + + SqliteCommand landSelectCmd = new SqliteCommand(landSelect, conn); + landDa = new SqliteDataAdapter(landSelectCmd); + + SqliteCommand landAccessListSelectCmd = new SqliteCommand(landAccessListSelect, conn); + landAccessListDa = new SqliteDataAdapter(landAccessListSelectCmd); + + // We fill the data set, now we've got copies in memory for the information + // TODO: see if the linkage actually holds. + // primDa.FillSchema(ds, SchemaType.Source, "PrimSchema"); + TestTables(conn); + + lock (ds) + { + ds.Tables.Add(createPrimTable()); + setupPrimCommands(primDa, conn); + primDa.Fill(ds.Tables["prims"]); + + ds.Tables.Add(createShapeTable()); + setupShapeCommands(shapeDa, conn); + + if (persistPrimInventories) + { + ds.Tables.Add(createItemsTable()); + setupItemsCommands(itemsDa, conn); + itemsDa.Fill(ds.Tables["primitems"]); + } + + ds.Tables.Add(createTerrainTable()); + setupTerrainCommands(terrainDa, conn); + + ds.Tables.Add(createLandTable()); + setupLandCommands(landDa, conn); + + ds.Tables.Add(createLandAccessListTable()); + setupLandAccessCommands(landAccessListDa, conn); + + // WORKAROUND: This is a work around for sqlite on + // windows, which gets really unhappy with blob columns + // that have no sample data in them. At some point we + // need to actually find a proper way to handle this. + try + { + shapeDa.Fill(ds.Tables["primshapes"]); + } + catch (Exception) + { + MainLog.Instance.Verbose("DATASTORE", "Caught fill error on primshapes table"); + } + + try + { + terrainDa.Fill(ds.Tables["terrain"]); + } + catch (Exception) + { + MainLog.Instance.Verbose("DATASTORE", "Caught fill error on terrain table"); + } + + try + { + landDa.Fill(ds.Tables["land"]); + } + catch (Exception) + { + MainLog.Instance.Verbose("DATASTORE", "Caught fill error on land table"); + } + + try + { + landAccessListDa.Fill(ds.Tables["landaccesslist"]); + } + catch (Exception) + { + MainLog.Instance.Verbose("DATASTORE", "Caught fill error on landaccesslist table"); + } + return; + } + } + + public void StoreObject(SceneObjectGroup obj, LLUUID regionUUID) + { + lock (ds) + { + foreach (SceneObjectPart prim in obj.Children.Values) + { + if ((prim.ObjectFlags & (uint) LLObject.ObjectFlags.Physics) == 0) + { + MainLog.Instance.Verbose("DATASTORE", "Adding obj: " + obj.UUID + " to region: " + regionUUID); + addPrim(prim, Util.ToRawUuidString(obj.UUID), Util.ToRawUuidString(regionUUID)); + } + else if (prim.Stopped) + { + MainLog.Instance.Verbose("DATASTORE", + "Adding stopped obj: " + obj.UUID + " to region: " + regionUUID); + addPrim(prim, Util.ToRawUuidString(obj.UUID), Util.ToRawUuidString(regionUUID)); + } + else + { + // MainLog.Instance.Verbose("DATASTORE", "Ignoring Physical obj: " + obj.UUID + " in region: " + regionUUID); + } + } + } + + Commit(); + // MainLog.Instance.Verbose("Dump of prims:", ds.GetXml()); + } + + public void RemoveObject(LLUUID obj, LLUUID regionUUID) + { + DataTable prims = ds.Tables["prims"]; + DataTable shapes = ds.Tables["primshapes"]; + + string selectExp = "SceneGroupID = '" + Util.ToRawUuidString(obj) + "'"; + lock (ds) + { + DataRow[] primRows = prims.Select(selectExp); + foreach (DataRow row in primRows) + { + LLUUID uuid = new LLUUID((string) row["UUID"]); + DataRow shapeRow = shapes.Rows.Find(Util.ToRawUuidString(uuid)); + if (shapeRow != null) + { + shapeRow.Delete(); + } + row.Delete(); + } + } + + Commit(); + } + + /// + /// Load persisted objects from region storage. + /// + /// + /// List of loaded groups + public List LoadObjects(LLUUID regionUUID) + { + Dictionary createdObjects = new Dictionary(); + + List retvals = new List(); + + DataTable prims = ds.Tables["prims"]; + DataTable shapes = ds.Tables["primshapes"]; + + string byRegion = "RegionUUID = '" + Util.ToRawUuidString(regionUUID) + "'"; + string orderByParent = "ParentID ASC"; + + lock (ds) + { + DataRow[] primsForRegion = prims.Select(byRegion, orderByParent); + MainLog.Instance.Verbose("DATASTORE", + "Loaded " + primsForRegion.Length + " prims for region: " + regionUUID); + + foreach (DataRow primRow in primsForRegion) + { + try + { + SceneObjectPart prim = null; + + string uuid = (string) primRow["UUID"]; + string objID = (string) primRow["SceneGroupID"]; + if (uuid == objID) //is new SceneObjectGroup ? + { + SceneObjectGroup group = new SceneObjectGroup(); + prim = buildPrim(primRow); + DataRow shapeRow = shapes.Rows.Find(Util.ToRawUuidString(prim.UUID)); + if (shapeRow != null) + { + prim.Shape = buildShape(shapeRow); + } + else + { + MainLog.Instance.Notice( + "No shape found for prim in storage, so setting default box shape"); + prim.Shape = PrimitiveBaseShape.Default; + } + group.AddPart(prim); + group.RootPart = prim; + + createdObjects.Add(Util.ToRawUuidString(group.UUID), group); + retvals.Add(group); + } + else + { + prim = buildPrim(primRow); + DataRow shapeRow = shapes.Rows.Find(Util.ToRawUuidString(prim.UUID)); + if (shapeRow != null) + { + prim.Shape = buildShape(shapeRow); + } + else + { + MainLog.Instance.Notice( + "No shape found for prim in storage, so setting default box shape"); + prim.Shape = PrimitiveBaseShape.Default; + } + createdObjects[new LLUUID(objID)].AddPart(prim); + } + + if (persistPrimInventories) + { + LoadItems(prim); + } + } + catch (Exception e) + { + MainLog.Instance.Error("DATASTORE", "Failed create prim object, exception and data follows"); + MainLog.Instance.Verbose("DATASTORE", e.ToString()); + foreach (DataColumn col in prims.Columns) + { + MainLog.Instance.Verbose("DATASTORE", "Col: " + col.ColumnName + " => " + primRow[col]); + } + } + } + } + return retvals; + } + + /// + /// Load in a prim's persisted inventory. + /// + /// + private void LoadItems(SceneObjectPart prim) + { + MainLog.Instance.Verbose("DATASTORE", "Loading inventory for {0}, {1}", prim.Name, prim.UUID); + + DataTable dbItems = ds.Tables["primitems"]; + + String sql = String.Format("primID = '{0}'", prim.UUID.ToString()); + DataRow[] dbItemRows = dbItems.Select(sql); + + IList inventory = new List(); + + foreach (DataRow row in dbItemRows) + { + TaskInventoryItem item = buildItem(row); + inventory.Add(item); + + MainLog.Instance.Verbose("DATASTORE", "Restored item {0}, {1}", item.name, item.item_id); + } + + prim.AddInventoryItems(inventory); + + // XXX A nasty little hack to recover the folder id for the prim (which is currently stored in + // every item). This data should really be stored in the prim table itself. + if (dbItemRows.Length > 0) + { + prim.FolderID = inventory[0].parent_id; + } + } + + public void StoreTerrain(double[,] ter, LLUUID regionID) + { + lock (ds) + { + int revision = Util.UnixTimeSinceEpoch(); + + // the following is an work around for .NET. The perf + // issues associated with it aren't as bad as you think. + SqliteConnection conn = new SqliteConnection(m_connectionString); + conn.Open(); + MainLog.Instance.Verbose("DATASTORE", "Storing terrain revision r" + revision.ToString()); + String sql = "insert into terrain(RegionUUID, Revision, Heightfield)" + + " values(:RegionUUID, :Revision, :Heightfield)"; + + using (SqliteCommand cmd = new SqliteCommand(sql, conn)) + { + cmd.Parameters.Add(new SqliteParameter(":RegionUUID", Util.ToRawUuidString(regionID))); + cmd.Parameters.Add(new SqliteParameter(":Revision", revision)); + cmd.Parameters.Add(new SqliteParameter(":Heightfield", serializeTerrain(ter))); + cmd.ExecuteNonQuery(); + } + + // This is added to get rid of the infinitely growing + // terrain databases which negatively impact on SQLite + // over time. Before reenabling this feature there + // needs to be a limitter put on the number of + // revisions in the database, as this old + // implementation is a DOS attack waiting to happen. + + using ( + SqliteCommand cmd = + new SqliteCommand("delete from terrain where RegionUUID=:RegionUUID and Revision < :Revision", + conn)) + { + cmd.Parameters.Add(new SqliteParameter(":RegionUUID", Util.ToRawUuidString(regionID))); + cmd.Parameters.Add(new SqliteParameter(":Revision", revision)); + cmd.ExecuteNonQuery(); + } + conn.Close(); + } + } + + public double[,] LoadTerrain(LLUUID regionID) + { + lock (ds) + { + double[,] terret = new double[256,256]; + terret.Initialize(); + // the following is an work around for .NET. The perf + // issues associated with it aren't as bad as you think. + SqliteConnection conn = new SqliteConnection(m_connectionString); + conn.Open(); + String sql = "select RegionUUID, Revision, Heightfield from terrain" + + " where RegionUUID=:RegionUUID order by Revision desc"; + + + using (SqliteCommand cmd = new SqliteCommand(sql, conn)) + { + cmd.Parameters.Add(new SqliteParameter(":RegionUUID", Util.ToRawUuidString(regionID))); + + using (IDataReader row = cmd.ExecuteReader()) + { + int rev = 0; + if (row.Read()) + { + // TODO: put this into a function + byte[] heightmap = (byte[]) row["Heightfield"]; + for (int x = 0; x < 256; x++) + { + for (int y = 0; y < 256; y++) + { + terret[x, y] = BitConverter.ToDouble(heightmap, ((x*256) + y)*8); + } + } + rev = (int) row["Revision"]; + } + else + { + MainLog.Instance.Verbose("DATASTORE", "No terrain found for region"); + conn.Close(); + return null; + } + + MainLog.Instance.Verbose("DATASTORE", "Loaded terrain revision r" + rev.ToString()); + } + } + conn.Close(); + return terret; + } + } + + public void RemoveLandObject(LLUUID globalID) + { + lock (ds) + { + SqliteConnection conn = new SqliteConnection(m_connectionString); + conn.Open(); + + using (SqliteCommand cmd = new SqliteCommand("delete from land where UUID=:UUID", conn)) + { + cmd.Parameters.Add(new SqliteParameter(":UUID", Util.ToRawUuidString(globalID))); + cmd.ExecuteNonQuery(); + } + + using (SqliteCommand cmd = new SqliteCommand("delete from landaccesslist where LandUUID=:UUID", conn)) + { + cmd.Parameters.Add(new SqliteParameter(":UUID", Util.ToRawUuidString(globalID))); + cmd.ExecuteNonQuery(); + } + conn.Close(); + } + } + + public void StoreLandObject(Land parcel, LLUUID regionUUID) + { + lock (ds) + { + SqliteConnection conn = new SqliteConnection(m_connectionString); + conn.Open(); + DataTable land = ds.Tables["land"]; + DataTable landaccesslist = ds.Tables["landaccesslist"]; + + DataRow landRow = land.Rows.Find(Util.ToRawUuidString(parcel.landData.globalID)); + if (landRow == null) + { + landRow = land.NewRow(); + fillLandRow(landRow, parcel.landData, regionUUID); + land.Rows.Add(landRow); + } + else + { + fillLandRow(landRow, parcel.landData, regionUUID); + } + + using ( + SqliteCommand cmd = new SqliteCommand("delete from landaccesslist where LandUUID=:LandUUID", conn)) + { + cmd.Parameters.Add(new SqliteParameter(":LandUUID", Util.ToRawUuidString(parcel.landData.globalID))); + cmd.ExecuteNonQuery(); + } + + foreach (ParcelManager.ParcelAccessEntry entry in parcel.landData.parcelAccessList) + { + DataRow newAccessRow = landaccesslist.NewRow(); + fillLandAccessRow(newAccessRow, entry, parcel.landData.globalID); + landaccesslist.Rows.Add(newAccessRow); + } + conn.Close(); + } + + Commit(); + } + + public List LoadLandObjects(LLUUID regionUUID) + { + List landDataForRegion = new List(); + lock (ds) + { + DataTable land = ds.Tables["land"]; + DataTable landaccesslist = ds.Tables["landaccesslist"]; + string searchExp = "RegionUUID = '" + Util.ToRawUuidString(regionUUID) + "'"; + DataRow[] rawDataForRegion = land.Select(searchExp); + foreach (DataRow rawDataLand in rawDataForRegion) + { + LandData newLand = buildLandData(rawDataLand); + string accessListSearchExp = "LandUUID = '" + Util.ToRawUuidString(newLand.globalID) + "'"; + DataRow[] rawDataForLandAccessList = landaccesslist.Select(accessListSearchExp); + foreach (DataRow rawDataLandAccess in rawDataForLandAccessList) + { + newLand.parcelAccessList.Add(buildLandAccessData(rawDataLandAccess)); + } + + landDataForRegion.Add(newLand); + } + } + return landDataForRegion; + } + + public void Commit() + { + lock (ds) + { + primDa.Update(ds, "prims"); + shapeDa.Update(ds, "primshapes"); + + if (persistPrimInventories) + { + itemsDa.Update(ds, "primitems"); + } + + terrainDa.Update(ds, "terrain"); + landDa.Update(ds, "land"); + landAccessListDa.Update(ds, "landaccesslist"); + ds.AcceptChanges(); + } + } + + public void Shutdown() + { + Commit(); + } + + /*********************************************************************** + * + * Database Definition Functions + * + * This should be db agnostic as we define them in ADO.NET terms + * + **********************************************************************/ + + private void createCol(DataTable dt, string name, Type type) + { + DataColumn col = new DataColumn(name, type); + dt.Columns.Add(col); + } + + private DataTable createTerrainTable() + { + DataTable terrain = new DataTable("terrain"); + + createCol(terrain, "RegionUUID", typeof (String)); + createCol(terrain, "Revision", typeof (Int32)); + createCol(terrain, "Heightfield", typeof (Byte[])); + + return terrain; + } + + private DataTable createPrimTable() + { + DataTable prims = new DataTable("prims"); + + createCol(prims, "UUID", typeof (String)); + createCol(prims, "RegionUUID", typeof (String)); + createCol(prims, "ParentID", typeof (Int32)); + createCol(prims, "CreationDate", typeof (Int32)); + createCol(prims, "Name", typeof (String)); + createCol(prims, "SceneGroupID", typeof (String)); + // various text fields + createCol(prims, "Text", typeof (String)); + createCol(prims, "Description", typeof (String)); + createCol(prims, "SitName", typeof (String)); + createCol(prims, "TouchName", typeof (String)); + // rex objectclickaction + createCol(prims, "ClickAction", typeof(Byte)); + // permissions + createCol(prims, "ObjectFlags", typeof (Int32)); + createCol(prims, "CreatorID", typeof (String)); + createCol(prims, "OwnerID", typeof (String)); + createCol(prims, "GroupID", typeof (String)); + createCol(prims, "LastOwnerID", typeof (String)); + createCol(prims, "OwnerMask", typeof (Int32)); + createCol(prims, "NextOwnerMask", typeof (Int32)); + createCol(prims, "GroupMask", typeof (Int32)); + createCol(prims, "EveryoneMask", typeof (Int32)); + createCol(prims, "BaseMask", typeof (Int32)); + // vectors + createCol(prims, "PositionX", typeof (Double)); + createCol(prims, "PositionY", typeof (Double)); + createCol(prims, "PositionZ", typeof (Double)); + createCol(prims, "GroupPositionX", typeof (Double)); + createCol(prims, "GroupPositionY", typeof (Double)); + createCol(prims, "GroupPositionZ", typeof (Double)); + createCol(prims, "VelocityX", typeof (Double)); + createCol(prims, "VelocityY", typeof (Double)); + createCol(prims, "VelocityZ", typeof (Double)); + createCol(prims, "AngularVelocityX", typeof (Double)); + createCol(prims, "AngularVelocityY", typeof (Double)); + createCol(prims, "AngularVelocityZ", typeof (Double)); + createCol(prims, "AccelerationX", typeof (Double)); + createCol(prims, "AccelerationY", typeof (Double)); + createCol(prims, "AccelerationZ", typeof (Double)); + // quaternions + createCol(prims, "RotationX", typeof (Double)); + createCol(prims, "RotationY", typeof (Double)); + createCol(prims, "RotationZ", typeof (Double)); + createCol(prims, "RotationW", typeof (Double)); + + // sit target + createCol(prims, "SitTargetOffsetX", typeof (Double)); + createCol(prims, "SitTargetOffsetY", typeof (Double)); + createCol(prims, "SitTargetOffsetZ", typeof (Double)); + + createCol(prims, "SitTargetOrientW", typeof (Double)); + createCol(prims, "SitTargetOrientX", typeof (Double)); + createCol(prims, "SitTargetOrientY", typeof (Double)); + createCol(prims, "SitTargetOrientZ", typeof (Double)); + + // Add in contraints + prims.PrimaryKey = new DataColumn[] {prims.Columns["UUID"]}; + + return prims; + } + + private DataTable createShapeTable() + { + DataTable shapes = new DataTable("primshapes"); + createCol(shapes, "UUID", typeof (String)); + // shape is an enum + createCol(shapes, "Shape", typeof (Int32)); + // vectors + createCol(shapes, "ScaleX", typeof (Double)); + createCol(shapes, "ScaleY", typeof (Double)); + createCol(shapes, "ScaleZ", typeof (Double)); + // paths + createCol(shapes, "PCode", typeof (Int32)); + createCol(shapes, "PathBegin", typeof (Int32)); + createCol(shapes, "PathEnd", typeof (Int32)); + createCol(shapes, "PathScaleX", typeof (Int32)); + createCol(shapes, "PathScaleY", typeof (Int32)); + createCol(shapes, "PathShearX", typeof (Int32)); + createCol(shapes, "PathShearY", typeof (Int32)); + createCol(shapes, "PathSkew", typeof (Int32)); + createCol(shapes, "PathCurve", typeof (Int32)); + createCol(shapes, "PathRadiusOffset", typeof (Int32)); + createCol(shapes, "PathRevolutions", typeof (Int32)); + createCol(shapes, "PathTaperX", typeof (Int32)); + createCol(shapes, "PathTaperY", typeof (Int32)); + createCol(shapes, "PathTwist", typeof (Int32)); + createCol(shapes, "PathTwistBegin", typeof (Int32)); + // profile + createCol(shapes, "ProfileBegin", typeof (Int32)); + createCol(shapes, "ProfileEnd", typeof (Int32)); + createCol(shapes, "ProfileCurve", typeof (Int32)); + createCol(shapes, "ProfileHollow", typeof (Int32)); + // text TODO: this isn't right, but I'm not sure the right + // way to specify this as a blob atm + createCol(shapes, "Texture", typeof (Byte[])); + createCol(shapes, "ExtraParams", typeof (Byte[])); + + shapes.PrimaryKey = new DataColumn[] {shapes.Columns["UUID"]}; + + return shapes; + } + + private DataTable createItemsTable() + { + DataTable items = new DataTable("primitems"); + + createCol(items, "itemID", typeof (String)); + createCol(items, "primID", typeof (String)); + createCol(items, "assetID", typeof (String)); + createCol(items, "parentFolderID", typeof (String)); + + createCol(items, "invType", typeof (String)); + createCol(items, "assetType", typeof (String)); + + createCol(items, "name", typeof (String)); + createCol(items, "description", typeof (String)); + + createCol(items, "creationDate", typeof (Int64)); + createCol(items, "creatorID", typeof (String)); + createCol(items, "ownerID", typeof (String)); + createCol(items, "lastOwnerID", typeof (String)); + createCol(items, "groupID", typeof (String)); + + createCol(items, "nextPermissions", typeof (UInt32)); + createCol(items, "currentPermissions", typeof (UInt32)); + createCol(items, "basePermissions", typeof (UInt32)); + createCol(items, "everyonePermissions", typeof (UInt32)); + createCol(items, "groupPermissions", typeof (UInt32)); + + items.PrimaryKey = new DataColumn[] {items.Columns["itemID"]}; + + return items; + } + + private DataTable createLandTable() + { + DataTable land = new DataTable("land"); + createCol(land, "UUID", typeof (String)); + createCol(land, "RegionUUID", typeof (String)); + createCol(land, "LocalLandID", typeof (UInt32)); + + // Bitmap is a byte[512] + createCol(land, "Bitmap", typeof (Byte[])); + + createCol(land, "Name", typeof (String)); + createCol(land, "Desc", typeof (String)); + createCol(land, "OwnerUUID", typeof (String)); + createCol(land, "IsGroupOwned", typeof (Boolean)); + createCol(land, "Area", typeof (Int32)); + createCol(land, "AuctionID", typeof (Int32)); //Unemplemented + createCol(land, "Category", typeof (Int32)); //Enum libsecondlife.Parcel.ParcelCategory + createCol(land, "ClaimDate", typeof (Int32)); + createCol(land, "ClaimPrice", typeof (Int32)); + createCol(land, "GroupUUID", typeof (string)); + createCol(land, "SalePrice", typeof (Int32)); + createCol(land, "LandStatus", typeof (Int32)); //Enum. libsecondlife.Parcel.ParcelStatus + createCol(land, "LandFlags", typeof (UInt32)); + createCol(land, "LandingType", typeof (Byte)); + createCol(land, "MediaAutoScale", typeof (Byte)); + createCol(land, "MediaTextureUUID", typeof (String)); + createCol(land, "MediaURL", typeof (String)); + createCol(land, "MusicURL", typeof (String)); + createCol(land, "PassHours", typeof (Double)); + createCol(land, "PassPrice", typeof (UInt32)); + createCol(land, "SnapshotUUID", typeof (String)); + createCol(land, "UserLocationX", typeof (Double)); + createCol(land, "UserLocationY", typeof (Double)); + createCol(land, "UserLocationZ", typeof (Double)); + createCol(land, "UserLookAtX", typeof (Double)); + createCol(land, "UserLookAtY", typeof (Double)); + createCol(land, "UserLookAtZ", typeof (Double)); + + land.PrimaryKey = new DataColumn[] {land.Columns["UUID"]}; + + return land; + } + + private DataTable createLandAccessListTable() + { + DataTable landaccess = new DataTable("landaccesslist"); + createCol(landaccess, "LandUUID", typeof (String)); + createCol(landaccess, "AccessUUID", typeof (String)); + createCol(landaccess, "Flags", typeof (UInt32)); + + return landaccess; + } + + /*********************************************************************** + * + * Convert between ADO.NET <=> OpenSim Objects + * + * These should be database independant + * + **********************************************************************/ + + private SceneObjectPart buildPrim(DataRow row) + { + // TODO: this doesn't work yet because something more + // interesting has to be done to actually get these values + // back out. Not enough time to figure it out yet. + SceneObjectPart prim = new SceneObjectPart(); + prim.UUID = new LLUUID((String) row["UUID"]); + // explicit conversion of integers is required, which sort + // of sucks. No idea if there is a shortcut here or not. + prim.ParentID = Convert.ToUInt32(row["ParentID"]); + prim.CreationDate = Convert.ToInt32(row["CreationDate"]); + prim.Name = (String) row["Name"]; + // various text fields + prim.Text = (String) row["Text"]; + prim.Description = (String) row["Description"]; + prim.SitName = (String) row["SitName"]; + prim.TouchName = (String) row["TouchName"]; + // rex objectclickaction + try + { + prim.ClickAction = Convert.ToByte(row["ClickAction"]); + } + catch (InvalidCastException) + { + prim.ClickAction = 0; + } + + // permissions + prim.ObjectFlags = Convert.ToUInt32(row["ObjectFlags"]); + prim.CreatorID = new LLUUID((String) row["CreatorID"]); + prim.OwnerID = new LLUUID((String) row["OwnerID"]); + prim.GroupID = new LLUUID((String) row["GroupID"]); + prim.LastOwnerID = new LLUUID((String) row["LastOwnerID"]); + prim.OwnerMask = Convert.ToUInt32(row["OwnerMask"]); + prim.NextOwnerMask = Convert.ToUInt32(row["NextOwnerMask"]); + prim.GroupMask = Convert.ToUInt32(row["GroupMask"]); + prim.EveryoneMask = Convert.ToUInt32(row["EveryoneMask"]); + prim.BaseMask = Convert.ToUInt32(row["BaseMask"]); + // vectors + prim.OffsetPosition = new LLVector3( + Convert.ToSingle(row["PositionX"]), + Convert.ToSingle(row["PositionY"]), + Convert.ToSingle(row["PositionZ"]) + ); + prim.GroupPosition = new LLVector3( + Convert.ToSingle(row["GroupPositionX"]), + Convert.ToSingle(row["GroupPositionY"]), + Convert.ToSingle(row["GroupPositionZ"]) + ); + prim.Velocity = new LLVector3( + Convert.ToSingle(row["VelocityX"]), + Convert.ToSingle(row["VelocityY"]), + Convert.ToSingle(row["VelocityZ"]) + ); + prim.AngularVelocity = new LLVector3( + Convert.ToSingle(row["AngularVelocityX"]), + Convert.ToSingle(row["AngularVelocityY"]), + Convert.ToSingle(row["AngularVelocityZ"]) + ); + prim.Acceleration = new LLVector3( + Convert.ToSingle(row["AccelerationX"]), + Convert.ToSingle(row["AccelerationY"]), + Convert.ToSingle(row["AccelerationZ"]) + ); + // quaternions + prim.RotationOffset = new LLQuaternion( + Convert.ToSingle(row["RotationX"]), + Convert.ToSingle(row["RotationY"]), + Convert.ToSingle(row["RotationZ"]), + Convert.ToSingle(row["RotationW"]) + ); + + try + { + prim.SetSitTargetLL(new LLVector3( + Convert.ToSingle(row["SitTargetOffsetX"]), + Convert.ToSingle(row["SitTargetOffsetY"]), + Convert.ToSingle(row["SitTargetOffsetZ"])), new LLQuaternion( + Convert.ToSingle( + row["SitTargetOrientX"]), + Convert.ToSingle( + row["SitTargetOrientY"]), + Convert.ToSingle( + row["SitTargetOrientZ"]), + Convert.ToSingle( + row["SitTargetOrientW"]))); + } + catch (InvalidCastException) + { + // Database table was created before we got here and now has null values :P + m_conn.Open(); + SqliteCommand cmd = + new SqliteCommand("ALTER TABLE prims ADD COLUMN SitTargetOffsetX float NOT NULL default 0;", m_conn); + cmd.ExecuteNonQuery(); + cmd = + new SqliteCommand("ALTER TABLE prims ADD COLUMN SitTargetOffsetY float NOT NULL default 0;", m_conn); + cmd.ExecuteNonQuery(); + cmd = + new SqliteCommand("ALTER TABLE prims ADD COLUMN SitTargetOffsetZ float NOT NULL default 0;", m_conn); + cmd.ExecuteNonQuery(); + cmd = + new SqliteCommand("ALTER TABLE prims ADD COLUMN SitTargetOrientW float NOT NULL default 0;", m_conn); + cmd.ExecuteNonQuery(); + cmd = + new SqliteCommand("ALTER TABLE prims ADD COLUMN SitTargetOrientX float NOT NULL default 0;", m_conn); + cmd.ExecuteNonQuery(); + cmd = + new SqliteCommand("ALTER TABLE prims ADD COLUMN SitTargetOrientY float NOT NULL default 0;", m_conn); + cmd.ExecuteNonQuery(); + cmd = + new SqliteCommand("ALTER TABLE prims ADD COLUMN SitTargetOrientZ float NOT NULL default 0;", m_conn); + cmd.ExecuteNonQuery(); + } + + return prim; + } + + /// + /// Build a prim inventory item from the persisted data. + /// + /// + /// + private TaskInventoryItem buildItem(DataRow row) + { + TaskInventoryItem taskItem = new TaskInventoryItem(); + + taskItem.item_id = new LLUUID((String)row["itemID"]); + taskItem.ParentPartID = new LLUUID((String)row["primID"]); + taskItem.asset_id = new LLUUID((String)row["assetID"]); + taskItem.parent_id = new LLUUID((String)row["parentFolderID"]); + + taskItem.inv_type = (String)row["invType"]; + taskItem.type = (String)row["assetType"]; + + taskItem.name = (String)row["name"]; + taskItem.desc = (String)row["description"]; + taskItem.creation_date = Convert.ToUInt32(row["creationDate"]); + taskItem.creator_id = new LLUUID((String)row["creatorID"]); + taskItem.owner_id = new LLUUID((String)row["ownerID"]); + taskItem.last_owner_id = new LLUUID((String)row["lastOwnerID"]); + taskItem.group_id = new LLUUID((String)row["groupID"]); + + taskItem.next_owner_mask = Convert.ToUInt32(row["nextPermissions"]); + taskItem.owner_mask = Convert.ToUInt32(row["currentPermissions"]); + taskItem.base_mask = Convert.ToUInt32(row["basePermissions"]); + taskItem.everyone_mask = Convert.ToUInt32(row["everyonePermissions"]); + taskItem.group_mask = Convert.ToUInt32(row["groupPermissions"]); + + return taskItem; + } + + private LandData buildLandData(DataRow row) + { + LandData newData = new LandData(); + + newData.globalID = new LLUUID((String) row["UUID"]); + newData.localID = Convert.ToInt32(row["LocalLandID"]); + + // Bitmap is a byte[512] + newData.landBitmapByteArray = (Byte[]) row["Bitmap"]; + + newData.landName = (String) row["Name"]; + newData.landDesc = (String) row["Desc"]; + newData.ownerID = (String) row["OwnerUUID"]; + newData.isGroupOwned = (Boolean) row["IsGroupOwned"]; + newData.area = Convert.ToInt32(row["Area"]); + newData.auctionID = Convert.ToUInt32(row["AuctionID"]); //Unemplemented + newData.category = (Parcel.ParcelCategory) Convert.ToInt32(row["Category"]); + //Enum libsecondlife.Parcel.ParcelCategory + newData.claimDate = Convert.ToInt32(row["ClaimDate"]); + newData.claimPrice = Convert.ToInt32(row["ClaimPrice"]); + newData.groupID = new LLUUID((String) row["GroupUUID"]); + newData.salePrice = Convert.ToInt32(row["SalePrice"]); + newData.landStatus = (Parcel.ParcelStatus) Convert.ToInt32(row["LandStatus"]); + //Enum. libsecondlife.Parcel.ParcelStatus + newData.landFlags = Convert.ToUInt32(row["LandFlags"]); + newData.landingType = (Byte) row["LandingType"]; + newData.mediaAutoScale = (Byte) row["MediaAutoScale"]; + newData.mediaID = new LLUUID((String) row["MediaTextureUUID"]); + newData.mediaURL = (String) row["MediaURL"]; + newData.musicURL = (String) row["MusicURL"]; + newData.passHours = Convert.ToSingle(row["PassHours"]); + newData.passPrice = Convert.ToInt32(row["PassPrice"]); + newData.snapshotID = (String) row["SnapshotUUID"]; + + newData.userLocation = + new LLVector3(Convert.ToSingle(row["UserLocationX"]), Convert.ToSingle(row["UserLocationY"]), + Convert.ToSingle(row["UserLocationZ"])); + newData.userLookAt = + new LLVector3(Convert.ToSingle(row["UserLookAtX"]), Convert.ToSingle(row["UserLookAtY"]), + Convert.ToSingle(row["UserLookAtZ"])); + newData.parcelAccessList = new List(); + + return newData; + } + + private ParcelManager.ParcelAccessEntry buildLandAccessData(DataRow row) + { + ParcelManager.ParcelAccessEntry entry = new ParcelManager.ParcelAccessEntry(); + entry.AgentID = new LLUUID((string) row["AccessUUID"]); + entry.Flags = (ParcelManager.AccessList) row["Flags"]; + entry.Time = new DateTime(); + return entry; + } + + private Array serializeTerrain(double[,] val) + { + MemoryStream str = new MemoryStream(65536*sizeof (double)); + BinaryWriter bw = new BinaryWriter(str); + + // TODO: COMPATIBILITY - Add byte-order conversions + for (int x = 0; x < 256; x++) + for (int y = 0; y < 256; y++) + bw.Write(val[x, y]); + + return str.ToArray(); + } + +// private void fillTerrainRow(DataRow row, LLUUID regionUUID, int rev, double[,] val) +// { +// row["RegionUUID"] = regionUUID; +// row["Revision"] = rev; + +// MemoryStream str = new MemoryStream(65536*sizeof (double)); +// BinaryWriter bw = new BinaryWriter(str); + +// // TODO: COMPATIBILITY - Add byte-order conversions +// for (int x = 0; x < 256; x++) +// for (int y = 0; y < 256; y++) +// bw.Write(val[x, y]); + +// row["Heightfield"] = str.ToArray(); +// } + + private void fillPrimRow(DataRow row, SceneObjectPart prim, LLUUID sceneGroupID, LLUUID regionUUID) + { + row["UUID"] = Util.ToRawUuidString(prim.UUID); + row["RegionUUID"] = Util.ToRawUuidString(regionUUID); + row["ParentID"] = prim.ParentID; + row["CreationDate"] = prim.CreationDate; + row["Name"] = prim.Name; + row["SceneGroupID"] = Util.ToRawUuidString(sceneGroupID); + // the UUID of the root part for this SceneObjectGroup + // various text fields + row["Text"] = prim.Text; + row["Description"] = prim.Description; + row["SitName"] = prim.SitName; + row["TouchName"] = prim.TouchName; + // rex objectclickaction + row["ClickAction"] = prim.ClickAction; + // permissions + row["ObjectFlags"] = prim.ObjectFlags; + row["CreatorID"] = Util.ToRawUuidString(prim.CreatorID); + row["OwnerID"] = Util.ToRawUuidString(prim.OwnerID); + row["GroupID"] = Util.ToRawUuidString(prim.GroupID); + row["LastOwnerID"] = Util.ToRawUuidString(prim.LastOwnerID); + row["OwnerMask"] = prim.OwnerMask; + row["NextOwnerMask"] = prim.NextOwnerMask; + row["GroupMask"] = prim.GroupMask; + row["EveryoneMask"] = prim.EveryoneMask; + row["BaseMask"] = prim.BaseMask; + // vectors + row["PositionX"] = prim.OffsetPosition.X; + row["PositionY"] = prim.OffsetPosition.Y; + row["PositionZ"] = prim.OffsetPosition.Z; + row["GroupPositionX"] = prim.GroupPosition.X; + row["GroupPositionY"] = prim.GroupPosition.Y; + row["GroupPositionZ"] = prim.GroupPosition.Z; + row["VelocityX"] = prim.Velocity.X; + row["VelocityY"] = prim.Velocity.Y; + row["VelocityZ"] = prim.Velocity.Z; + row["AngularVelocityX"] = prim.AngularVelocity.X; + row["AngularVelocityY"] = prim.AngularVelocity.Y; + row["AngularVelocityZ"] = prim.AngularVelocity.Z; + row["AccelerationX"] = prim.Acceleration.X; + row["AccelerationY"] = prim.Acceleration.Y; + row["AccelerationZ"] = prim.Acceleration.Z; + // quaternions + row["RotationX"] = prim.RotationOffset.X; + row["RotationY"] = prim.RotationOffset.Y; + row["RotationZ"] = prim.RotationOffset.Z; + row["RotationW"] = prim.RotationOffset.W; + + // Sit target + LLVector3 sitTargetPos = prim.GetSitTargetPositionLL(); + row["SitTargetOffsetX"] = sitTargetPos.X; + row["SitTargetOffsetY"] = sitTargetPos.Y; + row["SitTargetOffsetZ"] = sitTargetPos.Z; + + LLQuaternion sitTargetOrient = prim.GetSitTargetOrientationLL(); + row["SitTargetOrientW"] = sitTargetOrient.W; + row["SitTargetOrientX"] = sitTargetOrient.X; + row["SitTargetOrientY"] = sitTargetOrient.Y; + row["SitTargetOrientZ"] = sitTargetOrient.Z; + } + + private void fillItemRow(DataRow row, TaskInventoryItem taskItem) + { + row["itemID"] = taskItem.item_id; + row["primID"] = taskItem.ParentPartID; + row["assetID"] = taskItem.asset_id; + row["parentFolderID"] = taskItem.parent_id; + + row["invType"] = taskItem.inv_type; + row["assetType"] = taskItem.type; + + row["name"] = taskItem.name; + row["description"] = taskItem.desc; + row["creationDate"] = taskItem.creation_date; + row["creatorID"] = taskItem.creator_id; + row["ownerID"] = taskItem.owner_id; + row["lastOwnerID"] = taskItem.last_owner_id; + row["groupID"] = taskItem.group_id; + row["nextPermissions"] = taskItem.next_owner_mask; + row["currentPermissions"] = taskItem.owner_mask; + row["basePermissions"] = taskItem.base_mask; + row["everyonePermissions"] = taskItem.everyone_mask; + row["groupPermissions"] = taskItem.group_mask; + } + + private void fillLandRow(DataRow row, LandData land, LLUUID regionUUID) + { + row["UUID"] = Util.ToRawUuidString(land.globalID); + row["RegionUUID"] = Util.ToRawUuidString(regionUUID); + row["LocalLandID"] = land.localID; + + // Bitmap is a byte[512] + row["Bitmap"] = land.landBitmapByteArray; + + row["Name"] = land.landName; + row["Desc"] = land.landDesc; + row["OwnerUUID"] = Util.ToRawUuidString(land.ownerID); + row["IsGroupOwned"] = land.isGroupOwned; + row["Area"] = land.area; + row["AuctionID"] = land.auctionID; //Unemplemented + row["Category"] = land.category; //Enum libsecondlife.Parcel.ParcelCategory + row["ClaimDate"] = land.claimDate; + row["ClaimPrice"] = land.claimPrice; + row["GroupUUID"] = Util.ToRawUuidString(land.groupID); + row["SalePrice"] = land.salePrice; + row["LandStatus"] = land.landStatus; //Enum. libsecondlife.Parcel.ParcelStatus + row["LandFlags"] = land.landFlags; + row["LandingType"] = land.landingType; + row["MediaAutoScale"] = land.mediaAutoScale; + row["MediaTextureUUID"] = Util.ToRawUuidString(land.mediaID); + row["MediaURL"] = land.mediaURL; + row["MusicURL"] = land.musicURL; + row["PassHours"] = land.passHours; + row["PassPrice"] = land.passPrice; + row["SnapshotUUID"] = Util.ToRawUuidString(land.snapshotID); + row["UserLocationX"] = land.userLocation.X; + row["UserLocationY"] = land.userLocation.Y; + row["UserLocationZ"] = land.userLocation.Z; + row["UserLookAtX"] = land.userLookAt.X; + row["UserLookAtY"] = land.userLookAt.Y; + row["UserLookAtZ"] = land.userLookAt.Z; + } + + private void fillLandAccessRow(DataRow row, ParcelManager.ParcelAccessEntry entry, LLUUID parcelID) + { + row["LandUUID"] = Util.ToRawUuidString(parcelID); + row["AccessUUID"] = Util.ToRawUuidString(entry.AgentID); + row["Flags"] = entry.Flags; + } + + private PrimitiveBaseShape buildShape(DataRow row) + { + PrimitiveBaseShape s = new PrimitiveBaseShape(); + s.Scale = new LLVector3( + Convert.ToSingle(row["ScaleX"]), + Convert.ToSingle(row["ScaleY"]), + Convert.ToSingle(row["ScaleZ"]) + ); + // paths + s.PCode = Convert.ToByte(row["PCode"]); + s.PathBegin = Convert.ToUInt16(row["PathBegin"]); + s.PathEnd = Convert.ToUInt16(row["PathEnd"]); + s.PathScaleX = Convert.ToByte(row["PathScaleX"]); + s.PathScaleY = Convert.ToByte(row["PathScaleY"]); + s.PathShearX = Convert.ToByte(row["PathShearX"]); + s.PathShearY = Convert.ToByte(row["PathShearY"]); + s.PathSkew = Convert.ToSByte(row["PathSkew"]); + s.PathCurve = Convert.ToByte(row["PathCurve"]); + s.PathRadiusOffset = Convert.ToSByte(row["PathRadiusOffset"]); + s.PathRevolutions = Convert.ToByte(row["PathRevolutions"]); + s.PathTaperX = Convert.ToSByte(row["PathTaperX"]); + s.PathTaperY = Convert.ToSByte(row["PathTaperY"]); + s.PathTwist = Convert.ToSByte(row["PathTwist"]); + s.PathTwistBegin = Convert.ToSByte(row["PathTwistBegin"]); + // profile + s.ProfileBegin = Convert.ToUInt16(row["ProfileBegin"]); + s.ProfileEnd = Convert.ToUInt16(row["ProfileEnd"]); + s.ProfileCurve = Convert.ToByte(row["ProfileCurve"]); + s.ProfileHollow = Convert.ToUInt16(row["ProfileHollow"]); + // text TODO: this isn't right] = but I'm not sure the right + // way to specify this as a blob atm + + byte[] textureEntry = (byte[]) row["Texture"]; + s.TextureEntry = textureEntry; + + + s.ExtraParams = (byte[]) row["ExtraParams"]; + // System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding(); + // string texture = encoding.GetString((Byte[])row["Texture"]); + // if (!texture.StartsWith("<")) + // { + // //here so that we can still work with old format database files (ie from before I added xml serialization) + // LLObject.TextureEntry textureEntry = null; + // textureEntry = new LLObject.TextureEntry(new LLUUID(texture)); + // s.TextureEntry = textureEntry.ToBytes(); + // } + // else + // { + // TextureBlock textureEntry = TextureBlock.FromXmlString(texture); + // s.TextureEntry = textureEntry.TextureData; + // s.ExtraParams = textureEntry.ExtraParams; + // } + + return s; + } + + private void fillShapeRow(DataRow row, SceneObjectPart prim) + { + PrimitiveBaseShape s = prim.Shape; + row["UUID"] = Util.ToRawUuidString(prim.UUID); + // shape is an enum + row["Shape"] = 0; + // vectors + row["ScaleX"] = s.Scale.X; + row["ScaleY"] = s.Scale.Y; + row["ScaleZ"] = s.Scale.Z; + // paths + row["PCode"] = s.PCode; + row["PathBegin"] = s.PathBegin; + row["PathEnd"] = s.PathEnd; + row["PathScaleX"] = s.PathScaleX; + row["PathScaleY"] = s.PathScaleY; + row["PathShearX"] = s.PathShearX; + row["PathShearY"] = s.PathShearY; + row["PathSkew"] = s.PathSkew; + row["PathCurve"] = s.PathCurve; + row["PathRadiusOffset"] = s.PathRadiusOffset; + row["PathRevolutions"] = s.PathRevolutions; + row["PathTaperX"] = s.PathTaperX; + row["PathTaperY"] = s.PathTaperY; + row["PathTwist"] = s.PathTwist; + row["PathTwistBegin"] = s.PathTwistBegin; + // profile + row["ProfileBegin"] = s.ProfileBegin; + row["ProfileEnd"] = s.ProfileEnd; + row["ProfileCurve"] = s.ProfileCurve; + row["ProfileHollow"] = s.ProfileHollow; + + row["Texture"] = s.TextureEntry; + row["ExtraParams"] = s.ExtraParams; + } + + private void addPrim(SceneObjectPart prim, LLUUID sceneGroupID, LLUUID regionUUID) + { + DataTable prims = ds.Tables["prims"]; + DataTable shapes = ds.Tables["primshapes"]; + + DataRow primRow = prims.Rows.Find(Util.ToRawUuidString(prim.UUID)); + if (primRow == null) + { + primRow = prims.NewRow(); + fillPrimRow(primRow, prim, sceneGroupID, regionUUID); + prims.Rows.Add(primRow); + } + else + { + fillPrimRow(primRow, prim, sceneGroupID, regionUUID); + } + + DataRow shapeRow = shapes.Rows.Find(Util.ToRawUuidString(prim.UUID)); + if (shapeRow == null) + { + shapeRow = shapes.NewRow(); + fillShapeRow(shapeRow, prim); + shapes.Rows.Add(shapeRow); + } + else + { + fillShapeRow(shapeRow, prim); + } + + if (persistPrimInventories) + { + addPrimInventory(prim.UUID, prim.TaskInventory); + } + } + + /// + /// Persist prim inventory. Deletes, updates and inserts rows. + /// + /// + /// + /// + private void addPrimInventory(LLUUID primID, IDictionary items) + { + MainLog.Instance.Verbose("DATASTORE", "Entered addPrimInventory with prim ID {0}", primID); + + // Find all existing inventory rows for this prim + DataTable dbItems = ds.Tables["primitems"]; + + String sql = String.Format("primID = '{0}'", primID); + DataRow[] dbItemRows = dbItems.Select(sql); + + // Build structures for manipulation purposes + IDictionary dbItemsToRemove = new Dictionary(); + ICollection itemsToAdd + = new List(); + + foreach (DataRow row in dbItemRows) + { + dbItemsToRemove.Add((String)row["itemID"], row); + } + + // Eliminate rows from the deletion set which already exist for this prim's inventory + // TODO Very temporary, need to take account of simple metadata changes soon + foreach (LLUUID itemId in items.Keys) + { + String rawItemId = itemId.ToString(); + + if (dbItemsToRemove.ContainsKey(rawItemId)) + { + dbItemsToRemove.Remove(rawItemId); + } + else + { + itemsToAdd.Add(items[itemId]); + } + } + + // Delete excess rows + foreach (DataRow row in dbItemsToRemove.Values) + { + MainLog.Instance.Verbose( + "DATASTORE", + "Removing item {0}, {1} from prim ID {2}", + row["name"], row["itemID"], row["primID"]); + + row.Delete(); + } + + // Insert items not already present + foreach (TaskInventoryItem newItem in itemsToAdd) + { + MainLog.Instance.Verbose( + "DATASTORE", + "Adding item {0}, {1} to prim ID {1}", + newItem.name, newItem.item_id, newItem.ParentPartID); + + DataRow newItemRow = dbItems.NewRow(); + fillItemRow(newItemRow, newItem); + dbItems.Rows.Add(newItemRow); + } + } + + /*********************************************************************** + * + * SQL Statement Creation Functions + * + * These functions create SQL statements for update, insert, and create. + * They can probably be factored later to have a db independant + * portion and a db specific portion + * + **********************************************************************/ + + private SqliteCommand createInsertCommand(string table, DataTable dt) + { + /** + * This is subtle enough to deserve some commentary. + * Instead of doing *lots* and *lots of hardcoded strings + * for database definitions we'll use the fact that + * realistically all insert statements look like "insert + * into A(b, c) values(:b, :c) on the parameterized query + * front. If we just have a list of b, c, etc... we can + * generate these strings instead of typing them out. + */ + string[] cols = new string[dt.Columns.Count]; + for (int i = 0; i < dt.Columns.Count; i++) + { + DataColumn col = dt.Columns[i]; + cols[i] = col.ColumnName; + } + + string sql = "insert into " + table + "("; + sql += String.Join(", ", cols); + // important, the first ':' needs to be here, the rest get added in the join + sql += ") values (:"; + sql += String.Join(", :", cols); + sql += ")"; + SqliteCommand cmd = new SqliteCommand(sql); + + // this provides the binding for all our parameters, so + // much less code than it used to be + foreach (DataColumn col in dt.Columns) + { + cmd.Parameters.Add(createSqliteParameter(col.ColumnName, col.DataType)); + } + return cmd; + } + + private SqliteCommand createUpdateCommand(string table, string pk, DataTable dt) + { + string sql = "update " + table + " set "; + string subsql = ""; + foreach (DataColumn col in dt.Columns) + { + if (subsql.Length > 0) + { + // a map function would rock so much here + subsql += ", "; + } + subsql += col.ColumnName + "= :" + col.ColumnName; + } + sql += subsql; + sql += " where " + pk; + SqliteCommand cmd = new SqliteCommand(sql); + + // this provides the binding for all our parameters, so + // much less code than it used to be + + foreach (DataColumn col in dt.Columns) + { + cmd.Parameters.Add(createSqliteParameter(col.ColumnName, col.DataType)); + } + return cmd; + } + + + private string defineTable(DataTable dt) + { + string sql = "create table " + dt.TableName + "("; + string subsql = ""; + foreach (DataColumn col in dt.Columns) + { + if (subsql.Length > 0) + { + // a map function would rock so much here + subsql += ",\n"; + } + subsql += col.ColumnName + " " + sqliteType(col.DataType); + if (dt.PrimaryKey.Length > 0 && col == dt.PrimaryKey[0]) + { + subsql += " primary key"; + } + } + sql += subsql; + sql += ")"; + return sql; + } + + /*********************************************************************** + * + * Database Binding functions + * + * These will be db specific due to typing, and minor differences + * in databases. + * + **********************************************************************/ + + /// + /// This is a convenience function that collapses 5 repetitive + /// lines for defining SqliteParameters to 2 parameters: + /// column name and database type. + /// + /// It assumes certain conventions like :param as the param + /// name to replace in parametrized queries, and that source + /// version is always current version, both of which are fine + /// for us. + /// + ///a built sqlite parameter + private SqliteParameter createSqliteParameter(string name, Type type) + { + SqliteParameter param = new SqliteParameter(); + param.ParameterName = ":" + name; + param.DbType = dbtypeFromType(type); + param.SourceColumn = name; + param.SourceVersion = DataRowVersion.Current; + return param; + } + + private void setupItemsCommands(SqliteDataAdapter da, SqliteConnection conn) + { + da.InsertCommand = createInsertCommand("primitems", ds.Tables["primitems"]); + da.InsertCommand.Connection = conn; + + da.UpdateCommand = createUpdateCommand("primitems", "itemID = :itemID", ds.Tables["primitems"]); + da.UpdateCommand.Connection = conn; + + SqliteCommand delete = new SqliteCommand("delete from primitems where itemID = :itemID"); + delete.Parameters.Add(createSqliteParameter("itemID", typeof (String))); + delete.Connection = conn; + da.DeleteCommand = delete; + } + + private void setupPrimCommands(SqliteDataAdapter da, SqliteConnection conn) + { + da.InsertCommand = createInsertCommand("prims", ds.Tables["prims"]); + da.InsertCommand.Connection = conn; + + da.UpdateCommand = createUpdateCommand("prims", "UUID=:UUID", ds.Tables["prims"]); + da.UpdateCommand.Connection = conn; + + SqliteCommand delete = new SqliteCommand("delete from prims where UUID = :UUID"); + delete.Parameters.Add(createSqliteParameter("UUID", typeof (String))); + delete.Connection = conn; + da.DeleteCommand = delete; + } + + private void setupTerrainCommands(SqliteDataAdapter da, SqliteConnection conn) + { + da.InsertCommand = createInsertCommand("terrain", ds.Tables["terrain"]); + da.InsertCommand.Connection = conn; + } + + private void setupLandCommands(SqliteDataAdapter da, SqliteConnection conn) + { + da.InsertCommand = createInsertCommand("land", ds.Tables["land"]); + da.InsertCommand.Connection = conn; + + da.UpdateCommand = createUpdateCommand("land", "UUID=:UUID", ds.Tables["land"]); + da.UpdateCommand.Connection = conn; + } + + private void setupLandAccessCommands(SqliteDataAdapter da, SqliteConnection conn) + { + da.InsertCommand = createInsertCommand("landaccesslist", ds.Tables["landaccesslist"]); + da.InsertCommand.Connection = conn; + } + + private void setupShapeCommands(SqliteDataAdapter da, SqliteConnection conn) + { + da.InsertCommand = createInsertCommand("primshapes", ds.Tables["primshapes"]); + da.InsertCommand.Connection = conn; + + da.UpdateCommand = createUpdateCommand("primshapes", "UUID=:UUID", ds.Tables["primshapes"]); + da.UpdateCommand.Connection = conn; + + SqliteCommand delete = new SqliteCommand("delete from primshapes where UUID = :UUID"); + delete.Parameters.Add(createSqliteParameter("UUID", typeof (String))); + delete.Connection = conn; + da.DeleteCommand = delete; + } + + /// + /// Create the necessary database tables. + /// + /// + private void InitDB(SqliteConnection conn) + { + string createPrims = defineTable(createPrimTable()); + string createShapes = defineTable(createShapeTable()); + string createItems = defineTable(createItemsTable()); + string createTerrain = defineTable(createTerrainTable()); + string createLand = defineTable(createLandTable()); + string createLandAccessList = defineTable(createLandAccessListTable()); + + SqliteCommand pcmd = new SqliteCommand(createPrims, conn); + SqliteCommand scmd = new SqliteCommand(createShapes, conn); + SqliteCommand icmd = new SqliteCommand(createItems, conn); + SqliteCommand tcmd = new SqliteCommand(createTerrain, conn); + SqliteCommand lcmd = new SqliteCommand(createLand, conn); + SqliteCommand lalcmd = new SqliteCommand(createLandAccessList, conn); + + conn.Open(); + + try + { + pcmd.ExecuteNonQuery(); + } + catch (SqliteSyntaxException) + { + MainLog.Instance.Warn("SQLITE", "Primitives Table Already Exists"); + } + + try + { + scmd.ExecuteNonQuery(); + } + catch (SqliteSyntaxException) + { + MainLog.Instance.Warn("SQLITE", "Shapes Table Already Exists"); + } + + if (persistPrimInventories) + { + try + { + icmd.ExecuteNonQuery(); + } + catch (SqliteSyntaxException) + { + MainLog.Instance.Warn("SQLITE", "Primitives Inventory Table Already Exists"); + } + } + + try + { + tcmd.ExecuteNonQuery(); + } + catch (SqliteSyntaxException) + { + MainLog.Instance.Warn("SQLITE", "Terrain Table Already Exists"); + } + + try + { + lcmd.ExecuteNonQuery(); + } + catch (SqliteSyntaxException) + { + MainLog.Instance.Warn("SQLITE", "Land Table Already Exists"); + } + + try + { + lalcmd.ExecuteNonQuery(); + } + catch (SqliteSyntaxException) + { + MainLog.Instance.Warn("SQLITE", "LandAccessList Table Already Exists"); + } + conn.Close(); + } + + private bool TestTables(SqliteConnection conn) + { + SqliteCommand primSelectCmd = new SqliteCommand(primSelect, conn); + SqliteDataAdapter pDa = new SqliteDataAdapter(primSelectCmd); + + SqliteCommand shapeSelectCmd = new SqliteCommand(shapeSelect, conn); + SqliteDataAdapter sDa = new SqliteDataAdapter(shapeSelectCmd); + + SqliteCommand itemsSelectCmd = new SqliteCommand(itemsSelect, conn); + SqliteDataAdapter iDa = new SqliteDataAdapter(itemsSelectCmd); + + SqliteCommand terrainSelectCmd = new SqliteCommand(terrainSelect, conn); + SqliteDataAdapter tDa = new SqliteDataAdapter(terrainSelectCmd); + + SqliteCommand landSelectCmd = new SqliteCommand(landSelect, conn); + SqliteDataAdapter lDa = new SqliteDataAdapter(landSelectCmd); + + SqliteCommand landAccessListSelectCmd = new SqliteCommand(landAccessListSelect, conn); + SqliteDataAdapter lalDa = new SqliteDataAdapter(landAccessListSelectCmd); + + DataSet tmpDS = new DataSet(); + try + { + pDa.Fill(tmpDS, "prims"); + sDa.Fill(tmpDS, "primshapes"); + + if (persistPrimInventories) + iDa.Fill(tmpDS, "primitems"); + + tDa.Fill(tmpDS, "terrain"); + lDa.Fill(tmpDS, "land"); + lalDa.Fill(tmpDS, "landaccesslist"); + } + catch (SqliteSyntaxException) + { + MainLog.Instance.Verbose("DATASTORE", "SQLite Database doesn't exist... creating"); + InitDB(conn); + } + + pDa.Fill(tmpDS, "prims"); + sDa.Fill(tmpDS, "primshapes"); + + if (persistPrimInventories) + iDa.Fill(tmpDS, "primitems"); + + tDa.Fill(tmpDS, "terrain"); + lDa.Fill(tmpDS, "land"); + lalDa.Fill(tmpDS, "landaccesslist"); + + foreach (DataColumn col in createPrimTable().Columns) + { + if (!tmpDS.Tables["prims"].Columns.Contains(col.ColumnName)) + { + MainLog.Instance.Verbose("DATASTORE", "Missing required column:" + col.ColumnName); + return false; + } + } + + foreach (DataColumn col in createShapeTable().Columns) + { + if (!tmpDS.Tables["primshapes"].Columns.Contains(col.ColumnName)) + { + MainLog.Instance.Verbose("DATASTORE", "Missing required column:" + col.ColumnName); + return false; + } + } + + // TODO Not restoring prim inventories quite yet + + foreach (DataColumn col in createTerrainTable().Columns) + { + if (!tmpDS.Tables["terrain"].Columns.Contains(col.ColumnName)) + { + MainLog.Instance.Verbose("DATASTORE", "Missing require column:" + col.ColumnName); + return false; + } + } + + foreach (DataColumn col in createLandTable().Columns) + { + if (!tmpDS.Tables["land"].Columns.Contains(col.ColumnName)) + { + MainLog.Instance.Verbose("DATASTORE", "Missing require column:" + col.ColumnName); + return false; + } + } + + foreach (DataColumn col in createLandAccessListTable().Columns) + { + if (!tmpDS.Tables["landaccesslist"].Columns.Contains(col.ColumnName)) + { + MainLog.Instance.Verbose("DATASTORE", "Missing require column:" + col.ColumnName); + return false; + } + } + + return true; + } + + /*********************************************************************** + * + * Type conversion functions + * + **********************************************************************/ + + private DbType dbtypeFromType(Type type) + { + if (type == typeof (String)) + { + return DbType.String; + } + else if (type == typeof (Int32)) + { + return DbType.Int32; + } + else if (type == typeof (Double)) + { + return DbType.Double; + } + else if (type == typeof (Byte)) + { + return DbType.Byte; + } + else if (type == typeof (Double)) + { + return DbType.Double; + } + else if (type == typeof (Byte[])) + { + return DbType.Binary; + } + else + { + return DbType.String; + } + } + + // this is something we'll need to implement for each db + // slightly differently. + private string sqliteType(Type type) + { + if (type == typeof (String)) + { + return "varchar(255)"; + } + else if (type == typeof (Int32)) + { + return "integer"; + } + else if (type == typeof (Int64)) + { + return "integer"; + } + else if (type == typeof (Double)) + { + return "float"; + } + else if (type == typeof (Byte[])) + { + return "blob"; + } + else + { + return "string"; + } + } + } +} diff --git a/README_opensim.txt b/README_opensim.txt new file mode 100644 index 0000000000..5aae87432d --- /dev/null +++ b/README_opensim.txt @@ -0,0 +1,97 @@ +Welcome to OpenSim! + +Version 0.4 + +== LICENSE == + +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. + +== OVERVIEW == + +OpenSim is a BSD Licensed Open Source project to develop a functioning +virtual worlds server platform capable of supporting multiple clients +and servers in a heterogeneous grid structure. OpenSim is written in +C#, and can run under Mono or the Microsoft .NET runtimes. + +This is considered an alpha release. Some stuff works, a lot +doesn't. If it breaks, you get to keep *both* pieces. + +== Installation on Windows == + +Prereqs: + + * Load OpenSim.sln into Visual Studio .NET and build the solution. + * chdir bin + * OpenSim.exe + +See configuring OpenSim + +== Installation on Linux == + +Prereqs: + * Mono >= 1.2.3.1 + * Nant >= 0.85 + * sqlite3 + +From the distribution type: + * nant + * cd bin + * mono ./OpenSim.exe + +See configuring OpenSim + +== Configuring OpenSim == + +When OpenSim starts for the first time, you will be prompted with a +series of questions that look something like: + +[09-17 03:54:40] DEFAULT REGION CONFIG: Simulator Name [OpenSim Test]: + +At each of these you must provide you own value or just hit enter to +take the default (in this case "OpenSim Test"). + +YOUR SIM WILL NOT BE STARTED UNTIL YOU ANSWER ALL QUESTIONS + +Once you are presented with a prompt that looks like: + + Region# : + +You have successfully started OpenSim. + +== Connecting to your OpenSim == + +By default your sim will be running on http://127.0.0.1:9000. To use +your OpenSim add -loginuri http://127.0.0.1:9000 to your second life +client (running on the same machine as your OpenSim). + +== More Information on OpenSim == + +More extensive information on building, running, and configuring +OpenSim, as well as how to report bugs, and participate in the OpenSim +project can always be found at http://opensimulator.org. + +Thanks for trying OpenSim, we hope it was a pleasant experience. diff --git a/ThirdPartyLicenses/IronPython.txt b/ThirdPartyLicenses/IronPython.txt new file mode 100644 index 0000000000..fae52b0987 --- /dev/null +++ b/ThirdPartyLicenses/IronPython.txt @@ -0,0 +1,32 @@ +License: Microsoft Public License (Ms-PL) +Microsoft Public License (Ms-PL) + +This license governs use of the accompanying software. If you use the software, you accept this license. If you do not accept the license, do not use the software. + +1. Definitions + +The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under U.S. copyright law. + +A "contribution" is the original software, or any additions or changes to the software. + +A "contributor" is any person that distributes its contribution under this license. + +"Licensed patents" are a contributor's patent claims that read directly on its contribution. + +2. Grant of Rights + +(A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create. + +(B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software. + +3. Conditions and Limitations + +(A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks. + +(B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically. + +(C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software. + +(D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license. + +(E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement. \ No newline at end of file diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index 8cef459989..08ce5cdd62 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example @@ -21,7 +21,7 @@ physics = basicphysics ; storage_plugin = "OpenSim.DataStore.NullStorage.dll" ; --- To use sqlite as region storage: -storage_plugin = "OpenSim.Framework.Data.SQLite.dll" +storage_plugin = "OpenSim.DataStore.MonoSqlite.dll" storage_connection_string="URI=file:OpenSim.db,version=3"; ; --- To use MySQL storage, supply your own connectionstring (this is only an example): diff --git a/bin/ScriptEngines/Lib/BaseHTTPServer.py b/bin/ScriptEngines/Lib/BaseHTTPServer.py new file mode 100644 index 0000000000..0bb9198c15 --- /dev/null +++ b/bin/ScriptEngines/Lib/BaseHTTPServer.py @@ -0,0 +1,577 @@ +"""HTTP server base class. + +Note: the class in this module doesn't implement any HTTP request; see +SimpleHTTPServer for simple implementations of GET, HEAD and POST +(including CGI scripts). It does, however, optionally implement HTTP/1.1 +persistent connections, as of version 0.3. + +Contents: + +- BaseHTTPRequestHandler: HTTP request handler base class +- test: test function + +XXX To do: + +- log requests even later (to capture byte count) +- log user-agent header and other interesting goodies +- send error log to separate file +""" + + +# See also: +# +# HTTP Working Group T. Berners-Lee +# INTERNET-DRAFT R. T. Fielding +# H. Frystyk Nielsen +# Expires September 8, 1995 March 8, 1995 +# +# URL: http://www.ics.uci.edu/pub/ietf/http/draft-ietf-http-v10-spec-00.txt +# +# and +# +# Network Working Group R. Fielding +# Request for Comments: 2616 et al +# Obsoletes: 2068 June 1999 +# Category: Standards Track +# +# URL: http://www.faqs.org/rfcs/rfc2616.html + +# Log files +# --------- +# +# Here's a quote from the NCSA httpd docs about log file format. +# +# | The logfile format is as follows. Each line consists of: +# | +# | host rfc931 authuser [DD/Mon/YYYY:hh:mm:ss] "request" ddd bbbb +# | +# | host: Either the DNS name or the IP number of the remote client +# | rfc931: Any information returned by identd for this person, +# | - otherwise. +# | authuser: If user sent a userid for authentication, the user name, +# | - otherwise. +# | DD: Day +# | Mon: Month (calendar name) +# | YYYY: Year +# | hh: hour (24-hour format, the machine's timezone) +# | mm: minutes +# | ss: seconds +# | request: The first line of the HTTP request as sent by the client. +# | ddd: the status code returned by the server, - if not available. +# | bbbb: the total number of bytes sent, +# | *not including the HTTP/1.0 header*, - if not available +# | +# | You can determine the name of the file accessed through request. +# +# (Actually, the latter is only true if you know the server configuration +# at the time the request was made!) + +__version__ = "0.3" + +__all__ = ["HTTPServer", "BaseHTTPRequestHandler"] + +import sys +import time +import socket # For gethostbyaddr() +import mimetools +import SocketServer + +# Default error message +DEFAULT_ERROR_MESSAGE = """\ + +Error response + + +

Error response

+

Error code %(code)d. +

Message: %(message)s. +

Error code explanation: %(code)s = %(explain)s. + +""" + +def _quote_html(html): + return html.replace("&", "&").replace("<", "<").replace(">", ">") + +class HTTPServer(SocketServer.TCPServer): + + allow_reuse_address = 1 # Seems to make sense in testing environment + + def server_bind(self): + """Override server_bind to store the server name.""" + SocketServer.TCPServer.server_bind(self) + host, port = self.socket.getsockname()[:2] + self.server_name = socket.getfqdn(host) + self.server_port = port + + +class BaseHTTPRequestHandler(SocketServer.StreamRequestHandler): + + """HTTP request handler base class. + + The following explanation of HTTP serves to guide you through the + code as well as to expose any misunderstandings I may have about + HTTP (so you don't need to read the code to figure out I'm wrong + :-). + + HTTP (HyperText Transfer Protocol) is an extensible protocol on + top of a reliable stream transport (e.g. TCP/IP). The protocol + recognizes three parts to a request: + + 1. One line identifying the request type and path + 2. An optional set of RFC-822-style headers + 3. An optional data part + + The headers and data are separated by a blank line. + + The first line of the request has the form + + + + where is a (case-sensitive) keyword such as GET or POST, + is a string containing path information for the request, + and should be the string "HTTP/1.0" or "HTTP/1.1". + is encoded using the URL encoding scheme (using %xx to signify + the ASCII character with hex code xx). + + The specification specifies that lines are separated by CRLF but + for compatibility with the widest range of clients recommends + servers also handle LF. Similarly, whitespace in the request line + is treated sensibly (allowing multiple spaces between components + and allowing trailing whitespace). + + Similarly, for output, lines ought to be separated by CRLF pairs + but most clients grok LF characters just fine. + + If the first line of the request has the form + + + + (i.e. is left out) then this is assumed to be an HTTP + 0.9 request; this form has no optional headers and data part and + the reply consists of just the data. + + The reply form of the HTTP 1.x protocol again has three parts: + + 1. One line giving the response code + 2. An optional set of RFC-822-style headers + 3. The data + + Again, the headers and data are separated by a blank line. + + The response code line has the form + + + + where is the protocol version ("HTTP/1.0" or "HTTP/1.1"), + is a 3-digit response code indicating success or + failure of the request, and is an optional + human-readable string explaining what the response code means. + + This server parses the request and the headers, and then calls a + function specific to the request type (). Specifically, + a request SPAM will be handled by a method do_SPAM(). If no + such method exists the server sends an error response to the + client. If it exists, it is called with no arguments: + + do_SPAM() + + Note that the request name is case sensitive (i.e. SPAM and spam + are different requests). + + The various request details are stored in instance variables: + + - client_address is the client IP address in the form (host, + port); + + - command, path and version are the broken-down request line; + + - headers is an instance of mimetools.Message (or a derived + class) containing the header information; + + - rfile is a file object open for reading positioned at the + start of the optional input data part; + + - wfile is a file object open for writing. + + IT IS IMPORTANT TO ADHERE TO THE PROTOCOL FOR WRITING! + + The first thing to be written must be the response line. Then + follow 0 or more header lines, then a blank line, and then the + actual data (if any). The meaning of the header lines depends on + the command executed by the server; in most cases, when data is + returned, there should be at least one header line of the form + + Content-type: / + + where and should be registered MIME types, + e.g. "text/html" or "text/plain". + + """ + + # The Python system version, truncated to its first component. + sys_version = "Python/" + sys.version.split()[0] + + # The server software version. You may want to override this. + # The format is multiple whitespace-separated strings, + # where each string is of the form name[/version]. + server_version = "BaseHTTP/" + __version__ + + def parse_request(self): + """Parse a request (internal). + + The request should be stored in self.raw_requestline; the results + are in self.command, self.path, self.request_version and + self.headers. + + Return True for success, False for failure; on failure, an + error is sent back. + + """ + self.command = None # set in case of error on the first line + self.request_version = version = "HTTP/0.9" # Default + self.close_connection = 1 + requestline = self.raw_requestline + if requestline[-2:] == '\r\n': + requestline = requestline[:-2] + elif requestline[-1:] == '\n': + requestline = requestline[:-1] + self.requestline = requestline + words = requestline.split() + if len(words) == 3: + [command, path, version] = words + if version[:5] != 'HTTP/': + self.send_error(400, "Bad request version (%r)" % version) + return False + try: + base_version_number = version.split('/', 1)[1] + version_number = base_version_number.split(".") + # RFC 2145 section 3.1 says there can be only one "." and + # - major and minor numbers MUST be treated as + # separate integers; + # - HTTP/2.4 is a lower version than HTTP/2.13, which in + # turn is lower than HTTP/12.3; + # - Leading zeros MUST be ignored by recipients. + if len(version_number) != 2: + raise ValueError + version_number = int(version_number[0]), int(version_number[1]) + except (ValueError, IndexError): + self.send_error(400, "Bad request version (%r)" % version) + return False + if version_number >= (1, 1) and self.protocol_version >= "HTTP/1.1": + self.close_connection = 0 + if version_number >= (2, 0): + self.send_error(505, + "Invalid HTTP Version (%s)" % base_version_number) + return False + elif len(words) == 2: + [command, path] = words + self.close_connection = 1 + if command != 'GET': + self.send_error(400, + "Bad HTTP/0.9 request type (%r)" % command) + return False + elif not words: + return False + else: + self.send_error(400, "Bad request syntax (%r)" % requestline) + return False + self.command, self.path, self.request_version = command, path, version + + # Examine the headers and look for a Connection directive + self.headers = self.MessageClass(self.rfile, 0) + + conntype = self.headers.get('Connection', "") + if conntype.lower() == 'close': + self.close_connection = 1 + elif (conntype.lower() == 'keep-alive' and + self.protocol_version >= "HTTP/1.1"): + self.close_connection = 0 + return True + + def handle_one_request(self): + """Handle a single HTTP request. + + You normally don't need to override this method; see the class + __doc__ string for information on how to handle specific HTTP + commands such as GET and POST. + + """ + self.raw_requestline = self.rfile.readline() + if not self.raw_requestline: + self.close_connection = 1 + return + if not self.parse_request(): # An error code has been sent, just exit + return + mname = 'do_' + self.command + if not hasattr(self, mname): + self.send_error(501, "Unsupported method (%r)" % self.command) + return + method = getattr(self, mname) + method() + + def handle(self): + """Handle multiple requests if necessary.""" + self.close_connection = 1 + + self.handle_one_request() + while not self.close_connection: + self.handle_one_request() + + def send_error(self, code, message=None): + """Send and log an error reply. + + Arguments are the error code, and a detailed message. + The detailed message defaults to the short entry matching the + response code. + + This sends an error response (so it must be called before any + output has been generated), logs the error, and finally sends + a piece of HTML explaining the error to the user. + + """ + + try: + short, long = self.responses[code] + except KeyError: + short, long = '???', '???' + if message is None: + message = short + explain = long + self.log_error("code %d, message %s", code, message) + # using _quote_html to prevent Cross Site Scripting attacks (see bug #1100201) + content = (self.error_message_format % + {'code': code, 'message': _quote_html(message), 'explain': explain}) + self.send_response(code, message) + self.send_header("Content-Type", "text/html") + self.send_header('Connection', 'close') + self.end_headers() + if self.command != 'HEAD' and code >= 200 and code not in (204, 304): + self.wfile.write(content) + + error_message_format = DEFAULT_ERROR_MESSAGE + + def send_response(self, code, message=None): + """Send the response header and log the response code. + + Also send two standard headers with the server software + version and the current date. + + """ + self.log_request(code) + if message is None: + if code in self.responses: + message = self.responses[code][0] + else: + message = '' + if self.request_version != 'HTTP/0.9': + self.wfile.write("%s %d %s\r\n" % + (self.protocol_version, code, message)) + # print (self.protocol_version, code, message) + self.send_header('Server', self.version_string()) + self.send_header('Date', self.date_time_string()) + + def send_header(self, keyword, value): + """Send a MIME header.""" + if self.request_version != 'HTTP/0.9': + self.wfile.write("%s: %s\r\n" % (keyword, value)) + + if keyword.lower() == 'connection': + if value.lower() == 'close': + self.close_connection = 1 + elif value.lower() == 'keep-alive': + self.close_connection = 0 + + def end_headers(self): + """Send the blank line ending the MIME headers.""" + if self.request_version != 'HTTP/0.9': + self.wfile.write("\r\n") + + def log_request(self, code='-', size='-'): + """Log an accepted request. + + This is called by send_response(). + + """ + + self.log_message('"%s" %s %s', + self.requestline, str(code), str(size)) + + def log_error(self, *args): + """Log an error. + + This is called when a request cannot be fulfilled. By + default it passes the message on to log_message(). + + Arguments are the same as for log_message(). + + XXX This should go to the separate error log. + + """ + + self.log_message(*args) + + def log_message(self, format, *args): + """Log an arbitrary message. + + This is used by all other logging functions. Override + it if you have specific logging wishes. + + The first argument, FORMAT, is a format string for the + message to be logged. If the format string contains + any % escapes requiring parameters, they should be + specified as subsequent arguments (it's just like + printf!). + + The client host and current date/time are prefixed to + every message. + + """ + + sys.stderr.write("%s - - [%s] %s\n" % + (self.address_string(), + self.log_date_time_string(), + format%args)) + + def version_string(self): + """Return the server software version string.""" + return self.server_version + ' ' + self.sys_version + + def date_time_string(self): + """Return the current date and time formatted for a message header.""" + now = time.time() + year, month, day, hh, mm, ss, wd, y, z = time.gmtime(now) + s = "%s, %02d %3s %4d %02d:%02d:%02d GMT" % ( + self.weekdayname[wd], + day, self.monthname[month], year, + hh, mm, ss) + return s + + def log_date_time_string(self): + """Return the current time formatted for logging.""" + now = time.time() + year, month, day, hh, mm, ss, x, y, z = time.localtime(now) + s = "%02d/%3s/%04d %02d:%02d:%02d" % ( + day, self.monthname[month], year, hh, mm, ss) + return s + + weekdayname = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] + + monthname = [None, + 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', + 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] + + def address_string(self): + """Return the client address formatted for logging. + + This version looks up the full hostname using gethostbyaddr(), + and tries to find a name that contains at least one dot. + + """ + + host, port = self.client_address[:2] + return socket.getfqdn(host) + + # Essentially static class variables + + # The version of the HTTP protocol we support. + # Set this to HTTP/1.1 to enable automatic keepalive + protocol_version = "HTTP/1.0" + + # The Message-like class used to parse headers + MessageClass = mimetools.Message + + # Table mapping response codes to messages; entries have the + # form {code: (shortmessage, longmessage)}. + # See http://www.w3.org/hypertext/WWW/Protocols/HTTP/HTRESP.html + responses = { + 100: ('Continue', 'Request received, please continue'), + 101: ('Switching Protocols', + 'Switching to new protocol; obey Upgrade header'), + + 200: ('OK', 'Request fulfilled, document follows'), + 201: ('Created', 'Document created, URL follows'), + 202: ('Accepted', + 'Request accepted, processing continues off-line'), + 203: ('Non-Authoritative Information', 'Request fulfilled from cache'), + 204: ('No response', 'Request fulfilled, nothing follows'), + 205: ('Reset Content', 'Clear input form for further input.'), + 206: ('Partial Content', 'Partial content follows.'), + + 300: ('Multiple Choices', + 'Object has several resources -- see URI list'), + 301: ('Moved Permanently', 'Object moved permanently -- see URI list'), + 302: ('Found', 'Object moved temporarily -- see URI list'), + 303: ('See Other', 'Object moved -- see Method and URL list'), + 304: ('Not modified', + 'Document has not changed since given time'), + 305: ('Use Proxy', + 'You must use proxy specified in Location to access this ' + 'resource.'), + 307: ('Temporary Redirect', + 'Object moved temporarily -- see URI list'), + + 400: ('Bad request', + 'Bad request syntax or unsupported method'), + 401: ('Unauthorized', + 'No permission -- see authorization schemes'), + 402: ('Payment required', + 'No payment -- see charging schemes'), + 403: ('Forbidden', + 'Request forbidden -- authorization will not help'), + 404: ('Not Found', 'Nothing matches the given URI'), + 405: ('Method Not Allowed', + 'Specified method is invalid for this server.'), + 406: ('Not Acceptable', 'URI not available in preferred format.'), + 407: ('Proxy Authentication Required', 'You must authenticate with ' + 'this proxy before proceeding.'), + 408: ('Request Time-out', 'Request timed out; try again later.'), + 409: ('Conflict', 'Request conflict.'), + 410: ('Gone', + 'URI no longer exists and has been permanently removed.'), + 411: ('Length Required', 'Client must specify Content-Length.'), + 412: ('Precondition Failed', 'Precondition in headers is false.'), + 413: ('Request Entity Too Large', 'Entity is too large.'), + 414: ('Request-URI Too Long', 'URI is too long.'), + 415: ('Unsupported Media Type', 'Entity body in unsupported format.'), + 416: ('Requested Range Not Satisfiable', + 'Cannot satisfy request range.'), + 417: ('Expectation Failed', + 'Expect condition could not be satisfied.'), + + 500: ('Internal error', 'Server got itself in trouble'), + 501: ('Not Implemented', + 'Server does not support this operation'), + 502: ('Bad Gateway', 'Invalid responses from another server/proxy.'), + 503: ('Service temporarily overloaded', + 'The server cannot process the request due to a high load'), + 504: ('Gateway timeout', + 'The gateway server did not receive a timely response'), + 505: ('HTTP Version not supported', 'Cannot fulfill request.'), + } + + +def test(HandlerClass = BaseHTTPRequestHandler, + ServerClass = HTTPServer, protocol="HTTP/1.0"): + """Test the HTTP request handler class. + + This runs an HTTP server on port 8000 (or the first command line + argument). + + """ + + if sys.argv[1:]: + port = int(sys.argv[1]) + else: + port = 8000 + server_address = ('', port) + + HandlerClass.protocol_version = protocol + httpd = ServerClass(server_address, HandlerClass) + + sa = httpd.socket.getsockname() + print "Serving HTTP on", sa[0], "port", sa[1], "..." + httpd.serve_forever() + + +if __name__ == '__main__': + test() diff --git a/bin/ScriptEngines/Lib/Bastion.py b/bin/ScriptEngines/Lib/Bastion.py new file mode 100644 index 0000000000..a12e3682ec --- /dev/null +++ b/bin/ScriptEngines/Lib/Bastion.py @@ -0,0 +1,177 @@ +"""Bastionification utility. + +A bastion (for another object -- the 'original') is an object that has +the same methods as the original but does not give access to its +instance variables. Bastions have a number of uses, but the most +obvious one is to provide code executing in restricted mode with a +safe interface to an object implemented in unrestricted mode. + +The bastionification routine has an optional second argument which is +a filter function. Only those methods for which the filter method +(called with the method name as argument) returns true are accessible. +The default filter method returns true unless the method name begins +with an underscore. + +There are a number of possible implementations of bastions. We use a +'lazy' approach where the bastion's __getattr__() discipline does all +the work for a particular method the first time it is used. This is +usually fastest, especially if the user doesn't call all available +methods. The retrieved methods are stored as instance variables of +the bastion, so the overhead is only occurred on the first use of each +method. + +Detail: the bastion class has a __repr__() discipline which includes +the repr() of the original object. This is precomputed when the +bastion is created. + +""" + +__all__ = ["BastionClass", "Bastion"] + +from types import MethodType + + +class BastionClass: + + """Helper class used by the Bastion() function. + + You could subclass this and pass the subclass as the bastionclass + argument to the Bastion() function, as long as the constructor has + the same signature (a get() function and a name for the object). + + """ + + def __init__(self, get, name): + """Constructor. + + Arguments: + + get - a function that gets the attribute value (by name) + name - a human-readable name for the original object + (suggestion: use repr(object)) + + """ + self._get_ = get + self._name_ = name + + def __repr__(self): + """Return a representation string. + + This includes the name passed in to the constructor, so that + if you print the bastion during debugging, at least you have + some idea of what it is. + + """ + return "" % self._name_ + + def __getattr__(self, name): + """Get an as-yet undefined attribute value. + + This calls the get() function that was passed to the + constructor. The result is stored as an instance variable so + that the next time the same attribute is requested, + __getattr__() won't be invoked. + + If the get() function raises an exception, this is simply + passed on -- exceptions are not cached. + + """ + attribute = self._get_(name) + self.__dict__[name] = attribute + return attribute + + +def Bastion(object, filter = lambda name: name[:1] != '_', + name=None, bastionclass=BastionClass): + """Create a bastion for an object, using an optional filter. + + See the Bastion module's documentation for background. + + Arguments: + + object - the original object + filter - a predicate that decides whether a function name is OK; + by default all names are OK that don't start with '_' + name - the name of the object; default repr(object) + bastionclass - class used to create the bastion; default BastionClass + + """ + + raise RuntimeError, "This code is not secure in Python 2.2 and 2.3" + + # Note: we define *two* ad-hoc functions here, get1 and get2. + # Both are intended to be called in the same way: get(name). + # It is clear that the real work (getting the attribute + # from the object and calling the filter) is done in get1. + # Why can't we pass get1 to the bastion? Because the user + # would be able to override the filter argument! With get2, + # overriding the default argument is no security loophole: + # all it does is call it. + # Also notice that we can't place the object and filter as + # instance variables on the bastion object itself, since + # the user has full access to all instance variables! + + def get1(name, object=object, filter=filter): + """Internal function for Bastion(). See source comments.""" + if filter(name): + attribute = getattr(object, name) + if type(attribute) == MethodType: + return attribute + raise AttributeError, name + + def get2(name, get1=get1): + """Internal function for Bastion(). See source comments.""" + return get1(name) + + if name is None: + name = repr(object) + return bastionclass(get2, name) + + +def _test(): + """Test the Bastion() function.""" + class Original: + def __init__(self): + self.sum = 0 + def add(self, n): + self._add(n) + def _add(self, n): + self.sum = self.sum + n + def total(self): + return self.sum + o = Original() + b = Bastion(o) + testcode = """if 1: + b.add(81) + b.add(18) + print "b.total() =", b.total() + try: + print "b.sum =", b.sum, + except: + print "inaccessible" + else: + print "accessible" + try: + print "b._add =", b._add, + except: + print "inaccessible" + else: + print "accessible" + try: + print "b._get_.func_defaults =", map(type, b._get_.func_defaults), + except: + print "inaccessible" + else: + print "accessible" + \n""" + exec testcode + print '='*20, "Using rexec:", '='*20 + import rexec + r = rexec.RExec() + m = r.add_module('__main__') + m.b = b + r.r_exec(testcode) + + +if __name__ == '__main__': + _test() diff --git a/bin/ScriptEngines/Lib/CGIHTTPServer.py b/bin/ScriptEngines/Lib/CGIHTTPServer.py new file mode 100644 index 0000000000..39225d7aea --- /dev/null +++ b/bin/ScriptEngines/Lib/CGIHTTPServer.py @@ -0,0 +1,341 @@ +"""CGI-savvy HTTP Server. + +This module builds on SimpleHTTPServer by implementing GET and POST +requests to cgi-bin scripts. + +If the os.fork() function is not present (e.g. on Windows), +os.popen2() is used as a fallback, with slightly altered semantics; if +that function is not present either (e.g. on Macintosh), only Python +scripts are supported, and they are executed by the current process. + +In all cases, the implementation is intentionally naive -- all +requests are executed sychronously. + +SECURITY WARNING: DON'T USE THIS CODE UNLESS YOU ARE INSIDE A FIREWALL +-- it may execute arbitrary Python code or external programs. + +""" + + +__version__ = "0.4" + +__all__ = ["CGIHTTPRequestHandler"] + +import os +import sys +import urllib +import BaseHTTPServer +import SimpleHTTPServer +import select + + +class CGIHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): + + """Complete HTTP server with GET, HEAD and POST commands. + + GET and HEAD also support running CGI scripts. + + The POST command is *only* implemented for CGI scripts. + + """ + + # Determine platform specifics + have_fork = hasattr(os, 'fork') + have_popen2 = hasattr(os, 'popen2') + have_popen3 = hasattr(os, 'popen3') + + # Make rfile unbuffered -- we need to read one line and then pass + # the rest to a subprocess, so we can't use buffered input. + rbufsize = 0 + + def do_POST(self): + """Serve a POST request. + + This is only implemented for CGI scripts. + + """ + + if self.is_cgi(): + self.run_cgi() + else: + self.send_error(501, "Can only POST to CGI scripts") + + def send_head(self): + """Version of send_head that support CGI scripts""" + if self.is_cgi(): + return self.run_cgi() + else: + return SimpleHTTPServer.SimpleHTTPRequestHandler.send_head(self) + + def is_cgi(self): + """Test whether self.path corresponds to a CGI script. + + Return a tuple (dir, rest) if self.path requires running a + CGI script, None if not. Note that rest begins with a + slash if it is not empty. + + The default implementation tests whether the path + begins with one of the strings in the list + self.cgi_directories (and the next character is a '/' + or the end of the string). + + """ + + path = self.path + + for x in self.cgi_directories: + i = len(x) + if path[:i] == x and (not path[i:] or path[i] == '/'): + self.cgi_info = path[:i], path[i+1:] + return True + return False + + cgi_directories = ['/cgi-bin', '/htbin'] + + def is_executable(self, path): + """Test whether argument path is an executable file.""" + return executable(path) + + def is_python(self, path): + """Test whether argument path is a Python script.""" + head, tail = os.path.splitext(path) + return tail.lower() in (".py", ".pyw") + + def run_cgi(self): + """Execute a CGI script.""" + dir, rest = self.cgi_info + i = rest.rfind('?') + if i >= 0: + rest, query = rest[:i], rest[i+1:] + else: + query = '' + i = rest.find('/') + if i >= 0: + script, rest = rest[:i], rest[i:] + else: + script, rest = rest, '' + scriptname = dir + '/' + script + scriptfile = self.translate_path(scriptname) + if not os.path.exists(scriptfile): + self.send_error(404, "No such CGI script (%r)" % scriptname) + return + if not os.path.isfile(scriptfile): + self.send_error(403, "CGI script is not a plain file (%r)" % + scriptname) + return + ispy = self.is_python(scriptname) + if not ispy: + if not (self.have_fork or self.have_popen2 or self.have_popen3): + self.send_error(403, "CGI script is not a Python script (%r)" % + scriptname) + return + if not self.is_executable(scriptfile): + self.send_error(403, "CGI script is not executable (%r)" % + scriptname) + return + + # Reference: http://hoohoo.ncsa.uiuc.edu/cgi/env.html + # XXX Much of the following could be prepared ahead of time! + env = {} + env['SERVER_SOFTWARE'] = self.version_string() + env['SERVER_NAME'] = self.server.server_name + env['GATEWAY_INTERFACE'] = 'CGI/1.1' + env['SERVER_PROTOCOL'] = self.protocol_version + env['SERVER_PORT'] = str(self.server.server_port) + env['REQUEST_METHOD'] = self.command + uqrest = urllib.unquote(rest) + env['PATH_INFO'] = uqrest + env['PATH_TRANSLATED'] = self.translate_path(uqrest) + env['SCRIPT_NAME'] = scriptname + if query: + env['QUERY_STRING'] = query + host = self.address_string() + if host != self.client_address[0]: + env['REMOTE_HOST'] = host + env['REMOTE_ADDR'] = self.client_address[0] + authorization = self.headers.getheader("authorization") + if authorization: + authorization = authorization.split() + if len(authorization) == 2: + import base64, binascii + env['AUTH_TYPE'] = authorization[0] + if authorization[0].lower() == "basic": + try: + authorization = base64.decodestring(authorization[1]) + except binascii.Error: + pass + else: + authorization = authorization.split(':') + if len(authorization) == 2: + env['REMOTE_USER'] = authorization[0] + # XXX REMOTE_IDENT + if self.headers.typeheader is None: + env['CONTENT_TYPE'] = self.headers.type + else: + env['CONTENT_TYPE'] = self.headers.typeheader + length = self.headers.getheader('content-length') + if length: + env['CONTENT_LENGTH'] = length + accept = [] + for line in self.headers.getallmatchingheaders('accept'): + if line[:1] in "\t\n\r ": + accept.append(line.strip()) + else: + accept = accept + line[7:].split(',') + env['HTTP_ACCEPT'] = ','.join(accept) + ua = self.headers.getheader('user-agent') + if ua: + env['HTTP_USER_AGENT'] = ua + co = filter(None, self.headers.getheaders('cookie')) + if co: + env['HTTP_COOKIE'] = ', '.join(co) + # XXX Other HTTP_* headers + # Since we're setting the env in the parent, provide empty + # values to override previously set values + for k in ('QUERY_STRING', 'REMOTE_HOST', 'CONTENT_LENGTH', + 'HTTP_USER_AGENT', 'HTTP_COOKIE'): + env.setdefault(k, "") + os.environ.update(env) + + self.send_response(200, "Script output follows") + + decoded_query = query.replace('+', ' ') + + if self.have_fork: + # Unix -- fork as we should + args = [script] + if '=' not in decoded_query: + args.append(decoded_query) + nobody = nobody_uid() + self.wfile.flush() # Always flush before forking + pid = os.fork() + if pid != 0: + # Parent + pid, sts = os.waitpid(pid, 0) + # throw away additional data [see bug #427345] + while select.select([self.rfile], [], [], 0)[0]: + if not self.rfile.read(1): + break + if sts: + self.log_error("CGI script exit status %#x", sts) + return + # Child + try: + try: + os.setuid(nobody) + except os.error: + pass + os.dup2(self.rfile.fileno(), 0) + os.dup2(self.wfile.fileno(), 1) + os.execve(scriptfile, args, os.environ) + except: + self.server.handle_error(self.request, self.client_address) + os._exit(127) + + elif self.have_popen2 or self.have_popen3: + # Windows -- use popen2 or popen3 to create a subprocess + import shutil + if self.have_popen3: + popenx = os.popen3 + else: + popenx = os.popen2 + cmdline = scriptfile + if self.is_python(scriptfile): + interp = sys.executable + if interp.lower().endswith("w.exe"): + # On Windows, use python.exe, not pythonw.exe + interp = interp[:-5] + interp[-4:] + cmdline = "%s -u %s" % (interp, cmdline) + if '=' not in query and '"' not in query: + cmdline = '%s "%s"' % (cmdline, query) + self.log_message("command: %s", cmdline) + try: + nbytes = int(length) + except (TypeError, ValueError): + nbytes = 0 + files = popenx(cmdline, 'b') + fi = files[0] + fo = files[1] + if self.have_popen3: + fe = files[2] + if self.command.lower() == "post" and nbytes > 0: + data = self.rfile.read(nbytes) + fi.write(data) + # throw away additional data [see bug #427345] + while select.select([self.rfile._sock], [], [], 0)[0]: + if not self.rfile._sock.recv(1): + break + fi.close() + shutil.copyfileobj(fo, self.wfile) + if self.have_popen3: + errors = fe.read() + fe.close() + if errors: + self.log_error('%s', errors) + sts = fo.close() + if sts: + self.log_error("CGI script exit status %#x", sts) + else: + self.log_message("CGI script exited OK") + + else: + # Other O.S. -- execute script in this process + save_argv = sys.argv + save_stdin = sys.stdin + save_stdout = sys.stdout + save_stderr = sys.stderr + try: + save_cwd = os.getcwd() + try: + sys.argv = [scriptfile] + if '=' not in decoded_query: + sys.argv.append(decoded_query) + sys.stdout = self.wfile + sys.stdin = self.rfile + execfile(scriptfile, {"__name__": "__main__"}) + finally: + sys.argv = save_argv + sys.stdin = save_stdin + sys.stdout = save_stdout + sys.stderr = save_stderr + os.chdir(save_cwd) + except SystemExit, sts: + self.log_error("CGI script exit status %s", str(sts)) + else: + self.log_message("CGI script exited OK") + + +nobody = None + +def nobody_uid(): + """Internal routine to get nobody's uid""" + global nobody + if nobody: + return nobody + try: + import pwd + except ImportError: + return -1 + try: + nobody = pwd.getpwnam('nobody')[2] + except KeyError: + nobody = 1 + max(map(lambda x: x[2], pwd.getpwall())) + return nobody + + +def executable(path): + """Test for executable file.""" + try: + st = os.stat(path) + except os.error: + return False + return st.st_mode & 0111 != 0 + + +def test(HandlerClass = CGIHTTPRequestHandler, + ServerClass = BaseHTTPServer.HTTPServer): + SimpleHTTPServer.test(HandlerClass, ServerClass) + + +if __name__ == '__main__': + test() diff --git a/bin/ScriptEngines/Lib/ConfigParser.py b/bin/ScriptEngines/Lib/ConfigParser.py new file mode 100644 index 0000000000..537b4ec43a --- /dev/null +++ b/bin/ScriptEngines/Lib/ConfigParser.py @@ -0,0 +1,640 @@ +"""Configuration file parser. + +A setup file consists of sections, lead by a "[section]" header, +and followed by "name: value" entries, with continuations and such in +the style of RFC 822. + +The option values can contain format strings which refer to other values in +the same section, or values in a special [DEFAULT] section. + +For example: + + something: %(dir)s/whatever + +would resolve the "%(dir)s" to the value of dir. All reference +expansions are done late, on demand. + +Intrinsic defaults can be specified by passing them into the +ConfigParser constructor as a dictionary. + +class: + +ConfigParser -- responsible for parsing a list of + configuration files, and managing the parsed database. + + methods: + + __init__(defaults=None) + create the parser and specify a dictionary of intrinsic defaults. The + keys must be strings, the values must be appropriate for %()s string + interpolation. Note that `__name__' is always an intrinsic default; + its value is the section's name. + + sections() + return all the configuration section names, sans DEFAULT + + has_section(section) + return whether the given section exists + + has_option(section, option) + return whether the given option exists in the given section + + options(section) + return list of configuration options for the named section + + read(filenames) + read and parse the list of named configuration files, given by + name. A single filename is also allowed. Non-existing files + are ignored. Return list of successfully read files. + + readfp(fp, filename=None) + read and parse one configuration file, given as a file object. + The filename defaults to fp.name; it is only used in error + messages (if fp has no `name' attribute, the string `' is used). + + get(section, option, raw=False, vars=None) + return a string value for the named option. All % interpolations are + expanded in the return values, based on the defaults passed into the + constructor and the DEFAULT section. Additional substitutions may be + provided using the `vars' argument, which must be a dictionary whose + contents override any pre-existing defaults. + + getint(section, options) + like get(), but convert value to an integer + + getfloat(section, options) + like get(), but convert value to a float + + getboolean(section, options) + like get(), but convert value to a boolean (currently case + insensitively defined as 0, false, no, off for False, and 1, true, + yes, on for True). Returns False or True. + + items(section, raw=False, vars=None) + return a list of tuples with (name, value) for each option + in the section. + + remove_section(section) + remove the given file section and all its options + + remove_option(section, option) + remove the given option from the given section + + set(section, option, value) + set the given option + + write(fp) + write the configuration state in .ini format +""" + +import re + +__all__ = ["NoSectionError", "DuplicateSectionError", "NoOptionError", + "InterpolationError", "InterpolationDepthError", + "InterpolationSyntaxError", "ParsingError", + "MissingSectionHeaderError", + "ConfigParser", "SafeConfigParser", "RawConfigParser", + "DEFAULTSECT", "MAX_INTERPOLATION_DEPTH"] + +DEFAULTSECT = "DEFAULT" + +MAX_INTERPOLATION_DEPTH = 10 + + + +# exception classes +class Error(Exception): + """Base class for ConfigParser exceptions.""" + + def __init__(self, msg=''): + self.message = msg + Exception.__init__(self, msg) + + def __repr__(self): + return self.message + + __str__ = __repr__ + +class NoSectionError(Error): + """Raised when no section matches a requested option.""" + + def __init__(self, section): + Error.__init__(self, 'No section: %r' % (section,)) + self.section = section + +class DuplicateSectionError(Error): + """Raised when a section is multiply-created.""" + + def __init__(self, section): + Error.__init__(self, "Section %r already exists" % section) + self.section = section + +class NoOptionError(Error): + """A requested option was not found.""" + + def __init__(self, option, section): + Error.__init__(self, "No option %r in section: %r" % + (option, section)) + self.option = option + self.section = section + +class InterpolationError(Error): + """Base class for interpolation-related exceptions.""" + + def __init__(self, option, section, msg): + Error.__init__(self, msg) + self.option = option + self.section = section + +class InterpolationMissingOptionError(InterpolationError): + """A string substitution required a setting which was not available.""" + + def __init__(self, option, section, rawval, reference): + msg = ("Bad value substitution:\n" + "\tsection: [%s]\n" + "\toption : %s\n" + "\tkey : %s\n" + "\trawval : %s\n" + % (section, option, reference, rawval)) + InterpolationError.__init__(self, option, section, msg) + self.reference = reference + +class InterpolationSyntaxError(InterpolationError): + """Raised when the source text into which substitutions are made + does not conform to the required syntax.""" + +class InterpolationDepthError(InterpolationError): + """Raised when substitutions are nested too deeply.""" + + def __init__(self, option, section, rawval): + msg = ("Value interpolation too deeply recursive:\n" + "\tsection: [%s]\n" + "\toption : %s\n" + "\trawval : %s\n" + % (section, option, rawval)) + InterpolationError.__init__(self, option, section, msg) + +class ParsingError(Error): + """Raised when a configuration file does not follow legal syntax.""" + + def __init__(self, filename): + Error.__init__(self, 'File contains parsing errors: %s' % filename) + self.filename = filename + self.errors = [] + + def append(self, lineno, line): + self.errors.append((lineno, line)) + self.message += '\n\t[line %2d]: %s' % (lineno, line) + +class MissingSectionHeaderError(ParsingError): + """Raised when a key-value pair is found before any section header.""" + + def __init__(self, filename, lineno, line): + Error.__init__( + self, + 'File contains no section headers.\nfile: %s, line: %d\n%r' % + (filename, lineno, line)) + self.filename = filename + self.lineno = lineno + self.line = line + + + +class RawConfigParser: + def __init__(self, defaults=None): + self._sections = {} + self._defaults = {} + if defaults: + for key, value in defaults.items(): + self._defaults[self.optionxform(key)] = value + + def defaults(self): + return self._defaults + + def sections(self): + """Return a list of section names, excluding [DEFAULT]""" + # self._sections will never have [DEFAULT] in it + return self._sections.keys() + + def add_section(self, section): + """Create a new section in the configuration. + + Raise DuplicateSectionError if a section by the specified name + already exists. + """ + if section in self._sections: + raise DuplicateSectionError(section) + self._sections[section] = {} + + def has_section(self, section): + """Indicate whether the named section is present in the configuration. + + The DEFAULT section is not acknowledged. + """ + return section in self._sections + + def options(self, section): + """Return a list of option names for the given section name.""" + try: + opts = self._sections[section].copy() + except KeyError: + raise NoSectionError(section) + opts.update(self._defaults) + if '__name__' in opts: + del opts['__name__'] + return opts.keys() + + def read(self, filenames): + """Read and parse a filename or a list of filenames. + + Files that cannot be opened are silently ignored; this is + designed so that you can specify a list of potential + configuration file locations (e.g. current directory, user's + home directory, systemwide directory), and all existing + configuration files in the list will be read. A single + filename may also be given. + + Return list of successfully read files. + """ + if isinstance(filenames, basestring): + filenames = [filenames] + read_ok = [] + for filename in filenames: + try: + fp = open(filename) + except IOError: + continue + self._read(fp, filename) + fp.close() + read_ok.append(filename) + return read_ok + + def readfp(self, fp, filename=None): + """Like read() but the argument must be a file-like object. + + The `fp' argument must have a `readline' method. Optional + second argument is the `filename', which if not given, is + taken from fp.name. If fp has no `name' attribute, `' is + used. + + """ + if filename is None: + try: + filename = fp.name + except AttributeError: + filename = '' + self._read(fp, filename) + + def get(self, section, option): + opt = self.optionxform(option) + if section not in self._sections: + if section != DEFAULTSECT: + raise NoSectionError(section) + if opt in self._defaults: + return self._defaults[opt] + else: + raise NoOptionError(option, section) + elif opt in self._sections[section]: + return self._sections[section][opt] + elif opt in self._defaults: + return self._defaults[opt] + else: + raise NoOptionError(option, section) + + def items(self, section): + try: + d2 = self._sections[section] + except KeyError: + if section != DEFAULTSECT: + raise NoSectionError(section) + d2 = {} + d = self._defaults.copy() + d.update(d2) + if "__name__" in d: + del d["__name__"] + return d.items() + + def _get(self, section, conv, option): + return conv(self.get(section, option)) + + def getint(self, section, option): + return self._get(section, int, option) + + def getfloat(self, section, option): + return self._get(section, float, option) + + _boolean_states = {'1': True, 'yes': True, 'true': True, 'on': True, + '0': False, 'no': False, 'false': False, 'off': False} + + def getboolean(self, section, option): + v = self.get(section, option) + if v.lower() not in self._boolean_states: + raise ValueError, 'Not a boolean: %s' % v + return self._boolean_states[v.lower()] + + def optionxform(self, optionstr): + return optionstr.lower() + + def has_option(self, section, option): + """Check for the existence of a given option in a given section.""" + if not section or section == DEFAULTSECT: + option = self.optionxform(option) + return option in self._defaults + elif section not in self._sections: + return False + else: + option = self.optionxform(option) + return (option in self._sections[section] + or option in self._defaults) + + def set(self, section, option, value): + """Set an option.""" + if not section or section == DEFAULTSECT: + sectdict = self._defaults + else: + try: + sectdict = self._sections[section] + except KeyError: + raise NoSectionError(section) + sectdict[self.optionxform(option)] = value + + def write(self, fp): + """Write an .ini-format representation of the configuration state.""" + if self._defaults: + fp.write("[%s]\n" % DEFAULTSECT) + for (key, value) in self._defaults.items(): + fp.write("%s = %s\n" % (key, str(value).replace('\n', '\n\t'))) + fp.write("\n") + for section in self._sections: + fp.write("[%s]\n" % section) + for (key, value) in self._sections[section].items(): + if key != "__name__": + fp.write("%s = %s\n" % + (key, str(value).replace('\n', '\n\t'))) + fp.write("\n") + + def remove_option(self, section, option): + """Remove an option.""" + if not section or section == DEFAULTSECT: + sectdict = self._defaults + else: + try: + sectdict = self._sections[section] + except KeyError: + raise NoSectionError(section) + option = self.optionxform(option) + existed = option in sectdict + if existed: + del sectdict[option] + return existed + + def remove_section(self, section): + """Remove a file section.""" + existed = section in self._sections + if existed: + del self._sections[section] + return existed + + # + # Regular expressions for parsing section headers and options. + # + SECTCRE = re.compile( + r'\[' # [ + r'(?P

[^]]+)' # very permissive! + r'\]' # ] + ) + OPTCRE = re.compile( + r'(?P