From 88771aeed3d45e60a18aa9a810eeb37b8e5def12 Mon Sep 17 00:00:00 2001 From: Melanie Date: Tue, 9 Mar 2010 23:10:14 +0000 Subject: [PATCH 01/28] Cache UserLevel in ScenePresence on SP creation. Change IsAdministrator to use that stored value. --- .../World/Permissions/PermissionsModule.cs | 8 ++++++ .../Region/Framework/Scenes/ScenePresence.cs | 28 +++++++++++++------ 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs index 2211f3e4fa..845c4c2dba 100644 --- a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs +++ b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs @@ -490,6 +490,14 @@ namespace OpenSim.Region.CoreModules.World.Permissions if (m_allowGridGods) { + ScenePresence sp = m_scene.GetScenePresence(user); + if (sp != null) + { + if (sp.UserLevel >= 200) + return true; + return false; + } + UserAccount account = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, user); if (account != null) { diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 4256be9af9..7661f1efb8 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -146,7 +146,8 @@ namespace OpenSim.Region.Framework.Scenes private float m_sitAvatarHeight = 2.0f; - private float m_godlevel; + private int m_godLevel; + private int m_userLevel; private bool m_invulnerable = true; @@ -294,9 +295,14 @@ namespace OpenSim.Region.Framework.Scenes get { return m_invulnerable; } } - public float GodLevel + public int UserLevel { - get { return m_godlevel; } + get { return m_userLevel; } + } + + public int GodLevel + { + get { return m_godLevel; } } public ulong RegionHandle @@ -668,6 +674,10 @@ namespace OpenSim.Region.Framework.Scenes m_regionInfo = reginfo; m_localId = m_scene.AllocateLocalId(); + UserAccount account = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, m_uuid); + + m_userLevel = account.UserLevel; + IGroupsModule gm = m_scene.RequestModuleInterface(); if (gm != null) m_grouptitle = gm.GetGroupTitle(m_uuid); @@ -2967,17 +2977,17 @@ namespace OpenSim.Region.Framework.Scenes if (account != null) { if (account.UserLevel > 0) - m_godlevel = account.UserLevel; + m_godLevel = account.UserLevel; else - m_godlevel = 200; + m_godLevel = 200; } } else { - m_godlevel = 0; + m_godLevel = 0; } - ControllingClient.SendAdminResponse(token, (uint)m_godlevel); + ControllingClient.SendAdminResponse(token, (uint)m_godLevel); } #region Child Agent Updates @@ -3068,7 +3078,7 @@ namespace OpenSim.Region.Framework.Scenes cAgent.ControlFlags = (uint)m_AgentControlFlags; if (m_scene.Permissions.IsGod(new UUID(cAgent.AgentID))) - cAgent.GodLevel = (byte)m_godlevel; + cAgent.GodLevel = (byte)m_godLevel; else cAgent.GodLevel = (byte) 0; @@ -3157,7 +3167,7 @@ namespace OpenSim.Region.Framework.Scenes m_AgentControlFlags = (AgentManager.ControlFlags)cAgent.ControlFlags; if (m_scene.Permissions.IsGod(new UUID(cAgent.AgentID))) - m_godlevel = cAgent.GodLevel; + m_godLevel = cAgent.GodLevel; m_setAlwaysRun = cAgent.AlwaysRun; uint i = 0; From dbb2edf1a67442b5e41da3cd8010574114bba7c2 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 9 Mar 2010 17:09:44 -0800 Subject: [PATCH 02/28] Fixed caching of user accounts. --- .../LocalUserAccountServiceConnector.cs | 15 ++++--- .../RemoteUserAccountServiceConnector.cs | 15 ++++--- .../UserAccounts/UserAccountCache.cs | 44 +++++++++++-------- .../UserAccountServiceConnector.cs | 1 + .../UserAccountService/UserAccountService.cs | 2 + 5 files changed, 45 insertions(+), 32 deletions(-) diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/LocalUserAccountServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/LocalUserAccountServiceConnector.cs index 07fee79f48..ce0ca40870 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/LocalUserAccountServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/LocalUserAccountServiceConnector.cs @@ -142,26 +142,27 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts public UserAccount GetUserAccount(UUID scopeID, UUID userID) { - UserAccount account = m_Cache.Get(userID); - if (account != null) + bool inCache = false; + UserAccount account = m_Cache.Get(userID, out inCache); + if (inCache) return account; account = m_UserService.GetUserAccount(scopeID, userID); - if (account != null) - m_Cache.Cache(account); + m_Cache.Cache(userID, account); return account; } public UserAccount GetUserAccount(UUID scopeID, string firstName, string lastName) { - UserAccount account = m_Cache.Get(firstName + " " + lastName); - if (account != null) + bool inCache = false; + UserAccount account = m_Cache.Get(firstName + " " + lastName, out inCache); + if (inCache) return account; account = m_UserService.GetUserAccount(scopeID, firstName, lastName); if (account != null) - m_Cache.Cache(account); + m_Cache.Cache(account.PrincipalID, account); return account; } diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/RemoteUserAccountServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/RemoteUserAccountServiceConnector.cs index 1140692830..488dbd5dbe 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/RemoteUserAccountServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/RemoteUserAccountServiceConnector.cs @@ -119,26 +119,27 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts public override UserAccount GetUserAccount(UUID scopeID, UUID userID) { - UserAccount account = m_Cache.Get(userID); - if (account != null) + bool inCache = false; + UserAccount account = m_Cache.Get(userID, out inCache); + if (inCache) return account; account = base.GetUserAccount(scopeID, userID); - if (account != null) - m_Cache.Cache(account); + m_Cache.Cache(userID, account); return account; } public override UserAccount GetUserAccount(UUID scopeID, string firstName, string lastName) { - UserAccount account = m_Cache.Get(firstName + " " + lastName); - if (account != null) + bool inCache = false; + UserAccount account = m_Cache.Get(firstName + " " + lastName, out inCache); + if (inCache) return account; account = base.GetUserAccount(scopeID, firstName, lastName); if (account != null) - m_Cache.Cache(account); + m_Cache.Cache(account.PrincipalID, account); return account; } diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs index e430fc785c..a355661f6c 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs @@ -36,50 +36,58 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts { public class UserAccountCache { - //private static readonly ILog m_log = - // LogManager.GetLogger( - // MethodBase.GetCurrentMethod().DeclaringType); - - private ICnmCache m_UUIDCache; - private Dictionary m_NameCache; + private static readonly ILog m_log = + LogManager.GetLogger( + MethodBase.GetCurrentMethod().DeclaringType); + private ExpiringCache m_UUIDCache; + private ExpiringCache m_NameCache; public UserAccountCache() { // Warning: the size values are a bit fuzzy. What matters // most for this cache is the count value (128 entries). - m_UUIDCache = CnmSynchronizedCache.Synchronized(new CnmMemoryCache( - 128, 128*512, TimeSpan.FromMinutes(30.0))); - m_NameCache = new Dictionary(); // this one is unbound + m_UUIDCache = new ExpiringCache(); + m_NameCache = new ExpiringCache(); // this one is unbound } - public void Cache(UserAccount account) + public void Cache(UUID userID, UserAccount account) { - m_UUIDCache.Set(account.PrincipalID, account, 512); - m_NameCache[account.Name] = account.PrincipalID; + // Cache even null accounts + m_UUIDCache.AddOrUpdate(userID, account, DateTime.Now + TimeSpan.FromMinutes(2.0d)); + if (account != null) + m_NameCache.AddOrUpdate(account.Name, account.PrincipalID, DateTime.Now + TimeSpan.FromMinutes(2.0d)); - //m_log.DebugFormat("[USER CACHE]: cached user {0} {1}", account.FirstName, account.LastName); + m_log.DebugFormat("[USER CACHE]: cached user {0}", userID); } - public UserAccount Get(UUID userID) + public UserAccount Get(UUID userID, out bool inCache) { UserAccount account = null; + inCache = false; if (m_UUIDCache.TryGetValue(userID, out account)) { //m_log.DebugFormat("[USER CACHE]: Account {0} {1} found in cache", account.FirstName, account.LastName); + inCache = true; return account; } return null; } - public UserAccount Get(string name) + public UserAccount Get(string name, out bool inCache) { - if (!m_NameCache.ContainsKey(name)) + inCache = false; + if (!m_NameCache.Contains(name)) return null; UserAccount account = null; - if (m_UUIDCache.TryGetValue(m_NameCache[name], out account)) - return account; + UUID uuid = UUID.Zero; + if (m_NameCache.TryGetValue(name, out uuid)) + if (m_UUIDCache.TryGetValue(uuid, out account)) + { + inCache = true; + return account; + } return null; } diff --git a/OpenSim/Services/Connectors/UserAccounts/UserAccountServiceConnector.cs b/OpenSim/Services/Connectors/UserAccounts/UserAccountServiceConnector.cs index 8e7c92b9ef..2f9b520de9 100644 --- a/OpenSim/Services/Connectors/UserAccounts/UserAccountServiceConnector.cs +++ b/OpenSim/Services/Connectors/UserAccounts/UserAccountServiceConnector.cs @@ -113,6 +113,7 @@ namespace OpenSim.Services.Connectors public virtual UserAccount GetUserAccount(UUID scopeID, UUID userID) { + m_log.DebugFormat("[ACCOUNTS CONNECTOR]: GetUSerAccount {0}", userID); Dictionary sendData = new Dictionary(); //sendData["SCOPEID"] = scopeID.ToString(); sendData["VERSIONMIN"] = ProtocolVersions.ClientProtocolVersionMin.ToString(); diff --git a/OpenSim/Services/UserAccountService/UserAccountService.cs b/OpenSim/Services/UserAccountService/UserAccountService.cs index 82c34e7bfa..38caf745fe 100644 --- a/OpenSim/Services/UserAccountService/UserAccountService.cs +++ b/OpenSim/Services/UserAccountService/UserAccountService.cs @@ -200,7 +200,9 @@ namespace OpenSim.Services.UserAccountService } if (d.Length < 1) + { return null; + } return MakeUserAccount(d[0]); } From c5bb51b443267a8bab8dcd28c6674491cae2c01a Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 9 Mar 2010 17:33:31 -0800 Subject: [PATCH 03/28] Changed a cryptic debug message and a wrong comment --- OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs | 2 +- .../Services/Connectors/Hypergrid/UserAgentServiceConnector.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs index de324c072b..128515db23 100644 --- a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs @@ -481,7 +481,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends m_log.DebugFormat("[FRIENDS]: {0} offered friendship to {1}", principalID, friendID); // This user wants to be friends with the other user. - // Let's add both relations to the DB, but one of them is inactive (-1) + // Let's add the relation backwards, in case the other is not online FriendsService.StoreFriend(friendID, principalID.ToString(), 0); // Now let's ask the other user to be friends with this user diff --git a/OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs b/OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs index 83d34496af..03da834d46 100644 --- a/OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs +++ b/OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs @@ -334,7 +334,7 @@ namespace OpenSim.Services.Connectors.Hypergrid } catch (Exception e) { - m_log.Debug("[HGrid]: Exception " + e.Message); + m_log.Debug("[USER AGENT CONNECTOR]: Unable to contact remote server "); reason = "Exception: " + e.Message; return false; } From f58a0394edf3c0e4d46faf1f3053b940ba0a1c8c Mon Sep 17 00:00:00 2001 From: Jeff Ames Date: Wed, 10 Mar 2010 13:15:36 +0900 Subject: [PATCH 04/28] Formatting cleanup. Add copyright notices. --- OpenSim/Data/IGridUserData.cs | 2 +- OpenSim/Data/MSSQL/MSSQLAvatarData.cs | 2 +- .../Data/MSSQL/MSSQLGenericTableHandler.cs | 6 ++-- OpenSim/Data/MSSQL/MSSQLGridUserData.cs | 4 +-- OpenSim/Data/MSSQL/MSSQLManager.cs | 4 +-- OpenSim/Data/MSSQL/MSSQLUserAccountData.cs | 2 +- .../Data/MySQL/MySQLGenericTableHandler.cs | 2 +- OpenSim/Data/MySQL/MySQLGridUserData.cs | 2 +- OpenSim/Data/MySQL/MySQLPresenceData.cs | 2 +- OpenSim/Data/Null/NullPresenceData.cs | 16 ++++----- .../Data/SQLite/SQLiteAuthenticationData.cs | 2 +- OpenSim/Framework/MultipartForm.cs | 29 +++++++++++++++- OpenSim/Framework/SLUtil.cs | 33 +++++++++++++++++-- OpenSim/Framework/UntrustedWebRequest.cs | 33 +++++++++++++++++-- OpenSim/Framework/WebUtil.cs | 29 +++++++++++++++- .../Avatar/Attachments/AttachmentsModule.cs | 8 ++--- .../Avatar/Friends/FriendsModule.cs | 4 +-- .../InstantMessage/MessageTransferModule.cs | 2 +- .../InventoryAccess/InventoryAccessModule.cs | 2 +- .../Presence/Tests/PresenceConnectorsTests.cs | 4 +-- .../World/Land/LandManagementModule.cs | 10 +++--- .../CoreModules/World/Land/LandObject.cs | 2 +- .../Interfaces/IAttachmentsModule.cs | 6 ++-- .../Interfaces/IInventoryAccessModule.cs | 29 +++++++++++++++- .../Region/Framework/Scenes/EventManager.cs | 8 ++--- OpenSim/Region/Framework/Scenes/Scene.cs | 16 ++++----- .../Framework/Scenes/SceneObjectGroup.cs | 6 ++-- .../Framework/Scenes/SceneObjectPart.cs | 2 +- .../Shared/Api/Implementation/LSL_Api.cs | 2 +- .../Hypergrid/UserAgentServerConnector.cs | 29 +++++++++++++++- .../Inventory/XInventoryInConnector.cs | 2 +- OpenSim/Services/Base/ServiceBase.cs | 2 +- .../GridUser/GridUserServiceConnector.cs | 4 +-- .../Hypergrid/GatekeeperServiceConnector.cs | 29 +++++++++++++++- .../Hypergrid/UserAgentServiceConnector.cs | 29 +++++++++++++++- .../Inventory/XInventoryConnector.cs | 2 +- .../HypergridService/UserAgentService.cs | 29 +++++++++++++++- .../LLLoginService/LLLoginResponse.cs | 2 +- .../Services/LLLoginService/LLLoginService.cs | 29 +++++++++++++++- .../UserAccountService/GridUserService.cs | 2 +- 40 files changed, 349 insertions(+), 79 deletions(-) diff --git a/OpenSim/Data/IGridUserData.cs b/OpenSim/Data/IGridUserData.cs index abd2cef054..bd7a435391 100644 --- a/OpenSim/Data/IGridUserData.cs +++ b/OpenSim/Data/IGridUserData.cs @@ -44,7 +44,7 @@ namespace OpenSim.Data /// public interface IGridUserData { - GridUserData GetGridUserData(string userID); + GridUserData GetGridUserData(string userID); bool StoreGridUserData(GridUserData data); } } \ No newline at end of file diff --git a/OpenSim/Data/MSSQL/MSSQLAvatarData.cs b/OpenSim/Data/MSSQL/MSSQLAvatarData.cs index 4992183a3a..49a6b09f76 100644 --- a/OpenSim/Data/MSSQL/MSSQLAvatarData.cs +++ b/OpenSim/Data/MSSQL/MSSQLAvatarData.cs @@ -47,7 +47,7 @@ namespace OpenSim.Data.MSSQL public MSSQLAvatarData(string connectionString, string realm) : base(connectionString, realm, "Avatar") - { + { } public bool Delete(UUID principalID, string name) diff --git a/OpenSim/Data/MSSQL/MSSQLGenericTableHandler.cs b/OpenSim/Data/MSSQL/MSSQLGenericTableHandler.cs index 506056dd62..904366e995 100644 --- a/OpenSim/Data/MSSQL/MSSQLGenericTableHandler.cs +++ b/OpenSim/Data/MSSQL/MSSQLGenericTableHandler.cs @@ -110,7 +110,7 @@ namespace OpenSim.Data.MSSQL { List constraints = new List(); string query = string.Format(@"SELECT - COL_NAME(ic.object_id,ic.column_id) AS column_name + COL_NAME(ic.object_id,ic.column_id) AS column_name FROM sys.indexes AS i INNER JOIN sys.index_columns AS ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id @@ -157,7 +157,7 @@ namespace OpenSim.Data.MSSQL string where = String.Join(" AND ", terms.ToArray()); string query = String.Format("SELECT * FROM {0} WHERE {1}", - m_Realm, where); + m_Realm, where); cmd.Connection = conn; cmd.CommandText = query; @@ -296,7 +296,7 @@ namespace OpenSim.Data.MSSQL query.AppendFormat("[{0}] = {1} ", names[i], values[i]); if (constraints.Count > 0) { - List terms = new List(); + List terms = new List(); for (int j = 0; j < constraints.Count; j++) { terms.Add(" [" + constraints[j].Key + "] = @" + constraints[j].Key); diff --git a/OpenSim/Data/MSSQL/MSSQLGridUserData.cs b/OpenSim/Data/MSSQL/MSSQLGridUserData.cs index b4a945c08e..9993720a04 100644 --- a/OpenSim/Data/MSSQL/MSSQLGridUserData.cs +++ b/OpenSim/Data/MSSQL/MSSQLGridUserData.cs @@ -47,7 +47,7 @@ namespace OpenSim.Data.MSSQL public MSSQLGridUserData(string connectionString, string realm) : base(connectionString, realm, "UserGrid") - { + { } public GridUserData GetGridUserData(string userID) @@ -58,7 +58,7 @@ namespace OpenSim.Data.MSSQL return null; return ret[0]; - } + } public bool StoreGridUserData(GridUserData data) { diff --git a/OpenSim/Data/MSSQL/MSSQLManager.cs b/OpenSim/Data/MSSQL/MSSQLManager.cs index 4309b42366..575fd210c1 100644 --- a/OpenSim/Data/MSSQL/MSSQLManager.cs +++ b/OpenSim/Data/MSSQL/MSSQLManager.cs @@ -46,7 +46,7 @@ namespace OpenSim.Data.MSSQL /// /// Connection string for ADO.net /// - private readonly string connectionString; + private readonly string connectionString; /// /// Initialize the manager and set the connectionstring @@ -196,7 +196,7 @@ namespace OpenSim.Data.MSSQL migration.Update(); } - } + } /// /// Returns the version of this DB provider diff --git a/OpenSim/Data/MSSQL/MSSQLUserAccountData.cs b/OpenSim/Data/MSSQL/MSSQLUserAccountData.cs index 9f18e5e839..e7c8dc5a7e 100644 --- a/OpenSim/Data/MSSQL/MSSQLUserAccountData.cs +++ b/OpenSim/Data/MSSQL/MSSQLUserAccountData.cs @@ -43,7 +43,7 @@ namespace OpenSim.Data.MSSQL { } //private string m_Realm; - //private List m_ColumnNames = null; + //private List m_ColumnNames = null; //private MSSQLManager m_database; //public MSSQLUserAccountData(string connectionString, string realm) diff --git a/OpenSim/Data/MySQL/MySQLGenericTableHandler.cs b/OpenSim/Data/MySQL/MySQLGenericTableHandler.cs index 756b42d7c1..1253e0b455 100644 --- a/OpenSim/Data/MySQL/MySQLGenericTableHandler.cs +++ b/OpenSim/Data/MySQL/MySQLGenericTableHandler.cs @@ -197,7 +197,7 @@ namespace OpenSim.Data.MySQL public virtual T[] Get(string where) { using (MySqlCommand cmd = new MySqlCommand()) - { + { string query = String.Format("select * from {0} where {1}", m_Realm, where); diff --git a/OpenSim/Data/MySQL/MySQLGridUserData.cs b/OpenSim/Data/MySQL/MySQLGridUserData.cs index 15834d2ab7..df29ecdc2d 100644 --- a/OpenSim/Data/MySQL/MySQLGridUserData.cs +++ b/OpenSim/Data/MySQL/MySQLGridUserData.cs @@ -54,7 +54,7 @@ namespace OpenSim.Data.MySQL return null; return ret[0]; - } + } public bool StoreGridUserData(GridUserData data) { diff --git a/OpenSim/Data/MySQL/MySQLPresenceData.cs b/OpenSim/Data/MySQL/MySQLPresenceData.cs index 68a68af3c8..143dbe38cb 100644 --- a/OpenSim/Data/MySQL/MySQLPresenceData.cs +++ b/OpenSim/Data/MySQL/MySQLPresenceData.cs @@ -134,7 +134,7 @@ namespace OpenSim.Data.MySQL List deleteSessions = new List(); int online = 0; - while(reader.Read()) + while (reader.Read()) { if (bool.Parse(reader["Online"].ToString())) online++; diff --git a/OpenSim/Data/Null/NullPresenceData.cs b/OpenSim/Data/Null/NullPresenceData.cs index 9fc45958eb..b98b5c92b5 100644 --- a/OpenSim/Data/Null/NullPresenceData.cs +++ b/OpenSim/Data/Null/NullPresenceData.cs @@ -55,7 +55,7 @@ namespace OpenSim.Data.Null } public bool Store(PresenceData data) - { + { if (Instance != this) return Instance.Store(data); @@ -113,7 +113,7 @@ namespace OpenSim.Data.Null } public bool SetHomeLocation(string userID, UUID regionID, Vector3 position, Vector3 lookAt) - { + { if (Instance != this) return Instance.SetHomeLocation(userID, regionID, position, lookAt); @@ -130,28 +130,28 @@ namespace OpenSim.Data.Null p.Data["HomePosition"] = position.ToString(); p.Data["HomeLookAt"] = lookAt.ToString(); foundone = true; - } + } } return foundone; } public PresenceData[] Get(string field, string data) - { + { if (Instance != this) return Instance.Get(field, data); // m_log.DebugFormat( -// "[NULL PRESENCE DATA]: Getting presence data for field {0} with parameter {1}", field, data); +// "[NULL PRESENCE DATA]: Getting presence data for field {0} with parameter {1}", field, data); List presences = new List(); if (field == "UserID") { foreach (PresenceData p in m_presenceData.Values) { - if (p.UserID == data) + if (p.UserID == data) { - presences.Add(p); + presences.Add(p); // Console.WriteLine("HOME for " + p.UserID + " is " + (p.Data.ContainsKey("HomeRegionID") ? p.Data["HomeRegionID"] : "Not found")); } } @@ -194,7 +194,7 @@ namespace OpenSim.Data.Null } public void Prune(string userID) - { + { if (Instance != this) { Instance.Prune(userID); diff --git a/OpenSim/Data/SQLite/SQLiteAuthenticationData.cs b/OpenSim/Data/SQLite/SQLiteAuthenticationData.cs index 84ce77546a..2c28375485 100644 --- a/OpenSim/Data/SQLite/SQLiteAuthenticationData.cs +++ b/OpenSim/Data/SQLite/SQLiteAuthenticationData.cs @@ -120,7 +120,7 @@ namespace OpenSim.Data.SQLite } public bool Store(AuthenticationData data) - { + { if (data.Data.ContainsKey("UUID")) data.Data.Remove("UUID"); diff --git a/OpenSim/Framework/MultipartForm.cs b/OpenSim/Framework/MultipartForm.cs index 8ba6d22683..90c4007ddc 100644 --- a/OpenSim/Framework/MultipartForm.cs +++ b/OpenSim/Framework/MultipartForm.cs @@ -1,4 +1,31 @@ -using System; +/* + * 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 OpenSimulator 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.Net; using System.IO; diff --git a/OpenSim/Framework/SLUtil.cs b/OpenSim/Framework/SLUtil.cs index 2fc5bdf163..f6d6a7cf60 100644 --- a/OpenSim/Framework/SLUtil.cs +++ b/OpenSim/Framework/SLUtil.cs @@ -1,4 +1,31 @@ -using System; +/* + * 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 OpenSimulator 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.Reflection; using log4net; @@ -219,7 +246,7 @@ namespace OpenSim.Framework /// Parse a notecard in Linden format to a string of ordinary text. /// /// - /// + /// public static string ParseNotecardToString(string rawInput) { string[] output = ParseNotecardToList(rawInput).ToArray(); @@ -237,7 +264,7 @@ namespace OpenSim.Framework /// public static List ParseNotecardToList(string rawInput) { - string[] input = rawInput.Replace("\r", "").Split('\n'); + string[] input = rawInput.Replace("\r", "").Split('\n'); int idx = 0; int level = 0; List output = new List(); diff --git a/OpenSim/Framework/UntrustedWebRequest.cs b/OpenSim/Framework/UntrustedWebRequest.cs index 1af7c41558..e6411cc1e2 100644 --- a/OpenSim/Framework/UntrustedWebRequest.cs +++ b/OpenSim/Framework/UntrustedWebRequest.cs @@ -1,4 +1,31 @@ -using System; +/* + * 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 OpenSimulator 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.IO; using System.Net; @@ -118,7 +145,7 @@ namespace OpenSim.Framework /// True to allow loopback addresses to be used /// The URI to test for whether it should be allowed. /// - /// true if [is URI allowable] [the specified URI]; otherwise, false. + /// true if [is URI allowable] [the specified URI]; otherwise, false. /// private static bool IsUriAllowable(Uri uri, bool allowLoopback) { @@ -180,7 +207,7 @@ namespace OpenSim.Framework /// /// The ip address to check. /// - /// true if this is a loopback IP address; false otherwise. + /// true if this is a loopback IP address; false otherwise. /// private static bool IsIPv6Loopback(IPAddress ip) { diff --git a/OpenSim/Framework/WebUtil.cs b/OpenSim/Framework/WebUtil.cs index d9782ff9ac..16e44aff44 100644 --- a/OpenSim/Framework/WebUtil.cs +++ b/OpenSim/Framework/WebUtil.cs @@ -1,4 +1,31 @@ -using System; +/* + * 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 OpenSimulator 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.Collections.Specialized; using System.IO; diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index d458364052..3b7fe8872b 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs @@ -36,7 +36,7 @@ using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; namespace OpenSim.Region.CoreModules.Avatar.Attachments -{ +{ public class AttachmentsModule : IAttachmentsModule, IRegionModule { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); @@ -204,7 +204,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments if (m_scene.AvatarFactory != null) m_scene.AvatarFactory.UpdateDatabase(remoteClient.AgentId, presence.Appearance); } - } + } public void ShowDetachInUserInventory(UUID itemID, IClientAPI remoteClient) { @@ -222,7 +222,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments } DetachSingleAttachmentToInv(itemID, remoteClient); - } + } // What makes this method odd and unique is it tries to detach using an UUID.... Yay for standards. // To LocalId or UUID, *THAT* is the question. How now Brown UUID?? @@ -252,6 +252,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments } } } - } + } } } \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs index 128515db23..312db38ed0 100644 --- a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs @@ -394,11 +394,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends public IClientAPI LocateClientObject(UUID agentID) { Scene scene = GetClientScene(agentID); - if(scene == null) + if (scene == null) return null; ScenePresence presence = scene.GetScenePresence(agentID); - if(presence == null) + if (presence == null) return null; return presence.ControllingClient; diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs index c0d3f31076..ad050a1410 100644 --- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs @@ -108,7 +108,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage if (!m_Enabled) return; - lock(m_Scenes) + lock (m_Scenes) { m_Scenes.Remove(scene); } diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs index 0fc467bc43..16e05b7e1c 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs @@ -576,7 +576,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess foreach (SceneObjectPart part in partList) { if (part.OwnerID != item.Owner) - { + { part.LastOwnerID = part.OwnerID; part.OwnerID = item.Owner; part.Inventory.ChangeInventoryOwner(item.Owner); diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/Tests/PresenceConnectorsTests.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/Tests/PresenceConnectorsTests.cs index 292ff8ea87..63a28fc255 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/Tests/PresenceConnectorsTests.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/Tests/PresenceConnectorsTests.cs @@ -61,7 +61,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence.Tests m_LocalConnector = new LocalPresenceServicesConnector(config); // Let's stick in a test presence - m_LocalConnector.m_PresenceService.LoginAgent(UUID.Zero.ToString(), UUID.Zero, UUID.Zero); + m_LocalConnector.m_PresenceService.LoginAgent(UUID.Zero.ToString(), UUID.Zero, UUID.Zero); } /// @@ -80,7 +80,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence.Tests p.Data = new Dictionary(); p.Data["Online"] = true.ToString(); m_presenceData.Add(UUID.Zero, p); - */ + */ string user1 = UUID.Zero.ToString(); UUID session1 = UUID.Zero; diff --git a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs index 38f371a587..1279ac1ad5 100644 --- a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs @@ -175,7 +175,7 @@ namespace OpenSim.Region.CoreModules.World.Land void ClientOnPreAgentUpdate(IClientAPI remoteClient, AgentUpdateArgs agentData) { //If we are forcing a position for them to go - if( forcedPosition != null ) + if (forcedPosition != null) { ScenePresence clientAvatar = m_scene.GetScenePresence(remoteClient.AgentId); @@ -191,7 +191,7 @@ namespace OpenSim.Region.CoreModules.World.Land forcedPosition = null; } //if we are far away, teleport - else if(Vector3.Distance(clientAvatar.AbsolutePosition,forcedPosition.Value) > 3 ) + else if (Vector3.Distance(clientAvatar.AbsolutePosition,forcedPosition.Value) > 3) { Debug.WriteLine(string.Format("Teleporting out because {0} is too far from avatar position {1}",forcedPosition.Value,clientAvatar.AbsolutePosition)); clientAvatar.Teleport(forcedPosition.Value); @@ -332,7 +332,7 @@ namespace OpenSim.Region.CoreModules.World.Land public void SendYouAreRestrictedNotice(ScenePresence avatar) { - avatar.ControllingClient.SendAlertMessage( + avatar.ControllingClient.SendAlertMessage( "You are not allowed on this parcel because the land owner has restricted access."); } @@ -467,7 +467,7 @@ namespace OpenSim.Region.CoreModules.World.Land ForceAvatarToPosition(clientAvatar, m_scene.GetNearestAllowedPosition(clientAvatar)); } } - else if ( parcel.IsRestrictedFromLand(clientAvatar.UUID)) + else if (parcel.IsRestrictedFromLand(clientAvatar.UUID)) { //once we've sent the message once, keep going toward the target until we are done if (forcedPosition == null) @@ -479,7 +479,7 @@ namespace OpenSim.Region.CoreModules.World.Land else { //when we are finally in a safe place, lets release the forced position lock - forcedPosition = null; + forcedPosition = null; } } } diff --git a/OpenSim/Region/CoreModules/World/Land/LandObject.cs b/OpenSim/Region/CoreModules/World/Land/LandObject.cs index 27d9fdb5aa..e85136ae17 100644 --- a/OpenSim/Region/CoreModules/World/Land/LandObject.cs +++ b/OpenSim/Region/CoreModules/World/Land/LandObject.cs @@ -287,7 +287,7 @@ namespace OpenSim.Region.CoreModules.World.Land entry.Flags = AccessList.Ban; entry.Time = new DateTime(); //See if they are on the list, but make sure the owner isn't banned - if (LandData.ParcelAccessList.Contains(entry) && LandData.OwnerID != avatar ) + if (LandData.ParcelAccessList.Contains(entry) && LandData.OwnerID != avatar) { //They are banned, so lets send them a notice about this parcel return true; diff --git a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs index 367ff3da5f..6cf2a2e3a0 100644 --- a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs @@ -31,7 +31,7 @@ using OpenSim.Framework; using OpenSim.Region.Framework.Scenes; namespace OpenSim.Region.Framework.Interfaces -{ +{ public interface IAttachmentsModule { /// @@ -43,7 +43,7 @@ namespace OpenSim.Region.Framework.Interfaces /// /// /// - /// true if the object was successfully attached, false otherwise + /// true if the object was successfully attached, false otherwise bool AttachObject( IClientAPI controllingClient, uint localID, uint attachPoint, Quaternion rot, Vector3 pos, bool silent); @@ -54,7 +54,7 @@ namespace OpenSim.Region.Framework.Interfaces /// /// /// - /// + /// UUID SetAttachmentInventoryStatus( SceneObjectGroup att, IClientAPI remoteClient, UUID itemID, uint AttachmentPt); diff --git a/OpenSim/Region/Framework/Interfaces/IInventoryAccessModule.cs b/OpenSim/Region/Framework/Interfaces/IInventoryAccessModule.cs index 240140280b..81852583c6 100644 --- a/OpenSim/Region/Framework/Interfaces/IInventoryAccessModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IInventoryAccessModule.cs @@ -1,4 +1,31 @@ -using System; +/* + * 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 OpenSimulator 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 OpenSim.Framework; diff --git a/OpenSim/Region/Framework/Scenes/EventManager.cs b/OpenSim/Region/Framework/Scenes/EventManager.cs index f0d346fbc0..dc9ae19f85 100644 --- a/OpenSim/Region/Framework/Scenes/EventManager.cs +++ b/OpenSim/Region/Framework/Scenes/EventManager.cs @@ -113,15 +113,15 @@ namespace OpenSim.Region.Framework.Scenes /// Fired when an object is touched/grabbed. /// /// The originalID is the local ID of the part that was actually touched. The localID itself is always that of - /// the root part. + /// the root part. public event ObjectGrabDelegate OnObjectGrab; - public delegate void ObjectGrabDelegate(uint localID, uint originalID, Vector3 offsetPos, IClientAPI remoteClient, SurfaceTouchEventArgs surfaceArgs); + public delegate void ObjectGrabDelegate(uint localID, uint originalID, Vector3 offsetPos, IClientAPI remoteClient, SurfaceTouchEventArgs surfaceArgs); public event ObjectGrabDelegate OnObjectGrabbing; public event ObjectDeGrabDelegate OnObjectDeGrab; public event ScriptResetDelegate OnScriptReset; - public event OnPermissionErrorDelegate OnPermissionError; + public event OnPermissionErrorDelegate OnPermissionError; /// /// Fired when a new script is created. @@ -169,7 +169,7 @@ namespace OpenSim.Region.Framework.Scenes public delegate void ClientClosed(UUID clientID, Scene scene); - public event ClientClosed OnClientClosed; + public event ClientClosed OnClientClosed; /// /// This is fired when a scene object property that a script might be interested in (such as color, scale or diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 311821ab2a..87a753e5eb 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -1976,7 +1976,7 @@ namespace OpenSim.Region.Framework.Scenes public bool AddNewSceneObject(SceneObjectGroup sceneObject, bool attachToBackup, bool sendClientUpdates) { return m_sceneGraph.AddNewSceneObject(sceneObject, attachToBackup, sendClientUpdates); - } + } /// /// Delete every object from the scene @@ -2644,7 +2644,7 @@ namespace OpenSim.Region.Framework.Scenes public virtual void SubscribeToClientAttachmentEvents(IClientAPI client) { client.OnRezSingleAttachmentFromInv += RezSingleAttachment; - client.OnRezMultipleAttachmentsFromInv += RezMultipleAttachments; + client.OnRezMultipleAttachmentsFromInv += RezMultipleAttachments; client.OnObjectAttach += m_sceneGraph.AttachObject; client.OnObjectDetach += m_sceneGraph.DetachObject; @@ -2696,7 +2696,7 @@ namespace OpenSim.Region.Framework.Scenes } protected virtual void UnsubscribeToClientEvents(IClientAPI client) - { + { } /// @@ -2797,13 +2797,13 @@ namespace OpenSim.Region.Framework.Scenes } public virtual void UnSubscribeToClientAttachmentEvents(IClientAPI client) - { + { client.OnRezMultipleAttachmentsFromInv -= RezMultipleAttachments; - client.OnRezSingleAttachmentFromInv -= RezSingleAttachment; + client.OnRezSingleAttachmentFromInv -= RezSingleAttachment; client.OnObjectAttach -= m_sceneGraph.AttachObject; client.OnObjectDetach -= m_sceneGraph.DetachObject; - if (AttachmentsModule != null) + if (AttachmentsModule != null) client.OnDetachAttachmentIntoInv -= AttachmentsModule.ShowDetachInUserInventory; } @@ -3526,7 +3526,7 @@ namespace OpenSim.Region.Framework.Scenes { foreach (var parcel in AllParcels()) { - if( parcel.ContainsPoint((int)x,(int)y)) + if (parcel.ContainsPoint((int)x,(int)y)) { return parcel; } @@ -4965,7 +4965,7 @@ namespace OpenSim.Region.Framework.Scenes private Vector3 GetPositionAtAvatarHeightOrGroundHeight(ScenePresence avatar, float x, float y) { Vector3 ground = GetPositionAtGround(x, y); - if( avatar.AbsolutePosition.Z > ground.Z) + if (avatar.AbsolutePosition.Z > ground.Z) { ground.Z = avatar.AbsolutePosition.Z; } diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 37b4fd6348..88deedf174 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -569,7 +569,7 @@ namespace OpenSim.Region.Framework.Scenes ApplyPhysics(m_scene.m_physicalPrim); // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled - // for the same object with very different properties. The caller must schedule the update. + // for the same object with very different properties. The caller must schedule the update. //ScheduleGroupForFullUpdate(); } @@ -2032,11 +2032,11 @@ namespace OpenSim.Region.Framework.Scenes /// Immediately send a full update for this scene object. /// public void SendGroupFullUpdate() - { + { if (IsDeleted) return; -// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); +// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); RootPart.SendFullUpdateToAllClients(); diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 472938209e..89672526dd 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -2869,7 +2869,7 @@ namespace OpenSim.Region.Framework.Scenes { SendFullUpdateToClient(remoteClient, clientFlags); } - } + } /// /// Send a full update for this part to all clients. diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 59db81eeae..b040ca7748 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -4024,7 +4024,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return; } - if( message == string.Empty) + if (message == string.Empty) { ShoutError("Trying to use llTextBox with empty message."); } diff --git a/OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs b/OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs index 79c6b2a866..6b1152b00e 100644 --- a/OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs +++ b/OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs @@ -1,4 +1,31 @@ -using System; +/* + * 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 OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; using System.Collections; using System.Collections.Generic; using System.Net; diff --git a/OpenSim/Server/Handlers/Inventory/XInventoryInConnector.cs b/OpenSim/Server/Handlers/Inventory/XInventoryInConnector.cs index f9db859aa7..34f7dccc4e 100644 --- a/OpenSim/Server/Handlers/Inventory/XInventoryInConnector.cs +++ b/OpenSim/Server/Handlers/Inventory/XInventoryInConnector.cs @@ -289,7 +289,7 @@ namespace OpenSim.Server.Handlers.Asset foreach (InventoryItemBase i in icoll.Items) items[i.ID.ToString()] = EncodeItem(i); result["ITEMS"] = items; - } + } string xmlString = ServerUtils.BuildXmlResponse(result); m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); diff --git a/OpenSim/Services/Base/ServiceBase.cs b/OpenSim/Services/Base/ServiceBase.cs index 91d5c5650c..ef30cba6cf 100644 --- a/OpenSim/Services/Base/ServiceBase.cs +++ b/OpenSim/Services/Base/ServiceBase.cs @@ -72,7 +72,7 @@ namespace OpenSim.Services.Base // m_log.DebugFormat("[SERVICE BASE]: Found type {0}", pluginType); if (pluginType.IsPublic) - { + { if (className != String.Empty && pluginType.ToString() != pluginType.Namespace + "." + className) diff --git a/OpenSim/Services/Connectors/GridUser/GridUserServiceConnector.cs b/OpenSim/Services/Connectors/GridUser/GridUserServiceConnector.cs index ce88236ae3..0e8506706c 100644 --- a/OpenSim/Services/Connectors/GridUser/GridUserServiceConnector.cs +++ b/OpenSim/Services/Connectors/GridUser/GridUserServiceConnector.cs @@ -28,9 +28,9 @@ using System; namespace OpenSim.Services.Connectors -{ +{ public class GridUserServiceConnector - { + { public GridUserServiceConnector() { } diff --git a/OpenSim/Services/Connectors/Hypergrid/GatekeeperServiceConnector.cs b/OpenSim/Services/Connectors/Hypergrid/GatekeeperServiceConnector.cs index 9f73b388e8..c426bba807 100644 --- a/OpenSim/Services/Connectors/Hypergrid/GatekeeperServiceConnector.cs +++ b/OpenSim/Services/Connectors/Hypergrid/GatekeeperServiceConnector.cs @@ -1,4 +1,31 @@ -using System; +/* + * 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 OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; using System.Collections; using System.Collections.Generic; using System.Drawing; diff --git a/OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs b/OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs index 03da834d46..3e91e3a113 100644 --- a/OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs +++ b/OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs @@ -1,4 +1,31 @@ -using System; +/* + * 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 OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; using System.Collections; using System.Collections.Generic; using System.IO; diff --git a/OpenSim/Services/Connectors/Inventory/XInventoryConnector.cs b/OpenSim/Services/Connectors/Inventory/XInventoryConnector.cs index 9821dd40e2..0cc1978a0b 100644 --- a/OpenSim/Services/Connectors/Inventory/XInventoryConnector.cs +++ b/OpenSim/Services/Connectors/Inventory/XInventoryConnector.cs @@ -126,7 +126,7 @@ namespace OpenSim.Services.Connectors }); if (ret == null) - return null; + return null; if (ret.Count == 0) return null; diff --git a/OpenSim/Services/HypergridService/UserAgentService.cs b/OpenSim/Services/HypergridService/UserAgentService.cs index 15379b5b3e..26f211b5d9 100644 --- a/OpenSim/Services/HypergridService/UserAgentService.cs +++ b/OpenSim/Services/HypergridService/UserAgentService.cs @@ -1,4 +1,31 @@ -using System; +/* + * 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 OpenSimulator 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.Net; using System.Reflection; diff --git a/OpenSim/Services/LLLoginService/LLLoginResponse.cs b/OpenSim/Services/LLLoginService/LLLoginResponse.cs index 05f5b4cba3..1a59213be4 100644 --- a/OpenSim/Services/LLLoginService/LLLoginResponse.cs +++ b/OpenSim/Services/LLLoginService/LLLoginResponse.cs @@ -623,7 +623,7 @@ namespace OpenSim.Services.LLLoginService } private InventoryData GetInventorySkeleton(List folders) - { + { UUID rootID = UUID.Zero; ArrayList AgentInventoryArray = new ArrayList(); Hashtable TempHash; diff --git a/OpenSim/Services/LLLoginService/LLLoginService.cs b/OpenSim/Services/LLLoginService/LLLoginService.cs index ae729f8ca4..157887302b 100644 --- a/OpenSim/Services/LLLoginService/LLLoginService.cs +++ b/OpenSim/Services/LLLoginService/LLLoginService.cs @@ -1,4 +1,31 @@ -using System; +/* + * 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 OpenSimulator 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.Net; using System.Reflection; diff --git a/OpenSim/Services/UserAccountService/GridUserService.cs b/OpenSim/Services/UserAccountService/GridUserService.cs index 36cce758ce..c6e33bbbfe 100644 --- a/OpenSim/Services/UserAccountService/GridUserService.cs +++ b/OpenSim/Services/UserAccountService/GridUserService.cs @@ -58,7 +58,7 @@ namespace OpenSim.Services.UserAccountService info.HomePosition = Vector3.Parse(d.Data["HomePosition"]); info.HomeLookAt = Vector3.Parse(d.Data["HomeLookAt"]); - return info; + return info; } public bool StoreGridUserInfo(GridUserInfo info) From 04a6b1caf8033a413efce7db4cda4de4bf935a01 Mon Sep 17 00:00:00 2001 From: Melanie Date: Wed, 10 Mar 2010 05:31:34 +0000 Subject: [PATCH 05/28] Reintroduce a check that was dropped from permissions --- .../Region/CoreModules/World/Permissions/PermissionsModule.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs index 845c4c2dba..5c7f3b7225 100644 --- a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs +++ b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs @@ -618,7 +618,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions return objectOwnerMask; // Estate users should be able to edit anything in the sim if RegionOwnerIsGod is set - if (IsEstateManager(user) && m_RegionOwnerIsGod) + if (m_RegionOwnerIsGod && IsEstateManager(user) && !IsAdministrator(objectOwner)) return objectOwnerMask; // Admin should be able to edit anything in the sim (including admin objects) From 2af97b46ecc96a58028e53045efffd75c07ec857 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Wed, 10 Mar 2010 14:05:49 -0800 Subject: [PATCH 06/28] * Cleaned up and commented the messy SendInventoryUpdate, fixed a broken debug line, and commented the debug line out since it can quickly become noisy --- .../Framework/Scenes/Scene.Inventory.cs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index dad0efd6fa..7277527fde 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs @@ -1102,18 +1102,18 @@ namespace OpenSim.Region.Framework.Scenes if (folder == null) return; - m_log.DebugFormat("[AGENT INVENTORY]: Send Inventory Folder {0} Update to {1} {2}", folder.Name, client.FirstName, client.LastName); + // Fetch the folder contents InventoryCollection contents = InventoryService.GetFolderContent(client.AgentId, folder.ID); - InventoryFolderBase containingFolder = new InventoryFolderBase(); - containingFolder.ID = folder.ID; - containingFolder.Owner = client.AgentId; - containingFolder = InventoryService.GetFolder(containingFolder); - if (containingFolder != null) - { - int version = containingFolder.Version; - client.SendInventoryFolderDetails(client.AgentId, folder.ID, contents.Items, contents.Folders, version, fetchFolders, fetchItems); - } + // Fetch the folder itself to get its current version + InventoryFolderBase containingFolder = new InventoryFolderBase(folder.ID, client.AgentId); + containingFolder = InventoryService.GetFolder(containingFolder); + + //m_log.DebugFormat("[AGENT INVENTORY]: Sending inventory folder contents ({0} nodes) for \"{1}\" to {2} {3}", + // contents.Folders.Count + contents.Items.Count, containingFolder.Name, client.FirstName, client.LastName); + + if (containingFolder != null) + client.SendInventoryFolderDetails(client.AgentId, folder.ID, contents.Items, contents.Folders, containingFolder.Version, fetchFolders, fetchItems); } /// From 265c24ec33f53681e6b03684d9c453d0b1e91ce5 Mon Sep 17 00:00:00 2001 From: Mikko Pallari Date: Wed, 10 Mar 2010 14:44:53 +0200 Subject: [PATCH 07/28] Changed some properties and methods from private to protected in LLLoginResponse and LLLoginService so they could be inherited better. --- .../LLLoginService/LLLoginResponse.cs | 6 ++--- .../Services/LLLoginService/LLLoginService.cs | 24 +++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/OpenSim/Services/LLLoginService/LLLoginResponse.cs b/OpenSim/Services/LLLoginService/LLLoginResponse.cs index 1a59213be4..ee30fa38ef 100644 --- a/OpenSim/Services/LLLoginService/LLLoginResponse.cs +++ b/OpenSim/Services/LLLoginService/LLLoginResponse.cs @@ -47,9 +47,9 @@ namespace OpenSim.Services.LLLoginService { public class LLFailedLoginResponse : OpenSim.Services.Interfaces.FailedLoginResponse { - string m_key; - string m_value; - string m_login; + protected string m_key; + protected string m_value; + protected string m_login; public static LLFailedLoginResponse UserProblem; public static LLFailedLoginResponse AuthorizationProblem; diff --git a/OpenSim/Services/LLLoginService/LLLoginService.cs b/OpenSim/Services/LLLoginService/LLLoginService.cs index 157887302b..1eaf4d4158 100644 --- a/OpenSim/Services/LLLoginService/LLLoginService.cs +++ b/OpenSim/Services/LLLoginService/LLLoginService.cs @@ -51,24 +51,24 @@ namespace OpenSim.Services.LLLoginService private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static bool Initialized = false; - private IUserAccountService m_UserAccountService; - private IAuthenticationService m_AuthenticationService; - private IInventoryService m_InventoryService; - private IGridService m_GridService; - private IPresenceService m_PresenceService; + protected IUserAccountService m_UserAccountService; + protected IAuthenticationService m_AuthenticationService; + protected IInventoryService m_InventoryService; + protected IGridService m_GridService; + protected IPresenceService m_PresenceService; private ISimulationService m_LocalSimulationService; private ISimulationService m_RemoteSimulationService; - private ILibraryService m_LibraryService; - private IFriendsService m_FriendsService; - private IAvatarService m_AvatarService; + protected ILibraryService m_LibraryService; + protected IFriendsService m_FriendsService; + protected IAvatarService m_AvatarService; private IUserAgentService m_UserAgentService; private GatekeeperServiceConnector m_GatekeeperConnector; private string m_DefaultRegionName; - private string m_WelcomeMessage; + protected string m_WelcomeMessage; private bool m_RequireInventory; - private int m_MinLoginLevel; + protected int m_MinLoginLevel; private string m_GatekeeperURL; IConfig m_LoginServerConfig; @@ -286,7 +286,7 @@ namespace OpenSim.Services.LLLoginService } } - private GridRegion FindDestination(UserAccount account, PresenceInfo pinfo, UUID sessionID, string startLocation, out GridRegion gatekeeper, out string where, out Vector3 position, out Vector3 lookAt) + protected GridRegion FindDestination(UserAccount account, PresenceInfo pinfo, UUID sessionID, string startLocation, out GridRegion gatekeeper, out string where, out Vector3 position, out Vector3 lookAt) { m_log.DebugFormat("[LLOGIN SERVICE]: FindDestination for start location {0}", startLocation); @@ -497,7 +497,7 @@ namespace OpenSim.Services.LLLoginService } } - private AgentCircuitData LaunchAgentAtGrid(GridRegion gatekeeper, GridRegion destination, UserAccount account, AvatarData avatar, + protected AgentCircuitData LaunchAgentAtGrid(GridRegion gatekeeper, GridRegion destination, UserAccount account, AvatarData avatar, UUID session, UUID secureSession, Vector3 position, string currentWhere, out string where, out string reason) { where = currentWhere; From 20406498711d1f26037ae32e1b7f8378b01ad848 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Thu, 11 Mar 2010 10:05:03 -0800 Subject: [PATCH 08/28] Adding the SimianGrid connectors --- .../SimianGrid/SimianAssetServiceConnector.cs | 407 ++++++++ .../SimianAuthenticationServiceConnector.cs | 198 ++++ .../SimianAvatarServiceConnector.cs | 259 ++++++ .../SimianFriendsServiceConnector.cs | 229 +++++ .../Connectors/SimianGrid/SimianGrid.cs | 31 + .../SimianGrid/SimianGridServiceConnector.cs | 418 +++++++++ .../SimianInventoryServiceConnector.cs | 880 ++++++++++++++++++ .../SimianPresenceServiceConnector.cs | 502 ++++++++++ .../Connectors/SimianGrid/SimianProfiles.cs | 432 +++++++++ .../SimianUserAccountServiceConnector.cs | 307 ++++++ bin/OpenSim.ini.example | 1 + bin/config-include/SimianGrid.ini | 70 ++ prebuild.xml | 2 + 13 files changed, 3736 insertions(+) create mode 100644 OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs create mode 100644 OpenSim/Services/Connectors/SimianGrid/SimianAuthenticationServiceConnector.cs create mode 100644 OpenSim/Services/Connectors/SimianGrid/SimianAvatarServiceConnector.cs create mode 100644 OpenSim/Services/Connectors/SimianGrid/SimianFriendsServiceConnector.cs create mode 100644 OpenSim/Services/Connectors/SimianGrid/SimianGrid.cs create mode 100644 OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs create mode 100644 OpenSim/Services/Connectors/SimianGrid/SimianInventoryServiceConnector.cs create mode 100644 OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs create mode 100644 OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs create mode 100644 OpenSim/Services/Connectors/SimianGrid/SimianUserAccountServiceConnector.cs create mode 100644 bin/config-include/SimianGrid.ini diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs new file mode 100644 index 0000000000..9fb7723b1d --- /dev/null +++ b/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs @@ -0,0 +1,407 @@ +/* + * 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 OpenSimulator 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.IO; +using System.Net; +using System.Reflection; +using log4net; +using Mono.Addins; +using Nini.Config; +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Services.Interfaces; +using OpenMetaverse; +using OpenMetaverse.StructuredData; + +namespace OpenSim.Services.Connectors.SimianGrid +{ + /// + /// Connects to the SimianGrid asset service + /// + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] + public class SimianAssetServiceConnector : IAssetService, ISharedRegionModule + { + private static readonly ILog m_log = + LogManager.GetLogger( + MethodBase.GetCurrentMethod().DeclaringType); + private static string ZeroID = UUID.Zero.ToString(); + + private string m_serverUrl = String.Empty; + private IImprovedAssetCache m_cache; + + #region ISharedRegionModule + + public Type ReplaceableInterface { get { return null; } } + public void RegionLoaded(Scene scene) + { + if (m_cache == null) + { + IImprovedAssetCache cache = scene.RequestModuleInterface(); + if (cache is ISharedRegionModule) + m_cache = cache; + } + } + public void PostInitialise() { } + public void Close() { } + + public SimianAssetServiceConnector() { } + public string Name { get { return "SimianAssetServiceConnector"; } } + public void AddRegion(Scene scene) { scene.RegisterModuleInterface(this); } + public void RemoveRegion(Scene scene) { scene.UnregisterModuleInterface(this); } + + #endregion ISharedRegionModule + + public SimianAssetServiceConnector(IConfigSource source) + { + Initialise(source); + } + + public void Initialise(IConfigSource source) + { + IConfig gridConfig = source.Configs["AssetService"]; + if (gridConfig == null) + { + m_log.Error("[ASSET CONNECTOR]: AssetService missing from OpenSim.ini"); + throw new Exception("Asset connector init error"); + } + + string serviceUrl = gridConfig.GetString("AssetServerURI"); + if (String.IsNullOrEmpty(serviceUrl)) + { + m_log.Error("[ASSET CONNECTOR]: No AssetServerURI in section AssetService"); + throw new Exception("Asset connector init error"); + } + + if (!serviceUrl.EndsWith("/")) + serviceUrl = serviceUrl + '/'; + + m_serverUrl = serviceUrl; + } + + #region IAssetService + + public AssetBase Get(string id) + { + AssetBase asset = null; + + // Cache fetch + if (m_cache != null) + { + asset = m_cache.Get(id); + if (asset != null) + return asset; + } + + Uri url; + + // Determine if id is an absolute URL or a grid-relative UUID + if (!Uri.TryCreate(id, UriKind.Absolute, out url)) + url = new Uri(m_serverUrl + id); + + try + { + HttpWebRequest request = UntrustedHttpWebRequest.Create(url); + + using (WebResponse response = request.GetResponse()) + { + using (Stream responseStream = response.GetResponseStream()) + { + string creatorID = response.Headers.GetOne("X-Asset-Creator-Id") ?? String.Empty; + + // Create the asset object + asset = new AssetBase(id, String.Empty, SLUtil.ContentTypeToSLAssetType(response.ContentType), creatorID); + + UUID assetID; + if (UUID.TryParse(id, out assetID)) + asset.FullID = assetID; + + // Grab the asset data from the response stream + using (MemoryStream stream = new MemoryStream()) + { + responseStream.CopyTo(stream, Int32.MaxValue); + asset.Data = stream.ToArray(); + } + } + } + + // Cache store + if (m_cache != null && asset != null) + m_cache.Cache(asset); + + return asset; + } + catch (Exception ex) + { + m_log.Warn("[ASSET CONNECTOR]: Asset GET from " + url + " failed: " + ex.Message); + return null; + } + } + + /// + /// Get an asset's metadata + /// + /// + /// + public AssetMetadata GetMetadata(string id) + { + AssetMetadata metadata = null; + + // Cache fetch + if (m_cache != null) + { + AssetBase asset = m_cache.Get(id); + if (asset != null) + return asset.Metadata; + } + + Uri url; + + // Determine if id is an absolute URL or a grid-relative UUID + if (!Uri.TryCreate(id, UriKind.Absolute, out url)) + url = new Uri(m_serverUrl + id); + + try + { + HttpWebRequest request = UntrustedHttpWebRequest.Create(url); + request.Method = "HEAD"; + + using (WebResponse response = request.GetResponse()) + { + using (Stream responseStream = response.GetResponseStream()) + { + // Create the metadata object + metadata = new AssetMetadata(); + metadata.ContentType = response.ContentType; + metadata.ID = id; + + UUID uuid; + if (UUID.TryParse(id, out uuid)) + metadata.FullID = uuid; + + string lastModifiedStr = response.Headers.Get("Last-Modified"); + if (!String.IsNullOrEmpty(lastModifiedStr)) + { + DateTime lastModified; + if (DateTime.TryParse(lastModifiedStr, out lastModified)) + metadata.CreationDate = lastModified; + } + } + } + } + catch (Exception ex) + { + m_log.Warn("[ASSET CONNECTOR]: Asset GET from " + url + " failed: " + ex.Message); + } + + return metadata; + } + + public byte[] GetData(string id) + { + AssetBase asset = Get(id); + + if (asset != null) + return asset.Data; + + return null; + } + + /// + /// Get an asset asynchronously + /// + /// The asset id + /// Represents the requester. Passed back via the handler + /// The handler to call back once the asset has been retrieved + /// True if the id was parseable, false otherwise + public bool Get(string id, Object sender, AssetRetrieved handler) + { + Util.FireAndForget( + delegate(object o) + { + AssetBase asset = Get(id); + handler(id, sender, asset); + } + ); + + return true; + } + + /// + /// Creates a new asset + /// + /// Returns a random ID if none is passed into it + /// + /// + public string Store(AssetBase asset) + { + bool storedInCache = false; + string errorMessage = null; + + // AssetID handling + if (String.IsNullOrEmpty(asset.ID) || asset.ID == ZeroID) + { + asset.FullID = UUID.Random(); + asset.ID = asset.FullID.ToString(); + } + + // Cache handling + if (m_cache != null) + { + m_cache.Cache(asset); + storedInCache = true; + } + + // Local asset handling + if (asset.Local) + { + if (!storedInCache) + { + m_log.Error("Cannot store local " + asset.Metadata.ContentType + " asset without an asset cache"); + asset.ID = null; + asset.FullID = UUID.Zero; + } + + return asset.ID; + } + + // Distinguish public and private assets + bool isPublic = true; + switch ((AssetType)asset.Type) + { + case AssetType.CallingCard: + case AssetType.Gesture: + case AssetType.LSLBytecode: + case AssetType.LSLText: + isPublic = false; + break; + } + + // Make sure ContentType is set + if (String.IsNullOrEmpty(asset.Metadata.ContentType)) + asset.Metadata.ContentType = SLUtil.SLAssetTypeToContentType(asset.Type); + + // Build the remote storage request + List postParameters = new List() + { + new MultipartForm.Parameter("AssetID", asset.FullID.ToString()), + new MultipartForm.Parameter("CreatorID", asset.Metadata.CreatorID), + new MultipartForm.Parameter("Temporary", asset.Temporary ? "1" : "0"), + new MultipartForm.Parameter("Public", isPublic ? "1" : "0"), + new MultipartForm.File("Asset", asset.Name, asset.Metadata.ContentType, asset.Data) + }; + + // Make the remote storage request + try + { + HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(m_serverUrl); + + HttpWebResponse response = MultipartForm.Post(request, postParameters); + using (Stream responseStream = response.GetResponseStream()) + { + try + { + string responseStr = responseStream.GetStreamString(); + OSD responseOSD = OSDParser.Deserialize(responseStr); + if (responseOSD.Type == OSDType.Map) + { + OSDMap responseMap = (OSDMap)responseOSD; + if (responseMap["Success"].AsBoolean()) + return asset.ID; + else + errorMessage = "Upload failed: " + responseMap["Message"].AsString(); + } + else + { + errorMessage = "Response format was invalid."; + } + } + catch + { + errorMessage = "Failed to parse the response."; + } + } + } + catch (WebException ex) + { + errorMessage = ex.Message; + } + + m_log.WarnFormat("[ASSET CONNECTOR]: Failed to store asset \"{0}\" ({1}, {2}): {3}", + asset.Name, asset.ID, asset.Metadata.ContentType, errorMessage); + return null; + } + + /// + /// Update an asset's content + /// + /// Attachments and bare scripts need this!! + /// + /// + /// + public bool UpdateContent(string id, byte[] data) + { + AssetBase asset = Get(id); + + if (asset == null) + { + m_log.Warn("[ASSET CONNECTOR]: Failed to fetch asset " + id + " for updating"); + return false; + } + + asset.Data = data; + + string result = Store(asset); + return !String.IsNullOrEmpty(result); + } + + /// + /// Delete an asset + /// + /// + /// + public bool Delete(string id) + { + if (m_cache != null) + m_cache.Expire(id); + + string url = m_serverUrl + id; + + OSDMap response = WebUtil.ServiceRequest(url, "DELETE"); + if (response["Success"].AsBoolean()) + return true; + else + m_log.Warn("[ASSET CONNECTOR]: Failed to delete asset " + id + " from the asset service"); + + return false; + } + + #endregion IAssetService + } +} diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianAuthenticationServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianAuthenticationServiceConnector.cs new file mode 100644 index 0000000000..ec66341477 --- /dev/null +++ b/OpenSim/Services/Connectors/SimianGrid/SimianAuthenticationServiceConnector.cs @@ -0,0 +1,198 @@ +/* + * 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 OpenSimulator 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.Specialized; +using System.Reflection; +using log4net; +using Mono.Addins; +using Nini.Config; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Services.Interfaces; + +namespace OpenSim.Services.Connectors.SimianGrid +{ + /// + /// Connects authentication/authorization to the SimianGrid backend + /// + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] + public class SimianAuthenticationServiceConnector : IAuthenticationService, ISharedRegionModule + { + private static readonly ILog m_log = + LogManager.GetLogger( + MethodBase.GetCurrentMethod().DeclaringType); + + private string m_serverUrl = String.Empty; + + #region ISharedRegionModule + + public Type ReplaceableInterface { get { return null; } } + public void RegionLoaded(Scene scene) { } + public void PostInitialise() { } + public void Close() { } + + public SimianAuthenticationServiceConnector() { } + public string Name { get { return "SimianAuthenticationServiceConnector"; } } + public void AddRegion(Scene scene) { scene.RegisterModuleInterface(this); } + public void RemoveRegion(Scene scene) { scene.UnregisterModuleInterface(this); } + + #endregion ISharedRegionModule + + public SimianAuthenticationServiceConnector(IConfigSource source) + { + Initialise(source); + } + + public void Initialise(IConfigSource source) + { + IConfig assetConfig = source.Configs["AuthenticationService"]; + if (assetConfig == null) + { + m_log.Error("[AUTH CONNECTOR]: AuthenticationService missing from OpenSim.ini"); + throw new Exception("Authentication connector init error"); + } + + string serviceURI = assetConfig.GetString("AuthenticationServerURI"); + if (String.IsNullOrEmpty(serviceURI)) + { + m_log.Error("[AUTH CONNECTOR]: No Server URI named in section AuthenticationService"); + throw new Exception("Authentication connector init error"); + } + + m_serverUrl = serviceURI; + } + + public string Authenticate(UUID principalID, string password, int lifetime) + { + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "GetIdentities" }, + { "UserID", principalID.ToString() } + }; + + OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + if (response["Success"].AsBoolean() && response["Identities"] is OSDArray) + { + OSDArray identities = (OSDArray)response["Identities"]; + for (int i = 0; i < identities.Count; i++) + { + OSDMap identity = identities[i] as OSDMap; + if (identity != null) + { + if (identity["Type"].AsString() == "md5hash") + { + string credential = identity["Credential"].AsString(); + + if (password == credential || Utils.MD5String(password) == credential) + return Authorize(principalID); + } + } + } + + m_log.Warn("[AUTH CONNECTOR]: Authentication failed for " + principalID); + } + else + { + m_log.Warn("[AUTH CONNECTOR]: Failed to retrieve identities for " + principalID + ": " + + response["Message"].AsString()); + } + + return String.Empty; + } + + public bool Verify(UUID principalID, string token, int lifetime) + { + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "GetSession" }, + { "SessionID", token } + }; + + OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + if (response["Success"].AsBoolean()) + { + return true; + } + else + { + m_log.Warn("[AUTH CONNECTOR]: Could not verify session for " + principalID + ": " + + response["Message"].AsString()); + } + + return false; + } + + public bool Release(UUID principalID, string token) + { + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "RemoveSession" }, + { "UserID", principalID.ToString() } + }; + + OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + if (response["Success"].AsBoolean()) + { + return true; + } + else + { + m_log.Warn("[AUTH CONNECTOR]: Failed to remove session for " + principalID + ": " + + response["Message"].AsString()); + } + + return false; + } + + public bool SetPassword(UUID principalID, string passwd) + { + // TODO: Use GetIdentities to find the md5hash identity for principalID + // and then update it with AddIdentity + m_log.Error("[AUTH CONNECTOR]: Changing passwords is not implemented yet"); + return false; + } + + private string Authorize(UUID userID) + { + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "AddSession" }, + { "UserID", userID.ToString() } + }; + + OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + if (response["Success"].AsBoolean()) + return response["SessionID"].AsUUID().ToString(); + else + return String.Empty; + } + } +} diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianAvatarServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianAvatarServiceConnector.cs new file mode 100644 index 0000000000..220f143c78 --- /dev/null +++ b/OpenSim/Services/Connectors/SimianGrid/SimianAvatarServiceConnector.cs @@ -0,0 +1,259 @@ +/* + * 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 OpenSimulator 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.Collections.Specialized; +using System.IO; +using System.Net; +using System.Reflection; +using log4net; +using Mono.Addins; +using Nini.Config; +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Server.Base; +using OpenSim.Services.Interfaces; +using OpenMetaverse; +using OpenMetaverse.StructuredData; + +namespace OpenSim.Services.Connectors.SimianGrid +{ + /// + /// Connects avatar appearance data to the SimianGrid backend + /// + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] + public class SimianAvatarServiceConnector : IAvatarService, ISharedRegionModule + { + private static readonly ILog m_log = + LogManager.GetLogger( + MethodBase.GetCurrentMethod().DeclaringType); + private static string ZeroID = UUID.Zero.ToString(); + + private string m_serverUrl = String.Empty; + + #region ISharedRegionModule + + public Type ReplaceableInterface { get { return null; } } + public void RegionLoaded(Scene scene) { } + public void PostInitialise() { } + public void Close() { } + + public SimianAvatarServiceConnector() { } + public string Name { get { return "SimianAvatarServiceConnector"; } } + public void AddRegion(Scene scene) { scene.RegisterModuleInterface(this); } + public void RemoveRegion(Scene scene) { scene.UnregisterModuleInterface(this); } + + #endregion ISharedRegionModule + + public SimianAvatarServiceConnector(IConfigSource source) + { + Initialise(source); + } + + public void Initialise(IConfigSource source) + { + IConfig gridConfig = source.Configs["AvatarService"]; + if (gridConfig == null) + { + m_log.Error("[AVATAR CONNECTOR]: AvatarService missing from OpenSim.ini"); + throw new Exception("Avatar connector init error"); + } + + string serviceUrl = gridConfig.GetString("AvatarServerURI"); + if (String.IsNullOrEmpty(serviceUrl)) + { + m_log.Error("[AVATAR CONNECTOR]: No AvatarServerURI in section AvatarService"); + throw new Exception("Avatar connector init error"); + } + + if (!serviceUrl.EndsWith("/")) + serviceUrl = serviceUrl + '/'; + + m_serverUrl = serviceUrl; + } + + #region IAvatarService + + public AvatarData GetAvatar(UUID userID) + { + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "GetUser" }, + { "UserID", userID.ToString() } + }; + + OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + if (response["Success"].AsBoolean()) + { + OSDMap map = null; + try { map = OSDParser.DeserializeJson(response["LLAppearance"].AsString()) as OSDMap; } + catch { } + + if (map != null) + { + AvatarWearable[] wearables = new AvatarWearable[13]; + wearables[0] = new AvatarWearable(map["ShapeItem"].AsUUID(), map["ShapeAsset"].AsUUID()); + wearables[1] = new AvatarWearable(map["SkinItem"].AsUUID(), map["SkinAsset"].AsUUID()); + wearables[2] = new AvatarWearable(map["HairItem"].AsUUID(), map["HairAsset"].AsUUID()); + wearables[3] = new AvatarWearable(map["EyesItem"].AsUUID(), map["EyesAsset"].AsUUID()); + wearables[4] = new AvatarWearable(map["ShirtItem"].AsUUID(), map["ShirtAsset"].AsUUID()); + wearables[5] = new AvatarWearable(map["PantsItem"].AsUUID(), map["PantsAsset"].AsUUID()); + wearables[6] = new AvatarWearable(map["ShoesItem"].AsUUID(), map["ShoesAsset"].AsUUID()); + wearables[7] = new AvatarWearable(map["SocksItem"].AsUUID(), map["SocksAsset"].AsUUID()); + wearables[8] = new AvatarWearable(map["JacketItem"].AsUUID(), map["JacketAsset"].AsUUID()); + wearables[9] = new AvatarWearable(map["GlovesItem"].AsUUID(), map["GlovesAsset"].AsUUID()); + wearables[10] = new AvatarWearable(map["UndershirtItem"].AsUUID(), map["UndershirtAsset"].AsUUID()); + wearables[11] = new AvatarWearable(map["UnderpantsItem"].AsUUID(), map["UnderpantsAsset"].AsUUID()); + wearables[12] = new AvatarWearable(map["SkirtItem"].AsUUID(), map["SkirtAsset"].AsUUID()); + + AvatarAppearance appearance = new AvatarAppearance(userID); + appearance.Wearables = wearables; + appearance.AvatarHeight = (float)map["Height"].AsReal(); + + AvatarData avatar = new AvatarData(appearance); + + // Get attachments + map = null; + try { map = OSDParser.DeserializeJson(response["LLAttachments"].AsString()) as OSDMap; } + catch { } + + if (map != null) + { + foreach (KeyValuePair kvp in map) + avatar.Data[kvp.Key] = kvp.Value.AsString(); + } + + return avatar; + } + else + { + m_log.Warn("[AVATAR CONNECTOR]: Failed to get user appearance for " + userID + + ", LLAppearance is missing or invalid"); + return null; + } + } + else + { + m_log.Warn("[AVATAR CONNECTOR]: Failed to get user appearance for " + userID + ": " + + response["Message"].AsString()); + } + + return null; + } + + public bool SetAvatar(UUID userID, AvatarData avatar) + { + m_log.Debug("[AVATAR CONNECTOR]: SetAvatar called for " + userID); + + if (avatar.AvatarType == 1) // LLAvatar + { + AvatarAppearance appearance = avatar.ToAvatarAppearance(userID); + + OSDMap map = new OSDMap(); + + map["Height"] = OSD.FromReal(appearance.AvatarHeight); + + map["ShapeItem"] = OSD.FromUUID(appearance.BodyItem); + map["ShapeAsset"] = OSD.FromUUID(appearance.BodyAsset); + map["SkinItem"] = OSD.FromUUID(appearance.SkinItem); + map["SkinAsset"] = OSD.FromUUID(appearance.SkinAsset); + map["HairItem"] = OSD.FromUUID(appearance.HairItem); + map["HairAsset"] = OSD.FromUUID(appearance.HairAsset); + map["EyesItem"] = OSD.FromUUID(appearance.EyesItem); + map["EyesAsset"] = OSD.FromUUID(appearance.EyesAsset); + map["ShirtItem"] = OSD.FromUUID(appearance.ShirtItem); + map["ShirtAsset"] = OSD.FromUUID(appearance.ShirtAsset); + map["PantsItem"] = OSD.FromUUID(appearance.PantsItem); + map["PantsAsset"] = OSD.FromUUID(appearance.PantsAsset); + map["ShoesItem"] = OSD.FromUUID(appearance.ShoesItem); + map["ShoesAsset"] = OSD.FromUUID(appearance.ShoesAsset); + map["SocksItem"] = OSD.FromUUID(appearance.SocksItem); + map["SocksAsset"] = OSD.FromUUID(appearance.SocksAsset); + map["JacketItem"] = OSD.FromUUID(appearance.JacketItem); + map["JacketAsset"] = OSD.FromUUID(appearance.JacketAsset); + map["GlovesItem"] = OSD.FromUUID(appearance.GlovesItem); + map["GlovesAsset"] = OSD.FromUUID(appearance.GlovesAsset); + map["UndershirtItem"] = OSD.FromUUID(appearance.UnderShirtItem); + map["UndershirtAsset"] = OSD.FromUUID(appearance.UnderShirtAsset); + map["UnderpantsItem"] = OSD.FromUUID(appearance.UnderPantsItem); + map["UnderpantsAsset"] = OSD.FromUUID(appearance.UnderPantsAsset); + map["SkirtItem"] = OSD.FromUUID(appearance.SkirtItem); + map["SkirtAsset"] = OSD.FromUUID(appearance.SkirtAsset); + + OSDMap items = new OSDMap(); + foreach (KeyValuePair kvp in avatar.Data) + { + if (kvp.Key.StartsWith("_ap_")) + items.Add(kvp.Key, OSD.FromString(kvp.Value)); + } + + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "AddUserData" }, + { "UserID", userID.ToString() }, + { "LLAppearance", OSDParser.SerializeJsonString(map) }, + { "LLAttachments", OSDParser.SerializeJsonString(items) } + }; + + OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + bool success = response["Success"].AsBoolean(); + + if (!success) + m_log.Warn("[AVATAR CONNECTOR]: Failed saving appearance for " + userID + ": " + response["Message"].AsString()); + + return success; + } + else + { + m_log.Error("[AVATAR CONNECTOR]: Can't save appearance for " + userID + ". Unhandled avatar type " + avatar.AvatarType); + return false; + } + } + + public bool ResetAvatar(UUID userID) + { + m_log.Error("[AVATAR CONNECTOR]: ResetAvatar called for " + userID + ", implement this"); + return false; + } + + public bool SetItems(UUID userID, string[] names, string[] values) + { + m_log.Error("[AVATAR CONNECTOR]: SetItems called for " + userID + " with " + names.Length + " names and " + values.Length + " values, implement this"); + return false; + } + + public bool RemoveItems(UUID userID, string[] names) + { + m_log.Error("[AVATAR CONNECTOR]: RemoveItems called for " + userID + " with " + names.Length + " names, implement this"); + return false; + } + + #endregion IAvatarService + } +} diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianFriendsServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianFriendsServiceConnector.cs new file mode 100644 index 0000000000..3952a8c3d0 --- /dev/null +++ b/OpenSim/Services/Connectors/SimianGrid/SimianFriendsServiceConnector.cs @@ -0,0 +1,229 @@ +/* + * 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 OpenSimulator 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.Collections.Specialized; +using System.Reflection; +using log4net; +using Mono.Addins; +using Nini.Config; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Services.Interfaces; + +using FriendInfo = OpenSim.Services.Interfaces.FriendInfo; + +namespace OpenSim.Services.Connectors.SimianGrid +{ + /// + /// Stores and retrieves friend lists from the SimianGrid backend + /// + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] + public class SimianFriendsServiceConnector : IFriendsService, ISharedRegionModule + { + private static readonly ILog m_log = + LogManager.GetLogger( + MethodBase.GetCurrentMethod().DeclaringType); + + private string m_serverUrl = String.Empty; + + #region ISharedRegionModule + + public Type ReplaceableInterface { get { return null; } } + public void RegionLoaded(Scene scene) { } + public void PostInitialise() { } + public void Close() { } + + public SimianFriendsServiceConnector() { } + public string Name { get { return "SimianFriendsServiceConnector"; } } + public void AddRegion(Scene scene) { scene.RegisterModuleInterface(this); } + public void RemoveRegion(Scene scene) { scene.UnregisterModuleInterface(this); } + + #endregion ISharedRegionModule + + public SimianFriendsServiceConnector(IConfigSource source) + { + Initialise(source); + } + + public void Initialise(IConfigSource source) + { + IConfig assetConfig = source.Configs["FriendsService"]; + if (assetConfig == null) + { + m_log.Error("[FRIENDS CONNECTOR]: FriendsService missing from OpenSim.ini"); + throw new Exception("Friends connector init error"); + } + + string serviceURI = assetConfig.GetString("FriendsServerURI"); + if (String.IsNullOrEmpty(serviceURI)) + { + m_log.Error("[FRIENDS CONNECTOR]: No Server URI named in section FriendsService"); + throw new Exception("Friends connector init error"); + } + + m_serverUrl = serviceURI; + } + + #region IFriendsService + + public FriendInfo[] GetFriends(UUID principalID) + { + Dictionary friends = new Dictionary(); + + OSDArray friendsArray = GetFriended(principalID); + OSDArray friendedMeArray = GetFriendedBy(principalID); + + // Load the list of friends and their granted permissions + for (int i = 0; i < friendsArray.Count; i++) + { + OSDMap friendEntry = friendsArray[i] as OSDMap; + if (friendEntry != null) + { + UUID friendID = friendEntry["Key"].AsUUID(); + + FriendInfo friend = new FriendInfo(); + friend.PrincipalID = principalID; + friend.Friend = friendID.ToString(); + friend.MyFlags = friendEntry["Value"].AsInteger(); + friend.TheirFlags = -1; + + friends[friendID] = friend; + } + } + + // Load the permissions those friends have granted to this user + for (int i = 0; i < friendedMeArray.Count; i++) + { + OSDMap friendedMeEntry = friendedMeArray[i] as OSDMap; + if (friendedMeEntry != null) + { + UUID friendID = friendedMeEntry["OwnerID"].AsUUID(); + + FriendInfo friend; + if (friends.TryGetValue(friendID, out friend)) + friend.TheirFlags = friendedMeEntry["Value"].AsInteger(); + } + } + + // Convert the dictionary of friends to an array and return it + FriendInfo[] array = new FriendInfo[friends.Count]; + int j = 0; + foreach (FriendInfo friend in friends.Values) + array[j++] = friend; + + return array; + } + + public bool StoreFriend(UUID principalID, string friend, int flags) + { + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "AddGeneric" }, + { "OwnerID", principalID.ToString() }, + { "Type", "Friend" }, + { "Key", friend }, + { "Value", flags.ToString() } + }; + + OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + bool success = response["Success"].AsBoolean(); + + if (!success) + m_log.Error("[FRIENDS CONNECTOR]: Failed to store friend " + friend + " for user " + principalID + ": " + response["Message"].AsString()); + + return success; + } + + public bool Delete(UUID principalID, string friend) + { + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "RemoveGeneric" }, + { "OwnerID", principalID.ToString() }, + { "Type", "Friend" }, + { "Key", friend } + }; + + OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + bool success = response["Success"].AsBoolean(); + + if (!success) + m_log.Error("[FRIENDS CONNECTOR]: Failed to remove friend " + friend + " for user " + principalID + ": " + response["Message"].AsString()); + + return success; + } + + #endregion IFriendsService + + private OSDArray GetFriended(UUID ownerID) + { + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "GetGenerics" }, + { "OwnerID", ownerID.ToString() }, + { "Type", "Friend" } + }; + + OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + if (response["Success"].AsBoolean() && response["Entries"] is OSDArray) + { + return (OSDArray)response["Entries"]; + } + else + { + m_log.Warn("[FRIENDS CONNECTOR]: Failed to retrieve friends for user " + ownerID + ": " + response["Message"].AsString()); + return new OSDArray(0); + } + } + + private OSDArray GetFriendedBy(UUID ownerID) + { + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "GetGenerics" }, + { "Key", ownerID.ToString() }, + { "Type", "Friend" } + }; + + OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + if (response["Success"].AsBoolean() && response["Entries"] is OSDArray) + { + return (OSDArray)response["Entries"]; + } + else + { + m_log.Warn("[FRIENDS CONNECTOR]: Failed to retrieve reverse friends for user " + ownerID + ": " + response["Message"].AsString()); + return new OSDArray(0); + } + } + } +} diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianGrid.cs b/OpenSim/Services/Connectors/SimianGrid/SimianGrid.cs new file mode 100644 index 0000000000..41ed2f1646 --- /dev/null +++ b/OpenSim/Services/Connectors/SimianGrid/SimianGrid.cs @@ -0,0 +1,31 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator 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 Mono.Addins; + +[assembly: Addin("SimianGrid", "1.0")] +[assembly: AddinDependency("OpenSim", "0.5")] diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs new file mode 100644 index 0000000000..16819d174c --- /dev/null +++ b/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs @@ -0,0 +1,418 @@ +/* + * 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 OpenSimulator 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.Collections.Specialized; +using System.Net; +using System.Reflection; +using log4net; +using Mono.Addins; +using Nini.Config; +using OpenSim.Framework; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Services.Interfaces; +using OpenSim.Server.Base; +using OpenMetaverse; +using OpenMetaverse.StructuredData; + +using GridRegion = OpenSim.Services.Interfaces.GridRegion; + +namespace OpenSim.Services.Connectors.SimianGrid +{ + /// + /// Connects region registration and neighbor lookups to the SimianGrid + /// backend + /// + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] + public class SimianGridServiceConnector : IGridService, ISharedRegionModule + { + private static readonly ILog m_log = + LogManager.GetLogger( + MethodBase.GetCurrentMethod().DeclaringType); + + private string m_serverUrl = String.Empty; + + #region ISharedRegionModule + + public Type ReplaceableInterface { get { return null; } } + public void RegionLoaded(Scene scene) { } + public void PostInitialise() { } + public void Close() { } + + public SimianGridServiceConnector() { } + public string Name { get { return "SimianGridServiceConnector"; } } + public void AddRegion(Scene scene) { scene.RegisterModuleInterface(this); } + public void RemoveRegion(Scene scene) { scene.UnregisterModuleInterface(this); } + + #endregion ISharedRegionModule + + public SimianGridServiceConnector(IConfigSource source) + { + Initialise(source); + } + + public void Initialise(IConfigSource source) + { + IConfig gridConfig = source.Configs["GridService"]; + if (gridConfig == null) + { + m_log.Error("[GRID CONNECTOR]: GridService missing from OpenSim.ini"); + throw new Exception("Grid connector init error"); + } + + string serviceUrl = gridConfig.GetString("GridServerURI"); + if (String.IsNullOrEmpty(serviceUrl)) + { + m_log.Error("[GRID CONNECTOR]: No Server URI named in section GridService"); + throw new Exception("Grid connector init error"); + } + + m_serverUrl = serviceUrl; + } + + #region IGridService + + public string RegisterRegion(UUID scopeID, GridRegion regionInfo) + { + Vector3d minPosition = new Vector3d(regionInfo.RegionLocX, regionInfo.RegionLocY, 0.0); + Vector3d maxPosition = minPosition + new Vector3d(Constants.RegionSize, Constants.RegionSize, 4096.0); + + string httpAddress = "http://" + regionInfo.ExternalHostName + ":" + regionInfo.HttpPort + "/"; + + OSDMap extraData = new OSDMap + { + { "ServerURI", OSD.FromString(regionInfo.ServerURI) }, + { "InternalAddress", OSD.FromString(regionInfo.InternalEndPoint.Address.ToString()) }, + { "InternalPort", OSD.FromInteger(regionInfo.InternalEndPoint.Port) }, + { "ExternalAddress", OSD.FromString(regionInfo.ExternalEndPoint.Address.ToString()) }, + { "ExternalPort", OSD.FromInteger(regionInfo.ExternalEndPoint.Port) }, + { "MapTexture", OSD.FromUUID(regionInfo.TerrainImage) }, + { "Access", OSD.FromInteger(regionInfo.Access) }, + { "RegionSecret", OSD.FromString(regionInfo.RegionSecret) }, + { "EstateOwner", OSD.FromUUID(regionInfo.EstateOwner) }, + { "Token", OSD.FromString(regionInfo.Token) } + }; + + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "AddScene" }, + { "SceneID", regionInfo.RegionID.ToString() }, + { "Name", regionInfo.RegionName }, + { "MinPosition", minPosition.ToString() }, + { "MaxPosition", maxPosition.ToString() }, + { "Address", httpAddress }, + { "Enabled", "1" }, + { "ExtraData", OSDParser.SerializeJsonString(extraData) } + }; + + OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + if (response["Success"].AsBoolean()) + return String.Empty; + else + return "Region registration for " + regionInfo.RegionName + " failed: " + response["Message"].AsString(); + } + + public bool DeregisterRegion(UUID regionID) + { + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "AddScene" }, + { "SceneID", regionID.ToString() }, + { "Enabled", "0" } + }; + + OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + bool success = response["Success"].AsBoolean(); + + if (!success) + m_log.Warn("[GRID CONNECTOR]: Region deregistration for " + regionID + " failed: " + response["Message"].AsString()); + + return success; + } + + public List GetNeighbours(UUID scopeID, UUID regionID) + { + const int NEIGHBOR_RADIUS = 128; + + GridRegion region = GetRegionByUUID(scopeID, regionID); + + if (region != null) + { + List regions = GetRegionRange(scopeID, + region.RegionLocX - NEIGHBOR_RADIUS, region.RegionLocX + (int)Constants.RegionSize + NEIGHBOR_RADIUS, + region.RegionLocY - NEIGHBOR_RADIUS, region.RegionLocY + (int)Constants.RegionSize + NEIGHBOR_RADIUS); + + for (int i = 0; i < regions.Count; i++) + { + if (regions[i].RegionID == regionID) + { + regions.RemoveAt(i); + break; + } + } + + m_log.Debug("[GRID CONNECTOR]: Found " + regions.Count + " neighbors for region " + regionID); + return regions; + } + + return new List(0); + } + + public GridRegion GetRegionByUUID(UUID scopeID, UUID regionID) + { + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "GetScene" }, + { "SceneID", regionID.ToString() } + }; + + OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + if (response["Success"].AsBoolean()) + { + return ResponseToGridRegion(response); + } + else + { + m_log.Warn("[GRID CONNECTOR]: Grid service did not find a match for region " + regionID); + return null; + } + } + + public GridRegion GetRegionByPosition(UUID scopeID, int x, int y) + { + // Go one meter in from the requested x/y coords to avoid requesting a position + // that falls on the border of two sims + Vector3d position = new Vector3d(x + 1, y + 1, 0.0); + + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "GetScene" }, + { "Position", position.ToString() }, + { "Enabled", "1" } + }; + + OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + if (response["Success"].AsBoolean()) + { + return ResponseToGridRegion(response); + } + else + { + //m_log.InfoFormat("[GRID CONNECTOR]: Grid service did not find a match for region at {0},{1}", + // x / Constants.RegionSize, y / Constants.RegionSize); + return null; + } + } + + public GridRegion GetRegionByName(UUID scopeID, string regionName) + { + List regions = GetRegionsByName(scopeID, regionName, 1); + + m_log.Debug("[GRID CONNECTOR]: Got " + regions.Count + " matches for region name " + regionName); + + if (regions.Count > 0) + return regions[0]; + + return null; + } + + public List GetRegionsByName(UUID scopeID, string name, int maxNumber) + { + List foundRegions = new List(); + + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "GetScenes" }, + { "NameQuery", name }, + { "Enabled", "1" } + }; + if (maxNumber > 0) + requestArgs["MaxNumber"] = maxNumber.ToString(); + + OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + if (response["Success"].AsBoolean()) + { + OSDArray array = response["Scenes"] as OSDArray; + if (array != null) + { + for (int i = 0; i < array.Count; i++) + { + GridRegion region = ResponseToGridRegion(array[i] as OSDMap); + if (region != null) + foundRegions.Add(region); + } + } + } + + return foundRegions; + } + + public List GetRegionRange(UUID scopeID, int xmin, int xmax, int ymin, int ymax) + { + List foundRegions = new List(); + + Vector3d minPosition = new Vector3d(xmin, ymin, 0.0); + Vector3d maxPosition = new Vector3d(xmax, ymax, 4096.0); + + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "GetScenes" }, + { "MinPosition", minPosition.ToString() }, + { "MaxPosition", maxPosition.ToString() }, + { "Enabled", "1" } + }; + + OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + if (response["Success"].AsBoolean()) + { + OSDArray array = response["Scenes"] as OSDArray; + if (array != null) + { + for (int i = 0; i < array.Count; i++) + { + GridRegion region = ResponseToGridRegion(array[i] as OSDMap); + if (region != null) + foundRegions.Add(region); + } + } + } + + return foundRegions; + } + + public List GetDefaultRegions(UUID scopeID) + { + // TODO: Allow specifying the default grid location + const int DEFAULT_X = 1000 * 256; + const int DEFAULT_Y = 1000 * 256; + + GridRegion defRegion = GetNearestRegion(new Vector3d(DEFAULT_X, DEFAULT_Y, 0.0), true); + if (defRegion != null) + return new List(1) { defRegion }; + else + return new List(0); + } + + public List GetFallbackRegions(UUID scopeID, int x, int y) + { + GridRegion defRegion = GetNearestRegion(new Vector3d(x, y, 0.0), true); + if (defRegion != null) + return new List(1) { defRegion }; + else + return new List(0); + } + + public int GetRegionFlags(UUID scopeID, UUID regionID) + { + const int REGION_ONLINE = 4; + + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "GetScene" }, + { "SceneID", regionID.ToString() } + }; + + OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + if (response["Success"].AsBoolean()) + { + return response["Enabled"].AsBoolean() ? REGION_ONLINE : 0; + } + else + { + m_log.Warn("[GRID CONNECTOR]: Grid service did not find a match for region " + regionID + " during region flags check"); + return -1; + } + } + + #endregion IGridService + + private GridRegion GetNearestRegion(Vector3d position, bool onlyEnabled) + { + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "GetScene" }, + { "Position", position.ToString() }, + { "FindClosest", "1" } + }; + if (onlyEnabled) + requestArgs["Enabled"] = "1"; + + OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + if (response["Success"].AsBoolean()) + { + return ResponseToGridRegion(response); + } + else + { + m_log.Warn("[GRID CONNECTOR]: Grid service did not find a match for region at " + position); + return null; + } + } + + private GridRegion ResponseToGridRegion(OSDMap response) + { + if (response == null) + return null; + + OSDMap extraData = response["ExtraData"] as OSDMap; + if (extraData == null) + return null; + + GridRegion region = new GridRegion(); + + region.RegionID = response["SceneID"].AsUUID(); + region.RegionName = response["Name"].AsString(); + + Vector3d minPosition = response["MinPosition"].AsVector3d(); + region.RegionLocX = (int)minPosition.X; + region.RegionLocY = (int)minPosition.Y; + + Uri httpAddress = response["Address"].AsUri(); + region.ExternalHostName = httpAddress.Host; + region.HttpPort = (uint)httpAddress.Port; + + region.ServerURI = extraData["ServerURI"].AsString(); + + IPAddress internalAddress; + IPAddress.TryParse(extraData["InternalAddress"].AsString(), out internalAddress); + if (internalAddress == null) + internalAddress = IPAddress.Any; + + region.InternalEndPoint = new IPEndPoint(internalAddress, extraData["InternalPort"].AsInteger()); + region.TerrainImage = extraData["MapTexture"].AsUUID(); + region.Access = (byte)extraData["Access"].AsInteger(); + region.RegionSecret = extraData["RegionSecret"].AsString(); + region.EstateOwner = extraData["EstateOwner"].AsUUID(); + region.Token = extraData["Token"].AsString(); + + return region; + } + } +} diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianInventoryServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianInventoryServiceConnector.cs new file mode 100644 index 0000000000..c8128999c0 --- /dev/null +++ b/OpenSim/Services/Connectors/SimianGrid/SimianInventoryServiceConnector.cs @@ -0,0 +1,880 @@ +/* + * 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 OpenSimulator 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.Collections.Specialized; +using System.Reflection; +using log4net; +using Mono.Addins; +using Nini.Config; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Server.Base; +using OpenSim.Services.Interfaces; + +namespace OpenSim.Services.Connectors.SimianGrid +{ + /// + /// Permissions bitflags + /// + [Flags] + public enum PermissionMask : uint + { + None = 0, + Transfer = 1 << 13, + Modify = 1 << 14, + Copy = 1 << 15, + Move = 1 << 19, + Damage = 1 << 20, + All = 0x7FFFFFFF + } + + /// + /// Connects avatar inventories to the SimianGrid backend + /// + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] + public class SimianInventoryServiceConnector : IInventoryService, ISharedRegionModule + { + private static readonly ILog m_log = + LogManager.GetLogger( + MethodBase.GetCurrentMethod().DeclaringType); + + private string m_serverUrl = String.Empty; + private string m_userServerUrl = String.Empty; + private object m_gestureSyncRoot = new object(); + + #region ISharedRegionModule + + public Type ReplaceableInterface { get { return null; } } + public void RegionLoaded(Scene scene) { } + public void PostInitialise() { } + public void Close() { } + + public SimianInventoryServiceConnector() { } + public string Name { get { return "SimianInventoryServiceConnector"; } } + public void AddRegion(Scene scene) { scene.RegisterModuleInterface(this); } + public void RemoveRegion(Scene scene) { scene.UnregisterModuleInterface(this); } + + #endregion ISharedRegionModule + + public SimianInventoryServiceConnector(IConfigSource source) + { + Initialise(source); + } + + public void Initialise(IConfigSource source) + { + IConfig gridConfig = source.Configs["InventoryService"]; + if (gridConfig == null) + { + m_log.Error("[INVENTORY CONNECTOR]: InventoryService missing from OpenSim.ini"); + throw new Exception("Inventory connector init error"); + } + + string serviceUrl = gridConfig.GetString("InventoryServerURI"); + if (String.IsNullOrEmpty(serviceUrl)) + { + m_log.Error("[INVENTORY CONNECTOR]: No Server URI named in section InventoryService"); + throw new Exception("Inventory connector init error"); + } + + // FIXME: Get the user server URL too + + m_serverUrl = serviceUrl; + } + + /// + /// Create the entire inventory for a given user + /// + /// + /// + public bool CreateUserInventory(UUID userID) + { + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "AddInventory" }, + { "OwnerID", userID.ToString() } + }; + + OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + bool success = response["Success"].AsBoolean(); + + if (!success) + m_log.Warn("[INVENTORY CONNECTOR]: Inventory creation for " + userID + " failed: " + response["Message"].AsString()); + + return success; + } + + /// + /// Gets the skeleton of the inventory -- folders only + /// + /// + /// + public List GetInventorySkeleton(UUID userID) + { + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "GetInventoryNode" }, + { "ItemID", userID.ToString() }, + { "OwnerID", userID.ToString() }, + { "IncludeFolders", "1" }, + { "IncludeItems", "0" }, + { "ChildrenOnly", "0" } + }; + + OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + if (response["Success"].AsBoolean() && response["Items"] is OSDArray) + { + OSDArray items = (OSDArray)response["Items"]; + return GetFoldersFromResponse(items, userID, true); + } + else + { + m_log.Warn("[INVENTORY CONNECTOR]: Failed to retrieve inventory skeleton for " + userID + ": " + + response["Message"].AsString()); + return new List(0); + } + } + + /// + /// Synchronous inventory fetch. + /// + /// + /// + [Obsolete] + public InventoryCollection GetUserInventory(UUID userID) + { + m_log.Error("[INVENTORY CONNECTOR]: Obsolete GetUserInventory called for " + userID); + + InventoryCollection inventory = new InventoryCollection(); + inventory.UserID = userID; + inventory.Folders = new List(); + inventory.Items = new List(); + + return inventory; + } + + /// + /// Request the inventory for a user. This is an asynchronous operation that will call the callback when the + /// inventory has been received + /// + /// + /// + [Obsolete] + public void GetUserInventory(UUID userID, InventoryReceiptCallback callback) + { + m_log.Error("[INVENTORY CONNECTOR]: Obsolete GetUserInventory called for " + userID); + callback(new List(0), new List(0)); + } + + /// + /// Retrieve the root inventory folder for the given user. + /// + /// + /// null if no root folder was found + public InventoryFolderBase GetRootFolder(UUID userID) + { + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "GetInventoryNode" }, + { "ItemID", userID.ToString() }, + { "OwnerID", userID.ToString() }, + { "IncludeFolders", "1" }, + { "IncludeItems", "0" }, + { "ChildrenOnly", "1" } + }; + + OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + if (response["Success"].AsBoolean() && response["Items"] is OSDArray) + { + OSDArray items = (OSDArray)response["Items"]; + List folders = GetFoldersFromResponse(items, userID, true); + + if (folders.Count > 0) + return folders[0]; + } + + return null; + } + + /// + /// Gets the user folder for the given folder-type + /// + /// + /// + /// + public InventoryFolderBase GetFolderForType(UUID userID, AssetType type) + { + string contentType = SLUtil.SLAssetTypeToContentType((int)type); + + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "GetFolderForType" }, + { "ContentType", contentType }, + { "OwnerID", userID.ToString() } + }; + + OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + if (response["Success"].AsBoolean() && response["Folder"] is OSDMap) + { + OSDMap folder = (OSDMap)response["Folder"]; + + return new InventoryFolderBase( + folder["ID"].AsUUID(), + folder["Name"].AsString(), + folder["OwnerID"].AsUUID(), + (short)SLUtil.ContentTypeToSLAssetType(folder["ContentType"].AsString()), + folder["ParentID"].AsUUID(), + (ushort)folder["Version"].AsInteger() + ); + } + else + { + m_log.Warn("[INVENTORY CONNECTOR]: Default folder not found for content type " + contentType); + return GetRootFolder(userID); + } + } + + /// + /// Get an item, given by its UUID + /// + /// + /// + public InventoryItemBase GetItem(InventoryItemBase item) + { + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "GetInventoryNode" }, + { "ItemID", item.ID.ToString() }, + { "OwnerID", item.Owner.ToString() }, + { "IncludeFolders", "1" }, + { "IncludeItems", "1" }, + { "ChildrenOnly", "1" } + }; + + OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + if (response["Success"].AsBoolean() && response["Items"] is OSDArray) + { + List items = GetItemsFromResponse((OSDArray)response["Items"]); + if (items.Count > 0) + { + // The requested item should be the first in this list, but loop through + // and sanity check just in case + for (int i = 0; i < items.Count; i++) + { + if (items[i].ID == item.ID) + return items[i]; + } + } + } + + m_log.Warn("[INVENTORY CONNECTOR]: Item " + item.ID + " owned by " + item.Owner + " not found"); + return null; + } + + /// + /// Get a folder, given by its UUID + /// + /// + /// + public InventoryFolderBase GetFolder(InventoryFolderBase folder) + { + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "GetInventoryNode" }, + { "ItemID", folder.ID.ToString() }, + { "OwnerID", folder.Owner.ToString() }, + { "IncludeFolders", "1" }, + { "IncludeItems", "0" }, + { "ChildrenOnly", "1" } + }; + + OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + if (response["Success"].AsBoolean() && response["Items"] is OSDArray) + { + OSDArray items = (OSDArray)response["Items"]; + List folders = GetFoldersFromResponse(items, folder.ID, true); + + if (folders.Count > 0) + return folders[0]; + } + + return null; + } + + /// + /// Gets everything (folders and items) inside a folder + /// + /// + /// + /// + public InventoryCollection GetFolderContent(UUID userID, UUID folderID) + { + InventoryCollection inventory = new InventoryCollection(); + inventory.UserID = userID; + + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "GetInventoryNode" }, + { "ItemID", folderID.ToString() }, + { "OwnerID", userID.ToString() }, + { "IncludeFolders", "1" }, + { "IncludeItems", "1" }, + { "ChildrenOnly", "1" } + }; + + OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + if (response["Success"].AsBoolean() && response["Items"] is OSDArray) + { + OSDArray items = (OSDArray)response["Items"]; + + inventory.Folders = GetFoldersFromResponse(items, folderID, false); + inventory.Items = GetItemsFromResponse(items); + } + else + { + m_log.Warn("[INVENTORY CONNECTOR]: Error fetching folder " + folderID + " content for " + userID + ": " + + response["Message"].AsString()); + inventory.Folders = new List(0); + inventory.Items = new List(0); + } + + return inventory; + } + + /// + /// Gets the items inside a folder + /// + /// + /// + /// + public List GetFolderItems(UUID userID, UUID folderID) + { + InventoryCollection inventory = new InventoryCollection(); + inventory.UserID = userID; + + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "GetInventoryNode" }, + { "ItemID", folderID.ToString() }, + { "OwnerID", userID.ToString() }, + { "IncludeFolders", "0" }, + { "IncludeItems", "1" }, + { "ChildrenOnly", "1" } + }; + + OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + if (response["Success"].AsBoolean() && response["Items"] is OSDArray) + { + OSDArray items = (OSDArray)response["Items"]; + return GetItemsFromResponse(items); + } + else + { + m_log.Warn("[INVENTORY CONNECTOR]: Error fetching folder " + folderID + " for " + userID + ": " + + response["Message"].AsString()); + return new List(0); + } + } + + /// + /// Add a new folder to the user's inventory + /// + /// + /// true if the folder was successfully added + public bool AddFolder(InventoryFolderBase folder) + { + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "AddInventoryFolder" }, + { "FolderID", folder.ID.ToString() }, + { "ParentID", folder.ParentID.ToString() }, + { "OwnerID", folder.Owner.ToString() }, + { "Name", folder.Name }, + { "ContentType", SLUtil.SLAssetTypeToContentType(folder.Type) } + }; + + OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + bool success = response["Success"].AsBoolean(); + + if (!success) + { + m_log.Warn("[INVENTORY CONNECTOR]: Error creating folder " + folder.Name + " for " + folder.Owner + ": " + + response["Message"].AsString()); + } + + return success; + } + + /// + /// Update a folder in the user's inventory + /// + /// + /// true if the folder was successfully updated + public bool UpdateFolder(InventoryFolderBase folder) + { + return AddFolder(folder); + } + + /// + /// Move an inventory folder to a new location + /// + /// A folder containing the details of the new location + /// true if the folder was successfully moved + public bool MoveFolder(InventoryFolderBase folder) + { + return AddFolder(folder); + } + + /// + /// Delete an item from the user's inventory + /// + /// + /// true if the item was successfully deleted + //bool DeleteItem(InventoryItemBase item); + public bool DeleteFolders(UUID userID, List folderIDs) + { + return DeleteItems(userID, folderIDs); + } + + /// + /// Delete an item from the user's inventory + /// + /// + /// true if the item was successfully deleted + public bool DeleteItems(UUID userID, List itemIDs) + { + // TODO: RemoveInventoryNode should be replaced with RemoveInventoryNodes + bool allSuccess = true; + + for (int i = 0; i < itemIDs.Count; i++) + { + UUID itemID = itemIDs[i]; + + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "RemoveInventoryNode" }, + { "OwnerID", userID.ToString() }, + { "ItemID", itemID.ToString() } + }; + + OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + bool success = response["Success"].AsBoolean(); + + if (!success) + { + m_log.Warn("[INVENTORY CONNECTOR]: Error removing item " + itemID + " for " + userID + ": " + + response["Message"].AsString()); + allSuccess = false; + } + } + + return allSuccess; + } + + /// + /// Purge an inventory folder of all its items and subfolders. + /// + /// + /// true if the folder was successfully purged + public bool PurgeFolder(InventoryFolderBase folder) + { + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "PurgeInventoryFolder" }, + { "OwnerID", folder.Owner.ToString() }, + { "FolderID", folder.ID.ToString() } + }; + + OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + bool success = response["Success"].AsBoolean(); + + if (!success) + { + m_log.Warn("[INVENTORY CONNECTOR]: Error purging folder " + folder.ID + " for " + folder.Owner + ": " + + response["Message"].AsString()); + } + + return success; + } + + /// + /// Add a new item to the user's inventory + /// + /// + /// true if the item was successfully added + public bool AddItem(InventoryItemBase item) + { + // A folder of UUID.Zero means we need to find the most appropriate home for this item + if (item.Folder == UUID.Zero) + { + InventoryFolderBase folder = GetFolderForType(item.Owner, (AssetType)item.AssetType); + if (folder != null && folder.ID != UUID.Zero) + item.Folder = folder.ID; + else + item.Folder = item.Owner; // Root folder + } + + if ((AssetType)item.AssetType == AssetType.Gesture) + UpdateGesture(item.Owner, item.ID, item.Flags == 1); + + if (item.BasePermissions == 0) + m_log.WarnFormat("[INVENTORY CONNECTOR]: Adding inventory item {0} ({1}) with no base permissions", item.Name, item.ID); + + OSDMap permissions = new OSDMap + { + { "BaseMask", OSD.FromInteger(item.BasePermissions) }, + { "EveryoneMask", OSD.FromInteger(item.EveryOnePermissions) }, + { "GroupMask", OSD.FromInteger(item.GroupPermissions) }, + { "NextOwnerMask", OSD.FromInteger(item.NextPermissions) }, + { "OwnerMask", OSD.FromInteger(item.CurrentPermissions) } + }; + + OSDMap extraData = new OSDMap() + { + { "Flags", OSD.FromInteger(item.Flags) }, + { "GroupID", OSD.FromUUID(item.GroupID) }, + { "GroupOwned", OSD.FromBoolean(item.GroupOwned) }, + { "SalePrice", OSD.FromInteger(item.SalePrice) }, + { "SaleType", OSD.FromInteger(item.SaleType) }, + { "Permissions", permissions } + }; + + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "AddInventoryItem" }, + { "ItemID", item.ID.ToString() }, + { "AssetID", item.AssetID.ToString() }, + { "ParentID", item.Folder.ToString() }, + { "OwnerID", item.Owner.ToString() }, + { "Name", item.Name }, + { "Description", item.Description }, + { "CreatorID", item.CreatorId }, + { "ExtraData", OSDParser.SerializeJsonString(extraData) } + }; + + OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + bool success = response["Success"].AsBoolean(); + + if (!success) + { + m_log.Warn("[INVENTORY CONNECTOR]: Error creating item " + item.Name + " for " + item.Owner + ": " + + response["Message"].AsString()); + } + + return success; + } + + /// + /// Update an item in the user's inventory + /// + /// + /// true if the item was successfully updated + public bool UpdateItem(InventoryItemBase item) + { + if (item.AssetID != UUID.Zero) + { + return AddItem(item); + } + else + { + // This is actually a folder update + InventoryFolderBase folder = new InventoryFolderBase(item.ID, item.Name, item.Owner, (short)item.AssetType, item.Folder, 0); + return UpdateFolder(folder); + } + } + + public bool MoveItems(UUID ownerID, List items) + { + bool success = true; + + while (items.Count > 0) + { + List currentItems = new List(); + UUID destFolderID = items[0].Folder; + + // Find all of the items being moved to the current destination folder + for (int i = 0; i < items.Count; i++) + { + InventoryItemBase item = items[i]; + if (item.Folder == destFolderID) + currentItems.Add(item); + } + + // Do the inventory move for the current items + success &= MoveItems(ownerID, items, destFolderID); + + // Remove the processed items from the list + for (int i = 0; i < currentItems.Count; i++) + items.Remove(currentItems[i]); + } + + return success; + } + + /// + /// Does the given user have an inventory structure? + /// + /// + /// + public bool HasInventoryForUser(UUID userID) + { + return GetRootFolder(userID) != null; + } + + /// + /// Get the active gestures of the agent. + /// + /// + /// + public List GetActiveGestures(UUID userID) + { + OSDArray items = FetchGestures(userID); + + string[] itemIDs = new string[items.Count]; + for (int i = 0; i < items.Count; i++) + itemIDs[i] = items[i].AsUUID().ToString(); + + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "GetInventoryNodes" }, + { "OwnerID", userID.ToString() }, + { "Items", String.Join(",", itemIDs) } + }; + + // FIXME: Implement this in SimianGrid + return new List(0); + } + + /// + /// Get the union of permissions of all inventory items + /// that hold the given assetID. + /// + /// + /// + /// The permissions or 0 if no such asset is found in + /// the user's inventory + public int GetAssetPermissions(UUID userID, UUID assetID) + { + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "GetInventoryNodes" }, + { "OwnerID", userID.ToString() }, + { "AssetID", assetID.ToString() } + }; + + // FIXME: Implement this in SimianGrid + return (int)PermissionMask.All; + } + + private List GetFoldersFromResponse(OSDArray items, UUID baseFolder, bool includeBaseFolder) + { + List invFolders = new List(items.Count); + + for (int i = 0; i < items.Count; i++) + { + OSDMap item = items[i] as OSDMap; + + if (item != null && item["Type"].AsString() == "Folder") + { + UUID folderID = item["ID"].AsUUID(); + + if (folderID == baseFolder && !includeBaseFolder) + continue; + + invFolders.Add(new InventoryFolderBase( + folderID, + item["Name"].AsString(), + item["OwnerID"].AsUUID(), + (short)SLUtil.ContentTypeToSLAssetType(item["ContentType"].AsString()), + item["ParentID"].AsUUID(), + (ushort)item["Version"].AsInteger() + )); + } + } + + return invFolders; + } + + private List GetItemsFromResponse(OSDArray items) + { + List invItems = new List(items.Count); + + for (int i = 0; i < items.Count; i++) + { + OSDMap item = items[i] as OSDMap; + + if (item != null && item["Type"].AsString() == "Item") + { + InventoryItemBase invItem = new InventoryItemBase(); + + invItem.AssetID = item["AssetID"].AsUUID(); + invItem.AssetType = SLUtil.ContentTypeToSLAssetType(item["ContentType"].AsString()); + invItem.CreationDate = item["CreationDate"].AsInteger(); + invItem.CreatorId = item["CreatorID"].AsString(); + invItem.CreatorIdAsUuid = item["CreatorID"].AsUUID(); + invItem.Description = item["Description"].AsString(); + invItem.Folder = item["ParentID"].AsUUID(); + invItem.ID = item["ID"].AsUUID(); + invItem.InvType = SLUtil.ContentTypeToSLInvType(item["ContentType"].AsString()); + invItem.Name = item["Name"].AsString(); + invItem.Owner = item["OwnerID"].AsUUID(); + + OSDMap extraData = item["ExtraData"] as OSDMap; + if (extraData != null && extraData.Count > 0) + { + invItem.Flags = extraData["Flags"].AsUInteger(); + invItem.GroupID = extraData["GroupID"].AsUUID(); + invItem.GroupOwned = extraData["GroupOwned"].AsBoolean(); + invItem.SalePrice = extraData["SalePrice"].AsInteger(); + invItem.SaleType = (byte)extraData["SaleType"].AsInteger(); + + OSDMap perms = extraData["Permissions"] as OSDMap; + if (perms != null) + { + invItem.BasePermissions = perms["BaseMask"].AsUInteger(); + invItem.CurrentPermissions = perms["OwnerMask"].AsUInteger(); + invItem.EveryOnePermissions = perms["EveryoneMask"].AsUInteger(); + invItem.GroupPermissions = perms["GroupMask"].AsUInteger(); + invItem.NextPermissions = perms["NextOwnerMask"].AsUInteger(); + } + } + + if (invItem.BasePermissions == 0) + { + m_log.InfoFormat("[INVENTORY CONNECTOR]: Forcing item permissions to full for item {0} ({1})", + invItem.Name, invItem.ID); + invItem.BasePermissions = (uint)PermissionMask.All; + invItem.CurrentPermissions = (uint)PermissionMask.All; + invItem.EveryOnePermissions = (uint)PermissionMask.All; + invItem.GroupPermissions = (uint)PermissionMask.All; + invItem.NextPermissions = (uint)PermissionMask.All; + } + + invItems.Add(invItem); + } + } + + return invItems; + } + + private bool MoveItems(UUID ownerID, List items, UUID destFolderID) + { + string[] itemIDs = new string[items.Count]; + for (int i = 0; i < items.Count; i++) + itemIDs[i] = items[i].ID.ToString(); + + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "MoveInventoryNodes" }, + { "OwnerID", ownerID.ToString() }, + { "FolderID", destFolderID.ToString() }, + { "Items", String.Join(",", itemIDs) } + }; + + OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + bool success = response["Success"].AsBoolean(); + + if (!success) + { + m_log.Warn("[INVENTORY CONNECTOR]: Failed to move " + items.Count + " items to " + + destFolderID + ": " + response["Message"].AsString()); + } + + return success; + } + + private void UpdateGesture(UUID userID, UUID itemID, bool enabled) + { + OSDArray gestures = FetchGestures(userID); + OSDArray newGestures = new OSDArray(); + + for (int i = 0; i < gestures.Count; i++) + { + UUID gesture = gestures[i].AsUUID(); + if (gesture != itemID) + newGestures.Add(OSD.FromUUID(gesture)); + } + + if (enabled) + newGestures.Add(OSD.FromUUID(itemID)); + + SaveGestures(userID, newGestures); + } + + private OSDArray FetchGestures(UUID userID) + { + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "GetUser" }, + { "UserID", userID.ToString() } + }; + + OSDMap response = WebUtil.PostToService(m_userServerUrl, requestArgs); + if (response["Success"].AsBoolean()) + { + OSDMap user = response["User"] as OSDMap; + if (user != null && response.ContainsKey("Gestures")) + { + OSD gestures = OSDParser.DeserializeJson(response["Gestures"].AsString()); + if (gestures != null && gestures is OSDArray) + return (OSDArray)gestures; + else + m_log.Error("[INVENTORY CONNECTOR]: Unrecognized active gestures data for " + userID); + } + } + else + { + m_log.Warn("[INVENTORY CONNECTOR]: Failed to fetch active gestures for " + userID + ": " + + response["Message"].AsString()); + } + + return new OSDArray(); + } + + private void SaveGestures(UUID userID, OSDArray gestures) + { + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "AddUserData" }, + { "UserID", userID.ToString() }, + { "Gestures", OSDParser.SerializeJsonString(gestures) } + }; + + OSDMap response = WebUtil.PostToService(m_userServerUrl, requestArgs); + if (!response["Success"].AsBoolean()) + { + m_log.Warn("[INVENTORY CONNECTOR]: Failed to save active gestures for " + userID + ": " + + response["Message"].AsString()); + } + } + } +} diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs new file mode 100644 index 0000000000..65de1c513c --- /dev/null +++ b/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs @@ -0,0 +1,502 @@ +/* + * 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 OpenSimulator 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.Collections.Specialized; +using System.Net; +using System.Reflection; +using log4net; +using Mono.Addins; +using Nini.Config; +using OpenSim.Framework; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Services.Interfaces; +using OpenSim.Server.Base; +using OpenMetaverse; +using OpenMetaverse.StructuredData; + +using PresenceInfo = OpenSim.Services.Interfaces.PresenceInfo; + +namespace OpenSim.Services.Connectors.SimianGrid +{ + /// + /// Connects avatar presence information (for tracking current location and + /// message routing) to the SimianGrid backend + /// + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] + public class SimianPresenceServiceConnector : IPresenceService, ISharedRegionModule + { + private static readonly ILog m_log = + LogManager.GetLogger( + MethodBase.GetCurrentMethod().DeclaringType); + + private string m_serverUrl = String.Empty; + + #region ISharedRegionModule + + public Type ReplaceableInterface { get { return null; } } + public void RegionLoaded(Scene scene) { } + public void PostInitialise() { } + public void Close() { } + + public SimianPresenceServiceConnector() { } + public string Name { get { return "SimianPresenceServiceConnector"; } } + public void AddRegion(Scene scene) + { + scene.RegisterModuleInterface(this); + + scene.EventManager.OnMakeRootAgent += MakeRootAgentHandler; + scene.EventManager.OnNewClient += NewClientHandler; + scene.EventManager.OnSignificantClientMovement += SignificantClientMovementHandler; + + LogoutRegionAgents(scene.RegionInfo.RegionID); + } + public void RemoveRegion(Scene scene) + { + scene.UnregisterModuleInterface(this); + + scene.EventManager.OnMakeRootAgent -= MakeRootAgentHandler; + scene.EventManager.OnNewClient -= NewClientHandler; + scene.EventManager.OnSignificantClientMovement -= SignificantClientMovementHandler; + + LogoutRegionAgents(scene.RegionInfo.RegionID); + } + + #endregion ISharedRegionModule + + public SimianPresenceServiceConnector(IConfigSource source) + { + Initialise(source); + } + + public void Initialise(IConfigSource source) + { + IConfig gridConfig = source.Configs["PresenceService"]; + if (gridConfig == null) + { + m_log.Error("[PRESENCE CONNECTOR]: PresenceService missing from OpenSim.ini"); + throw new Exception("Presence connector init error"); + } + + string serviceUrl = gridConfig.GetString("PresenceServerURI"); + if (String.IsNullOrEmpty(serviceUrl)) + { + m_log.Error("[PRESENCE CONNECTOR]: No PresenceServerURI in section PresenceService"); + throw new Exception("Presence connector init error"); + } + + m_serverUrl = serviceUrl; + } + + #region IPresenceService + + public bool LoginAgent(string userID, UUID sessionID, UUID secureSessionID) + { + m_log.ErrorFormat("[PRESENCE CONNECTOR]: Login requested, UserID={0}, SessionID={1}, SecureSessionID={2}", + userID, sessionID, secureSessionID); + + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "AddSession" }, + { "UserID", userID.ToString() } + }; + if (sessionID != UUID.Zero) + { + requestArgs["SessionID"] = sessionID.ToString(); + requestArgs["SecureSessionID"] = secureSessionID.ToString(); + } + + OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + bool success = response["Success"].AsBoolean(); + + if (!success) + m_log.Warn("[PRESENCE CONNECTOR]: Failed to login agent " + userID + ": " + response["Message"].AsString()); + + return success; + } + + public bool LogoutAgent(UUID sessionID, Vector3 position, Vector3 lookAt) + { + m_log.InfoFormat("[PRESENCE CONNECTOR]: Logout requested for agent with sessionID " + sessionID); + + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "RemoveSession" }, + { "SessionID", sessionID.ToString() } + }; + + OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + bool success = response["Success"].AsBoolean(); + + if (!success) + m_log.Warn("[PRESENCE CONNECTOR]: Failed to logout agent with sessionID " + sessionID + ": " + response["Message"].AsString()); + + return success; + } + + public bool LogoutRegionAgents(UUID regionID) + { + m_log.InfoFormat("[PRESENCE CONNECTOR]: Logout requested for all agents in region " + regionID); + + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "RemoveSessions" }, + { "SceneID", regionID.ToString() } + }; + + OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + bool success = response["Success"].AsBoolean(); + + if (!success) + m_log.Warn("[PRESENCE CONNECTOR]: Failed to logout agents from region " + regionID + ": " + response["Message"].AsString()); + + return success; + } + + public bool ReportAgent(UUID sessionID, UUID regionID, Vector3 position, Vector3 lookAt) + { + //m_log.DebugFormat("[PRESENCE CONNECTOR]: Updating session data for agent with sessionID " + sessionID); + + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "UpdateSession" }, + { "SessionID", sessionID.ToString() }, + { "SceneID", regionID.ToString() }, + { "ScenePosition", position.ToString() }, + { "SceneLookAt", lookAt.ToString() } + }; + + OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + bool success = response["Success"].AsBoolean(); + + if (!success) + m_log.Warn("[PRESENCE CONNECTOR]: Failed to update agent session " + sessionID + ": " + response["Message"].AsString()); + + return success; + } + + public PresenceInfo GetAgent(UUID sessionID) + { + m_log.DebugFormat("[PRESENCE CONNECTOR]: Requesting session data for agent with sessionID " + sessionID); + + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "GetSession" }, + { "SessionID", sessionID.ToString() } + }; + + OSDMap sessionResponse = WebUtil.PostToService(m_serverUrl, requestArgs); + if (sessionResponse["Success"].AsBoolean()) + { + UUID userID = sessionResponse["UserID"].AsUUID(); + m_log.DebugFormat("[PRESENCE CONNECTOR]: Requesting user data for " + userID); + + requestArgs = new NameValueCollection + { + { "RequestMethod", "GetUser" }, + { "UserID", userID.ToString() } + }; + + OSDMap userResponse = WebUtil.PostToService(m_serverUrl, requestArgs); + if (userResponse["Success"].AsBoolean()) + return ResponseToPresenceInfo(sessionResponse, userResponse); + else + m_log.Warn("[PRESENCE CONNECTOR]: Failed to retrieve user data for " + userID + ": " + userResponse["Message"].AsString()); + } + else + { + m_log.Warn("[PRESENCE CONNECTOR]: Failed to retrieve session " + sessionID + ": " + sessionResponse["Message"].AsString()); + } + + return null; + } + + public PresenceInfo[] GetAgents(string[] userIDs) + { + List presences = new List(userIDs.Length); + + for (int i = 0; i < userIDs.Length; i++) + { + UUID userID; + if (UUID.TryParse(userIDs[i], out userID) && userID != UUID.Zero) + presences.AddRange(GetSessions(userID)); + } + + return presences.ToArray(); + } + + public bool SetHomeLocation(string userID, UUID regionID, Vector3 position, Vector3 lookAt) + { + m_log.DebugFormat("[PRESENCE CONNECTOR]: Setting home location for user " + userID); + + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "AddUserData" }, + { "UserID", userID.ToString() }, + { "HomeLocation", SerializeLocation(regionID, position, lookAt) } + }; + + OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + bool success = response["Success"].AsBoolean(); + + if (!success) + m_log.Warn("[PRESENCE CONNECTOR]: Failed to set home location for " + userID + ": " + response["Message"].AsString()); + + return success; + } + + #endregion IPresenceService + + #region Presence Detection + + private void MakeRootAgentHandler(ScenePresence sp) + { + m_log.DebugFormat("[PRESENCE DETECTOR]: Detected root presence {0} in {1}", sp.UUID, sp.Scene.RegionInfo.RegionName); + + ReportAgent(sp.ControllingClient.SessionId, sp.Scene.RegionInfo.RegionID, sp.AbsolutePosition, sp.Lookat); + SetLastLocation(sp.UUID, sp.Scene.RegionInfo.RegionID, sp.AbsolutePosition, sp.Lookat); + } + + private void NewClientHandler(IClientAPI client) + { + client.OnConnectionClosed += LogoutHandler; + } + + private void SignificantClientMovementHandler(IClientAPI client) + { + ScenePresence sp; + if (client.Scene is Scene && ((Scene)client.Scene).TryGetAvatar(client.AgentId, out sp)) + ReportAgent(sp.ControllingClient.SessionId, sp.Scene.RegionInfo.RegionID, sp.AbsolutePosition, sp.Lookat); + } + + private void LogoutHandler(IClientAPI client) + { + if (client.IsLoggingOut) + { + client.OnConnectionClosed -= LogoutHandler; + + object obj; + if (client.Scene.TryGetAvatar(client.AgentId, out obj) && obj is ScenePresence) + { + // The avatar is still in the scene, we can get the exact logout position + ScenePresence sp = (ScenePresence)obj; + SetLastLocation(client.AgentId, client.Scene.RegionInfo.RegionID, sp.AbsolutePosition, sp.Lookat); + } + else + { + // The avatar was already removed from the scene, store LastLocation using the most recent session data + m_log.Warn("[PRESENCE]: " + client.Name + " has already been removed from the scene, storing approximate LastLocation"); + SetLastLocation(client.SessionId); + } + + LogoutAgent(client.SessionId, Vector3.Zero, Vector3.UnitX); + } + } + + #endregion Presence Detection + + #region Helpers + + private OSDMap GetUserData(UUID userID) + { + m_log.DebugFormat("[PRESENCE CONNECTOR]: Requesting user data for " + userID); + + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "GetUser" }, + { "UserID", userID.ToString() } + }; + + OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + if (response["Success"].AsBoolean() && response["User"] is OSDMap) + return response; + else + m_log.Warn("[PRESENCE CONNECTOR]: Failed to retrieve user data for " + userID + ": " + response["Message"].AsString()); + + return null; + } + + private OSDMap GetSessionData(UUID sessionID) + { + m_log.DebugFormat("[PRESENCE CONNECTOR]: Requesting session data for session " + sessionID); + + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "GetSession" }, + { "SessionID", sessionID.ToString() } + }; + + OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + if (response["Success"].AsBoolean()) + return response; + else + m_log.Warn("[PRESENCE CONNECTOR]: Failed to retrieve session data for session " + sessionID); + + return null; + } + + private List GetSessions(UUID userID) + { + List presences = new List(1); + + OSDMap userResponse = GetUserData(userID); + if (userResponse != null) + { + m_log.DebugFormat("[PRESENCE CONNECTOR]: Requesting sessions for " + userID); + + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "GetSession" }, + { "UserID", userID.ToString() } + }; + + OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + if (response["Success"].AsBoolean()) + { + PresenceInfo presence = ResponseToPresenceInfo(response, userResponse); + if (presence != null) + presences.Add(presence); + } + else + { + m_log.Warn("[PRESENCE CONNECTOR]: Failed to retrieve sessions for " + userID + ": " + response["Message"].AsString()); + } + } + + return presences; + } + + /// + /// Fetch the last known avatar location with GetSession and persist it + /// as user data with AddUserData + /// + private bool SetLastLocation(UUID sessionID) + { + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "GetSession" }, + { "SessionID", sessionID.ToString() } + }; + + OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + bool success = response["Success"].AsBoolean(); + + if (success) + { + UUID userID = response["UserID"].AsUUID(); + UUID sceneID = response["SceneID"].AsUUID(); + Vector3 position = response["ScenePosition"].AsVector3(); + Vector3 lookAt = response["SceneLookAt"].AsVector3(); + + return SetLastLocation(userID, sceneID, position, lookAt); + } + else + { + m_log.Warn("[PRESENCE CONNECTOR]: Failed to retrieve presence information for session " + sessionID + + " while saving last location: " + response["Message"].AsString()); + } + + return success; + } + + private bool SetLastLocation(UUID userID, UUID sceneID, Vector3 position, Vector3 lookAt) + { + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "AddUserData" }, + { "UserID", userID.ToString() }, + { "LastLocation", SerializeLocation(sceneID, position, lookAt) } + }; + + OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + bool success = response["Success"].AsBoolean(); + + if (!success) + m_log.Warn("[PRESENCE CONNECTOR]: Failed to set last location for " + userID + ": " + response["Message"].AsString()); + + return success; + } + + private PresenceInfo ResponseToPresenceInfo(OSDMap sessionResponse, OSDMap userResponse) + { + if (sessionResponse == null) + return null; + + PresenceInfo info = new PresenceInfo(); + + info.Online = true; + info.UserID = sessionResponse["UserID"].AsUUID().ToString(); + info.RegionID = sessionResponse["SceneID"].AsUUID(); + info.Position = sessionResponse["ScenePosition"].AsVector3(); + info.LookAt = sessionResponse["SceneLookAt"].AsVector3(); + + if (userResponse != null && userResponse["User"] is OSDMap) + { + OSDMap user = (OSDMap)userResponse["User"]; + + info.Login = user["LastLoginDate"].AsDate(); + info.Logout = user["LastLogoutDate"].AsDate(); + DeserializeLocation(user["HomeLocation"].AsString(), out info.HomeRegionID, out info.HomePosition, out info.HomeLookAt); + } + + return info; + } + + private string SerializeLocation(UUID regionID, Vector3 position, Vector3 lookAt) + { + return "{" + String.Format("\"SceneID\":\"{0}\",\"Position\":\"{1}\",\"LookAt\":\"{2}\"", regionID, position, lookAt) + "}"; + } + + private bool DeserializeLocation(string location, out UUID regionID, out Vector3 position, out Vector3 lookAt) + { + OSDMap map = null; + + try { map = OSDParser.DeserializeJson(location) as OSDMap; } + catch { } + + if (map != null) + { + regionID = map["SceneID"].AsUUID(); + if (Vector3.TryParse(map["Position"].AsString(), out position) && + Vector3.TryParse(map["LookAt"].AsString(), out lookAt)) + { + return true; + } + } + + regionID = UUID.Zero; + position = Vector3.Zero; + lookAt = Vector3.Zero; + return false; + } + + #endregion Helpers + } +} diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs b/OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs new file mode 100644 index 0000000000..1e19982da2 --- /dev/null +++ b/OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs @@ -0,0 +1,432 @@ +/* + * 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 OpenSimulator 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.Collections.Specialized; +using System.Reflection; +using log4net; +using Mono.Addins; +using Nini.Config; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using OpenSim.Framework; +using OpenSim.Framework.Client; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Services.Interfaces; + +namespace OpenSim.Services.Connectors.SimianGrid +{ + /// + /// Avatar profile flags + /// + [Flags] + public enum ProfileFlags : uint + { + AllowPublish = 1, + MaturePublish = 2, + Identified = 4, + Transacted = 8, + Online = 16 + } + + /// + /// Connects avatar profile and classified queries to the SimianGrid + /// backend + /// + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] + public class SimianProfiles : INonSharedRegionModule + { + private static readonly ILog m_log = + LogManager.GetLogger( + MethodBase.GetCurrentMethod().DeclaringType); + + private string m_serverUrl = String.Empty; + + #region INonSharedRegionModule + + public Type ReplaceableInterface { get { return null; } } + public void RegionLoaded(Scene scene) { } + public void Close() { } + + public SimianProfiles() { } + public string Name { get { return "SimianProfiles"; } } + public void AddRegion(Scene scene) { CheckEstateManager(scene); scene.EventManager.OnClientConnect += ClientConnectHandler; } + public void RemoveRegion(Scene scene) { scene.EventManager.OnClientConnect -= ClientConnectHandler; } + + #endregion INonSharedRegionModule + + public SimianProfiles(IConfigSource source) + { + Initialise(source); + } + + public void Initialise(IConfigSource source) + { + IConfig gridConfig = source.Configs["UserAccountService"]; + if (gridConfig == null) + { + m_log.Error("[PROFILES]: UserAccountService missing from OpenSim.ini"); + throw new Exception("Profiles init error"); + } + + string serviceUrl = gridConfig.GetString("UserAccountServerURI"); + if (String.IsNullOrEmpty(serviceUrl)) + { + m_log.Error("[PROFILES]: No UserAccountServerURI in section UserAccountService"); + throw new Exception("Profiles init error"); + } + + if (!serviceUrl.EndsWith("/")) + serviceUrl = serviceUrl + '/'; + + m_serverUrl = serviceUrl; + } + + private void ClientConnectHandler(IClientCore clientCore) + { + if (clientCore is IClientAPI) + { + IClientAPI client = (IClientAPI)clientCore; + + // Classifieds + client.AddGenericPacketHandler("avatarclassifiedsrequest", AvatarClassifiedsRequestHandler); + client.OnClassifiedInfoRequest += ClassifiedInfoRequestHandler; + client.OnClassifiedInfoUpdate += ClassifiedInfoUpdateHandler; + client.OnClassifiedDelete += ClassifiedDeleteHandler; + + // Picks + client.AddGenericPacketHandler("avatarpicksrequest", HandleAvatarPicksRequest); + client.AddGenericPacketHandler("pickinforequest", HandlePickInfoRequest); + client.OnPickInfoUpdate += PickInfoUpdateHandler; + client.OnPickDelete += PickDeleteHandler; + + // Notes + client.AddGenericPacketHandler("avatarnotesrequest", HandleAvatarNotesRequest); + client.OnAvatarNotesUpdate += AvatarNotesUpdateHandler; + + // Profiles + client.OnRequestAvatarProperties += RequestAvatarPropertiesHandler; + client.OnUpdateAvatarProperties += UpdateAvatarPropertiesHandler; + client.OnAvatarInterestUpdate += AvatarInterestUpdateHandler; + client.OnUserInfoRequest += UserInfoRequestHandler; + client.OnUpdateUserInfo += UpdateUserInfoHandler; + } + } + + #region Classifieds + + private void AvatarClassifiedsRequestHandler(Object sender, string method, List args) + { + if (!(sender is IClientAPI)) + return; + IClientAPI client = (IClientAPI)sender; + + UUID targetAvatarID; + if (args.Count < 1 || !UUID.TryParse(args[0], out targetAvatarID)) + { + m_log.Error("[PROFILES]: Unrecognized arguments for " + method); + return; + } + + // FIXME: Query the generic key/value store for classifieds + client.SendAvatarClassifiedReply(targetAvatarID, new Dictionary(0)); + } + + private void ClassifiedInfoRequestHandler(UUID classifiedID, IClientAPI client) + { + // FIXME: Fetch this info + client.SendClassifiedInfoReply(classifiedID, UUID.Zero, 0, Utils.DateTimeToUnixTime(DateTime.UtcNow + TimeSpan.FromDays(1)), + 0, String.Empty, String.Empty, UUID.Zero, 0, UUID.Zero, String.Empty, Vector3.Zero, String.Empty, 0, 0); + } + + private void ClassifiedInfoUpdateHandler(UUID classifiedID, uint category, string name, string description, + UUID parcelID, uint parentEstate, UUID snapshotID, Vector3 globalPos, byte classifiedFlags, int price, + IClientAPI client) + { + // FIXME: Save this info + } + + private void ClassifiedDeleteHandler(UUID classifiedID, IClientAPI client) + { + // FIXME: Delete the specified classified ad + } + + #endregion Classifieds + + #region Picks + + private void HandleAvatarPicksRequest(Object sender, string method, List args) + { + if (!(sender is IClientAPI)) + return; + IClientAPI client = (IClientAPI)sender; + + UUID targetAvatarID; + if (args.Count < 1 || !UUID.TryParse(args[0], out targetAvatarID)) + { + m_log.Error("[PROFILES]: Unrecognized arguments for " + method); + return; + } + + // FIXME: Fetch these + client.SendAvatarPicksReply(targetAvatarID, new Dictionary(0)); + } + + private void HandlePickInfoRequest(Object sender, string method, List args) + { + if (!(sender is IClientAPI)) + return; + IClientAPI client = (IClientAPI)sender; + + UUID avatarID; + UUID pickID; + if (args.Count < 2 || !UUID.TryParse(args[0], out avatarID) || !UUID.TryParse(args[1], out pickID)) + { + m_log.Error("[PROFILES]: Unrecognized arguments for " + method); + return; + } + + // FIXME: Fetch this + client.SendPickInfoReply(pickID, avatarID, false, UUID.Zero, String.Empty, String.Empty, UUID.Zero, String.Empty, + String.Empty, String.Empty, Vector3.Zero, 0, false); + } + + private void PickInfoUpdateHandler(IClientAPI client, UUID pickID, UUID creatorID, bool topPick, string name, + string desc, UUID snapshotID, int sortOrder, bool enabled) + { + // FIXME: Save this + } + + private void PickDeleteHandler(IClientAPI client, UUID pickID) + { + // FIXME: Delete + } + + #endregion Picks + + #region Notes + + private void HandleAvatarNotesRequest(Object sender, string method, List args) + { + if (!(sender is IClientAPI)) + return; + IClientAPI client = (IClientAPI)sender; + + UUID targetAvatarID; + if (args.Count < 1 || !UUID.TryParse(args[0], out targetAvatarID)) + { + m_log.Error("[PROFILES]: Unrecognized arguments for " + method); + return; + } + + // FIXME: Fetch this + client.SendAvatarNotesReply(targetAvatarID, String.Empty); + } + + private void AvatarNotesUpdateHandler(IClientAPI client, UUID targetID, string notes) + { + // FIXME: Save this + } + + #endregion Notes + + #region Profiles + + private void RequestAvatarPropertiesHandler(IClientAPI client, UUID avatarID) + { + OSDMap user = FetchUserData(avatarID); + + ProfileFlags flags = ProfileFlags.AllowPublish | ProfileFlags.MaturePublish; + + if (user != null) + { + OSDMap about = null; + if (user.ContainsKey("LLAbout")) + { + try { about = OSDParser.DeserializeJson(user["LLAbout"].AsString()) as OSDMap; } + catch { } + } + + if (about == null) + about = new OSDMap(0); + + // Check if this user is a grid operator + byte[] charterMember; + if (user["AccessLevel"].AsInteger() >= 200) + charterMember = Utils.StringToBytes("Operator"); + else + charterMember = Utils.EmptyBytes; + + // Check if the user is online + if (client.Scene is Scene) + { + OpenSim.Services.Interfaces.PresenceInfo[] presences = ((Scene)client.Scene).PresenceService.GetAgents(new string[] { avatarID.ToString() }); + if (presences != null && presences.Length > 0) + flags |= ProfileFlags.Online; + } + + // Check if the user is identified + if (user["Identified"].AsBoolean()) + flags |= ProfileFlags.Identified; + + client.SendAvatarProperties(avatarID, about["About"].AsString(), user["CreationDate"].AsDate().ToString("M/d/yyyy", + System.Globalization.CultureInfo.InvariantCulture), charterMember, about["FLAbout"].AsString(), (uint)flags, + about["FLImage"].AsUUID(), about["Image"].AsUUID(), about["URL"].AsString(), user["Partner"].AsUUID()); + + } + else + { + m_log.Warn("[PROFILES]: Failed to fetch profile information for " + client.Name + ", returning default values"); + client.SendAvatarProperties(avatarID, String.Empty, "1/1/1970", Utils.EmptyBytes, + String.Empty, (uint)flags, UUID.Zero, UUID.Zero, String.Empty, UUID.Zero); + } + } + + private void UpdateAvatarPropertiesHandler(IClientAPI client, UserProfileData profileData) + { + OSDMap map = new OSDMap + { + { "About", OSD.FromString(profileData.AboutText) }, + { "Image", OSD.FromUUID(profileData.Image) }, + { "FLAbout", OSD.FromString(profileData.FirstLifeAboutText) }, + { "FLImage", OSD.FromUUID(profileData.FirstLifeImage) }, + { "URL", OSD.FromString(profileData.ProfileUrl) } + }; + + AddUserData(client.AgentId, "LLAbout", map); + } + + private void AvatarInterestUpdateHandler(IClientAPI client, uint wantmask, string wanttext, uint skillsmask, + string skillstext, string languages) + { + OSDMap map = new OSDMap + { + { "WantMask", OSD.FromInteger(wantmask) }, + { "WantText", OSD.FromString(wanttext) }, + { "SkillsMask", OSD.FromInteger(skillsmask) }, + { "SkillsText", OSD.FromString(skillstext) }, + { "Languages", OSD.FromString(languages) } + }; + + AddUserData(client.AgentId, "LLInterests", map); + } + + private void UserInfoRequestHandler(IClientAPI client) + { + m_log.Error("[PROFILES]: UserInfoRequestHandler"); + + // Fetch this user's e-mail address + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "GetUser" }, + { "UserID", client.AgentId.ToString() } + }; + + OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + string email = response["Email"].AsString(); + + if (!response["Success"].AsBoolean()) + m_log.Warn("[PROFILES]: GetUser failed during a user info request for " + client.Name); + + client.SendUserInfoReply(false, true, email); + } + + private void UpdateUserInfoHandler(bool imViaEmail, bool visible, IClientAPI client) + { + m_log.Info("[PROFILES]: Ignoring user info update from " + client.Name); + } + + #endregion Profiles + + /// + /// Sanity checks regions for a valid estate owner at startup + /// + private void CheckEstateManager(Scene scene) + { + EstateSettings estate = scene.RegionInfo.EstateSettings; + + if (estate.EstateOwner == UUID.Zero) + { + // Attempt to lookup the grid admin + UserAccount admin = scene.UserAccountService.GetUserAccount(scene.RegionInfo.ScopeID, UUID.Zero); + if (admin != null) + { + m_log.InfoFormat("[PROFILES]: Setting estate {0} (ID: {1}) owner to {2}", estate.EstateName, + estate.EstateID, admin.Name); + + estate.EstateOwner = admin.PrincipalID; + estate.Save(); + } + else + { + m_log.WarnFormat("[PROFILES]: Estate {0} (ID: {1}) does not have an owner", estate.EstateName, estate.EstateID); + } + } + } + + private bool AddUserData(UUID userID, string key, OSDMap value) + { + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "AddUserData" }, + { "UserID", userID.ToString() }, + { key, OSDParser.SerializeJsonString(value) } + }; + + OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + bool success = response["Success"].AsBoolean(); + + if (!success) + m_log.WarnFormat("[PROFILES]: Failed to add user data with key {0} for {1}: {2}", key, userID, response["Message"].AsString()); + + return success; + } + + private OSDMap FetchUserData(UUID userID) + { + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "GetUser" }, + { "UserID", userID.ToString() } + }; + + OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + if (response["Success"].AsBoolean() && response["User"] is OSDMap) + { + return (OSDMap)response["User"]; + } + else + { + m_log.Error("[PROFILES]: Failed to fetch user data for " + userID + ": " + response["Message"].AsString()); + } + + return null; + } + } +} diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianUserAccountServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianUserAccountServiceConnector.cs new file mode 100644 index 0000000000..14097d0bdc --- /dev/null +++ b/OpenSim/Services/Connectors/SimianGrid/SimianUserAccountServiceConnector.cs @@ -0,0 +1,307 @@ +/* + * 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 OpenSimulator 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.Collections.Specialized; +using System.IO; +using System.Reflection; +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Services.Interfaces; +using log4net; +using Mono.Addins; +using Nini.Config; +using OpenMetaverse; +using OpenMetaverse.StructuredData; + +namespace OpenSim.Services.Connectors.SimianGrid +{ + /// + /// Connects user account data (creating new users, looking up existing + /// users) to the SimianGrid backend + /// + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] + public class SimianUserAccountServiceConnector : IUserAccountService, ISharedRegionModule + { + private static readonly ILog m_log = + LogManager.GetLogger( + MethodBase.GetCurrentMethod().DeclaringType); + + private string m_serverUrl = String.Empty; + private ExpiringCache m_accountCache = new ExpiringCache(); + + #region ISharedRegionModule + + public Type ReplaceableInterface { get { return null; } } + public void RegionLoaded(Scene scene) { } + public void PostInitialise() { } + public void Close() { } + + public SimianUserAccountServiceConnector() { } + public string Name { get { return "SimianUserAccountServiceConnector"; } } + public void AddRegion(Scene scene) { scene.RegisterModuleInterface(this); } + public void RemoveRegion(Scene scene) { scene.UnregisterModuleInterface(this); } + + #endregion ISharedRegionModule + + public SimianUserAccountServiceConnector(IConfigSource source) + { + Initialise(source); + } + + public void Initialise(IConfigSource source) + { + IConfig assetConfig = source.Configs["UserAccountService"]; + if (assetConfig == null) + { + m_log.Error("[ACCOUNT CONNECTOR]: UserAccountService missing from OpenSim.ini"); + throw new Exception("User account connector init error"); + } + + string serviceURI = assetConfig.GetString("UserAccountServerURI"); + if (String.IsNullOrEmpty(serviceURI)) + { + m_log.Error("[ACCOUNT CONNECTOR]: No UserAccountServerURI in section UserAccountService"); + throw new Exception("User account connector init error"); + } + + m_serverUrl = serviceURI; + } + + public UserAccount GetUserAccount(UUID scopeID, string firstName, string lastName) + { + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "GetUser" }, + { "Name", firstName + ' ' + lastName } + }; + + return GetUser(requestArgs); + } + + public UserAccount GetUserAccount(UUID scopeID, string email) + { + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "GetUser" }, + { "Email", email } + }; + + return GetUser(requestArgs); + } + + public UserAccount GetUserAccount(UUID scopeID, UUID userID) + { + // Cache check + UserAccount account; + if (m_accountCache.TryGetValue(userID, out account)) + return account; + + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "GetUser" }, + { "UserID", userID.ToString() } + }; + + return GetUser(requestArgs); + } + + public List GetUserAccounts(UUID scopeID, string query) + { + List accounts = new List(); + + m_log.DebugFormat("[ACCOUNT CONNECTOR]: Searching for user accounts with name query " + query); + + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "GetUsers" }, + { "NameQuery", query } + }; + + OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + if (response["Success"].AsBoolean()) + { + OSDArray array = response["Users"] as OSDArray; + if (array != null && array.Count > 0) + { + for (int i = 0; i < array.Count; i++) + { + UserAccount account = ResponseToUserAccount(array[i] as OSDMap); + if (account != null) + accounts.Add(account); + } + } + else + { + m_log.Warn("[ACCOUNT CONNECTOR]: Account search failed, response data was in an invalid format"); + } + } + else + { + m_log.Warn("[ACCOUNT CONNECTOR]: Failed to search for account data by name " + query); + } + + return accounts; + } + + public bool StoreUserAccount(UserAccount data) + { + m_log.InfoFormat("[ACCOUNT CONNECTOR]: Storing user account for " + data.Name); + + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "AddUser" }, + { "UserID", data.PrincipalID.ToString() }, + { "Name", data.Name }, + { "Email", data.Email }, + { "AccessLevel", data.UserLevel.ToString() } + }; + + OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + + if (response["Success"].AsBoolean()) + { + m_log.InfoFormat("[ACCOUNT CONNECTOR]: Storing user account data for " + data.Name); + + requestArgs = new NameValueCollection + { + { "RequestMethod", "AddUserData" }, + { "UserID", data.PrincipalID.ToString() }, + { "CreationDate", data.Created.ToString() }, + { "UserFlags", data.UserFlags.ToString() }, + { "UserTitle", data.UserTitle } + }; + + response = WebUtil.PostToService(m_serverUrl, requestArgs); + bool success = response["Success"].AsBoolean(); + + if (success) + { + // Cache the user account info + m_accountCache.AddOrUpdate(data.PrincipalID, data, DateTime.Now + TimeSpan.FromMinutes(2.0d)); + } + else + { + m_log.Warn("[ACCOUNT CONNECTOR]: Failed to store user account data for " + data.Name + ": " + response["Message"].AsString()); + } + + return success; + } + else + { + m_log.Warn("[ACCOUNT CONNECTOR]: Failed to store user account for " + data.Name + ": " + response["Message"].AsString()); + } + + return false; + } + + /// + /// Helper method for the various ways of retrieving a user account + /// + /// Service query parameters + /// A UserAccount object on success, null on failure + private UserAccount GetUser(NameValueCollection requestArgs) + { + string lookupValue = (requestArgs.Count > 1) ? requestArgs[1] : "(Unknown)"; + m_log.DebugFormat("[ACCOUNT CONNECTOR]: Looking up user account with query: " + lookupValue); + + OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + if (response["Success"].AsBoolean()) + { + OSDMap user = response["User"] as OSDMap; + if (user != null) + return ResponseToUserAccount(user); + else + m_log.Warn("[ACCOUNT CONNECTOR]: Account search failed, response data was in an invalid format"); + } + else + { + m_log.Warn("[ACCOUNT CONNECTOR]: Failed to lookup user account with query: " + lookupValue); + } + + return null; + } + + /// + /// Convert a User object in LLSD format to a UserAccount + /// + /// LLSD containing user account data + /// A UserAccount object on success, null on failure + private UserAccount ResponseToUserAccount(OSDMap response) + { + if (response == null) + return null; + + UserAccount account = new UserAccount(); + account.PrincipalID = response["UserID"].AsUUID(); + account.Created = response["CreationDate"].AsInteger(); + account.Email = response["Email"].AsString(); + account.ServiceURLs = new Dictionary(0); + account.UserFlags = response["UserFlags"].AsInteger(); + account.UserLevel = response["AccessLevel"].AsInteger(); + account.UserTitle = response["UserTitle"].AsString(); + GetFirstLastName(response["Name"].AsString(), out account.FirstName, out account.LastName); + + // Cache the user account info + m_accountCache.AddOrUpdate(account.PrincipalID, account, DateTime.Now + TimeSpan.FromMinutes(2.0d)); + + return account; + } + + /// + /// Convert a name with a single space in it to a first and last name + /// + /// A full name such as "John Doe" + /// First name + /// Last name (surname) + private static void GetFirstLastName(string name, out string firstName, out string lastName) + { + if (String.IsNullOrEmpty(name)) + { + firstName = String.Empty; + lastName = String.Empty; + } + else + { + string[] names = name.Split(' '); + + if (names.Length == 2) + { + firstName = names[0]; + lastName = names[1]; + } + else + { + firstName = String.Empty; + lastName = name; + } + } + } + } +} diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index 74100f59bd..23c324115a 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example @@ -1248,6 +1248,7 @@ ;Include-HGStandalone = "config-include/StandaloneHypergrid.ini" ;Include-Grid = "config-include/Grid.ini" ;Include-HGGrid = "config-include/GridHypergrid.ini" + ;Include-SimianGrid = "config-include/SimianGrid.ini" ; Then choose ; config-include/StandaloneCommon.ini.example (if you're in standlone) OR diff --git a/bin/config-include/SimianGrid.ini b/bin/config-include/SimianGrid.ini new file mode 100644 index 0000000000..af3386039b --- /dev/null +++ b/bin/config-include/SimianGrid.ini @@ -0,0 +1,70 @@ +[Modules] + GridServices = "OpenSim.Services.Connectors.dll:SimianGridServiceConnector" + PresenceServices = "OpenSim.Services.Connectors.dll:SimianPresenceServiceConnector" + UserAccountServices = "OpenSim.Services.Connectors.dll:SimianGridUserAccountServiceConnector" + AuthenticationServices = "OpenSim.Services.Connectors.dll:SimianAuthenticationServiceConnector" + AssetServices = "OpenSim.Services.Connectors.dll:SimianAssetServiceConnector" + InventoryServices = "OpenSim.Services.Connectors.dll:SimianInventoryServiceConnector" + AvatarServices = "OpenSim.Services.Connectors.dll:SimianAvatarServiceConnector" + + NeighbourServices = "RemoteNeighbourServicesConnector" + SimulationServices = "RemoteSimulationConnectorModule" + EntityTransferModule = "BasicEntityTransferModule" + InventoryAccessModule = "BasicInventoryAccessModule" + + LandServiceInConnector = true + NeighbourServiceInConnector = true + SimulationServiceInConnector = true + LibraryModule = false + + AssetCaching = "FlotsamAssetCache" + +[Friends] + Connector = "OpenSim.Services.Connectors.dll:SimianFriendsServiceConnector" + +[GridService] + LocalServiceModule = "OpenSim.Services.GridService.dll:GridService" + StorageProvider = "OpenSim.Data.Null.dll:NullRegionData" + GridServerURI = "http://localhost/Grid/" + +[LibraryService] + LocalServiceModule = "OpenSim.Services.InventoryService.dll:LibraryService" + LibraryName = "OpenSim Library" + DefaultLibrary = "./inventory/Libraries.xml" + +[AssetService] + DefaultAssetLoader = "OpenSim.Framework.AssetLoader.Filesystem.dll" + AssetLoaderArgs = "assets/AssetSets.xml" + AssetServerURI = "http://localhost/Grid/?id=" + +[InventoryService] + InventoryServerURI = "http://localhost/Grid/" + +[AvatarService] + AvatarServerURI = "http://localhost/Grid/" + +[PresenceService] + PresenceServerURI = "http://localhost/Grid/" + +[UserAccountService] + UserAccountServerURI = "http://localhost/Grid/" + +[AuthenticationService] + AuthenticationServerURI = "http://localhost/Grid/" + +[FriendsService] + FriendsServerURI = "http://localhost/Grid/" + +[AssetCache] + CacheDirectory = ./assetcache + LogLevel = 0 + HitRateDisplay = 100 + MemoryCacheEnabled = false + ; How long {in hours} to keep assets cached in memory, .5 == 30 minutes + MemoryCacheTimeout = 2 + ; How long {in hours} to keep assets cached on disk, .5 == 30 minutes + ; Specify 0 if you do not want your disk cache to expire + FileCacheTimeout = 0 + ; How often {in hours} should the disk be checked for expired filed + ; Specify 0 to disable expiration checking + FileCleanupTimer = 0 ;roughly every 10 minutes diff --git a/prebuild.xml b/prebuild.xml index cf0eecca55..5cc742c45a 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -929,7 +929,9 @@ + + From a578feefba7d740180b8c891fc9e257dbb4ab48d Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Thu, 11 Mar 2010 20:20:38 +0000 Subject: [PATCH 09/28] very minor spacing adjustment --- OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs index d13408de86..5ee2045bde 100644 --- a/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs +++ b/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs @@ -73,7 +73,6 @@ namespace OpenSim.Framework.Servers.HttpServer /// true if the handler was successfully registered, false if a handler with the same name already existed. /// bool AddHTTPHandler(string methodName, GenericHTTPMethod handler); - bool AddPollServiceHTTPHandler(string methodName, GenericHTTPMethod handler, PollServiceEventArgs args); From e844524b4130bae62d0ede3ae4fa123b96848aac Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Thu, 11 Mar 2010 21:04:56 +0000 Subject: [PATCH 10/28] Upgrade Newtonsoft.Json.dll from 1.3 to 3.5r6 Actually using the one built against Net 2.0 (labelled Newtonsoft.Json.Net20.dll) since the 3.5 build is not compatible with Mono 2.4 (though it is with Mono 2.6) --- CONTRIBUTORS.txt | 1 + bin/Newtonsoft.Json.XML | 6817 +++++++++++++++++++++++++++++++++------ bin/Newtonsoft.Json.dll | Bin 73728 -> 356352 bytes bin/Newtonsoft.Json.pdb | Bin 192000 -> 742912 bytes 4 files changed, 5828 insertions(+), 990 deletions(-) diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index 5b4959afbb..e5c8cb97e8 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -164,6 +164,7 @@ This software uses components from the following developers: * log4net (http://logging.apache.org/log4net/) * GlynnTucker.Cache (http://gtcache.sourceforge.net/) * NDesk.Options 0.2.1 (http://www.ndesk.org/Options) +* Json.NET 3.5 Release 6. The binary used is actually Newtonsoft.Json.Net20.dll for Mono 2.4 compatability (http://james.newtonking.com/projects/json-net.aspx) Some plugins are based on Cable Beach Cable Beach is Copyright (c) 2008 Intel Corporation diff --git a/bin/Newtonsoft.Json.XML b/bin/Newtonsoft.Json.XML index b84e336fd6..5af3593d22 100644 --- a/bin/Newtonsoft.Json.XML +++ b/bin/Newtonsoft.Json.XML @@ -1,990 +1,5827 @@ - - - - Newtonsoft.Json - - - - - Determines whether the string contains white space. - - The string to test for white space. - - true if the string contains white space; otherwise, false. - - - - - Determines whether the string is all white space. Empty string will return false. - - The string to test whether it is all white space. - - true if the string is all white space; otherwise, false. - - - - - Ensures the target string ends with the specified string. - - The target. - The value. - The target string with the value string at the end. - - - - Determines whether the SqlString is null or empty. - - The string. - - true if the SqlString is null or empty; otherwise, false. - - - - - Perform an action if the string is not null or empty. - - The value. - The action to perform. - - - - Indents the specified string. - - The string to indent. - The number of characters to indent by. - - - - - Indents the specified string. - - The string to indent. - The number of characters to indent by. - The indent character. - - - - - Numbers the lines. - - The string to number. - - - - - Nulls an empty string. - - The string. - Null if the string was null, otherwise the string unchanged. - - - - The exception thrown when an error occurs while reading Json text. - - - - - Initializes a new instance of the class. - - - - - Initializes a new instance of the class - with a specified error message. - - The error message that explains the reason for the exception. - - - - Initializes a new instance of the class - with a specified error message and a reference to the inner exception that is the cause of this exception. - - The error message that explains the reason for the exception. - The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified. - - - - Gets the type of the typed list's items. - - The type. - The type of the typed list's items. - - - - Tests whether the list's items are their unitialized value. - - The list. - Whether the list's items are their unitialized value - - - - Gets the member's underlying type. - - The member. - The underlying type of the member. - - - - Determines whether the member is an indexed property. - - The member. - - true if the member is an indexed property; otherwise, false. - - - - - Determines whether the property is an indexed property. - - The property. - - true if the property is an indexed property; otherwise, false. - - - - - Gets the member's value on the object. - - The member. - The target object. - The member's value on the object. - - - - Sets the member's value on the target object. - - The member. - The target. - The value. - - - - Determines whether the specified MemberInfo can be read. - - The MemberInfo to determine whether can be read. - - true if the specified MemberInfo can be read; otherwise, false. - - - - - Determines whether the specified MemberInfo can be set. - - The MemberInfo to determine whether can be set. - - true if the specified MemberInfo can be set; otherwise, false. - - - - - Specifies reference loop handling options for the . - - - - - Throw a when a loop is encountered. - - - - - Ignore loop references and do not serialize. - - - - - Serialize loop references. - - - - - Serializes and deserializes objects into and from the Json format. - The enables you to control how objects are encoded into Json. - - - - - Initializes a new instance of the class. - - - - - Deserializes the Json structure contained by the specified . - - The that contains the Json structure to deserialize. - The being deserialized. - - - - Deserializes the Json structure contained by the specified - into an instance of the specified type. - - The type of object to create. - The of object being deserialized. - The instance of being deserialized. - - - - Serializes the specified and writes the Json structure - to a Stream using the specified . - - The used to write the Json structure. - The to serialize. - - - - Serializes the specified and writes the Json structure - to a Stream using the specified . - - The used to write the Json structure. - The to serialize. - - - - Get or set how reference loops (e.g. a class referencing itself) is handled. - - - - - Represents a JavaScript array. - - - - - Initializes a new instance of the class. - - - - - Initializes a new instance of the class that - contains elements copied from the specified collection. - - The collection whose elements are copied to the new array. - - - - Initializes a new instance of the class that - is empty and has the specified initial capacity. - - The number of elements that the new array can initially store. - - - - Provides methods for converting between common language runtime types and JavaScript types. - - - - - Represents JavaScript's boolean value true as a string. This field is read-only. - - - - - Represents JavaScript's boolean value false as a string. This field is read-only. - - - - - Represents JavaScript's null as a string. This field is read-only. - - - - - Represents JavaScript's undefined as a string. This field is read-only. - - - - - Converts the to it's JavaScript string representation. - - The value to convert. - A Json string representation of the . - - - - Converts the to it's JavaScript string representation. - - The value to convert. - A Json string representation of the . - - - - Converts the to it's JavaScript string representation. - - The value to convert. - A Json string representation of the . - - - - Converts the to it's JavaScript string representation. - - The value to convert. - A Json string representation of the . - - - - Converts the to it's JavaScript string representation. - - The value to convert. - A Json string representation of the . - - - - Converts the to it's JavaScript string representation. - - The value to convert. - A Json string representation of the . - - - - Converts the to it's JavaScript string representation. - - The value to convert. - A Json string representation of the . - - - - Converts the to it's JavaScript string representation. - - The value to convert. - A Json string representation of the . - - - - Converts the to it's JavaScript string representation. - - The value to convert. - A Json string representation of the . - - - - Converts the to it's JavaScript string representation. - - The value to convert. - A Json string representation of the . - - - - Converts the to it's JavaScript string representation. - - The value to convert. - A Json string representation of the . - - - - Converts the to it's JavaScript string representation. - - The value to convert. - A Json string representation of the . - - - - Converts the to it's JavaScript string representation. - - The value to convert. - A Json string representation of the . - - - - Converts the to it's JavaScript string representation. - - The value to convert. - A Json string representation of the . - - - - Converts the to it's JavaScript string representation. - - The value to convert. - A Json string representation of the . - - - - Converts the to it's JavaScript string representation. - - The value to convert. - A Json string representation of the . - - - - Converts the to it's JavaScript string representation. - - The value to convert. - A Json string representation of the . - - - - Converts the to it's JavaScript string representation. - - The value to convert. - The string delimiter character. - A Json string representation of the . - - - - Converts the to it's JavaScript string representation. - - The value to convert. - A Json string representation of the . - - - - Serializes the specified object to a Json object. - - The object to serialize. - A Json string representation of the object. - - - - Deserializes the specified object to a Json object. - - The object to deserialize. - The deserialized object from the Json string. - - - - Deserializes the specified object to a Json object. - - The object to deserialize. - The of object being deserialized. - The deserialized object from the Json string. - - - - Deserializes the specified object to a Json object. - - The type of the object to deserialize. - The object to deserialize. - The deserialized object from the Json string. - - - - Deserializes the specified object to a Json object. - - The type of the object to deserialize. - The object to deserialize. - Converters to use while deserializing. - The deserialized object from the Json string. - - - - The exception thrown when an error occurs during Json serialization or deserialization. - - - - - Initializes a new instance of the class. - - - - - Initializes a new instance of the class - with a specified error message. - - The error message that explains the reason for the exception. - - - - Initializes a new instance of the class - with a specified error message and a reference to the inner exception that is the cause of this exception. - - The error message that explains the reason for the exception. - The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified. - - - - The exception thrown when an error occurs while reading Json text. - - - - - Initializes a new instance of the class. - - - - - Initializes a new instance of the class - with a specified error message. - - The error message that explains the reason for the exception. - - - - Initializes a new instance of the class - with a specified error message and a reference to the inner exception that is the cause of this exception. - - The error message that explains the reason for the exception. - The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified. - - - - Represents a JavaScript constructor. - - - - - Determines whether the collection is null or empty. - - The collection. - - true if the collection is null or empty; otherwise, false. - - - - - Determines whether the collection is null or empty. - - The collection. - - true if the collection is null or empty; otherwise, false. - - - - - Determines whether the collection is null, empty or its contents are uninitialized values. - - The list. - - true if the collection is null or empty or its contents are uninitialized values; otherwise, false. - - - - - Makes a slice of the specified list in between the start and end indexes. - - The list. - The start index. - The end index. - A slice of the list. - - - - Makes a slice of the specified list in between the start and end indexes, - getting every so many items based upon the step. - - The list. - The start index. - The end index. - The step. - A slice of the list. - - - - Group the collection using a function which returns the key. - - The source collection to group. - The key selector. - A Dictionary with each key relating to a list of objects in a list grouped under it. - - - - Adds the elements of the specified collection to the specified generic IList. - - The list to add to. - The collection of elements to add. - - - - Builds a string. Unlike StringBuilder this class lets you reuse it's internal buffer. - - - - - Represents a JavaScript object. - - - - - Initializes a new instance of the class. - - - - - Initializes a new instance of the class that - contains values copied from the specified . - - The whose elements are copied to the new object. - - - - Specifies the type of Json token. - - - - - This is returned by the if a method has not been called. - - - - - An object start token. - - - - - An array start token. - - - - - An object property name. - - - - - A comment. - - - - - An interger. - - - - - A float. - - - - - A string. - - - - - A boolean. - - - - - A null token. - - - - - An undefined token. - - - - - An object end token. - - - - - An array end token. - - - - - A JavaScript object constructor. - - - - - A Date. - - - - - Checks if the attributeName is a namespace attribute. - - Attribute name to test. - The attribute name prefix if it has one, otherwise an empty string. - True if attribute name is for a namespace attribute, otherwise false. - - - - Specifies the state of the . - - - - - An exception has been thrown, which has left the in an invalid state. - You may call the method to put the in the Closed state. - Any other method calls results in an being thrown. - - - - - The method has been called. - - - - - An object is being written. - - - - - A array is being written. - - - - - A property is being written. - - - - - A write method has not been called. - - - - - Specifies formatting options for the . - - - - - No special formatting is applied. This is the default. - - - - - Causes child objects to be indented according to the and settings. - - - - - Represents a writer that provides a fast, non-cached, forward-only way of generating Json data. - - - - - Creates an instance of the JsonWriter class using the specified . - - The TextWriter to write to. - - - - Flushes whatever is in the buffer to the underlying streams and also flushes the underlying stream. - - - - - Closes this stream and the underlying stream. - - - - - Writes the beginning of a Json object. - - - - - Writes the end of a Json object. - - - - - Writes the beginning of a Json array. - - - - - Writes the end of an array. - - - - - Writes the property name of a name/value pair on a Json object. - - - - - - Writes the end of the current Json object or array. - - - - - Writes a null value. - - - - - Writes an undefined value. - - - - - Writes raw JavaScript manually. - - The raw JavaScript to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes out a comment /*...*/ containing the specified text. - - Text to place inside the comment. - - - - Writes out the given white space. - - The string of white space characters. - - - - Gets the state of the writer. - - - - - Indicates how the output is formatted. - - - - - Gets or sets how many IndentChars to write for each level in the hierarchy when is set to Formatting.Indented. - - - - - Gets or sets which character to use to quote attribute values. - - - - - Gets or sets which character to use for indenting when is set to Formatting.Indented. - - - - - Gets or sets a value indicating whether object names will be surrounded with quotes. - - - - - Represents a reader that provides fast, non-cached, forward-only access to serialized Json data. - - - - - Initializes a new instance of the class with the specified . - - The TextReader containing the XML data to read. - - - - Reads the next Json token from the stream. - - - - - - Changes the to Closed. - - - - - Gets the quotation mark character used to enclose the value of a string. - - - - - Gets the type of the current Json token. - - - - - Gets the text value of the current Json token. - - - - - Gets The Common Language Runtime (CLR) type for the current Json token. - - - - + + + + Newtonsoft.Json.Net20 + + + + + Represents a reader that provides fast, non-cached, forward-only access to serialized Json data. + + + + + Represents a reader that provides fast, non-cached, forward-only access to serialized Json data. + + + + + Initializes a new instance of the class with the specified . + + + + + Reads the next JSON token from the stream. + + true if the next token was read successfully; false if there are no more tokens to read. + + + + Reads the next JSON token from the stream as a . + + A or a null reference if the next JSON token is null. + + + + Skips the children of the current token. + + + + + Sets the current token. + + The new token. + + + + Sets the current token and value. + + The new token. + The value. + + + + Sets the state based on current token type. + + + + + Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + + + + + Releases unmanaged and - optionally - managed resources + + true to release both managed and unmanaged resources; false to release only unmanaged resources. + + + + Changes the to Closed. + + + + + Gets the current reader state. + + The current reader state. + + + + Gets the quotation mark character used to enclose the value of a string. + + + + + Gets the type of the current Json token. + + + + + Gets the text value of the current Json token. + + + + + Gets The Common Language Runtime (CLR) type for the current Json token. + + + + + Gets the depth of the current token in the JSON document. + + The depth of the current token in the JSON document. + + + + Specifies the state of the reader. + + + + + The Read method has not been called. + + + + + The end of the file has been reached successfully. + + + + + Reader is at a property. + + + + + Reader is at the start of an object. + + + + + Reader is in an object. + + + + + Reader is at the start of an array. + + + + + Reader is in an array. + + + + + The Close method has been called. + + + + + Reader has just read a value. + + + + + Reader is at the start of a constructor. + + + + + Reader in a constructor. + + + + + An error occurred that prevents the read operation from continuing. + + + + + The end of the file has been reached successfully. + + + + + Initializes a new instance of the class. + + The stream. + + + + Initializes a new instance of the class. + + The stream. + if set to true the root object will be read as a JSON array. + The used when reading values from BSON. + + + + Reads the next JSON token from the stream as a . + + + A or a null reference if the next JSON token is null. + + + + + Reads the next JSON token from the stream. + + + true if the next token was read successfully; false if there are no more tokens to read. + + + + + Gets or sets a value indicating whether the root object will be read as a JSON array. + + + true if the root object will be read as a JSON array; otherwise, false. + + + + + Gets or sets the used when reading values from BSON. + + The used when reading values from BSON. + + + + Represents a writer that provides a fast, non-cached, forward-only way of generating Json data. + + + + + Represents a writer that provides a fast, non-cached, forward-only way of generating Json data. + + + + + Represents a writer that provides a fast, non-cached, forward-only way of generating Json data. + + + + + Creates an instance of the JsonWriter class. + + + + + Flushes whatever is in the buffer to the underlying streams and also flushes the underlying stream. + + + + + Closes this stream and the underlying stream. + + + + + Writes the beginning of a Json object. + + + + + Writes the end of a Json object. + + + + + Writes the beginning of a Json array. + + + + + Writes the end of an array. + + + + + Writes the start of a constructor with the given name. + + The name of the constructor. + + + + Writes the end constructor. + + + + + Writes the property name of a name/value pair on a Json object. + + The name of the property. + + + + Writes the end of the current Json object or array. + + + + + Writes the current token. + + The to read the token from. + + + + Writes the specified end token. + + The end token to write. + + + + Writes indent characters. + + + + + Writes the JSON value delimiter. + + + + + Writes an indent space. + + + + + Writes a null value. + + + + + Writes an undefined value. + + + + + Writes raw JSON without changing the writer's state. + + The raw JSON to write. + + + + Writes raw JSON where a value is expected and updates the writer's state. + + The raw JSON to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + An error will raised if the value cannot be written as a single JSON token. + + The value to write. + + + + Writes out a comment /*...*/ containing the specified text. + + Text to place inside the comment. + + + + Writes out the given white space. + + The string of white space characters. + + + + Gets the top. + + The top. + + + + Gets the state of the writer. + + + + + Indicates how the output is formatted. + + + + + Initializes a new instance of the class writing to the given . + + The container being written to. + + + + Initializes a new instance of the class. + + + + + Flushes whatever is in the buffer to the underlying streams and also flushes the underlying stream. + + + + + Closes this stream and the underlying stream. + + + + + Writes the beginning of a Json object. + + + + + Writes the beginning of a Json array. + + + + + Writes the start of a constructor with the given name. + + The name of the constructor. + + + + Writes the end. + + The token. + + + + Writes the property name of a name/value pair on a Json object. + + The name of the property. + + + + Writes a null value. + + + + + Writes an undefined value. + + + + + Writes raw JSON. + + The raw JSON to write. + + + + Writes out a comment /*...*/ containing the specified text. + + Text to place inside the comment. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Gets the token being writen. + + The token being writen. + + + + Initializes a new instance of the class. + + The stream. + + + + Flushes whatever is in the buffer to the underlying streams and also flushes the underlying stream. + + + + + Writes the end. + + The token. + + + + Writes out a comment /*...*/ containing the specified text. + + Text to place inside the comment. + + + + Writes the start of a constructor with the given name. + + The name of the constructor. + + + + Writes raw JSON. + + The raw JSON to write. + + + + Writes raw JSON where a value is expected and updates the writer's state. + + The raw JSON to write. + + + + Specifies how constructors are used when initializing objects during deserialization by the . + + + + + First attempt to use the public default constructor then fall back to single paramatized constructor. + + + + + Allow Json.NET to use a non-public default constructor. + + + + + Converts a binary value to and from a base 64 string value. + + + + + Converts an object to and from JSON. + + + + + Writes the JSON representation of the object. + + The to write to. + The value. + The calling serializer. + + + + Reads the JSON representation of the object. + + The to read from. + Type of the object. + The calling serializer. + The object value. + + + + Determines whether this instance can convert the specified object type. + + Type of the object. + + true if this instance can convert the specified object type; otherwise, false. + + + + + Writes the JSON representation of the object. + + The to write to. + The value. + The calling serializer. + + + + Reads the JSON representation of the object. + + The to read from. + Type of the object. + The calling serializer. + The object value. + + + + Determines whether this instance can convert the specified object type. + + Type of the object. + + true if this instance can convert the specified object type; otherwise, false. + + + + + Create a custom object + + + + + + Writes the JSON representation of the object. + + The to write to. + The value. + The calling serializer. + + + + Reads the JSON representation of the object. + + The to read from. + Type of the object. + The calling serializer. + The object value. + + + + Creates an object which will then be populated by the serializer. + + Type of the object. + + + + + Determines whether this instance can convert the specified object type. + + Type of the object. + + true if this instance can convert the specified object type; otherwise, false. + + + + + Converts a to and from JSON. + + + + + Writes the JSON representation of the object. + + The to write to. + The value. + The calling serializer. + + + + Reads the JSON representation of the object. + + The to read from. + Type of the object. + The calling serializer. + The object value. + + + + Determines whether this instance can convert the specified value type. + + Type of the value. + + true if this instance can convert the specified value type; otherwise, false. + + + + + Converts a to and from JSON. + + + + + Writes the JSON representation of the object. + + The to write to. + The value. + The calling serializer. + + + + Reads the JSON representation of the object. + + The to read from. + Type of the object. + The calling serializer. + The object value. + + + + Determines whether this instance can convert the specified value type. + + Type of the value. + + true if this instance can convert the specified value type; otherwise, false. + + + + + Provides a base class for converting a to and from JSON. + + + + + Determines whether this instance can convert the specified object type. + + Type of the object. + + true if this instance can convert the specified object type; otherwise, false. + + + + + Converts an to and from its name string value. + + + + + Writes the JSON representation of the object. + + The to write to. + The value. + The calling serializer. + + + + Reads the JSON representation of the object. + + The to read from. + Type of the object. + The calling serializer. + The object value. + + + + Determines whether this instance can convert the specified object type. + + Type of the object. + + true if this instance can convert the specified object type; otherwise, false. + + + + + Represents a view of a . + + + + + Initializes a new instance of the class. + + The name. + Type of the property. + + + + When overridden in a derived class, returns whether resetting an object changes its value. + + + true if resetting the component changes its value; otherwise, false. + + The component to test for reset capability. + + + + + When overridden in a derived class, gets the current value of the property on a component. + + + The value of a property for a given component. + + The component with the property for which to retrieve the value. + + + + + When overridden in a derived class, resets the value for this property of the component to the default value. + + The component with the property value that is to be reset to the default value. + + + + + When overridden in a derived class, sets the value of the component to a different value. + + The component with the property value that is to be set. + The new value. + + + + + When overridden in a derived class, determines a value indicating whether the value of this property needs to be persisted. + + + true if the property should be persisted; otherwise, false. + + The component with the property to be examined for persistence. + + + + + When overridden in a derived class, gets the type of the component this property is bound to. + + + A that represents the type of component this property is bound to. When the or methods are invoked, the object specified might be an instance of this type. + + + + + When overridden in a derived class, gets a value indicating whether this property is read-only. + + + true if the property is read-only; otherwise, false. + + + + + When overridden in a derived class, gets the type of the property. + + + A that represents the type of the property. + + + + + Gets the hash code for the name of the member. + + + + The hash code for the name of the member. + + + + + Represents a view of a . + + + + + Initializes a new instance of the class. + + The value. + + + + Returns the properties for this instance of a component. + + + A that represents the properties for this component instance. + + + + + Returns the properties for this instance of a component using the attribute array as a filter. + + An array of type that is used as a filter. + + A that represents the filtered properties for this component instance. + + + + + Returns a collection of custom attributes for this instance of a component. + + + An containing the attributes for this object. + + + + + Returns the class name of this instance of a component. + + + The class name of the object, or null if the class does not have a name. + + + + + Returns the name of this instance of a component. + + + The name of the object, or null if the object does not have a name. + + + + + Returns a type converter for this instance of a component. + + + A that is the converter for this object, or null if there is no for this object. + + + + + Returns the default event for this instance of a component. + + + An that represents the default event for this object, or null if this object does not have events. + + + + + Returns the default property for this instance of a component. + + + A that represents the default property for this object, or null if this object does not have properties. + + + + + Returns an editor of the specified type for this instance of a component. + + A that represents the editor for this object. + + An of the specified type that is the editor for this object, or null if the editor cannot be found. + + + + + Returns the events for this instance of a component using the specified attribute array as a filter. + + An array of type that is used as a filter. + + An that represents the filtered events for this component instance. + + + + + Returns the events for this instance of a component. + + + An that represents the events for this component instance. + + + + + Returns an object that contains the property described by the specified property descriptor. + + A that represents the property whose owner is to be found. + + An that represents the owner of the specified property. + + + + + Represents a raw JSON string. + + + + + Represents a value in JSON (string, integer, date, etc). + + + + + Represents an abstract JSON token. + + + + + Represents a collection of objects. + + The type of token + + + + Gets the with the specified key. + + + + + + Provides an interface to enable a class to return line and position information. + + + + + Gets a value indicating whether the class can return line information. + + + true if LineNumber and LinePosition can be provided; otherwise, false. + + + + + Gets the current line number. + + The current line number or 0 if no line information is available (for example, HasLineInfo returns false). + + + + Gets the current line position. + + The current line position or 0 if no line information is available (for example, HasLineInfo returns false). + + + + Compares the values of two tokens, including the values of all descendant tokens. + + The first to compare. + The second to compare. + true if the tokens are equal; otherwise false. + + + + Adds the specified content immediately after this token. + + A content object that contains simple content or a collection of content objects to be added after this token. + + + + Adds the specified content immediately before this token. + + A content object that contains simple content or a collection of content objects to be added before this token. + + + + Returns a collection of the ancestor tokens of this token. + + A collection of the ancestor tokens of this token. + + + + Returns a collection of the sibling tokens after this token, in document order. + + A collection of the sibling tokens after this tokens, in document order. + + + + Returns a collection of the sibling tokens before this token, in document order. + + A collection of the sibling tokens before this token, in document order. + + + + Gets the with the specified key converted to the specified type. + + The type to convert the token to. + The token key. + The converted token value. + + + + Returns a collection of the child tokens of this token, in document order. + + An of containing the child tokens of this , in document order. + + + + Returns a collection of the child tokens of this token, in document order, filtered by the specified type. + + The type to filter the child tokens on. + A containing the child tokens of this , in document order. + + + + Returns a collection of the child values of this token, in document order. + + The type to convert the values to. + A containing the child values of this , in document order. + + + + Removes this token from its parent. + + + + + Replaces this token with the specified token. + + The value. + + + + Writes this token to a . + + A into which this method will write. + A collection of which will be used when writing the token. + + + + Returns the indented JSON for this token. + + + The indented JSON for this token. + + + + + Returns the JSON for this token using the given formatting and converters. + + Indicates how the output is formatted. + A collection of which will be used when writing the token. + The JSON for this token using the given formatting and converters. + + + + Performs an explicit conversion from to . + + The value. + The result of the conversion. + + + + Performs an explicit conversion from to . + + The value. + The result of the conversion. + + + + Performs an explicit conversion from to . + + The value. + The result of the conversion. + + + + Performs an explicit conversion from to . + + The value. + The result of the conversion. + + + + Performs an explicit conversion from to . + + The value. + The result of the conversion. + + + + Performs an explicit conversion from to . + + The value. + The result of the conversion. + + + + Performs an explicit conversion from to . + + The value. + The result of the conversion. + + + + Performs an explicit conversion from to . + + The value. + The result of the conversion. + + + + Performs an explicit conversion from to . + + The value. + The result of the conversion. + + + + Performs an explicit conversion from to . + + The value. + The result of the conversion. + + + + Performs an explicit conversion from to . + + The value. + The result of the conversion. + + + + Performs an explicit conversion from to . + + The value. + The result of the conversion. + + + + Performs an explicit conversion from to . + + The value. + The result of the conversion. + + + + Performs an explicit conversion from to . + + The value. + The result of the conversion. + + + + Performs an explicit conversion from to . + + The value. + The result of the conversion. + + + + Performs an explicit conversion from to . + + The value. + The result of the conversion. + + + + Performs an explicit conversion from to . + + The value. + The result of the conversion. + + + + Performs an explicit conversion from to . + + The value. + The result of the conversion. + + + + Performs an explicit conversion from to . + + The value. + The result of the conversion. + + + + Performs an explicit conversion from to . + + The value. + The result of the conversion. + + + + Performs an implicit conversion from to . + + The value to create a from. + The initialized with the specified value. + + + + Performs an implicit conversion from to . + + The value to create a from. + The initialized with the specified value. + + + + Performs an implicit conversion from to . + + The value to create a from. + The initialized with the specified value. + + + + Performs an implicit conversion from to . + + The value to create a from. + The initialized with the specified value. + + + + Performs an implicit conversion from to . + + The value to create a from. + The initialized with the specified value. + + + + Performs an implicit conversion from to . + + The value to create a from. + The initialized with the specified value. + + + + Performs an implicit conversion from to . + + The value to create a from. + The initialized with the specified value. + + + + Performs an implicit conversion from to . + + The value to create a from. + The initialized with the specified value. + + + + Performs an implicit conversion from to . + + The value to create a from. + The initialized with the specified value. + + + + Performs an implicit conversion from to . + + The value to create a from. + The initialized with the specified value. + + + + Performs an implicit conversion from to . + + The value to create a from. + The initialized with the specified value. + + + + Performs an implicit conversion from to . + + The value to create a from. + The initialized with the specified value. + + + + Performs an implicit conversion from to . + + The value to create a from. + The initialized with the specified value. + + + + Performs an implicit conversion from to . + + The value to create a from. + The initialized with the specified value. + + + + Performs an implicit conversion from to . + + The value to create a from. + The initialized with the specified value. + + + + Performs an implicit conversion from to . + + The value to create a from. + The initialized with the specified value. + + + + Performs an implicit conversion from to . + + The value to create a from. + The initialized with the specified value. + + + + Performs an implicit conversion from to . + + The value to create a from. + The initialized with the specified value. + + + + Performs an implicit conversion from to . + + The value to create a from. + The initialized with the specified value. + + + + Performs an implicit conversion from to . + + The value to create a from. + The initialized with the specified value. + + + + Performs an implicit conversion from to . + + The value to create a from. + The initialized with the specified value. + + + + Performs an implicit conversion from to . + + The value to create a from. + The initialized with the specified value. + + + + Creates an for this token. + + An that can be used to read this token and its descendants. + + + + Creates a from an object. + + The object that will be used to create . + A with the value of the specified object + + + + Creates a from an object using the specified . + + The object that will be used to create . + The that will be used when reading the object. + A with the value of the specified object + + + + Creates a from a . + + An positioned at the token to read into this . + + An that contains the token and its descendant tokens + that were read from the reader. The runtime type of the token is determined + by the token type of the first token encountered in the reader. + + + + + Selects the token that matches the object path. + + + The object path from the current to the + to be returned. This must be a string of property names or array indexes separated + by periods, such as Tables[0].DefaultView[0].Price in C# or + Tables(0).DefaultView(0).Price in Visual Basic. + + The that matches the object path or a null reference if no matching token is found. + + + + Selects the token that matches the object path. + + + The object path from the current to the + to be returned. This must be a string of property names or array indexes separated + by periods, such as Tables[0].DefaultView[0].Price in C# or + Tables(0).DefaultView(0).Price in Visual Basic. + + A flag to indicate whether an error should be thrown if no token is found. + The that matches the object path. + + + + Gets a comparer that can compare two tokens for value equality. + + A that can compare two nodes for value equality. + + + + Gets or sets the parent. + + The parent. + + + + Gets the root of this . + + The root of this . + + + + Gets the node type for this . + + The type. + + + + Gets a value indicating whether this token has childen tokens. + + + true if this token has child values; otherwise, false. + + + + + Gets the next sibling token of this node. + + The that contains the next sibling token. + + + + Gets the previous sibling token of this node. + + The that contains the previous sibling token. + + + + Gets the with the specified key. + + The with the specified key. + + + + Get the first child token of this token. + + A containing the first child token of the . + + + + Get the last child token of this token. + + A containing the last child token of the . + + + + Initializes a new instance of the class from another object. + + A object to copy from. + + + + Initializes a new instance of the class with the given value. + + The value. + + + + Initializes a new instance of the class with the given value. + + The value. + + + + Initializes a new instance of the class with the given value. + + The value. + + + + Initializes a new instance of the class with the given value. + + The value. + + + + Initializes a new instance of the class with the given value. + + The value. + + + + Initializes a new instance of the class with the given value. + + The value. + + + + Initializes a new instance of the class with the given value. + + The value. + + + + Creates a comment with the given value. + + The value. + A comment with the given value. + + + + Creates a string with the given value. + + The value. + A string with the given value. + + + + Writes this token to a . + + A into which this method will write. + A collection of which will be used when writing the token. + + + + Indicates whether the current object is equal to another object of the same type. + + + true if the current object is equal to the parameter; otherwise, false. + + An object to compare with this object. + + + + Determines whether the specified is equal to the current . + + The to compare with the current . + + true if the specified is equal to the current ; otherwise, false. + + + The parameter is null. + + + + + Serves as a hash function for a particular type. + + + A hash code for the current . + + + + + Gets a value indicating whether this token has childen tokens. + + + true if this token has child values; otherwise, false. + + + + + Gets the node type for this . + + The type. + + + + Gets or sets the underlying token value. + + The underlying token value. + + + + Initializes a new instance of the class from another object. + + A object to copy from. + + + + Initializes a new instance of the class. + + The raw json. + + + + Creates an instance of with the content of the reader's current token. + + The reader. + An instance of with the content of the reader's current token. + + + + Indicating whether a property is required. + + + + + The property is not required. The default state. + + + + + The property must be defined in JSON but can be a null value. + + + + + The property must be defined in JSON and cannot be a null value. + + + + + Used to resolve references when serializing and deserializing JSON by the . + + + + + Resolves a reference to its object. + + The reference to resolve. + The object that + + + + Gets the reference for the sepecified object. + + The object to get a reference for. + The reference to the object. + + + + Determines whether the specified object is referenced. + + The object to test for a reference. + + true if the specified object is referenced; otherwise, false. + + + + + Adds a reference to the specified object. + + The reference. + The object to reference. + + + + Specifies reference handling options for the . + + + + + Do not preserve references when serializing types. + + + + + Preserve references when serializing into a JSON object structure. + + + + + Preserve references when serializing into a JSON array structure. + + + + + Preserve references when serializing. + + + + + Instructs the how to serialize the collection. + + + + + Instructs the how to serialize the object. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class with the specified container Id. + + The container Id. + + + + Gets or sets the id. + + The id. + + + + Gets or sets the title. + + The title. + + + + Gets or sets the description. + + The description. + + + + Gets or sets a value that indicates whether to preserve object reference data. + + + true to keep object reference; otherwise, false. The default is false. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class with a flag indicating whether the array can contain null items + + A flag indicating whether the array can contain null items. + + + + Initializes a new instance of the class with the specified container Id. + + The container Id. + + + + Gets or sets a value indicating whether null items are allowed in the collection. + + true if null items are allowed in the collection; otherwise, false. + + + + Specifies default value handling options for the . + + + + + Include null values when serializing and deserializing objects. + + + + + Ignore null values when serializing and deserializing objects. + + + + + Instructs the to use the specified when serializing the member or class. + + + + + Initializes a new instance of the class. + + Type of the converter. + + + + Gets the type of the converter. + + The type of the converter. + + + + Instructs the how to serialize the object. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class with the specified member serialization. + + The member serialization. + + + + Initializes a new instance of the class with the specified container Id. + + The container Id. + + + + Gets or sets the member serialization. + + The member serialization. + + + + Specifies the settings on a object. + + + + + Initializes a new instance of the class. + + + + + Gets or sets how reference loops (e.g. a class referencing itself) is handled. + + Reference loop handling. + + + + Gets or sets how missing members (e.g. JSON contains a property that isn't a member on the object) are handled during deserialization. + + Missing member handling. + + + + Gets or sets how objects are created during deserialization. + + The object creation handling. + + + + Gets or sets how null values are handled during serialization and deserialization. + + Null value handling. + + + + Gets or sets how null default are handled during serialization and deserialization. + + The default value handling. + + + + Gets or sets a collection that will be used during serialization. + + The converters. + + + + Gets or sets how object references are preserved by the serializer. + + The preserve references handling. + + + + Gets or sets how type name writing and reading is handled by the serializer. + + The type name handling. + + + + Gets or sets how constructors are used during deserialization. + + The constructor handling. + + + + Gets or sets the contract resolver used by the serializer when + serializing .NET objects to JSON and vice versa. + + The contract resolver. + + + + Gets or sets the used by the serializer when resolving references. + + The reference resolver. + + + + Gets or sets the used by the serializer when resolving type names. + + The binder. + + + + Gets or sets the error handler called during serialization and deserialization. + + The error handler called during serialization and deserialization. + + + + Gets or sets the used by the serializer when invoking serialization callback methods. + + The context. + + + + Represents a reader that provides validation. + + + + + Initializes a new instance of the class that + validates the content returned from the given . + + The to read from while validating. + + + + Reads the next JSON token from the stream as a . + + + A or a null reference if the next JSON token is null. + + + + + Reads the next JSON token from the stream. + + + true if the next token was read successfully; false if there are no more tokens to read. + + + + + Sets an event handler for receiving schema validation errors. + + + + + Gets the text value of the current Json token. + + + + + + Gets the depth of the current token in the JSON document. + + The depth of the current token in the JSON document. + + + + Gets the quotation mark character used to enclose the value of a string. + + + + + + Gets the type of the current Json token. + + + + + + Gets The Common Language Runtime (CLR) type for the current Json token. + + + + + + Gets or sets the schema. + + The schema. + + + + Gets the used to construct this . + + The specified in the constructor. + + + + Compares tokens to determine whether they are equal. + + + + + Determines whether the specified objects are equal. + + The first object of type to compare. + The second object of type to compare. + + true if the specified objects are equal; otherwise, false. + + + + + Returns a hash code for the specified object. + + The for which a hash code is to be returned. + A hash code for the specified object. + The type of is a reference type and is null. + + + + Specifies the member serialization options for the . + + + + + All members are serialized by default. Members can be excluded using the . + + + + + Only members must be marked with the are serialized. + + + + + Specifies how object creation is handled by the . + + + + + Reuse existing objects, create new objects when needed. + + + + + Only reuse existing objects. + + + + + Always create new objects. + + + + + Converts a to and from the ISO 8601 date format (e.g. 2008-04-12T12:53Z). + + + + + Writes the JSON representation of the object. + + The to write to. + The value. + The calling serializer. + + + + Reads the JSON representation of the object. + + The to read from. + Type of the object. + The calling serializer. + The object value. + + + + Gets or sets the date time styles used when converting a date to and from JSON. + + The date time styles used when converting a date to and from JSON. + + + + Gets or sets the date time format used when converting a date to and from JSON. + + The date time format used when converting a date to and from JSON. + + + + Gets or sets the culture used when converting a date to and from JSON. + + The culture used when converting a date to and from JSON. + + + + Converts a to and from a JavaScript date constructor (e.g. new Date(52231943)). + + + + + Writes the JSON representation of the object. + + The to write to. + The value. + The calling serializer. + + + + Reads the JSON representation of the object. + + The to read from. + Type of the object. + The calling serializer. + The object value. + + + + Specifies whether a DateTime object represents a local time, a Coordinated Universal Time (UTC), or is not specified as either local time or UTC. + + + + + The time represented is local time. + + + + + The time represented is UTC. + + + + + The time represented is not specified as either local time or Coordinated Universal Time (UTC). + + + + + Preserves the DateTimeKind field of a date when a DateTime object is converted to a string and the string is then converted back to a DateTime object. + + + + + Converts an to and from JSON. + + + + + Writes the JSON representation of the object. + + The to write to. + The calling serializer. + The value. + + + + Reads the JSON representation of the object. + + The to read from. + Type of the object. + The calling serializer. + The object value. + + + + Checks if the attributeName is a namespace attribute. + + Attribute name to test. + The attribute name prefix if it has one, otherwise an empty string. + True if attribute name is for a namespace attribute, otherwise false. + + + + Determines whether this instance can convert the specified value type. + + Type of the value. + + true if this instance can convert the specified value type; otherwise, false. + + + + + Gets or sets the name of the root element to insert when deserializing to XML if the JSON structure has produces multiple root elements. + + The name of the deserialize root element. + + + + Converts a object to and from JSON. + + + + + Writes the JSON representation of the object. + + The to write to. + The calling serializer. + The value. + + + + Determines whether this instance can convert the specified value type. + + Type of the value. + + true if this instance can convert the specified value type; otherwise, false. + + + + + Reads the JSON representation of the object. + + The to read from. + Type of the object. + The calling serializer. + The object value. + + + + Represents a reader that provides fast, non-cached, forward-only access to serialized Json data. + + + + + Initializes a new instance of the class with the specified . + + The TextReader containing the XML data to read. + + + + Reads the next JSON token from the stream. + + + true if the next token was read successfully; false if there are no more tokens to read. + + + + + Reads the next JSON token from the stream as a . + + + A or a null reference if the next JSON token is null. + + + + + Changes the state to closed. + + + + + Gets a value indicating whether the class can return line information. + + + true if LineNumber and LinePosition can be provided; otherwise, false. + + + + + Gets the current line number. + + + The current line number or 0 if no line information is available (for example, HasLineInfo returns false). + + + + + Gets the current line position. + + + The current line position or 0 if no line information is available (for example, HasLineInfo returns false). + + + + + Instructs the to always serialize the member with the specified name. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class with the specified name. + + Name of the property. + + + + Gets or sets the null value handling used when serializing this property. + + The null value handling. + + + + Gets or sets the default value handling used when serializing this property. + + The default value handling. + + + + Gets or sets the reference loop handling used when serializing this property. + + The reference loop handling. + + + + Gets or sets the object creation handling used when deserializing this property. + + The object creation handling. + + + + Gets or sets whether this property's value is serialized as a reference. + + Whether this property's value is serialized as a reference. + + + + Gets or sets the name of the property. + + The name of the property. + + + + Gets or sets a value indicating whether this property is required. + + + A value indicating whether this property is required. + + + + + Instructs the not to serialize the public field or public read/write property value. + + + + + Represents a writer that provides a fast, non-cached, forward-only way of generating Json data. + + + + + Creates an instance of the JsonWriter class using the specified . + + The TextWriter to write to. + + + + Flushes whatever is in the buffer to the underlying streams and also flushes the underlying stream. + + + + + Closes this stream and the underlying stream. + + + + + Writes the beginning of a Json object. + + + + + Writes the beginning of a Json array. + + + + + Writes the start of a constructor with the given name. + + The name of the constructor. + + + + Writes the specified end token. + + The end token to write. + + + + Writes the property name of a name/value pair on a Json object. + + The name of the property. + + + + Writes indent characters. + + + + + Writes the JSON value delimiter. + + + + + Writes an indent space. + + + + + Writes a null value. + + + + + Writes an undefined value. + + + + + Writes raw JSON. + + The raw JSON to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes out a comment /*...*/ containing the specified text. + + Text to place inside the comment. + + + + Writes out the given white space. + + The string of white space characters. + + + + Gets or sets how many IndentChars to write for each level in the hierarchy when is set to Formatting.Indented. + + + + + Gets or sets which character to use to quote attribute values. + + + + + Gets or sets which character to use for indenting when is set to Formatting.Indented. + + + + + Gets or sets a value indicating whether object names will be surrounded with quotes. + + + + + The exception thrown when an error occurs while reading Json text. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class + with a specified error message. + + The error message that explains the reason for the exception. + + + + Initializes a new instance of the class + with a specified error message and a reference to the inner exception that is the cause of this exception. + + The error message that explains the reason for the exception. + The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified. + + + + The exception thrown when an error occurs while reading Json text. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class + with a specified error message. + + The error message that explains the reason for the exception. + + + + Initializes a new instance of the class + with a specified error message and a reference to the inner exception that is the cause of this exception. + + The error message that explains the reason for the exception. + The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified. + + + + Gets the line number indicating where the error occurred. + + The line number indicating where the error occurred. + + + + Gets the line position indicating where the error occurred. + + The line position indicating where the error occurred. + + + + Represents a collection of . + + + + + Provides methods for converting between common language runtime types and JSON types. + + + + + Represents JavaScript's boolean value true as a string. This field is read-only. + + + + + Represents JavaScript's boolean value false as a string. This field is read-only. + + + + + Represents JavaScript's null as a string. This field is read-only. + + + + + Represents JavaScript's undefined as a string. This field is read-only. + + + + + Represents JavaScript's positive infinity as a string. This field is read-only. + + + + + Represents JavaScript's negative infinity as a string. This field is read-only. + + + + + Represents JavaScript's NaN as a string. This field is read-only. + + + + + Converts the to its JSON string representation. + + The value to convert. + A JSON string representation of the . + + + + Converts the to its JSON string representation. + + The value to convert. + A JSON string representation of the . + + + + Converts the to its JSON string representation. + + The value to convert. + A JSON string representation of the . + + + + Converts the to its JSON string representation. + + The value to convert. + A JSON string representation of the . + + + + Converts the to its JSON string representation. + + The value to convert. + A JSON string representation of the . + + + + Converts the to its JSON string representation. + + The value to convert. + A JSON string representation of the . + + + + Converts the to its JSON string representation. + + The value to convert. + A JSON string representation of the . + + + + Converts the to its JSON string representation. + + The value to convert. + A JSON string representation of the . + + + + Converts the to its JSON string representation. + + The value to convert. + A JSON string representation of the . + + + + Converts the to its JSON string representation. + + The value to convert. + A JSON string representation of the . + + + + Converts the to its JSON string representation. + + The value to convert. + A JSON string representation of the . + + + + Converts the to its JSON string representation. + + The value to convert. + A JSON string representation of the . + + + + Converts the to its JSON string representation. + + The value to convert. + A JSON string representation of the . + + + + Converts the to its JSON string representation. + + The value to convert. + A JSON string representation of the . + + + + Converts the to its JSON string representation. + + The value to convert. + A JSON string representation of the . + + + + Converts the to its JSON string representation. + + The value to convert. + A JSON string representation of the . + + + + Converts the to its JSON string representation. + + The value to convert. + A JSON string representation of the . + + + + Converts the to its JSON string representation. + + The value to convert. + The string delimiter character. + A JSON string representation of the . + + + + Converts the to its JSON string representation. + + The value to convert. + A JSON string representation of the . + + + + Serializes the specified object to a JSON string. + + The object to serialize. + A JSON string representation of the object. + + + + Serializes the specified object to a JSON string. + + The object to serialize. + Indicates how the output is formatted. + + A JSON string representation of the object. + + + + + Serializes the specified object to a JSON string using a collection of . + + The object to serialize. + A collection converters used while serializing. + A JSON string representation of the object. + + + + Serializes the specified object to a JSON string using a collection of . + + The object to serialize. + Indicates how the output is formatted. + A collection converters used while serializing. + A JSON string representation of the object. + + + + Serializes the specified object to a JSON string using a collection of . + + The object to serialize. + Indicates how the output is formatted. + The used to serialize the object. + If this is null, default serialization settings will be is used. + + A JSON string representation of the object. + + + + + Deserializes the specified object to a Json object. + + The object to deserialize. + The deserialized object from the Json string. + + + + Deserializes the specified object to a Json object. + + The object to deserialize. + The of object being deserialized. + The deserialized object from the Json string. + + + + Deserializes the specified object to a Json object. + + The type of the object to deserialize. + The object to deserialize. + The deserialized object from the Json string. + + + + Deserializes the specified JSON to the given anonymous type. + + + The anonymous type to deserialize to. This can't be specified + traditionally and must be infered from the anonymous type passed + as a parameter. + + The object to deserialize. + The anonymous type object. + The deserialized anonymous type from the JSON string. + + + + Deserializes the JSON string to the specified type. + + The type of the object to deserialize. + The object to deserialize. + Converters to use while deserializing. + The deserialized object from the JSON string. + + + + Deserializes the JSON string to the specified type. + + The type of the object to deserialize. + The object to deserialize. + + The used to deserialize the object. + If this is null, default serialization settings will be is used. + + The deserialized object from the JSON string. + + + + Deserializes the JSON string to the specified type. + + The object to deserialize. + The type of the object to deserialize. + Converters to use while deserializing. + The deserialized object from the JSON string. + + + + Deserializes the JSON string to the specified type. + + The JSON to deserialize. + The type of the object to deserialize. + + The used to deserialize the object. + If this is null, default serialization settings will be is used. + + The deserialized object from the JSON string. + + + + Populates the object with values from the JSON string. + + The JSON to populate values from. + The target object to populate values onto. + + + + Populates the object with values from the JSON string. + + The JSON to populate values from. + The target object to populate values onto. + + The used to deserialize the object. + If this is null, default serialization settings will be is used. + + + + + Serializes the XML node to a JSON string. + + The node to serialize. + A JSON string of the XmlNode. + + + + Deserializes the XmlNode from a JSON string. + + The JSON string. + The deserialized XmlNode + + + + Deserializes the XmlNode from a JSON string nested in a root elment. + + The JSON string. + The name of the root element to append when deserializing. + The deserialized XmlNode + + + + The exception thrown when an error occurs during Json serialization or deserialization. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class + with a specified error message. + + The error message that explains the reason for the exception. + + + + Initializes a new instance of the class + with a specified error message and a reference to the inner exception that is the cause of this exception. + + The error message that explains the reason for the exception. + The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified. + + + + Serializes and deserializes objects into and from the JSON format. + The enables you to control how objects are encoded into JSON. + + + + + Initializes a new instance of the class. + + + + + Creates a new instance using the specified . + + The settings to be applied to the . + A new instance using the specified . + + + + Populates the JSON values onto the target object. + + The that contains the JSON structure to reader values from. + The target object to populate values onto. + + + + Populates the JSON values onto the target object. + + The that contains the JSON structure to reader values from. + The target object to populate values onto. + + + + Deserializes the Json structure contained by the specified . + + The that contains the JSON structure to deserialize. + The being deserialized. + + + + Deserializes the Json structure contained by the specified + into an instance of the specified type. + + The containing the object. + The of object being deserialized. + The instance of being deserialized. + + + + Deserializes the Json structure contained by the specified + into an instance of the specified type. + + The containing the object. + The type of the object to deserialize. + The instance of being deserialized. + + + + Deserializes the Json structure contained by the specified + into an instance of the specified type. + + The containing the object. + The of object being deserialized. + The instance of being deserialized. + + + + Serializes the specified and writes the Json structure + to a Stream using the specified . + + The used to write the Json structure. + The to serialize. + + + + Serializes the specified and writes the Json structure + to a Stream using the specified . + + The used to write the Json structure. + The to serialize. + + + + Occurs when the errors during serialization and deserialization. + + + + + Gets or sets the used by the serializer when resolving references. + + + + + Gets or sets the used by the serializer when resolving type names. + + + + + Gets or sets how type name writing and reading is handled by the serializer. + + + + + Gets or sets how object references are preserved by the serializer. + + + + + Get or set how reference loops (e.g. a class referencing itself) is handled. + + + + + Get or set how missing members (e.g. JSON contains a property that isn't a member on the object) are handled during deserialization. + + + + + Get or set how null values are handled during serialization and deserialization. + + + + + Get or set how null default are handled during serialization and deserialization. + + + + + Gets or sets how objects are created during deserialization. + + The object creation handling. + + + + Gets or sets how constructors are used during deserialization. + + The constructor handling. + + + + Gets a collection that will be used during serialization. + + Collection that will be used during serialization. + + + + Gets or sets the contract resolver used by the serializer when + serializing .NET objects to JSON and vice versa. + + + + + Gets or sets the used by the serializer when invoking serialization callback methods. + + The context. + + + + Contains the LINQ to JSON extension methods. + + + + + Returns a collection of tokens that contains the ancestors of every token in the source collection. + + The type of the objects in source, constrained to . + An of that contains the source collection. + An of that contains the ancestors of every node in the source collection. + + + + Returns a collection of tokens that contains the descendants of every token in the source collection. + + The type of the objects in source, constrained to . + An of that contains the source collection. + An of that contains the descendants of every node in the source collection. + + + + Returns a collection of child properties of every object in the source collection. + + An of that contains the source collection. + An of that contains the properties of every object in the source collection. + + + + Returns a collection of child values of every object in the source collection with the given key. + + An of that contains the source collection. + The token key. + An of that contains the values of every node in the source collection with the given key. + + + + Returns a collection of child values of every object in the source collection. + + An of that contains the source collection. + An of that contains the values of every node in the source collection. + + + + Returns a collection of converted child values of every object in the source collection with the given key. + + The type to convert the values to. + An of that contains the source collection. + The token key. + An that contains the converted values of every node in the source collection with the given key. + + + + Returns a collection of converted child values of every object in the source collection. + + The type to convert the values to. + An of that contains the source collection. + An that contains the converted values of every node in the source collection. + + + + Converts the value. + + The type to convert the value to. + A cast as a of . + A converted value. + + + + Converts the value. + + The source collection type. + The type to convert the value to. + A cast as a of . + A converted value. + + + + Returns a collection of child tokens of every array in the source collection. + + The source collection type. + An of that contains the source collection. + An of that contains the values of every node in the source collection. + + + + Returns a collection of converted child tokens of every array in the source collection. + + An of that contains the source collection. + The type to convert the values to. + The source collection type. + An that contains the converted values of every node in the source collection. + + + + Returns the input typed as . + + An of that contains the source collection. + The input typed as . + + + + Returns the input typed as . + + The source collection type. + An of that contains the source collection. + The input typed as . + + + + Represents a JSON constructor. + + + + + Represents a token that can contain other tokens. + + + + + Raises the event. + + The instance containing the event data. + + + + Raises the event. + + The instance containing the event data. + + + + Returns a collection of the child tokens of this token, in document order. + + + An of containing the child tokens of this , in document order. + + + + + Returns a collection of the child values of this token, in document order. + + The type to convert the values to. + + A containing the child values of this , in document order. + + + + + Returns a collection of the descendant tokens for this token in document order. + + An containing the descendant tokens of the . + + + + Adds the specified content as children of this . + + The content to be added. + + + + Adds the specified content as the first children of this . + + The content to be added. + + + + Creates an that can be used to add tokens to the . + + An that is ready to have content written to it. + + + + Replaces the children nodes of this token with the specified content. + + The content. + + + + Removes the child nodes from this token. + + + + + Occurs when the list changes or an item in the list changes. + + + + + Occurs before an item is added to the collection. + + + + + Gets a value indicating whether this token has childen tokens. + + + true if this token has child values; otherwise, false. + + + + + Get the first child token of this token. + + + A containing the first child token of the . + + + + + Get the last child token of this token. + + + A containing the last child token of the . + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class from another object. + + A object to copy from. + + + + Initializes a new instance of the class with the specified name and content. + + The constructor name. + The contents of the constructor. + + + + Initializes a new instance of the class with the specified name and content. + + The constructor name. + The contents of the constructor. + + + + Initializes a new instance of the class with the specified name. + + The constructor name. + + + + Writes this token to a . + + A into which this method will write. + A collection of which will be used when writing the token. + + + + Loads an from a . + + A that will be read for the content of the . + A that contains the JSON that was read from the specified . + + + + Gets or sets the name of this constructor. + + The constructor name. + + + + Gets the node type for this . + + The type. + + + + Gets the with the specified key. + + The with the specified key. + + + + Represents a collection of objects. + + The type of token + + + + An empty collection of objects. + + + + + Initializes a new instance of the struct. + + The enumerable. + + + + Returns an enumerator that iterates through the collection. + + + A that can be used to iterate through the collection. + + + + + Returns an enumerator that iterates through a collection. + + + An object that can be used to iterate through the collection. + + + + + Determines whether the specified is equal to this instance. + + The to compare with this instance. + + true if the specified is equal to this instance; otherwise, false. + + + + + Returns a hash code for this instance. + + + A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. + + + + + Gets the with the specified key. + + + + + + Represents a JSON object. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class from another object. + + A object to copy from. + + + + Initializes a new instance of the class with the specified content. + + The contents of the object. + + + + Initializes a new instance of the class with the specified content. + + The contents of the object. + + + + Gets an of this object's properties. + + An of this object's properties. + + + + Gets a the specified name. + + The property name. + A with the specified name or null. + + + + Gets an of this object's property values. + + An of this object's property values. + + + + Loads an from a . + + A that will be read for the content of the . + A that contains the JSON that was read from the specified . + + + + Load a from a string that contains JSON. + + A that contains JSON. + A populated from the string that contains JSON. + + + + Creates a from an object. + + The object that will be used to create . + A with the values of the specified object + + + + Creates a from an object. + + The object that will be used to create . + The that will be used to read the object. + A with the values of the specified object + + + + Writes this token to a . + + A into which this method will write. + A collection of which will be used when writing the token. + + + + Adds the specified property name. + + Name of the property. + The value. + + + + Removes the property with the specified name. + + Name of the property. + true if item was successfully removed; otherwise, false. + + + + Tries the get value. + + Name of the property. + The value. + true if a value was successfully retrieved; otherwise, false. + + + + Returns an enumerator that iterates through the collection. + + + A that can be used to iterate through the collection. + + + + + Raises the event with the provided arguments. + + Name of the property. + + + + Occurs when a property value changes. + + + + + Gets the node type for this . + + The type. + + + + Gets the with the specified key. + + The with the specified key. + + + + Gets or sets the with the specified property name. + + + + + + Gets the number of elements contained in the . + + + The number of elements contained in the . + + + + Represents a JSON array. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class from another object. + + A object to copy from. + + + + Initializes a new instance of the class with the specified content. + + The contents of the array. + + + + Initializes a new instance of the class with the specified content. + + The contents of the array. + + + + Loads an from a . + + A that will be read for the content of the . + A that contains the JSON that was read from the specified . + + + + Load a from a string that contains JSON. + + A that contains JSON. + A populated from the string that contains JSON. + + + + Creates a from an object. + + The object that will be used to create . + A with the values of the specified object + + + + Creates a from an object. + + The object that will be used to create . + The that will be used to read the object. + A with the values of the specified object + + + + Writes this token to a . + + A into which this method will write. + A collection of which will be used when writing the token. + + + + Determines the index of a specific item in the . + + The object to locate in the . + + The index of if found in the list; otherwise, -1. + + + + + Inserts an item to the at the specified index. + + The zero-based index at which should be inserted. + The object to insert into the . + + is not a valid index in the . + The is read-only. + + + + Removes the item at the specified index. + + The zero-based index of the item to remove. + + is not a valid index in the . + The is read-only. + + + + Adds an item to the . + + The object to add to the . + The is read-only. + + + + Removes all items from the . + + The is read-only. + + + + Determines whether the contains a specific value. + + The object to locate in the . + + true if is found in the ; otherwise, false. + + + + + Removes the first occurrence of a specific object from the . + + The object to remove from the . + + true if was successfully removed from the ; otherwise, false. This method also returns false if is not found in the original . + + The is read-only. + + + + Gets the node type for this . + + The type. + + + + Gets the with the specified key. + + The with the specified key. + + + + Gets or sets the at the specified index. + + + + + + Gets the number of elements contained in the . + + + The number of elements contained in the . + + + + Represents a reader that provides fast, non-cached, forward-only access to serialized Json data. + + + + + Initializes a new instance of the class. + + The token to read from. + + + + Reads the next JSON token from the stream as a . + + + A or a null reference if the next JSON token is null. + + + + + Reads the next JSON token from the stream. + + + true if the next token was read successfully; false if there are no more tokens to read. + + + + + Represents a JSON property. + + + + + Initializes a new instance of the class from another object. + + A object to copy from. + + + + Returns a collection of the child tokens of this token, in document order. + + + An of containing the child tokens of this , in document order. + + + + + Initializes a new instance of the class. + + The property name. + The property content. + + + + Initializes a new instance of the class. + + The property name. + The property content. + + + + Writes this token to a . + + A into which this method will write. + A collection of which will be used when writing the token. + + + + Loads an from a . + + A that will be read for the content of the . + A that contains the JSON that was read from the specified . + + + + Gets the property name. + + The property name. + + + + Gets or sets the property value. + + The property value. + + + + Gets the node type for this . + + The type. + + + + Specifies the type of token. + + + + + No token type has been set. + + + + + A JSON object. + + + + + A JSON array. + + + + + A JSON constructor. + + + + + A JSON object property. + + + + + A comment. + + + + + An integer value. + + + + + A float value. + + + + + A string value. + + + + + A boolean value. + + + + + A null value. + + + + + An undefined value. + + + + + A date value. + + + + + A raw JSON value. + + + + + A collection of bytes value. + + + + + Contains the JSON schema extension methods. + + + + + Determines whether the is valid. + + The source to test. + The schema to test with. + + true if the specified is valid; otherwise, false. + + + + + Validates the specified . + + The source to test. + The schema to test with. + + + + Validates the specified . + + The source to test. + The schema to test with. + The validation event handler. + + + + Returns detailed information about the schema exception. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class + with a specified error message. + + The error message that explains the reason for the exception. + + + + Initializes a new instance of the class + with a specified error message and a reference to the inner exception that is the cause of this exception. + + The error message that explains the reason for the exception. + The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified. + + + + Gets the line number indicating where the error occurred. + + The line number indicating where the error occurred. + + + + Gets the line position indicating where the error occurred. + + The line position indicating where the error occurred. + + + + Resolves from an id. + + + + + Initializes a new instance of the class. + + + + + Gets a for the specified id. + + The id. + A for the specified id. + + + + Gets or sets the loaded schemas. + + The loaded schemas. + + + + Specifies undefined schema Id handling options for the . + + + + + Do not infer a schema Id. + + + + + Use the .NET type name as the schema Id. + + + + + Use the assembly qualified .NET type name as the schema Id. + + + + + Returns detailed information related to the . + + + + + Gets the associated with the validation event. + + The JsonSchemaException associated with the validation event. + + + + Gets the text description corresponding to the validation event. + + The text description. + + + + Represents the callback method that will handle JSON schema validation events and the . + + + + + Resolves member mappings for a type, camel casing property names. + + + + + Used by to resolves a for a given . + + + + + Used by to resolves a for a given . + + + + + Resolves the contract for a given type. + + The type to resolve a contract for. + The contract for a given type. + + + + Initializes a new instance of the class. + + + + + Resolves the contract for a given type. + + The type to resolve a contract for. + The contract for a given type. + + + + Gets the serializable members for the type. + + The type to get serializable members for. + The serializable members for the type. + + + + Creates a for the given type. + + Type of the object. + A for the given type. + + + + Resolves the default for the contract. + + Type of the object. + + + + + Creates a for the given type. + + Type of the object. + A for the given type. + + + + Creates a for the given type. + + Type of the object. + A for the given type. + + + + Creates a for the given type. + + Type of the object. + A for the given type. + + + + Creates a for the given type. + + Type of the object. + A for the given type. + + + + Creates properties for the given . + + The contract to create properties for. + Properties for the given . + + + + Creates the used by the serializer to get and set values from a member. + + The member. + The used by the serializer to get and set values from a member. + + + + Creates a for the given . + + The member's declaring types . + The member to create a for. + A created for the given . + + + + Resolves the name of the property. + + Name of the property. + Name of the property. + + + + Gets or sets the default members search flags. + + The default members search flags. + + + + Resolves the name of the property. + + Name of the property. + The property name camel cased. + + + + The default serialization binder used when resolving and loading classes from type names. + + + + + When overridden in a derived class, controls the binding of a serialized object to a type. + + Specifies the name of the serialized object. + Specifies the name of the serialized object. + + The type of the object the formatter creates a new instance of. + + + + + Get and set values for a using dynamic methods. + + + + + Provides methods to get and set values. + + + + + Sets the value. + + The target to set the value on. + The value to set on the target. + + + + Gets the value. + + The target to get the value from. + The value. + + + + Initializes a new instance of the class. + + The member info. + + + + Sets the value. + + The target to set the value on. + The value to set on the target. + + + + Gets the value. + + The target to get the value from. + The value. + + + + Provides information surrounding an error. + + + + + Gets or sets the error. + + The error. + + + + Gets the original object that caused the error. + + The original object that caused the error. + + + + Gets the member that caused the error. + + The member that caused the error. + + + + Gets or sets a value indicating whether this is handled. + + true if handled; otherwise, false. + + + + Provides data for the Error event. + + + + + Initializes a new instance of the class. + + The current object. + The error context. + + + + Gets the current object the error event is being raised against. + + The current object the error event is being raised against. + + + + Gets the error context. + + The error context. + + + + Contract details for a used by the . + + + + + Contract details for a used by the . + + + + + Gets the underlying type for the contract. + + The underlying type for the contract. + + + + Gets or sets the type created during deserialization. + + The type created during deserialization. + + + + Gets or sets whether this type contract is serialized as a reference. + + Whether this type contract is serialized as a reference. + + + + Gets or sets the default for this contract. + + The converter. + + + + Gets or sets the method called immediately after deserialization of the object. + + The method called immediately after deserialization of the object. + + + + Gets or sets the method called during deserialization of the object. + + The method called during deserialization of the object. + + + + Gets or sets the method called after serialization of the object graph. + + The method called after serialization of the object graph. + + + + Gets or sets the method called before serialization of the object. + + The method called before serialization of the object. + + + + Gets or sets the default creator. + + The default creator. + + + + Gets or sets a value indicating whether [default creator non public]. + + true if the default object creator is non-public; otherwise, false. + + + + Gets or sets the method called when an error is thrown during the serialization of the object. + + The method called when an error is thrown during the serialization of the object. + + + + Initializes a new instance of the class. + + The underlying type for the contract. + + + + Contract details for a used by the . + + + + + Initializes a new instance of the class. + + The underlying type for the contract. + + + + Contract details for a used by the . + + + + + Initializes a new instance of the class. + + The underlying type for the contract. + + + + Contract details for a used by the . + + + + + Initializes a new instance of the class. + + The underlying type for the contract. + + + + Maps a JSON property to a .NET member. + + + + + Gets the name of the property. + + The name of the property. + + + + Gets the that will get and set the during serialization. + + The that will get and set the during serialization. + + + + Gets or sets the type of the property. + + The type of the property. + + + + Gets or sets the for the property. + If set this converter takes presidence over the contract converter for the property type. + + The converter. + + + + Gets a value indicating whether this is ignored. + + true if ignored; otherwise, false. + + + + Gets a value indicating whether this is readable. + + true if readable; otherwise, false. + + + + Gets a value indicating whether this is writable. + + true if writable; otherwise, false. + + + + Gets the member converter. + + The member converter. + + + + Gets the default value. + + The default value. + + + + Gets a value indicating whether this is required. + + A value indicating whether this is required. + + + + Gets a value indicating whether this property preserves object references. + + + true if this instance is reference; otherwise, false. + + + + + Gets the property null value handling. + + The null value handling. + + + + Gets the property default value handling. + + The default value handling. + + + + Gets the property reference loop handling. + + The reference loop handling. + + + + Gets the property object creation handling. + + The object creation handling. + + + + A collection of objects. + + + + + Initializes a new instance of the class. + + The contract. + + + + When implemented in a derived class, extracts the key from the specified element. + + The element from which to extract the key. + The key for the specified element. + + + + Adds a object. + + The property to add to the collection. + + + + Gets the closest matching object. + First attempts to get an exact case match of propertyName and then + a case insensitive match. + + Name of the property. + A matching property if found. + + + + Gets a property by property name. + + The name of the property to get. + Type property name string comparison. + A matching property if found. + + + + Specifies missing member handling options for the . + + + + + Ignore a missing member and do not attempt to deserialize it. + + + + + Throw a when a missing member is encountered during deserialization. + + + + + Specifies null value handling options for the . + + + + + Include null values when serializing and deserializing objects. + + + + + Ignore null values when serializing and deserializing objects. + + + + + Specifies reference loop handling options for the . + + + + + Throw a when a loop is encountered. + + + + + Ignore loop references and do not serialize. + + + + + Serialize loop references. + + + + + An in-memory representation of a JSON Schema. + + + + + Initializes a new instance of the class. + + + + + Reads a from the specified . + + The containing the JSON Schema to read. + The object representing the JSON Schema. + + + + Reads a from the specified . + + The containing the JSON Schema to read. + The to use when resolving schema references. + The object representing the JSON Schema. + + + + Load a from a string that contains schema JSON. + + A that contains JSON. + A populated from the string that contains JSON. + + + + Parses the specified json. + + The json. + The resolver. + A populated from the string that contains JSON. + + + + Writes this schema to a . + + A into which this method will write. + + + + Writes this schema to a using the specified . + + A into which this method will write. + The resolver used. + + + + Returns a that represents the current . + + + A that represents the current . + + + + + Gets or sets the id. + + + + + Gets or sets the title. + + + + + Gets or sets whether the object is optional. + + + + + Gets or sets whether the object is read only. + + + + + Gets or sets whether the object is visible to users. + + + + + Gets or sets whether the object is transient. + + + + + Gets or sets the description of the object. + + + + + Gets or sets the types of values allowed by the object. + + The type. + + + + Gets or sets the pattern. + + The pattern. + + + + Gets or sets the minimum length. + + The minimum length. + + + + Gets or sets the maximum length. + + The maximum length. + + + + Gets or sets the maximum decimals. + + The maximum decimals. + + + + Gets or sets the minimum. + + The minimum. + + + + Gets or sets the maximum. + + The maximum. + + + + Gets or sets the minimum number of items. + + The minimum number of items. + + + + Gets or sets the maximum number of items. + + The maximum number of items. + + + + Gets or sets the of items. + + The of items. + + + + Gets or sets the of properties. + + The of properties. + + + + Gets or sets the of additional properties. + + The of additional properties. + + + + Gets or sets a value indicating whether additional properties are allowed. + + + true if additional properties are allowed; otherwise, false. + + + + + Gets or sets the required property if this property is present. + + The required property if this property is present. + + + + Gets or sets the identity. + + The identity. + + + + Gets or sets the a collection of valid enum values allowed. + + A collection of valid enum values allowed. + + + + Gets or sets a collection of options. + + A collection of options. + + + + Gets or sets disallowed types. + + The disallow types. + + + + Gets or sets the default value. + + The default value. + + + + Gets or sets the extend . + + The extended . + + + + Gets or sets the format. + + The format. + + + + Generates a from a specified . + + + + + Generate a from the specified type. + + The type to generate a from. + A generated from the specified type. + + + + Generate a from the specified type. + + The type to generate a from. + The used to resolve schema references. + A generated from the specified type. + + + + Generate a from the specified type. + + The type to generate a from. + Specify whether the generated root will be nullable. + A generated from the specified type. + + + + Generate a from the specified type. + + The type to generate a from. + The used to resolve schema references. + Specify whether the generated root will be nullable. + A generated from the specified type. + + + + Gets or sets how undefined schemas are handled by the serializer. + + + + + Gets or sets the contract resolver. + + The contract resolver. + + + + The value types allowed by the . + + + + + No type specified. + + + + + String type. + + + + + Float type. + + + + + Integer type. + + + + + Boolean type. + + + + + Object type. + + + + + Array type. + + + + + Null type. + + + + + Any type. + + + + + Contract details for a used by the . + + + + + Initializes a new instance of the class. + + The underlying type for the contract. + + + + Gets or sets the object member serialization. + + The member object serialization. + + + + Gets the object's properties. + + The object's properties. + + + + Gets or sets the parametrized constructor used to create the object. + + The parametrized constructor. + + + + When applied to a method, specifies that the method is called when an error occurs serializing an object. + + + + + Get and set values for a using reflection. + + + + + Initializes a new instance of the class. + + The member info. + + + + Sets the value. + + The target to set the value on. + The value to set on the target. + + + + Gets the value. + + The target to get the value from. + The value. + + + + Specifies type name handling options for the . + + + + + Do not include the .NET type name when serializing types. + + + + + Include the .NET type name when serializing into a JSON object structure. + + + + + Include the .NET type name when serializing into a JSON array structure. + + + + + Always include the .NET type name when serializing. + + + + + Converts the value to the specified type. + + The type to convert the value to. + The value to convert. + The converted type. + + + + Converts the value to the specified type. + + The type to convert the value to. + The value to convert. + The culture to use when converting. + The converted type. + + + + Converts the value to the specified type. + + The value to convert. + The culture to use when converting. + The type to convert the value to. + The converted type. + + + + Converts the value to the specified type. + + The type to convert the value to. + The value to convert. + The converted value if the conversion was successful or the default value of T if it failed. + + true if initialValue was converted successfully; otherwise, false. + + + + + Converts the value to the specified type. + + The type to convert the value to. + The value to convert. + The culture to use when converting. + The converted value if the conversion was successful or the default value of T if it failed. + + true if initialValue was converted successfully; otherwise, false. + + + + + Converts the value to the specified type. + + The value to convert. + The culture to use when converting. + The type to convert the value to. + The converted value if the conversion was successful or the default value of T if it failed. + + true if initialValue was converted successfully; otherwise, false. + + + + + Converts the value to the specified type. If the value is unable to be converted, the + value is checked whether it assignable to the specified type. + + The type to convert or cast the value to. + The value to convert. + The converted type. If conversion was unsuccessful, the initial value is returned if assignable to the target type + + + + Converts the value to the specified type. If the value is unable to be converted, the + value is checked whether it assignable to the specified type. + + The type to convert or cast the value to. + The value to convert. + The culture to use when converting. + The converted type. If conversion was unsuccessful, the initial value is returned if assignable to the target type + + + + Converts the value to the specified type. If the value is unable to be converted, the + value is checked whether it assignable to the specified type. + + The value to convert. + The culture to use when converting. + The type to convert or cast the value to. + + The converted type. If conversion was unsuccessful, the initial value + is returned if assignable to the target type. + + + + + Converts the value to the specified type. If the value is unable to be converted, the + value is checked whether it assignable to the specified type. + + The type to convert the value to. + The value to convert. + The converted value if the conversion was successful or the default value of T if it failed. + + true if initialValue was converted successfully or is assignable; otherwise, false. + + + + + Converts the value to the specified type. If the value is unable to be converted, the + value is checked whether it assignable to the specified type. + + The type to convert the value to. + The value to convert. + The culture to use when converting. + The converted value if the conversion was successful or the default value of T if it failed. + + true if initialValue was converted successfully or is assignable; otherwise, false. + + + + + Converts the value to the specified type. If the value is unable to be converted, the + value is checked whether it assignable to the specified type. + + The value to convert. + The culture to use when converting. + The type to convert the value to. + The converted value if the conversion was successful or the default value of T if it failed. + + true if initialValue was converted successfully or is assignable; otherwise, false. + + + + + Parses the specified enum member name, returning it's value. + + Name of the enum member. + + + + + Parses the specified enum member name, returning it's value. + + Name of the enum member. + If set to true ignore case. + + + + + Gets a dictionary of the names and values of an Enum type. + + + + + + Gets a dictionary of the names and values of an Enum type. + + + + + + Gets a dictionary of the names and values of an Enum type. + + The enum type to get names and values for. + + + + + Gets the maximum valid value of an Enum type. Flags enums are ORed. + + The type of the returned value. Must be assignable from the enum's underlying value type. + The enum type to get the maximum value for. + + + + + Specifies the type of Json token. + + + + + This is returned by the if a method has not been called. + + + + + An object start token. + + + + + An array start token. + + + + + A constructor start token. + + + + + An object property name. + + + + + A comment. + + + + + Raw JSON. + + + + + An interger. + + + + + A float. + + + + + A string. + + + + + A boolean. + + + + + A null token. + + + + + An undefined token. + + + + + An object end token. + + + + + An array end token. + + + + + A constructor end token. + + + + + A Date. + + + + + Byte data. + + + + + Specifies the state of the . + + + + + An exception has been thrown, which has left the in an invalid state. + You may call the method to put the in the Closed state. + Any other method calls results in an being thrown. + + + + + The method has been called. + + + + + An object is being written. + + + + + A array is being written. + + + + + A constructor is being written. + + + + + A property is being written. + + + + + A write method has not been called. + + + + + Specifies formatting options for the . + + + + + No special formatting is applied. This is the default. + + + + + Causes child objects to be indented according to the and settings. + + + + + Builds a string. Unlike StringBuilder this class lets you reuse it's internal buffer. + + + + + Determines whether the collection is null or empty. + + The collection. + + true if the collection is null or empty; otherwise, false. + + + + + Determines whether the collection is null or empty. + + The collection. + + true if the collection is null or empty; otherwise, false. + + + + + Determines whether the collection is null, empty or its contents are uninitialized values. + + The list. + + true if the collection is null or empty or its contents are uninitialized values; otherwise, false. + + + + + Makes a slice of the specified list in between the start and end indexes. + + The list. + The start index. + The end index. + A slice of the list. + + + + Makes a slice of the specified list in between the start and end indexes, + getting every so many items based upon the step. + + The list. + The start index. + The end index. + The step. + A slice of the list. + + + + Group the collection using a function which returns the key. + + The source collection to group. + The key selector. + A Dictionary with each key relating to a list of objects in a list grouped under it. + + + + Adds the elements of the specified collection to the specified generic IList. + + The list to add to. + The collection of elements to add. + + + + Gets the type of the typed collection's items. + + The type. + The type of the typed collection's items. + + + + Tests whether the list's items are their unitialized value. + + The list. + Whether the list's items are their unitialized value + + + + Gets the member's underlying type. + + The member. + The underlying type of the member. + + + + Determines whether the member is an indexed property. + + The member. + + true if the member is an indexed property; otherwise, false. + + + + + Determines whether the property is an indexed property. + + The property. + + true if the property is an indexed property; otherwise, false. + + + + + Gets the member's value on the object. + + The member. + The target object. + The member's value on the object. + + + + Sets the member's value on the target object. + + The member. + The target. + The value. + + + + Determines whether the specified MemberInfo can be read. + + The MemberInfo to determine whether can be read. + + true if the specified MemberInfo can be read; otherwise, false. + + + + + Determines whether the specified MemberInfo can be set. + + The MemberInfo to determine whether can be set. + + true if the specified MemberInfo can be set; otherwise, false. + + + + + Determines whether the string contains white space. + + The string to test for white space. + + true if the string contains white space; otherwise, false. + + + + + Determines whether the string is all white space. Empty string will return false. + + The string to test whether it is all white space. + + true if the string is all white space; otherwise, false. + + + + + Ensures the target string ends with the specified string. + + The target. + The value. + The target string with the value string at the end. + + + + Perform an action if the string is not null or empty. + + The value. + The action to perform. + + + + Indents the specified string. + + The string to indent. + The number of characters to indent by. + + + + + Indents the specified string. + + The string to indent. + The number of characters to indent by. + The indent character. + + + + + Numbers the lines. + + The string to number. + + + + + Nulls an empty string. + + The string. + Null if the string was null, otherwise the string unchanged. + + + diff --git a/bin/Newtonsoft.Json.dll b/bin/Newtonsoft.Json.dll index 3b1444881422fe4aad3a904f09ebd5d4102c66e8..177d9b5d9490e194cf026e476008be37649a8956 100644 GIT binary patch literal 356352 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

!QeCz(pup>!Qe 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 CYWsEo literal 73728 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 diff --git a/bin/Newtonsoft.Json.pdb b/bin/Newtonsoft.Json.pdb index a8b8b8f27d9a97dce82798551ee1bbcc6fddb9f4..892546a3fc54e0d0b5c1d006b4787da4e529d2b3 100644 GIT binary patch literal 742912 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

$ns>O5qo;xl6~5*q30h`7X0J9hXHq+>jio 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

5OQUYRxcfG;mv8K`x1An`+n(axAfZci8>qM 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 Date: Thu, 11 Mar 2010 23:33:55 +0000 Subject: [PATCH 11/28] minor: add some more documentation for IHttpServer.AddHTTPHandler() to tell the caller that the best match for an incoming request URI is invoked --- OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs | 6 ++---- .../Framework/Servers/HttpServer/Interfaces/IHttpServer.cs | 6 +++++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs index 214f936e1e..9a6ef77437 100644 --- a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs +++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs @@ -202,16 +202,14 @@ namespace OpenSim.Framework.Servers.HttpServer if (!m_pollHandlers.ContainsKey(methodName)) { m_pollHandlers.Add(methodName,args); - pollHandlerResult = true; - + pollHandlerResult = true; } } if (pollHandlerResult) return AddHTTPHandler(methodName, handler); - return false; - + return false; } // Note that the agent string is provided simply to differentiate diff --git a/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs index 5ee2045bde..65b1eb5699 100644 --- a/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs +++ b/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs @@ -47,7 +47,7 @@ namespace OpenSim.Framework.Servers.HttpServer bool AddAgentHandler(string agent, IHttpAgentHandler handler); ///

- /// Add a handler for an HTTP request + /// Add a handler for an HTTP request. /// /// /// This handler can actually be invoked either as @@ -66,6 +66,10 @@ namespace OpenSim.Framework.Servers.HttpServer /// or /// /// http://localhost:9000/object/ + /// + /// In addition, the handler invoked by the HTTP server for any request is the one when best matches the request + /// URI. So if a handler for "/myapp/" is registered and a request for "/myapp/page" is received, then + /// the "/myapp/" handler is invoked if no "/myapp/page" handler exists. /// /// /// From ed3288a8db33be13e9e278d47cc00b3666d9d262 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Fri, 12 Mar 2010 10:16:21 -0800 Subject: [PATCH 12/28] Bug fix: "last location" login. --- OpenSim/Services/PresenceService/PresenceService.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/OpenSim/Services/PresenceService/PresenceService.cs b/OpenSim/Services/PresenceService/PresenceService.cs index 304538ab65..ea8d673c1f 100644 --- a/OpenSim/Services/PresenceService/PresenceService.cs +++ b/OpenSim/Services/PresenceService/PresenceService.cs @@ -72,6 +72,10 @@ namespace OpenSim.Services.PresenceService data.Data["HomeRegionID"] = d[0].Data["HomeRegionID"]; data.Data["HomePosition"] = d[0].Data["HomePosition"]; data.Data["HomeLookAt"] = d[0].Data["HomeLookAt"]; + data.Data["Position"] = d[0].Data["Position"]; + data.Data["LookAt"] = d[0].Data["LookAt"]; + + data.RegionID = d[0].RegionID; } else { From 8b1e33eb2d253daddb760c90526f1a3de95c17d0 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Fri, 12 Mar 2010 10:31:43 -0800 Subject: [PATCH 13/28] Fixed SimianGrid.ini to use GridCommon.ini(.example) --- bin/config-include/SimianGrid.ini | 55 ++++++++++++------------------- 1 file changed, 21 insertions(+), 34 deletions(-) diff --git a/bin/config-include/SimianGrid.ini b/bin/config-include/SimianGrid.ini index af3386039b..58dcae9e24 100644 --- a/bin/config-include/SimianGrid.ini +++ b/bin/config-include/SimianGrid.ini @@ -1,3 +1,24 @@ +;; +;; Please don't change this file. +;; All optional settings are in GridCommon.ini.example, +;; which you can copy and change. +;; + +;; +;; In GridCommon.ini, these are the URLs you would use if SimianGrid is +;; installed at http://www.mygrid.com/Grid/ +;; +; AssetServerURI = "http://www.mygrid.com/Grid/?id=" +; InventoryServerURI = "http://www.mygrid.com/Grid/" +; AvatarServerURI = "http://www.mygrid.com/Grid/" +; PresenceServerURI = "http://www.mygrid.com/Grid/" +; UserAccountServerURI = "http://www.mygrid.com/Grid/" +; AuthenticationServerURI = "http://www.mygrid.com/Grid/" +; FriendsServerURI = "http://www.mygrid.com/Grid/" + +[Includes] + Include-Common = "config-include/GridCommon.ini" + [Modules] GridServices = "OpenSim.Services.Connectors.dll:SimianGridServiceConnector" PresenceServices = "OpenSim.Services.Connectors.dll:SimianPresenceServiceConnector" @@ -25,7 +46,6 @@ [GridService] LocalServiceModule = "OpenSim.Services.GridService.dll:GridService" StorageProvider = "OpenSim.Data.Null.dll:NullRegionData" - GridServerURI = "http://localhost/Grid/" [LibraryService] LocalServiceModule = "OpenSim.Services.InventoryService.dll:LibraryService" @@ -35,36 +55,3 @@ [AssetService] DefaultAssetLoader = "OpenSim.Framework.AssetLoader.Filesystem.dll" AssetLoaderArgs = "assets/AssetSets.xml" - AssetServerURI = "http://localhost/Grid/?id=" - -[InventoryService] - InventoryServerURI = "http://localhost/Grid/" - -[AvatarService] - AvatarServerURI = "http://localhost/Grid/" - -[PresenceService] - PresenceServerURI = "http://localhost/Grid/" - -[UserAccountService] - UserAccountServerURI = "http://localhost/Grid/" - -[AuthenticationService] - AuthenticationServerURI = "http://localhost/Grid/" - -[FriendsService] - FriendsServerURI = "http://localhost/Grid/" - -[AssetCache] - CacheDirectory = ./assetcache - LogLevel = 0 - HitRateDisplay = 100 - MemoryCacheEnabled = false - ; How long {in hours} to keep assets cached in memory, .5 == 30 minutes - MemoryCacheTimeout = 2 - ; How long {in hours} to keep assets cached on disk, .5 == 30 minutes - ; Specify 0 if you do not want your disk cache to expire - FileCacheTimeout = 0 - ; How often {in hours} should the disk be checked for expired filed - ; Specify 0 to disable expiration checking - FileCleanupTimer = 0 ;roughly every 10 minutes From f2de50bb14bd8215ea98c79c79aabe1e6b4f2780 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 12 Mar 2010 19:31:14 +0000 Subject: [PATCH 14/28] Fix tests broken in 88771aeed3d45e60a18aa9a810eeb37b8e5def12 Adds MockUserAccountService and connects it up Stops services being carried over between tests since this leads to hard to find bugs Improves information and error reporting when loading plugins --- .../LocalUserAccountServiceConnector.cs | 18 ++++---- .../Scenes/Tests/SceneObjectBasicTests.cs | 13 ++---- OpenSim/Server/Base/ServerUtils.cs | 40 ++++++++--------- .../Interfaces/IUserAccountService.cs | 20 ++++++--- .../Common/Mock/MockUserAccountService.cs | 45 +++++++++++++++++++ OpenSim/Tests/Common/Mock/TestScene.cs | 4 +- .../Tests/Common/Setup/SceneSetupHelpers.cs | 34 +++++++++++--- 7 files changed, 120 insertions(+), 54 deletions(-) create mode 100644 OpenSim/Tests/Common/Mock/MockUserAccountService.cs diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/LocalUserAccountServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/LocalUserAccountServiceConnector.cs index ce0ca40870..30ebb2147b 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/LocalUserAccountServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/LocalUserAccountServiceConnector.cs @@ -73,33 +73,31 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts IConfig userConfig = source.Configs["UserAccountService"]; if (userConfig == null) { - m_log.Error("[USER CONNECTOR]: UserAccountService missing from OpenSim.ini"); + m_log.Error("[LOCAL USER ACCOUNT SERVICE CONNECTOR]: UserAccountService missing from OpenSim.ini"); return; } - string serviceDll = userConfig.GetString("LocalServiceModule", - String.Empty); + string serviceDll = userConfig.GetString("LocalServiceModule", String.Empty); if (serviceDll == String.Empty) { - m_log.Error("[USER CONNECTOR]: No LocalServiceModule named in section UserService"); + m_log.Error("[LOCAL USER ACCOUNT SERVICE CONNECTOR]: No LocalServiceModule named in section UserService"); return; } Object[] args = new Object[] { source }; - m_UserService = - ServerUtils.LoadPlugin(serviceDll, - args); + m_UserService = ServerUtils.LoadPlugin(serviceDll, args); if (m_UserService == null) { - m_log.Error("[USER CONNECTOR]: Can't load user account service"); + m_log.ErrorFormat( + "[LOCAL USER ACCOUNT SERVICE CONNECTOR]: Cannot load user account service specified as {0}", serviceDll); return; } m_Enabled = true; m_Cache = new UserAccountCache(); - m_log.Info("[USER CONNECTOR]: Local user connector enabled"); + m_log.Info("[LOCAL USER ACCOUNT SERVICE CONNECTOR]: Local user connector enabled"); } } } @@ -134,6 +132,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts { if (!m_Enabled) return; + + m_log.InfoFormat("[LOCAL USER ACCOUNT SERVICE CONNECTOR]: Enabled local user accounts for region {0}", scene.RegionInfo.RegionName); } #endregion diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs index b50d4ca5b2..78f2ae3aa1 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs @@ -86,6 +86,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests public void TestDeleteSceneObjectAsync() { TestHelper.InMethod(); + //log4net.Config.XmlConfigurator.Configure(); UUID agentId = UUID.Parse("00000000-0000-0000-0000-000000000001"); @@ -97,15 +98,9 @@ namespace OpenSim.Region.Framework.Scenes.Tests SceneObjectPart part = SceneSetupHelpers.AddSceneObject(scene); - try - { - IClientAPI client = SceneSetupHelpers.AddRootAgent(scene, agentId); - scene.DeRezObject(client, part.LocalId, UUID.Zero, DeRezAction.Delete, UUID.Zero); - } - catch (Exception e) - { - Console.WriteLine("Exception: " + e.StackTrace); - } + IClientAPI client = SceneSetupHelpers.AddRootAgent(scene, agentId); + scene.DeRezObject(client, part.LocalId, UUID.Zero, DeRezAction.Delete, UUID.Zero); + SceneObjectPart retrievedPart = scene.GetSceneObjectPart(part.LocalId); Assert.That(retrievedPart, Is.Not.Null); diff --git a/OpenSim/Server/Base/ServerUtils.cs b/OpenSim/Server/Base/ServerUtils.cs index 9c5441031d..a399672d4d 100644 --- a/OpenSim/Server/Base/ServerUtils.cs +++ b/OpenSim/Server/Base/ServerUtils.cs @@ -57,6 +57,12 @@ namespace OpenSim.Server.Base return ret; } + /// + /// Load a plugin from a dll with the given class or interface + /// + /// + /// The arguments which control which constructor is invoked on the plugin + /// public static T LoadPlugin(string dllName, Object[] args) where T:class { string[] parts = dllName.Split(new char[] {':'}); @@ -71,6 +77,13 @@ namespace OpenSim.Server.Base return LoadPlugin(dllName, className, args); } + /// + /// Load a plugin from a dll with the given class or interface + /// + /// + /// + /// The arguments which control which constructor is invoked on the plugin + /// public static T LoadPlugin(string dllName, string className, Object[] args) where T:class { string interfaceName = typeof(T).ToString(); @@ -83,28 +96,15 @@ namespace OpenSim.Server.Base { if (pluginType.IsPublic) { - if (className != String.Empty && - pluginType.ToString() != - pluginType.Namespace + "." + className) + if (className != String.Empty + && pluginType.ToString() != pluginType.Namespace + "." + className) continue; - Type typeInterface = - pluginType.GetInterface(interfaceName, true); + + Type typeInterface = pluginType.GetInterface(interfaceName, true); + if (typeInterface != null) { - T plug = null; - try - { - plug = (T)Activator.CreateInstance(pluginType, - args); - } - catch (Exception e) - { - if (!(e is System.MissingMethodException)) - m_log.ErrorFormat("Error loading plugin from {0}, exception {1}", dllName, e.InnerException); - return null; - } - - return plug; + return (T)Activator.CreateInstance(pluginType, args); } } } @@ -113,7 +113,7 @@ namespace OpenSim.Server.Base } catch (Exception e) { - m_log.ErrorFormat("Error loading plugin from {0}, exception {1}", dllName, e); + m_log.Error(string.Format("Error loading plugin from {0}", dllName), e); return null; } } diff --git a/OpenSim/Services/Interfaces/IUserAccountService.cs b/OpenSim/Services/Interfaces/IUserAccountService.cs index 3dacf53453..a45bf8c79b 100644 --- a/OpenSim/Services/Interfaces/IUserAccountService.cs +++ b/OpenSim/Services/Interfaces/IUserAccountService.cs @@ -140,14 +140,20 @@ namespace OpenSim.Services.Interfaces UserAccount GetUserAccount(UUID scopeID, UUID userID); UserAccount GetUserAccount(UUID scopeID, string FirstName, string LastName); UserAccount GetUserAccount(UUID scopeID, string Email); - // Returns the list of avatars that matches both the search - // criterion and the scope ID passed - // + + /// + /// Returns the list of avatars that matches both the search criterion and the scope ID passed + /// + /// + /// + /// List GetUserAccounts(UUID scopeID, string query); - // Store the data given, wich replaces the sotred data, therefore - // must be complete. - // + /// + /// Store the data given, wich replaces the sotred data, therefore must be complete. + /// + /// + /// bool StoreUserAccount(UserAccount data); } -} +} \ No newline at end of file diff --git a/OpenSim/Tests/Common/Mock/MockUserAccountService.cs b/OpenSim/Tests/Common/Mock/MockUserAccountService.cs new file mode 100644 index 0000000000..f5d758a8c2 --- /dev/null +++ b/OpenSim/Tests/Common/Mock/MockUserAccountService.cs @@ -0,0 +1,45 @@ +/* + * 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 OpenSimulator 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.Collections.Generic; +using Nini.Config; +using OpenMetaverse; +using OpenSim.Services.Interfaces; + +namespace OpenSim.Tests.Common.Mock +{ + public class MockUserAccountService : IUserAccountService + { + public MockUserAccountService(IConfigSource config) {} + + public UserAccount GetUserAccount(UUID scopeID, UUID userID) { return new UserAccount(); } + public UserAccount GetUserAccount(UUID scopeID, string FirstName, string LastName) { return new UserAccount(); } + public UserAccount GetUserAccount(UUID scopeID, string Email) { return new UserAccount(); } + public List GetUserAccounts(UUID scopeID, string query) { return new List(); } + public bool StoreUserAccount(UserAccount data) { return true; } + } +} \ No newline at end of file diff --git a/OpenSim/Tests/Common/Mock/TestScene.cs b/OpenSim/Tests/Common/Mock/TestScene.cs index 076cb7a36a..01f2c146e8 100644 --- a/OpenSim/Tests/Common/Mock/TestScene.cs +++ b/OpenSim/Tests/Common/Mock/TestScene.cs @@ -65,6 +65,6 @@ namespace OpenSim.Tests.Common.Mock public AsyncSceneObjectGroupDeleter SceneObjectGroupDeleter { get { return m_asyncSceneObjectDeleter; } - } + } } -} +} \ No newline at end of file diff --git a/OpenSim/Tests/Common/Setup/SceneSetupHelpers.cs b/OpenSim/Tests/Common/Setup/SceneSetupHelpers.cs index 9e718f6a1c..ab3e7cb976 100644 --- a/OpenSim/Tests/Common/Setup/SceneSetupHelpers.cs +++ b/OpenSim/Tests/Common/Setup/SceneSetupHelpers.cs @@ -128,7 +128,7 @@ namespace OpenSim.Tests.Common.Setup /// Starts real inventory and asset services, as opposed to mock ones, if true /// public static TestScene SetupScene( - string name, UUID id, uint x, uint y, String realServices) + string name, UUID id, uint x, uint y, String realServices) { bool newScene = false; @@ -179,15 +179,16 @@ namespace OpenSim.Tests.Common.Setup StartAssetService(testScene, true); else StartAssetService(testScene, false); + if (realServices.Contains("inventory")) StartInventoryService(testScene, true); else StartInventoryService(testScene, false); + if (realServices.Contains("grid")) StartGridService(testScene, true); - if (realServices.Contains("useraccounts")) - StartUserAccountService(testScene, true); - + + StartUserAccountService(testScene, realServices.Contains("useraccounts")); } // If not, make sure the shared module gets references to this new scene else @@ -196,9 +197,13 @@ namespace OpenSim.Tests.Common.Setup m_assetService.RegionLoaded(testScene); m_inventoryService.AddRegion(testScene); m_inventoryService.RegionLoaded(testScene); + m_userAccountService.AddRegion(testScene); + m_userAccountService.RegionLoaded(testScene); } + m_inventoryService.PostInitialise(); m_assetService.PostInitialise(); + m_userAccountService.PostInitialise(); testScene.SetModuleInterfaces(); @@ -209,6 +214,11 @@ namespace OpenSim.Tests.Common.Setup physicsPluginManager.LoadPluginsFromAssembly("Physics/OpenSim.Region.Physics.BasicPhysicsPlugin.dll"); testScene.PhysicsScene = physicsPluginManager.GetPhysicsScene("basicphysics", "ZeroMesher", new IniConfigSource(), "test"); + + m_assetService = null; + m_inventoryService = null; + m_gridService = null; + m_userAccountService = null; return testScene; } @@ -273,6 +283,11 @@ namespace OpenSim.Tests.Common.Setup //testScene.AddRegionModule(m_gridService.Name, m_gridService); } + /// + /// Start a user account service, whether real or mock + /// + /// + /// Starts a real service if true, a mock service if not private static void StartUserAccountService(Scene testScene, bool real) { IConfigSource config = new IniConfigSource(); @@ -280,8 +295,14 @@ namespace OpenSim.Tests.Common.Setup config.AddConfig("UserAccountService"); config.Configs["Modules"].Set("UserAccountServices", "LocalUserAccountServicesConnector"); config.Configs["UserAccountService"].Set("StorageProvider", "OpenSim.Data.Null.dll"); + if (real) - config.Configs["UserAccountService"].Set("LocalServiceModule", "OpenSim.Services.UserAccountService.dll:UserAccountService"); + config.Configs["UserAccountService"].Set( + "LocalServiceModule", "OpenSim.Services.UserAccountService.dll:UserAccountService"); + else + config.Configs["UserAccountService"].Set( + "LocalServiceModule", "OpenSim.Tests.Common.dll:MockUserAccountService"); + if (m_userAccountService == null) { ISharedRegionModule userAccountService = new LocalUserAccountServicesConnector(); @@ -292,10 +313,9 @@ namespace OpenSim.Tests.Common.Setup // config.Configs["GridService"].Set("LocalServiceModule", "OpenSim.Tests.Common.dll:TestGridService"); m_userAccountService.AddRegion(testScene); m_userAccountService.RegionLoaded(testScene); - //testScene.AddRegionModule(m_gridService.Name, m_gridService); + testScene.AddRegionModule(m_userAccountService.Name, m_userAccountService); } - /// /// Setup modules for a scene using their default settings. /// From aad17e751383069b799c6a78a3ac4e0ca1020a4d Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 12 Mar 2010 20:29:17 +0000 Subject: [PATCH 15/28] Simplify database setup and remove migration problems by moving all sqlite config-include settings to a separate file for standalone Update information in StandaloneCommon.ini.example to reflect this Remove ISharedRegionModule interfaces from all SimianGrid connector classes temporarily since this stopped standalone from working (due to absence of AssetURI settings, etc.). Solution here may be to create separate region module connectors as done by local/grid/hypergrid so that loading can be controlled via include files Or otherwise work out how to stop these modules from being loaded for all OpenSim invocations --- .../SimianGrid/SimianAssetServiceConnector.cs | 2 +- .../SimianAuthenticationServiceConnector.cs | 2 +- .../SimianAvatarServiceConnector.cs | 2 +- .../SimianFriendsServiceConnector.cs | 2 +- .../SimianGrid/SimianGridServiceConnector.cs | 2 +- .../SimianInventoryServiceConnector.cs | 2 +- .../SimianPresenceServiceConnector.cs | 2 +- .../Connectors/SimianGrid/SimianProfiles.cs | 2 +- .../SimianUserAccountServiceConnector.cs | 2 +- .../Common/Mock/MockUserAccountService.cs | 1 + .../Tests/Common/Setup/SceneSetupHelpers.cs | 3 +++ bin/config-include/Standalone.ini | 4 ---- .../StandaloneCommon.ini.example | 23 +++++++++++-------- .../storage/SQLiteStandalone.ini | 16 +++++++++++++ 14 files changed, 43 insertions(+), 22 deletions(-) create mode 100644 bin/config-include/storage/SQLiteStandalone.ini diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs index 9fb7723b1d..201bc7082f 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs @@ -46,7 +46,7 @@ namespace OpenSim.Services.Connectors.SimianGrid /// Connects to the SimianGrid asset service ///

o7>p1Bc1**?7I_c7WwrkMUiT*&-{8|^A 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

[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] - public class SimianAssetServiceConnector : IAssetService, ISharedRegionModule + public class SimianAssetServiceConnector : IAssetService { private static readonly ILog m_log = LogManager.GetLogger( diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianAuthenticationServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianAuthenticationServiceConnector.cs index ec66341477..25e04d7578 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianAuthenticationServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianAuthenticationServiceConnector.cs @@ -44,7 +44,7 @@ namespace OpenSim.Services.Connectors.SimianGrid /// Connects authentication/authorization to the SimianGrid backend ///
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] - public class SimianAuthenticationServiceConnector : IAuthenticationService, ISharedRegionModule + public class SimianAuthenticationServiceConnector : IAuthenticationService { private static readonly ILog m_log = LogManager.GetLogger( diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianAvatarServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianAvatarServiceConnector.cs index 220f143c78..08403b9644 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianAvatarServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianAvatarServiceConnector.cs @@ -48,7 +48,7 @@ namespace OpenSim.Services.Connectors.SimianGrid /// Connects avatar appearance data to the SimianGrid backend ///
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] - public class SimianAvatarServiceConnector : IAvatarService, ISharedRegionModule + public class SimianAvatarServiceConnector : IAvatarService { private static readonly ILog m_log = LogManager.GetLogger( diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianFriendsServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianFriendsServiceConnector.cs index 3952a8c3d0..856381d324 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianFriendsServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianFriendsServiceConnector.cs @@ -47,7 +47,7 @@ namespace OpenSim.Services.Connectors.SimianGrid /// Stores and retrieves friend lists from the SimianGrid backend ///
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] - public class SimianFriendsServiceConnector : IFriendsService, ISharedRegionModule + public class SimianFriendsServiceConnector : IFriendsService { private static readonly ILog m_log = LogManager.GetLogger( diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs index 16819d174c..c375076514 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs @@ -51,7 +51,7 @@ namespace OpenSim.Services.Connectors.SimianGrid /// backend ///
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] - public class SimianGridServiceConnector : IGridService, ISharedRegionModule + public class SimianGridServiceConnector : IGridService { private static readonly ILog m_log = LogManager.GetLogger( diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianInventoryServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianInventoryServiceConnector.cs index c8128999c0..9879295e19 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianInventoryServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianInventoryServiceConnector.cs @@ -61,7 +61,7 @@ namespace OpenSim.Services.Connectors.SimianGrid /// Connects avatar inventories to the SimianGrid backend ///
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] - public class SimianInventoryServiceConnector : IInventoryService, ISharedRegionModule + public class SimianInventoryServiceConnector : IInventoryService { private static readonly ILog m_log = LogManager.GetLogger( diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs index 65de1c513c..45d18241d9 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs @@ -51,7 +51,7 @@ namespace OpenSim.Services.Connectors.SimianGrid /// message routing) to the SimianGrid backend /// [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] - public class SimianPresenceServiceConnector : IPresenceService, ISharedRegionModule + public class SimianPresenceServiceConnector : IPresenceService { private static readonly ILog m_log = LogManager.GetLogger( diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs b/OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs index 1e19982da2..32f17ae105 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs @@ -60,7 +60,7 @@ namespace OpenSim.Services.Connectors.SimianGrid /// backend /// [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] - public class SimianProfiles : INonSharedRegionModule + public class SimianProfiles { private static readonly ILog m_log = LogManager.GetLogger( diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianUserAccountServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianUserAccountServiceConnector.cs index 14097d0bdc..708ced3a8f 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianUserAccountServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianUserAccountServiceConnector.cs @@ -47,7 +47,7 @@ namespace OpenSim.Services.Connectors.SimianGrid /// users) to the SimianGrid backend /// [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] - public class SimianUserAccountServiceConnector : IUserAccountService, ISharedRegionModule + public class SimianUserAccountServiceConnector : IUserAccountService { private static readonly ILog m_log = LogManager.GetLogger( diff --git a/OpenSim/Tests/Common/Mock/MockUserAccountService.cs b/OpenSim/Tests/Common/Mock/MockUserAccountService.cs index f5d758a8c2..0769c7aa16 100644 --- a/OpenSim/Tests/Common/Mock/MockUserAccountService.cs +++ b/OpenSim/Tests/Common/Mock/MockUserAccountService.cs @@ -34,6 +34,7 @@ namespace OpenSim.Tests.Common.Mock { public class MockUserAccountService : IUserAccountService { + public MockUserAccountService(IConfigSource config) {} public UserAccount GetUserAccount(UUID scopeID, UUID userID) { return new UserAccount(); } diff --git a/OpenSim/Tests/Common/Setup/SceneSetupHelpers.cs b/OpenSim/Tests/Common/Setup/SceneSetupHelpers.cs index ab3e7cb976..864e2aa7c3 100644 --- a/OpenSim/Tests/Common/Setup/SceneSetupHelpers.cs +++ b/OpenSim/Tests/Common/Setup/SceneSetupHelpers.cs @@ -215,6 +215,9 @@ namespace OpenSim.Tests.Common.Setup testScene.PhysicsScene = physicsPluginManager.GetPhysicsScene("basicphysics", "ZeroMesher", new IniConfigSource(), "test"); + // It's really not a good idea to use static variables as they carry over between tests, leading to + // problems that are extremely hard to debug. Really, these static fields need to be eliminated - + // tests using multiple regions that need to share modules need to find another solution. m_assetService = null; m_inventoryService = null; m_gridService = null; diff --git a/bin/config-include/Standalone.ini b/bin/config-include/Standalone.ini index 30113708a1..54e11af432 100644 --- a/bin/config-include/Standalone.ini +++ b/bin/config-include/Standalone.ini @@ -32,14 +32,12 @@ [AvatarService] LocalServiceModule = "OpenSim.Services.AvatarService.dll:AvatarService" - ConnectionString = "URI=file:avatars.db,version=3" [AuthorizationService] LocalServiceModule = "OpenSim.Services.AuthorizationService.dll:AuthorizationService" [AuthenticationService] LocalServiceModule = "OpenSim.Services.AuthenticationService.dll:PasswordAuthenticationService" - ConnectionString = "URI=file:auth.db,version=3" [GridService] LocalServiceModule = "OpenSim.Services.GridService.dll:GridService" @@ -52,7 +50,6 @@ [UserAccountService] LocalServiceModule = "OpenSim.Services.UserAccountService.dll:UserAccountService" - ConnectionString = "URI=file:userprofiles.db,version=3" ;; These are for creating new accounts AuthenticationService = "OpenSim.Services.AuthenticationService.dll:PasswordAuthenticationService" @@ -62,7 +59,6 @@ [FriendsService] LocalServiceModule = "OpenSim.Services.FriendsService.dll" - ConnectionString = "URI=file:friends.db,version=3" [Friends] Connector = "OpenSim.Services.FriendsService.dll" diff --git a/bin/config-include/StandaloneCommon.ini.example b/bin/config-include/StandaloneCommon.ini.example index 8e21a8c477..f89c67a779 100644 --- a/bin/config-include/StandaloneCommon.ini.example +++ b/bin/config-include/StandaloneCommon.ini.example @@ -1,19 +1,24 @@ +; This is the main configuration file for standalone OpenSim instances + [DatabaseService] ; - ;### Choose the DB + ; ### Choose the DB ; - ;--- For SQLite - StorageProvider = "OpenSim.Data.SQLite.dll" - ;--- For MySql + + ; SQLite + ; Uncomment this line if you want to use sqlite storage + Include-Storage = "config-include/storage/SQLiteStandalone.ini"; + + ; For MySql. + ; Uncomment these lines if you want to use mysql storage + ; Change the connection string to your db details ;StorageProvider = "OpenSim.Data.MySQL.dll" ;ConnectionString = "Data Source=localhost;Database=opensim;User ID=opensim;Password=***;" [AssetService] - DefaultAssetLoader = "OpenSim.Framework.AssetLoader.Filesystem.dll" AssetLoaderArgs = "assets/AssetSets.xml" - [Modules] ;; Choose 0 or 1 cache modules, and the corresponding config file, if it exists. ;; Copy the config .example file into your own .ini file and change configs there @@ -35,10 +40,10 @@ [GridService] ;; For in-memory region storage (default) - StorageProvider = "OpenSim.Data.Null.dll:NullRegionData" + StorageProvider = "OpenSim.Data.Null.dll:NullRegionData" ;;--- For MySql region storage (alternative) - ;StorageProvider = "OpenSim.Data.MySQL.dll:MySqlRegionData" - ;ConnectionString = "Data Source=localhost;Database=opensim;User ID=opensim;Password=***;" + ;StorageProvider = "OpenSim.Data.MySQL.dll:MySqlRegionData" + ;; Next, we can specify properties of regions, including default and fallback regions ;; The syntax is: Region_ = "" ;; where can be DefaultRegion, FallbackRegion, NoDirectLogin, Persistent, LockedOut diff --git a/bin/config-include/storage/SQLiteStandalone.ini b/bin/config-include/storage/SQLiteStandalone.ini new file mode 100644 index 0000000000..1ce03578f2 --- /dev/null +++ b/bin/config-include/storage/SQLiteStandalone.ini @@ -0,0 +1,16 @@ +; These are the initialization settings for running OpenSim Standalone with an SQLite database + +[DatabaseService] + StorageProvider = "OpenSim.Data.SQLite.dll" + +[AvatarService] + ConnectionString = "URI=file:avatars.db,version=3" + +[AuthenticationService] + ConnectionString = "URI=file:auth.db,version=3" + +[UserAccountService] + ConnectionString = "URI=file:userprofiles.db,version=3" + +[FriendsService] + ConnectionString = "URI=file:friends.db,version=3" From 0b5141d45bcd409544e909aedabc3e58e6a86a13 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Fri, 12 Mar 2010 13:16:44 -0800 Subject: [PATCH 16/28] Fixed SimianGrid connectors to gracefully exit if the required config sections are missing --- .../SimianGrid/SimianAssetServiceConnector.cs | 12 +++---- .../SimianAuthenticationServiceConnector.cs | 10 +++--- .../SimianAvatarServiceConnector.cs | 10 +++--- .../SimianFriendsServiceConnector.cs | 10 +++--- .../SimianGrid/SimianGridServiceConnector.cs | 10 +++--- .../SimianInventoryServiceConnector.cs | 10 +++--- .../SimianPresenceServiceConnector.cs | 32 +++++++++++-------- .../Connectors/SimianGrid/SimianProfiles.cs | 12 +++---- .../SimianUserAccountServiceConnector.cs | 13 ++++---- 9 files changed, 63 insertions(+), 56 deletions(-) diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs index 201bc7082f..89aa9114d2 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs @@ -46,7 +46,7 @@ namespace OpenSim.Services.Connectors.SimianGrid /// Connects to the SimianGrid asset service /// [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] - public class SimianAssetServiceConnector : IAssetService + public class SimianAssetServiceConnector : IAssetService, ISharedRegionModule { private static readonly ILog m_log = LogManager.GetLogger( @@ -73,9 +73,9 @@ namespace OpenSim.Services.Connectors.SimianGrid public SimianAssetServiceConnector() { } public string Name { get { return "SimianAssetServiceConnector"; } } - public void AddRegion(Scene scene) { scene.RegisterModuleInterface(this); } - public void RemoveRegion(Scene scene) { scene.UnregisterModuleInterface(this); } - + public void AddRegion(Scene scene) { if (!String.IsNullOrEmpty(m_serverUrl)) { scene.RegisterModuleInterface(this); } } + public void RemoveRegion(Scene scene) { if (!String.IsNullOrEmpty(m_serverUrl)) { scene.UnregisterModuleInterface(this); } } + #endregion ISharedRegionModule public SimianAssetServiceConnector(IConfigSource source) @@ -88,8 +88,8 @@ namespace OpenSim.Services.Connectors.SimianGrid IConfig gridConfig = source.Configs["AssetService"]; if (gridConfig == null) { - m_log.Error("[ASSET CONNECTOR]: AssetService missing from OpenSim.ini"); - throw new Exception("Asset connector init error"); + m_log.Info("[ASSET CONNECTOR]: AssetService missing from OpenSim.ini, skipping SimianAssetServiceConnector"); + return; } string serviceUrl = gridConfig.GetString("AssetServerURI"); diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianAuthenticationServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianAuthenticationServiceConnector.cs index 25e04d7578..55aca36bb2 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianAuthenticationServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianAuthenticationServiceConnector.cs @@ -44,7 +44,7 @@ namespace OpenSim.Services.Connectors.SimianGrid /// Connects authentication/authorization to the SimianGrid backend /// [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] - public class SimianAuthenticationServiceConnector : IAuthenticationService + public class SimianAuthenticationServiceConnector : IAuthenticationService, ISharedRegionModule { private static readonly ILog m_log = LogManager.GetLogger( @@ -61,8 +61,8 @@ namespace OpenSim.Services.Connectors.SimianGrid public SimianAuthenticationServiceConnector() { } public string Name { get { return "SimianAuthenticationServiceConnector"; } } - public void AddRegion(Scene scene) { scene.RegisterModuleInterface(this); } - public void RemoveRegion(Scene scene) { scene.UnregisterModuleInterface(this); } + public void AddRegion(Scene scene) { if (!String.IsNullOrEmpty(m_serverUrl)) { scene.RegisterModuleInterface(this); } } + public void RemoveRegion(Scene scene) { if (!String.IsNullOrEmpty(m_serverUrl)) { scene.UnregisterModuleInterface(this); } } #endregion ISharedRegionModule @@ -76,8 +76,8 @@ namespace OpenSim.Services.Connectors.SimianGrid IConfig assetConfig = source.Configs["AuthenticationService"]; if (assetConfig == null) { - m_log.Error("[AUTH CONNECTOR]: AuthenticationService missing from OpenSim.ini"); - throw new Exception("Authentication connector init error"); + m_log.Info("[AUTH CONNECTOR]: AuthenticationService missing from OpenSim.ini, skipping SimianAuthenticationServiceConnector"); + return; } string serviceURI = assetConfig.GetString("AuthenticationServerURI"); diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianAvatarServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianAvatarServiceConnector.cs index 08403b9644..b5cef0c2ce 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianAvatarServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianAvatarServiceConnector.cs @@ -48,7 +48,7 @@ namespace OpenSim.Services.Connectors.SimianGrid /// Connects avatar appearance data to the SimianGrid backend /// [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] - public class SimianAvatarServiceConnector : IAvatarService + public class SimianAvatarServiceConnector : IAvatarService, ISharedRegionModule { private static readonly ILog m_log = LogManager.GetLogger( @@ -66,8 +66,8 @@ namespace OpenSim.Services.Connectors.SimianGrid public SimianAvatarServiceConnector() { } public string Name { get { return "SimianAvatarServiceConnector"; } } - public void AddRegion(Scene scene) { scene.RegisterModuleInterface(this); } - public void RemoveRegion(Scene scene) { scene.UnregisterModuleInterface(this); } + public void AddRegion(Scene scene) { if (!String.IsNullOrEmpty(m_serverUrl)) { scene.RegisterModuleInterface(this); } } + public void RemoveRegion(Scene scene) { if (!String.IsNullOrEmpty(m_serverUrl)) { scene.UnregisterModuleInterface(this); } } #endregion ISharedRegionModule @@ -81,8 +81,8 @@ namespace OpenSim.Services.Connectors.SimianGrid IConfig gridConfig = source.Configs["AvatarService"]; if (gridConfig == null) { - m_log.Error("[AVATAR CONNECTOR]: AvatarService missing from OpenSim.ini"); - throw new Exception("Avatar connector init error"); + m_log.Info("[AVATAR CONNECTOR]: AvatarService missing from OpenSim.ini, skipping SimianAvatarServiceConnector"); + return; } string serviceUrl = gridConfig.GetString("AvatarServerURI"); diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianFriendsServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianFriendsServiceConnector.cs index 856381d324..a569e91ee4 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianFriendsServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianFriendsServiceConnector.cs @@ -47,7 +47,7 @@ namespace OpenSim.Services.Connectors.SimianGrid /// Stores and retrieves friend lists from the SimianGrid backend /// [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] - public class SimianFriendsServiceConnector : IFriendsService + public class SimianFriendsServiceConnector : IFriendsService, ISharedRegionModule { private static readonly ILog m_log = LogManager.GetLogger( @@ -64,8 +64,8 @@ namespace OpenSim.Services.Connectors.SimianGrid public SimianFriendsServiceConnector() { } public string Name { get { return "SimianFriendsServiceConnector"; } } - public void AddRegion(Scene scene) { scene.RegisterModuleInterface(this); } - public void RemoveRegion(Scene scene) { scene.UnregisterModuleInterface(this); } + public void AddRegion(Scene scene) { if (!String.IsNullOrEmpty(m_serverUrl)) { scene.RegisterModuleInterface(this); } } + public void RemoveRegion(Scene scene) { if (!String.IsNullOrEmpty(m_serverUrl)) { scene.UnregisterModuleInterface(this); } } #endregion ISharedRegionModule @@ -79,8 +79,8 @@ namespace OpenSim.Services.Connectors.SimianGrid IConfig assetConfig = source.Configs["FriendsService"]; if (assetConfig == null) { - m_log.Error("[FRIENDS CONNECTOR]: FriendsService missing from OpenSim.ini"); - throw new Exception("Friends connector init error"); + m_log.Info("[FRIENDS CONNECTOR]: FriendsService missing from OpenSim.ini, skipping SimianFriendsServiceConnector"); + return; } string serviceURI = assetConfig.GetString("FriendsServerURI"); diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs index c375076514..2e600f0b3d 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs @@ -51,7 +51,7 @@ namespace OpenSim.Services.Connectors.SimianGrid /// backend /// [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] - public class SimianGridServiceConnector : IGridService + public class SimianGridServiceConnector : IGridService, ISharedRegionModule { private static readonly ILog m_log = LogManager.GetLogger( @@ -68,8 +68,8 @@ namespace OpenSim.Services.Connectors.SimianGrid public SimianGridServiceConnector() { } public string Name { get { return "SimianGridServiceConnector"; } } - public void AddRegion(Scene scene) { scene.RegisterModuleInterface(this); } - public void RemoveRegion(Scene scene) { scene.UnregisterModuleInterface(this); } + public void AddRegion(Scene scene) { if (!String.IsNullOrEmpty(m_serverUrl)) { scene.RegisterModuleInterface(this); } } + public void RemoveRegion(Scene scene) { if (!String.IsNullOrEmpty(m_serverUrl)) { scene.UnregisterModuleInterface(this); } } #endregion ISharedRegionModule @@ -83,8 +83,8 @@ namespace OpenSim.Services.Connectors.SimianGrid IConfig gridConfig = source.Configs["GridService"]; if (gridConfig == null) { - m_log.Error("[GRID CONNECTOR]: GridService missing from OpenSim.ini"); - throw new Exception("Grid connector init error"); + m_log.Info("[GRID CONNECTOR]: GridService missing from OpenSim.ini, skipping SimianGridServiceConnector"); + return; } string serviceUrl = gridConfig.GetString("GridServerURI"); diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianInventoryServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianInventoryServiceConnector.cs index 9879295e19..a50ecbc9a8 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianInventoryServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianInventoryServiceConnector.cs @@ -61,7 +61,7 @@ namespace OpenSim.Services.Connectors.SimianGrid /// Connects avatar inventories to the SimianGrid backend /// [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] - public class SimianInventoryServiceConnector : IInventoryService + public class SimianInventoryServiceConnector : IInventoryService, ISharedRegionModule { private static readonly ILog m_log = LogManager.GetLogger( @@ -80,8 +80,8 @@ namespace OpenSim.Services.Connectors.SimianGrid public SimianInventoryServiceConnector() { } public string Name { get { return "SimianInventoryServiceConnector"; } } - public void AddRegion(Scene scene) { scene.RegisterModuleInterface(this); } - public void RemoveRegion(Scene scene) { scene.UnregisterModuleInterface(this); } + public void AddRegion(Scene scene) { if (!String.IsNullOrEmpty(m_serverUrl)) { scene.RegisterModuleInterface(this); } } + public void RemoveRegion(Scene scene) { if (!String.IsNullOrEmpty(m_serverUrl)) { scene.UnregisterModuleInterface(this); } } #endregion ISharedRegionModule @@ -95,8 +95,8 @@ namespace OpenSim.Services.Connectors.SimianGrid IConfig gridConfig = source.Configs["InventoryService"]; if (gridConfig == null) { - m_log.Error("[INVENTORY CONNECTOR]: InventoryService missing from OpenSim.ini"); - throw new Exception("Inventory connector init error"); + m_log.Info("[INVENTORY CONNECTOR]: InventoryService missing from OpenSim.ini, skipping SimianInventoryServiceConnector"); + return; } string serviceUrl = gridConfig.GetString("InventoryServerURI"); diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs index 45d18241d9..542093f83f 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs @@ -51,7 +51,7 @@ namespace OpenSim.Services.Connectors.SimianGrid /// message routing) to the SimianGrid backend /// [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] - public class SimianPresenceServiceConnector : IPresenceService + public class SimianPresenceServiceConnector : IPresenceService, ISharedRegionModule { private static readonly ILog m_log = LogManager.GetLogger( @@ -70,23 +70,29 @@ namespace OpenSim.Services.Connectors.SimianGrid public string Name { get { return "SimianPresenceServiceConnector"; } } public void AddRegion(Scene scene) { - scene.RegisterModuleInterface(this); + if (!String.IsNullOrEmpty(m_serverUrl)) + { + scene.RegisterModuleInterface(this); - scene.EventManager.OnMakeRootAgent += MakeRootAgentHandler; - scene.EventManager.OnNewClient += NewClientHandler; - scene.EventManager.OnSignificantClientMovement += SignificantClientMovementHandler; + scene.EventManager.OnMakeRootAgent += MakeRootAgentHandler; + scene.EventManager.OnNewClient += NewClientHandler; + scene.EventManager.OnSignificantClientMovement += SignificantClientMovementHandler; - LogoutRegionAgents(scene.RegionInfo.RegionID); + LogoutRegionAgents(scene.RegionInfo.RegionID); + } } public void RemoveRegion(Scene scene) { - scene.UnregisterModuleInterface(this); + if (!String.IsNullOrEmpty(m_serverUrl)) + { + scene.UnregisterModuleInterface(this); - scene.EventManager.OnMakeRootAgent -= MakeRootAgentHandler; - scene.EventManager.OnNewClient -= NewClientHandler; - scene.EventManager.OnSignificantClientMovement -= SignificantClientMovementHandler; + scene.EventManager.OnMakeRootAgent -= MakeRootAgentHandler; + scene.EventManager.OnNewClient -= NewClientHandler; + scene.EventManager.OnSignificantClientMovement -= SignificantClientMovementHandler; - LogoutRegionAgents(scene.RegionInfo.RegionID); + LogoutRegionAgents(scene.RegionInfo.RegionID); + } } #endregion ISharedRegionModule @@ -101,8 +107,8 @@ namespace OpenSim.Services.Connectors.SimianGrid IConfig gridConfig = source.Configs["PresenceService"]; if (gridConfig == null) { - m_log.Error("[PRESENCE CONNECTOR]: PresenceService missing from OpenSim.ini"); - throw new Exception("Presence connector init error"); + m_log.Info("[PRESENCE CONNECTOR]: PresenceService missing from OpenSim.ini, skipping SimianPresenceServiceConnector"); + return; } string serviceUrl = gridConfig.GetString("PresenceServerURI"); diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs b/OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs index 32f17ae105..b3b171cebc 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs @@ -60,7 +60,7 @@ namespace OpenSim.Services.Connectors.SimianGrid /// backend /// [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] - public class SimianProfiles + public class SimianProfiles : INonSharedRegionModule { private static readonly ILog m_log = LogManager.GetLogger( @@ -69,15 +69,15 @@ namespace OpenSim.Services.Connectors.SimianGrid private string m_serverUrl = String.Empty; #region INonSharedRegionModule - + public Type ReplaceableInterface { get { return null; } } public void RegionLoaded(Scene scene) { } public void Close() { } public SimianProfiles() { } public string Name { get { return "SimianProfiles"; } } - public void AddRegion(Scene scene) { CheckEstateManager(scene); scene.EventManager.OnClientConnect += ClientConnectHandler; } - public void RemoveRegion(Scene scene) { scene.EventManager.OnClientConnect -= ClientConnectHandler; } + public void AddRegion(Scene scene) { if (!String.IsNullOrEmpty(m_serverUrl)) { CheckEstateManager(scene); scene.EventManager.OnClientConnect += ClientConnectHandler; } } + public void RemoveRegion(Scene scene) { if (!String.IsNullOrEmpty(m_serverUrl)) { scene.EventManager.OnClientConnect -= ClientConnectHandler; } } #endregion INonSharedRegionModule @@ -91,8 +91,8 @@ namespace OpenSim.Services.Connectors.SimianGrid IConfig gridConfig = source.Configs["UserAccountService"]; if (gridConfig == null) { - m_log.Error("[PROFILES]: UserAccountService missing from OpenSim.ini"); - throw new Exception("Profiles init error"); + m_log.Error("[PROFILES]: UserAccountService missing from OpenSim.ini, skipping SimianProfiles"); + return; } string serviceUrl = gridConfig.GetString("UserAccountServerURI"); diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianUserAccountServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianUserAccountServiceConnector.cs index 708ced3a8f..855b2137db 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianUserAccountServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianUserAccountServiceConnector.cs @@ -47,14 +47,14 @@ namespace OpenSim.Services.Connectors.SimianGrid /// users) to the SimianGrid backend /// [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] - public class SimianUserAccountServiceConnector : IUserAccountService + public class SimianUserAccountServiceConnector : IUserAccountService, ISharedRegionModule { private static readonly ILog m_log = LogManager.GetLogger( MethodBase.GetCurrentMethod().DeclaringType); private string m_serverUrl = String.Empty; - private ExpiringCache m_accountCache = new ExpiringCache(); + private ExpiringCache m_accountCache; #region ISharedRegionModule @@ -65,8 +65,8 @@ namespace OpenSim.Services.Connectors.SimianGrid public SimianUserAccountServiceConnector() { } public string Name { get { return "SimianUserAccountServiceConnector"; } } - public void AddRegion(Scene scene) { scene.RegisterModuleInterface(this); } - public void RemoveRegion(Scene scene) { scene.UnregisterModuleInterface(this); } + public void AddRegion(Scene scene) { if (!String.IsNullOrEmpty(m_serverUrl)) { scene.RegisterModuleInterface(this); } } + public void RemoveRegion(Scene scene) { if (!String.IsNullOrEmpty(m_serverUrl)) { scene.UnregisterModuleInterface(this); } } #endregion ISharedRegionModule @@ -80,8 +80,8 @@ namespace OpenSim.Services.Connectors.SimianGrid IConfig assetConfig = source.Configs["UserAccountService"]; if (assetConfig == null) { - m_log.Error("[ACCOUNT CONNECTOR]: UserAccountService missing from OpenSim.ini"); - throw new Exception("User account connector init error"); + m_log.Error("[ACCOUNT CONNECTOR]: UserAccountService missing from OpenSim.ini, skipping SimianUserAccountServiceConnector"); + return; } string serviceURI = assetConfig.GetString("UserAccountServerURI"); @@ -91,6 +91,7 @@ namespace OpenSim.Services.Connectors.SimianGrid throw new Exception("User account connector init error"); } + m_accountCache = new ExpiringCache(); m_serverUrl = serviceURI; } From 9e3cdc4da5483ce0187c7774fa274e99845da232 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Fri, 12 Mar 2010 13:28:16 -0800 Subject: [PATCH 17/28] Fixing the previous patch to work correctly with standalone mode --- .../Connectors/SimianGrid/SimianAssetServiceConnector.cs | 8 ++++---- .../SimianGrid/SimianAuthenticationServiceConnector.cs | 8 ++++---- .../Connectors/SimianGrid/SimianAvatarServiceConnector.cs | 8 ++++---- .../SimianGrid/SimianFriendsServiceConnector.cs | 8 ++++---- .../Connectors/SimianGrid/SimianGridServiceConnector.cs | 8 ++++---- .../SimianGrid/SimianInventoryServiceConnector.cs | 8 ++++---- .../SimianGrid/SimianPresenceServiceConnector.cs | 8 ++++---- OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs | 8 ++++---- .../SimianGrid/SimianUserAccountServiceConnector.cs | 8 ++++---- 9 files changed, 36 insertions(+), 36 deletions(-) diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs index 89aa9114d2..3f00534700 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs @@ -88,15 +88,15 @@ namespace OpenSim.Services.Connectors.SimianGrid IConfig gridConfig = source.Configs["AssetService"]; if (gridConfig == null) { - m_log.Info("[ASSET CONNECTOR]: AssetService missing from OpenSim.ini, skipping SimianAssetServiceConnector"); - return; + m_log.Error("[ASSET CONNECTOR]: AssetService missing from OpenSim.ini"); + throw new Exception("Asset connector init error"); } string serviceUrl = gridConfig.GetString("AssetServerURI"); if (String.IsNullOrEmpty(serviceUrl)) { - m_log.Error("[ASSET CONNECTOR]: No AssetServerURI in section AssetService"); - throw new Exception("Asset connector init error"); + m_log.Info("[ASSET CONNECTOR]: No AssetServerURI in section AssetService, skipping SimianAssetServiceConnector"); + return; } if (!serviceUrl.EndsWith("/")) diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianAuthenticationServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianAuthenticationServiceConnector.cs index 55aca36bb2..0876efbaf0 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianAuthenticationServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianAuthenticationServiceConnector.cs @@ -76,15 +76,15 @@ namespace OpenSim.Services.Connectors.SimianGrid IConfig assetConfig = source.Configs["AuthenticationService"]; if (assetConfig == null) { - m_log.Info("[AUTH CONNECTOR]: AuthenticationService missing from OpenSim.ini, skipping SimianAuthenticationServiceConnector"); - return; + m_log.Error("[AUTH CONNECTOR]: AuthenticationService missing from OpenSim.ini"); + throw new Exception("Authentication connector init error"); } string serviceURI = assetConfig.GetString("AuthenticationServerURI"); if (String.IsNullOrEmpty(serviceURI)) { - m_log.Error("[AUTH CONNECTOR]: No Server URI named in section AuthenticationService"); - throw new Exception("Authentication connector init error"); + m_log.Info("[AUTH CONNECTOR]: No Server URI named in section AuthenticationService, skipping SimianAuthenticationServiceConnector"); + return; } m_serverUrl = serviceURI; diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianAvatarServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianAvatarServiceConnector.cs index b5cef0c2ce..697bb43132 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianAvatarServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianAvatarServiceConnector.cs @@ -81,15 +81,15 @@ namespace OpenSim.Services.Connectors.SimianGrid IConfig gridConfig = source.Configs["AvatarService"]; if (gridConfig == null) { - m_log.Info("[AVATAR CONNECTOR]: AvatarService missing from OpenSim.ini, skipping SimianAvatarServiceConnector"); - return; + m_log.Error("[AVATAR CONNECTOR]: AvatarService missing from OpenSim.ini"); + throw new Exception("Avatar connector init error"); } string serviceUrl = gridConfig.GetString("AvatarServerURI"); if (String.IsNullOrEmpty(serviceUrl)) { - m_log.Error("[AVATAR CONNECTOR]: No AvatarServerURI in section AvatarService"); - throw new Exception("Avatar connector init error"); + m_log.Info("[AVATAR CONNECTOR]: No AvatarServerURI in section AvatarService, skipping SimianAvatarServiceConnector"); + return; } if (!serviceUrl.EndsWith("/")) diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianFriendsServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianFriendsServiceConnector.cs index a569e91ee4..abb98a3389 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianFriendsServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianFriendsServiceConnector.cs @@ -79,15 +79,15 @@ namespace OpenSim.Services.Connectors.SimianGrid IConfig assetConfig = source.Configs["FriendsService"]; if (assetConfig == null) { - m_log.Info("[FRIENDS CONNECTOR]: FriendsService missing from OpenSim.ini, skipping SimianFriendsServiceConnector"); - return; + m_log.Error("[FRIENDS CONNECTOR]: FriendsService missing from OpenSim.ini"); + throw new Exception("Friends connector init error"); } string serviceURI = assetConfig.GetString("FriendsServerURI"); if (String.IsNullOrEmpty(serviceURI)) { - m_log.Error("[FRIENDS CONNECTOR]: No Server URI named in section FriendsService"); - throw new Exception("Friends connector init error"); + m_log.Info("[FRIENDS CONNECTOR]: No Server URI named in section FriendsService, skipping SimianFriendsServiceConnector"); + return; } m_serverUrl = serviceURI; diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs index 2e600f0b3d..ef943ec7cd 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs @@ -83,15 +83,15 @@ namespace OpenSim.Services.Connectors.SimianGrid IConfig gridConfig = source.Configs["GridService"]; if (gridConfig == null) { - m_log.Info("[GRID CONNECTOR]: GridService missing from OpenSim.ini, skipping SimianGridServiceConnector"); - return; + m_log.Error("[GRID CONNECTOR]: GridService missing from OpenSim.ini"); + throw new Exception("Grid connector init error"); } string serviceUrl = gridConfig.GetString("GridServerURI"); if (String.IsNullOrEmpty(serviceUrl)) { - m_log.Error("[GRID CONNECTOR]: No Server URI named in section GridService"); - throw new Exception("Grid connector init error"); + m_log.Info("[GRID CONNECTOR]: No Server URI named in section GridService, skipping SimianGridServiceConnector"); + return; } m_serverUrl = serviceUrl; diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianInventoryServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianInventoryServiceConnector.cs index a50ecbc9a8..a41e493c0c 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianInventoryServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianInventoryServiceConnector.cs @@ -95,15 +95,15 @@ namespace OpenSim.Services.Connectors.SimianGrid IConfig gridConfig = source.Configs["InventoryService"]; if (gridConfig == null) { - m_log.Info("[INVENTORY CONNECTOR]: InventoryService missing from OpenSim.ini, skipping SimianInventoryServiceConnector"); - return; + m_log.Error("[INVENTORY CONNECTOR]: InventoryService missing from OpenSim.ini"); + throw new Exception("Inventory connector init error"); } string serviceUrl = gridConfig.GetString("InventoryServerURI"); if (String.IsNullOrEmpty(serviceUrl)) { - m_log.Error("[INVENTORY CONNECTOR]: No Server URI named in section InventoryService"); - throw new Exception("Inventory connector init error"); + m_log.Info("[INVENTORY CONNECTOR]: No Server URI named in section InventoryService, skipping SimianInventoryServiceConnector"); + return; } // FIXME: Get the user server URL too diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs index 542093f83f..fa387ba695 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs @@ -107,15 +107,15 @@ namespace OpenSim.Services.Connectors.SimianGrid IConfig gridConfig = source.Configs["PresenceService"]; if (gridConfig == null) { - m_log.Info("[PRESENCE CONNECTOR]: PresenceService missing from OpenSim.ini, skipping SimianPresenceServiceConnector"); - return; + m_log.Error("[PRESENCE CONNECTOR]: PresenceService missing from OpenSim.ini"); + throw new Exception("Presence connector init error"); } string serviceUrl = gridConfig.GetString("PresenceServerURI"); if (String.IsNullOrEmpty(serviceUrl)) { - m_log.Error("[PRESENCE CONNECTOR]: No PresenceServerURI in section PresenceService"); - throw new Exception("Presence connector init error"); + m_log.Info("[PRESENCE CONNECTOR]: No PresenceServerURI in section PresenceService, skipping SimianPresenceServiceConnector"); + return; } m_serverUrl = serviceUrl; diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs b/OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs index b3b171cebc..3c937258c8 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs @@ -91,15 +91,15 @@ namespace OpenSim.Services.Connectors.SimianGrid IConfig gridConfig = source.Configs["UserAccountService"]; if (gridConfig == null) { - m_log.Error("[PROFILES]: UserAccountService missing from OpenSim.ini, skipping SimianProfiles"); - return; + m_log.Error("[PROFILES]: UserAccountService missing from OpenSim.ini"); + throw new Exception("Profiles init error"); } string serviceUrl = gridConfig.GetString("UserAccountServerURI"); if (String.IsNullOrEmpty(serviceUrl)) { - m_log.Error("[PROFILES]: No UserAccountServerURI in section UserAccountService"); - throw new Exception("Profiles init error"); + m_log.Info("[PROFILES]: No UserAccountServerURI in section UserAccountService, skipping SimianProfiles"); + return; } if (!serviceUrl.EndsWith("/")) diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianUserAccountServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianUserAccountServiceConnector.cs index 855b2137db..3a35d9a7a0 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianUserAccountServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianUserAccountServiceConnector.cs @@ -80,15 +80,15 @@ namespace OpenSim.Services.Connectors.SimianGrid IConfig assetConfig = source.Configs["UserAccountService"]; if (assetConfig == null) { - m_log.Error("[ACCOUNT CONNECTOR]: UserAccountService missing from OpenSim.ini, skipping SimianUserAccountServiceConnector"); - return; + m_log.Error("[ACCOUNT CONNECTOR]: UserAccountService missing from OpenSim.ini"); + throw new Exception("User account connector init error"); } string serviceURI = assetConfig.GetString("UserAccountServerURI"); if (String.IsNullOrEmpty(serviceURI)) { - m_log.Error("[ACCOUNT CONNECTOR]: No UserAccountServerURI in section UserAccountService"); - throw new Exception("User account connector init error"); + m_log.Info("[ACCOUNT CONNECTOR]: No UserAccountServerURI in section UserAccountService, skipping SimianUserAccountServiceConnector"); + return; } m_accountCache = new ExpiringCache(); From 19b4770fe7620b184060b57fe5fa4418c5010c14 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 12 Mar 2010 22:18:48 +0000 Subject: [PATCH 18/28] start laoding griduser local connector, though it isn't invoked by anything yet --- .../Resources/CoreModulePlugin.addin.xml | 3 ++ bin/config-include/Standalone.ini | 40 ++++++++++--------- 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/OpenSim/Region/CoreModules/Resources/CoreModulePlugin.addin.xml b/OpenSim/Region/CoreModules/Resources/CoreModulePlugin.addin.xml index 0195c03d4c..aaa318cabb 100644 --- a/OpenSim/Region/CoreModules/Resources/CoreModulePlugin.addin.xml +++ b/OpenSim/Region/CoreModules/Resources/CoreModulePlugin.addin.xml @@ -56,6 +56,9 @@ + + + diff --git a/bin/config-include/Standalone.ini b/bin/config-include/Standalone.ini index 54e11af432..92c215498e 100644 --- a/bin/config-include/Standalone.ini +++ b/bin/config-include/Standalone.ini @@ -5,17 +5,18 @@ ;; [Modules] - AssetServices = "LocalAssetServicesConnector" - InventoryServices = "LocalInventoryServicesConnector" - NeighbourServices = "LocalNeighbourServicesConnector" - AuthenticationServices = "LocalAuthenticationServicesConnector" - GridServices = "LocalGridServicesConnector" - PresenceServices = "LocalPresenceServicesConnector" - UserAccountServices = "LocalUserAccountServicesConnector" - SimulationServices = "LocalSimulationConnectorModule" - AvatarServices = "LocalAvatarServicesConnector" - EntityTransferModule = "BasicEntityTransferModule" - InventoryAccessModule = "BasicInventoryAccessModule" + AssetServices = "LocalAssetServicesConnector" + InventoryServices = "LocalInventoryServicesConnector" + NeighbourServices = "LocalNeighbourServicesConnector" + AuthenticationServices = "LocalAuthenticationServicesConnector" + GridServices = "LocalGridServicesConnector" + PresenceServices = "LocalPresenceServicesConnector" + UserAccountServices = "LocalUserAccountServicesConnector" + GridUserServices = "LocalGridUserServicesConnector" + SimulationServices = "LocalSimulationConnectorModule" + AvatarServices = "LocalAvatarServicesConnector" + EntityTransferModule = "BasicEntityTransferModule" + InventoryAccessModule = "BasicInventoryAccessModule" LibraryModule = true LLLoginServiceInConnector = true @@ -57,6 +58,9 @@ GridService = "OpenSim.Services.GridService.dll:GridService" InventoryService = "OpenSim.Services.InventoryService.dll:InventoryService" +[GridUserService] + LocalServiceModule = "OpenSim.Services.UserAccountService.dll:GridUserService" + [FriendsService] LocalServiceModule = "OpenSim.Services.FriendsService.dll" @@ -64,14 +68,14 @@ Connector = "OpenSim.Services.FriendsService.dll" [LoginService] - LocalServiceModule = "OpenSim.Services.LLLoginService.dll:LLLoginService" - UserAccountService = "OpenSim.Services.UserAccountService.dll:UserAccountService" + LocalServiceModule = "OpenSim.Services.LLLoginService.dll:LLLoginService" + UserAccountService = "OpenSim.Services.UserAccountService.dll:UserAccountService" AuthenticationService = "OpenSim.Services.AuthenticationService.dll:PasswordAuthenticationService" - InventoryService = "OpenSim.Services.InventoryService.dll:InventoryService" - PresenceService = "OpenSim.Services.PresenceService.dll:PresenceService" - GridService = "OpenSim.Services.GridService.dll:GridService" - AvatarService = "OpenSim.Services.AvatarService.dll:AvatarService" - FriendsService = "OpenSim.Services.FriendsService.dll:FriendsService" + InventoryService = "OpenSim.Services.InventoryService.dll:InventoryService" + PresenceService = "OpenSim.Services.PresenceService.dll:PresenceService" + GridService = "OpenSim.Services.GridService.dll:GridService" + AvatarService = "OpenSim.Services.AvatarService.dll:AvatarService" + FriendsService = "OpenSim.Services.FriendsService.dll:FriendsService" WelcomeMessage = "Welcome, Avatar!" From 3036aba875187923b4e4d8481d46334e53393107 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Fri, 12 Mar 2010 14:28:31 -0800 Subject: [PATCH 19/28] * Added a better check to the SimianGrid connectors to test if they are enabled or not. This method should work equally well with standalone or robust mode * Applying #4602 from Misterblu to add collision detection to BulletDotNET --- .../Framework/Scenes/SceneObjectPart.cs | 1 + .../BulletDotNETCharacter.cs | 33 +- .../BulletDotNETPlugin/BulletDotNETPrim.cs | 102 +- .../BulletDotNETPlugin/BulletDotNETScene.cs | 99 +- OpenSim/Region/Physics/OdePlugin/ODEPrim.cs | 4 +- .../SimianGrid/SimianAssetServiceConnector.cs | 35 +- .../SimianAuthenticationServiceConnector.cs | 27 +- .../SimianAvatarServiceConnector.cs | 35 +- .../SimianFriendsServiceConnector.cs | 27 +- .../Connectors/SimianGrid/SimianGrid.cs | 16 + .../SimianGrid/SimianGridServiceConnector.cs | 27 +- .../SimianInventoryServiceConnector.cs | 45 +- .../SimianPresenceServiceConnector.cs | 27 +- .../Connectors/SimianGrid/SimianProfiles.cs | 35 +- .../SimianUserAccountServiceConnector.cs | 29 +- bin/BulletDotNET.dll | Bin 58880 -> 58880 bytes bin/Newtonsoft.Json.XML | 11654 ++++++++-------- bin/libbulletnet.dll | Bin 360448 -> 369664 bytes 18 files changed, 6198 insertions(+), 5998 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 89672526dd..a2b98b9f85 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -2044,6 +2044,7 @@ namespace OpenSim.Region.Framework.Scenes { m_lastColliders.Remove(localID); } + if (m_parentGroup == null) return; if (m_parentGroup.IsDeleted) diff --git a/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETCharacter.cs b/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETCharacter.cs index 6a54705cb1..ac4e2b9c73 100644 --- a/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETCharacter.cs +++ b/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETCharacter.cs @@ -108,12 +108,11 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin private bool[] m_colliderarr = new bool[11]; private bool[] m_colliderGroundarr = new bool[11]; - - private BulletDotNETScene m_parent_scene; public int m_eventsubscription = 0; - // private CollisionEventUpdate CollisionEventsThisFrame = new CollisionEventUpdate(); + private CollisionEventUpdate CollisionEventsThisFrame = null; + private int m_requestedUpdateFrequency = 0; public BulletDotNETCharacter(string avName, BulletDotNETScene parent_scene, Vector3 pos, Vector3 size, float pid_d, float pid_p, float capsule_radius, float tensor, float density, float height_fudge_factor, float walk_divisor, float rundivisor) { @@ -212,7 +211,8 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin m_mass = Mass; Body = new btRigidBody(m_mass, m_bodyMotionState, Shell); - Body.setUserPointer(new IntPtr((int)Body.Handle)); + // this is used for self identification. User localID instead of body handle + Body.setUserPointer(new IntPtr((int)m_localID)); if (ClosestCastResult != null) ClosestCastResult.Dispose(); @@ -717,6 +717,7 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin public override void SubscribeEvents(int ms) { m_eventsubscription = ms; + m_requestedUpdateFrequency = ms; m_parent_scene.addCollisionEventReporting(this); } @@ -724,6 +725,7 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin { m_parent_scene.remCollisionEventReporting(this); m_eventsubscription = 0; + m_requestedUpdateFrequency = 0; } public override bool SubscribedEvents() @@ -733,6 +735,29 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin return false; } + public void AddCollision(uint collideWith, ContactPoint contact) + { + if (CollisionEventsThisFrame == null) + { + CollisionEventsThisFrame = new CollisionEventUpdate(); + } + CollisionEventsThisFrame.addCollider(collideWith, contact); + } + + public void SendCollisions() + { + if (m_eventsubscription >= m_requestedUpdateFrequency) + { + if (CollisionEventsThisFrame != null) + { + base.SendCollisionUpdate(CollisionEventsThisFrame); + } + CollisionEventsThisFrame = new CollisionEventUpdate(); + m_eventsubscription = 0; + } + return; + } + internal void Dispose() { if (Body.isInWorld()) diff --git a/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETPrim.cs b/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETPrim.cs index 920ed96ee7..dc3229a752 100644 --- a/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETPrim.cs +++ b/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETPrim.cs @@ -154,7 +154,8 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin private Vector3 _target_velocity; public int m_eventsubscription; - // private CollisionEventUpdate CollisionEventsThisFrame = null; + private int m_requestedUpdateFrequency = 0; + private CollisionEventUpdate CollisionEventsThisFrame = null; public volatile bool childPrim; @@ -595,6 +596,7 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin public override void SubscribeEvents(int ms) { m_eventsubscription = ms; + m_requestedUpdateFrequency = ms; _parent_scene.addCollisionEventReporting(this); } @@ -602,6 +604,7 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin { _parent_scene.remCollisionEventReporting(this); m_eventsubscription = 0; + m_requestedUpdateFrequency = 0; } public override bool SubscribedEvents() @@ -611,7 +614,28 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin #endregion + public void AddCollision(uint collideWith, ContactPoint contact) + { + if (CollisionEventsThisFrame == null) + { + CollisionEventsThisFrame = new CollisionEventUpdate(); + } + CollisionEventsThisFrame.addCollider(collideWith, contact); + } + public void SendCollisions() + { + if (m_eventsubscription >= m_requestedUpdateFrequency) + { + if (CollisionEventsThisFrame != null) + { + base.SendCollisionUpdate(CollisionEventsThisFrame); + } + CollisionEventsThisFrame = null; + // m_eventsubscription = 0; + } + return; + } internal void Dispose() { @@ -759,7 +783,7 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin { if (m_taintadd) { - m_log.Debug("[PHYSICS]: TaintAdd"); + // m_log.Debug("[PHYSICS]: TaintAdd"); changeadd(timestep); } @@ -771,7 +795,7 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin SetBody(Mass); else SetBody(0); - m_log.Debug("[PHYSICS]: GEOM_DOESNT_EXSIT"); + // m_log.Debug("[PHYSICS]: GEOM_DOESNT_EXSIT"); } if (prim_geom.Handle == IntPtr.Zero) @@ -782,31 +806,31 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin SetBody(Mass); else SetBody(0); - m_log.Debug("[PHYSICS]: GEOM_DOESNT_EXSIT"); + // m_log.Debug("[PHYSICS]: GEOM_DOESNT_EXSIT"); } if (!_position.ApproxEquals(m_taintposition, 0f)) { - m_log.Debug("[PHYSICS]: TaintMove"); + // m_log.Debug("[PHYSICS]: TaintMove"); changemove(timestep); } if (m_taintrot != _orientation) { - m_log.Debug("[PHYSICS]: TaintRotate"); + // m_log.Debug("[PHYSICS]: TaintRotate"); rotate(timestep); } // if (m_taintPhysics != m_isphysical && !(m_taintparent != _parent)) { - m_log.Debug("[PHYSICS]: TaintPhysics"); + // m_log.Debug("[PHYSICS]: TaintPhysics"); changePhysicsStatus(timestep); } // if (!_size.ApproxEquals(m_taintsize, 0f)) { - m_log.Debug("[PHYSICS]: TaintSize"); + // m_log.Debug("[PHYSICS]: TaintSize"); changesize(timestep); } @@ -814,43 +838,43 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin if (m_taintshape) { - m_log.Debug("[PHYSICS]: TaintShape"); + // m_log.Debug("[PHYSICS]: TaintShape"); changeshape(timestep); } // if (m_taintforce) { - m_log.Debug("[PHYSICS]: TaintForce"); + // m_log.Debug("[PHYSICS]: TaintForce"); changeAddForce(timestep); } if (m_taintaddangularforce) { - m_log.Debug("[PHYSICS]: TaintAngularForce"); + // m_log.Debug("[PHYSICS]: TaintAngularForce"); changeAddAngularForce(timestep); } if (!m_taintTorque.ApproxEquals(Vector3.Zero, 0.001f)) { - m_log.Debug("[PHYSICS]: TaintTorque"); + // m_log.Debug("[PHYSICS]: TaintTorque"); changeSetTorque(timestep); } if (m_taintdisable) { - m_log.Debug("[PHYSICS]: TaintDisable"); + // m_log.Debug("[PHYSICS]: TaintDisable"); changedisable(timestep); } if (m_taintselected != m_isSelected) { - m_log.Debug("[PHYSICS]: TaintSelected"); + // m_log.Debug("[PHYSICS]: TaintSelected"); changeSelectedStatus(timestep); } if (!m_taintVelocity.ApproxEquals(Vector3.Zero, 0.001f)) { - m_log.Debug("[PHYSICS]: TaintVelocity"); + // m_log.Debug("[PHYSICS]: TaintVelocity"); changevelocity(timestep); } if (m_taintparent != _parent) { - m_log.Debug("[PHYSICS]: TaintLink"); + // m_log.Debug("[PHYSICS]: TaintLink"); changelink(timestep); } if (m_taintCollidesWater != m_collidesWater) @@ -859,7 +883,7 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin } if (!m_angularlock.ApproxEquals(m_taintAngularLock, 0)) { - m_log.Debug("[PHYSICS]: TaintAngularLock"); + // m_log.Debug("[PHYSICS]: TaintAngularLock"); changeAngularLock(timestep); } if (m_taintremove) @@ -917,7 +941,7 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin private void changemove(float timestep) { - m_log.Debug("[PHYSICS]: _________ChangeMove"); + // m_log.Debug("[PHYSICS]: _________ChangeMove"); if (!m_isphysical) { tempTransform2 = Body.getWorldTransform(); @@ -977,7 +1001,7 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin private void rotate(float timestep) { - m_log.Debug("[PHYSICS]: _________ChangeRotate"); + // m_log.Debug("[PHYSICS]: _________ChangeRotate"); tempTransform2 = Body.getWorldTransform(); tempOrientation2 = new btQuaternion(_orientation.X, _orientation.Y, _orientation.Z, _orientation.W); tempTransform2.setRotation(tempOrientation2); @@ -1000,7 +1024,7 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin //Body = null; // TODO: dispose parts that make up body } - m_log.Debug("[PHYSICS]: _________ChangePhysics"); + // m_log.Debug("[PHYSICS]: _________ChangePhysics"); ProcessGeomCreation(); @@ -1092,7 +1116,7 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin // TODO: dispose parts that make up body } - m_log.Debug("[PHYSICS]: _________ChangeSize"); + // m_log.Debug("[PHYSICS]: _________ChangeSize"); SetCollisionShape(null); // Construction of new prim ProcessGeomCreation(); @@ -1297,13 +1321,13 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin // TODO: throw new NotImplementedException(); if (m_taintselected) { - Body.setCollisionFlags((int)ContactFlags.CF_NO_CONTACT_RESPONSE); + // Body.setCollisionFlags((int)ContactFlags.CF_NO_CONTACT_RESPONSE); disableBodySoft(); } else { - Body.setCollisionFlags(0 | (int)ContactFlags.CF_CUSTOM_MATERIAL_CALLBACK); + // Body.setCollisionFlags(0 | (int)ContactFlags.CF_CUSTOM_MATERIAL_CALLBACK); enableBodySoft(); } m_isSelected = m_taintselected; @@ -1605,6 +1629,11 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin enableBodySoft(); } */ + if (!Body.isActive()) + { + Body.clearForces(); + enableBodySoft(); + } // 35x10 = 350n times the mass per second applied maximum. float nmax = 35f * m_mass; @@ -1632,6 +1661,12 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin Body.applyCentralImpulse(tempAddForce); } } + else + { + // if no forces on the prim, make sure everything is zero + Body.clearForces(); + enableBodySoft(); + } } else { @@ -1985,7 +2020,7 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin public void CreateGeom(IntPtr m_targetSpace, IMesh p_mesh) { - m_log.Debug("[PHYSICS]: _________CreateGeom"); + // m_log.Debug("[PHYSICS]: _________CreateGeom"); if (p_mesh != null) { //_mesh = _parent_scene.mesher.CreateMesh(m_primName, _pbs, _size, _parent_scene.meshSculptLOD, IsPhysical); @@ -2042,7 +2077,7 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin // TODO: Set Collision Body Mesh // This sleeper is there to moderate how long it takes between // setting up the mesh and pre-processing it when we get rapid fire mesh requests on a single object - m_log.Debug("_________SetMesh"); + // m_log.Debug("_________SetMesh"); Thread.Sleep(10); //Kill Body so that mesh can re-make the geom @@ -2159,7 +2194,14 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin // Body = new btRigidBody(mass, tempMotionState1, prim_geom); //else - Body = new btRigidBody(mass, tempMotionState1, prim_geom, tempInertia1); + // Body = new btRigidBody(mass, tempMotionState1, prim_geom, tempInertia1); + if (Body == null) + { + Body = new btRigidBody(mass, tempMotionState1, prim_geom, tempInertia1); + // add localID so we can later map bullet object back to OpenSim object + Body.setUserPointer(new IntPtr((int)m_localID)); + } + if (prim_geom is btGImpactMeshShape) { @@ -2250,7 +2292,13 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin // Body = new btRigidBody(mass, tempMotionState1, prim_geom); //else - Body = new btRigidBody(mass, tempMotionState1, prim_geom, tempInertia1); + // Body = new btRigidBody(mass, tempMotionState1, prim_geom, tempInertia1); + if (Body == null) + { + Body = new btRigidBody(mass, tempMotionState1, prim_geom, tempInertia1); + // each body has the localID stored into it so we can identify collision objects + Body.setUserPointer(new IntPtr((int)m_localID)); + } if (prim_geom is btGImpactMeshShape) { diff --git a/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETScene.cs b/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETScene.cs index 9e048ab69c..85e34c1e3d 100644 --- a/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETScene.cs +++ b/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETScene.cs @@ -47,7 +47,9 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin // private string m_sceneIdentifier = string.Empty; private List m_characters = new List(); + private Dictionary m_charactersLocalID = new Dictionary(); private List m_prims = new List(); + private Dictionary m_primsLocalID = new Dictionary(); private List m_activePrims = new List(); private List m_taintedActors = new List(); private btDiscreteDynamicsWorld m_world; @@ -134,7 +136,7 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration); m_world = new btDiscreteDynamicsWorld(m_dispatcher, m_broadphase, m_solver, m_collisionConfiguration); m_world.setGravity(m_gravity); - //EnableCollisionInterface(); + EnableCollisionInterface(); } @@ -145,7 +147,16 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin avCapRadius, avStandupTensor, avDensity, avHeightFudgeFactor, avMovementDivisorWalk, avMovementDivisorRun); - m_characters.Add(chr); + try + { + m_characters.Add(chr); + m_charactersLocalID.Add(chr.m_localID, chr); + } + catch + { + // noop if it's already there + m_log.Debug("[PHYSICS] BulletDotNet: adding duplicate avatar localID"); + } AddPhysicsActorTaint(chr); return chr; } @@ -154,6 +165,7 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin { BulletDotNETCharacter chr = (BulletDotNETCharacter) actor; + m_charactersLocalID.Remove(chr.m_localID); m_characters.Remove(chr); m_world.removeRigidBody(chr.Body); m_world.removeCollisionObject(chr.Body); @@ -279,7 +291,7 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin prim.Move(timeStep); } } - float steps = m_world.stepSimulation(timeStep * 1000, 10, WorldTimeComp); + float steps = m_world.stepSimulation(timeStep, 10, WorldTimeComp); foreach (BulletDotNETCharacter chr in m_characters) { @@ -296,20 +308,67 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin } if (m_CollisionInterface != null) { - List collisions = m_CollisionInterface.GetContactList(); - lock (collisions) + List primsWithCollisions = new List(); + List charactersWithCollisions = new List(); + + // get the collisions that happened this tick + List collisions = m_CollisionInterface.GetContactList(); + // passed back the localID of the prim so we can associate the prim + foreach (BulletDotNET.ContactAddedCallbackHandler.ContactInfo ci in collisions) { - foreach (int pvalue in collisions) - { - System.Console.Write(string.Format("{0} ", pvalue)); - } + // ContactPoint = { contactPoint, contactNormal, penetrationDepth } + ContactPoint contact = new ContactPoint(new Vector3(ci.pX, ci.pY, ci.pZ), + new Vector3(ci.nX, ci.nY, ci.nZ), ci.depth); + + ProcessContact(ci.contact, ci.contactWith, contact, ref primsWithCollisions, ref charactersWithCollisions); + ProcessContact(ci.contactWith, ci.contact, contact, ref primsWithCollisions, ref charactersWithCollisions); + } m_CollisionInterface.Clear(); - + // for those prims and characters that had collisions cause collision events + foreach (BulletDotNETPrim bdnp in primsWithCollisions) + { + bdnp.SendCollisions(); + } + foreach (BulletDotNETCharacter bdnc in charactersWithCollisions) + { + bdnc.SendCollisions(); + } } return steps; } + private void ProcessContact(uint cont, uint contWith, ContactPoint contact, + ref List primsWithCollisions, + ref List charactersWithCollisions) + { + BulletDotNETPrim bdnp; + // collisions with a normal prim? + if (m_primsLocalID.TryGetValue(cont, out bdnp)) + { + // Added collision event to the prim. This creates a pile of events + // that will be sent to any subscribed listeners. + bdnp.AddCollision(contWith, contact); + if (!primsWithCollisions.Contains(bdnp)) + { + primsWithCollisions.Add(bdnp); + } + } + else + { + BulletDotNETCharacter bdnc; + // if not a prim, maybe it's one of the characters + if (m_charactersLocalID.TryGetValue(cont, out bdnc)) + { + bdnc.AddCollision(contWith, contact); + if (!charactersWithCollisions.Contains(bdnc)) + { + charactersWithCollisions.Add(bdnc); + } + } + } + } + public override void GetResults() { @@ -387,6 +446,7 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin m_terrainTransform = new btTransform(QuatIdentity, m_terrainPosition); m_terrainMotionState = new btDefaultMotionState(m_terrainTransform); TerrainBody = new btRigidBody(0, m_terrainMotionState, m_terrainShape); + TerrainBody.setUserPointer((IntPtr)0); m_world.addRigidBody(TerrainBody); @@ -459,6 +519,7 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin { lock (m_prims) { + m_primsLocalID.Clear(); foreach (BulletDotNETPrim prim in m_prims) { if (prim.Body != null) @@ -513,6 +574,7 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin m_world.removeRigidBody(body); } remActivePrim(prm); + m_primsLocalID.Remove(prm.m_localID); m_prims.Remove(prm); } @@ -686,9 +748,18 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin { if (!m_prims.Contains(pPrim)) { - m_prims.Add(pPrim); + try + { + m_prims.Add(pPrim); + m_primsLocalID.Add(pPrim.m_localID, pPrim); + } + catch + { + // noop if it's already there + m_log.Debug("[PHYSICS] BulletDotNet: adding duplicate prim localID"); + } m_world.addRigidBody(pPrim.Body); - m_log.Debug("ADDED"); + // m_log.Debug("[PHYSICS] added prim to scene"); } } } @@ -696,8 +767,8 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin { if (m_CollisionInterface == null) { - m_CollisionInterface = new ContactAddedCallbackHandler(); - m_world.SetCollisionAddedCallback(m_CollisionInterface); + m_CollisionInterface = new ContactAddedCallbackHandler(m_world); + // m_world.SetCollisionAddedCallback(m_CollisionInterface); } } diff --git a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs index 03736d157b..0720b5ee53 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs @@ -1575,11 +1575,11 @@ Console.WriteLine(" JointCreateFixed"); { //Console.WriteLine("Move " + m_primName); if (!d.BodyIsEnabled (Body)) d.BodyEnable (Body); // KF add 161009 - /* // NON-'VEHICLES' are dealt with here if (d.BodyIsEnabled(Body) && !m_angularlock.ApproxEquals(Vector3.Zero, 0.003f)) { d.Vector3 avel2 = d.BodyGetAngularVel(Body); + /* if (m_angularlock.X == 1) avel2.X = 0; if (m_angularlock.Y == 1) @@ -1587,8 +1587,8 @@ Console.WriteLine(" JointCreateFixed"); if (m_angularlock.Z == 1) avel2.Z = 0; d.BodySetAngularVel(Body, avel2.X, avel2.Y, avel2.Z); + */ } - */ //float PID_P = 900.0f; float m_mass = CalculateMass(); diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs index 3f00534700..7cb075e803 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs @@ -85,24 +85,27 @@ namespace OpenSim.Services.Connectors.SimianGrid public void Initialise(IConfigSource source) { - IConfig gridConfig = source.Configs["AssetService"]; - if (gridConfig == null) + if (Simian.IsSimianEnabled(source, "AssetServices")) { - m_log.Error("[ASSET CONNECTOR]: AssetService missing from OpenSim.ini"); - throw new Exception("Asset connector init error"); + IConfig gridConfig = source.Configs["AssetService"]; + if (gridConfig == null) + { + m_log.Error("[ASSET CONNECTOR]: AssetService missing from OpenSim.ini"); + throw new Exception("Asset connector init error"); + } + + string serviceUrl = gridConfig.GetString("AssetServerURI"); + if (String.IsNullOrEmpty(serviceUrl)) + { + m_log.Error("[ASSET CONNECTOR]: No AssetServerURI in section AssetService"); + throw new Exception("Asset connector init error"); + } + + if (!serviceUrl.EndsWith("/")) + serviceUrl = serviceUrl + '/'; + + m_serverUrl = serviceUrl; } - - string serviceUrl = gridConfig.GetString("AssetServerURI"); - if (String.IsNullOrEmpty(serviceUrl)) - { - m_log.Info("[ASSET CONNECTOR]: No AssetServerURI in section AssetService, skipping SimianAssetServiceConnector"); - return; - } - - if (!serviceUrl.EndsWith("/")) - serviceUrl = serviceUrl + '/'; - - m_serverUrl = serviceUrl; } #region IAssetService diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianAuthenticationServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianAuthenticationServiceConnector.cs index 0876efbaf0..6317b8711e 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianAuthenticationServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianAuthenticationServiceConnector.cs @@ -73,21 +73,24 @@ namespace OpenSim.Services.Connectors.SimianGrid public void Initialise(IConfigSource source) { - IConfig assetConfig = source.Configs["AuthenticationService"]; - if (assetConfig == null) + if (Simian.IsSimianEnabled(source, "AuthenticationServices")) { - m_log.Error("[AUTH CONNECTOR]: AuthenticationService missing from OpenSim.ini"); - throw new Exception("Authentication connector init error"); - } + IConfig assetConfig = source.Configs["AuthenticationService"]; + if (assetConfig == null) + { + m_log.Error("[AUTH CONNECTOR]: AuthenticationService missing from OpenSim.ini"); + throw new Exception("Authentication connector init error"); + } - string serviceURI = assetConfig.GetString("AuthenticationServerURI"); - if (String.IsNullOrEmpty(serviceURI)) - { - m_log.Info("[AUTH CONNECTOR]: No Server URI named in section AuthenticationService, skipping SimianAuthenticationServiceConnector"); - return; - } + string serviceURI = assetConfig.GetString("AuthenticationServerURI"); + if (String.IsNullOrEmpty(serviceURI)) + { + m_log.Error("[AUTH CONNECTOR]: No Server URI named in section AuthenticationService"); + throw new Exception("Authentication connector init error"); + } - m_serverUrl = serviceURI; + m_serverUrl = serviceURI; + } } public string Authenticate(UUID principalID, string password, int lifetime) diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianAvatarServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianAvatarServiceConnector.cs index 697bb43132..a18cb2286e 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianAvatarServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianAvatarServiceConnector.cs @@ -78,24 +78,27 @@ namespace OpenSim.Services.Connectors.SimianGrid public void Initialise(IConfigSource source) { - IConfig gridConfig = source.Configs["AvatarService"]; - if (gridConfig == null) + if (Simian.IsSimianEnabled(source, "AvatarServices")) { - m_log.Error("[AVATAR CONNECTOR]: AvatarService missing from OpenSim.ini"); - throw new Exception("Avatar connector init error"); + IConfig gridConfig = source.Configs["AvatarService"]; + if (gridConfig == null) + { + m_log.Error("[AVATAR CONNECTOR]: AvatarService missing from OpenSim.ini"); + throw new Exception("Avatar connector init error"); + } + + string serviceUrl = gridConfig.GetString("AvatarServerURI"); + if (String.IsNullOrEmpty(serviceUrl)) + { + m_log.Error("[AVATAR CONNECTOR]: No AvatarServerURI in section AvatarService"); + throw new Exception("Avatar connector init error"); + } + + if (!serviceUrl.EndsWith("/")) + serviceUrl = serviceUrl + '/'; + + m_serverUrl = serviceUrl; } - - string serviceUrl = gridConfig.GetString("AvatarServerURI"); - if (String.IsNullOrEmpty(serviceUrl)) - { - m_log.Info("[AVATAR CONNECTOR]: No AvatarServerURI in section AvatarService, skipping SimianAvatarServiceConnector"); - return; - } - - if (!serviceUrl.EndsWith("/")) - serviceUrl = serviceUrl + '/'; - - m_serverUrl = serviceUrl; } #region IAvatarService diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianFriendsServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianFriendsServiceConnector.cs index abb98a3389..b3ecc7e907 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianFriendsServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianFriendsServiceConnector.cs @@ -76,21 +76,24 @@ namespace OpenSim.Services.Connectors.SimianGrid public void Initialise(IConfigSource source) { - IConfig assetConfig = source.Configs["FriendsService"]; - if (assetConfig == null) + if (Simian.IsSimianEnabled(source, "FriendsServices")) { - m_log.Error("[FRIENDS CONNECTOR]: FriendsService missing from OpenSim.ini"); - throw new Exception("Friends connector init error"); - } + IConfig assetConfig = source.Configs["FriendsService"]; + if (assetConfig == null) + { + m_log.Error("[FRIENDS CONNECTOR]: FriendsService missing from OpenSim.ini"); + throw new Exception("Friends connector init error"); + } - string serviceURI = assetConfig.GetString("FriendsServerURI"); - if (String.IsNullOrEmpty(serviceURI)) - { - m_log.Info("[FRIENDS CONNECTOR]: No Server URI named in section FriendsService, skipping SimianFriendsServiceConnector"); - return; - } + string serviceURI = assetConfig.GetString("FriendsServerURI"); + if (String.IsNullOrEmpty(serviceURI)) + { + m_log.Error("[FRIENDS CONNECTOR]: No Server URI named in section FriendsService"); + throw new Exception("Friends connector init error"); + } - m_serverUrl = serviceURI; + m_serverUrl = serviceURI; + } } #region IFriendsService diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianGrid.cs b/OpenSim/Services/Connectors/SimianGrid/SimianGrid.cs index 41ed2f1646..c3de98ef58 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianGrid.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianGrid.cs @@ -25,7 +25,23 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +using System; using Mono.Addins; +using Nini.Config; [assembly: Addin("SimianGrid", "1.0")] [assembly: AddinDependency("OpenSim", "0.5")] + +public static class Simian +{ + public static bool IsSimianEnabled(IConfigSource config, string moduleName) + { + if (config.Configs["Modules"] != null) + { + string module = config.Configs["Modules"].GetString("AuthenticationServices"); + return !String.IsNullOrEmpty(module) && module.Contains("Simian"); + } + + return false; + } +} \ No newline at end of file diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs index ef943ec7cd..eebdf14b92 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs @@ -80,21 +80,24 @@ namespace OpenSim.Services.Connectors.SimianGrid public void Initialise(IConfigSource source) { - IConfig gridConfig = source.Configs["GridService"]; - if (gridConfig == null) + if (Simian.IsSimianEnabled(source, "GridServices")) { - m_log.Error("[GRID CONNECTOR]: GridService missing from OpenSim.ini"); - throw new Exception("Grid connector init error"); - } + IConfig gridConfig = source.Configs["GridService"]; + if (gridConfig == null) + { + m_log.Error("[GRID CONNECTOR]: GridService missing from OpenSim.ini"); + throw new Exception("Grid connector init error"); + } - string serviceUrl = gridConfig.GetString("GridServerURI"); - if (String.IsNullOrEmpty(serviceUrl)) - { - m_log.Info("[GRID CONNECTOR]: No Server URI named in section GridService, skipping SimianGridServiceConnector"); - return; - } + string serviceUrl = gridConfig.GetString("GridServerURI"); + if (String.IsNullOrEmpty(serviceUrl)) + { + m_log.Error("[GRID CONNECTOR]: No Server URI named in section GridService"); + throw new Exception("Grid connector init error"); + } - m_serverUrl = serviceUrl; + m_serverUrl = serviceUrl; + } } #region IGridService diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianInventoryServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianInventoryServiceConnector.cs index a41e493c0c..891782fdad 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianInventoryServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianInventoryServiceConnector.cs @@ -92,23 +92,38 @@ namespace OpenSim.Services.Connectors.SimianGrid public void Initialise(IConfigSource source) { - IConfig gridConfig = source.Configs["InventoryService"]; - if (gridConfig == null) + if (Simian.IsSimianEnabled(source, "InventoryServices")) { - m_log.Error("[INVENTORY CONNECTOR]: InventoryService missing from OpenSim.ini"); - throw new Exception("Inventory connector init error"); + IConfig gridConfig = source.Configs["InventoryService"]; + if (gridConfig == null) + { + m_log.Error("[INVENTORY CONNECTOR]: InventoryService missing from OpenSim.ini"); + throw new Exception("Inventory connector init error"); + } + + string serviceUrl = gridConfig.GetString("InventoryServerURI"); + if (String.IsNullOrEmpty(serviceUrl)) + { + m_log.Error("[INVENTORY CONNECTOR]: No Server URI named in section InventoryService"); + throw new Exception("Inventory connector init error"); + } + + m_serverUrl = serviceUrl; + + gridConfig = source.Configs["UserAccountService"]; + if (gridConfig != null) + { + serviceUrl = gridConfig.GetString("UserAccountServerURI"); + if (!String.IsNullOrEmpty(serviceUrl)) + m_userServerUrl = serviceUrl; + else + m_log.Info("[INVENTORY CONNECTOR]: No Server URI named in section UserAccountService"); + } + else + { + m_log.Warn("[INVENTORY CONNECTOR]: UserAccountService missing from OpenSim.ini"); + } } - - string serviceUrl = gridConfig.GetString("InventoryServerURI"); - if (String.IsNullOrEmpty(serviceUrl)) - { - m_log.Info("[INVENTORY CONNECTOR]: No Server URI named in section InventoryService, skipping SimianInventoryServiceConnector"); - return; - } - - // FIXME: Get the user server URL too - - m_serverUrl = serviceUrl; } /// diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs index fa387ba695..1b5edf4ba2 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs @@ -104,21 +104,24 @@ namespace OpenSim.Services.Connectors.SimianGrid public void Initialise(IConfigSource source) { - IConfig gridConfig = source.Configs["PresenceService"]; - if (gridConfig == null) + if (Simian.IsSimianEnabled(source, "PresenceServices")) { - m_log.Error("[PRESENCE CONNECTOR]: PresenceService missing from OpenSim.ini"); - throw new Exception("Presence connector init error"); - } + IConfig gridConfig = source.Configs["PresenceService"]; + if (gridConfig == null) + { + m_log.Error("[PRESENCE CONNECTOR]: PresenceService missing from OpenSim.ini"); + throw new Exception("Presence connector init error"); + } - string serviceUrl = gridConfig.GetString("PresenceServerURI"); - if (String.IsNullOrEmpty(serviceUrl)) - { - m_log.Info("[PRESENCE CONNECTOR]: No PresenceServerURI in section PresenceService, skipping SimianPresenceServiceConnector"); - return; - } + string serviceUrl = gridConfig.GetString("PresenceServerURI"); + if (String.IsNullOrEmpty(serviceUrl)) + { + m_log.Error("[PRESENCE CONNECTOR]: No PresenceServerURI in section PresenceService"); + throw new Exception("Presence connector init error"); + } - m_serverUrl = serviceUrl; + m_serverUrl = serviceUrl; + } } #region IPresenceService diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs b/OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs index 3c937258c8..9c226fb5b0 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs @@ -88,24 +88,27 @@ namespace OpenSim.Services.Connectors.SimianGrid public void Initialise(IConfigSource source) { - IConfig gridConfig = source.Configs["UserAccountService"]; - if (gridConfig == null) + if (Simian.IsSimianEnabled(source, "UserAccountServices")) { - m_log.Error("[PROFILES]: UserAccountService missing from OpenSim.ini"); - throw new Exception("Profiles init error"); + IConfig gridConfig = source.Configs["UserAccountService"]; + if (gridConfig == null) + { + m_log.Error("[PROFILES]: UserAccountService missing from OpenSim.ini"); + throw new Exception("Profiles init error"); + } + + string serviceUrl = gridConfig.GetString("UserAccountServerURI"); + if (String.IsNullOrEmpty(serviceUrl)) + { + m_log.Error("[PROFILES]: No UserAccountServerURI in section UserAccountService"); + throw new Exception("Profiles init error"); + } + + if (!serviceUrl.EndsWith("/")) + serviceUrl = serviceUrl + '/'; + + m_serverUrl = serviceUrl; } - - string serviceUrl = gridConfig.GetString("UserAccountServerURI"); - if (String.IsNullOrEmpty(serviceUrl)) - { - m_log.Info("[PROFILES]: No UserAccountServerURI in section UserAccountService, skipping SimianProfiles"); - return; - } - - if (!serviceUrl.EndsWith("/")) - serviceUrl = serviceUrl + '/'; - - m_serverUrl = serviceUrl; } private void ClientConnectHandler(IClientCore clientCore) diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianUserAccountServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianUserAccountServiceConnector.cs index 3a35d9a7a0..bb0ac57b98 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianUserAccountServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianUserAccountServiceConnector.cs @@ -77,22 +77,25 @@ namespace OpenSim.Services.Connectors.SimianGrid public void Initialise(IConfigSource source) { - IConfig assetConfig = source.Configs["UserAccountService"]; - if (assetConfig == null) + if (Simian.IsSimianEnabled(source, "UserAccountServices")) { - m_log.Error("[ACCOUNT CONNECTOR]: UserAccountService missing from OpenSim.ini"); - throw new Exception("User account connector init error"); - } + IConfig assetConfig = source.Configs["UserAccountService"]; + if (assetConfig == null) + { + m_log.Error("[ACCOUNT CONNECTOR]: UserAccountService missing from OpenSim.ini"); + throw new Exception("User account connector init error"); + } - string serviceURI = assetConfig.GetString("UserAccountServerURI"); - if (String.IsNullOrEmpty(serviceURI)) - { - m_log.Info("[ACCOUNT CONNECTOR]: No UserAccountServerURI in section UserAccountService, skipping SimianUserAccountServiceConnector"); - return; - } + string serviceURI = assetConfig.GetString("UserAccountServerURI"); + if (String.IsNullOrEmpty(serviceURI)) + { + m_log.Error("[ACCOUNT CONNECTOR]: No UserAccountServerURI in section UserAccountService, skipping SimianUserAccountServiceConnector"); + throw new Exception("User account connector init error"); + } - m_accountCache = new ExpiringCache(); - m_serverUrl = serviceURI; + m_accountCache = new ExpiringCache(); + m_serverUrl = serviceURI; + } } public UserAccount GetUserAccount(UUID scopeID, string firstName, string lastName) diff --git a/bin/BulletDotNET.dll b/bin/BulletDotNET.dll index 8abe03a849dd6c09ce6d17851ffc0b35505ae749..40c43484721f11588300459121af3bedd09fbfb4 100644 GIT binary patch literal 58880 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 literal 58880 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 FzW^vnxoQ9a diff --git a/bin/Newtonsoft.Json.XML b/bin/Newtonsoft.Json.XML index 5af3593d22..1a1e56cef3 100644 --- a/bin/Newtonsoft.Json.XML +++ b/bin/Newtonsoft.Json.XML @@ -1,5827 +1,5827 @@ - - - - Newtonsoft.Json.Net20 - - - - - Represents a reader that provides fast, non-cached, forward-only access to serialized Json data. - - - - - Represents a reader that provides fast, non-cached, forward-only access to serialized Json data. - - - - - Initializes a new instance of the class with the specified . - - - - - Reads the next JSON token from the stream. - - true if the next token was read successfully; false if there are no more tokens to read. - - - - Reads the next JSON token from the stream as a . - - A or a null reference if the next JSON token is null. - - - - Skips the children of the current token. - - - - - Sets the current token. - - The new token. - - - - Sets the current token and value. - - The new token. - The value. - - - - Sets the state based on current token type. - - - - - Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - - - - - Releases unmanaged and - optionally - managed resources - - true to release both managed and unmanaged resources; false to release only unmanaged resources. - - - - Changes the to Closed. - - - - - Gets the current reader state. - - The current reader state. - - - - Gets the quotation mark character used to enclose the value of a string. - - - - - Gets the type of the current Json token. - - - - - Gets the text value of the current Json token. - - - - - Gets The Common Language Runtime (CLR) type for the current Json token. - - - - - Gets the depth of the current token in the JSON document. - - The depth of the current token in the JSON document. - - - - Specifies the state of the reader. - - - - - The Read method has not been called. - - - - - The end of the file has been reached successfully. - - - - - Reader is at a property. - - - - - Reader is at the start of an object. - - - - - Reader is in an object. - - - - - Reader is at the start of an array. - - - - - Reader is in an array. - - - - - The Close method has been called. - - - - - Reader has just read a value. - - - - - Reader is at the start of a constructor. - - - - - Reader in a constructor. - - - - - An error occurred that prevents the read operation from continuing. - - - - - The end of the file has been reached successfully. - - - - - Initializes a new instance of the class. - - The stream. - - - - Initializes a new instance of the class. - - The stream. - if set to true the root object will be read as a JSON array. - The used when reading values from BSON. - - - - Reads the next JSON token from the stream as a . - - - A or a null reference if the next JSON token is null. - - - - - Reads the next JSON token from the stream. - - - true if the next token was read successfully; false if there are no more tokens to read. - - - - - Gets or sets a value indicating whether the root object will be read as a JSON array. - - - true if the root object will be read as a JSON array; otherwise, false. - - - - - Gets or sets the used when reading values from BSON. - - The used when reading values from BSON. - - - - Represents a writer that provides a fast, non-cached, forward-only way of generating Json data. - - - - - Represents a writer that provides a fast, non-cached, forward-only way of generating Json data. - - - - - Represents a writer that provides a fast, non-cached, forward-only way of generating Json data. - - - - - Creates an instance of the JsonWriter class. - - - - - Flushes whatever is in the buffer to the underlying streams and also flushes the underlying stream. - - - - - Closes this stream and the underlying stream. - - - - - Writes the beginning of a Json object. - - - - - Writes the end of a Json object. - - - - - Writes the beginning of a Json array. - - - - - Writes the end of an array. - - - - - Writes the start of a constructor with the given name. - - The name of the constructor. - - - - Writes the end constructor. - - - - - Writes the property name of a name/value pair on a Json object. - - The name of the property. - - - - Writes the end of the current Json object or array. - - - - - Writes the current token. - - The to read the token from. - - - - Writes the specified end token. - - The end token to write. - - - - Writes indent characters. - - - - - Writes the JSON value delimiter. - - - - - Writes an indent space. - - - - - Writes a null value. - - - - - Writes an undefined value. - - - - - Writes raw JSON without changing the writer's state. - - The raw JSON to write. - - - - Writes raw JSON where a value is expected and updates the writer's state. - - The raw JSON to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - An error will raised if the value cannot be written as a single JSON token. - - The value to write. - - - - Writes out a comment /*...*/ containing the specified text. - - Text to place inside the comment. - - - - Writes out the given white space. - - The string of white space characters. - - - - Gets the top. - - The top. - - - - Gets the state of the writer. - - - - - Indicates how the output is formatted. - - - - - Initializes a new instance of the class writing to the given . - - The container being written to. - - - - Initializes a new instance of the class. - - - - - Flushes whatever is in the buffer to the underlying streams and also flushes the underlying stream. - - - - - Closes this stream and the underlying stream. - - - - - Writes the beginning of a Json object. - - - - - Writes the beginning of a Json array. - - - - - Writes the start of a constructor with the given name. - - The name of the constructor. - - - - Writes the end. - - The token. - - - - Writes the property name of a name/value pair on a Json object. - - The name of the property. - - - - Writes a null value. - - - - - Writes an undefined value. - - - - - Writes raw JSON. - - The raw JSON to write. - - - - Writes out a comment /*...*/ containing the specified text. - - Text to place inside the comment. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Gets the token being writen. - - The token being writen. - - - - Initializes a new instance of the class. - - The stream. - - - - Flushes whatever is in the buffer to the underlying streams and also flushes the underlying stream. - - - - - Writes the end. - - The token. - - - - Writes out a comment /*...*/ containing the specified text. - - Text to place inside the comment. - - - - Writes the start of a constructor with the given name. - - The name of the constructor. - - - - Writes raw JSON. - - The raw JSON to write. - - - - Writes raw JSON where a value is expected and updates the writer's state. - - The raw JSON to write. - - - - Specifies how constructors are used when initializing objects during deserialization by the . - - - - - First attempt to use the public default constructor then fall back to single paramatized constructor. - - - - - Allow Json.NET to use a non-public default constructor. - - - - - Converts a binary value to and from a base 64 string value. - - - - - Converts an object to and from JSON. - - - - - Writes the JSON representation of the object. - - The to write to. - The value. - The calling serializer. - - - - Reads the JSON representation of the object. - - The to read from. - Type of the object. - The calling serializer. - The object value. - - - - Determines whether this instance can convert the specified object type. - - Type of the object. - - true if this instance can convert the specified object type; otherwise, false. - - - - - Writes the JSON representation of the object. - - The to write to. - The value. - The calling serializer. - - - - Reads the JSON representation of the object. - - The to read from. - Type of the object. - The calling serializer. - The object value. - - - - Determines whether this instance can convert the specified object type. - - Type of the object. - - true if this instance can convert the specified object type; otherwise, false. - - - - - Create a custom object - - - - - - Writes the JSON representation of the object. - - The to write to. - The value. - The calling serializer. - - - - Reads the JSON representation of the object. - - The to read from. - Type of the object. - The calling serializer. - The object value. - - - - Creates an object which will then be populated by the serializer. - - Type of the object. - - - - - Determines whether this instance can convert the specified object type. - - Type of the object. - - true if this instance can convert the specified object type; otherwise, false. - - - - - Converts a to and from JSON. - - - - - Writes the JSON representation of the object. - - The to write to. - The value. - The calling serializer. - - - - Reads the JSON representation of the object. - - The to read from. - Type of the object. - The calling serializer. - The object value. - - - - Determines whether this instance can convert the specified value type. - - Type of the value. - - true if this instance can convert the specified value type; otherwise, false. - - - - - Converts a to and from JSON. - - - - - Writes the JSON representation of the object. - - The to write to. - The value. - The calling serializer. - - - - Reads the JSON representation of the object. - - The to read from. - Type of the object. - The calling serializer. - The object value. - - - - Determines whether this instance can convert the specified value type. - - Type of the value. - - true if this instance can convert the specified value type; otherwise, false. - - - - - Provides a base class for converting a to and from JSON. - - - - - Determines whether this instance can convert the specified object type. - - Type of the object. - - true if this instance can convert the specified object type; otherwise, false. - - - - - Converts an to and from its name string value. - - - - - Writes the JSON representation of the object. - - The to write to. - The value. - The calling serializer. - - - - Reads the JSON representation of the object. - - The to read from. - Type of the object. - The calling serializer. - The object value. - - - - Determines whether this instance can convert the specified object type. - - Type of the object. - - true if this instance can convert the specified object type; otherwise, false. - - - - - Represents a view of a . - - - - - Initializes a new instance of the class. - - The name. - Type of the property. - - - - When overridden in a derived class, returns whether resetting an object changes its value. - - - true if resetting the component changes its value; otherwise, false. - - The component to test for reset capability. - - - - - When overridden in a derived class, gets the current value of the property on a component. - - - The value of a property for a given component. - - The component with the property for which to retrieve the value. - - - - - When overridden in a derived class, resets the value for this property of the component to the default value. - - The component with the property value that is to be reset to the default value. - - - - - When overridden in a derived class, sets the value of the component to a different value. - - The component with the property value that is to be set. - The new value. - - - - - When overridden in a derived class, determines a value indicating whether the value of this property needs to be persisted. - - - true if the property should be persisted; otherwise, false. - - The component with the property to be examined for persistence. - - - - - When overridden in a derived class, gets the type of the component this property is bound to. - - - A that represents the type of component this property is bound to. When the or methods are invoked, the object specified might be an instance of this type. - - - - - When overridden in a derived class, gets a value indicating whether this property is read-only. - - - true if the property is read-only; otherwise, false. - - - - - When overridden in a derived class, gets the type of the property. - - - A that represents the type of the property. - - - - - Gets the hash code for the name of the member. - - - - The hash code for the name of the member. - - - - - Represents a view of a . - - - - - Initializes a new instance of the class. - - The value. - - - - Returns the properties for this instance of a component. - - - A that represents the properties for this component instance. - - - - - Returns the properties for this instance of a component using the attribute array as a filter. - - An array of type that is used as a filter. - - A that represents the filtered properties for this component instance. - - - - - Returns a collection of custom attributes for this instance of a component. - - - An containing the attributes for this object. - - - - - Returns the class name of this instance of a component. - - - The class name of the object, or null if the class does not have a name. - - - - - Returns the name of this instance of a component. - - - The name of the object, or null if the object does not have a name. - - - - - Returns a type converter for this instance of a component. - - - A that is the converter for this object, or null if there is no for this object. - - - - - Returns the default event for this instance of a component. - - - An that represents the default event for this object, or null if this object does not have events. - - - - - Returns the default property for this instance of a component. - - - A that represents the default property for this object, or null if this object does not have properties. - - - - - Returns an editor of the specified type for this instance of a component. - - A that represents the editor for this object. - - An of the specified type that is the editor for this object, or null if the editor cannot be found. - - - - - Returns the events for this instance of a component using the specified attribute array as a filter. - - An array of type that is used as a filter. - - An that represents the filtered events for this component instance. - - - - - Returns the events for this instance of a component. - - - An that represents the events for this component instance. - - - - - Returns an object that contains the property described by the specified property descriptor. - - A that represents the property whose owner is to be found. - - An that represents the owner of the specified property. - - - - - Represents a raw JSON string. - - - - - Represents a value in JSON (string, integer, date, etc). - - - - - Represents an abstract JSON token. - - - - - Represents a collection of objects. - - The type of token - - - - Gets the with the specified key. - - - - - - Provides an interface to enable a class to return line and position information. - - - - - Gets a value indicating whether the class can return line information. - - - true if LineNumber and LinePosition can be provided; otherwise, false. - - - - - Gets the current line number. - - The current line number or 0 if no line information is available (for example, HasLineInfo returns false). - - - - Gets the current line position. - - The current line position or 0 if no line information is available (for example, HasLineInfo returns false). - - - - Compares the values of two tokens, including the values of all descendant tokens. - - The first to compare. - The second to compare. - true if the tokens are equal; otherwise false. - - - - Adds the specified content immediately after this token. - - A content object that contains simple content or a collection of content objects to be added after this token. - - - - Adds the specified content immediately before this token. - - A content object that contains simple content or a collection of content objects to be added before this token. - - - - Returns a collection of the ancestor tokens of this token. - - A collection of the ancestor tokens of this token. - - - - Returns a collection of the sibling tokens after this token, in document order. - - A collection of the sibling tokens after this tokens, in document order. - - - - Returns a collection of the sibling tokens before this token, in document order. - - A collection of the sibling tokens before this token, in document order. - - - - Gets the with the specified key converted to the specified type. - - The type to convert the token to. - The token key. - The converted token value. - - - - Returns a collection of the child tokens of this token, in document order. - - An of containing the child tokens of this , in document order. - - - - Returns a collection of the child tokens of this token, in document order, filtered by the specified type. - - The type to filter the child tokens on. - A containing the child tokens of this , in document order. - - - - Returns a collection of the child values of this token, in document order. - - The type to convert the values to. - A containing the child values of this , in document order. - - - - Removes this token from its parent. - - - - - Replaces this token with the specified token. - - The value. - - - - Writes this token to a . - - A into which this method will write. - A collection of which will be used when writing the token. - - - - Returns the indented JSON for this token. - - - The indented JSON for this token. - - - - - Returns the JSON for this token using the given formatting and converters. - - Indicates how the output is formatted. - A collection of which will be used when writing the token. - The JSON for this token using the given formatting and converters. - - - - Performs an explicit conversion from to . - - The value. - The result of the conversion. - - - - Performs an explicit conversion from to . - - The value. - The result of the conversion. - - - - Performs an explicit conversion from to . - - The value. - The result of the conversion. - - - - Performs an explicit conversion from to . - - The value. - The result of the conversion. - - - - Performs an explicit conversion from to . - - The value. - The result of the conversion. - - - - Performs an explicit conversion from to . - - The value. - The result of the conversion. - - - - Performs an explicit conversion from to . - - The value. - The result of the conversion. - - - - Performs an explicit conversion from to . - - The value. - The result of the conversion. - - - - Performs an explicit conversion from to . - - The value. - The result of the conversion. - - - - Performs an explicit conversion from to . - - The value. - The result of the conversion. - - - - Performs an explicit conversion from to . - - The value. - The result of the conversion. - - - - Performs an explicit conversion from to . - - The value. - The result of the conversion. - - - - Performs an explicit conversion from to . - - The value. - The result of the conversion. - - - - Performs an explicit conversion from to . - - The value. - The result of the conversion. - - - - Performs an explicit conversion from to . - - The value. - The result of the conversion. - - - - Performs an explicit conversion from to . - - The value. - The result of the conversion. - - - - Performs an explicit conversion from to . - - The value. - The result of the conversion. - - - - Performs an explicit conversion from to . - - The value. - The result of the conversion. - - - - Performs an explicit conversion from to . - - The value. - The result of the conversion. - - - - Performs an explicit conversion from to . - - The value. - The result of the conversion. - - - - Performs an implicit conversion from to . - - The value to create a from. - The initialized with the specified value. - - - - Performs an implicit conversion from to . - - The value to create a from. - The initialized with the specified value. - - - - Performs an implicit conversion from to . - - The value to create a from. - The initialized with the specified value. - - - - Performs an implicit conversion from to . - - The value to create a from. - The initialized with the specified value. - - - - Performs an implicit conversion from to . - - The value to create a from. - The initialized with the specified value. - - - - Performs an implicit conversion from to . - - The value to create a from. - The initialized with the specified value. - - - - Performs an implicit conversion from to . - - The value to create a from. - The initialized with the specified value. - - - - Performs an implicit conversion from to . - - The value to create a from. - The initialized with the specified value. - - - - Performs an implicit conversion from to . - - The value to create a from. - The initialized with the specified value. - - - - Performs an implicit conversion from to . - - The value to create a from. - The initialized with the specified value. - - - - Performs an implicit conversion from to . - - The value to create a from. - The initialized with the specified value. - - - - Performs an implicit conversion from to . - - The value to create a from. - The initialized with the specified value. - - - - Performs an implicit conversion from to . - - The value to create a from. - The initialized with the specified value. - - - - Performs an implicit conversion from to . - - The value to create a from. - The initialized with the specified value. - - - - Performs an implicit conversion from to . - - The value to create a from. - The initialized with the specified value. - - - - Performs an implicit conversion from to . - - The value to create a from. - The initialized with the specified value. - - - - Performs an implicit conversion from to . - - The value to create a from. - The initialized with the specified value. - - - - Performs an implicit conversion from to . - - The value to create a from. - The initialized with the specified value. - - - - Performs an implicit conversion from to . - - The value to create a from. - The initialized with the specified value. - - - - Performs an implicit conversion from to . - - The value to create a from. - The initialized with the specified value. - - - - Performs an implicit conversion from to . - - The value to create a from. - The initialized with the specified value. - - - - Performs an implicit conversion from to . - - The value to create a from. - The initialized with the specified value. - - - - Creates an for this token. - - An that can be used to read this token and its descendants. - - - - Creates a from an object. - - The object that will be used to create . - A with the value of the specified object - - - - Creates a from an object using the specified . - - The object that will be used to create . - The that will be used when reading the object. - A with the value of the specified object - - - - Creates a from a . - - An positioned at the token to read into this . - - An that contains the token and its descendant tokens - that were read from the reader. The runtime type of the token is determined - by the token type of the first token encountered in the reader. - - - - - Selects the token that matches the object path. - - - The object path from the current to the - to be returned. This must be a string of property names or array indexes separated - by periods, such as Tables[0].DefaultView[0].Price in C# or - Tables(0).DefaultView(0).Price in Visual Basic. - - The that matches the object path or a null reference if no matching token is found. - - - - Selects the token that matches the object path. - - - The object path from the current to the - to be returned. This must be a string of property names or array indexes separated - by periods, such as Tables[0].DefaultView[0].Price in C# or - Tables(0).DefaultView(0).Price in Visual Basic. - - A flag to indicate whether an error should be thrown if no token is found. - The that matches the object path. - - - - Gets a comparer that can compare two tokens for value equality. - - A that can compare two nodes for value equality. - - - - Gets or sets the parent. - - The parent. - - - - Gets the root of this . - - The root of this . - - - - Gets the node type for this . - - The type. - - - - Gets a value indicating whether this token has childen tokens. - - - true if this token has child values; otherwise, false. - - - - - Gets the next sibling token of this node. - - The that contains the next sibling token. - - - - Gets the previous sibling token of this node. - - The that contains the previous sibling token. - - - - Gets the with the specified key. - - The with the specified key. - - - - Get the first child token of this token. - - A containing the first child token of the . - - - - Get the last child token of this token. - - A containing the last child token of the . - - - - Initializes a new instance of the class from another object. - - A object to copy from. - - - - Initializes a new instance of the class with the given value. - - The value. - - - - Initializes a new instance of the class with the given value. - - The value. - - - - Initializes a new instance of the class with the given value. - - The value. - - - - Initializes a new instance of the class with the given value. - - The value. - - - - Initializes a new instance of the class with the given value. - - The value. - - - - Initializes a new instance of the class with the given value. - - The value. - - - - Initializes a new instance of the class with the given value. - - The value. - - - - Creates a comment with the given value. - - The value. - A comment with the given value. - - - - Creates a string with the given value. - - The value. - A string with the given value. - - - - Writes this token to a . - - A into which this method will write. - A collection of which will be used when writing the token. - - - - Indicates whether the current object is equal to another object of the same type. - - - true if the current object is equal to the parameter; otherwise, false. - - An object to compare with this object. - - - - Determines whether the specified is equal to the current . - - The to compare with the current . - - true if the specified is equal to the current ; otherwise, false. - - - The parameter is null. - - - - - Serves as a hash function for a particular type. - - - A hash code for the current . - - - - - Gets a value indicating whether this token has childen tokens. - - - true if this token has child values; otherwise, false. - - - - - Gets the node type for this . - - The type. - - - - Gets or sets the underlying token value. - - The underlying token value. - - - - Initializes a new instance of the class from another object. - - A object to copy from. - - - - Initializes a new instance of the class. - - The raw json. - - - - Creates an instance of with the content of the reader's current token. - - The reader. - An instance of with the content of the reader's current token. - - - - Indicating whether a property is required. - - - - - The property is not required. The default state. - - - - - The property must be defined in JSON but can be a null value. - - - - - The property must be defined in JSON and cannot be a null value. - - - - - Used to resolve references when serializing and deserializing JSON by the . - - - - - Resolves a reference to its object. - - The reference to resolve. - The object that - - - - Gets the reference for the sepecified object. - - The object to get a reference for. - The reference to the object. - - - - Determines whether the specified object is referenced. - - The object to test for a reference. - - true if the specified object is referenced; otherwise, false. - - - - - Adds a reference to the specified object. - - The reference. - The object to reference. - - - - Specifies reference handling options for the . - - - - - Do not preserve references when serializing types. - - - - - Preserve references when serializing into a JSON object structure. - - - - - Preserve references when serializing into a JSON array structure. - - - - - Preserve references when serializing. - - - - - Instructs the how to serialize the collection. - - - - - Instructs the how to serialize the object. - - - - - Initializes a new instance of the class. - - - - - Initializes a new instance of the class with the specified container Id. - - The container Id. - - - - Gets or sets the id. - - The id. - - - - Gets or sets the title. - - The title. - - - - Gets or sets the description. - - The description. - - - - Gets or sets a value that indicates whether to preserve object reference data. - - - true to keep object reference; otherwise, false. The default is false. - - - - - Initializes a new instance of the class. - - - - - Initializes a new instance of the class with a flag indicating whether the array can contain null items - - A flag indicating whether the array can contain null items. - - - - Initializes a new instance of the class with the specified container Id. - - The container Id. - - - - Gets or sets a value indicating whether null items are allowed in the collection. - - true if null items are allowed in the collection; otherwise, false. - - - - Specifies default value handling options for the . - - - - - Include null values when serializing and deserializing objects. - - - - - Ignore null values when serializing and deserializing objects. - - - - - Instructs the to use the specified when serializing the member or class. - - - - - Initializes a new instance of the class. - - Type of the converter. - - - - Gets the type of the converter. - - The type of the converter. - - - - Instructs the how to serialize the object. - - - - - Initializes a new instance of the class. - - - - - Initializes a new instance of the class with the specified member serialization. - - The member serialization. - - - - Initializes a new instance of the class with the specified container Id. - - The container Id. - - - - Gets or sets the member serialization. - - The member serialization. - - - - Specifies the settings on a object. - - - - - Initializes a new instance of the class. - - - - - Gets or sets how reference loops (e.g. a class referencing itself) is handled. - - Reference loop handling. - - - - Gets or sets how missing members (e.g. JSON contains a property that isn't a member on the object) are handled during deserialization. - - Missing member handling. - - - - Gets or sets how objects are created during deserialization. - - The object creation handling. - - - - Gets or sets how null values are handled during serialization and deserialization. - - Null value handling. - - - - Gets or sets how null default are handled during serialization and deserialization. - - The default value handling. - - - - Gets or sets a collection that will be used during serialization. - - The converters. - - - - Gets or sets how object references are preserved by the serializer. - - The preserve references handling. - - - - Gets or sets how type name writing and reading is handled by the serializer. - - The type name handling. - - - - Gets or sets how constructors are used during deserialization. - - The constructor handling. - - - - Gets or sets the contract resolver used by the serializer when - serializing .NET objects to JSON and vice versa. - - The contract resolver. - - - - Gets or sets the used by the serializer when resolving references. - - The reference resolver. - - - - Gets or sets the used by the serializer when resolving type names. - - The binder. - - - - Gets or sets the error handler called during serialization and deserialization. - - The error handler called during serialization and deserialization. - - - - Gets or sets the used by the serializer when invoking serialization callback methods. - - The context. - - - - Represents a reader that provides validation. - - - - - Initializes a new instance of the class that - validates the content returned from the given . - - The to read from while validating. - - - - Reads the next JSON token from the stream as a . - - - A or a null reference if the next JSON token is null. - - - - - Reads the next JSON token from the stream. - - - true if the next token was read successfully; false if there are no more tokens to read. - - - - - Sets an event handler for receiving schema validation errors. - - - - - Gets the text value of the current Json token. - - - - - - Gets the depth of the current token in the JSON document. - - The depth of the current token in the JSON document. - - - - Gets the quotation mark character used to enclose the value of a string. - - - - - - Gets the type of the current Json token. - - - - - - Gets The Common Language Runtime (CLR) type for the current Json token. - - - - - - Gets or sets the schema. - - The schema. - - - - Gets the used to construct this . - - The specified in the constructor. - - - - Compares tokens to determine whether they are equal. - - - - - Determines whether the specified objects are equal. - - The first object of type to compare. - The second object of type to compare. - - true if the specified objects are equal; otherwise, false. - - - - - Returns a hash code for the specified object. - - The for which a hash code is to be returned. - A hash code for the specified object. - The type of is a reference type and is null. - - - - Specifies the member serialization options for the . - - - - - All members are serialized by default. Members can be excluded using the . - - - - - Only members must be marked with the are serialized. - - - - - Specifies how object creation is handled by the . - - - - - Reuse existing objects, create new objects when needed. - - - - - Only reuse existing objects. - - - - - Always create new objects. - - - - - Converts a to and from the ISO 8601 date format (e.g. 2008-04-12T12:53Z). - - - - - Writes the JSON representation of the object. - - The to write to. - The value. - The calling serializer. - - - - Reads the JSON representation of the object. - - The to read from. - Type of the object. - The calling serializer. - The object value. - - - - Gets or sets the date time styles used when converting a date to and from JSON. - - The date time styles used when converting a date to and from JSON. - - - - Gets or sets the date time format used when converting a date to and from JSON. - - The date time format used when converting a date to and from JSON. - - - - Gets or sets the culture used when converting a date to and from JSON. - - The culture used when converting a date to and from JSON. - - - - Converts a to and from a JavaScript date constructor (e.g. new Date(52231943)). - - - - - Writes the JSON representation of the object. - - The to write to. - The value. - The calling serializer. - - - - Reads the JSON representation of the object. - - The to read from. - Type of the object. - The calling serializer. - The object value. - - - - Specifies whether a DateTime object represents a local time, a Coordinated Universal Time (UTC), or is not specified as either local time or UTC. - - - - - The time represented is local time. - - - - - The time represented is UTC. - - - - - The time represented is not specified as either local time or Coordinated Universal Time (UTC). - - - - - Preserves the DateTimeKind field of a date when a DateTime object is converted to a string and the string is then converted back to a DateTime object. - - - - - Converts an to and from JSON. - - - - - Writes the JSON representation of the object. - - The to write to. - The calling serializer. - The value. - - - - Reads the JSON representation of the object. - - The to read from. - Type of the object. - The calling serializer. - The object value. - - - - Checks if the attributeName is a namespace attribute. - - Attribute name to test. - The attribute name prefix if it has one, otherwise an empty string. - True if attribute name is for a namespace attribute, otherwise false. - - - - Determines whether this instance can convert the specified value type. - - Type of the value. - - true if this instance can convert the specified value type; otherwise, false. - - - - - Gets or sets the name of the root element to insert when deserializing to XML if the JSON structure has produces multiple root elements. - - The name of the deserialize root element. - - - - Converts a object to and from JSON. - - - - - Writes the JSON representation of the object. - - The to write to. - The calling serializer. - The value. - - - - Determines whether this instance can convert the specified value type. - - Type of the value. - - true if this instance can convert the specified value type; otherwise, false. - - - - - Reads the JSON representation of the object. - - The to read from. - Type of the object. - The calling serializer. - The object value. - - - - Represents a reader that provides fast, non-cached, forward-only access to serialized Json data. - - - - - Initializes a new instance of the class with the specified . - - The TextReader containing the XML data to read. - - - - Reads the next JSON token from the stream. - - - true if the next token was read successfully; false if there are no more tokens to read. - - - - - Reads the next JSON token from the stream as a . - - - A or a null reference if the next JSON token is null. - - - - - Changes the state to closed. - - - - - Gets a value indicating whether the class can return line information. - - - true if LineNumber and LinePosition can be provided; otherwise, false. - - - - - Gets the current line number. - - - The current line number or 0 if no line information is available (for example, HasLineInfo returns false). - - - - - Gets the current line position. - - - The current line position or 0 if no line information is available (for example, HasLineInfo returns false). - - - - - Instructs the to always serialize the member with the specified name. - - - - - Initializes a new instance of the class. - - - - - Initializes a new instance of the class with the specified name. - - Name of the property. - - - - Gets or sets the null value handling used when serializing this property. - - The null value handling. - - - - Gets or sets the default value handling used when serializing this property. - - The default value handling. - - - - Gets or sets the reference loop handling used when serializing this property. - - The reference loop handling. - - - - Gets or sets the object creation handling used when deserializing this property. - - The object creation handling. - - - - Gets or sets whether this property's value is serialized as a reference. - - Whether this property's value is serialized as a reference. - - - - Gets or sets the name of the property. - - The name of the property. - - - - Gets or sets a value indicating whether this property is required. - - - A value indicating whether this property is required. - - - - - Instructs the not to serialize the public field or public read/write property value. - - - - - Represents a writer that provides a fast, non-cached, forward-only way of generating Json data. - - - - - Creates an instance of the JsonWriter class using the specified . - - The TextWriter to write to. - - - - Flushes whatever is in the buffer to the underlying streams and also flushes the underlying stream. - - - - - Closes this stream and the underlying stream. - - - - - Writes the beginning of a Json object. - - - - - Writes the beginning of a Json array. - - - - - Writes the start of a constructor with the given name. - - The name of the constructor. - - - - Writes the specified end token. - - The end token to write. - - - - Writes the property name of a name/value pair on a Json object. - - The name of the property. - - - - Writes indent characters. - - - - - Writes the JSON value delimiter. - - - - - Writes an indent space. - - - - - Writes a null value. - - - - - Writes an undefined value. - - - - - Writes raw JSON. - - The raw JSON to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes a value. - - The value to write. - - - - Writes out a comment /*...*/ containing the specified text. - - Text to place inside the comment. - - - - Writes out the given white space. - - The string of white space characters. - - - - Gets or sets how many IndentChars to write for each level in the hierarchy when is set to Formatting.Indented. - - - - - Gets or sets which character to use to quote attribute values. - - - - - Gets or sets which character to use for indenting when is set to Formatting.Indented. - - - - - Gets or sets a value indicating whether object names will be surrounded with quotes. - - - - - The exception thrown when an error occurs while reading Json text. - - - - - Initializes a new instance of the class. - - - - - Initializes a new instance of the class - with a specified error message. - - The error message that explains the reason for the exception. - - - - Initializes a new instance of the class - with a specified error message and a reference to the inner exception that is the cause of this exception. - - The error message that explains the reason for the exception. - The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified. - - - - The exception thrown when an error occurs while reading Json text. - - - - - Initializes a new instance of the class. - - - - - Initializes a new instance of the class - with a specified error message. - - The error message that explains the reason for the exception. - - - - Initializes a new instance of the class - with a specified error message and a reference to the inner exception that is the cause of this exception. - - The error message that explains the reason for the exception. - The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified. - - - - Gets the line number indicating where the error occurred. - - The line number indicating where the error occurred. - - - - Gets the line position indicating where the error occurred. - - The line position indicating where the error occurred. - - - - Represents a collection of . - - - - - Provides methods for converting between common language runtime types and JSON types. - - - - - Represents JavaScript's boolean value true as a string. This field is read-only. - - - - - Represents JavaScript's boolean value false as a string. This field is read-only. - - - - - Represents JavaScript's null as a string. This field is read-only. - - - - - Represents JavaScript's undefined as a string. This field is read-only. - - - - - Represents JavaScript's positive infinity as a string. This field is read-only. - - - - - Represents JavaScript's negative infinity as a string. This field is read-only. - - - - - Represents JavaScript's NaN as a string. This field is read-only. - - - - - Converts the to its JSON string representation. - - The value to convert. - A JSON string representation of the . - - - - Converts the to its JSON string representation. - - The value to convert. - A JSON string representation of the . - - - - Converts the to its JSON string representation. - - The value to convert. - A JSON string representation of the . - - - - Converts the to its JSON string representation. - - The value to convert. - A JSON string representation of the . - - - - Converts the to its JSON string representation. - - The value to convert. - A JSON string representation of the . - - - - Converts the to its JSON string representation. - - The value to convert. - A JSON string representation of the . - - - - Converts the to its JSON string representation. - - The value to convert. - A JSON string representation of the . - - - - Converts the to its JSON string representation. - - The value to convert. - A JSON string representation of the . - - - - Converts the to its JSON string representation. - - The value to convert. - A JSON string representation of the . - - - - Converts the to its JSON string representation. - - The value to convert. - A JSON string representation of the . - - - - Converts the to its JSON string representation. - - The value to convert. - A JSON string representation of the . - - - - Converts the to its JSON string representation. - - The value to convert. - A JSON string representation of the . - - - - Converts the to its JSON string representation. - - The value to convert. - A JSON string representation of the . - - - - Converts the to its JSON string representation. - - The value to convert. - A JSON string representation of the . - - - - Converts the to its JSON string representation. - - The value to convert. - A JSON string representation of the . - - - - Converts the to its JSON string representation. - - The value to convert. - A JSON string representation of the . - - - - Converts the to its JSON string representation. - - The value to convert. - A JSON string representation of the . - - - - Converts the to its JSON string representation. - - The value to convert. - The string delimiter character. - A JSON string representation of the . - - - - Converts the to its JSON string representation. - - The value to convert. - A JSON string representation of the . - - - - Serializes the specified object to a JSON string. - - The object to serialize. - A JSON string representation of the object. - - - - Serializes the specified object to a JSON string. - - The object to serialize. - Indicates how the output is formatted. - - A JSON string representation of the object. - - - - - Serializes the specified object to a JSON string using a collection of . - - The object to serialize. - A collection converters used while serializing. - A JSON string representation of the object. - - - - Serializes the specified object to a JSON string using a collection of . - - The object to serialize. - Indicates how the output is formatted. - A collection converters used while serializing. - A JSON string representation of the object. - - - - Serializes the specified object to a JSON string using a collection of . - - The object to serialize. - Indicates how the output is formatted. - The used to serialize the object. - If this is null, default serialization settings will be is used. - - A JSON string representation of the object. - - - - - Deserializes the specified object to a Json object. - - The object to deserialize. - The deserialized object from the Json string. - - - - Deserializes the specified object to a Json object. - - The object to deserialize. - The of object being deserialized. - The deserialized object from the Json string. - - - - Deserializes the specified object to a Json object. - - The type of the object to deserialize. - The object to deserialize. - The deserialized object from the Json string. - - - - Deserializes the specified JSON to the given anonymous type. - - - The anonymous type to deserialize to. This can't be specified - traditionally and must be infered from the anonymous type passed - as a parameter. - - The object to deserialize. - The anonymous type object. - The deserialized anonymous type from the JSON string. - - - - Deserializes the JSON string to the specified type. - - The type of the object to deserialize. - The object to deserialize. - Converters to use while deserializing. - The deserialized object from the JSON string. - - - - Deserializes the JSON string to the specified type. - - The type of the object to deserialize. - The object to deserialize. - - The used to deserialize the object. - If this is null, default serialization settings will be is used. - - The deserialized object from the JSON string. - - - - Deserializes the JSON string to the specified type. - - The object to deserialize. - The type of the object to deserialize. - Converters to use while deserializing. - The deserialized object from the JSON string. - - - - Deserializes the JSON string to the specified type. - - The JSON to deserialize. - The type of the object to deserialize. - - The used to deserialize the object. - If this is null, default serialization settings will be is used. - - The deserialized object from the JSON string. - - - - Populates the object with values from the JSON string. - - The JSON to populate values from. - The target object to populate values onto. - - - - Populates the object with values from the JSON string. - - The JSON to populate values from. - The target object to populate values onto. - - The used to deserialize the object. - If this is null, default serialization settings will be is used. - - - - - Serializes the XML node to a JSON string. - - The node to serialize. - A JSON string of the XmlNode. - - - - Deserializes the XmlNode from a JSON string. - - The JSON string. - The deserialized XmlNode - - - - Deserializes the XmlNode from a JSON string nested in a root elment. - - The JSON string. - The name of the root element to append when deserializing. - The deserialized XmlNode - - - - The exception thrown when an error occurs during Json serialization or deserialization. - - - - - Initializes a new instance of the class. - - - - - Initializes a new instance of the class - with a specified error message. - - The error message that explains the reason for the exception. - - - - Initializes a new instance of the class - with a specified error message and a reference to the inner exception that is the cause of this exception. - - The error message that explains the reason for the exception. - The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified. - - - - Serializes and deserializes objects into and from the JSON format. - The enables you to control how objects are encoded into JSON. - - - - - Initializes a new instance of the class. - - - - - Creates a new instance using the specified . - - The settings to be applied to the . - A new instance using the specified . - - - - Populates the JSON values onto the target object. - - The that contains the JSON structure to reader values from. - The target object to populate values onto. - - - - Populates the JSON values onto the target object. - - The that contains the JSON structure to reader values from. - The target object to populate values onto. - - - - Deserializes the Json structure contained by the specified . - - The that contains the JSON structure to deserialize. - The being deserialized. - - - - Deserializes the Json structure contained by the specified - into an instance of the specified type. - - The containing the object. - The of object being deserialized. - The instance of being deserialized. - - - - Deserializes the Json structure contained by the specified - into an instance of the specified type. - - The containing the object. - The type of the object to deserialize. - The instance of being deserialized. - - - - Deserializes the Json structure contained by the specified - into an instance of the specified type. - - The containing the object. - The of object being deserialized. - The instance of being deserialized. - - - - Serializes the specified and writes the Json structure - to a Stream using the specified . - - The used to write the Json structure. - The to serialize. - - - - Serializes the specified and writes the Json structure - to a Stream using the specified . - - The used to write the Json structure. - The to serialize. - - - - Occurs when the errors during serialization and deserialization. - - - - - Gets or sets the used by the serializer when resolving references. - - - - - Gets or sets the used by the serializer when resolving type names. - - - - - Gets or sets how type name writing and reading is handled by the serializer. - - - - - Gets or sets how object references are preserved by the serializer. - - - - - Get or set how reference loops (e.g. a class referencing itself) is handled. - - - - - Get or set how missing members (e.g. JSON contains a property that isn't a member on the object) are handled during deserialization. - - - - - Get or set how null values are handled during serialization and deserialization. - - - - - Get or set how null default are handled during serialization and deserialization. - - - - - Gets or sets how objects are created during deserialization. - - The object creation handling. - - - - Gets or sets how constructors are used during deserialization. - - The constructor handling. - - - - Gets a collection that will be used during serialization. - - Collection that will be used during serialization. - - - - Gets or sets the contract resolver used by the serializer when - serializing .NET objects to JSON and vice versa. - - - - - Gets or sets the used by the serializer when invoking serialization callback methods. - - The context. - - - - Contains the LINQ to JSON extension methods. - - - - - Returns a collection of tokens that contains the ancestors of every token in the source collection. - - The type of the objects in source, constrained to . - An of that contains the source collection. - An of that contains the ancestors of every node in the source collection. - - - - Returns a collection of tokens that contains the descendants of every token in the source collection. - - The type of the objects in source, constrained to . - An of that contains the source collection. - An of that contains the descendants of every node in the source collection. - - - - Returns a collection of child properties of every object in the source collection. - - An of that contains the source collection. - An of that contains the properties of every object in the source collection. - - - - Returns a collection of child values of every object in the source collection with the given key. - - An of that contains the source collection. - The token key. - An of that contains the values of every node in the source collection with the given key. - - - - Returns a collection of child values of every object in the source collection. - - An of that contains the source collection. - An of that contains the values of every node in the source collection. - - - - Returns a collection of converted child values of every object in the source collection with the given key. - - The type to convert the values to. - An of that contains the source collection. - The token key. - An that contains the converted values of every node in the source collection with the given key. - - - - Returns a collection of converted child values of every object in the source collection. - - The type to convert the values to. - An of that contains the source collection. - An that contains the converted values of every node in the source collection. - - - - Converts the value. - - The type to convert the value to. - A cast as a of . - A converted value. - - - - Converts the value. - - The source collection type. - The type to convert the value to. - A cast as a of . - A converted value. - - - - Returns a collection of child tokens of every array in the source collection. - - The source collection type. - An of that contains the source collection. - An of that contains the values of every node in the source collection. - - - - Returns a collection of converted child tokens of every array in the source collection. - - An of that contains the source collection. - The type to convert the values to. - The source collection type. - An that contains the converted values of every node in the source collection. - - - - Returns the input typed as . - - An of that contains the source collection. - The input typed as . - - - - Returns the input typed as . - - The source collection type. - An of that contains the source collection. - The input typed as . - - - - Represents a JSON constructor. - - - - - Represents a token that can contain other tokens. - - - - - Raises the event. - - The instance containing the event data. - - - - Raises the event. - - The instance containing the event data. - - - - Returns a collection of the child tokens of this token, in document order. - - - An of containing the child tokens of this , in document order. - - - - - Returns a collection of the child values of this token, in document order. - - The type to convert the values to. - - A containing the child values of this , in document order. - - - - - Returns a collection of the descendant tokens for this token in document order. - - An containing the descendant tokens of the . - - - - Adds the specified content as children of this . - - The content to be added. - - - - Adds the specified content as the first children of this . - - The content to be added. - - - - Creates an that can be used to add tokens to the . - - An that is ready to have content written to it. - - - - Replaces the children nodes of this token with the specified content. - - The content. - - - - Removes the child nodes from this token. - - - - - Occurs when the list changes or an item in the list changes. - - - - - Occurs before an item is added to the collection. - - - - - Gets a value indicating whether this token has childen tokens. - - - true if this token has child values; otherwise, false. - - - - - Get the first child token of this token. - - - A containing the first child token of the . - - - - - Get the last child token of this token. - - - A containing the last child token of the . - - - - - Initializes a new instance of the class. - - - - - Initializes a new instance of the class from another object. - - A object to copy from. - - - - Initializes a new instance of the class with the specified name and content. - - The constructor name. - The contents of the constructor. - - - - Initializes a new instance of the class with the specified name and content. - - The constructor name. - The contents of the constructor. - - - - Initializes a new instance of the class with the specified name. - - The constructor name. - - - - Writes this token to a . - - A into which this method will write. - A collection of which will be used when writing the token. - - - - Loads an from a . - - A that will be read for the content of the . - A that contains the JSON that was read from the specified . - - - - Gets or sets the name of this constructor. - - The constructor name. - - - - Gets the node type for this . - - The type. - - - - Gets the with the specified key. - - The with the specified key. - - - - Represents a collection of objects. - - The type of token - - - - An empty collection of objects. - - - - - Initializes a new instance of the struct. - - The enumerable. - - - - Returns an enumerator that iterates through the collection. - - - A that can be used to iterate through the collection. - - - - - Returns an enumerator that iterates through a collection. - - - An object that can be used to iterate through the collection. - - - - - Determines whether the specified is equal to this instance. - - The to compare with this instance. - - true if the specified is equal to this instance; otherwise, false. - - - - - Returns a hash code for this instance. - - - A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. - - - - - Gets the with the specified key. - - - - - - Represents a JSON object. - - - - - Initializes a new instance of the class. - - - - - Initializes a new instance of the class from another object. - - A object to copy from. - - - - Initializes a new instance of the class with the specified content. - - The contents of the object. - - - - Initializes a new instance of the class with the specified content. - - The contents of the object. - - - - Gets an of this object's properties. - - An of this object's properties. - - - - Gets a the specified name. - - The property name. - A with the specified name or null. - - - - Gets an of this object's property values. - - An of this object's property values. - - - - Loads an from a . - - A that will be read for the content of the . - A that contains the JSON that was read from the specified . - - - - Load a from a string that contains JSON. - - A that contains JSON. - A populated from the string that contains JSON. - - - - Creates a from an object. - - The object that will be used to create . - A with the values of the specified object - - - - Creates a from an object. - - The object that will be used to create . - The that will be used to read the object. - A with the values of the specified object - - - - Writes this token to a . - - A into which this method will write. - A collection of which will be used when writing the token. - - - - Adds the specified property name. - - Name of the property. - The value. - - - - Removes the property with the specified name. - - Name of the property. - true if item was successfully removed; otherwise, false. - - - - Tries the get value. - - Name of the property. - The value. - true if a value was successfully retrieved; otherwise, false. - - - - Returns an enumerator that iterates through the collection. - - - A that can be used to iterate through the collection. - - - - - Raises the event with the provided arguments. - - Name of the property. - - - - Occurs when a property value changes. - - - - - Gets the node type for this . - - The type. - - - - Gets the with the specified key. - - The with the specified key. - - - - Gets or sets the with the specified property name. - - - - - - Gets the number of elements contained in the . - - - The number of elements contained in the . - - - - Represents a JSON array. - - - - - Initializes a new instance of the class. - - - - - Initializes a new instance of the class from another object. - - A object to copy from. - - - - Initializes a new instance of the class with the specified content. - - The contents of the array. - - - - Initializes a new instance of the class with the specified content. - - The contents of the array. - - - - Loads an from a . - - A that will be read for the content of the . - A that contains the JSON that was read from the specified . - - - - Load a from a string that contains JSON. - - A that contains JSON. - A populated from the string that contains JSON. - - - - Creates a from an object. - - The object that will be used to create . - A with the values of the specified object - - - - Creates a from an object. - - The object that will be used to create . - The that will be used to read the object. - A with the values of the specified object - - - - Writes this token to a . - - A into which this method will write. - A collection of which will be used when writing the token. - - - - Determines the index of a specific item in the . - - The object to locate in the . - - The index of if found in the list; otherwise, -1. - - - - - Inserts an item to the at the specified index. - - The zero-based index at which should be inserted. - The object to insert into the . - - is not a valid index in the . - The is read-only. - - - - Removes the item at the specified index. - - The zero-based index of the item to remove. - - is not a valid index in the . - The is read-only. - - - - Adds an item to the . - - The object to add to the . - The is read-only. - - - - Removes all items from the . - - The is read-only. - - - - Determines whether the contains a specific value. - - The object to locate in the . - - true if is found in the ; otherwise, false. - - - - - Removes the first occurrence of a specific object from the . - - The object to remove from the . - - true if was successfully removed from the ; otherwise, false. This method also returns false if is not found in the original . - - The is read-only. - - - - Gets the node type for this . - - The type. - - - - Gets the with the specified key. - - The with the specified key. - - - - Gets or sets the at the specified index. - - - - - - Gets the number of elements contained in the . - - - The number of elements contained in the . - - - - Represents a reader that provides fast, non-cached, forward-only access to serialized Json data. - - - - - Initializes a new instance of the class. - - The token to read from. - - - - Reads the next JSON token from the stream as a . - - - A or a null reference if the next JSON token is null. - - - - - Reads the next JSON token from the stream. - - - true if the next token was read successfully; false if there are no more tokens to read. - - - - - Represents a JSON property. - - - - - Initializes a new instance of the class from another object. - - A object to copy from. - - - - Returns a collection of the child tokens of this token, in document order. - - - An of containing the child tokens of this , in document order. - - - - - Initializes a new instance of the class. - - The property name. - The property content. - - - - Initializes a new instance of the class. - - The property name. - The property content. - - - - Writes this token to a . - - A into which this method will write. - A collection of which will be used when writing the token. - - - - Loads an from a . - - A that will be read for the content of the . - A that contains the JSON that was read from the specified . - - - - Gets the property name. - - The property name. - - - - Gets or sets the property value. - - The property value. - - - - Gets the node type for this . - - The type. - - - - Specifies the type of token. - - - - - No token type has been set. - - - - - A JSON object. - - - - - A JSON array. - - - - - A JSON constructor. - - - - - A JSON object property. - - - - - A comment. - - - - - An integer value. - - - - - A float value. - - - - - A string value. - - - - - A boolean value. - - - - - A null value. - - - - - An undefined value. - - - - - A date value. - - - - - A raw JSON value. - - - - - A collection of bytes value. - - - - - Contains the JSON schema extension methods. - - - - - Determines whether the is valid. - - The source to test. - The schema to test with. - - true if the specified is valid; otherwise, false. - - - - - Validates the specified . - - The source to test. - The schema to test with. - - - - Validates the specified . - - The source to test. - The schema to test with. - The validation event handler. - - - - Returns detailed information about the schema exception. - - - - - Initializes a new instance of the class. - - - - - Initializes a new instance of the class - with a specified error message. - - The error message that explains the reason for the exception. - - - - Initializes a new instance of the class - with a specified error message and a reference to the inner exception that is the cause of this exception. - - The error message that explains the reason for the exception. - The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified. - - - - Gets the line number indicating where the error occurred. - - The line number indicating where the error occurred. - - - - Gets the line position indicating where the error occurred. - - The line position indicating where the error occurred. - - - - Resolves from an id. - - - - - Initializes a new instance of the class. - - - - - Gets a for the specified id. - - The id. - A for the specified id. - - - - Gets or sets the loaded schemas. - - The loaded schemas. - - - - Specifies undefined schema Id handling options for the . - - - - - Do not infer a schema Id. - - - - - Use the .NET type name as the schema Id. - - - - - Use the assembly qualified .NET type name as the schema Id. - - - - - Returns detailed information related to the . - - - - - Gets the associated with the validation event. - - The JsonSchemaException associated with the validation event. - - - - Gets the text description corresponding to the validation event. - - The text description. - - - - Represents the callback method that will handle JSON schema validation events and the . - - - - - Resolves member mappings for a type, camel casing property names. - - - - - Used by to resolves a for a given . - - - - - Used by to resolves a for a given . - - - - - Resolves the contract for a given type. - - The type to resolve a contract for. - The contract for a given type. - - - - Initializes a new instance of the class. - - - - - Resolves the contract for a given type. - - The type to resolve a contract for. - The contract for a given type. - - - - Gets the serializable members for the type. - - The type to get serializable members for. - The serializable members for the type. - - - - Creates a for the given type. - - Type of the object. - A for the given type. - - - - Resolves the default for the contract. - - Type of the object. - - - - - Creates a for the given type. - - Type of the object. - A for the given type. - - - - Creates a for the given type. - - Type of the object. - A for the given type. - - - - Creates a for the given type. - - Type of the object. - A for the given type. - - - - Creates a for the given type. - - Type of the object. - A for the given type. - - - - Creates properties for the given . - - The contract to create properties for. - Properties for the given . - - - - Creates the used by the serializer to get and set values from a member. - - The member. - The used by the serializer to get and set values from a member. - - - - Creates a for the given . - - The member's declaring types . - The member to create a for. - A created for the given . - - - - Resolves the name of the property. - - Name of the property. - Name of the property. - - - - Gets or sets the default members search flags. - - The default members search flags. - - - - Resolves the name of the property. - - Name of the property. - The property name camel cased. - - - - The default serialization binder used when resolving and loading classes from type names. - - - - - When overridden in a derived class, controls the binding of a serialized object to a type. - - Specifies the name of the serialized object. - Specifies the name of the serialized object. - - The type of the object the formatter creates a new instance of. - - - - - Get and set values for a using dynamic methods. - - - - - Provides methods to get and set values. - - - - - Sets the value. - - The target to set the value on. - The value to set on the target. - - - - Gets the value. - - The target to get the value from. - The value. - - - - Initializes a new instance of the class. - - The member info. - - - - Sets the value. - - The target to set the value on. - The value to set on the target. - - - - Gets the value. - - The target to get the value from. - The value. - - - - Provides information surrounding an error. - - - - - Gets or sets the error. - - The error. - - - - Gets the original object that caused the error. - - The original object that caused the error. - - - - Gets the member that caused the error. - - The member that caused the error. - - - - Gets or sets a value indicating whether this is handled. - - true if handled; otherwise, false. - - - - Provides data for the Error event. - - - - - Initializes a new instance of the class. - - The current object. - The error context. - - - - Gets the current object the error event is being raised against. - - The current object the error event is being raised against. - - - - Gets the error context. - - The error context. - - - - Contract details for a used by the . - - - - - Contract details for a used by the . - - - - - Gets the underlying type for the contract. - - The underlying type for the contract. - - - - Gets or sets the type created during deserialization. - - The type created during deserialization. - - - - Gets or sets whether this type contract is serialized as a reference. - - Whether this type contract is serialized as a reference. - - - - Gets or sets the default for this contract. - - The converter. - - - - Gets or sets the method called immediately after deserialization of the object. - - The method called immediately after deserialization of the object. - - - - Gets or sets the method called during deserialization of the object. - - The method called during deserialization of the object. - - - - Gets or sets the method called after serialization of the object graph. - - The method called after serialization of the object graph. - - - - Gets or sets the method called before serialization of the object. - - The method called before serialization of the object. - - - - Gets or sets the default creator. - - The default creator. - - - - Gets or sets a value indicating whether [default creator non public]. - - true if the default object creator is non-public; otherwise, false. - - - - Gets or sets the method called when an error is thrown during the serialization of the object. - - The method called when an error is thrown during the serialization of the object. - - - - Initializes a new instance of the class. - - The underlying type for the contract. - - - - Contract details for a used by the . - - - - - Initializes a new instance of the class. - - The underlying type for the contract. - - - - Contract details for a used by the . - - - - - Initializes a new instance of the class. - - The underlying type for the contract. - - - - Contract details for a used by the . - - - - - Initializes a new instance of the class. - - The underlying type for the contract. - - - - Maps a JSON property to a .NET member. - - - - - Gets the name of the property. - - The name of the property. - - - - Gets the that will get and set the during serialization. - - The that will get and set the during serialization. - - - - Gets or sets the type of the property. - - The type of the property. - - - - Gets or sets the for the property. - If set this converter takes presidence over the contract converter for the property type. - - The converter. - - - - Gets a value indicating whether this is ignored. - - true if ignored; otherwise, false. - - - - Gets a value indicating whether this is readable. - - true if readable; otherwise, false. - - - - Gets a value indicating whether this is writable. - - true if writable; otherwise, false. - - - - Gets the member converter. - - The member converter. - - - - Gets the default value. - - The default value. - - - - Gets a value indicating whether this is required. - - A value indicating whether this is required. - - - - Gets a value indicating whether this property preserves object references. - - - true if this instance is reference; otherwise, false. - - - - - Gets the property null value handling. - - The null value handling. - - - - Gets the property default value handling. - - The default value handling. - - - - Gets the property reference loop handling. - - The reference loop handling. - - - - Gets the property object creation handling. - - The object creation handling. - - - - A collection of objects. - - - - - Initializes a new instance of the class. - - The contract. - - - - When implemented in a derived class, extracts the key from the specified element. - - The element from which to extract the key. - The key for the specified element. - - - - Adds a object. - - The property to add to the collection. - - - - Gets the closest matching object. - First attempts to get an exact case match of propertyName and then - a case insensitive match. - - Name of the property. - A matching property if found. - - - - Gets a property by property name. - - The name of the property to get. - Type property name string comparison. - A matching property if found. - - - - Specifies missing member handling options for the . - - - - - Ignore a missing member and do not attempt to deserialize it. - - - - - Throw a when a missing member is encountered during deserialization. - - - - - Specifies null value handling options for the . - - - - - Include null values when serializing and deserializing objects. - - - - - Ignore null values when serializing and deserializing objects. - - - - - Specifies reference loop handling options for the . - - - - - Throw a when a loop is encountered. - - - - - Ignore loop references and do not serialize. - - - - - Serialize loop references. - - - - - An in-memory representation of a JSON Schema. - - - - - Initializes a new instance of the class. - - - - - Reads a from the specified . - - The containing the JSON Schema to read. - The object representing the JSON Schema. - - - - Reads a from the specified . - - The containing the JSON Schema to read. - The to use when resolving schema references. - The object representing the JSON Schema. - - - - Load a from a string that contains schema JSON. - - A that contains JSON. - A populated from the string that contains JSON. - - - - Parses the specified json. - - The json. - The resolver. - A populated from the string that contains JSON. - - - - Writes this schema to a . - - A into which this method will write. - - - - Writes this schema to a using the specified . - - A into which this method will write. - The resolver used. - - - - Returns a that represents the current . - - - A that represents the current . - - - - - Gets or sets the id. - - - - - Gets or sets the title. - - - - - Gets or sets whether the object is optional. - - - - - Gets or sets whether the object is read only. - - - - - Gets or sets whether the object is visible to users. - - - - - Gets or sets whether the object is transient. - - - - - Gets or sets the description of the object. - - - - - Gets or sets the types of values allowed by the object. - - The type. - - - - Gets or sets the pattern. - - The pattern. - - - - Gets or sets the minimum length. - - The minimum length. - - - - Gets or sets the maximum length. - - The maximum length. - - - - Gets or sets the maximum decimals. - - The maximum decimals. - - - - Gets or sets the minimum. - - The minimum. - - - - Gets or sets the maximum. - - The maximum. - - - - Gets or sets the minimum number of items. - - The minimum number of items. - - - - Gets or sets the maximum number of items. - - The maximum number of items. - - - - Gets or sets the of items. - - The of items. - - - - Gets or sets the of properties. - - The of properties. - - - - Gets or sets the of additional properties. - - The of additional properties. - - - - Gets or sets a value indicating whether additional properties are allowed. - - - true if additional properties are allowed; otherwise, false. - - - - - Gets or sets the required property if this property is present. - - The required property if this property is present. - - - - Gets or sets the identity. - - The identity. - - - - Gets or sets the a collection of valid enum values allowed. - - A collection of valid enum values allowed. - - - - Gets or sets a collection of options. - - A collection of options. - - - - Gets or sets disallowed types. - - The disallow types. - - - - Gets or sets the default value. - - The default value. - - - - Gets or sets the extend . - - The extended . - - - - Gets or sets the format. - - The format. - - - - Generates a from a specified . - - - - - Generate a from the specified type. - - The type to generate a from. - A generated from the specified type. - - - - Generate a from the specified type. - - The type to generate a from. - The used to resolve schema references. - A generated from the specified type. - - - - Generate a from the specified type. - - The type to generate a from. - Specify whether the generated root will be nullable. - A generated from the specified type. - - - - Generate a from the specified type. - - The type to generate a from. - The used to resolve schema references. - Specify whether the generated root will be nullable. - A generated from the specified type. - - - - Gets or sets how undefined schemas are handled by the serializer. - - - - - Gets or sets the contract resolver. - - The contract resolver. - - - - The value types allowed by the . - - - - - No type specified. - - - - - String type. - - - - - Float type. - - - - - Integer type. - - - - - Boolean type. - - - - - Object type. - - - - - Array type. - - - - - Null type. - - - - - Any type. - - - - - Contract details for a used by the . - - - - - Initializes a new instance of the class. - - The underlying type for the contract. - - - - Gets or sets the object member serialization. - - The member object serialization. - - - - Gets the object's properties. - - The object's properties. - - - - Gets or sets the parametrized constructor used to create the object. - - The parametrized constructor. - - - - When applied to a method, specifies that the method is called when an error occurs serializing an object. - - - - - Get and set values for a using reflection. - - - - - Initializes a new instance of the class. - - The member info. - - - - Sets the value. - - The target to set the value on. - The value to set on the target. - - - - Gets the value. - - The target to get the value from. - The value. - - - - Specifies type name handling options for the . - - - - - Do not include the .NET type name when serializing types. - - - - - Include the .NET type name when serializing into a JSON object structure. - - - - - Include the .NET type name when serializing into a JSON array structure. - - - - - Always include the .NET type name when serializing. - - - - - Converts the value to the specified type. - - The type to convert the value to. - The value to convert. - The converted type. - - - - Converts the value to the specified type. - - The type to convert the value to. - The value to convert. - The culture to use when converting. - The converted type. - - - - Converts the value to the specified type. - - The value to convert. - The culture to use when converting. - The type to convert the value to. - The converted type. - - - - Converts the value to the specified type. - - The type to convert the value to. - The value to convert. - The converted value if the conversion was successful or the default value of T if it failed. - - true if initialValue was converted successfully; otherwise, false. - - - - - Converts the value to the specified type. - - The type to convert the value to. - The value to convert. - The culture to use when converting. - The converted value if the conversion was successful or the default value of T if it failed. - - true if initialValue was converted successfully; otherwise, false. - - - - - Converts the value to the specified type. - - The value to convert. - The culture to use when converting. - The type to convert the value to. - The converted value if the conversion was successful or the default value of T if it failed. - - true if initialValue was converted successfully; otherwise, false. - - - - - Converts the value to the specified type. If the value is unable to be converted, the - value is checked whether it assignable to the specified type. - - The type to convert or cast the value to. - The value to convert. - The converted type. If conversion was unsuccessful, the initial value is returned if assignable to the target type - - - - Converts the value to the specified type. If the value is unable to be converted, the - value is checked whether it assignable to the specified type. - - The type to convert or cast the value to. - The value to convert. - The culture to use when converting. - The converted type. If conversion was unsuccessful, the initial value is returned if assignable to the target type - - - - Converts the value to the specified type. If the value is unable to be converted, the - value is checked whether it assignable to the specified type. - - The value to convert. - The culture to use when converting. - The type to convert or cast the value to. - - The converted type. If conversion was unsuccessful, the initial value - is returned if assignable to the target type. - - - - - Converts the value to the specified type. If the value is unable to be converted, the - value is checked whether it assignable to the specified type. - - The type to convert the value to. - The value to convert. - The converted value if the conversion was successful or the default value of T if it failed. - - true if initialValue was converted successfully or is assignable; otherwise, false. - - - - - Converts the value to the specified type. If the value is unable to be converted, the - value is checked whether it assignable to the specified type. - - The type to convert the value to. - The value to convert. - The culture to use when converting. - The converted value if the conversion was successful or the default value of T if it failed. - - true if initialValue was converted successfully or is assignable; otherwise, false. - - - - - Converts the value to the specified type. If the value is unable to be converted, the - value is checked whether it assignable to the specified type. - - The value to convert. - The culture to use when converting. - The type to convert the value to. - The converted value if the conversion was successful or the default value of T if it failed. - - true if initialValue was converted successfully or is assignable; otherwise, false. - - - - - Parses the specified enum member name, returning it's value. - - Name of the enum member. - - - - - Parses the specified enum member name, returning it's value. - - Name of the enum member. - If set to true ignore case. - - - - - Gets a dictionary of the names and values of an Enum type. - - - - - - Gets a dictionary of the names and values of an Enum type. - - - - - - Gets a dictionary of the names and values of an Enum type. - - The enum type to get names and values for. - - - - - Gets the maximum valid value of an Enum type. Flags enums are ORed. - - The type of the returned value. Must be assignable from the enum's underlying value type. - The enum type to get the maximum value for. - - - - - Specifies the type of Json token. - - - - - This is returned by the if a method has not been called. - - - - - An object start token. - - - - - An array start token. - - - - - A constructor start token. - - - - - An object property name. - - - - - A comment. - - - - - Raw JSON. - - - - - An interger. - - - - - A float. - - - - - A string. - - - - - A boolean. - - - - - A null token. - - - - - An undefined token. - - - - - An object end token. - - - - - An array end token. - - - - - A constructor end token. - - - - - A Date. - - - - - Byte data. - - - - - Specifies the state of the . - - - - - An exception has been thrown, which has left the in an invalid state. - You may call the method to put the in the Closed state. - Any other method calls results in an being thrown. - - - - - The method has been called. - - - - - An object is being written. - - - - - A array is being written. - - - - - A constructor is being written. - - - - - A property is being written. - - - - - A write method has not been called. - - - - - Specifies formatting options for the . - - - - - No special formatting is applied. This is the default. - - - - - Causes child objects to be indented according to the and settings. - - - - - Builds a string. Unlike StringBuilder this class lets you reuse it's internal buffer. - - - - - Determines whether the collection is null or empty. - - The collection. - - true if the collection is null or empty; otherwise, false. - - - - - Determines whether the collection is null or empty. - - The collection. - - true if the collection is null or empty; otherwise, false. - - - - - Determines whether the collection is null, empty or its contents are uninitialized values. - - The list. - - true if the collection is null or empty or its contents are uninitialized values; otherwise, false. - - - - - Makes a slice of the specified list in between the start and end indexes. - - The list. - The start index. - The end index. - A slice of the list. - - - - Makes a slice of the specified list in between the start and end indexes, - getting every so many items based upon the step. - - The list. - The start index. - The end index. - The step. - A slice of the list. - - - - Group the collection using a function which returns the key. - - The source collection to group. - The key selector. - A Dictionary with each key relating to a list of objects in a list grouped under it. - - - - Adds the elements of the specified collection to the specified generic IList. - - The list to add to. - The collection of elements to add. - - - - Gets the type of the typed collection's items. - - The type. - The type of the typed collection's items. - - - - Tests whether the list's items are their unitialized value. - - The list. - Whether the list's items are their unitialized value - - - - Gets the member's underlying type. - - The member. - The underlying type of the member. - - - - Determines whether the member is an indexed property. - - The member. - - true if the member is an indexed property; otherwise, false. - - - - - Determines whether the property is an indexed property. - - The property. - - true if the property is an indexed property; otherwise, false. - - - - - Gets the member's value on the object. - - The member. - The target object. - The member's value on the object. - - - - Sets the member's value on the target object. - - The member. - The target. - The value. - - - - Determines whether the specified MemberInfo can be read. - - The MemberInfo to determine whether can be read. - - true if the specified MemberInfo can be read; otherwise, false. - - - - - Determines whether the specified MemberInfo can be set. - - The MemberInfo to determine whether can be set. - - true if the specified MemberInfo can be set; otherwise, false. - - - - - Determines whether the string contains white space. - - The string to test for white space. - - true if the string contains white space; otherwise, false. - - - - - Determines whether the string is all white space. Empty string will return false. - - The string to test whether it is all white space. - - true if the string is all white space; otherwise, false. - - - - - Ensures the target string ends with the specified string. - - The target. - The value. - The target string with the value string at the end. - - - - Perform an action if the string is not null or empty. - - The value. - The action to perform. - - - - Indents the specified string. - - The string to indent. - The number of characters to indent by. - - - - - Indents the specified string. - - The string to indent. - The number of characters to indent by. - The indent character. - - - - - Numbers the lines. - - The string to number. - - - - - Nulls an empty string. - - The string. - Null if the string was null, otherwise the string unchanged. - - - + + + + Newtonsoft.Json.Net20 + + + + + Represents a reader that provides fast, non-cached, forward-only access to serialized Json data. + + + + + Represents a reader that provides fast, non-cached, forward-only access to serialized Json data. + + + + + Initializes a new instance of the class with the specified . + + + + + Reads the next JSON token from the stream. + + true if the next token was read successfully; false if there are no more tokens to read. + + + + Reads the next JSON token from the stream as a . + + A or a null reference if the next JSON token is null. + + + + Skips the children of the current token. + + + + + Sets the current token. + + The new token. + + + + Sets the current token and value. + + The new token. + The value. + + + + Sets the state based on current token type. + + + + + Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + + + + + Releases unmanaged and - optionally - managed resources + + true to release both managed and unmanaged resources; false to release only unmanaged resources. + + + + Changes the to Closed. + + + + + Gets the current reader state. + + The current reader state. + + + + Gets the quotation mark character used to enclose the value of a string. + + + + + Gets the type of the current Json token. + + + + + Gets the text value of the current Json token. + + + + + Gets The Common Language Runtime (CLR) type for the current Json token. + + + + + Gets the depth of the current token in the JSON document. + + The depth of the current token in the JSON document. + + + + Specifies the state of the reader. + + + + + The Read method has not been called. + + + + + The end of the file has been reached successfully. + + + + + Reader is at a property. + + + + + Reader is at the start of an object. + + + + + Reader is in an object. + + + + + Reader is at the start of an array. + + + + + Reader is in an array. + + + + + The Close method has been called. + + + + + Reader has just read a value. + + + + + Reader is at the start of a constructor. + + + + + Reader in a constructor. + + + + + An error occurred that prevents the read operation from continuing. + + + + + The end of the file has been reached successfully. + + + + + Initializes a new instance of the class. + + The stream. + + + + Initializes a new instance of the class. + + The stream. + if set to true the root object will be read as a JSON array. + The used when reading values from BSON. + + + + Reads the next JSON token from the stream as a . + + + A or a null reference if the next JSON token is null. + + + + + Reads the next JSON token from the stream. + + + true if the next token was read successfully; false if there are no more tokens to read. + + + + + Gets or sets a value indicating whether the root object will be read as a JSON array. + + + true if the root object will be read as a JSON array; otherwise, false. + + + + + Gets or sets the used when reading values from BSON. + + The used when reading values from BSON. + + + + Represents a writer that provides a fast, non-cached, forward-only way of generating Json data. + + + + + Represents a writer that provides a fast, non-cached, forward-only way of generating Json data. + + + + + Represents a writer that provides a fast, non-cached, forward-only way of generating Json data. + + + + + Creates an instance of the JsonWriter class. + + + + + Flushes whatever is in the buffer to the underlying streams and also flushes the underlying stream. + + + + + Closes this stream and the underlying stream. + + + + + Writes the beginning of a Json object. + + + + + Writes the end of a Json object. + + + + + Writes the beginning of a Json array. + + + + + Writes the end of an array. + + + + + Writes the start of a constructor with the given name. + + The name of the constructor. + + + + Writes the end constructor. + + + + + Writes the property name of a name/value pair on a Json object. + + The name of the property. + + + + Writes the end of the current Json object or array. + + + + + Writes the current token. + + The to read the token from. + + + + Writes the specified end token. + + The end token to write. + + + + Writes indent characters. + + + + + Writes the JSON value delimiter. + + + + + Writes an indent space. + + + + + Writes a null value. + + + + + Writes an undefined value. + + + + + Writes raw JSON without changing the writer's state. + + The raw JSON to write. + + + + Writes raw JSON where a value is expected and updates the writer's state. + + The raw JSON to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + An error will raised if the value cannot be written as a single JSON token. + + The value to write. + + + + Writes out a comment /*...*/ containing the specified text. + + Text to place inside the comment. + + + + Writes out the given white space. + + The string of white space characters. + + + + Gets the top. + + The top. + + + + Gets the state of the writer. + + + + + Indicates how the output is formatted. + + + + + Initializes a new instance of the class writing to the given . + + The container being written to. + + + + Initializes a new instance of the class. + + + + + Flushes whatever is in the buffer to the underlying streams and also flushes the underlying stream. + + + + + Closes this stream and the underlying stream. + + + + + Writes the beginning of a Json object. + + + + + Writes the beginning of a Json array. + + + + + Writes the start of a constructor with the given name. + + The name of the constructor. + + + + Writes the end. + + The token. + + + + Writes the property name of a name/value pair on a Json object. + + The name of the property. + + + + Writes a null value. + + + + + Writes an undefined value. + + + + + Writes raw JSON. + + The raw JSON to write. + + + + Writes out a comment /*...*/ containing the specified text. + + Text to place inside the comment. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Gets the token being writen. + + The token being writen. + + + + Initializes a new instance of the class. + + The stream. + + + + Flushes whatever is in the buffer to the underlying streams and also flushes the underlying stream. + + + + + Writes the end. + + The token. + + + + Writes out a comment /*...*/ containing the specified text. + + Text to place inside the comment. + + + + Writes the start of a constructor with the given name. + + The name of the constructor. + + + + Writes raw JSON. + + The raw JSON to write. + + + + Writes raw JSON where a value is expected and updates the writer's state. + + The raw JSON to write. + + + + Specifies how constructors are used when initializing objects during deserialization by the . + + + + + First attempt to use the public default constructor then fall back to single paramatized constructor. + + + + + Allow Json.NET to use a non-public default constructor. + + + + + Converts a binary value to and from a base 64 string value. + + + + + Converts an object to and from JSON. + + + + + Writes the JSON representation of the object. + + The to write to. + The value. + The calling serializer. + + + + Reads the JSON representation of the object. + + The to read from. + Type of the object. + The calling serializer. + The object value. + + + + Determines whether this instance can convert the specified object type. + + Type of the object. + + true if this instance can convert the specified object type; otherwise, false. + + + + + Writes the JSON representation of the object. + + The to write to. + The value. + The calling serializer. + + + + Reads the JSON representation of the object. + + The to read from. + Type of the object. + The calling serializer. + The object value. + + + + Determines whether this instance can convert the specified object type. + + Type of the object. + + true if this instance can convert the specified object type; otherwise, false. + + + + + Create a custom object + + + + + + Writes the JSON representation of the object. + + The to write to. + The value. + The calling serializer. + + + + Reads the JSON representation of the object. + + The to read from. + Type of the object. + The calling serializer. + The object value. + + + + Creates an object which will then be populated by the serializer. + + Type of the object. + + + + + Determines whether this instance can convert the specified object type. + + Type of the object. + + true if this instance can convert the specified object type; otherwise, false. + + + + + Converts a to and from JSON. + + + + + Writes the JSON representation of the object. + + The to write to. + The value. + The calling serializer. + + + + Reads the JSON representation of the object. + + The to read from. + Type of the object. + The calling serializer. + The object value. + + + + Determines whether this instance can convert the specified value type. + + Type of the value. + + true if this instance can convert the specified value type; otherwise, false. + + + + + Converts a to and from JSON. + + + + + Writes the JSON representation of the object. + + The to write to. + The value. + The calling serializer. + + + + Reads the JSON representation of the object. + + The to read from. + Type of the object. + The calling serializer. + The object value. + + + + Determines whether this instance can convert the specified value type. + + Type of the value. + + true if this instance can convert the specified value type; otherwise, false. + + + + + Provides a base class for converting a to and from JSON. + + + + + Determines whether this instance can convert the specified object type. + + Type of the object. + + true if this instance can convert the specified object type; otherwise, false. + + + + + Converts an to and from its name string value. + + + + + Writes the JSON representation of the object. + + The to write to. + The value. + The calling serializer. + + + + Reads the JSON representation of the object. + + The to read from. + Type of the object. + The calling serializer. + The object value. + + + + Determines whether this instance can convert the specified object type. + + Type of the object. + + true if this instance can convert the specified object type; otherwise, false. + + + + + Represents a view of a . + + + + + Initializes a new instance of the class. + + The name. + Type of the property. + + + + When overridden in a derived class, returns whether resetting an object changes its value. + + + true if resetting the component changes its value; otherwise, false. + + The component to test for reset capability. + + + + + When overridden in a derived class, gets the current value of the property on a component. + + + The value of a property for a given component. + + The component with the property for which to retrieve the value. + + + + + When overridden in a derived class, resets the value for this property of the component to the default value. + + The component with the property value that is to be reset to the default value. + + + + + When overridden in a derived class, sets the value of the component to a different value. + + The component with the property value that is to be set. + The new value. + + + + + When overridden in a derived class, determines a value indicating whether the value of this property needs to be persisted. + + + true if the property should be persisted; otherwise, false. + + The component with the property to be examined for persistence. + + + + + When overridden in a derived class, gets the type of the component this property is bound to. + + + A that represents the type of component this property is bound to. When the or methods are invoked, the object specified might be an instance of this type. + + + + + When overridden in a derived class, gets a value indicating whether this property is read-only. + + + true if the property is read-only; otherwise, false. + + + + + When overridden in a derived class, gets the type of the property. + + + A that represents the type of the property. + + + + + Gets the hash code for the name of the member. + + + + The hash code for the name of the member. + + + + + Represents a view of a . + + + + + Initializes a new instance of the class. + + The value. + + + + Returns the properties for this instance of a component. + + + A that represents the properties for this component instance. + + + + + Returns the properties for this instance of a component using the attribute array as a filter. + + An array of type that is used as a filter. + + A that represents the filtered properties for this component instance. + + + + + Returns a collection of custom attributes for this instance of a component. + + + An containing the attributes for this object. + + + + + Returns the class name of this instance of a component. + + + The class name of the object, or null if the class does not have a name. + + + + + Returns the name of this instance of a component. + + + The name of the object, or null if the object does not have a name. + + + + + Returns a type converter for this instance of a component. + + + A that is the converter for this object, or null if there is no for this object. + + + + + Returns the default event for this instance of a component. + + + An that represents the default event for this object, or null if this object does not have events. + + + + + Returns the default property for this instance of a component. + + + A that represents the default property for this object, or null if this object does not have properties. + + + + + Returns an editor of the specified type for this instance of a component. + + A that represents the editor for this object. + + An of the specified type that is the editor for this object, or null if the editor cannot be found. + + + + + Returns the events for this instance of a component using the specified attribute array as a filter. + + An array of type that is used as a filter. + + An that represents the filtered events for this component instance. + + + + + Returns the events for this instance of a component. + + + An that represents the events for this component instance. + + + + + Returns an object that contains the property described by the specified property descriptor. + + A that represents the property whose owner is to be found. + + An that represents the owner of the specified property. + + + + + Represents a raw JSON string. + + + + + Represents a value in JSON (string, integer, date, etc). + + + + + Represents an abstract JSON token. + + + + + Represents a collection of objects. + + The type of token + + + + Gets the with the specified key. + + + + + + Provides an interface to enable a class to return line and position information. + + + + + Gets a value indicating whether the class can return line information. + + + true if LineNumber and LinePosition can be provided; otherwise, false. + + + + + Gets the current line number. + + The current line number or 0 if no line information is available (for example, HasLineInfo returns false). + + + + Gets the current line position. + + The current line position or 0 if no line information is available (for example, HasLineInfo returns false). + + + + Compares the values of two tokens, including the values of all descendant tokens. + + The first to compare. + The second to compare. + true if the tokens are equal; otherwise false. + + + + Adds the specified content immediately after this token. + + A content object that contains simple content or a collection of content objects to be added after this token. + + + + Adds the specified content immediately before this token. + + A content object that contains simple content or a collection of content objects to be added before this token. + + + + Returns a collection of the ancestor tokens of this token. + + A collection of the ancestor tokens of this token. + + + + Returns a collection of the sibling tokens after this token, in document order. + + A collection of the sibling tokens after this tokens, in document order. + + + + Returns a collection of the sibling tokens before this token, in document order. + + A collection of the sibling tokens before this token, in document order. + + + + Gets the with the specified key converted to the specified type. + + The type to convert the token to. + The token key. + The converted token value. + + + + Returns a collection of the child tokens of this token, in document order. + + An of containing the child tokens of this , in document order. + + + + Returns a collection of the child tokens of this token, in document order, filtered by the specified type. + + The type to filter the child tokens on. + A containing the child tokens of this , in document order. + + + + Returns a collection of the child values of this token, in document order. + + The type to convert the values to. + A containing the child values of this , in document order. + + + + Removes this token from its parent. + + + + + Replaces this token with the specified token. + + The value. + + + + Writes this token to a . + + A into which this method will write. + A collection of which will be used when writing the token. + + + + Returns the indented JSON for this token. + + + The indented JSON for this token. + + + + + Returns the JSON for this token using the given formatting and converters. + + Indicates how the output is formatted. + A collection of which will be used when writing the token. + The JSON for this token using the given formatting and converters. + + + + Performs an explicit conversion from to . + + The value. + The result of the conversion. + + + + Performs an explicit conversion from to . + + The value. + The result of the conversion. + + + + Performs an explicit conversion from to . + + The value. + The result of the conversion. + + + + Performs an explicit conversion from to . + + The value. + The result of the conversion. + + + + Performs an explicit conversion from to . + + The value. + The result of the conversion. + + + + Performs an explicit conversion from to . + + The value. + The result of the conversion. + + + + Performs an explicit conversion from to . + + The value. + The result of the conversion. + + + + Performs an explicit conversion from to . + + The value. + The result of the conversion. + + + + Performs an explicit conversion from to . + + The value. + The result of the conversion. + + + + Performs an explicit conversion from to . + + The value. + The result of the conversion. + + + + Performs an explicit conversion from to . + + The value. + The result of the conversion. + + + + Performs an explicit conversion from to . + + The value. + The result of the conversion. + + + + Performs an explicit conversion from to . + + The value. + The result of the conversion. + + + + Performs an explicit conversion from to . + + The value. + The result of the conversion. + + + + Performs an explicit conversion from to . + + The value. + The result of the conversion. + + + + Performs an explicit conversion from to . + + The value. + The result of the conversion. + + + + Performs an explicit conversion from to . + + The value. + The result of the conversion. + + + + Performs an explicit conversion from to . + + The value. + The result of the conversion. + + + + Performs an explicit conversion from to . + + The value. + The result of the conversion. + + + + Performs an explicit conversion from to . + + The value. + The result of the conversion. + + + + Performs an implicit conversion from to . + + The value to create a from. + The initialized with the specified value. + + + + Performs an implicit conversion from to . + + The value to create a from. + The initialized with the specified value. + + + + Performs an implicit conversion from to . + + The value to create a from. + The initialized with the specified value. + + + + Performs an implicit conversion from to . + + The value to create a from. + The initialized with the specified value. + + + + Performs an implicit conversion from to . + + The value to create a from. + The initialized with the specified value. + + + + Performs an implicit conversion from to . + + The value to create a from. + The initialized with the specified value. + + + + Performs an implicit conversion from to . + + The value to create a from. + The initialized with the specified value. + + + + Performs an implicit conversion from to . + + The value to create a from. + The initialized with the specified value. + + + + Performs an implicit conversion from to . + + The value to create a from. + The initialized with the specified value. + + + + Performs an implicit conversion from to . + + The value to create a from. + The initialized with the specified value. + + + + Performs an implicit conversion from to . + + The value to create a from. + The initialized with the specified value. + + + + Performs an implicit conversion from to . + + The value to create a from. + The initialized with the specified value. + + + + Performs an implicit conversion from to . + + The value to create a from. + The initialized with the specified value. + + + + Performs an implicit conversion from to . + + The value to create a from. + The initialized with the specified value. + + + + Performs an implicit conversion from to . + + The value to create a from. + The initialized with the specified value. + + + + Performs an implicit conversion from to . + + The value to create a from. + The initialized with the specified value. + + + + Performs an implicit conversion from to . + + The value to create a from. + The initialized with the specified value. + + + + Performs an implicit conversion from to . + + The value to create a from. + The initialized with the specified value. + + + + Performs an implicit conversion from to . + + The value to create a from. + The initialized with the specified value. + + + + Performs an implicit conversion from to . + + The value to create a from. + The initialized with the specified value. + + + + Performs an implicit conversion from to . + + The value to create a from. + The initialized with the specified value. + + + + Performs an implicit conversion from to . + + The value to create a from. + The initialized with the specified value. + + + + Creates an for this token. + + An that can be used to read this token and its descendants. + + + + Creates a from an object. + + The object that will be used to create . + A with the value of the specified object + + + + Creates a from an object using the specified . + + The object that will be used to create . + The that will be used when reading the object. + A with the value of the specified object + + + + Creates a from a . + + An positioned at the token to read into this . + + An that contains the token and its descendant tokens + that were read from the reader. The runtime type of the token is determined + by the token type of the first token encountered in the reader. + + + + + Selects the token that matches the object path. + + + The object path from the current to the + to be returned. This must be a string of property names or array indexes separated + by periods, such as Tables[0].DefaultView[0].Price in C# or + Tables(0).DefaultView(0).Price in Visual Basic. + + The that matches the object path or a null reference if no matching token is found. + + + + Selects the token that matches the object path. + + + The object path from the current to the + to be returned. This must be a string of property names or array indexes separated + by periods, such as Tables[0].DefaultView[0].Price in C# or + Tables(0).DefaultView(0).Price in Visual Basic. + + A flag to indicate whether an error should be thrown if no token is found. + The that matches the object path. + + + + Gets a comparer that can compare two tokens for value equality. + + A that can compare two nodes for value equality. + + + + Gets or sets the parent. + + The parent. + + + + Gets the root of this . + + The root of this . + + + + Gets the node type for this . + + The type. + + + + Gets a value indicating whether this token has childen tokens. + + + true if this token has child values; otherwise, false. + + + + + Gets the next sibling token of this node. + + The that contains the next sibling token. + + + + Gets the previous sibling token of this node. + + The that contains the previous sibling token. + + + + Gets the with the specified key. + + The with the specified key. + + + + Get the first child token of this token. + + A containing the first child token of the . + + + + Get the last child token of this token. + + A containing the last child token of the . + + + + Initializes a new instance of the class from another object. + + A object to copy from. + + + + Initializes a new instance of the class with the given value. + + The value. + + + + Initializes a new instance of the class with the given value. + + The value. + + + + Initializes a new instance of the class with the given value. + + The value. + + + + Initializes a new instance of the class with the given value. + + The value. + + + + Initializes a new instance of the class with the given value. + + The value. + + + + Initializes a new instance of the class with the given value. + + The value. + + + + Initializes a new instance of the class with the given value. + + The value. + + + + Creates a comment with the given value. + + The value. + A comment with the given value. + + + + Creates a string with the given value. + + The value. + A string with the given value. + + + + Writes this token to a . + + A into which this method will write. + A collection of which will be used when writing the token. + + + + Indicates whether the current object is equal to another object of the same type. + + + true if the current object is equal to the parameter; otherwise, false. + + An object to compare with this object. + + + + Determines whether the specified is equal to the current . + + The to compare with the current . + + true if the specified is equal to the current ; otherwise, false. + + + The parameter is null. + + + + + Serves as a hash function for a particular type. + + + A hash code for the current . + + + + + Gets a value indicating whether this token has childen tokens. + + + true if this token has child values; otherwise, false. + + + + + Gets the node type for this . + + The type. + + + + Gets or sets the underlying token value. + + The underlying token value. + + + + Initializes a new instance of the class from another object. + + A object to copy from. + + + + Initializes a new instance of the class. + + The raw json. + + + + Creates an instance of with the content of the reader's current token. + + The reader. + An instance of with the content of the reader's current token. + + + + Indicating whether a property is required. + + + + + The property is not required. The default state. + + + + + The property must be defined in JSON but can be a null value. + + + + + The property must be defined in JSON and cannot be a null value. + + + + + Used to resolve references when serializing and deserializing JSON by the . + + + + + Resolves a reference to its object. + + The reference to resolve. + The object that + + + + Gets the reference for the sepecified object. + + The object to get a reference for. + The reference to the object. + + + + Determines whether the specified object is referenced. + + The object to test for a reference. + + true if the specified object is referenced; otherwise, false. + + + + + Adds a reference to the specified object. + + The reference. + The object to reference. + + + + Specifies reference handling options for the . + + + + + Do not preserve references when serializing types. + + + + + Preserve references when serializing into a JSON object structure. + + + + + Preserve references when serializing into a JSON array structure. + + + + + Preserve references when serializing. + + + + + Instructs the how to serialize the collection. + + + + + Instructs the how to serialize the object. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class with the specified container Id. + + The container Id. + + + + Gets or sets the id. + + The id. + + + + Gets or sets the title. + + The title. + + + + Gets or sets the description. + + The description. + + + + Gets or sets a value that indicates whether to preserve object reference data. + + + true to keep object reference; otherwise, false. The default is false. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class with a flag indicating whether the array can contain null items + + A flag indicating whether the array can contain null items. + + + + Initializes a new instance of the class with the specified container Id. + + The container Id. + + + + Gets or sets a value indicating whether null items are allowed in the collection. + + true if null items are allowed in the collection; otherwise, false. + + + + Specifies default value handling options for the . + + + + + Include null values when serializing and deserializing objects. + + + + + Ignore null values when serializing and deserializing objects. + + + + + Instructs the to use the specified when serializing the member or class. + + + + + Initializes a new instance of the class. + + Type of the converter. + + + + Gets the type of the converter. + + The type of the converter. + + + + Instructs the how to serialize the object. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class with the specified member serialization. + + The member serialization. + + + + Initializes a new instance of the class with the specified container Id. + + The container Id. + + + + Gets or sets the member serialization. + + The member serialization. + + + + Specifies the settings on a object. + + + + + Initializes a new instance of the class. + + + + + Gets or sets how reference loops (e.g. a class referencing itself) is handled. + + Reference loop handling. + + + + Gets or sets how missing members (e.g. JSON contains a property that isn't a member on the object) are handled during deserialization. + + Missing member handling. + + + + Gets or sets how objects are created during deserialization. + + The object creation handling. + + + + Gets or sets how null values are handled during serialization and deserialization. + + Null value handling. + + + + Gets or sets how null default are handled during serialization and deserialization. + + The default value handling. + + + + Gets or sets a collection that will be used during serialization. + + The converters. + + + + Gets or sets how object references are preserved by the serializer. + + The preserve references handling. + + + + Gets or sets how type name writing and reading is handled by the serializer. + + The type name handling. + + + + Gets or sets how constructors are used during deserialization. + + The constructor handling. + + + + Gets or sets the contract resolver used by the serializer when + serializing .NET objects to JSON and vice versa. + + The contract resolver. + + + + Gets or sets the used by the serializer when resolving references. + + The reference resolver. + + + + Gets or sets the used by the serializer when resolving type names. + + The binder. + + + + Gets or sets the error handler called during serialization and deserialization. + + The error handler called during serialization and deserialization. + + + + Gets or sets the used by the serializer when invoking serialization callback methods. + + The context. + + + + Represents a reader that provides validation. + + + + + Initializes a new instance of the class that + validates the content returned from the given . + + The to read from while validating. + + + + Reads the next JSON token from the stream as a . + + + A or a null reference if the next JSON token is null. + + + + + Reads the next JSON token from the stream. + + + true if the next token was read successfully; false if there are no more tokens to read. + + + + + Sets an event handler for receiving schema validation errors. + + + + + Gets the text value of the current Json token. + + + + + + Gets the depth of the current token in the JSON document. + + The depth of the current token in the JSON document. + + + + Gets the quotation mark character used to enclose the value of a string. + + + + + + Gets the type of the current Json token. + + + + + + Gets The Common Language Runtime (CLR) type for the current Json token. + + + + + + Gets or sets the schema. + + The schema. + + + + Gets the used to construct this . + + The specified in the constructor. + + + + Compares tokens to determine whether they are equal. + + + + + Determines whether the specified objects are equal. + + The first object of type to compare. + The second object of type to compare. + + true if the specified objects are equal; otherwise, false. + + + + + Returns a hash code for the specified object. + + The for which a hash code is to be returned. + A hash code for the specified object. + The type of is a reference type and is null. + + + + Specifies the member serialization options for the . + + + + + All members are serialized by default. Members can be excluded using the . + + + + + Only members must be marked with the are serialized. + + + + + Specifies how object creation is handled by the . + + + + + Reuse existing objects, create new objects when needed. + + + + + Only reuse existing objects. + + + + + Always create new objects. + + + + + Converts a to and from the ISO 8601 date format (e.g. 2008-04-12T12:53Z). + + + + + Writes the JSON representation of the object. + + The to write to. + The value. + The calling serializer. + + + + Reads the JSON representation of the object. + + The to read from. + Type of the object. + The calling serializer. + The object value. + + + + Gets or sets the date time styles used when converting a date to and from JSON. + + The date time styles used when converting a date to and from JSON. + + + + Gets or sets the date time format used when converting a date to and from JSON. + + The date time format used when converting a date to and from JSON. + + + + Gets or sets the culture used when converting a date to and from JSON. + + The culture used when converting a date to and from JSON. + + + + Converts a to and from a JavaScript date constructor (e.g. new Date(52231943)). + + + + + Writes the JSON representation of the object. + + The to write to. + The value. + The calling serializer. + + + + Reads the JSON representation of the object. + + The to read from. + Type of the object. + The calling serializer. + The object value. + + + + Specifies whether a DateTime object represents a local time, a Coordinated Universal Time (UTC), or is not specified as either local time or UTC. + + + + + The time represented is local time. + + + + + The time represented is UTC. + + + + + The time represented is not specified as either local time or Coordinated Universal Time (UTC). + + + + + Preserves the DateTimeKind field of a date when a DateTime object is converted to a string and the string is then converted back to a DateTime object. + + + + + Converts an to and from JSON. + + + + + Writes the JSON representation of the object. + + The to write to. + The calling serializer. + The value. + + + + Reads the JSON representation of the object. + + The to read from. + Type of the object. + The calling serializer. + The object value. + + + + Checks if the attributeName is a namespace attribute. + + Attribute name to test. + The attribute name prefix if it has one, otherwise an empty string. + True if attribute name is for a namespace attribute, otherwise false. + + + + Determines whether this instance can convert the specified value type. + + Type of the value. + + true if this instance can convert the specified value type; otherwise, false. + + + + + Gets or sets the name of the root element to insert when deserializing to XML if the JSON structure has produces multiple root elements. + + The name of the deserialize root element. + + + + Converts a object to and from JSON. + + + + + Writes the JSON representation of the object. + + The to write to. + The calling serializer. + The value. + + + + Determines whether this instance can convert the specified value type. + + Type of the value. + + true if this instance can convert the specified value type; otherwise, false. + + + + + Reads the JSON representation of the object. + + The to read from. + Type of the object. + The calling serializer. + The object value. + + + + Represents a reader that provides fast, non-cached, forward-only access to serialized Json data. + + + + + Initializes a new instance of the class with the specified . + + The TextReader containing the XML data to read. + + + + Reads the next JSON token from the stream. + + + true if the next token was read successfully; false if there are no more tokens to read. + + + + + Reads the next JSON token from the stream as a . + + + A or a null reference if the next JSON token is null. + + + + + Changes the state to closed. + + + + + Gets a value indicating whether the class can return line information. + + + true if LineNumber and LinePosition can be provided; otherwise, false. + + + + + Gets the current line number. + + + The current line number or 0 if no line information is available (for example, HasLineInfo returns false). + + + + + Gets the current line position. + + + The current line position or 0 if no line information is available (for example, HasLineInfo returns false). + + + + + Instructs the to always serialize the member with the specified name. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class with the specified name. + + Name of the property. + + + + Gets or sets the null value handling used when serializing this property. + + The null value handling. + + + + Gets or sets the default value handling used when serializing this property. + + The default value handling. + + + + Gets or sets the reference loop handling used when serializing this property. + + The reference loop handling. + + + + Gets or sets the object creation handling used when deserializing this property. + + The object creation handling. + + + + Gets or sets whether this property's value is serialized as a reference. + + Whether this property's value is serialized as a reference. + + + + Gets or sets the name of the property. + + The name of the property. + + + + Gets or sets a value indicating whether this property is required. + + + A value indicating whether this property is required. + + + + + Instructs the not to serialize the public field or public read/write property value. + + + + + Represents a writer that provides a fast, non-cached, forward-only way of generating Json data. + + + + + Creates an instance of the JsonWriter class using the specified . + + The TextWriter to write to. + + + + Flushes whatever is in the buffer to the underlying streams and also flushes the underlying stream. + + + + + Closes this stream and the underlying stream. + + + + + Writes the beginning of a Json object. + + + + + Writes the beginning of a Json array. + + + + + Writes the start of a constructor with the given name. + + The name of the constructor. + + + + Writes the specified end token. + + The end token to write. + + + + Writes the property name of a name/value pair on a Json object. + + The name of the property. + + + + Writes indent characters. + + + + + Writes the JSON value delimiter. + + + + + Writes an indent space. + + + + + Writes a null value. + + + + + Writes an undefined value. + + + + + Writes raw JSON. + + The raw JSON to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes a value. + + The value to write. + + + + Writes out a comment /*...*/ containing the specified text. + + Text to place inside the comment. + + + + Writes out the given white space. + + The string of white space characters. + + + + Gets or sets how many IndentChars to write for each level in the hierarchy when is set to Formatting.Indented. + + + + + Gets or sets which character to use to quote attribute values. + + + + + Gets or sets which character to use for indenting when is set to Formatting.Indented. + + + + + Gets or sets a value indicating whether object names will be surrounded with quotes. + + + + + The exception thrown when an error occurs while reading Json text. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class + with a specified error message. + + The error message that explains the reason for the exception. + + + + Initializes a new instance of the class + with a specified error message and a reference to the inner exception that is the cause of this exception. + + The error message that explains the reason for the exception. + The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified. + + + + The exception thrown when an error occurs while reading Json text. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class + with a specified error message. + + The error message that explains the reason for the exception. + + + + Initializes a new instance of the class + with a specified error message and a reference to the inner exception that is the cause of this exception. + + The error message that explains the reason for the exception. + The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified. + + + + Gets the line number indicating where the error occurred. + + The line number indicating where the error occurred. + + + + Gets the line position indicating where the error occurred. + + The line position indicating where the error occurred. + + + + Represents a collection of . + + + + + Provides methods for converting between common language runtime types and JSON types. + + + + + Represents JavaScript's boolean value true as a string. This field is read-only. + + + + + Represents JavaScript's boolean value false as a string. This field is read-only. + + + + + Represents JavaScript's null as a string. This field is read-only. + + + + + Represents JavaScript's undefined as a string. This field is read-only. + + + + + Represents JavaScript's positive infinity as a string. This field is read-only. + + + + + Represents JavaScript's negative infinity as a string. This field is read-only. + + + + + Represents JavaScript's NaN as a string. This field is read-only. + + + + + Converts the to its JSON string representation. + + The value to convert. + A JSON string representation of the . + + + + Converts the to its JSON string representation. + + The value to convert. + A JSON string representation of the . + + + + Converts the to its JSON string representation. + + The value to convert. + A JSON string representation of the . + + + + Converts the to its JSON string representation. + + The value to convert. + A JSON string representation of the . + + + + Converts the to its JSON string representation. + + The value to convert. + A JSON string representation of the . + + + + Converts the to its JSON string representation. + + The value to convert. + A JSON string representation of the . + + + + Converts the to its JSON string representation. + + The value to convert. + A JSON string representation of the . + + + + Converts the to its JSON string representation. + + The value to convert. + A JSON string representation of the . + + + + Converts the to its JSON string representation. + + The value to convert. + A JSON string representation of the . + + + + Converts the to its JSON string representation. + + The value to convert. + A JSON string representation of the . + + + + Converts the to its JSON string representation. + + The value to convert. + A JSON string representation of the . + + + + Converts the to its JSON string representation. + + The value to convert. + A JSON string representation of the . + + + + Converts the to its JSON string representation. + + The value to convert. + A JSON string representation of the . + + + + Converts the to its JSON string representation. + + The value to convert. + A JSON string representation of the . + + + + Converts the to its JSON string representation. + + The value to convert. + A JSON string representation of the . + + + + Converts the to its JSON string representation. + + The value to convert. + A JSON string representation of the . + + + + Converts the to its JSON string representation. + + The value to convert. + A JSON string representation of the . + + + + Converts the to its JSON string representation. + + The value to convert. + The string delimiter character. + A JSON string representation of the . + + + + Converts the to its JSON string representation. + + The value to convert. + A JSON string representation of the . + + + + Serializes the specified object to a JSON string. + + The object to serialize. + A JSON string representation of the object. + + + + Serializes the specified object to a JSON string. + + The object to serialize. + Indicates how the output is formatted. + + A JSON string representation of the object. + + + + + Serializes the specified object to a JSON string using a collection of . + + The object to serialize. + A collection converters used while serializing. + A JSON string representation of the object. + + + + Serializes the specified object to a JSON string using a collection of . + + The object to serialize. + Indicates how the output is formatted. + A collection converters used while serializing. + A JSON string representation of the object. + + + + Serializes the specified object to a JSON string using a collection of . + + The object to serialize. + Indicates how the output is formatted. + The used to serialize the object. + If this is null, default serialization settings will be is used. + + A JSON string representation of the object. + + + + + Deserializes the specified object to a Json object. + + The object to deserialize. + The deserialized object from the Json string. + + + + Deserializes the specified object to a Json object. + + The object to deserialize. + The of object being deserialized. + The deserialized object from the Json string. + + + + Deserializes the specified object to a Json object. + + The type of the object to deserialize. + The object to deserialize. + The deserialized object from the Json string. + + + + Deserializes the specified JSON to the given anonymous type. + + + The anonymous type to deserialize to. This can't be specified + traditionally and must be infered from the anonymous type passed + as a parameter. + + The object to deserialize. + The anonymous type object. + The deserialized anonymous type from the JSON string. + + + + Deserializes the JSON string to the specified type. + + The type of the object to deserialize. + The object to deserialize. + Converters to use while deserializing. + The deserialized object from the JSON string. + + + + Deserializes the JSON string to the specified type. + + The type of the object to deserialize. + The object to deserialize. + + The used to deserialize the object. + If this is null, default serialization settings will be is used. + + The deserialized object from the JSON string. + + + + Deserializes the JSON string to the specified type. + + The object to deserialize. + The type of the object to deserialize. + Converters to use while deserializing. + The deserialized object from the JSON string. + + + + Deserializes the JSON string to the specified type. + + The JSON to deserialize. + The type of the object to deserialize. + + The used to deserialize the object. + If this is null, default serialization settings will be is used. + + The deserialized object from the JSON string. + + + + Populates the object with values from the JSON string. + + The JSON to populate values from. + The target object to populate values onto. + + + + Populates the object with values from the JSON string. + + The JSON to populate values from. + The target object to populate values onto. + + The used to deserialize the object. + If this is null, default serialization settings will be is used. + + + + + Serializes the XML node to a JSON string. + + The node to serialize. + A JSON string of the XmlNode. + + + + Deserializes the XmlNode from a JSON string. + + The JSON string. + The deserialized XmlNode + + + + Deserializes the XmlNode from a JSON string nested in a root elment. + + The JSON string. + The name of the root element to append when deserializing. + The deserialized XmlNode + + + + The exception thrown when an error occurs during Json serialization or deserialization. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class + with a specified error message. + + The error message that explains the reason for the exception. + + + + Initializes a new instance of the class + with a specified error message and a reference to the inner exception that is the cause of this exception. + + The error message that explains the reason for the exception. + The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified. + + + + Serializes and deserializes objects into and from the JSON format. + The enables you to control how objects are encoded into JSON. + + + + + Initializes a new instance of the class. + + + + + Creates a new instance using the specified . + + The settings to be applied to the . + A new instance using the specified . + + + + Populates the JSON values onto the target object. + + The that contains the JSON structure to reader values from. + The target object to populate values onto. + + + + Populates the JSON values onto the target object. + + The that contains the JSON structure to reader values from. + The target object to populate values onto. + + + + Deserializes the Json structure contained by the specified . + + The that contains the JSON structure to deserialize. + The being deserialized. + + + + Deserializes the Json structure contained by the specified + into an instance of the specified type. + + The containing the object. + The of object being deserialized. + The instance of being deserialized. + + + + Deserializes the Json structure contained by the specified + into an instance of the specified type. + + The containing the object. + The type of the object to deserialize. + The instance of being deserialized. + + + + Deserializes the Json structure contained by the specified + into an instance of the specified type. + + The containing the object. + The of object being deserialized. + The instance of being deserialized. + + + + Serializes the specified and writes the Json structure + to a Stream using the specified . + + The used to write the Json structure. + The to serialize. + + + + Serializes the specified and writes the Json structure + to a Stream using the specified . + + The used to write the Json structure. + The to serialize. + + + + Occurs when the errors during serialization and deserialization. + + + + + Gets or sets the used by the serializer when resolving references. + + + + + Gets or sets the used by the serializer when resolving type names. + + + + + Gets or sets how type name writing and reading is handled by the serializer. + + + + + Gets or sets how object references are preserved by the serializer. + + + + + Get or set how reference loops (e.g. a class referencing itself) is handled. + + + + + Get or set how missing members (e.g. JSON contains a property that isn't a member on the object) are handled during deserialization. + + + + + Get or set how null values are handled during serialization and deserialization. + + + + + Get or set how null default are handled during serialization and deserialization. + + + + + Gets or sets how objects are created during deserialization. + + The object creation handling. + + + + Gets or sets how constructors are used during deserialization. + + The constructor handling. + + + + Gets a collection that will be used during serialization. + + Collection that will be used during serialization. + + + + Gets or sets the contract resolver used by the serializer when + serializing .NET objects to JSON and vice versa. + + + + + Gets or sets the used by the serializer when invoking serialization callback methods. + + The context. + + + + Contains the LINQ to JSON extension methods. + + + + + Returns a collection of tokens that contains the ancestors of every token in the source collection. + + The type of the objects in source, constrained to . + An of that contains the source collection. + An of that contains the ancestors of every node in the source collection. + + + + Returns a collection of tokens that contains the descendants of every token in the source collection. + + The type of the objects in source, constrained to . + An of that contains the source collection. + An of that contains the descendants of every node in the source collection. + + + + Returns a collection of child properties of every object in the source collection. + + An of that contains the source collection. + An of that contains the properties of every object in the source collection. + + + + Returns a collection of child values of every object in the source collection with the given key. + + An of that contains the source collection. + The token key. + An of that contains the values of every node in the source collection with the given key. + + + + Returns a collection of child values of every object in the source collection. + + An of that contains the source collection. + An of that contains the values of every node in the source collection. + + + + Returns a collection of converted child values of every object in the source collection with the given key. + + The type to convert the values to. + An of that contains the source collection. + The token key. + An that contains the converted values of every node in the source collection with the given key. + + + + Returns a collection of converted child values of every object in the source collection. + + The type to convert the values to. + An of that contains the source collection. + An that contains the converted values of every node in the source collection. + + + + Converts the value. + + The type to convert the value to. + A cast as a of . + A converted value. + + + + Converts the value. + + The source collection type. + The type to convert the value to. + A cast as a of . + A converted value. + + + + Returns a collection of child tokens of every array in the source collection. + + The source collection type. + An of that contains the source collection. + An of that contains the values of every node in the source collection. + + + + Returns a collection of converted child tokens of every array in the source collection. + + An of that contains the source collection. + The type to convert the values to. + The source collection type. + An that contains the converted values of every node in the source collection. + + + + Returns the input typed as . + + An of that contains the source collection. + The input typed as . + + + + Returns the input typed as . + + The source collection type. + An of that contains the source collection. + The input typed as . + + + + Represents a JSON constructor. + + + + + Represents a token that can contain other tokens. + + + + + Raises the event. + + The instance containing the event data. + + + + Raises the event. + + The instance containing the event data. + + + + Returns a collection of the child tokens of this token, in document order. + + + An of containing the child tokens of this , in document order. + + + + + Returns a collection of the child values of this token, in document order. + + The type to convert the values to. + + A containing the child values of this , in document order. + + + + + Returns a collection of the descendant tokens for this token in document order. + + An containing the descendant tokens of the . + + + + Adds the specified content as children of this . + + The content to be added. + + + + Adds the specified content as the first children of this . + + The content to be added. + + + + Creates an that can be used to add tokens to the . + + An that is ready to have content written to it. + + + + Replaces the children nodes of this token with the specified content. + + The content. + + + + Removes the child nodes from this token. + + + + + Occurs when the list changes or an item in the list changes. + + + + + Occurs before an item is added to the collection. + + + + + Gets a value indicating whether this token has childen tokens. + + + true if this token has child values; otherwise, false. + + + + + Get the first child token of this token. + + + A containing the first child token of the . + + + + + Get the last child token of this token. + + + A containing the last child token of the . + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class from another object. + + A object to copy from. + + + + Initializes a new instance of the class with the specified name and content. + + The constructor name. + The contents of the constructor. + + + + Initializes a new instance of the class with the specified name and content. + + The constructor name. + The contents of the constructor. + + + + Initializes a new instance of the class with the specified name. + + The constructor name. + + + + Writes this token to a . + + A into which this method will write. + A collection of which will be used when writing the token. + + + + Loads an from a . + + A that will be read for the content of the . + A that contains the JSON that was read from the specified . + + + + Gets or sets the name of this constructor. + + The constructor name. + + + + Gets the node type for this . + + The type. + + + + Gets the with the specified key. + + The with the specified key. + + + + Represents a collection of objects. + + The type of token + + + + An empty collection of objects. + + + + + Initializes a new instance of the struct. + + The enumerable. + + + + Returns an enumerator that iterates through the collection. + + + A that can be used to iterate through the collection. + + + + + Returns an enumerator that iterates through a collection. + + + An object that can be used to iterate through the collection. + + + + + Determines whether the specified is equal to this instance. + + The to compare with this instance. + + true if the specified is equal to this instance; otherwise, false. + + + + + Returns a hash code for this instance. + + + A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. + + + + + Gets the with the specified key. + + + + + + Represents a JSON object. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class from another object. + + A object to copy from. + + + + Initializes a new instance of the class with the specified content. + + The contents of the object. + + + + Initializes a new instance of the class with the specified content. + + The contents of the object. + + + + Gets an of this object's properties. + + An of this object's properties. + + + + Gets a the specified name. + + The property name. + A with the specified name or null. + + + + Gets an of this object's property values. + + An of this object's property values. + + + + Loads an from a . + + A that will be read for the content of the . + A that contains the JSON that was read from the specified . + + + + Load a from a string that contains JSON. + + A that contains JSON. + A populated from the string that contains JSON. + + + + Creates a from an object. + + The object that will be used to create . + A with the values of the specified object + + + + Creates a from an object. + + The object that will be used to create . + The that will be used to read the object. + A with the values of the specified object + + + + Writes this token to a . + + A into which this method will write. + A collection of which will be used when writing the token. + + + + Adds the specified property name. + + Name of the property. + The value. + + + + Removes the property with the specified name. + + Name of the property. + true if item was successfully removed; otherwise, false. + + + + Tries the get value. + + Name of the property. + The value. + true if a value was successfully retrieved; otherwise, false. + + + + Returns an enumerator that iterates through the collection. + + + A that can be used to iterate through the collection. + + + + + Raises the event with the provided arguments. + + Name of the property. + + + + Occurs when a property value changes. + + + + + Gets the node type for this . + + The type. + + + + Gets the with the specified key. + + The with the specified key. + + + + Gets or sets the with the specified property name. + + + + + + Gets the number of elements contained in the . + + + The number of elements contained in the . + + + + Represents a JSON array. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class from another object. + + A object to copy from. + + + + Initializes a new instance of the class with the specified content. + + The contents of the array. + + + + Initializes a new instance of the class with the specified content. + + The contents of the array. + + + + Loads an from a . + + A that will be read for the content of the . + A that contains the JSON that was read from the specified . + + + + Load a from a string that contains JSON. + + A that contains JSON. + A populated from the string that contains JSON. + + + + Creates a from an object. + + The object that will be used to create . + A with the values of the specified object + + + + Creates a from an object. + + The object that will be used to create . + The that will be used to read the object. + A with the values of the specified object + + + + Writes this token to a . + + A into which this method will write. + A collection of which will be used when writing the token. + + + + Determines the index of a specific item in the . + + The object to locate in the . + + The index of if found in the list; otherwise, -1. + + + + + Inserts an item to the at the specified index. + + The zero-based index at which should be inserted. + The object to insert into the . + + is not a valid index in the . + The is read-only. + + + + Removes the item at the specified index. + + The zero-based index of the item to remove. + + is not a valid index in the . + The is read-only. + + + + Adds an item to the . + + The object to add to the . + The is read-only. + + + + Removes all items from the . + + The is read-only. + + + + Determines whether the contains a specific value. + + The object to locate in the . + + true if is found in the ; otherwise, false. + + + + + Removes the first occurrence of a specific object from the . + + The object to remove from the . + + true if was successfully removed from the ; otherwise, false. This method also returns false if is not found in the original . + + The is read-only. + + + + Gets the node type for this . + + The type. + + + + Gets the with the specified key. + + The with the specified key. + + + + Gets or sets the at the specified index. + + + + + + Gets the number of elements contained in the . + + + The number of elements contained in the . + + + + Represents a reader that provides fast, non-cached, forward-only access to serialized Json data. + + + + + Initializes a new instance of the class. + + The token to read from. + + + + Reads the next JSON token from the stream as a . + + + A or a null reference if the next JSON token is null. + + + + + Reads the next JSON token from the stream. + + + true if the next token was read successfully; false if there are no more tokens to read. + + + + + Represents a JSON property. + + + + + Initializes a new instance of the class from another object. + + A object to copy from. + + + + Returns a collection of the child tokens of this token, in document order. + + + An of containing the child tokens of this , in document order. + + + + + Initializes a new instance of the class. + + The property name. + The property content. + + + + Initializes a new instance of the class. + + The property name. + The property content. + + + + Writes this token to a . + + A into which this method will write. + A collection of which will be used when writing the token. + + + + Loads an from a . + + A that will be read for the content of the . + A that contains the JSON that was read from the specified . + + + + Gets the property name. + + The property name. + + + + Gets or sets the property value. + + The property value. + + + + Gets the node type for this . + + The type. + + + + Specifies the type of token. + + + + + No token type has been set. + + + + + A JSON object. + + + + + A JSON array. + + + + + A JSON constructor. + + + + + A JSON object property. + + + + + A comment. + + + + + An integer value. + + + + + A float value. + + + + + A string value. + + + + + A boolean value. + + + + + A null value. + + + + + An undefined value. + + + + + A date value. + + + + + A raw JSON value. + + + + + A collection of bytes value. + + + + + Contains the JSON schema extension methods. + + + + + Determines whether the is valid. + + The source to test. + The schema to test with. + + true if the specified is valid; otherwise, false. + + + + + Validates the specified . + + The source to test. + The schema to test with. + + + + Validates the specified . + + The source to test. + The schema to test with. + The validation event handler. + + + + Returns detailed information about the schema exception. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class + with a specified error message. + + The error message that explains the reason for the exception. + + + + Initializes a new instance of the class + with a specified error message and a reference to the inner exception that is the cause of this exception. + + The error message that explains the reason for the exception. + The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified. + + + + Gets the line number indicating where the error occurred. + + The line number indicating where the error occurred. + + + + Gets the line position indicating where the error occurred. + + The line position indicating where the error occurred. + + + + Resolves from an id. + + + + + Initializes a new instance of the class. + + + + + Gets a for the specified id. + + The id. + A for the specified id. + + + + Gets or sets the loaded schemas. + + The loaded schemas. + + + + Specifies undefined schema Id handling options for the . + + + + + Do not infer a schema Id. + + + + + Use the .NET type name as the schema Id. + + + + + Use the assembly qualified .NET type name as the schema Id. + + + + + Returns detailed information related to the . + + + + + Gets the associated with the validation event. + + The JsonSchemaException associated with the validation event. + + + + Gets the text description corresponding to the validation event. + + The text description. + + + + Represents the callback method that will handle JSON schema validation events and the . + + + + + Resolves member mappings for a type, camel casing property names. + + + + + Used by to resolves a for a given . + + + + + Used by to resolves a for a given . + + + + + Resolves the contract for a given type. + + The type to resolve a contract for. + The contract for a given type. + + + + Initializes a new instance of the class. + + + + + Resolves the contract for a given type. + + The type to resolve a contract for. + The contract for a given type. + + + + Gets the serializable members for the type. + + The type to get serializable members for. + The serializable members for the type. + + + + Creates a for the given type. + + Type of the object. + A for the given type. + + + + Resolves the default for the contract. + + Type of the object. + + + + + Creates a for the given type. + + Type of the object. + A for the given type. + + + + Creates a for the given type. + + Type of the object. + A for the given type. + + + + Creates a for the given type. + + Type of the object. + A for the given type. + + + + Creates a for the given type. + + Type of the object. + A for the given type. + + + + Creates properties for the given . + + The contract to create properties for. + Properties for the given . + + + + Creates the used by the serializer to get and set values from a member. + + The member. + The used by the serializer to get and set values from a member. + + + + Creates a for the given . + + The member's declaring types . + The member to create a for. + A created for the given . + + + + Resolves the name of the property. + + Name of the property. + Name of the property. + + + + Gets or sets the default members search flags. + + The default members search flags. + + + + Resolves the name of the property. + + Name of the property. + The property name camel cased. + + + + The default serialization binder used when resolving and loading classes from type names. + + + + + When overridden in a derived class, controls the binding of a serialized object to a type. + + Specifies the name of the serialized object. + Specifies the name of the serialized object. + + The type of the object the formatter creates a new instance of. + + + + + Get and set values for a using dynamic methods. + + + + + Provides methods to get and set values. + + + + + Sets the value. + + The target to set the value on. + The value to set on the target. + + + + Gets the value. + + The target to get the value from. + The value. + + + + Initializes a new instance of the class. + + The member info. + + + + Sets the value. + + The target to set the value on. + The value to set on the target. + + + + Gets the value. + + The target to get the value from. + The value. + + + + Provides information surrounding an error. + + + + + Gets or sets the error. + + The error. + + + + Gets the original object that caused the error. + + The original object that caused the error. + + + + Gets the member that caused the error. + + The member that caused the error. + + + + Gets or sets a value indicating whether this is handled. + + true if handled; otherwise, false. + + + + Provides data for the Error event. + + + + + Initializes a new instance of the class. + + The current object. + The error context. + + + + Gets the current object the error event is being raised against. + + The current object the error event is being raised against. + + + + Gets the error context. + + The error context. + + + + Contract details for a used by the . + + + + + Contract details for a used by the . + + + + + Gets the underlying type for the contract. + + The underlying type for the contract. + + + + Gets or sets the type created during deserialization. + + The type created during deserialization. + + + + Gets or sets whether this type contract is serialized as a reference. + + Whether this type contract is serialized as a reference. + + + + Gets or sets the default for this contract. + + The converter. + + + + Gets or sets the method called immediately after deserialization of the object. + + The method called immediately after deserialization of the object. + + + + Gets or sets the method called during deserialization of the object. + + The method called during deserialization of the object. + + + + Gets or sets the method called after serialization of the object graph. + + The method called after serialization of the object graph. + + + + Gets or sets the method called before serialization of the object. + + The method called before serialization of the object. + + + + Gets or sets the default creator. + + The default creator. + + + + Gets or sets a value indicating whether [default creator non public]. + + true if the default object creator is non-public; otherwise, false. + + + + Gets or sets the method called when an error is thrown during the serialization of the object. + + The method called when an error is thrown during the serialization of the object. + + + + Initializes a new instance of the class. + + The underlying type for the contract. + + + + Contract details for a used by the . + + + + + Initializes a new instance of the class. + + The underlying type for the contract. + + + + Contract details for a used by the . + + + + + Initializes a new instance of the class. + + The underlying type for the contract. + + + + Contract details for a used by the . + + + + + Initializes a new instance of the class. + + The underlying type for the contract. + + + + Maps a JSON property to a .NET member. + + + + + Gets the name of the property. + + The name of the property. + + + + Gets the that will get and set the during serialization. + + The that will get and set the during serialization. + + + + Gets or sets the type of the property. + + The type of the property. + + + + Gets or sets the for the property. + If set this converter takes presidence over the contract converter for the property type. + + The converter. + + + + Gets a value indicating whether this is ignored. + + true if ignored; otherwise, false. + + + + Gets a value indicating whether this is readable. + + true if readable; otherwise, false. + + + + Gets a value indicating whether this is writable. + + true if writable; otherwise, false. + + + + Gets the member converter. + + The member converter. + + + + Gets the default value. + + The default value. + + + + Gets a value indicating whether this is required. + + A value indicating whether this is required. + + + + Gets a value indicating whether this property preserves object references. + + + true if this instance is reference; otherwise, false. + + + + + Gets the property null value handling. + + The null value handling. + + + + Gets the property default value handling. + + The default value handling. + + + + Gets the property reference loop handling. + + The reference loop handling. + + + + Gets the property object creation handling. + + The object creation handling. + + + + A collection of objects. + + + + + Initializes a new instance of the class. + + The contract. + + + + When implemented in a derived class, extracts the key from the specified element. + + The element from which to extract the key. + The key for the specified element. + + + + Adds a object. + + The property to add to the collection. + + + + Gets the closest matching object. + First attempts to get an exact case match of propertyName and then + a case insensitive match. + + Name of the property. + A matching property if found. + + + + Gets a property by property name. + + The name of the property to get. + Type property name string comparison. + A matching property if found. + + + + Specifies missing member handling options for the . + + + + + Ignore a missing member and do not attempt to deserialize it. + + + + + Throw a when a missing member is encountered during deserialization. + + + + + Specifies null value handling options for the . + + + + + Include null values when serializing and deserializing objects. + + + + + Ignore null values when serializing and deserializing objects. + + + + + Specifies reference loop handling options for the . + + + + + Throw a when a loop is encountered. + + + + + Ignore loop references and do not serialize. + + + + + Serialize loop references. + + + + + An in-memory representation of a JSON Schema. + + + + + Initializes a new instance of the class. + + + + + Reads a from the specified . + + The containing the JSON Schema to read. + The object representing the JSON Schema. + + + + Reads a from the specified . + + The containing the JSON Schema to read. + The to use when resolving schema references. + The object representing the JSON Schema. + + + + Load a from a string that contains schema JSON. + + A that contains JSON. + A populated from the string that contains JSON. + + + + Parses the specified json. + + The json. + The resolver. + A populated from the string that contains JSON. + + + + Writes this schema to a . + + A into which this method will write. + + + + Writes this schema to a using the specified . + + A into which this method will write. + The resolver used. + + + + Returns a that represents the current . + + + A that represents the current . + + + + + Gets or sets the id. + + + + + Gets or sets the title. + + + + + Gets or sets whether the object is optional. + + + + + Gets or sets whether the object is read only. + + + + + Gets or sets whether the object is visible to users. + + + + + Gets or sets whether the object is transient. + + + + + Gets or sets the description of the object. + + + + + Gets or sets the types of values allowed by the object. + + The type. + + + + Gets or sets the pattern. + + The pattern. + + + + Gets or sets the minimum length. + + The minimum length. + + + + Gets or sets the maximum length. + + The maximum length. + + + + Gets or sets the maximum decimals. + + The maximum decimals. + + + + Gets or sets the minimum. + + The minimum. + + + + Gets or sets the maximum. + + The maximum. + + + + Gets or sets the minimum number of items. + + The minimum number of items. + + + + Gets or sets the maximum number of items. + + The maximum number of items. + + + + Gets or sets the of items. + + The of items. + + + + Gets or sets the of properties. + + The of properties. + + + + Gets or sets the of additional properties. + + The of additional properties. + + + + Gets or sets a value indicating whether additional properties are allowed. + + + true if additional properties are allowed; otherwise, false. + + + + + Gets or sets the required property if this property is present. + + The required property if this property is present. + + + + Gets or sets the identity. + + The identity. + + + + Gets or sets the a collection of valid enum values allowed. + + A collection of valid enum values allowed. + + + + Gets or sets a collection of options. + + A collection of options. + + + + Gets or sets disallowed types. + + The disallow types. + + + + Gets or sets the default value. + + The default value. + + + + Gets or sets the extend . + + The extended . + + + + Gets or sets the format. + + The format. + + + + Generates a from a specified . + + + + + Generate a from the specified type. + + The type to generate a from. + A generated from the specified type. + + + + Generate a from the specified type. + + The type to generate a from. + The used to resolve schema references. + A generated from the specified type. + + + + Generate a from the specified type. + + The type to generate a from. + Specify whether the generated root will be nullable. + A generated from the specified type. + + + + Generate a from the specified type. + + The type to generate a from. + The used to resolve schema references. + Specify whether the generated root will be nullable. + A generated from the specified type. + + + + Gets or sets how undefined schemas are handled by the serializer. + + + + + Gets or sets the contract resolver. + + The contract resolver. + + + + The value types allowed by the . + + + + + No type specified. + + + + + String type. + + + + + Float type. + + + + + Integer type. + + + + + Boolean type. + + + + + Object type. + + + + + Array type. + + + + + Null type. + + + + + Any type. + + + + + Contract details for a used by the . + + + + + Initializes a new instance of the class. + + The underlying type for the contract. + + + + Gets or sets the object member serialization. + + The member object serialization. + + + + Gets the object's properties. + + The object's properties. + + + + Gets or sets the parametrized constructor used to create the object. + + The parametrized constructor. + + + + When applied to a method, specifies that the method is called when an error occurs serializing an object. + + + + + Get and set values for a using reflection. + + + + + Initializes a new instance of the class. + + The member info. + + + + Sets the value. + + The target to set the value on. + The value to set on the target. + + + + Gets the value. + + The target to get the value from. + The value. + + + + Specifies type name handling options for the . + + + + + Do not include the .NET type name when serializing types. + + + + + Include the .NET type name when serializing into a JSON object structure. + + + + + Include the .NET type name when serializing into a JSON array structure. + + + + + Always include the .NET type name when serializing. + + + + + Converts the value to the specified type. + + The type to convert the value to. + The value to convert. + The converted type. + + + + Converts the value to the specified type. + + The type to convert the value to. + The value to convert. + The culture to use when converting. + The converted type. + + + + Converts the value to the specified type. + + The value to convert. + The culture to use when converting. + The type to convert the value to. + The converted type. + + + + Converts the value to the specified type. + + The type to convert the value to. + The value to convert. + The converted value if the conversion was successful or the default value of T if it failed. + + true if initialValue was converted successfully; otherwise, false. + + + + + Converts the value to the specified type. + + The type to convert the value to. + The value to convert. + The culture to use when converting. + The converted value if the conversion was successful or the default value of T if it failed. + + true if initialValue was converted successfully; otherwise, false. + + + + + Converts the value to the specified type. + + The value to convert. + The culture to use when converting. + The type to convert the value to. + The converted value if the conversion was successful or the default value of T if it failed. + + true if initialValue was converted successfully; otherwise, false. + + + + + Converts the value to the specified type. If the value is unable to be converted, the + value is checked whether it assignable to the specified type. + + The type to convert or cast the value to. + The value to convert. + The converted type. If conversion was unsuccessful, the initial value is returned if assignable to the target type + + + + Converts the value to the specified type. If the value is unable to be converted, the + value is checked whether it assignable to the specified type. + + The type to convert or cast the value to. + The value to convert. + The culture to use when converting. + The converted type. If conversion was unsuccessful, the initial value is returned if assignable to the target type + + + + Converts the value to the specified type. If the value is unable to be converted, the + value is checked whether it assignable to the specified type. + + The value to convert. + The culture to use when converting. + The type to convert or cast the value to. + + The converted type. If conversion was unsuccessful, the initial value + is returned if assignable to the target type. + + + + + Converts the value to the specified type. If the value is unable to be converted, the + value is checked whether it assignable to the specified type. + + The type to convert the value to. + The value to convert. + The converted value if the conversion was successful or the default value of T if it failed. + + true if initialValue was converted successfully or is assignable; otherwise, false. + + + + + Converts the value to the specified type. If the value is unable to be converted, the + value is checked whether it assignable to the specified type. + + The type to convert the value to. + The value to convert. + The culture to use when converting. + The converted value if the conversion was successful or the default value of T if it failed. + + true if initialValue was converted successfully or is assignable; otherwise, false. + + + + + Converts the value to the specified type. If the value is unable to be converted, the + value is checked whether it assignable to the specified type. + + The value to convert. + The culture to use when converting. + The type to convert the value to. + The converted value if the conversion was successful or the default value of T if it failed. + + true if initialValue was converted successfully or is assignable; otherwise, false. + + + + + Parses the specified enum member name, returning it's value. + + Name of the enum member. + + + + + Parses the specified enum member name, returning it's value. + + Name of the enum member. + If set to true ignore case. + + + + + Gets a dictionary of the names and values of an Enum type. + + + + + + Gets a dictionary of the names and values of an Enum type. + + + + + + Gets a dictionary of the names and values of an Enum type. + + The enum type to get names and values for. + + + + + Gets the maximum valid value of an Enum type. Flags enums are ORed. + + The type of the returned value. Must be assignable from the enum's underlying value type. + The enum type to get the maximum value for. + + + + + Specifies the type of Json token. + + + + + This is returned by the if a method has not been called. + + + + + An object start token. + + + + + An array start token. + + + + + A constructor start token. + + + + + An object property name. + + + + + A comment. + + + + + Raw JSON. + + + + + An interger. + + + + + A float. + + + + + A string. + + + + + A boolean. + + + + + A null token. + + + + + An undefined token. + + + + + An object end token. + + + + + An array end token. + + + + + A constructor end token. + + + + + A Date. + + + + + Byte data. + + + + + Specifies the state of the . + + + + + An exception has been thrown, which has left the in an invalid state. + You may call the method to put the in the Closed state. + Any other method calls results in an being thrown. + + + + + The method has been called. + + + + + An object is being written. + + + + + A array is being written. + + + + + A constructor is being written. + + + + + A property is being written. + + + + + A write method has not been called. + + + + + Specifies formatting options for the . + + + + + No special formatting is applied. This is the default. + + + + + Causes child objects to be indented according to the and settings. + + + + + Builds a string. Unlike StringBuilder this class lets you reuse it's internal buffer. + + + + + Determines whether the collection is null or empty. + + The collection. + + true if the collection is null or empty; otherwise, false. + + + + + Determines whether the collection is null or empty. + + The collection. + + true if the collection is null or empty; otherwise, false. + + + + + Determines whether the collection is null, empty or its contents are uninitialized values. + + The list. + + true if the collection is null or empty or its contents are uninitialized values; otherwise, false. + + + + + Makes a slice of the specified list in between the start and end indexes. + + The list. + The start index. + The end index. + A slice of the list. + + + + Makes a slice of the specified list in between the start and end indexes, + getting every so many items based upon the step. + + The list. + The start index. + The end index. + The step. + A slice of the list. + + + + Group the collection using a function which returns the key. + + The source collection to group. + The key selector. + A Dictionary with each key relating to a list of objects in a list grouped under it. + + + + Adds the elements of the specified collection to the specified generic IList. + + The list to add to. + The collection of elements to add. + + + + Gets the type of the typed collection's items. + + The type. + The type of the typed collection's items. + + + + Tests whether the list's items are their unitialized value. + + The list. + Whether the list's items are their unitialized value + + + + Gets the member's underlying type. + + The member. + The underlying type of the member. + + + + Determines whether the member is an indexed property. + + The member. + + true if the member is an indexed property; otherwise, false. + + + + + Determines whether the property is an indexed property. + + The property. + + true if the property is an indexed property; otherwise, false. + + + + + Gets the member's value on the object. + + The member. + The target object. + The member's value on the object. + + + + Sets the member's value on the target object. + + The member. + The target. + The value. + + + + Determines whether the specified MemberInfo can be read. + + The MemberInfo to determine whether can be read. + + true if the specified MemberInfo can be read; otherwise, false. + + + + + Determines whether the specified MemberInfo can be set. + + The MemberInfo to determine whether can be set. + + true if the specified MemberInfo can be set; otherwise, false. + + + + + Determines whether the string contains white space. + + The string to test for white space. + + true if the string contains white space; otherwise, false. + + + + + Determines whether the string is all white space. Empty string will return false. + + The string to test whether it is all white space. + + true if the string is all white space; otherwise, false. + + + + + Ensures the target string ends with the specified string. + + The target. + The value. + The target string with the value string at the end. + + + + Perform an action if the string is not null or empty. + + The value. + The action to perform. + + + + Indents the specified string. + + The string to indent. + The number of characters to indent by. + + + + + Indents the specified string. + + The string to indent. + The number of characters to indent by. + The indent character. + + + + + Numbers the lines. + + The string to number. + + + + + Nulls an empty string. + + The string. + Null if the string was null, otherwise the string unchanged. + + + diff --git a/bin/libbulletnet.dll b/bin/libbulletnet.dll index 3edd005cc893bff51d9a01bca04d560d0fee15d4..8ec7c55da4ff6777fca389342d5f97bf44bac151 100644 GIT binary patch delta 69128 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 wo>I?gkKZFCv*bAVs+0#zs6cb1Dc7{rv Date: Fri, 12 Mar 2010 22:39:15 +0000 Subject: [PATCH 20/28] refactor: move client invoked AttachObject from SceneGraph to AttachmentsModule --- .../Avatar/Attachments/AttachmentsModule.cs | 32 ++++++++++++++++- .../Interfaces/IAttachmentsModule.cs | 17 +++++++-- OpenSim/Region/Framework/Scenes/Scene.cs | 13 ++++--- OpenSim/Region/Framework/Scenes/SceneGraph.cs | 35 ------------------- 4 files changed, 53 insertions(+), 44 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index 3b7fe8872b..3c2cc42dc0 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs @@ -67,6 +67,36 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments get { return false; } } + public void AttachObject(IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, Quaternion rot, bool silent) + { + m_log.Debug("[ATTACHMENTS MODULE]: Invoking AttachObject"); + + // If we can't take it, we can't attach it! + SceneObjectPart part = m_scene.GetSceneObjectPart(objectLocalID); + if (part == null) + return; + + if (!m_scene.Permissions.CanTakeObject(part.UUID, remoteClient.AgentId)) + return; + + // Calls attach with a Zero position + if (AttachObject(remoteClient, objectLocalID, AttachmentPt, rot, Vector3.Zero, false)) + { + m_scene.EventManager.TriggerOnAttach(objectLocalID, part.ParentGroup.GetFromItemID(), remoteClient.AgentId); + + // Save avatar attachment information + ScenePresence presence; + if (m_scene.AvatarFactory != null && m_scene.TryGetAvatar(remoteClient.AgentId, out presence)) + { + m_log.Info( + "[ATTACHMENTS MODULE]: Saving avatar attachment. AgentID: " + remoteClient.AgentId + + ", AttachmentPoint: " + AttachmentPt); + + m_scene.AvatarFactory.UpdateDatabase(remoteClient.AgentId, presence.Appearance); + } + } + } + public bool AttachObject( IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, Quaternion rot, Vector3 attachPos, bool silent) { @@ -143,7 +173,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments SceneObjectGroup att, IClientAPI remoteClient, UUID itemID, uint AttachmentPt) { m_log.DebugFormat( - "[ATTACHMENTS MODULEY]: Updating inventory of {0} to show attachment of {1} (item ID {2})", + "[ATTACHMENTS MODULE]: Updating inventory of {0} to show attachment of {1} (item ID {2})", remoteClient.Name, att.Name, itemID); if (!att.IsDeleted) diff --git a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs index 6cf2a2e3a0..21c10569c7 100644 --- a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs @@ -34,6 +34,17 @@ namespace OpenSim.Region.Framework.Interfaces { public interface IAttachmentsModule { + /// + /// Attach an object to an avatar from the world. + /// + /// + /// + /// + /// + /// + void AttachObject( + IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, Quaternion rot, bool silent); + /// /// Attach an object to an avatar. /// @@ -41,11 +52,11 @@ namespace OpenSim.Region.Framework.Interfaces /// /// /// - /// + /// /// - /// true if the object was successfully attached, false otherwise + /// true if the object was successfully attached, false otherwise bool AttachObject( - IClientAPI controllingClient, uint localID, uint attachPoint, Quaternion rot, Vector3 pos, bool silent); + IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, Quaternion rot, Vector3 attachPos, bool silent); /// /// Update the user inventory to the attachment of an item diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 87a753e5eb..d4d134fc8b 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -2644,12 +2644,14 @@ namespace OpenSim.Region.Framework.Scenes public virtual void SubscribeToClientAttachmentEvents(IClientAPI client) { client.OnRezSingleAttachmentFromInv += RezSingleAttachment; - client.OnRezMultipleAttachmentsFromInv += RezMultipleAttachments; - client.OnObjectAttach += m_sceneGraph.AttachObject; + client.OnRezMultipleAttachmentsFromInv += RezMultipleAttachments; client.OnObjectDetach += m_sceneGraph.DetachObject; if (AttachmentsModule != null) + { + client.OnObjectAttach += AttachmentsModule.AttachObject; client.OnDetachAttachmentIntoInv += AttachmentsModule.ShowDetachInUserInventory; + } } public virtual void SubscribeToClientTeleportEvents(IClientAPI client) @@ -2774,7 +2776,6 @@ namespace OpenSim.Region.Framework.Scenes client.OnRezObject -= RezObject; } - public virtual void UnSubscribeToClientInventoryEvents(IClientAPI client) { client.OnCreateNewInventoryItem -= CreateNewInventoryItem; @@ -2799,12 +2800,14 @@ namespace OpenSim.Region.Framework.Scenes public virtual void UnSubscribeToClientAttachmentEvents(IClientAPI client) { client.OnRezMultipleAttachmentsFromInv -= RezMultipleAttachments; - client.OnRezSingleAttachmentFromInv -= RezSingleAttachment; - client.OnObjectAttach -= m_sceneGraph.AttachObject; + client.OnRezSingleAttachmentFromInv -= RezSingleAttachment; client.OnObjectDetach -= m_sceneGraph.DetachObject; if (AttachmentsModule != null) + { + client.OnObjectAttach -= AttachmentsModule.AttachObject; client.OnDetachAttachmentIntoInv -= AttachmentsModule.ShowDetachInUserInventory; + } } public virtual void UnSubscribeToClientTeleportEvents(IClientAPI client) diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index 380722d53b..a88d456e10 100644 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs @@ -486,41 +486,6 @@ namespace OpenSim.Region.Framework.Scenes } } - /// - /// Event Handling routine for Attach Object - /// - /// - /// - /// - /// - protected internal void AttachObject(IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, Quaternion rot, bool silent) - { - // If we can't take it, we can't attach it! - SceneObjectPart part = m_parentScene.GetSceneObjectPart(objectLocalID); - if (part == null) - return; - - if (!m_parentScene.Permissions.CanTakeObject(part.UUID, remoteClient.AgentId)) - return; - - // Calls attach with a Zero position - if (m_parentScene.AttachmentsModule.AttachObject(remoteClient, objectLocalID, AttachmentPt, rot, Vector3.Zero, false)) - { - m_parentScene.SendAttachEvent(objectLocalID, part.ParentGroup.GetFromItemID(), remoteClient.AgentId); - - // Save avatar attachment information - ScenePresence presence; - if (m_parentScene.AvatarFactory != null && m_parentScene.TryGetAvatar(remoteClient.AgentId, out presence)) - { - m_log.Info( - "[SCENE]: Saving avatar attachment. AgentID: " + remoteClient.AgentId - + ", AttachmentPoint: " + AttachmentPt); - - m_parentScene.AvatarFactory.UpdateDatabase(remoteClient.AgentId, presence.Appearance); - } - } - } - /// /// Rez an attachment /// From 3ea9fdea8b8a17f50e2156e7a09ebb6523a0d4fc Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Fri, 12 Mar 2010 14:39:51 -0800 Subject: [PATCH 21/28] Minor tweak to clean up SimianGrid asset service URLs --- .../Connectors/SimianGrid/SimianAssetServiceConnector.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs index 7cb075e803..1c22a72bc4 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs @@ -101,7 +101,7 @@ namespace OpenSim.Services.Connectors.SimianGrid throw new Exception("Asset connector init error"); } - if (!serviceUrl.EndsWith("/")) + if (!serviceUrl.EndsWith("/") && !serviceUrl.EndsWith("=")) serviceUrl = serviceUrl + '/'; m_serverUrl = serviceUrl; From 582375509c82220c40579c4e4095225bd9d67010 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 12 Mar 2010 22:48:49 +0000 Subject: [PATCH 22/28] refactor: move RezSingleAttachmentFromInventory() from SceneGraph to AttachmentsModule --- .../Avatar/Attachments/AttachmentsModule.cs | 46 ++++++++++++++++ .../Interfaces/IAttachmentsModule.cs | 11 +++- .../Framework/Scenes/Scene.Inventory.cs | 2 +- OpenSim/Region/Framework/Scenes/Scene.cs | 6 +-- OpenSim/Region/Framework/Scenes/SceneGraph.cs | 53 ------------------- 5 files changed, 60 insertions(+), 58 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index 3c2cc42dc0..084f3c9c54 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs @@ -168,6 +168,52 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments return true; } + + public SceneObjectGroup RezSingleAttachmentFromInventory(IClientAPI remoteClient, UUID itemID, uint AttachmentPt) + { + IInventoryAccessModule invAccess = m_scene.RequestModuleInterface(); + if (invAccess != null) + { + SceneObjectGroup objatt = invAccess.RezObject(remoteClient, + itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, + false, false, remoteClient.AgentId, true); + +// m_log.DebugFormat( +// "[ATTACHMENTS MODULE]: Retrieved single object {0} for attachment to {1} on point {2}", +// objatt.Name, remoteClient.Name, AttachmentPt); + + if (objatt != null) + { + bool tainted = false; + if (AttachmentPt != 0 && AttachmentPt != objatt.GetAttachmentPoint()) + tainted = true; + + AttachObject( + remoteClient, objatt.LocalId, AttachmentPt, Quaternion.Identity, objatt.AbsolutePosition, false); + //objatt.ScheduleGroupForFullUpdate(); + + if (tainted) + objatt.HasGroupChanged = true; + + // Fire after attach, so we don't get messy perms dialogs + // 3 == AttachedRez + objatt.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 3); + + // Do this last so that event listeners have access to all the effects of the attachment + m_scene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, remoteClient.AgentId); + } + else + { + m_log.WarnFormat( + "[ATTACHMENTS MODULE]: Could not retrieve item {0} for attaching to avatar {1} at point {2}", + itemID, remoteClient.Name, AttachmentPt); + } + + return objatt; + } + + return null; + } public UUID SetAttachmentInventoryStatus( SceneObjectGroup att, IClientAPI remoteClient, UUID itemID, uint AttachmentPt) diff --git a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs index 21c10569c7..1fa77e4274 100644 --- a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs @@ -56,7 +56,16 @@ namespace OpenSim.Region.Framework.Interfaces /// /// true if the object was successfully attached, false otherwise bool AttachObject( - IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, Quaternion rot, Vector3 attachPos, bool silent); + IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, Quaternion rot, Vector3 attachPos, bool silent); + + /// + /// Rez an attachment from user inventory + /// + /// + /// + /// + /// The scene object that was attached. Null if the scene object could not be found + SceneObjectGroup RezSingleAttachmentFromInventory(IClientAPI remoteClient, UUID itemID, uint AttachmentPt); /// /// Update the user inventory to the attachment of an item diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index 7277527fde..dcd92d6366 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs @@ -1854,7 +1854,7 @@ namespace OpenSim.Region.Framework.Scenes { m_log.DebugFormat("[USER INVENTORY]: Rezzing single attachment from item {0} for {1}", itemID, remoteClient.Name); - SceneObjectGroup att = m_sceneGraph.RezSingleAttachment(remoteClient, itemID, AttachmentPt); + SceneObjectGroup att = AttachmentsModule.RezSingleAttachmentFromInventory(remoteClient, itemID, AttachmentPt); if (att == null) { diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index d4d134fc8b..50553dde63 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -2338,10 +2338,10 @@ namespace OpenSim.Region.Framework.Scenes //m_log.DebugFormat(" >>> IncomingCreateObject(userID, itemID) <<< {0} {1}", userID, itemID); ScenePresence sp = GetScenePresence(userID); - if (sp != null) + if (sp != null && AttachmentsModule != null) { - uint attPt = (uint)sp.Appearance.GetAttachpoint(itemID); - m_sceneGraph.RezSingleAttachment(sp.ControllingClient, itemID, attPt); + uint attPt = (uint)sp.Appearance.GetAttachpoint(itemID); + AttachmentsModule.RezSingleAttachmentFromInventory(sp.ControllingClient, itemID, attPt); } return false; diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index a88d456e10..d944834f70 100644 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs @@ -486,59 +486,6 @@ namespace OpenSim.Region.Framework.Scenes } } - /// - /// Rez an attachment - /// - /// - /// - /// - /// The scene object that was attached. Null if the scene object could not be found - public SceneObjectGroup RezSingleAttachment(IClientAPI remoteClient, UUID itemID, uint AttachmentPt) - { - IInventoryAccessModule invAccess = m_parentScene.RequestModuleInterface(); - if (invAccess != null) - { - SceneObjectGroup objatt = invAccess.RezObject(remoteClient, - itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, - false, false, remoteClient.AgentId, true); - -// m_log.DebugFormat( -// "[SCENE GRAPH]: Retrieved single object {0} for attachment to {1} on point {2}", -// objatt.Name, remoteClient.Name, AttachmentPt); - - if (objatt != null) - { - bool tainted = false; - if (AttachmentPt != 0 && AttachmentPt != objatt.GetAttachmentPoint()) - tainted = true; - - m_parentScene.AttachmentsModule.AttachObject( - remoteClient, objatt.LocalId, AttachmentPt, Quaternion.Identity, objatt.AbsolutePosition, false); - //objatt.ScheduleGroupForFullUpdate(); - - if (tainted) - objatt.HasGroupChanged = true; - - // Fire after attach, so we don't get messy perms dialogs - // 3 == AttachedRez - objatt.CreateScriptInstances(0, true, m_parentScene.DefaultScriptEngine, 3); - - // Do this last so that event listeners have access to all the effects of the attachment - m_parentScene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, remoteClient.AgentId); - } - else - { - m_log.WarnFormat( - "[SCENE GRAPH]: Could not retrieve item {0} for attaching to avatar {1} at point {2}", - itemID, remoteClient.Name, AttachmentPt); - } - - return objatt; - } - - return null; - } - protected internal ScenePresence CreateAndAddChildScenePresence(IClientAPI client, AvatarAppearance appearance) { ScenePresence newAvatar = null; From 315fa06c75d023ef3e4285842dd730a4d94b78d6 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 12 Mar 2010 23:20:38 +0000 Subject: [PATCH 23/28] refactor: Move another RezSingleAttachment() from Scene.Inventory to AttachmentsModule --- .../Avatar/Attachments/AttachmentsModule.cs | 31 ++++++++++++++++++- .../Interfaces/IAttachmentsModule.cs | 18 +++++++++-- .../Framework/Scenes/Scene.Inventory.cs | 25 +-------------- OpenSim/Region/Framework/Scenes/Scene.cs | 8 ++--- .../Region/Framework/Scenes/ScenePresence.cs | 12 +++---- 5 files changed, 57 insertions(+), 37 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index 084f3c9c54..f54e41abee 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs @@ -169,7 +169,36 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments return true; } - public SceneObjectGroup RezSingleAttachmentFromInventory(IClientAPI remoteClient, UUID itemID, uint AttachmentPt) + public UUID RezSingleAttachmentFromInventory(IClientAPI remoteClient, UUID itemID, uint AttachmentPt) + { + m_log.DebugFormat("[ATTACHMENTS MODULE]: Rezzing single attachment from item {0} for {1}", itemID, remoteClient.Name); + + return RezSingleAttachmentFromInventory(remoteClient, itemID, AttachmentPt, true); + } + + public UUID RezSingleAttachmentFromInventory( + IClientAPI remoteClient, UUID itemID, uint AttachmentPt, bool updateInventoryStatus) + { + SceneObjectGroup att = RezSingleAttachmentFromInventoryInternal(remoteClient, itemID, AttachmentPt); + + if (updateInventoryStatus) + { + if (att == null) + { + ShowDetachInUserInventory(itemID, remoteClient); + } + + SetAttachmentInventoryStatus(att, remoteClient, itemID, AttachmentPt); + } + + if (null == att) + return UUID.Zero; + else + return att.UUID; + } + + protected SceneObjectGroup RezSingleAttachmentFromInventoryInternal( + IClientAPI remoteClient, UUID itemID, uint AttachmentPt) { IInventoryAccessModule invAccess = m_scene.RequestModuleInterface(); if (invAccess != null) diff --git a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs index 1fa77e4274..0222b020c7 100644 --- a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs @@ -59,13 +59,27 @@ namespace OpenSim.Region.Framework.Interfaces IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, Quaternion rot, Vector3 attachPos, bool silent); /// - /// Rez an attachment from user inventory + /// Rez an attachment from user inventory and change inventory status to match. /// /// /// /// /// The scene object that was attached. Null if the scene object could not be found - SceneObjectGroup RezSingleAttachmentFromInventory(IClientAPI remoteClient, UUID itemID, uint AttachmentPt); + UUID RezSingleAttachmentFromInventory(IClientAPI remoteClient, UUID itemID, uint AttachmentPt); + + /// + /// Rez an attachment from user inventory + /// + /// + /// + /// + /// + /// If true, we also update the user's inventory to show that the attachment is set. If false, we do not. + /// False is required so that we don't attempt to update information when a user enters a scene with the + /// attachment already correctly set up in inventory. + /// The uuid of the scene object that was attached. Null if the scene object could not be found + UUID RezSingleAttachmentFromInventory( + IClientAPI remoteClient, UUID itemID, uint AttachmentPt, bool updateInventoryStatus); /// /// Update the user inventory to the attachment of an item diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index dcd92d6366..41533a1ef8 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs @@ -1842,35 +1842,12 @@ namespace OpenSim.Region.Framework.Scenes EventManager.TriggerOnAttach(localID, itemID, avatarID); } - /// - /// Called when the client receives a request to rez a single attachment on to the avatar from inventory - /// (RezSingleAttachmentFromInv packet). - /// - /// - /// - /// - /// - public UUID RezSingleAttachment(IClientAPI remoteClient, UUID itemID, uint AttachmentPt) - { - m_log.DebugFormat("[USER INVENTORY]: Rezzing single attachment from item {0} for {1}", itemID, remoteClient.Name); - - SceneObjectGroup att = AttachmentsModule.RezSingleAttachmentFromInventory(remoteClient, itemID, AttachmentPt); - - if (att == null) - { - AttachmentsModule.ShowDetachInUserInventory(itemID, remoteClient); - return UUID.Zero; - } - - return AttachmentsModule.SetAttachmentInventoryStatus(att, remoteClient, itemID, AttachmentPt); - } - public void RezMultipleAttachments(IClientAPI remoteClient, RezMultipleAttachmentsFromInvPacket.HeaderDataBlock header, RezMultipleAttachmentsFromInvPacket.ObjectDataBlock[] objects) { foreach (RezMultipleAttachmentsFromInvPacket.ObjectDataBlock obj in objects) { - RezSingleAttachment(remoteClient, obj.ItemID, obj.AttachmentPt); + AttachmentsModule.RezSingleAttachmentFromInventory(remoteClient, obj.ItemID, obj.AttachmentPt); } } diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 50553dde63..c510dc81a3 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -2642,13 +2642,13 @@ namespace OpenSim.Region.Framework.Scenes } public virtual void SubscribeToClientAttachmentEvents(IClientAPI client) - { - client.OnRezSingleAttachmentFromInv += RezSingleAttachment; + { client.OnRezMultipleAttachmentsFromInv += RezMultipleAttachments; client.OnObjectDetach += m_sceneGraph.DetachObject; if (AttachmentsModule != null) { + client.OnRezSingleAttachmentFromInv += AttachmentsModule.RezSingleAttachmentFromInventory; client.OnObjectAttach += AttachmentsModule.AttachObject; client.OnDetachAttachmentIntoInv += AttachmentsModule.ShowDetachInUserInventory; } @@ -2799,12 +2799,12 @@ namespace OpenSim.Region.Framework.Scenes public virtual void UnSubscribeToClientAttachmentEvents(IClientAPI client) { - client.OnRezMultipleAttachmentsFromInv -= RezMultipleAttachments; - client.OnRezSingleAttachmentFromInv -= RezSingleAttachment; + client.OnRezMultipleAttachmentsFromInv -= RezMultipleAttachments; client.OnObjectDetach -= m_sceneGraph.DetachObject; if (AttachmentsModule != null) { + client.OnRezSingleAttachmentFromInv -= AttachmentsModule.RezSingleAttachmentFromInventory; client.OnObjectAttach -= AttachmentsModule.AttachObject; client.OnDetachAttachmentIntoInv -= AttachmentsModule.ShowDetachInUserInventory; } diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 7661f1efb8..317c9088ef 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -3738,7 +3738,7 @@ namespace OpenSim.Region.Framework.Scenes { if (null == m_appearance) { - m_log.WarnFormat("[ATTACHMENT] Appearance has not been initialized for agent {0}", UUID); + m_log.WarnFormat("[ATTACHMENT]: Appearance has not been initialized for agent {0}", UUID); return; } @@ -3762,12 +3762,12 @@ namespace OpenSim.Region.Framework.Scenes try { // Rez from inventory - UUID asset = m_scene.RezSingleAttachment(ControllingClient, - itemID, (uint)p); - - m_log.InfoFormat("[ATTACHMENT]: Rezzed attachment in point {0} from item {1} and asset {2} ({3})", - p, itemID, assetID, asset); + UUID asset + = m_scene.AttachmentsModule.RezSingleAttachmentFromInventory(ControllingClient, itemID, (uint)p); + m_log.InfoFormat( + "[ATTACHMENT]: Rezzed attachment in point {0} from item {1} and asset {2} ({3})", + p, itemID, assetID, asset); } catch (Exception e) { From 4b813932745775ef585a2cbca99233e57d20e13e Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 12 Mar 2010 23:21:45 +0000 Subject: [PATCH 24/28] minor: remove some mono compiler warnings --- OpenSim/Services/GridService/GridService.cs | 6 ++---- OpenSim/Services/GridService/HypergridLinker.cs | 5 +++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/OpenSim/Services/GridService/GridService.cs b/OpenSim/Services/GridService/GridService.cs index 1368e46623..2faf018e72 100644 --- a/OpenSim/Services/GridService/GridService.cs +++ b/OpenSim/Services/GridService/GridService.cs @@ -123,8 +123,7 @@ namespace OpenSim.Services.GridService if ((rflags & OpenSim.Data.RegionFlags.Reservation) != 0) { // Regions reserved for the null key cannot be taken. - // - if (region.Data["PrincipalID"] == UUID.Zero.ToString()) + if ((string)region.Data["PrincipalID"] == UUID.Zero.ToString()) return "Region location us reserved"; // Treat it as an auth request @@ -132,7 +131,6 @@ namespace OpenSim.Services.GridService // NOTE: Fudging the flags value here, so these flags // should not be used elsewhere. Don't optimize // this with the later retrieval of the same flags! - // rflags |= OpenSim.Data.RegionFlags.Authenticate; } @@ -489,7 +487,7 @@ namespace OpenSim.Services.GridService f |= (OpenSim.Data.RegionFlags)val; } } - catch (Exception e) + catch (Exception) { MainConsole.Instance.Output("Error in flag specification: " + p); } diff --git a/OpenSim/Services/GridService/HypergridLinker.cs b/OpenSim/Services/GridService/HypergridLinker.cs index de5df9d645..58746d0a1b 100644 --- a/OpenSim/Services/GridService/HypergridLinker.cs +++ b/OpenSim/Services/GridService/HypergridLinker.cs @@ -168,10 +168,11 @@ namespace OpenSim.Services.GridService } // Sanity check. - IPAddress ipaddr = null; + //IPAddress ipaddr = null; try { - ipaddr = Util.GetHostFromDNS(host); + //ipaddr = Util.GetHostFromDNS(host); + Util.GetHostFromDNS(host); } catch { From 1d14cf8c3f2ac706d7e4e9cc3a32a0dcc76d0061 Mon Sep 17 00:00:00 2001 From: dahlia Date: Fri, 12 Mar 2010 21:21:28 -0800 Subject: [PATCH 25/28] some improvements to sculptmap alpha handling and LOD --- OpenSim/Region/Physics/Meshing/SculptMesh.cs | 1272 +++++++++--------- 1 file changed, 645 insertions(+), 627 deletions(-) diff --git a/OpenSim/Region/Physics/Meshing/SculptMesh.cs b/OpenSim/Region/Physics/Meshing/SculptMesh.cs index 4dc6e2e510..11b6cd42c5 100644 --- a/OpenSim/Region/Physics/Meshing/SculptMesh.cs +++ b/OpenSim/Region/Physics/Meshing/SculptMesh.cs @@ -1,627 +1,645 @@ -/* - * Copyright (c) Contributors - * 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 OpenSimulator 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. - */ - -// to build without references to System.Drawing, comment this out -#define SYSTEM_DRAWING - -using System; -using System.Collections.Generic; -using System.Text; -using System.IO; - -#if SYSTEM_DRAWING -using System.Drawing; -using System.Drawing.Imaging; -#endif - -namespace PrimMesher -{ - - public class SculptMesh - { - public List coords; - public List faces; - - public List viewerFaces; - public List normals; - public List uvs; - - public enum SculptType { sphere = 1, torus = 2, plane = 3, cylinder = 4 }; - -#if SYSTEM_DRAWING - // private Bitmap ScaleImage(Bitmap srcImage, float scale) - // { - // int sourceWidth = srcImage.Width; - // int sourceHeight = srcImage.Height; - // int sourceX = 0; - // int sourceY = 0; - - // int destX = 0; - // int destY = 0; - // int destWidth = (int)(srcImage.Width * scale); - // int destHeight = (int)(srcImage.Height * scale); - - // if (srcImage.PixelFormat == PixelFormat.Format32bppArgb) - // for (int y = 0; y < srcImage.Height; y++) - // for (int x = 0; x < srcImage.Width; x++) - // { - // Color c = srcImage.GetPixel(x, y); - // srcImage.SetPixel(x, y, Color.FromArgb(255, c.R, c.G, c.B)); - // } - - // Bitmap scaledImage = new Bitmap(destWidth, destHeight, - // PixelFormat.Format24bppRgb); - - // scaledImage.SetResolution(96.0f, 96.0f); - - // Graphics grPhoto = Graphics.FromImage(scaledImage); - // grPhoto.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Low; - - // grPhoto.DrawImage(srcImage, - // new Rectangle(destX, destY, destWidth, destHeight), - // new Rectangle(sourceX, sourceY, sourceWidth, sourceHeight), - // GraphicsUnit.Pixel); - - // grPhoto.Dispose(); - // return scaledImage; - // } - - - public SculptMesh SculptMeshFromFile(string fileName, SculptType sculptType, int lod, bool viewerMode) - { - Bitmap bitmap = (Bitmap)Bitmap.FromFile(fileName); - SculptMesh sculptMesh = new SculptMesh(bitmap, sculptType, lod, viewerMode); - bitmap.Dispose(); - return sculptMesh; - } - - public SculptMesh(string fileName, int sculptType, int lod, int viewerMode, int mirror, int invert) - { - Bitmap bitmap = (Bitmap)Bitmap.FromFile(fileName); - _SculptMesh(bitmap, (SculptType)sculptType, lod, viewerMode != 0, mirror != 0, invert != 0); - bitmap.Dispose(); - } -#endif - - /// - /// ** Experimental ** May disappear from future versions ** not recommeneded for use in applications - /// Construct a sculpt mesh from a 2D array of floats - /// - /// - /// - /// - /// - /// - /// - public SculptMesh(float[,] zMap, float xBegin, float xEnd, float yBegin, float yEnd, bool viewerMode) - { - float xStep, yStep; - float uStep, vStep; - - int numYElements = zMap.GetLength(0); - int numXElements = zMap.GetLength(1); - - try - { - xStep = (xEnd - xBegin) / (float)(numXElements - 1); - yStep = (yEnd - yBegin) / (float)(numYElements - 1); - - uStep = 1.0f / (numXElements - 1); - vStep = 1.0f / (numYElements - 1); - } - catch (DivideByZeroException) - { - return; - } - - coords = new List(); - faces = new List(); - normals = new List(); - uvs = new List(); - - viewerFaces = new List(); - - int p1, p2, p3, p4; - - int x, y; - int xStart = 0, yStart = 0; - - for (y = yStart; y < numYElements; y++) - { - int rowOffset = y * numXElements; - - for (x = xStart; x < numXElements; x++) - { - /* - * p1-----p2 - * | \ f2 | - * | \ | - * | f1 \| - * p3-----p4 - */ - - p4 = rowOffset + x; - p3 = p4 - 1; - - p2 = p4 - numXElements; - p1 = p3 - numXElements; - - Coord c = new Coord(xBegin + x * xStep, yBegin + y * yStep, zMap[y, x]); - this.coords.Add(c); - if (viewerMode) - { - this.normals.Add(new Coord()); - this.uvs.Add(new UVCoord(uStep * x, 1.0f - vStep * y)); - } - - if (y > 0 && x > 0) - { - Face f1, f2; - - if (viewerMode) - { - f1 = new Face(p1, p4, p3, p1, p4, p3); - f1.uv1 = p1; - f1.uv2 = p4; - f1.uv3 = p3; - - f2 = new Face(p1, p2, p4, p1, p2, p4); - f2.uv1 = p1; - f2.uv2 = p2; - f2.uv3 = p4; - } - else - { - f1 = new Face(p1, p4, p3); - f2 = new Face(p1, p2, p4); - } - - this.faces.Add(f1); - this.faces.Add(f2); - } - } - } - - if (viewerMode) - calcVertexNormals(SculptType.plane, numXElements, numYElements); - } - -#if SYSTEM_DRAWING - public SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode) - { - _SculptMesh(sculptBitmap, sculptType, lod, viewerMode, false, false); - } - - public SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode, bool mirror, bool invert) - { - _SculptMesh(sculptBitmap, sculptType, lod, viewerMode, mirror, invert); - } -#endif - - public SculptMesh(List> rows, SculptType sculptType, bool viewerMode, bool mirror, bool invert) - { - _SculptMesh(rows, sculptType, viewerMode, mirror, invert); - } - -#if SYSTEM_DRAWING - /// - /// converts a bitmap to a list of lists of coords, while scaling the image. - /// the scaling is done in floating point so as to allow for reduced vertex position - /// quantization as the position will be averaged between pixel values. this routine will - /// likely fail if the bitmap width and height are not powers of 2. - /// - /// - /// - /// - /// - private List> bitmap2Coords(Bitmap bitmap, int scale, bool mirror) - { - int numRows = bitmap.Height / scale; - int numCols = bitmap.Width / scale; - List> rows = new List>(numRows); - - float pixScale = 1.0f / (scale * scale); - pixScale /= 255; - - int imageX, imageY = 0; - - int rowNdx, colNdx; - - for (rowNdx = 0; rowNdx < numRows; rowNdx++) - { - List row = new List(numCols); - for (colNdx = 0; colNdx < numCols; colNdx++) - { - imageX = colNdx * scale; - int imageYStart = rowNdx * scale; - int imageYEnd = imageYStart + scale; - int imageXEnd = imageX + scale; - float rSum = 0.0f; - float gSum = 0.0f; - float bSum = 0.0f; - for (; imageX < imageXEnd; imageX++) - { - for (imageY = imageYStart; imageY < imageYEnd; imageY++) - { - Color c = bitmap.GetPixel(imageX, imageY); - rSum += c.R; - gSum += c.G; - bSum += c.B; - } - } - if (mirror) - row.Add(new Coord(-(rSum * pixScale - 0.5f), gSum * pixScale - 0.5f, bSum * pixScale - 0.5f)); - else - row.Add(new Coord(rSum * pixScale - 0.5f, gSum * pixScale - 0.5f, bSum * pixScale - 0.5f)); - - } - rows.Add(row); - } - return rows; - } - - - void _SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode, bool mirror, bool invert) - { - coords = new List(); - faces = new List(); - normals = new List(); - uvs = new List(); - - sculptType = (SculptType)(((int)sculptType) & 0x07); - - if (mirror) - if (sculptType == SculptType.plane) - invert = !invert; - - float sourceScaleFactor = (float)(lod) / (float)Math.Sqrt(sculptBitmap.Width * sculptBitmap.Height); - - int scale = (int)(1.0f / sourceScaleFactor); - if (scale < 1) scale = 1; - - _SculptMesh(bitmap2Coords(sculptBitmap, scale, mirror), sculptType, viewerMode, mirror, invert); - } -#endif - - - void _SculptMesh(List> rows, SculptType sculptType, bool viewerMode, bool mirror, bool invert) - { - coords = new List(); - faces = new List(); - normals = new List(); - uvs = new List(); - - sculptType = (SculptType)(((int)sculptType) & 0x07); - - if (mirror) - if (sculptType == SculptType.plane) - invert = !invert; - - viewerFaces = new List(); - - int width = rows[0].Count; - - int p1, p2, p3, p4; - - int imageX, imageY; - - if (sculptType != SculptType.plane) - { - for (int rowNdx = 0; rowNdx < rows.Count; rowNdx++) - rows[rowNdx].Add(rows[rowNdx][0]); - } - - Coord topPole = rows[0][width / 2]; - Coord bottomPole = rows[rows.Count - 1][width / 2]; - - if (sculptType == SculptType.sphere) - { - int count = rows[0].Count; - List topPoleRow = new List(count); - List bottomPoleRow = new List(count); - - for (int i = 0; i < count; i++) - { - topPoleRow.Add(topPole); - bottomPoleRow.Add(bottomPole); - } - rows.Insert(0, topPoleRow); - rows.Add(bottomPoleRow); - } - else if (sculptType == SculptType.torus) - rows.Add(rows[0]); - - int coordsDown = rows.Count; - int coordsAcross = rows[0].Count; - - float widthUnit = 1.0f / (coordsAcross - 1); - float heightUnit = 1.0f / (coordsDown - 1); - - for (imageY = 0; imageY < coordsDown; imageY++) - { - int rowOffset = imageY * coordsAcross; - - for (imageX = 0; imageX < coordsAcross; imageX++) - { - /* - * p1-----p2 - * | \ f2 | - * | \ | - * | f1 \| - * p3-----p4 - */ - - p4 = rowOffset + imageX; - p3 = p4 - 1; - - p2 = p4 - coordsAcross; - p1 = p3 - coordsAcross; - - this.coords.Add(rows[imageY][imageX]); - if (viewerMode) - { - this.normals.Add(new Coord()); - this.uvs.Add(new UVCoord(widthUnit * imageX, heightUnit * imageY)); - } - - if (imageY > 0 && imageX > 0) - { - Face f1, f2; - - if (viewerMode) - { - if (invert) - { - f1 = new Face(p1, p4, p3, p1, p4, p3); - f1.uv1 = p1; - f1.uv2 = p4; - f1.uv3 = p3; - - f2 = new Face(p1, p2, p4, p1, p2, p4); - f2.uv1 = p1; - f2.uv2 = p2; - f2.uv3 = p4; - } - else - { - f1 = new Face(p1, p3, p4, p1, p3, p4); - f1.uv1 = p1; - f1.uv2 = p3; - f1.uv3 = p4; - - f2 = new Face(p1, p4, p2, p1, p4, p2); - f2.uv1 = p1; - f2.uv2 = p4; - f2.uv3 = p2; - } - } - else - { - if (invert) - { - f1 = new Face(p1, p4, p3); - f2 = new Face(p1, p2, p4); - } - else - { - f1 = new Face(p1, p3, p4); - f2 = new Face(p1, p4, p2); - } - } - - this.faces.Add(f1); - this.faces.Add(f2); - } - } - } - - if (viewerMode) - calcVertexNormals(sculptType, coordsAcross, coordsDown); - } - - /// - /// Duplicates a SculptMesh object. All object properties are copied by value, including lists. - /// - /// - public SculptMesh Copy() - { - return new SculptMesh(this); - } - - public SculptMesh(SculptMesh sm) - { - coords = new List(sm.coords); - faces = new List(sm.faces); - viewerFaces = new List(sm.viewerFaces); - normals = new List(sm.normals); - uvs = new List(sm.uvs); - } - - private void calcVertexNormals(SculptType sculptType, int xSize, int ySize) - { // compute vertex normals by summing all the surface normals of all the triangles sharing - // each vertex and then normalizing - int numFaces = this.faces.Count; - for (int i = 0; i < numFaces; i++) - { - Face face = this.faces[i]; - Coord surfaceNormal = face.SurfaceNormal(this.coords); - this.normals[face.n1] += surfaceNormal; - this.normals[face.n2] += surfaceNormal; - this.normals[face.n3] += surfaceNormal; - } - - int numNormals = this.normals.Count; - for (int i = 0; i < numNormals; i++) - this.normals[i] = this.normals[i].Normalize(); - - if (sculptType != SculptType.plane) - { // blend the vertex normals at the cylinder seam - for (int y = 0; y < ySize; y++) - { - int rowOffset = y * xSize; - - this.normals[rowOffset] = this.normals[rowOffset + xSize - 1] = (this.normals[rowOffset] + this.normals[rowOffset + xSize - 1]).Normalize(); - } - } - - foreach (Face face in this.faces) - { - ViewerFace vf = new ViewerFace(0); - vf.v1 = this.coords[face.v1]; - vf.v2 = this.coords[face.v2]; - vf.v3 = this.coords[face.v3]; - - vf.coordIndex1 = face.v1; - vf.coordIndex2 = face.v2; - vf.coordIndex3 = face.v3; - - vf.n1 = this.normals[face.n1]; - vf.n2 = this.normals[face.n2]; - vf.n3 = this.normals[face.n3]; - - vf.uv1 = this.uvs[face.uv1]; - vf.uv2 = this.uvs[face.uv2]; - vf.uv3 = this.uvs[face.uv3]; - - this.viewerFaces.Add(vf); - } - } - - /// - /// Adds a value to each XYZ vertex coordinate in the mesh - /// - /// - /// - /// - public void AddPos(float x, float y, float z) - { - int i; - int numVerts = this.coords.Count; - Coord vert; - - for (i = 0; i < numVerts; i++) - { - vert = this.coords[i]; - vert.X += x; - vert.Y += y; - vert.Z += z; - this.coords[i] = vert; - } - - if (this.viewerFaces != null) - { - int numViewerFaces = this.viewerFaces.Count; - - for (i = 0; i < numViewerFaces; i++) - { - ViewerFace v = this.viewerFaces[i]; - v.AddPos(x, y, z); - this.viewerFaces[i] = v; - } - } - } - - /// - /// Rotates the mesh - /// - /// - public void AddRot(Quat q) - { - int i; - int numVerts = this.coords.Count; - - for (i = 0; i < numVerts; i++) - this.coords[i] *= q; - - int numNormals = this.normals.Count; - for (i = 0; i < numNormals; i++) - this.normals[i] *= q; - - if (this.viewerFaces != null) - { - int numViewerFaces = this.viewerFaces.Count; - - for (i = 0; i < numViewerFaces; i++) - { - ViewerFace v = this.viewerFaces[i]; - v.v1 *= q; - v.v2 *= q; - v.v3 *= q; - - v.n1 *= q; - v.n2 *= q; - v.n3 *= q; - - this.viewerFaces[i] = v; - } - } - } - - public void Scale(float x, float y, float z) - { - int i; - int numVerts = this.coords.Count; - - Coord m = new Coord(x, y, z); - for (i = 0; i < numVerts; i++) - this.coords[i] *= m; - - if (this.viewerFaces != null) - { - int numViewerFaces = this.viewerFaces.Count; - for (i = 0; i < numViewerFaces; i++) - { - ViewerFace v = this.viewerFaces[i]; - v.v1 *= m; - v.v2 *= m; - v.v3 *= m; - this.viewerFaces[i] = v; - } - } - } - - public void DumpRaw(String path, String name, String title) - { - if (path == null) - return; - String fileName = name + "_" + title + ".raw"; - String completePath = System.IO.Path.Combine(path, fileName); - StreamWriter sw = new StreamWriter(completePath); - - for (int i = 0; i < this.faces.Count; i++) - { - string s = this.coords[this.faces[i].v1].ToString(); - s += " " + this.coords[this.faces[i].v2].ToString(); - s += " " + this.coords[this.faces[i].v3].ToString(); - - sw.WriteLine(s); - } - - sw.Close(); - } - } -} +/* + * Copyright (c) Contributors + * 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 OpenSimulator 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. + */ + +// to build without references to System.Drawing, comment this out +#define SYSTEM_DRAWING + +using System; +using System.Collections.Generic; +using System.Text; +using System.IO; + +#if SYSTEM_DRAWING +using System.Drawing; +using System.Drawing.Imaging; +#endif + +namespace PrimMesher +{ + + public class SculptMesh + { + public List coords; + public List faces; + + public List viewerFaces; + public List normals; + public List uvs; + + public enum SculptType { sphere = 1, torus = 2, plane = 3, cylinder = 4 }; + +#if SYSTEM_DRAWING + private Bitmap ScaleImage(Bitmap srcImage, float scale, bool removeAlpha) + { + int sourceWidth = srcImage.Width; + int sourceHeight = srcImage.Height; + int sourceX = 0; + int sourceY = 0; + + int destX = 0; + int destY = 0; + int destWidth = (int)(srcImage.Width * scale); + int destHeight = (int)(srcImage.Height * scale); + + Bitmap scaledImage; + + if (removeAlpha) + { + if (srcImage.PixelFormat == PixelFormat.Format32bppArgb) + for (int y = 0; y < srcImage.Height; y++) + for (int x = 0; x < srcImage.Width; x++) + { + Color c = srcImage.GetPixel(x, y); + srcImage.SetPixel(x, y, Color.FromArgb(255, c.R, c.G, c.B)); + } + + scaledImage = new Bitmap(destWidth, destHeight, + PixelFormat.Format24bppRgb); + } + else + scaledImage = new Bitmap(srcImage, destWidth, destHeight); + + scaledImage.SetResolution(96.0f, 96.0f); + + Graphics grPhoto = Graphics.FromImage(scaledImage); + grPhoto.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Low; + + grPhoto.DrawImage(srcImage, + new Rectangle(destX, destY, destWidth, destHeight), + new Rectangle(sourceX, sourceY, sourceWidth, sourceHeight), + GraphicsUnit.Pixel); + + grPhoto.Dispose(); + return scaledImage; + } + + + public SculptMesh SculptMeshFromFile(string fileName, SculptType sculptType, int lod, bool viewerMode) + { + Bitmap bitmap = (Bitmap)Bitmap.FromFile(fileName); + SculptMesh sculptMesh = new SculptMesh(bitmap, sculptType, lod, viewerMode); + bitmap.Dispose(); + return sculptMesh; + } + + public SculptMesh(string fileName, int sculptType, int lod, int viewerMode, int mirror, int invert) + { + Bitmap bitmap = (Bitmap)Bitmap.FromFile(fileName); + _SculptMesh(bitmap, (SculptType)sculptType, lod, viewerMode != 0, mirror != 0, invert != 0); + bitmap.Dispose(); + } +#endif + + /// + /// ** Experimental ** May disappear from future versions ** not recommeneded for use in applications + /// Construct a sculpt mesh from a 2D array of floats + /// + /// + /// + /// + /// + /// + /// + public SculptMesh(float[,] zMap, float xBegin, float xEnd, float yBegin, float yEnd, bool viewerMode) + { + float xStep, yStep; + float uStep, vStep; + + int numYElements = zMap.GetLength(0); + int numXElements = zMap.GetLength(1); + + try + { + xStep = (xEnd - xBegin) / (float)(numXElements - 1); + yStep = (yEnd - yBegin) / (float)(numYElements - 1); + + uStep = 1.0f / (numXElements - 1); + vStep = 1.0f / (numYElements - 1); + } + catch (DivideByZeroException) + { + return; + } + + coords = new List(); + faces = new List(); + normals = new List(); + uvs = new List(); + + viewerFaces = new List(); + + int p1, p2, p3, p4; + + int x, y; + int xStart = 0, yStart = 0; + + for (y = yStart; y < numYElements; y++) + { + int rowOffset = y * numXElements; + + for (x = xStart; x < numXElements; x++) + { + /* + * p1-----p2 + * | \ f2 | + * | \ | + * | f1 \| + * p3-----p4 + */ + + p4 = rowOffset + x; + p3 = p4 - 1; + + p2 = p4 - numXElements; + p1 = p3 - numXElements; + + Coord c = new Coord(xBegin + x * xStep, yBegin + y * yStep, zMap[y, x]); + this.coords.Add(c); + if (viewerMode) + { + this.normals.Add(new Coord()); + this.uvs.Add(new UVCoord(uStep * x, 1.0f - vStep * y)); + } + + if (y > 0 && x > 0) + { + Face f1, f2; + + if (viewerMode) + { + f1 = new Face(p1, p4, p3, p1, p4, p3); + f1.uv1 = p1; + f1.uv2 = p4; + f1.uv3 = p3; + + f2 = new Face(p1, p2, p4, p1, p2, p4); + f2.uv1 = p1; + f2.uv2 = p2; + f2.uv3 = p4; + } + else + { + f1 = new Face(p1, p4, p3); + f2 = new Face(p1, p2, p4); + } + + this.faces.Add(f1); + this.faces.Add(f2); + } + } + } + + if (viewerMode) + calcVertexNormals(SculptType.plane, numXElements, numYElements); + } + +#if SYSTEM_DRAWING + public SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode) + { + _SculptMesh(sculptBitmap, sculptType, lod, viewerMode, false, false); + } + + public SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode, bool mirror, bool invert) + { + _SculptMesh(sculptBitmap, sculptType, lod, viewerMode, mirror, invert); + } +#endif + + public SculptMesh(List> rows, SculptType sculptType, bool viewerMode, bool mirror, bool invert) + { + _SculptMesh(rows, sculptType, viewerMode, mirror, invert); + } + +#if SYSTEM_DRAWING + /// + /// converts a bitmap to a list of lists of coords, while scaling the image. + /// the scaling is done in floating point so as to allow for reduced vertex position + /// quantization as the position will be averaged between pixel values. this routine will + /// likely fail if the bitmap width and height are not powers of 2. + /// + /// + /// + /// + /// + private List> bitmap2Coords(Bitmap bitmap, int scale, bool mirror) + { + int numRows = bitmap.Height / scale; + int numCols = bitmap.Width / scale; + List> rows = new List>(numRows); + + float pixScale = 1.0f / (scale * scale); + pixScale /= 255; + + int imageX, imageY = 0; + + int rowNdx, colNdx; + + for (rowNdx = 0; rowNdx < numRows; rowNdx++) + { + List row = new List(numCols); + for (colNdx = 0; colNdx < numCols; colNdx++) + { + imageX = colNdx * scale; + int imageYStart = rowNdx * scale; + int imageYEnd = imageYStart + scale; + int imageXEnd = imageX + scale; + float rSum = 0.0f; + float gSum = 0.0f; + float bSum = 0.0f; + for (; imageX < imageXEnd; imageX++) + { + for (imageY = imageYStart; imageY < imageYEnd; imageY++) + { + Color c = bitmap.GetPixel(imageX, imageY); + if (c.A != 255) + { + bitmap.SetPixel(imageX, imageY, Color.FromArgb(255, c.R, c.G, c.B)); + c = bitmap.GetPixel(imageX, imageY); + } + rSum += c.R; + gSum += c.G; + bSum += c.B; + } + } + if (mirror) + row.Add(new Coord(-(rSum * pixScale - 0.5f), gSum * pixScale - 0.5f, bSum * pixScale - 0.5f)); + else + row.Add(new Coord(rSum * pixScale - 0.5f, gSum * pixScale - 0.5f, bSum * pixScale - 0.5f)); + + } + rows.Add(row); + } + return rows; + } + + + void _SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode, bool mirror, bool invert) + { + coords = new List(); + faces = new List(); + normals = new List(); + uvs = new List(); + + sculptType = (SculptType)(((int)sculptType) & 0x07); + + if (mirror) + if (sculptType == SculptType.plane) + invert = !invert; + + float sculptBitmapLod = (float)Math.Sqrt(sculptBitmap.Width * sculptBitmap.Height); + + float sourceScaleFactor = (float)(lod) / sculptBitmapLod; + + float fScale = 1.0f / sourceScaleFactor; + + int iScale = (int)fScale; + if (iScale < 1) iScale = 1; + if (iScale > 2 && iScale % 2 == 0) + _SculptMesh(bitmap2Coords(ScaleImage(sculptBitmap, 64.0f / sculptBitmapLod, true), 64 / lod, mirror), sculptType, viewerMode, mirror, invert); + else + _SculptMesh(bitmap2Coords(sculptBitmap, iScale, mirror), sculptType, viewerMode, mirror, invert); + } +#endif + + + void _SculptMesh(List> rows, SculptType sculptType, bool viewerMode, bool mirror, bool invert) + { + coords = new List(); + faces = new List(); + normals = new List(); + uvs = new List(); + + sculptType = (SculptType)(((int)sculptType) & 0x07); + + if (mirror) + if (sculptType == SculptType.plane) + invert = !invert; + + viewerFaces = new List(); + + int width = rows[0].Count; + + int p1, p2, p3, p4; + + int imageX, imageY; + + if (sculptType != SculptType.plane) + { + for (int rowNdx = 0; rowNdx < rows.Count; rowNdx++) + rows[rowNdx].Add(rows[rowNdx][0]); + } + + Coord topPole = rows[0][width / 2]; + Coord bottomPole = rows[rows.Count - 1][width / 2]; + + if (sculptType == SculptType.sphere) + { + int count = rows[0].Count; + List topPoleRow = new List(count); + List bottomPoleRow = new List(count); + + for (int i = 0; i < count; i++) + { + topPoleRow.Add(topPole); + bottomPoleRow.Add(bottomPole); + } + rows.Insert(0, topPoleRow); + rows.Add(bottomPoleRow); + } + else if (sculptType == SculptType.torus) + rows.Add(rows[0]); + + int coordsDown = rows.Count; + int coordsAcross = rows[0].Count; + + float widthUnit = 1.0f / (coordsAcross - 1); + float heightUnit = 1.0f / (coordsDown - 1); + + for (imageY = 0; imageY < coordsDown; imageY++) + { + int rowOffset = imageY * coordsAcross; + + for (imageX = 0; imageX < coordsAcross; imageX++) + { + /* + * p1-----p2 + * | \ f2 | + * | \ | + * | f1 \| + * p3-----p4 + */ + + p4 = rowOffset + imageX; + p3 = p4 - 1; + + p2 = p4 - coordsAcross; + p1 = p3 - coordsAcross; + + this.coords.Add(rows[imageY][imageX]); + if (viewerMode) + { + this.normals.Add(new Coord()); + this.uvs.Add(new UVCoord(widthUnit * imageX, heightUnit * imageY)); + } + + if (imageY > 0 && imageX > 0) + { + Face f1, f2; + + if (viewerMode) + { + if (invert) + { + f1 = new Face(p1, p4, p3, p1, p4, p3); + f1.uv1 = p1; + f1.uv2 = p4; + f1.uv3 = p3; + + f2 = new Face(p1, p2, p4, p1, p2, p4); + f2.uv1 = p1; + f2.uv2 = p2; + f2.uv3 = p4; + } + else + { + f1 = new Face(p1, p3, p4, p1, p3, p4); + f1.uv1 = p1; + f1.uv2 = p3; + f1.uv3 = p4; + + f2 = new Face(p1, p4, p2, p1, p4, p2); + f2.uv1 = p1; + f2.uv2 = p4; + f2.uv3 = p2; + } + } + else + { + if (invert) + { + f1 = new Face(p1, p4, p3); + f2 = new Face(p1, p2, p4); + } + else + { + f1 = new Face(p1, p3, p4); + f2 = new Face(p1, p4, p2); + } + } + + this.faces.Add(f1); + this.faces.Add(f2); + } + } + } + + if (viewerMode) + calcVertexNormals(sculptType, coordsAcross, coordsDown); + } + + /// + /// Duplicates a SculptMesh object. All object properties are copied by value, including lists. + /// + /// + public SculptMesh Copy() + { + return new SculptMesh(this); + } + + public SculptMesh(SculptMesh sm) + { + coords = new List(sm.coords); + faces = new List(sm.faces); + viewerFaces = new List(sm.viewerFaces); + normals = new List(sm.normals); + uvs = new List(sm.uvs); + } + + private void calcVertexNormals(SculptType sculptType, int xSize, int ySize) + { // compute vertex normals by summing all the surface normals of all the triangles sharing + // each vertex and then normalizing + int numFaces = this.faces.Count; + for (int i = 0; i < numFaces; i++) + { + Face face = this.faces[i]; + Coord surfaceNormal = face.SurfaceNormal(this.coords); + this.normals[face.n1] += surfaceNormal; + this.normals[face.n2] += surfaceNormal; + this.normals[face.n3] += surfaceNormal; + } + + int numNormals = this.normals.Count; + for (int i = 0; i < numNormals; i++) + this.normals[i] = this.normals[i].Normalize(); + + if (sculptType != SculptType.plane) + { // blend the vertex normals at the cylinder seam + for (int y = 0; y < ySize; y++) + { + int rowOffset = y * xSize; + + this.normals[rowOffset] = this.normals[rowOffset + xSize - 1] = (this.normals[rowOffset] + this.normals[rowOffset + xSize - 1]).Normalize(); + } + } + + foreach (Face face in this.faces) + { + ViewerFace vf = new ViewerFace(0); + vf.v1 = this.coords[face.v1]; + vf.v2 = this.coords[face.v2]; + vf.v3 = this.coords[face.v3]; + + vf.coordIndex1 = face.v1; + vf.coordIndex2 = face.v2; + vf.coordIndex3 = face.v3; + + vf.n1 = this.normals[face.n1]; + vf.n2 = this.normals[face.n2]; + vf.n3 = this.normals[face.n3]; + + vf.uv1 = this.uvs[face.uv1]; + vf.uv2 = this.uvs[face.uv2]; + vf.uv3 = this.uvs[face.uv3]; + + this.viewerFaces.Add(vf); + } + } + + /// + /// Adds a value to each XYZ vertex coordinate in the mesh + /// + /// + /// + /// + public void AddPos(float x, float y, float z) + { + int i; + int numVerts = this.coords.Count; + Coord vert; + + for (i = 0; i < numVerts; i++) + { + vert = this.coords[i]; + vert.X += x; + vert.Y += y; + vert.Z += z; + this.coords[i] = vert; + } + + if (this.viewerFaces != null) + { + int numViewerFaces = this.viewerFaces.Count; + + for (i = 0; i < numViewerFaces; i++) + { + ViewerFace v = this.viewerFaces[i]; + v.AddPos(x, y, z); + this.viewerFaces[i] = v; + } + } + } + + /// + /// Rotates the mesh + /// + /// + public void AddRot(Quat q) + { + int i; + int numVerts = this.coords.Count; + + for (i = 0; i < numVerts; i++) + this.coords[i] *= q; + + int numNormals = this.normals.Count; + for (i = 0; i < numNormals; i++) + this.normals[i] *= q; + + if (this.viewerFaces != null) + { + int numViewerFaces = this.viewerFaces.Count; + + for (i = 0; i < numViewerFaces; i++) + { + ViewerFace v = this.viewerFaces[i]; + v.v1 *= q; + v.v2 *= q; + v.v3 *= q; + + v.n1 *= q; + v.n2 *= q; + v.n3 *= q; + + this.viewerFaces[i] = v; + } + } + } + + public void Scale(float x, float y, float z) + { + int i; + int numVerts = this.coords.Count; + + Coord m = new Coord(x, y, z); + for (i = 0; i < numVerts; i++) + this.coords[i] *= m; + + if (this.viewerFaces != null) + { + int numViewerFaces = this.viewerFaces.Count; + for (i = 0; i < numViewerFaces; i++) + { + ViewerFace v = this.viewerFaces[i]; + v.v1 *= m; + v.v2 *= m; + v.v3 *= m; + this.viewerFaces[i] = v; + } + } + } + + public void DumpRaw(String path, String name, String title) + { + if (path == null) + return; + String fileName = name + "_" + title + ".raw"; + String completePath = System.IO.Path.Combine(path, fileName); + StreamWriter sw = new StreamWriter(completePath); + + for (int i = 0; i < this.faces.Count; i++) + { + string s = this.coords[this.faces[i].v1].ToString(); + s += " " + this.coords[this.faces[i].v2].ToString(); + s += " " + this.coords[this.faces[i].v3].ToString(); + + sw.WriteLine(s); + } + + sw.Close(); + } + } +} From 41a98b902b0d95b28a5f26717150556107ca07b7 Mon Sep 17 00:00:00 2001 From: dahlia Date: Fri, 12 Mar 2010 22:05:22 -0800 Subject: [PATCH 26/28] correct some references which could produce erroneous prim face numbers --- OpenSim/Region/Physics/Meshing/PrimMesher.cs | 4403 +++++++++--------- 1 file changed, 2201 insertions(+), 2202 deletions(-) diff --git a/OpenSim/Region/Physics/Meshing/PrimMesher.cs b/OpenSim/Region/Physics/Meshing/PrimMesher.cs index 2a213c3d88..b75e2712f0 100644 --- a/OpenSim/Region/Physics/Meshing/PrimMesher.cs +++ b/OpenSim/Region/Physics/Meshing/PrimMesher.cs @@ -1,2202 +1,2201 @@ -/* - * Copyright (c) Contributors - * 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 OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.Text; -using System.IO; - -namespace PrimMesher -{ - public struct Quat - { - /// X value - public float X; - /// Y value - public float Y; - /// Z value - public float Z; - /// W value - public float W; - - public Quat(float x, float y, float z, float w) - { - X = x; - Y = y; - Z = z; - W = w; - } - - public Quat(Coord axis, float angle) - { - axis = axis.Normalize(); - - angle *= 0.5f; - float c = (float)Math.Cos(angle); - float s = (float)Math.Sin(angle); - - X = axis.X * s; - Y = axis.Y * s; - Z = axis.Z * s; - W = c; - - Normalize(); - } - - public float Length() - { - return (float)Math.Sqrt(X * X + Y * Y + Z * Z + W * W); - } - - public Quat Normalize() - { - const float MAG_THRESHOLD = 0.0000001f; - float mag = Length(); - - // Catch very small rounding errors when normalizing - if (mag > MAG_THRESHOLD) - { - float oomag = 1f / mag; - X *= oomag; - Y *= oomag; - Z *= oomag; - W *= oomag; - } - else - { - X = 0f; - Y = 0f; - Z = 0f; - W = 1f; - } - - return this; - } - - public static Quat operator *(Quat q1, Quat q2) - { - float x = q1.W * q2.X + q1.X * q2.W + q1.Y * q2.Z - q1.Z * q2.Y; - float y = q1.W * q2.Y - q1.X * q2.Z + q1.Y * q2.W + q1.Z * q2.X; - float z = q1.W * q2.Z + q1.X * q2.Y - q1.Y * q2.X + q1.Z * q2.W; - float w = q1.W * q2.W - q1.X * q2.X - q1.Y * q2.Y - q1.Z * q2.Z; - return new Quat(x, y, z, w); - } - - public override string ToString() - { - return "< X: " + this.X.ToString() + ", Y: " + this.Y.ToString() + ", Z: " + this.Z.ToString() + ", W: " + this.W.ToString() + ">"; - } - } - - public struct Coord - { - public float X; - public float Y; - public float Z; - - public Coord(float x, float y, float z) - { - this.X = x; - this.Y = y; - this.Z = z; - } - - public float Length() - { - return (float)Math.Sqrt(this.X * this.X + this.Y * this.Y + this.Z * this.Z); - } - - public Coord Invert() - { - this.X = -this.X; - this.Y = -this.Y; - this.Z = -this.Z; - - return this; - } - - public Coord Normalize() - { - const float MAG_THRESHOLD = 0.0000001f; - float mag = Length(); - - // Catch very small rounding errors when normalizing - if (mag > MAG_THRESHOLD) - { - float oomag = 1.0f / mag; - this.X *= oomag; - this.Y *= oomag; - this.Z *= oomag; - } - else - { - this.X = 0.0f; - this.Y = 0.0f; - this.Z = 0.0f; - } - - return this; - } - - public override string ToString() - { - return this.X.ToString() + " " + this.Y.ToString() + " " + this.Z.ToString(); - } - - public static Coord Cross(Coord c1, Coord c2) - { - return new Coord( - c1.Y * c2.Z - c2.Y * c1.Z, - c1.Z * c2.X - c2.Z * c1.X, - c1.X * c2.Y - c2.X * c1.Y - ); - } - - public static Coord operator +(Coord v, Coord a) - { - return new Coord(v.X + a.X, v.Y + a.Y, v.Z + a.Z); - } - - public static Coord operator *(Coord v, Coord m) - { - return new Coord(v.X * m.X, v.Y * m.Y, v.Z * m.Z); - } - - public static Coord operator *(Coord v, Quat q) - { - // From http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/transforms/ - - Coord c2 = new Coord(0.0f, 0.0f, 0.0f); - - c2.X = q.W * q.W * v.X + - 2f * q.Y * q.W * v.Z - - 2f * q.Z * q.W * v.Y + - q.X * q.X * v.X + - 2f * q.Y * q.X * v.Y + - 2f * q.Z * q.X * v.Z - - q.Z * q.Z * v.X - - q.Y * q.Y * v.X; - - c2.Y = - 2f * q.X * q.Y * v.X + - q.Y * q.Y * v.Y + - 2f * q.Z * q.Y * v.Z + - 2f * q.W * q.Z * v.X - - q.Z * q.Z * v.Y + - q.W * q.W * v.Y - - 2f * q.X * q.W * v.Z - - q.X * q.X * v.Y; - - c2.Z = - 2f * q.X * q.Z * v.X + - 2f * q.Y * q.Z * v.Y + - q.Z * q.Z * v.Z - - 2f * q.W * q.Y * v.X - - q.Y * q.Y * v.Z + - 2f * q.W * q.X * v.Y - - q.X * q.X * v.Z + - q.W * q.W * v.Z; - - return c2; - } - } - - public struct UVCoord - { - public float U; - public float V; - - - public UVCoord(float u, float v) - { - this.U = u; - this.V = v; - } - } - - public struct Face - { - public int primFace; - - // vertices - public int v1; - public int v2; - public int v3; - - //normals - public int n1; - public int n2; - public int n3; - - // uvs - public int uv1; - public int uv2; - public int uv3; - - - public Face(int v1, int v2, int v3) - { - primFace = 0; - - this.v1 = v1; - this.v2 = v2; - this.v3 = v3; - - this.n1 = 0; - this.n2 = 0; - this.n3 = 0; - - this.uv1 = 0; - this.uv2 = 0; - this.uv3 = 0; - - } - - public Face(int v1, int v2, int v3, int n1, int n2, int n3) - { - primFace = 0; - - this.v1 = v1; - this.v2 = v2; - this.v3 = v3; - - this.n1 = n1; - this.n2 = n2; - this.n3 = n3; - - this.uv1 = 0; - this.uv2 = 0; - this.uv3 = 0; - } - - public Coord SurfaceNormal(List coordList) - { - Coord c1 = coordList[this.v1]; - Coord c2 = coordList[this.v2]; - Coord c3 = coordList[this.v3]; - - Coord edge1 = new Coord(c2.X - c1.X, c2.Y - c1.Y, c2.Z - c1.Z); - Coord edge2 = new Coord(c3.X - c1.X, c3.Y - c1.Y, c3.Z - c1.Z); - - return Coord.Cross(edge1, edge2).Normalize(); - } - } - - public struct ViewerFace - { - public int primFaceNumber; - - public Coord v1; - public Coord v2; - public Coord v3; - - public int coordIndex1; - public int coordIndex2; - public int coordIndex3; - - public Coord n1; - public Coord n2; - public Coord n3; - - public UVCoord uv1; - public UVCoord uv2; - public UVCoord uv3; - - public ViewerFace(int primFaceNumber) - { - this.primFaceNumber = primFaceNumber; - - this.v1 = new Coord(); - this.v2 = new Coord(); - this.v3 = new Coord(); - - this.coordIndex1 = this.coordIndex2 = this.coordIndex3 = -1; // -1 means not assigned yet - - this.n1 = new Coord(); - this.n2 = new Coord(); - this.n3 = new Coord(); - - this.uv1 = new UVCoord(); - this.uv2 = new UVCoord(); - this.uv3 = new UVCoord(); - } - - public void Scale(float x, float y, float z) - { - this.v1.X *= x; - this.v1.Y *= y; - this.v1.Z *= z; - - this.v2.X *= x; - this.v2.Y *= y; - this.v2.Z *= z; - - this.v3.X *= x; - this.v3.Y *= y; - this.v3.Z *= z; - } - - public void AddPos(float x, float y, float z) - { - this.v1.X += x; - this.v2.X += x; - this.v3.X += x; - - this.v1.Y += y; - this.v2.Y += y; - this.v3.Y += y; - - this.v1.Z += z; - this.v2.Z += z; - this.v3.Z += z; - } - - public void AddRot(Quat q) - { - this.v1 *= q; - this.v2 *= q; - this.v3 *= q; - - this.n1 *= q; - this.n2 *= q; - this.n3 *= q; - } - - public void CalcSurfaceNormal() - { - - Coord edge1 = new Coord(this.v2.X - this.v1.X, this.v2.Y - this.v1.Y, this.v2.Z - this.v1.Z); - Coord edge2 = new Coord(this.v3.X - this.v1.X, this.v3.Y - this.v1.Y, this.v3.Z - this.v1.Z); - - this.n1 = this.n2 = this.n3 = Coord.Cross(edge1, edge2).Normalize(); - } - } - - internal struct Angle - { - internal float angle; - internal float X; - internal float Y; - - internal Angle(float angle, float x, float y) - { - this.angle = angle; - this.X = x; - this.Y = y; - } - } - - internal class AngleList - { - private float iX, iY; // intersection point - - private static Angle[] angles3 = - { - new Angle(0.0f, 1.0f, 0.0f), - new Angle(0.33333333333333333f, -0.5f, 0.86602540378443871f), - new Angle(0.66666666666666667f, -0.5f, -0.86602540378443837f), - new Angle(1.0f, 1.0f, 0.0f) - }; - - private static Coord[] normals3 = - { - new Coord(0.25f, 0.4330127019f, 0.0f).Normalize(), - new Coord(-0.5f, 0.0f, 0.0f).Normalize(), - new Coord(0.25f, -0.4330127019f, 0.0f).Normalize(), - new Coord(0.25f, 0.4330127019f, 0.0f).Normalize() - }; - - private static Angle[] angles4 = - { - new Angle(0.0f, 1.0f, 0.0f), - new Angle(0.25f, 0.0f, 1.0f), - new Angle(0.5f, -1.0f, 0.0f), - new Angle(0.75f, 0.0f, -1.0f), - new Angle(1.0f, 1.0f, 0.0f) - }; - - private static Coord[] normals4 = - { - new Coord(0.5f, 0.5f, 0.0f).Normalize(), - new Coord(-0.5f, 0.5f, 0.0f).Normalize(), - new Coord(-0.5f, -0.5f, 0.0f).Normalize(), - new Coord(0.5f, -0.5f, 0.0f).Normalize(), - new Coord(0.5f, 0.5f, 0.0f).Normalize() - }; - - private static Angle[] angles24 = - { - new Angle(0.0f, 1.0f, 0.0f), - new Angle(0.041666666666666664f, 0.96592582628906831f, 0.25881904510252074f), - new Angle(0.083333333333333329f, 0.86602540378443871f, 0.5f), - new Angle(0.125f, 0.70710678118654757f, 0.70710678118654746f), - new Angle(0.16666666666666667f, 0.5f, 0.8660254037844386f), - new Angle(0.20833333333333331f, 0.25881904510252096f, 0.9659258262890682f), - new Angle(0.25f, 0.0f, 1.0f), - new Angle(0.29166666666666663f, -0.25881904510252063f, 0.96592582628906831f), - new Angle(0.33333333333333333f, -0.5f, 0.86602540378443871f), - new Angle(0.375f, -0.70710678118654746f, 0.70710678118654757f), - new Angle(0.41666666666666663f, -0.86602540378443849f, 0.5f), - new Angle(0.45833333333333331f, -0.9659258262890682f, 0.25881904510252102f), - new Angle(0.5f, -1.0f, 0.0f), - new Angle(0.54166666666666663f, -0.96592582628906842f, -0.25881904510252035f), - new Angle(0.58333333333333326f, -0.86602540378443882f, -0.5f), - new Angle(0.62499999999999989f, -0.70710678118654791f, -0.70710678118654713f), - new Angle(0.66666666666666667f, -0.5f, -0.86602540378443837f), - new Angle(0.70833333333333326f, -0.25881904510252152f, -0.96592582628906809f), - new Angle(0.75f, 0.0f, -1.0f), - new Angle(0.79166666666666663f, 0.2588190451025203f, -0.96592582628906842f), - new Angle(0.83333333333333326f, 0.5f, -0.86602540378443904f), - new Angle(0.875f, 0.70710678118654735f, -0.70710678118654768f), - new Angle(0.91666666666666663f, 0.86602540378443837f, -0.5f), - new Angle(0.95833333333333326f, 0.96592582628906809f, -0.25881904510252157f), - new Angle(1.0f, 1.0f, 0.0f) - }; - - private Angle interpolatePoints(float newPoint, Angle p1, Angle p2) - { - float m = (newPoint - p1.angle) / (p2.angle - p1.angle); - return new Angle(newPoint, p1.X + m * (p2.X - p1.X), p1.Y + m * (p2.Y - p1.Y)); - } - - private void intersection(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) - { // ref: http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline2d/ - double denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1); - double uaNumerator = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3); - - if (denom != 0.0) - { - double ua = uaNumerator / denom; - iX = (float)(x1 + ua * (x2 - x1)); - iY = (float)(y1 + ua * (y2 - y1)); - } - } - - internal List angles; - internal List normals; - - internal void makeAngles(int sides, float startAngle, float stopAngle) - { - angles = new List(); - normals = new List(); - - double twoPi = System.Math.PI * 2.0; - float twoPiInv = 1.0f / (float)twoPi; - - if (sides < 1) - throw new Exception("number of sides not greater than zero"); - if (stopAngle <= startAngle) - throw new Exception("stopAngle not greater than startAngle"); - - if ((sides == 3 || sides == 4 || sides == 24)) - { - startAngle *= twoPiInv; - stopAngle *= twoPiInv; - - Angle[] sourceAngles; - if (sides == 3) - sourceAngles = angles3; - else if (sides == 4) - sourceAngles = angles4; - else sourceAngles = angles24; - - int startAngleIndex = (int)(startAngle * sides); - int endAngleIndex = sourceAngles.Length - 1; - if (stopAngle < 1.0f) - endAngleIndex = (int)(stopAngle * sides) + 1; - if (endAngleIndex == startAngleIndex) - endAngleIndex++; - - for (int angleIndex = startAngleIndex; angleIndex < endAngleIndex + 1; angleIndex++) - { - angles.Add(sourceAngles[angleIndex]); - if (sides == 3) - normals.Add(normals3[angleIndex]); - else if (sides == 4) - normals.Add(normals4[angleIndex]); - } - - if (startAngle > 0.0f) - angles[0] = interpolatePoints(startAngle, angles[0], angles[1]); - - if (stopAngle < 1.0f) - { - int lastAngleIndex = angles.Count - 1; - angles[lastAngleIndex] = interpolatePoints(stopAngle, angles[lastAngleIndex - 1], angles[lastAngleIndex]); - } - } - else - { - double stepSize = twoPi / sides; - - int startStep = (int)(startAngle / stepSize); - double angle = stepSize * startStep; - int step = startStep; - double stopAngleTest = stopAngle; - if (stopAngle < twoPi) - { - stopAngleTest = stepSize * ((int)(stopAngle / stepSize) + 1); - if (stopAngleTest < stopAngle) - stopAngleTest += stepSize; - if (stopAngleTest > twoPi) - stopAngleTest = twoPi; - } - - while (angle <= stopAngleTest) - { - Angle newAngle; - newAngle.angle = (float)angle; - newAngle.X = (float)System.Math.Cos(angle); - newAngle.Y = (float)System.Math.Sin(angle); - angles.Add(newAngle); - step += 1; - angle = stepSize * step; - } - - if (startAngle > angles[0].angle) - { - Angle newAngle; - intersection(angles[0].X, angles[0].Y, angles[1].X, angles[1].Y, 0.0f, 0.0f, (float)Math.Cos(startAngle), (float)Math.Sin(startAngle)); - newAngle.angle = startAngle; - newAngle.X = iX; - newAngle.Y = iY; - angles[0] = newAngle; - } - - int index = angles.Count - 1; - if (stopAngle < angles[index].angle) - { - Angle newAngle; - intersection(angles[index - 1].X, angles[index - 1].Y, angles[index].X, angles[index].Y, 0.0f, 0.0f, (float)Math.Cos(stopAngle), (float)Math.Sin(stopAngle)); - newAngle.angle = stopAngle; - newAngle.X = iX; - newAngle.Y = iY; - angles[index] = newAngle; - } - } - } - } - - /// - /// generates a profile for extrusion - /// - internal class Profile - { - private const float twoPi = 2.0f * (float)Math.PI; - - internal string errorMessage = null; - - internal List coords; - internal List faces; - internal List vertexNormals; - internal List us; - internal List faceUVs; - internal List faceNumbers; - - // use these for making individual meshes for each prim face - internal List outerCoordIndices = null; - internal List hollowCoordIndices = null; - internal List cut1CoordIndices = null; - internal List cut2CoordIndices = null; - - internal Coord faceNormal = new Coord(0.0f, 0.0f, 1.0f); - internal Coord cutNormal1 = new Coord(); - internal Coord cutNormal2 = new Coord(); - - internal int numOuterVerts = 0; - internal int numHollowVerts = 0; - - internal bool calcVertexNormals = false; - internal int bottomFaceNumber = 0; - internal int numPrimFaces = 0; - - internal Profile() - { - this.coords = new List(); - this.faces = new List(); - this.vertexNormals = new List(); - this.us = new List(); - this.faceUVs = new List(); - this.faceNumbers = new List(); - } - - internal Profile(int sides, float profileStart, float profileEnd, float hollow, int hollowSides, bool createFaces, bool calcVertexNormals) - { - this.calcVertexNormals = calcVertexNormals; - this.coords = new List(); - this.faces = new List(); - this.vertexNormals = new List(); - this.us = new List(); - this.faceUVs = new List(); - this.faceNumbers = new List(); - - Coord center = new Coord(0.0f, 0.0f, 0.0f); - //bool hasCenter = false; - - List hollowCoords = new List(); - List hollowNormals = new List(); - List hollowUs = new List(); - - if (calcVertexNormals) - { - this.outerCoordIndices = new List(); - this.hollowCoordIndices = new List(); - this.cut1CoordIndices = new List(); - this.cut2CoordIndices = new List(); - } - - bool hasHollow = (hollow > 0.0f); - - bool hasProfileCut = (profileStart > 0.0f || profileEnd < 1.0f); - - AngleList angles = new AngleList(); - AngleList hollowAngles = new AngleList(); - - float xScale = 0.5f; - float yScale = 0.5f; - if (sides == 4) // corners of a square are sqrt(2) from center - { - xScale = 0.707f; - yScale = 0.707f; - } - - float startAngle = profileStart * twoPi; - float stopAngle = profileEnd * twoPi; - - try { angles.makeAngles(sides, startAngle, stopAngle); } - catch (Exception ex) - { - - errorMessage = "makeAngles failed: Exception: " + ex.ToString() - + "\nsides: " + sides.ToString() + " startAngle: " + startAngle.ToString() + " stopAngle: " + stopAngle.ToString(); - - return; - } - - this.numOuterVerts = angles.angles.Count; - - // flag to create as few triangles as possible for 3 or 4 side profile - bool simpleFace = (sides < 5 && !hasHollow && !hasProfileCut); - - if (hasHollow) - { - if (sides == hollowSides) - hollowAngles = angles; - else - { - try { hollowAngles.makeAngles(hollowSides, startAngle, stopAngle); } - catch (Exception ex) - { - errorMessage = "makeAngles failed: Exception: " + ex.ToString() - + "\nsides: " + sides.ToString() + " startAngle: " + startAngle.ToString() + " stopAngle: " + stopAngle.ToString(); - - return; - } - } - this.numHollowVerts = hollowAngles.angles.Count; - } - else if (!simpleFace) - { - this.coords.Add(center); - //hasCenter = true; - if (this.calcVertexNormals) - this.vertexNormals.Add(new Coord(0.0f, 0.0f, 1.0f)); - this.us.Add(0.0f); - } - - float z = 0.0f; - - Angle angle; - Coord newVert = new Coord(); - if (hasHollow && hollowSides != sides) - { - int numHollowAngles = hollowAngles.angles.Count; - for (int i = 0; i < numHollowAngles; i++) - { - angle = hollowAngles.angles[i]; - newVert.X = hollow * xScale * angle.X; - newVert.Y = hollow * yScale * angle.Y; - newVert.Z = z; - - hollowCoords.Add(newVert); - if (this.calcVertexNormals) - { - if (hollowSides < 5) - hollowNormals.Add(hollowAngles.normals[i].Invert()); - else - hollowNormals.Add(new Coord(-angle.X, -angle.Y, 0.0f)); - - hollowUs.Add(angle.angle * hollow); - } - } - } - - int index = 0; - int numAngles = angles.angles.Count; - - for (int i = 0; i < numAngles; i++) - { - angle = angles.angles[i]; - newVert.X = angle.X * xScale; - newVert.Y = angle.Y * yScale; - newVert.Z = z; - this.coords.Add(newVert); - if (this.calcVertexNormals) - { - this.outerCoordIndices.Add(this.coords.Count - 1); - - if (sides < 5) - { - this.vertexNormals.Add(angles.normals[i]); - float u = angle.angle; - this.us.Add(u); - } - else - { - this.vertexNormals.Add(new Coord(angle.X, angle.Y, 0.0f)); - this.us.Add(angle.angle); - } - } - - if (hasHollow) - { - if (hollowSides == sides) - { - newVert.X *= hollow; - newVert.Y *= hollow; - newVert.Z = z; - hollowCoords.Add(newVert); - if (this.calcVertexNormals) - { - if (sides < 5) - { - hollowNormals.Add(angles.normals[i].Invert()); - } - - else - hollowNormals.Add(new Coord(-angle.X, -angle.Y, 0.0f)); - - hollowUs.Add(angle.angle * hollow); - } - } - } - else if (!simpleFace && createFaces && angle.angle > 0.0001f) - { - Face newFace = new Face(); - newFace.v1 = 0; - newFace.v2 = index; - newFace.v3 = index + 1; - - this.faces.Add(newFace); - } - index += 1; - } - - if (hasHollow) - { - hollowCoords.Reverse(); - if (this.calcVertexNormals) - { - hollowNormals.Reverse(); - hollowUs.Reverse(); - } - - if (createFaces) - { - int numOuterVerts = this.coords.Count; - int numHollowVerts = hollowCoords.Count; - int numTotalVerts = numOuterVerts + numHollowVerts; - - if (numOuterVerts == numHollowVerts) - { - Face newFace = new Face(); - - for (int coordIndex = 0; coordIndex < numOuterVerts - 1; coordIndex++) - { - newFace.v1 = coordIndex; - newFace.v2 = coordIndex + 1; - newFace.v3 = numTotalVerts - coordIndex - 1; - this.faces.Add(newFace); - - newFace.v1 = coordIndex + 1; - newFace.v2 = numTotalVerts - coordIndex - 2; - newFace.v3 = numTotalVerts - coordIndex - 1; - this.faces.Add(newFace); - } - } - else - { - if (numOuterVerts < numHollowVerts) - { - Face newFace = new Face(); - int j = 0; // j is the index for outer vertices - int maxJ = numOuterVerts - 1; - for (int i = 0; i < numHollowVerts; i++) // i is the index for inner vertices - { - if (j < maxJ) - if (angles.angles[j + 1].angle - hollowAngles.angles[i].angle < hollowAngles.angles[i].angle - angles.angles[j].angle + 0.000001f) - { - newFace.v1 = numTotalVerts - i - 1; - newFace.v2 = j; - newFace.v3 = j + 1; - - this.faces.Add(newFace); - j += 1; - } - - newFace.v1 = j; - newFace.v2 = numTotalVerts - i - 2; - newFace.v3 = numTotalVerts - i - 1; - - this.faces.Add(newFace); - } - } - else // numHollowVerts < numOuterVerts - { - Face newFace = new Face(); - int j = 0; // j is the index for inner vertices - int maxJ = numHollowVerts - 1; - for (int i = 0; i < numOuterVerts; i++) - { - if (j < maxJ) - if (hollowAngles.angles[j + 1].angle - angles.angles[i].angle < angles.angles[i].angle - hollowAngles.angles[j].angle + 0.000001f) - { - newFace.v1 = i; - newFace.v2 = numTotalVerts - j - 2; - newFace.v3 = numTotalVerts - j - 1; - - this.faces.Add(newFace); - j += 1; - } - - newFace.v1 = numTotalVerts - j - 1; - newFace.v2 = i; - newFace.v3 = i + 1; - - this.faces.Add(newFace); - } - } - } - } - - if (calcVertexNormals) - { - foreach (Coord hc in hollowCoords) - { - this.coords.Add(hc); - hollowCoordIndices.Add(this.coords.Count - 1); - } - } - else - this.coords.AddRange(hollowCoords); - - if (this.calcVertexNormals) - { - this.vertexNormals.AddRange(hollowNormals); - this.us.AddRange(hollowUs); - - } - } - - if (simpleFace && createFaces) - { - if (sides == 3) - this.faces.Add(new Face(0, 1, 2)); - else if (sides == 4) - { - this.faces.Add(new Face(0, 1, 2)); - this.faces.Add(new Face(0, 2, 3)); - } - } - - if (calcVertexNormals && hasProfileCut) - { - if (hasHollow) - { - int lastOuterVertIndex = this.numOuterVerts - 1; - - this.cut1CoordIndices.Add(0); - this.cut1CoordIndices.Add(this.coords.Count - 1); - - this.cut2CoordIndices.Add(lastOuterVertIndex + 1); - this.cut2CoordIndices.Add(lastOuterVertIndex); - - this.cutNormal1.X = this.coords[0].Y - this.coords[this.coords.Count - 1].Y; - this.cutNormal1.Y = -(this.coords[0].X - this.coords[this.coords.Count - 1].X); - - this.cutNormal2.X = this.coords[lastOuterVertIndex + 1].Y - this.coords[lastOuterVertIndex].Y; - this.cutNormal2.Y = -(this.coords[lastOuterVertIndex + 1].X - this.coords[lastOuterVertIndex].X); - } - - else - { - this.cutNormal1.X = this.vertexNormals[1].Y; - this.cutNormal1.Y = -this.vertexNormals[1].X; - - this.cutNormal2.X = -this.vertexNormals[this.vertexNormals.Count - 2].Y; - this.cutNormal2.Y = this.vertexNormals[this.vertexNormals.Count - 2].X; - - } - this.cutNormal1.Normalize(); - this.cutNormal2.Normalize(); - } - - this.MakeFaceUVs(); - - hollowCoords = null; - hollowNormals = null; - hollowUs = null; - - if (calcVertexNormals) - { // calculate prim face numbers - - // face number order is top, outer, hollow, bottom, start cut, end cut - // I know it's ugly but so is the whole concept of prim face numbers - - int faceNum = 1; // start with outer faces - int startVert = hasProfileCut && !hasHollow ? 1 : 0; - if (startVert > 0) - this.faceNumbers.Add(-1); - for (int i = 0; i < numOuterVerts - 1; i++) - this.faceNumbers.Add(sides < 5 ? faceNum++ : faceNum); - - //if (!hasHollow && !hasProfileCut) - // this.bottomFaceNumber = faceNum++; - - this.faceNumbers.Add(hasProfileCut ? -1 : faceNum++); - - if (sides > 4 && (hasHollow || hasProfileCut)) - faceNum++; - - if (hasHollow) - { - for (int i = 0; i < numHollowVerts; i++) - this.faceNumbers.Add(faceNum); - - faceNum++; - } - //if (hasProfileCut || hasHollow) - // this.bottomFaceNumber = faceNum++; - this.bottomFaceNumber = faceNum++; - - if (hasHollow && hasProfileCut) - this.faceNumbers.Add(faceNum++); - for (int i = 0; i < this.faceNumbers.Count; i++) - if (this.faceNumbers[i] == -1) - this.faceNumbers[i] = faceNum++; - - - this.numPrimFaces = faceNum; - } - - } - - internal void MakeFaceUVs() - { - this.faceUVs = new List(); - foreach (Coord c in this.coords) - this.faceUVs.Add(new UVCoord(1.0f - (0.5f + c.X), 1.0f - (0.5f - c.Y))); - } - - internal Profile Copy() - { - return this.Copy(true); - } - - internal Profile Copy(bool needFaces) - { - Profile copy = new Profile(); - - copy.coords.AddRange(this.coords); - copy.faceUVs.AddRange(this.faceUVs); - - if (needFaces) - copy.faces.AddRange(this.faces); - if ((copy.calcVertexNormals = this.calcVertexNormals) == true) - { - copy.vertexNormals.AddRange(this.vertexNormals); - copy.faceNormal = this.faceNormal; - copy.cutNormal1 = this.cutNormal1; - copy.cutNormal2 = this.cutNormal2; - copy.us.AddRange(this.us); - copy.faceNumbers.AddRange(this.faceNumbers); - - copy.cut1CoordIndices = new List(this.cut1CoordIndices); - copy.cut2CoordIndices = new List(this.cut2CoordIndices); - copy.hollowCoordIndices = new List(this.hollowCoordIndices); - copy.outerCoordIndices = new List(this.outerCoordIndices); - } - copy.numOuterVerts = this.numOuterVerts; - copy.numHollowVerts = this.numHollowVerts; - - return copy; - } - - internal void AddPos(Coord v) - { - this.AddPos(v.X, v.Y, v.Z); - } - - internal void AddPos(float x, float y, float z) - { - int i; - int numVerts = this.coords.Count; - Coord vert; - - for (i = 0; i < numVerts; i++) - { - vert = this.coords[i]; - vert.X += x; - vert.Y += y; - vert.Z += z; - this.coords[i] = vert; - } - } - - internal void AddRot(Quat q) - { - int i; - int numVerts = this.coords.Count; - - for (i = 0; i < numVerts; i++) - this.coords[i] *= q; - - if (this.calcVertexNormals) - { - int numNormals = this.vertexNormals.Count; - for (i = 0; i < numNormals; i++) - this.vertexNormals[i] *= q; - - this.faceNormal *= q; - this.cutNormal1 *= q; - this.cutNormal2 *= q; - - } - } - - internal void Scale(float x, float y) - { - int i; - int numVerts = this.coords.Count; - Coord vert; - - for (i = 0; i < numVerts; i++) - { - vert = this.coords[i]; - vert.X *= x; - vert.Y *= y; - this.coords[i] = vert; - } - } - - /// - /// Changes order of the vertex indices and negates the center vertex normal. Does not alter vertex normals of radial vertices - /// - internal void FlipNormals() - { - int i; - int numFaces = this.faces.Count; - Face tmpFace; - int tmp; - - for (i = 0; i < numFaces; i++) - { - tmpFace = this.faces[i]; - tmp = tmpFace.v3; - tmpFace.v3 = tmpFace.v1; - tmpFace.v1 = tmp; - this.faces[i] = tmpFace; - } - - if (this.calcVertexNormals) - { - int normalCount = this.vertexNormals.Count; - if (normalCount > 0) - { - Coord n = this.vertexNormals[normalCount - 1]; - n.Z = -n.Z; - this.vertexNormals[normalCount - 1] = n; - } - } - - this.faceNormal.X = -this.faceNormal.X; - this.faceNormal.Y = -this.faceNormal.Y; - this.faceNormal.Z = -this.faceNormal.Z; - - int numfaceUVs = this.faceUVs.Count; - for (i = 0; i < numfaceUVs; i++) - { - UVCoord uv = this.faceUVs[i]; - uv.V = 1.0f - uv.V; - this.faceUVs[i] = uv; - } - } - - internal void AddValue2FaceVertexIndices(int num) - { - int numFaces = this.faces.Count; - Face tmpFace; - for (int i = 0; i < numFaces; i++) - { - tmpFace = this.faces[i]; - tmpFace.v1 += num; - tmpFace.v2 += num; - tmpFace.v3 += num; - - this.faces[i] = tmpFace; - } - } - - internal void AddValue2FaceNormalIndices(int num) - { - if (this.calcVertexNormals) - { - int numFaces = this.faces.Count; - Face tmpFace; - for (int i = 0; i < numFaces; i++) - { - tmpFace = this.faces[i]; - tmpFace.n1 += num; - tmpFace.n2 += num; - tmpFace.n3 += num; - - this.faces[i] = tmpFace; - } - } - } - - internal void DumpRaw(String path, String name, String title) - { - if (path == null) - return; - String fileName = name + "_" + title + ".raw"; - String completePath = System.IO.Path.Combine(path, fileName); - StreamWriter sw = new StreamWriter(completePath); - - for (int i = 0; i < this.faces.Count; i++) - { - string s = this.coords[this.faces[i].v1].ToString(); - s += " " + this.coords[this.faces[i].v2].ToString(); - s += " " + this.coords[this.faces[i].v3].ToString(); - - sw.WriteLine(s); - } - - sw.Close(); - } - } - - public struct PathNode - { - public Coord position; - public Quat rotation; - public float xScale; - public float yScale; - public float percentOfPath; - } - - public enum PathType { Linear = 0, Circular = 1, Flexible = 2 } - - public class Path - { - public List pathNodes = new List(); - - public float twistBegin = 0.0f; - public float twistEnd = 0.0f; - public float topShearX = 0.0f; - public float topShearY = 0.0f; - public float pathCutBegin = 0.0f; - public float pathCutEnd = 1.0f; - public float dimpleBegin = 0.0f; - public float dimpleEnd = 1.0f; - public float skew = 0.0f; - public float holeSizeX = 1.0f; // called pathScaleX in pbs - public float holeSizeY = 0.25f; - public float taperX = 0.0f; - public float taperY = 0.0f; - public float radius = 0.0f; - public float revolutions = 1.0f; - public int stepsPerRevolution = 24; - - private const float twoPi = 2.0f * (float)Math.PI; - - public void Create(PathType pathType, int steps) - { - if (pathType == PathType.Linear || pathType == PathType.Flexible) - { - int step = 0; - - float length = this.pathCutEnd - this.pathCutBegin; - float twistTotal = twistEnd - twistBegin; - float twistTotalAbs = Math.Abs(twistTotal); - if (twistTotalAbs > 0.01f) - steps += (int)(twistTotalAbs * 3.66); // dahlia's magic number - - float start = -0.5f; - float stepSize = length / (float)steps; - float percentOfPathMultiplier = stepSize; - float xOffset = 0.0f; - float yOffset = 0.0f; - float zOffset = start; - float xOffsetStepIncrement = this.topShearX / steps; - float yOffsetStepIncrement = this.topShearY / steps; - - float percentOfPath = this.pathCutBegin; - zOffset += percentOfPath; - - // sanity checks - - bool done = false; - - while (!done) - { - PathNode newNode = new PathNode(); - - newNode.xScale = 1.0f; - if (this.taperX == 0.0f) - newNode.xScale = 1.0f; - else if (this.taperX > 0.0f) - newNode.xScale = 1.0f - percentOfPath * this.taperX; - else newNode.xScale = 1.0f + (1.0f - percentOfPath) * this.taperX; - - newNode.yScale = 1.0f; - if (this.taperY == 0.0f) - newNode.yScale = 1.0f; - else if (this.taperY > 0.0f) - newNode.yScale = 1.0f - percentOfPath * this.taperY; - else newNode.yScale = 1.0f + (1.0f - percentOfPath) * this.taperY; - - float twist = twistBegin + twistTotal * percentOfPath; - - newNode.rotation = new Quat(new Coord(0.0f, 0.0f, 1.0f), twist); - newNode.position = new Coord(xOffset, yOffset, zOffset); - newNode.percentOfPath = percentOfPath; - - pathNodes.Add(newNode); - - if (step < steps) - { - step += 1; - percentOfPath += percentOfPathMultiplier; - xOffset += xOffsetStepIncrement; - yOffset += yOffsetStepIncrement; - zOffset += stepSize; - if (percentOfPath > this.pathCutEnd) - done = true; - } - else done = true; - } - } // end of linear path code - - else // pathType == Circular - { - float twistTotal = twistEnd - twistBegin; - - // if the profile has a lot of twist, add more layers otherwise the layers may overlap - // and the resulting mesh may be quite inaccurate. This method is arbitrary and doesn't - // accurately match the viewer - float twistTotalAbs = Math.Abs(twistTotal); - if (twistTotalAbs > 0.01f) - { - if (twistTotalAbs > Math.PI * 1.5f) - steps *= 2; - if (twistTotalAbs > Math.PI * 3.0f) - steps *= 2; - } - - float yPathScale = this.holeSizeY * 0.5f; - float pathLength = this.pathCutEnd - this.pathCutBegin; - float totalSkew = this.skew * 2.0f * pathLength; - float skewStart = this.pathCutBegin * 2.0f * this.skew - this.skew; - float xOffsetTopShearXFactor = this.topShearX * (0.25f + 0.5f * (0.5f - this.holeSizeY)); - float yShearCompensation = 1.0f + Math.Abs(this.topShearY) * 0.25f; - - // It's not quite clear what pushY (Y top shear) does, but subtracting it from the start and end - // angles appears to approximate it's effects on path cut. Likewise, adding it to the angle used - // to calculate the sine for generating the path radius appears to approximate it's effects there - // too, but there are some subtle differences in the radius which are noticeable as the prim size - // increases and it may affect megaprims quite a bit. The effect of the Y top shear parameter on - // the meshes generated with this technique appear nearly identical in shape to the same prims when - // displayed by the viewer. - - float startAngle = (twoPi * this.pathCutBegin * this.revolutions) - this.topShearY * 0.9f; - float endAngle = (twoPi * this.pathCutEnd * this.revolutions) - this.topShearY * 0.9f; - float stepSize = twoPi / this.stepsPerRevolution; - - int step = (int)(startAngle / stepSize); -// int firstStep = step; - float angle = startAngle; - - bool done = false; - while (!done) // loop through the length of the path and add the layers - { - PathNode newNode = new PathNode(); - - float xProfileScale = (1.0f - Math.Abs(this.skew)) * this.holeSizeX; - float yProfileScale = this.holeSizeY; - - float percentOfPath = angle / (twoPi * this.revolutions); - float percentOfAngles = (angle - startAngle) / (endAngle - startAngle); - - if (this.taperX > 0.01f) - xProfileScale *= 1.0f - percentOfPath * this.taperX; - else if (this.taperX < -0.01f) - xProfileScale *= 1.0f + (1.0f - percentOfPath) * this.taperX; - - if (this.taperY > 0.01f) - yProfileScale *= 1.0f - percentOfPath * this.taperY; - else if (this.taperY < -0.01f) - yProfileScale *= 1.0f + (1.0f - percentOfPath) * this.taperY; - - newNode.xScale = xProfileScale; - newNode.yScale = yProfileScale; - - float radiusScale = 1.0f; - if (this.radius > 0.001f) - radiusScale = 1.0f - this.radius * percentOfPath; - else if (this.radius < 0.001f) - radiusScale = 1.0f + this.radius * (1.0f - percentOfPath); - - float twist = twistBegin + twistTotal * percentOfPath; - - float xOffset = 0.5f * (skewStart + totalSkew * percentOfAngles); - xOffset += (float)Math.Sin(angle) * xOffsetTopShearXFactor; - - float yOffset = yShearCompensation * (float)Math.Cos(angle) * (0.5f - yPathScale) * radiusScale; - - float zOffset = (float)Math.Sin(angle + this.topShearY) * (0.5f - yPathScale) * radiusScale; - - newNode.position = new Coord(xOffset, yOffset, zOffset); - - // now orient the rotation of the profile layer relative to it's position on the path - // adding taperY to the angle used to generate the quat appears to approximate the viewer - - newNode.rotation = new Quat(new Coord(1.0f, 0.0f, 0.0f), angle + this.topShearY); - - // next apply twist rotation to the profile layer - if (twistTotal != 0.0f || twistBegin != 0.0f) - newNode.rotation *= new Quat(new Coord(0.0f, 0.0f, 1.0f), twist); - - newNode.percentOfPath = percentOfPath; - - pathNodes.Add(newNode); - - // calculate terms for next iteration - // calculate the angle for the next iteration of the loop - - if (angle >= endAngle - 0.01) - done = true; - else - { - step += 1; - angle = stepSize * step; - if (angle > endAngle) - angle = endAngle; - } - } - } - } - } - - public class PrimMesh - { - public string errorMessage = ""; - private const float twoPi = 2.0f * (float)Math.PI; - - public List coords; - public List normals; - public List faces; - - public List viewerFaces; - - private int sides = 4; - private int hollowSides = 4; - private float profileStart = 0.0f; - private float profileEnd = 1.0f; - private float hollow = 0.0f; - public int twistBegin = 0; - public int twistEnd = 0; - public float topShearX = 0.0f; - public float topShearY = 0.0f; - public float pathCutBegin = 0.0f; - public float pathCutEnd = 1.0f; - public float dimpleBegin = 0.0f; - public float dimpleEnd = 1.0f; - public float skew = 0.0f; - public float holeSizeX = 1.0f; // called pathScaleX in pbs - public float holeSizeY = 0.25f; - public float taperX = 0.0f; - public float taperY = 0.0f; - public float radius = 0.0f; - public float revolutions = 1.0f; - public int stepsPerRevolution = 24; - - private bool hasProfileCut = false; - private bool hasHollow = false; - public bool calcVertexNormals = false; - private bool normalsProcessed = false; - public bool viewerMode = false; - - public int numPrimFaces = 0; - - /// - /// Human readable string representation of the parameters used to create a mesh. - /// - /// - public string ParamsToDisplayString() - { - string s = ""; - s += "sides..................: " + this.sides.ToString(); - s += "\nhollowSides..........: " + this.hollowSides.ToString(); - s += "\nprofileStart.........: " + this.profileStart.ToString(); - s += "\nprofileEnd...........: " + this.profileEnd.ToString(); - s += "\nhollow...............: " + this.hollow.ToString(); - s += "\ntwistBegin...........: " + this.twistBegin.ToString(); - s += "\ntwistEnd.............: " + this.twistEnd.ToString(); - s += "\ntopShearX............: " + this.topShearX.ToString(); - s += "\ntopShearY............: " + this.topShearY.ToString(); - s += "\npathCutBegin.........: " + this.pathCutBegin.ToString(); - s += "\npathCutEnd...........: " + this.pathCutEnd.ToString(); - s += "\ndimpleBegin..........: " + this.dimpleBegin.ToString(); - s += "\ndimpleEnd............: " + this.dimpleEnd.ToString(); - s += "\nskew.................: " + this.skew.ToString(); - s += "\nholeSizeX............: " + this.holeSizeX.ToString(); - s += "\nholeSizeY............: " + this.holeSizeY.ToString(); - s += "\ntaperX...............: " + this.taperX.ToString(); - s += "\ntaperY...............: " + this.taperY.ToString(); - s += "\nradius...............: " + this.radius.ToString(); - s += "\nrevolutions..........: " + this.revolutions.ToString(); - s += "\nstepsPerRevolution...: " + this.stepsPerRevolution.ToString(); - - return s; - } - - /// - /// Constructs a PrimMesh object and creates the profile for extrusion. - /// - /// - /// - /// - /// - /// - public PrimMesh(int sides, float profileStart, float profileEnd, float hollow, int hollowSides) - { - this.coords = new List(); - this.faces = new List(); - - this.sides = sides; - this.profileStart = profileStart; - this.profileEnd = profileEnd; - this.hollow = hollow; - this.hollowSides = hollowSides; - - if (sides < 3) - this.sides = 3; - if (hollowSides < 3) - this.hollowSides = 3; - if (profileStart < 0.0f) - this.profileStart = 0.0f; - if (profileEnd > 1.0f) - this.profileEnd = 1.0f; - if (profileEnd < 0.02f) - this.profileEnd = 0.02f; - if (profileStart >= profileEnd) - this.profileStart = profileEnd - 0.02f; - if (hollow > 0.99f) - this.hollow = 0.99f; - if (hollow < 0.0f) - this.hollow = 0.0f; - - this.hasProfileCut = (this.profileStart > 0.0f || this.profileEnd < 1.0f); - this.hasHollow = (this.hollow > 0.001f); - } - - /// - /// Extrudes a profile along a path. - /// - public void Extrude(PathType pathType) - { - this.coords = new List(); - this.faces = new List(); - - if (this.viewerMode) - { - this.viewerFaces = new List(); - this.calcVertexNormals = true; - } - - if (this.calcVertexNormals) - this.normals = new List(); - - int steps = 1; - - float length = this.pathCutEnd - this.pathCutBegin; - normalsProcessed = false; - - if (this.viewerMode && this.sides == 3) - { - // prisms don't taper well so add some vertical resolution - // other prims may benefit from this but just do prisms for now - if (Math.Abs(this.taperX) > 0.01 || Math.Abs(this.taperY) > 0.01) - steps = (int)(steps * 4.5 * length); - } - - - float twistBegin = this.twistBegin / 360.0f * twoPi; - float twistEnd = this.twistEnd / 360.0f * twoPi; - float twistTotal = twistEnd - twistBegin; - float twistTotalAbs = Math.Abs(twistTotal); - if (twistTotalAbs > 0.01f) - steps += (int)(twistTotalAbs * 3.66); // dahlia's magic number - - float hollow = this.hollow; - - // sanity checks - float initialProfileRot = 0.0f; - if (pathType == PathType.Circular) - { - if (this.sides == 3) - { - initialProfileRot = (float)Math.PI; - if (this.hollowSides == 4) - { - if (hollow > 0.7f) - hollow = 0.7f; - hollow *= 0.707f; - } - else hollow *= 0.5f; - } - else if (this.sides == 4) - { - initialProfileRot = 0.25f * (float)Math.PI; - if (this.hollowSides != 4) - hollow *= 0.707f; - } - else if (this.sides > 4) - { - initialProfileRot = (float)Math.PI; - if (this.hollowSides == 4) - { - if (hollow > 0.7f) - hollow = 0.7f; - hollow /= 0.7f; - } - } - } - else - { - if (this.sides == 3) - { - if (this.hollowSides == 4) - { - if (hollow > 0.7f) - hollow = 0.7f; - hollow *= 0.707f; - } - else hollow *= 0.5f; - } - else if (this.sides == 4) - { - initialProfileRot = 1.25f * (float)Math.PI; - if (this.hollowSides != 4) - hollow *= 0.707f; - } - else if (this.sides == 24 && this.hollowSides == 4) - hollow *= 1.414f; - } - - Profile profile = new Profile(this.sides, this.profileStart, this.profileEnd, hollow, this.hollowSides, true, calcVertexNormals); - this.errorMessage = profile.errorMessage; - - this.numPrimFaces = profile.numPrimFaces; - - int cut1Vert = -1; - int cut2Vert = -1; - if (hasProfileCut) - { - cut1Vert = hasHollow ? profile.coords.Count - 1 : 0; - cut2Vert = hasHollow ? profile.numOuterVerts - 1 : profile.numOuterVerts; - } - - if (initialProfileRot != 0.0f) - { - profile.AddRot(new Quat(new Coord(0.0f, 0.0f, 1.0f), initialProfileRot)); - if (viewerMode) - profile.MakeFaceUVs(); - } - - Coord lastCutNormal1 = new Coord(); - Coord lastCutNormal2 = new Coord(); - float lastV = 1.0f; - - Path path = new Path(); - path.twistBegin = twistBegin; - path.twistEnd = twistEnd; - path.topShearX = topShearX; - path.topShearY = topShearY; - path.pathCutBegin = pathCutBegin; - path.pathCutEnd = pathCutEnd; - path.dimpleBegin = dimpleBegin; - path.dimpleEnd = dimpleEnd; - path.skew = skew; - path.holeSizeX = holeSizeX; - path.holeSizeY = holeSizeY; - path.taperX = taperX; - path.taperY = taperY; - path.radius = radius; - path.revolutions = revolutions; - path.stepsPerRevolution = stepsPerRevolution; - - path.Create(pathType, steps); - - bool needEndFaces = false; - if (pathType == PathType.Circular) - { - needEndFaces = false; - if (this.pathCutBegin != 0.0f || this.pathCutEnd != 1.0f) - needEndFaces = true; - else if (this.taperX != 0.0f || this.taperY != 0.0f) - needEndFaces = true; - else if (this.skew != 0.0f) - needEndFaces = true; - else if (twistTotal != 0.0f) - needEndFaces = true; - else if (this.radius != 0.0f) - needEndFaces = true; - } - else needEndFaces = true; - - for (int nodeIndex = 0; nodeIndex < path.pathNodes.Count; nodeIndex++) - { - PathNode node = path.pathNodes[nodeIndex]; - Profile newLayer = profile.Copy(); - newLayer.Scale(node.xScale, node.yScale); - - newLayer.AddRot(node.rotation); - newLayer.AddPos(node.position); - - if (needEndFaces && nodeIndex == 0) - { - newLayer.FlipNormals(); - - // add the top faces to the viewerFaces list here - if (this.viewerMode) - { - Coord faceNormal = newLayer.faceNormal; - ViewerFace newViewerFace = new ViewerFace(profile.bottomFaceNumber); - int numFaces = newLayer.faces.Count; - List faces = newLayer.faces; - - for (int i = 0; i < numFaces; i++) - { - Face face = faces[i]; - newViewerFace.v1 = newLayer.coords[face.v1]; - newViewerFace.v2 = newLayer.coords[face.v2]; - newViewerFace.v3 = newLayer.coords[face.v3]; - - newViewerFace.coordIndex1 = face.v1; - newViewerFace.coordIndex2 = face.v2; - newViewerFace.coordIndex3 = face.v3; - - newViewerFace.n1 = faceNormal; - newViewerFace.n2 = faceNormal; - newViewerFace.n3 = faceNormal; - - newViewerFace.uv1 = newLayer.faceUVs[face.v1]; - newViewerFace.uv2 = newLayer.faceUVs[face.v2]; - newViewerFace.uv3 = newLayer.faceUVs[face.v3]; - - this.viewerFaces.Add(newViewerFace); - } - } - } // if (nodeIndex == 0) - - // append this layer - - int coordsLen = this.coords.Count; -// int lastCoordsLen = coordsLen; - newLayer.AddValue2FaceVertexIndices(coordsLen); - - this.coords.AddRange(newLayer.coords); - - if (this.calcVertexNormals) - { - newLayer.AddValue2FaceNormalIndices(this.normals.Count); - this.normals.AddRange(newLayer.vertexNormals); - } - - if (node.percentOfPath < this.pathCutBegin + 0.01f || node.percentOfPath > this.pathCutEnd - 0.01f) - this.faces.AddRange(newLayer.faces); - - // fill faces between layers - - int numVerts = newLayer.coords.Count; - Face newFace = new Face(); - - if (nodeIndex > 0) - { - int startVert = coordsLen + 1; - int endVert = this.coords.Count; - - if (sides < 5 || this.hasProfileCut || hollow > 0.0f) - startVert--; - - for (int i = startVert; i < endVert; i++) - { - int iNext = i + 1; - if (i == endVert - 1) - iNext = startVert; - - int whichVert = i - startVert; - - newFace.v1 = i; - newFace.v2 = i - numVerts; - newFace.v3 = iNext - numVerts; - this.faces.Add(newFace); - - newFace.v2 = iNext - numVerts; - newFace.v3 = iNext; - this.faces.Add(newFace); - - if (this.viewerMode) - { - // add the side faces to the list of viewerFaces here - - int primFaceNum = profile.faceNumbers[whichVert]; - if (!needEndFaces) - primFaceNum -= 1; - - ViewerFace newViewerFace1 = new ViewerFace(primFaceNum); - ViewerFace newViewerFace2 = new ViewerFace(primFaceNum); - - float u1 = newLayer.us[whichVert]; - float u2 = 1.0f; - if (whichVert < newLayer.us.Count - 1) - u2 = newLayer.us[whichVert + 1]; - - if (whichVert == cut1Vert || whichVert == cut2Vert) - { - u1 = 0.0f; - u2 = 1.0f; - } - else if (sides < 5) - { - if (whichVert < profile.numOuterVerts) - { // boxes and prisms have one texture face per side of the prim, so the U values have to be scaled - // to reflect the entire texture width - u1 *= sides; - u2 *= sides; - u2 -= (int)u1; - u1 -= (int)u1; - if (u2 < 0.1f) - u2 = 1.0f; - } - else if (whichVert > profile.coords.Count - profile.numHollowVerts - 1) - { - u1 *= 2.0f; - u2 *= 2.0f; - } - } - - newViewerFace1.uv1.U = u1; - newViewerFace1.uv2.U = u1; - newViewerFace1.uv3.U = u2; - - newViewerFace1.uv1.V = 1.0f - node.percentOfPath; - newViewerFace1.uv2.V = lastV; - newViewerFace1.uv3.V = lastV; - - newViewerFace2.uv1.U = u1; - newViewerFace2.uv2.U = u2; - newViewerFace2.uv3.U = u2; - - newViewerFace2.uv1.V = 1.0f - node.percentOfPath; - newViewerFace2.uv2.V = lastV; - newViewerFace2.uv3.V = 1.0f - node.percentOfPath; - - newViewerFace1.v1 = this.coords[i]; - newViewerFace1.v2 = this.coords[i - numVerts]; - newViewerFace1.v3 = this.coords[iNext - numVerts]; - - newViewerFace2.v1 = this.coords[i]; - newViewerFace2.v2 = this.coords[iNext - numVerts]; - newViewerFace2.v3 = this.coords[iNext]; - - newViewerFace1.coordIndex1 = i; - newViewerFace1.coordIndex2 = i - numVerts; - newViewerFace1.coordIndex3 = iNext - numVerts; - - newViewerFace2.coordIndex1 = i; - newViewerFace2.coordIndex2 = iNext - numVerts; - newViewerFace2.coordIndex3 = iNext; - - // profile cut faces - if (whichVert == cut1Vert) - { - newViewerFace1.n1 = newLayer.cutNormal1; - newViewerFace1.n2 = newViewerFace1.n3 = lastCutNormal1; - - newViewerFace2.n1 = newViewerFace2.n3 = newLayer.cutNormal1; - newViewerFace2.n2 = lastCutNormal1; - } - else if (whichVert == cut2Vert) - { - newViewerFace1.n1 = newLayer.cutNormal2; - newViewerFace1.n2 = newViewerFace1.n3 = lastCutNormal2; - - newViewerFace2.n1 = newViewerFace2.n3 = newLayer.cutNormal2; - newViewerFace2.n2 = lastCutNormal2; - } - - else // outer and hollow faces - { - if ((sides < 5 && whichVert < newLayer.numOuterVerts) || (hollowSides < 5 && whichVert >= newLayer.numOuterVerts)) - { // looks terrible when path is twisted... need vertex normals here - newViewerFace1.CalcSurfaceNormal(); - newViewerFace2.CalcSurfaceNormal(); - } - else - { - newViewerFace1.n1 = this.normals[i]; - newViewerFace1.n2 = this.normals[i - numVerts]; - newViewerFace1.n3 = this.normals[iNext - numVerts]; - - newViewerFace2.n1 = this.normals[i]; - newViewerFace2.n2 = this.normals[iNext - numVerts]; - newViewerFace2.n3 = this.normals[iNext]; - } - } - - this.viewerFaces.Add(newViewerFace1); - this.viewerFaces.Add(newViewerFace2); - - } - } - } - - lastCutNormal1 = newLayer.cutNormal1; - lastCutNormal2 = newLayer.cutNormal2; - lastV = 1.0f - node.percentOfPath; - - if (needEndFaces && nodeIndex == path.pathNodes.Count - 1 && viewerMode) - { - // add the top faces to the viewerFaces list here - Coord faceNormal = newLayer.faceNormal; - ViewerFace newViewerFace = new ViewerFace(); - newViewerFace.primFaceNumber = 0; - int numFaces = newLayer.faces.Count; - List faces = newLayer.faces; - - for (int i = 0; i < numFaces; i++) - { - Face face = faces[i]; - newViewerFace.v1 = newLayer.coords[face.v1 - coordsLen]; - newViewerFace.v2 = newLayer.coords[face.v2 - coordsLen]; - newViewerFace.v3 = newLayer.coords[face.v3 - coordsLen]; - - newViewerFace.coordIndex1 = face.v1 - coordsLen; - newViewerFace.coordIndex2 = face.v2 - coordsLen; - newViewerFace.coordIndex3 = face.v3 - coordsLen; - - newViewerFace.n1 = faceNormal; - newViewerFace.n2 = faceNormal; - newViewerFace.n3 = faceNormal; - - newViewerFace.uv1 = newLayer.faceUVs[face.v1 - coordsLen]; - newViewerFace.uv2 = newLayer.faceUVs[face.v2 - coordsLen]; - newViewerFace.uv3 = newLayer.faceUVs[face.v3 - coordsLen]; - - this.viewerFaces.Add(newViewerFace); - } - } - - - } // for (int nodeIndex = 0; nodeIndex < path.pathNodes.Count; nodeIndex++) - - } - - - /// - /// DEPRICATED - use Extrude(PathType.Linear) instead - /// Extrudes a profile along a straight line path. Used for prim types box, cylinder, and prism. - /// - /// - public void ExtrudeLinear() - { - this.Extrude(PathType.Linear); - } - - - /// - /// DEPRICATED - use Extrude(PathType.Circular) instead - /// Extrude a profile into a circular path prim mesh. Used for prim types torus, tube, and ring. - /// - /// - public void ExtrudeCircular() - { - this.Extrude(PathType.Circular); - } - - - private Coord SurfaceNormal(Coord c1, Coord c2, Coord c3) - { - Coord edge1 = new Coord(c2.X - c1.X, c2.Y - c1.Y, c2.Z - c1.Z); - Coord edge2 = new Coord(c3.X - c1.X, c3.Y - c1.Y, c3.Z - c1.Z); - - Coord normal = Coord.Cross(edge1, edge2); - - normal.Normalize(); - - return normal; - } - - private Coord SurfaceNormal(Face face) - { - return SurfaceNormal(this.coords[face.v1], this.coords[face.v2], this.coords[face.v3]); - } - - /// - /// Calculate the surface normal for a face in the list of faces - /// - /// - /// - public Coord SurfaceNormal(int faceIndex) - { - int numFaces = this.faces.Count; - if (faceIndex < 0 || faceIndex >= numFaces) - throw new Exception("faceIndex out of range"); - - return SurfaceNormal(this.faces[faceIndex]); - } - - /// - /// Duplicates a PrimMesh object. All object properties are copied by value, including lists. - /// - /// - public PrimMesh Copy() - { - PrimMesh copy = new PrimMesh(this.sides, this.profileStart, this.profileEnd, this.hollow, this.hollowSides); - copy.twistBegin = this.twistBegin; - copy.twistEnd = this.twistEnd; - copy.topShearX = this.topShearX; - copy.topShearY = this.topShearY; - copy.pathCutBegin = this.pathCutBegin; - copy.pathCutEnd = this.pathCutEnd; - copy.dimpleBegin = this.dimpleBegin; - copy.dimpleEnd = this.dimpleEnd; - copy.skew = this.skew; - copy.holeSizeX = this.holeSizeX; - copy.holeSizeY = this.holeSizeY; - copy.taperX = this.taperX; - copy.taperY = this.taperY; - copy.radius = this.radius; - copy.revolutions = this.revolutions; - copy.stepsPerRevolution = this.stepsPerRevolution; - copy.calcVertexNormals = this.calcVertexNormals; - copy.normalsProcessed = this.normalsProcessed; - copy.viewerMode = this.viewerMode; - copy.numPrimFaces = this.numPrimFaces; - copy.errorMessage = this.errorMessage; - - copy.coords = new List(this.coords); - copy.faces = new List(this.faces); - copy.viewerFaces = new List(this.viewerFaces); - copy.normals = new List(this.normals); - - return copy; - } - - /// - /// Calculate surface normals for all of the faces in the list of faces in this mesh - /// - public void CalcNormals() - { - if (normalsProcessed) - return; - - normalsProcessed = true; - - int numFaces = faces.Count; - - if (!this.calcVertexNormals) - this.normals = new List(); - - for (int i = 0; i < numFaces; i++) - { - Face face = faces[i]; - - this.normals.Add(SurfaceNormal(i).Normalize()); - - int normIndex = normals.Count - 1; - face.n1 = normIndex; - face.n2 = normIndex; - face.n3 = normIndex; - - this.faces[i] = face; - } - } - - /// - /// Adds a value to each XYZ vertex coordinate in the mesh - /// - /// - /// - /// - public void AddPos(float x, float y, float z) - { - int i; - int numVerts = this.coords.Count; - Coord vert; - - for (i = 0; i < numVerts; i++) - { - vert = this.coords[i]; - vert.X += x; - vert.Y += y; - vert.Z += z; - this.coords[i] = vert; - } - - if (this.viewerFaces != null) - { - int numViewerFaces = this.viewerFaces.Count; - - for (i = 0; i < numViewerFaces; i++) - { - ViewerFace v = this.viewerFaces[i]; - v.AddPos(x, y, z); - this.viewerFaces[i] = v; - } - } - } - - /// - /// Rotates the mesh - /// - /// - public void AddRot(Quat q) - { - int i; - int numVerts = this.coords.Count; - - for (i = 0; i < numVerts; i++) - this.coords[i] *= q; - - if (this.normals != null) - { - int numNormals = this.normals.Count; - for (i = 0; i < numNormals; i++) - this.normals[i] *= q; - } - - if (this.viewerFaces != null) - { - int numViewerFaces = this.viewerFaces.Count; - - for (i = 0; i < numViewerFaces; i++) - { - ViewerFace v = this.viewerFaces[i]; - v.v1 *= q; - v.v2 *= q; - v.v3 *= q; - - v.n1 *= q; - v.n2 *= q; - v.n3 *= q; - this.viewerFaces[i] = v; - } - } - } - -#if VERTEX_INDEXER - public VertexIndexer GetVertexIndexer() - { - if (this.viewerMode && this.viewerFaces.Count > 0) - return new VertexIndexer(this); - return null; - } -#endif - - /// - /// Scales the mesh - /// - /// - /// - /// - public void Scale(float x, float y, float z) - { - int i; - int numVerts = this.coords.Count; - //Coord vert; - - Coord m = new Coord(x, y, z); - for (i = 0; i < numVerts; i++) - this.coords[i] *= m; - - if (this.viewerFaces != null) - { - int numViewerFaces = this.viewerFaces.Count; - for (i = 0; i < numViewerFaces; i++) - { - ViewerFace v = this.viewerFaces[i]; - v.v1 *= m; - v.v2 *= m; - v.v3 *= m; - this.viewerFaces[i] = v; - } - - } - - } - - /// - /// Dumps the mesh to a Blender compatible "Raw" format file - /// - /// - /// - /// - public void DumpRaw(String path, String name, String title) - { - if (path == null) - return; - String fileName = name + "_" + title + ".raw"; - String completePath = System.IO.Path.Combine(path, fileName); - StreamWriter sw = new StreamWriter(completePath); - - for (int i = 0; i < this.faces.Count; i++) - { - string s = this.coords[this.faces[i].v1].ToString(); - s += " " + this.coords[this.faces[i].v2].ToString(); - s += " " + this.coords[this.faces[i].v3].ToString(); - - sw.WriteLine(s); - } - - sw.Close(); - } - } -} +/* + * Copyright (c) Contributors + * 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 OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Text; +using System.IO; + +namespace PrimMesher +{ + public struct Quat + { + /// X value + public float X; + /// Y value + public float Y; + /// Z value + public float Z; + /// W value + public float W; + + public Quat(float x, float y, float z, float w) + { + X = x; + Y = y; + Z = z; + W = w; + } + + public Quat(Coord axis, float angle) + { + axis = axis.Normalize(); + + angle *= 0.5f; + float c = (float)Math.Cos(angle); + float s = (float)Math.Sin(angle); + + X = axis.X * s; + Y = axis.Y * s; + Z = axis.Z * s; + W = c; + + Normalize(); + } + + public float Length() + { + return (float)Math.Sqrt(X * X + Y * Y + Z * Z + W * W); + } + + public Quat Normalize() + { + const float MAG_THRESHOLD = 0.0000001f; + float mag = Length(); + + // Catch very small rounding errors when normalizing + if (mag > MAG_THRESHOLD) + { + float oomag = 1f / mag; + X *= oomag; + Y *= oomag; + Z *= oomag; + W *= oomag; + } + else + { + X = 0f; + Y = 0f; + Z = 0f; + W = 1f; + } + + return this; + } + + public static Quat operator *(Quat q1, Quat q2) + { + float x = q1.W * q2.X + q1.X * q2.W + q1.Y * q2.Z - q1.Z * q2.Y; + float y = q1.W * q2.Y - q1.X * q2.Z + q1.Y * q2.W + q1.Z * q2.X; + float z = q1.W * q2.Z + q1.X * q2.Y - q1.Y * q2.X + q1.Z * q2.W; + float w = q1.W * q2.W - q1.X * q2.X - q1.Y * q2.Y - q1.Z * q2.Z; + return new Quat(x, y, z, w); + } + + public override string ToString() + { + return "< X: " + this.X.ToString() + ", Y: " + this.Y.ToString() + ", Z: " + this.Z.ToString() + ", W: " + this.W.ToString() + ">"; + } + } + + public struct Coord + { + public float X; + public float Y; + public float Z; + + public Coord(float x, float y, float z) + { + this.X = x; + this.Y = y; + this.Z = z; + } + + public float Length() + { + return (float)Math.Sqrt(this.X * this.X + this.Y * this.Y + this.Z * this.Z); + } + + public Coord Invert() + { + this.X = -this.X; + this.Y = -this.Y; + this.Z = -this.Z; + + return this; + } + + public Coord Normalize() + { + const float MAG_THRESHOLD = 0.0000001f; + float mag = Length(); + + // Catch very small rounding errors when normalizing + if (mag > MAG_THRESHOLD) + { + float oomag = 1.0f / mag; + this.X *= oomag; + this.Y *= oomag; + this.Z *= oomag; + } + else + { + this.X = 0.0f; + this.Y = 0.0f; + this.Z = 0.0f; + } + + return this; + } + + public override string ToString() + { + return this.X.ToString() + " " + this.Y.ToString() + " " + this.Z.ToString(); + } + + public static Coord Cross(Coord c1, Coord c2) + { + return new Coord( + c1.Y * c2.Z - c2.Y * c1.Z, + c1.Z * c2.X - c2.Z * c1.X, + c1.X * c2.Y - c2.X * c1.Y + ); + } + + public static Coord operator +(Coord v, Coord a) + { + return new Coord(v.X + a.X, v.Y + a.Y, v.Z + a.Z); + } + + public static Coord operator *(Coord v, Coord m) + { + return new Coord(v.X * m.X, v.Y * m.Y, v.Z * m.Z); + } + + public static Coord operator *(Coord v, Quat q) + { + // From http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/transforms/ + + Coord c2 = new Coord(0.0f, 0.0f, 0.0f); + + c2.X = q.W * q.W * v.X + + 2f * q.Y * q.W * v.Z - + 2f * q.Z * q.W * v.Y + + q.X * q.X * v.X + + 2f * q.Y * q.X * v.Y + + 2f * q.Z * q.X * v.Z - + q.Z * q.Z * v.X - + q.Y * q.Y * v.X; + + c2.Y = + 2f * q.X * q.Y * v.X + + q.Y * q.Y * v.Y + + 2f * q.Z * q.Y * v.Z + + 2f * q.W * q.Z * v.X - + q.Z * q.Z * v.Y + + q.W * q.W * v.Y - + 2f * q.X * q.W * v.Z - + q.X * q.X * v.Y; + + c2.Z = + 2f * q.X * q.Z * v.X + + 2f * q.Y * q.Z * v.Y + + q.Z * q.Z * v.Z - + 2f * q.W * q.Y * v.X - + q.Y * q.Y * v.Z + + 2f * q.W * q.X * v.Y - + q.X * q.X * v.Z + + q.W * q.W * v.Z; + + return c2; + } + } + + public struct UVCoord + { + public float U; + public float V; + + + public UVCoord(float u, float v) + { + this.U = u; + this.V = v; + } + } + + public struct Face + { + public int primFace; + + // vertices + public int v1; + public int v2; + public int v3; + + //normals + public int n1; + public int n2; + public int n3; + + // uvs + public int uv1; + public int uv2; + public int uv3; + + + public Face(int v1, int v2, int v3) + { + primFace = 0; + + this.v1 = v1; + this.v2 = v2; + this.v3 = v3; + + this.n1 = 0; + this.n2 = 0; + this.n3 = 0; + + this.uv1 = 0; + this.uv2 = 0; + this.uv3 = 0; + + } + + public Face(int v1, int v2, int v3, int n1, int n2, int n3) + { + primFace = 0; + + this.v1 = v1; + this.v2 = v2; + this.v3 = v3; + + this.n1 = n1; + this.n2 = n2; + this.n3 = n3; + + this.uv1 = 0; + this.uv2 = 0; + this.uv3 = 0; + } + + public Coord SurfaceNormal(List coordList) + { + Coord c1 = coordList[this.v1]; + Coord c2 = coordList[this.v2]; + Coord c3 = coordList[this.v3]; + + Coord edge1 = new Coord(c2.X - c1.X, c2.Y - c1.Y, c2.Z - c1.Z); + Coord edge2 = new Coord(c3.X - c1.X, c3.Y - c1.Y, c3.Z - c1.Z); + + return Coord.Cross(edge1, edge2).Normalize(); + } + } + + public struct ViewerFace + { + public int primFaceNumber; + + public Coord v1; + public Coord v2; + public Coord v3; + + public int coordIndex1; + public int coordIndex2; + public int coordIndex3; + + public Coord n1; + public Coord n2; + public Coord n3; + + public UVCoord uv1; + public UVCoord uv2; + public UVCoord uv3; + + public ViewerFace(int primFaceNumber) + { + this.primFaceNumber = primFaceNumber; + + this.v1 = new Coord(); + this.v2 = new Coord(); + this.v3 = new Coord(); + + this.coordIndex1 = this.coordIndex2 = this.coordIndex3 = -1; // -1 means not assigned yet + + this.n1 = new Coord(); + this.n2 = new Coord(); + this.n3 = new Coord(); + + this.uv1 = new UVCoord(); + this.uv2 = new UVCoord(); + this.uv3 = new UVCoord(); + } + + public void Scale(float x, float y, float z) + { + this.v1.X *= x; + this.v1.Y *= y; + this.v1.Z *= z; + + this.v2.X *= x; + this.v2.Y *= y; + this.v2.Z *= z; + + this.v3.X *= x; + this.v3.Y *= y; + this.v3.Z *= z; + } + + public void AddPos(float x, float y, float z) + { + this.v1.X += x; + this.v2.X += x; + this.v3.X += x; + + this.v1.Y += y; + this.v2.Y += y; + this.v3.Y += y; + + this.v1.Z += z; + this.v2.Z += z; + this.v3.Z += z; + } + + public void AddRot(Quat q) + { + this.v1 *= q; + this.v2 *= q; + this.v3 *= q; + + this.n1 *= q; + this.n2 *= q; + this.n3 *= q; + } + + public void CalcSurfaceNormal() + { + + Coord edge1 = new Coord(this.v2.X - this.v1.X, this.v2.Y - this.v1.Y, this.v2.Z - this.v1.Z); + Coord edge2 = new Coord(this.v3.X - this.v1.X, this.v3.Y - this.v1.Y, this.v3.Z - this.v1.Z); + + this.n1 = this.n2 = this.n3 = Coord.Cross(edge1, edge2).Normalize(); + } + } + + internal struct Angle + { + internal float angle; + internal float X; + internal float Y; + + internal Angle(float angle, float x, float y) + { + this.angle = angle; + this.X = x; + this.Y = y; + } + } + + internal class AngleList + { + private float iX, iY; // intersection point + + private static Angle[] angles3 = + { + new Angle(0.0f, 1.0f, 0.0f), + new Angle(0.33333333333333333f, -0.5f, 0.86602540378443871f), + new Angle(0.66666666666666667f, -0.5f, -0.86602540378443837f), + new Angle(1.0f, 1.0f, 0.0f) + }; + + private static Coord[] normals3 = + { + new Coord(0.25f, 0.4330127019f, 0.0f).Normalize(), + new Coord(-0.5f, 0.0f, 0.0f).Normalize(), + new Coord(0.25f, -0.4330127019f, 0.0f).Normalize(), + new Coord(0.25f, 0.4330127019f, 0.0f).Normalize() + }; + + private static Angle[] angles4 = + { + new Angle(0.0f, 1.0f, 0.0f), + new Angle(0.25f, 0.0f, 1.0f), + new Angle(0.5f, -1.0f, 0.0f), + new Angle(0.75f, 0.0f, -1.0f), + new Angle(1.0f, 1.0f, 0.0f) + }; + + private static Coord[] normals4 = + { + new Coord(0.5f, 0.5f, 0.0f).Normalize(), + new Coord(-0.5f, 0.5f, 0.0f).Normalize(), + new Coord(-0.5f, -0.5f, 0.0f).Normalize(), + new Coord(0.5f, -0.5f, 0.0f).Normalize(), + new Coord(0.5f, 0.5f, 0.0f).Normalize() + }; + + private static Angle[] angles24 = + { + new Angle(0.0f, 1.0f, 0.0f), + new Angle(0.041666666666666664f, 0.96592582628906831f, 0.25881904510252074f), + new Angle(0.083333333333333329f, 0.86602540378443871f, 0.5f), + new Angle(0.125f, 0.70710678118654757f, 0.70710678118654746f), + new Angle(0.16666666666666667f, 0.5f, 0.8660254037844386f), + new Angle(0.20833333333333331f, 0.25881904510252096f, 0.9659258262890682f), + new Angle(0.25f, 0.0f, 1.0f), + new Angle(0.29166666666666663f, -0.25881904510252063f, 0.96592582628906831f), + new Angle(0.33333333333333333f, -0.5f, 0.86602540378443871f), + new Angle(0.375f, -0.70710678118654746f, 0.70710678118654757f), + new Angle(0.41666666666666663f, -0.86602540378443849f, 0.5f), + new Angle(0.45833333333333331f, -0.9659258262890682f, 0.25881904510252102f), + new Angle(0.5f, -1.0f, 0.0f), + new Angle(0.54166666666666663f, -0.96592582628906842f, -0.25881904510252035f), + new Angle(0.58333333333333326f, -0.86602540378443882f, -0.5f), + new Angle(0.62499999999999989f, -0.70710678118654791f, -0.70710678118654713f), + new Angle(0.66666666666666667f, -0.5f, -0.86602540378443837f), + new Angle(0.70833333333333326f, -0.25881904510252152f, -0.96592582628906809f), + new Angle(0.75f, 0.0f, -1.0f), + new Angle(0.79166666666666663f, 0.2588190451025203f, -0.96592582628906842f), + new Angle(0.83333333333333326f, 0.5f, -0.86602540378443904f), + new Angle(0.875f, 0.70710678118654735f, -0.70710678118654768f), + new Angle(0.91666666666666663f, 0.86602540378443837f, -0.5f), + new Angle(0.95833333333333326f, 0.96592582628906809f, -0.25881904510252157f), + new Angle(1.0f, 1.0f, 0.0f) + }; + + private Angle interpolatePoints(float newPoint, Angle p1, Angle p2) + { + float m = (newPoint - p1.angle) / (p2.angle - p1.angle); + return new Angle(newPoint, p1.X + m * (p2.X - p1.X), p1.Y + m * (p2.Y - p1.Y)); + } + + private void intersection(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) + { // ref: http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline2d/ + double denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1); + double uaNumerator = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3); + + if (denom != 0.0) + { + double ua = uaNumerator / denom; + iX = (float)(x1 + ua * (x2 - x1)); + iY = (float)(y1 + ua * (y2 - y1)); + } + } + + internal List angles; + internal List normals; + + internal void makeAngles(int sides, float startAngle, float stopAngle) + { + angles = new List(); + normals = new List(); + + double twoPi = System.Math.PI * 2.0; + float twoPiInv = 1.0f / (float)twoPi; + + if (sides < 1) + throw new Exception("number of sides not greater than zero"); + if (stopAngle <= startAngle) + throw new Exception("stopAngle not greater than startAngle"); + + if ((sides == 3 || sides == 4 || sides == 24)) + { + startAngle *= twoPiInv; + stopAngle *= twoPiInv; + + Angle[] sourceAngles; + if (sides == 3) + sourceAngles = angles3; + else if (sides == 4) + sourceAngles = angles4; + else sourceAngles = angles24; + + int startAngleIndex = (int)(startAngle * sides); + int endAngleIndex = sourceAngles.Length - 1; + if (stopAngle < 1.0f) + endAngleIndex = (int)(stopAngle * sides) + 1; + if (endAngleIndex == startAngleIndex) + endAngleIndex++; + + for (int angleIndex = startAngleIndex; angleIndex < endAngleIndex + 1; angleIndex++) + { + angles.Add(sourceAngles[angleIndex]); + if (sides == 3) + normals.Add(normals3[angleIndex]); + else if (sides == 4) + normals.Add(normals4[angleIndex]); + } + + if (startAngle > 0.0f) + angles[0] = interpolatePoints(startAngle, angles[0], angles[1]); + + if (stopAngle < 1.0f) + { + int lastAngleIndex = angles.Count - 1; + angles[lastAngleIndex] = interpolatePoints(stopAngle, angles[lastAngleIndex - 1], angles[lastAngleIndex]); + } + } + else + { + double stepSize = twoPi / sides; + + int startStep = (int)(startAngle / stepSize); + double angle = stepSize * startStep; + int step = startStep; + double stopAngleTest = stopAngle; + if (stopAngle < twoPi) + { + stopAngleTest = stepSize * ((int)(stopAngle / stepSize) + 1); + if (stopAngleTest < stopAngle) + stopAngleTest += stepSize; + if (stopAngleTest > twoPi) + stopAngleTest = twoPi; + } + + while (angle <= stopAngleTest) + { + Angle newAngle; + newAngle.angle = (float)angle; + newAngle.X = (float)System.Math.Cos(angle); + newAngle.Y = (float)System.Math.Sin(angle); + angles.Add(newAngle); + step += 1; + angle = stepSize * step; + } + + if (startAngle > angles[0].angle) + { + Angle newAngle; + intersection(angles[0].X, angles[0].Y, angles[1].X, angles[1].Y, 0.0f, 0.0f, (float)Math.Cos(startAngle), (float)Math.Sin(startAngle)); + newAngle.angle = startAngle; + newAngle.X = iX; + newAngle.Y = iY; + angles[0] = newAngle; + } + + int index = angles.Count - 1; + if (stopAngle < angles[index].angle) + { + Angle newAngle; + intersection(angles[index - 1].X, angles[index - 1].Y, angles[index].X, angles[index].Y, 0.0f, 0.0f, (float)Math.Cos(stopAngle), (float)Math.Sin(stopAngle)); + newAngle.angle = stopAngle; + newAngle.X = iX; + newAngle.Y = iY; + angles[index] = newAngle; + } + } + } + } + + /// + /// generates a profile for extrusion + /// + internal class Profile + { + private const float twoPi = 2.0f * (float)Math.PI; + + internal string errorMessage = null; + + internal List coords; + internal List faces; + internal List vertexNormals; + internal List us; + internal List faceUVs; + internal List faceNumbers; + + // use these for making individual meshes for each prim face + internal List outerCoordIndices = null; + internal List hollowCoordIndices = null; + internal List cut1CoordIndices = null; + internal List cut2CoordIndices = null; + + internal Coord faceNormal = new Coord(0.0f, 0.0f, 1.0f); + internal Coord cutNormal1 = new Coord(); + internal Coord cutNormal2 = new Coord(); + + internal int numOuterVerts = 0; + internal int numHollowVerts = 0; + + internal bool calcVertexNormals = false; + internal int bottomFaceNumber = 0; + internal int numPrimFaces = 0; + + internal Profile() + { + this.coords = new List(); + this.faces = new List(); + this.vertexNormals = new List(); + this.us = new List(); + this.faceUVs = new List(); + this.faceNumbers = new List(); + } + + internal Profile(int sides, float profileStart, float profileEnd, float hollow, int hollowSides, bool createFaces, bool calcVertexNormals) + { + this.calcVertexNormals = calcVertexNormals; + this.coords = new List(); + this.faces = new List(); + this.vertexNormals = new List(); + this.us = new List(); + this.faceUVs = new List(); + this.faceNumbers = new List(); + + Coord center = new Coord(0.0f, 0.0f, 0.0f); + //bool hasCenter = false; + + List hollowCoords = new List(); + List hollowNormals = new List(); + List hollowUs = new List(); + + if (calcVertexNormals) + { + this.outerCoordIndices = new List(); + this.hollowCoordIndices = new List(); + this.cut1CoordIndices = new List(); + this.cut2CoordIndices = new List(); + } + + bool hasHollow = (hollow > 0.0f); + + bool hasProfileCut = (profileStart > 0.0f || profileEnd < 1.0f); + + AngleList angles = new AngleList(); + AngleList hollowAngles = new AngleList(); + + float xScale = 0.5f; + float yScale = 0.5f; + if (sides == 4) // corners of a square are sqrt(2) from center + { + xScale = 0.707f; + yScale = 0.707f; + } + + float startAngle = profileStart * twoPi; + float stopAngle = profileEnd * twoPi; + + try { angles.makeAngles(sides, startAngle, stopAngle); } + catch (Exception ex) + { + + errorMessage = "makeAngles failed: Exception: " + ex.ToString() + + "\nsides: " + sides.ToString() + " startAngle: " + startAngle.ToString() + " stopAngle: " + stopAngle.ToString(); + + return; + } + + this.numOuterVerts = angles.angles.Count; + + // flag to create as few triangles as possible for 3 or 4 side profile + bool simpleFace = (sides < 5 && !hasHollow && !hasProfileCut); + + if (hasHollow) + { + if (sides == hollowSides) + hollowAngles = angles; + else + { + try { hollowAngles.makeAngles(hollowSides, startAngle, stopAngle); } + catch (Exception ex) + { + errorMessage = "makeAngles failed: Exception: " + ex.ToString() + + "\nsides: " + sides.ToString() + " startAngle: " + startAngle.ToString() + " stopAngle: " + stopAngle.ToString(); + + return; + } + } + this.numHollowVerts = hollowAngles.angles.Count; + } + else if (!simpleFace) + { + this.coords.Add(center); + //hasCenter = true; + if (this.calcVertexNormals) + this.vertexNormals.Add(new Coord(0.0f, 0.0f, 1.0f)); + this.us.Add(0.0f); + } + + float z = 0.0f; + + Angle angle; + Coord newVert = new Coord(); + if (hasHollow && hollowSides != sides) + { + int numHollowAngles = hollowAngles.angles.Count; + for (int i = 0; i < numHollowAngles; i++) + { + angle = hollowAngles.angles[i]; + newVert.X = hollow * xScale * angle.X; + newVert.Y = hollow * yScale * angle.Y; + newVert.Z = z; + + hollowCoords.Add(newVert); + if (this.calcVertexNormals) + { + if (hollowSides < 5) + hollowNormals.Add(hollowAngles.normals[i].Invert()); + else + hollowNormals.Add(new Coord(-angle.X, -angle.Y, 0.0f)); + + hollowUs.Add(angle.angle * hollow); + } + } + } + + int index = 0; + int numAngles = angles.angles.Count; + + for (int i = 0; i < numAngles; i++) + { + angle = angles.angles[i]; + newVert.X = angle.X * xScale; + newVert.Y = angle.Y * yScale; + newVert.Z = z; + this.coords.Add(newVert); + if (this.calcVertexNormals) + { + this.outerCoordIndices.Add(this.coords.Count - 1); + + if (sides < 5) + { + this.vertexNormals.Add(angles.normals[i]); + float u = angle.angle; + this.us.Add(u); + } + else + { + this.vertexNormals.Add(new Coord(angle.X, angle.Y, 0.0f)); + this.us.Add(angle.angle); + } + } + + if (hasHollow) + { + if (hollowSides == sides) + { + newVert.X *= hollow; + newVert.Y *= hollow; + newVert.Z = z; + hollowCoords.Add(newVert); + if (this.calcVertexNormals) + { + if (sides < 5) + { + hollowNormals.Add(angles.normals[i].Invert()); + } + + else + hollowNormals.Add(new Coord(-angle.X, -angle.Y, 0.0f)); + + hollowUs.Add(angle.angle * hollow); + } + } + } + else if (!simpleFace && createFaces && angle.angle > 0.0001f) + { + Face newFace = new Face(); + newFace.v1 = 0; + newFace.v2 = index; + newFace.v3 = index + 1; + + this.faces.Add(newFace); + } + index += 1; + } + + if (hasHollow) + { + hollowCoords.Reverse(); + if (this.calcVertexNormals) + { + hollowNormals.Reverse(); + hollowUs.Reverse(); + } + + if (createFaces) + { + //int numOuterVerts = this.coords.Count; + //numOuterVerts = this.coords.Count; + //int numHollowVerts = hollowCoords.Count; + int numTotalVerts = this.numOuterVerts + this.numHollowVerts; + + if (this.numOuterVerts == this.numHollowVerts) + { + Face newFace = new Face(); + + for (int coordIndex = 0; coordIndex < this.numOuterVerts - 1; coordIndex++) + { + newFace.v1 = coordIndex; + newFace.v2 = coordIndex + 1; + newFace.v3 = numTotalVerts - coordIndex - 1; + this.faces.Add(newFace); + + newFace.v1 = coordIndex + 1; + newFace.v2 = numTotalVerts - coordIndex - 2; + newFace.v3 = numTotalVerts - coordIndex - 1; + this.faces.Add(newFace); + } + } + else + { + if (this.numOuterVerts < this.numHollowVerts) + { + Face newFace = new Face(); + int j = 0; // j is the index for outer vertices + int maxJ = this.numOuterVerts - 1; + for (int i = 0; i < this.numHollowVerts; i++) // i is the index for inner vertices + { + if (j < maxJ) + if (angles.angles[j + 1].angle - hollowAngles.angles[i].angle < hollowAngles.angles[i].angle - angles.angles[j].angle + 0.000001f) + { + newFace.v1 = numTotalVerts - i - 1; + newFace.v2 = j; + newFace.v3 = j + 1; + + this.faces.Add(newFace); + j += 1; + } + + newFace.v1 = j; + newFace.v2 = numTotalVerts - i - 2; + newFace.v3 = numTotalVerts - i - 1; + + this.faces.Add(newFace); + } + } + else // numHollowVerts < numOuterVerts + { + Face newFace = new Face(); + int j = 0; // j is the index for inner vertices + int maxJ = this.numHollowVerts - 1; + for (int i = 0; i < this.numOuterVerts; i++) + { + if (j < maxJ) + if (hollowAngles.angles[j + 1].angle - angles.angles[i].angle < angles.angles[i].angle - hollowAngles.angles[j].angle + 0.000001f) + { + newFace.v1 = i; + newFace.v2 = numTotalVerts - j - 2; + newFace.v3 = numTotalVerts - j - 1; + + this.faces.Add(newFace); + j += 1; + } + + newFace.v1 = numTotalVerts - j - 1; + newFace.v2 = i; + newFace.v3 = i + 1; + + this.faces.Add(newFace); + } + } + } + } + + if (calcVertexNormals) + { + foreach (Coord hc in hollowCoords) + { + this.coords.Add(hc); + hollowCoordIndices.Add(this.coords.Count - 1); + } + } + else + this.coords.AddRange(hollowCoords); + + if (this.calcVertexNormals) + { + this.vertexNormals.AddRange(hollowNormals); + this.us.AddRange(hollowUs); + + } + } + + if (simpleFace && createFaces) + { + if (sides == 3) + this.faces.Add(new Face(0, 1, 2)); + else if (sides == 4) + { + this.faces.Add(new Face(0, 1, 2)); + this.faces.Add(new Face(0, 2, 3)); + } + } + + if (calcVertexNormals && hasProfileCut) + { + if (hasHollow) + { + int lastOuterVertIndex = this.numOuterVerts - 1; + + this.cut1CoordIndices.Add(0); + this.cut1CoordIndices.Add(this.coords.Count - 1); + + this.cut2CoordIndices.Add(lastOuterVertIndex + 1); + this.cut2CoordIndices.Add(lastOuterVertIndex); + + this.cutNormal1.X = this.coords[0].Y - this.coords[this.coords.Count - 1].Y; + this.cutNormal1.Y = -(this.coords[0].X - this.coords[this.coords.Count - 1].X); + + this.cutNormal2.X = this.coords[lastOuterVertIndex + 1].Y - this.coords[lastOuterVertIndex].Y; + this.cutNormal2.Y = -(this.coords[lastOuterVertIndex + 1].X - this.coords[lastOuterVertIndex].X); + } + + else + { + this.cutNormal1.X = this.vertexNormals[1].Y; + this.cutNormal1.Y = -this.vertexNormals[1].X; + + this.cutNormal2.X = -this.vertexNormals[this.vertexNormals.Count - 2].Y; + this.cutNormal2.Y = this.vertexNormals[this.vertexNormals.Count - 2].X; + + } + this.cutNormal1.Normalize(); + this.cutNormal2.Normalize(); + } + + this.MakeFaceUVs(); + + hollowCoords = null; + hollowNormals = null; + hollowUs = null; + + if (calcVertexNormals) + { // calculate prim face numbers + + // face number order is top, outer, hollow, bottom, start cut, end cut + // I know it's ugly but so is the whole concept of prim face numbers + + int faceNum = 1; // start with outer faces + int startVert = hasProfileCut && !hasHollow ? 1 : 0; + if (startVert > 0) + this.faceNumbers.Add(-1); + for (int i = 0; i < this.numOuterVerts - 1; i++) + this.faceNumbers.Add(sides < 5 ? faceNum++ : faceNum); + + //if (!hasHollow && !hasProfileCut) + // this.bottomFaceNumber = faceNum++; + + this.faceNumbers.Add(hasProfileCut ? -1 : faceNum++); + + if (sides > 4 && (hasHollow || hasProfileCut)) + faceNum++; + + if (hasHollow) + { + for (int i = 0; i < this.numHollowVerts; i++) + this.faceNumbers.Add(faceNum); + + faceNum++; + } + //if (hasProfileCut || hasHollow) + // this.bottomFaceNumber = faceNum++; + this.bottomFaceNumber = faceNum++; + + if (hasHollow && hasProfileCut) + this.faceNumbers.Add(faceNum++); + for (int i = 0; i < this.faceNumbers.Count; i++) + if (this.faceNumbers[i] == -1) + this.faceNumbers[i] = faceNum++; + + + this.numPrimFaces = faceNum; + } + + } + + internal void MakeFaceUVs() + { + this.faceUVs = new List(); + foreach (Coord c in this.coords) + this.faceUVs.Add(new UVCoord(1.0f - (0.5f + c.X), 1.0f - (0.5f - c.Y))); + } + + internal Profile Copy() + { + return this.Copy(true); + } + + internal Profile Copy(bool needFaces) + { + Profile copy = new Profile(); + + copy.coords.AddRange(this.coords); + copy.faceUVs.AddRange(this.faceUVs); + + if (needFaces) + copy.faces.AddRange(this.faces); + if ((copy.calcVertexNormals = this.calcVertexNormals) == true) + { + copy.vertexNormals.AddRange(this.vertexNormals); + copy.faceNormal = this.faceNormal; + copy.cutNormal1 = this.cutNormal1; + copy.cutNormal2 = this.cutNormal2; + copy.us.AddRange(this.us); + copy.faceNumbers.AddRange(this.faceNumbers); + + copy.cut1CoordIndices = new List(this.cut1CoordIndices); + copy.cut2CoordIndices = new List(this.cut2CoordIndices); + copy.hollowCoordIndices = new List(this.hollowCoordIndices); + copy.outerCoordIndices = new List(this.outerCoordIndices); + } + copy.numOuterVerts = this.numOuterVerts; + copy.numHollowVerts = this.numHollowVerts; + + return copy; + } + + internal void AddPos(Coord v) + { + this.AddPos(v.X, v.Y, v.Z); + } + + internal void AddPos(float x, float y, float z) + { + int i; + int numVerts = this.coords.Count; + Coord vert; + + for (i = 0; i < numVerts; i++) + { + vert = this.coords[i]; + vert.X += x; + vert.Y += y; + vert.Z += z; + this.coords[i] = vert; + } + } + + internal void AddRot(Quat q) + { + int i; + int numVerts = this.coords.Count; + + for (i = 0; i < numVerts; i++) + this.coords[i] *= q; + + if (this.calcVertexNormals) + { + int numNormals = this.vertexNormals.Count; + for (i = 0; i < numNormals; i++) + this.vertexNormals[i] *= q; + + this.faceNormal *= q; + this.cutNormal1 *= q; + this.cutNormal2 *= q; + + } + } + + internal void Scale(float x, float y) + { + int i; + int numVerts = this.coords.Count; + Coord vert; + + for (i = 0; i < numVerts; i++) + { + vert = this.coords[i]; + vert.X *= x; + vert.Y *= y; + this.coords[i] = vert; + } + } + + /// + /// Changes order of the vertex indices and negates the center vertex normal. Does not alter vertex normals of radial vertices + /// + internal void FlipNormals() + { + int i; + int numFaces = this.faces.Count; + Face tmpFace; + int tmp; + + for (i = 0; i < numFaces; i++) + { + tmpFace = this.faces[i]; + tmp = tmpFace.v3; + tmpFace.v3 = tmpFace.v1; + tmpFace.v1 = tmp; + this.faces[i] = tmpFace; + } + + if (this.calcVertexNormals) + { + int normalCount = this.vertexNormals.Count; + if (normalCount > 0) + { + Coord n = this.vertexNormals[normalCount - 1]; + n.Z = -n.Z; + this.vertexNormals[normalCount - 1] = n; + } + } + + this.faceNormal.X = -this.faceNormal.X; + this.faceNormal.Y = -this.faceNormal.Y; + this.faceNormal.Z = -this.faceNormal.Z; + + int numfaceUVs = this.faceUVs.Count; + for (i = 0; i < numfaceUVs; i++) + { + UVCoord uv = this.faceUVs[i]; + uv.V = 1.0f - uv.V; + this.faceUVs[i] = uv; + } + } + + internal void AddValue2FaceVertexIndices(int num) + { + int numFaces = this.faces.Count; + Face tmpFace; + for (int i = 0; i < numFaces; i++) + { + tmpFace = this.faces[i]; + tmpFace.v1 += num; + tmpFace.v2 += num; + tmpFace.v3 += num; + + this.faces[i] = tmpFace; + } + } + + internal void AddValue2FaceNormalIndices(int num) + { + if (this.calcVertexNormals) + { + int numFaces = this.faces.Count; + Face tmpFace; + for (int i = 0; i < numFaces; i++) + { + tmpFace = this.faces[i]; + tmpFace.n1 += num; + tmpFace.n2 += num; + tmpFace.n3 += num; + + this.faces[i] = tmpFace; + } + } + } + + internal void DumpRaw(String path, String name, String title) + { + if (path == null) + return; + String fileName = name + "_" + title + ".raw"; + String completePath = System.IO.Path.Combine(path, fileName); + StreamWriter sw = new StreamWriter(completePath); + + for (int i = 0; i < this.faces.Count; i++) + { + string s = this.coords[this.faces[i].v1].ToString(); + s += " " + this.coords[this.faces[i].v2].ToString(); + s += " " + this.coords[this.faces[i].v3].ToString(); + + sw.WriteLine(s); + } + + sw.Close(); + } + } + + public struct PathNode + { + public Coord position; + public Quat rotation; + public float xScale; + public float yScale; + public float percentOfPath; + } + + public enum PathType { Linear = 0, Circular = 1, Flexible = 2 } + + public class Path + { + public List pathNodes = new List(); + + public float twistBegin = 0.0f; + public float twistEnd = 0.0f; + public float topShearX = 0.0f; + public float topShearY = 0.0f; + public float pathCutBegin = 0.0f; + public float pathCutEnd = 1.0f; + public float dimpleBegin = 0.0f; + public float dimpleEnd = 1.0f; + public float skew = 0.0f; + public float holeSizeX = 1.0f; // called pathScaleX in pbs + public float holeSizeY = 0.25f; + public float taperX = 0.0f; + public float taperY = 0.0f; + public float radius = 0.0f; + public float revolutions = 1.0f; + public int stepsPerRevolution = 24; + + private const float twoPi = 2.0f * (float)Math.PI; + + public void Create(PathType pathType, int steps) + { + if (pathType == PathType.Linear || pathType == PathType.Flexible) + { + int step = 0; + + float length = this.pathCutEnd - this.pathCutBegin; + float twistTotal = twistEnd - twistBegin; + float twistTotalAbs = Math.Abs(twistTotal); + if (twistTotalAbs > 0.01f) + steps += (int)(twistTotalAbs * 3.66); // dahlia's magic number + + float start = -0.5f; + float stepSize = length / (float)steps; + float percentOfPathMultiplier = stepSize; + float xOffset = 0.0f; + float yOffset = 0.0f; + float zOffset = start; + float xOffsetStepIncrement = this.topShearX / steps; + float yOffsetStepIncrement = this.topShearY / steps; + + float percentOfPath = this.pathCutBegin; + zOffset += percentOfPath; + + // sanity checks + + bool done = false; + + while (!done) + { + PathNode newNode = new PathNode(); + + newNode.xScale = 1.0f; + if (this.taperX == 0.0f) + newNode.xScale = 1.0f; + else if (this.taperX > 0.0f) + newNode.xScale = 1.0f - percentOfPath * this.taperX; + else newNode.xScale = 1.0f + (1.0f - percentOfPath) * this.taperX; + + newNode.yScale = 1.0f; + if (this.taperY == 0.0f) + newNode.yScale = 1.0f; + else if (this.taperY > 0.0f) + newNode.yScale = 1.0f - percentOfPath * this.taperY; + else newNode.yScale = 1.0f + (1.0f - percentOfPath) * this.taperY; + + float twist = twistBegin + twistTotal * percentOfPath; + + newNode.rotation = new Quat(new Coord(0.0f, 0.0f, 1.0f), twist); + newNode.position = new Coord(xOffset, yOffset, zOffset); + newNode.percentOfPath = percentOfPath; + + pathNodes.Add(newNode); + + if (step < steps) + { + step += 1; + percentOfPath += percentOfPathMultiplier; + xOffset += xOffsetStepIncrement; + yOffset += yOffsetStepIncrement; + zOffset += stepSize; + if (percentOfPath > this.pathCutEnd) + done = true; + } + else done = true; + } + } // end of linear path code + + else // pathType == Circular + { + float twistTotal = twistEnd - twistBegin; + + // if the profile has a lot of twist, add more layers otherwise the layers may overlap + // and the resulting mesh may be quite inaccurate. This method is arbitrary and doesn't + // accurately match the viewer + float twistTotalAbs = Math.Abs(twistTotal); + if (twistTotalAbs > 0.01f) + { + if (twistTotalAbs > Math.PI * 1.5f) + steps *= 2; + if (twistTotalAbs > Math.PI * 3.0f) + steps *= 2; + } + + float yPathScale = this.holeSizeY * 0.5f; + float pathLength = this.pathCutEnd - this.pathCutBegin; + float totalSkew = this.skew * 2.0f * pathLength; + float skewStart = this.pathCutBegin * 2.0f * this.skew - this.skew; + float xOffsetTopShearXFactor = this.topShearX * (0.25f + 0.5f * (0.5f - this.holeSizeY)); + float yShearCompensation = 1.0f + Math.Abs(this.topShearY) * 0.25f; + + // It's not quite clear what pushY (Y top shear) does, but subtracting it from the start and end + // angles appears to approximate it's effects on path cut. Likewise, adding it to the angle used + // to calculate the sine for generating the path radius appears to approximate it's effects there + // too, but there are some subtle differences in the radius which are noticeable as the prim size + // increases and it may affect megaprims quite a bit. The effect of the Y top shear parameter on + // the meshes generated with this technique appear nearly identical in shape to the same prims when + // displayed by the viewer. + + float startAngle = (twoPi * this.pathCutBegin * this.revolutions) - this.topShearY * 0.9f; + float endAngle = (twoPi * this.pathCutEnd * this.revolutions) - this.topShearY * 0.9f; + float stepSize = twoPi / this.stepsPerRevolution; + + int step = (int)(startAngle / stepSize); + float angle = startAngle; + + bool done = false; + while (!done) // loop through the length of the path and add the layers + { + PathNode newNode = new PathNode(); + + float xProfileScale = (1.0f - Math.Abs(this.skew)) * this.holeSizeX; + float yProfileScale = this.holeSizeY; + + float percentOfPath = angle / (twoPi * this.revolutions); + float percentOfAngles = (angle - startAngle) / (endAngle - startAngle); + + if (this.taperX > 0.01f) + xProfileScale *= 1.0f - percentOfPath * this.taperX; + else if (this.taperX < -0.01f) + xProfileScale *= 1.0f + (1.0f - percentOfPath) * this.taperX; + + if (this.taperY > 0.01f) + yProfileScale *= 1.0f - percentOfPath * this.taperY; + else if (this.taperY < -0.01f) + yProfileScale *= 1.0f + (1.0f - percentOfPath) * this.taperY; + + newNode.xScale = xProfileScale; + newNode.yScale = yProfileScale; + + float radiusScale = 1.0f; + if (this.radius > 0.001f) + radiusScale = 1.0f - this.radius * percentOfPath; + else if (this.radius < 0.001f) + radiusScale = 1.0f + this.radius * (1.0f - percentOfPath); + + float twist = twistBegin + twistTotal * percentOfPath; + + float xOffset = 0.5f * (skewStart + totalSkew * percentOfAngles); + xOffset += (float)Math.Sin(angle) * xOffsetTopShearXFactor; + + float yOffset = yShearCompensation * (float)Math.Cos(angle) * (0.5f - yPathScale) * radiusScale; + + float zOffset = (float)Math.Sin(angle + this.topShearY) * (0.5f - yPathScale) * radiusScale; + + newNode.position = new Coord(xOffset, yOffset, zOffset); + + // now orient the rotation of the profile layer relative to it's position on the path + // adding taperY to the angle used to generate the quat appears to approximate the viewer + + newNode.rotation = new Quat(new Coord(1.0f, 0.0f, 0.0f), angle + this.topShearY); + + // next apply twist rotation to the profile layer + if (twistTotal != 0.0f || twistBegin != 0.0f) + newNode.rotation *= new Quat(new Coord(0.0f, 0.0f, 1.0f), twist); + + newNode.percentOfPath = percentOfPath; + + pathNodes.Add(newNode); + + // calculate terms for next iteration + // calculate the angle for the next iteration of the loop + + if (angle >= endAngle - 0.01) + done = true; + else + { + step += 1; + angle = stepSize * step; + if (angle > endAngle) + angle = endAngle; + } + } + } + } + } + + public class PrimMesh + { + public string errorMessage = ""; + private const float twoPi = 2.0f * (float)Math.PI; + + public List coords; + public List normals; + public List faces; + + public List viewerFaces; + + private int sides = 4; + private int hollowSides = 4; + private float profileStart = 0.0f; + private float profileEnd = 1.0f; + private float hollow = 0.0f; + public int twistBegin = 0; + public int twistEnd = 0; + public float topShearX = 0.0f; + public float topShearY = 0.0f; + public float pathCutBegin = 0.0f; + public float pathCutEnd = 1.0f; + public float dimpleBegin = 0.0f; + public float dimpleEnd = 1.0f; + public float skew = 0.0f; + public float holeSizeX = 1.0f; // called pathScaleX in pbs + public float holeSizeY = 0.25f; + public float taperX = 0.0f; + public float taperY = 0.0f; + public float radius = 0.0f; + public float revolutions = 1.0f; + public int stepsPerRevolution = 24; + + private bool hasProfileCut = false; + private bool hasHollow = false; + public bool calcVertexNormals = false; + private bool normalsProcessed = false; + public bool viewerMode = false; + + public int numPrimFaces = 0; + + /// + /// Human readable string representation of the parameters used to create a mesh. + /// + /// + public string ParamsToDisplayString() + { + string s = ""; + s += "sides..................: " + this.sides.ToString(); + s += "\nhollowSides..........: " + this.hollowSides.ToString(); + s += "\nprofileStart.........: " + this.profileStart.ToString(); + s += "\nprofileEnd...........: " + this.profileEnd.ToString(); + s += "\nhollow...............: " + this.hollow.ToString(); + s += "\ntwistBegin...........: " + this.twistBegin.ToString(); + s += "\ntwistEnd.............: " + this.twistEnd.ToString(); + s += "\ntopShearX............: " + this.topShearX.ToString(); + s += "\ntopShearY............: " + this.topShearY.ToString(); + s += "\npathCutBegin.........: " + this.pathCutBegin.ToString(); + s += "\npathCutEnd...........: " + this.pathCutEnd.ToString(); + s += "\ndimpleBegin..........: " + this.dimpleBegin.ToString(); + s += "\ndimpleEnd............: " + this.dimpleEnd.ToString(); + s += "\nskew.................: " + this.skew.ToString(); + s += "\nholeSizeX............: " + this.holeSizeX.ToString(); + s += "\nholeSizeY............: " + this.holeSizeY.ToString(); + s += "\ntaperX...............: " + this.taperX.ToString(); + s += "\ntaperY...............: " + this.taperY.ToString(); + s += "\nradius...............: " + this.radius.ToString(); + s += "\nrevolutions..........: " + this.revolutions.ToString(); + s += "\nstepsPerRevolution...: " + this.stepsPerRevolution.ToString(); + + return s; + } + + /// + /// Constructs a PrimMesh object and creates the profile for extrusion. + /// + /// + /// + /// + /// + /// + public PrimMesh(int sides, float profileStart, float profileEnd, float hollow, int hollowSides) + { + this.coords = new List(); + this.faces = new List(); + + this.sides = sides; + this.profileStart = profileStart; + this.profileEnd = profileEnd; + this.hollow = hollow; + this.hollowSides = hollowSides; + + if (sides < 3) + this.sides = 3; + if (hollowSides < 3) + this.hollowSides = 3; + if (profileStart < 0.0f) + this.profileStart = 0.0f; + if (profileEnd > 1.0f) + this.profileEnd = 1.0f; + if (profileEnd < 0.02f) + this.profileEnd = 0.02f; + if (profileStart >= profileEnd) + this.profileStart = profileEnd - 0.02f; + if (hollow > 0.99f) + this.hollow = 0.99f; + if (hollow < 0.0f) + this.hollow = 0.0f; + + this.hasProfileCut = (this.profileStart > 0.0f || this.profileEnd < 1.0f); + this.hasHollow = (this.hollow > 0.001f); + } + + /// + /// Extrudes a profile along a path. + /// + public void Extrude(PathType pathType) + { + this.coords = new List(); + this.faces = new List(); + + if (this.viewerMode) + { + this.viewerFaces = new List(); + this.calcVertexNormals = true; + } + + if (this.calcVertexNormals) + this.normals = new List(); + + int steps = 1; + + float length = this.pathCutEnd - this.pathCutBegin; + normalsProcessed = false; + + if (this.viewerMode && this.sides == 3) + { + // prisms don't taper well so add some vertical resolution + // other prims may benefit from this but just do prisms for now + if (Math.Abs(this.taperX) > 0.01 || Math.Abs(this.taperY) > 0.01) + steps = (int)(steps * 4.5 * length); + } + + + float twistBegin = this.twistBegin / 360.0f * twoPi; + float twistEnd = this.twistEnd / 360.0f * twoPi; + float twistTotal = twistEnd - twistBegin; + float twistTotalAbs = Math.Abs(twistTotal); + if (twistTotalAbs > 0.01f) + steps += (int)(twistTotalAbs * 3.66); // dahlia's magic number + + float hollow = this.hollow; + + // sanity checks + float initialProfileRot = 0.0f; + if (pathType == PathType.Circular) + { + if (this.sides == 3) + { + initialProfileRot = (float)Math.PI; + if (this.hollowSides == 4) + { + if (hollow > 0.7f) + hollow = 0.7f; + hollow *= 0.707f; + } + else hollow *= 0.5f; + } + else if (this.sides == 4) + { + initialProfileRot = 0.25f * (float)Math.PI; + if (this.hollowSides != 4) + hollow *= 0.707f; + } + else if (this.sides > 4) + { + initialProfileRot = (float)Math.PI; + if (this.hollowSides == 4) + { + if (hollow > 0.7f) + hollow = 0.7f; + hollow /= 0.7f; + } + } + } + else + { + if (this.sides == 3) + { + if (this.hollowSides == 4) + { + if (hollow > 0.7f) + hollow = 0.7f; + hollow *= 0.707f; + } + else hollow *= 0.5f; + } + else if (this.sides == 4) + { + initialProfileRot = 1.25f * (float)Math.PI; + if (this.hollowSides != 4) + hollow *= 0.707f; + } + else if (this.sides == 24 && this.hollowSides == 4) + hollow *= 1.414f; + } + + Profile profile = new Profile(this.sides, this.profileStart, this.profileEnd, hollow, this.hollowSides, true, calcVertexNormals); + this.errorMessage = profile.errorMessage; + + this.numPrimFaces = profile.numPrimFaces; + + int cut1Vert = -1; + int cut2Vert = -1; + if (hasProfileCut) + { + cut1Vert = hasHollow ? profile.coords.Count - 1 : 0; + cut2Vert = hasHollow ? profile.numOuterVerts - 1 : profile.numOuterVerts; + } + + if (initialProfileRot != 0.0f) + { + profile.AddRot(new Quat(new Coord(0.0f, 0.0f, 1.0f), initialProfileRot)); + if (viewerMode) + profile.MakeFaceUVs(); + } + + Coord lastCutNormal1 = new Coord(); + Coord lastCutNormal2 = new Coord(); + float lastV = 1.0f; + + Path path = new Path(); + path.twistBegin = twistBegin; + path.twistEnd = twistEnd; + path.topShearX = topShearX; + path.topShearY = topShearY; + path.pathCutBegin = pathCutBegin; + path.pathCutEnd = pathCutEnd; + path.dimpleBegin = dimpleBegin; + path.dimpleEnd = dimpleEnd; + path.skew = skew; + path.holeSizeX = holeSizeX; + path.holeSizeY = holeSizeY; + path.taperX = taperX; + path.taperY = taperY; + path.radius = radius; + path.revolutions = revolutions; + path.stepsPerRevolution = stepsPerRevolution; + + path.Create(pathType, steps); + + bool needEndFaces = false; + if (pathType == PathType.Circular) + { + needEndFaces = false; + if (this.pathCutBegin != 0.0f || this.pathCutEnd != 1.0f) + needEndFaces = true; + else if (this.taperX != 0.0f || this.taperY != 0.0f) + needEndFaces = true; + else if (this.skew != 0.0f) + needEndFaces = true; + else if (twistTotal != 0.0f) + needEndFaces = true; + else if (this.radius != 0.0f) + needEndFaces = true; + } + else needEndFaces = true; + + for (int nodeIndex = 0; nodeIndex < path.pathNodes.Count; nodeIndex++) + { + PathNode node = path.pathNodes[nodeIndex]; + Profile newLayer = profile.Copy(); + newLayer.Scale(node.xScale, node.yScale); + + newLayer.AddRot(node.rotation); + newLayer.AddPos(node.position); + + if (needEndFaces && nodeIndex == 0) + { + newLayer.FlipNormals(); + + // add the top faces to the viewerFaces list here + if (this.viewerMode) + { + Coord faceNormal = newLayer.faceNormal; + ViewerFace newViewerFace = new ViewerFace(profile.bottomFaceNumber); + int numFaces = newLayer.faces.Count; + List faces = newLayer.faces; + + for (int i = 0; i < numFaces; i++) + { + Face face = faces[i]; + newViewerFace.v1 = newLayer.coords[face.v1]; + newViewerFace.v2 = newLayer.coords[face.v2]; + newViewerFace.v3 = newLayer.coords[face.v3]; + + newViewerFace.coordIndex1 = face.v1; + newViewerFace.coordIndex2 = face.v2; + newViewerFace.coordIndex3 = face.v3; + + newViewerFace.n1 = faceNormal; + newViewerFace.n2 = faceNormal; + newViewerFace.n3 = faceNormal; + + newViewerFace.uv1 = newLayer.faceUVs[face.v1]; + newViewerFace.uv2 = newLayer.faceUVs[face.v2]; + newViewerFace.uv3 = newLayer.faceUVs[face.v3]; + + this.viewerFaces.Add(newViewerFace); + } + } + } // if (nodeIndex == 0) + + // append this layer + + int coordsLen = this.coords.Count; + newLayer.AddValue2FaceVertexIndices(coordsLen); + + this.coords.AddRange(newLayer.coords); + + if (this.calcVertexNormals) + { + newLayer.AddValue2FaceNormalIndices(this.normals.Count); + this.normals.AddRange(newLayer.vertexNormals); + } + + if (node.percentOfPath < this.pathCutBegin + 0.01f || node.percentOfPath > this.pathCutEnd - 0.01f) + this.faces.AddRange(newLayer.faces); + + // fill faces between layers + + int numVerts = newLayer.coords.Count; + Face newFace = new Face(); + + if (nodeIndex > 0) + { + int startVert = coordsLen + 1; + int endVert = this.coords.Count; + + if (sides < 5 || this.hasProfileCut || hollow > 0.0f) + startVert--; + + for (int i = startVert; i < endVert; i++) + { + int iNext = i + 1; + if (i == endVert - 1) + iNext = startVert; + + int whichVert = i - startVert; + + newFace.v1 = i; + newFace.v2 = i - numVerts; + newFace.v3 = iNext - numVerts; + this.faces.Add(newFace); + + newFace.v2 = iNext - numVerts; + newFace.v3 = iNext; + this.faces.Add(newFace); + + if (this.viewerMode) + { + // add the side faces to the list of viewerFaces here + + int primFaceNum = profile.faceNumbers[whichVert]; + if (!needEndFaces) + primFaceNum -= 1; + + ViewerFace newViewerFace1 = new ViewerFace(primFaceNum); + ViewerFace newViewerFace2 = new ViewerFace(primFaceNum); + + float u1 = newLayer.us[whichVert]; + float u2 = 1.0f; + if (whichVert < newLayer.us.Count - 1) + u2 = newLayer.us[whichVert + 1]; + + if (whichVert == cut1Vert || whichVert == cut2Vert) + { + u1 = 0.0f; + u2 = 1.0f; + } + else if (sides < 5) + { + if (whichVert < profile.numOuterVerts) + { // boxes and prisms have one texture face per side of the prim, so the U values have to be scaled + // to reflect the entire texture width + u1 *= sides; + u2 *= sides; + u2 -= (int)u1; + u1 -= (int)u1; + if (u2 < 0.1f) + u2 = 1.0f; + } + else if (whichVert > profile.coords.Count - profile.numHollowVerts - 1) + { + u1 *= 2.0f; + u2 *= 2.0f; + } + } + + newViewerFace1.uv1.U = u1; + newViewerFace1.uv2.U = u1; + newViewerFace1.uv3.U = u2; + + newViewerFace1.uv1.V = 1.0f - node.percentOfPath; + newViewerFace1.uv2.V = lastV; + newViewerFace1.uv3.V = lastV; + + newViewerFace2.uv1.U = u1; + newViewerFace2.uv2.U = u2; + newViewerFace2.uv3.U = u2; + + newViewerFace2.uv1.V = 1.0f - node.percentOfPath; + newViewerFace2.uv2.V = lastV; + newViewerFace2.uv3.V = 1.0f - node.percentOfPath; + + newViewerFace1.v1 = this.coords[i]; + newViewerFace1.v2 = this.coords[i - numVerts]; + newViewerFace1.v3 = this.coords[iNext - numVerts]; + + newViewerFace2.v1 = this.coords[i]; + newViewerFace2.v2 = this.coords[iNext - numVerts]; + newViewerFace2.v3 = this.coords[iNext]; + + newViewerFace1.coordIndex1 = i; + newViewerFace1.coordIndex2 = i - numVerts; + newViewerFace1.coordIndex3 = iNext - numVerts; + + newViewerFace2.coordIndex1 = i; + newViewerFace2.coordIndex2 = iNext - numVerts; + newViewerFace2.coordIndex3 = iNext; + + // profile cut faces + if (whichVert == cut1Vert) + { + newViewerFace1.n1 = newLayer.cutNormal1; + newViewerFace1.n2 = newViewerFace1.n3 = lastCutNormal1; + + newViewerFace2.n1 = newViewerFace2.n3 = newLayer.cutNormal1; + newViewerFace2.n2 = lastCutNormal1; + } + else if (whichVert == cut2Vert) + { + newViewerFace1.n1 = newLayer.cutNormal2; + newViewerFace1.n2 = newViewerFace1.n3 = lastCutNormal2; + + newViewerFace2.n1 = newViewerFace2.n3 = newLayer.cutNormal2; + newViewerFace2.n2 = lastCutNormal2; + } + + else // outer and hollow faces + { + if ((sides < 5 && whichVert < newLayer.numOuterVerts) || (hollowSides < 5 && whichVert >= newLayer.numOuterVerts)) + { // looks terrible when path is twisted... need vertex normals here + newViewerFace1.CalcSurfaceNormal(); + newViewerFace2.CalcSurfaceNormal(); + } + else + { + newViewerFace1.n1 = this.normals[i]; + newViewerFace1.n2 = this.normals[i - numVerts]; + newViewerFace1.n3 = this.normals[iNext - numVerts]; + + newViewerFace2.n1 = this.normals[i]; + newViewerFace2.n2 = this.normals[iNext - numVerts]; + newViewerFace2.n3 = this.normals[iNext]; + } + } + + this.viewerFaces.Add(newViewerFace1); + this.viewerFaces.Add(newViewerFace2); + + } + } + } + + lastCutNormal1 = newLayer.cutNormal1; + lastCutNormal2 = newLayer.cutNormal2; + lastV = 1.0f - node.percentOfPath; + + if (needEndFaces && nodeIndex == path.pathNodes.Count - 1 && viewerMode) + { + // add the top faces to the viewerFaces list here + Coord faceNormal = newLayer.faceNormal; + ViewerFace newViewerFace = new ViewerFace(); + newViewerFace.primFaceNumber = 0; + int numFaces = newLayer.faces.Count; + List faces = newLayer.faces; + + for (int i = 0; i < numFaces; i++) + { + Face face = faces[i]; + newViewerFace.v1 = newLayer.coords[face.v1 - coordsLen]; + newViewerFace.v2 = newLayer.coords[face.v2 - coordsLen]; + newViewerFace.v3 = newLayer.coords[face.v3 - coordsLen]; + + newViewerFace.coordIndex1 = face.v1 - coordsLen; + newViewerFace.coordIndex2 = face.v2 - coordsLen; + newViewerFace.coordIndex3 = face.v3 - coordsLen; + + newViewerFace.n1 = faceNormal; + newViewerFace.n2 = faceNormal; + newViewerFace.n3 = faceNormal; + + newViewerFace.uv1 = newLayer.faceUVs[face.v1 - coordsLen]; + newViewerFace.uv2 = newLayer.faceUVs[face.v2 - coordsLen]; + newViewerFace.uv3 = newLayer.faceUVs[face.v3 - coordsLen]; + + this.viewerFaces.Add(newViewerFace); + } + } + + + } // for (int nodeIndex = 0; nodeIndex < path.pathNodes.Count; nodeIndex++) + + } + + + /// + /// DEPRICATED - use Extrude(PathType.Linear) instead + /// Extrudes a profile along a straight line path. Used for prim types box, cylinder, and prism. + /// + /// + public void ExtrudeLinear() + { + this.Extrude(PathType.Linear); + } + + + /// + /// DEPRICATED - use Extrude(PathType.Circular) instead + /// Extrude a profile into a circular path prim mesh. Used for prim types torus, tube, and ring. + /// + /// + public void ExtrudeCircular() + { + this.Extrude(PathType.Circular); + } + + + private Coord SurfaceNormal(Coord c1, Coord c2, Coord c3) + { + Coord edge1 = new Coord(c2.X - c1.X, c2.Y - c1.Y, c2.Z - c1.Z); + Coord edge2 = new Coord(c3.X - c1.X, c3.Y - c1.Y, c3.Z - c1.Z); + + Coord normal = Coord.Cross(edge1, edge2); + + normal.Normalize(); + + return normal; + } + + private Coord SurfaceNormal(Face face) + { + return SurfaceNormal(this.coords[face.v1], this.coords[face.v2], this.coords[face.v3]); + } + + /// + /// Calculate the surface normal for a face in the list of faces + /// + /// + /// + public Coord SurfaceNormal(int faceIndex) + { + int numFaces = this.faces.Count; + if (faceIndex < 0 || faceIndex >= numFaces) + throw new Exception("faceIndex out of range"); + + return SurfaceNormal(this.faces[faceIndex]); + } + + /// + /// Duplicates a PrimMesh object. All object properties are copied by value, including lists. + /// + /// + public PrimMesh Copy() + { + PrimMesh copy = new PrimMesh(this.sides, this.profileStart, this.profileEnd, this.hollow, this.hollowSides); + copy.twistBegin = this.twistBegin; + copy.twistEnd = this.twistEnd; + copy.topShearX = this.topShearX; + copy.topShearY = this.topShearY; + copy.pathCutBegin = this.pathCutBegin; + copy.pathCutEnd = this.pathCutEnd; + copy.dimpleBegin = this.dimpleBegin; + copy.dimpleEnd = this.dimpleEnd; + copy.skew = this.skew; + copy.holeSizeX = this.holeSizeX; + copy.holeSizeY = this.holeSizeY; + copy.taperX = this.taperX; + copy.taperY = this.taperY; + copy.radius = this.radius; + copy.revolutions = this.revolutions; + copy.stepsPerRevolution = this.stepsPerRevolution; + copy.calcVertexNormals = this.calcVertexNormals; + copy.normalsProcessed = this.normalsProcessed; + copy.viewerMode = this.viewerMode; + copy.numPrimFaces = this.numPrimFaces; + copy.errorMessage = this.errorMessage; + + copy.coords = new List(this.coords); + copy.faces = new List(this.faces); + copy.viewerFaces = new List(this.viewerFaces); + copy.normals = new List(this.normals); + + return copy; + } + + /// + /// Calculate surface normals for all of the faces in the list of faces in this mesh + /// + public void CalcNormals() + { + if (normalsProcessed) + return; + + normalsProcessed = true; + + int numFaces = faces.Count; + + if (!this.calcVertexNormals) + this.normals = new List(); + + for (int i = 0; i < numFaces; i++) + { + Face face = faces[i]; + + this.normals.Add(SurfaceNormal(i).Normalize()); + + int normIndex = normals.Count - 1; + face.n1 = normIndex; + face.n2 = normIndex; + face.n3 = normIndex; + + this.faces[i] = face; + } + } + + /// + /// Adds a value to each XYZ vertex coordinate in the mesh + /// + /// + /// + /// + public void AddPos(float x, float y, float z) + { + int i; + int numVerts = this.coords.Count; + Coord vert; + + for (i = 0; i < numVerts; i++) + { + vert = this.coords[i]; + vert.X += x; + vert.Y += y; + vert.Z += z; + this.coords[i] = vert; + } + + if (this.viewerFaces != null) + { + int numViewerFaces = this.viewerFaces.Count; + + for (i = 0; i < numViewerFaces; i++) + { + ViewerFace v = this.viewerFaces[i]; + v.AddPos(x, y, z); + this.viewerFaces[i] = v; + } + } + } + + /// + /// Rotates the mesh + /// + /// + public void AddRot(Quat q) + { + int i; + int numVerts = this.coords.Count; + + for (i = 0; i < numVerts; i++) + this.coords[i] *= q; + + if (this.normals != null) + { + int numNormals = this.normals.Count; + for (i = 0; i < numNormals; i++) + this.normals[i] *= q; + } + + if (this.viewerFaces != null) + { + int numViewerFaces = this.viewerFaces.Count; + + for (i = 0; i < numViewerFaces; i++) + { + ViewerFace v = this.viewerFaces[i]; + v.v1 *= q; + v.v2 *= q; + v.v3 *= q; + + v.n1 *= q; + v.n2 *= q; + v.n3 *= q; + this.viewerFaces[i] = v; + } + } + } + +#if VERTEX_INDEXER + public VertexIndexer GetVertexIndexer() + { + if (this.viewerMode && this.viewerFaces.Count > 0) + return new VertexIndexer(this); + return null; + } +#endif + + /// + /// Scales the mesh + /// + /// + /// + /// + public void Scale(float x, float y, float z) + { + int i; + int numVerts = this.coords.Count; + //Coord vert; + + Coord m = new Coord(x, y, z); + for (i = 0; i < numVerts; i++) + this.coords[i] *= m; + + if (this.viewerFaces != null) + { + int numViewerFaces = this.viewerFaces.Count; + for (i = 0; i < numViewerFaces; i++) + { + ViewerFace v = this.viewerFaces[i]; + v.v1 *= m; + v.v2 *= m; + v.v3 *= m; + this.viewerFaces[i] = v; + } + + } + + } + + /// + /// Dumps the mesh to a Blender compatible "Raw" format file + /// + /// + /// + /// + public void DumpRaw(String path, String name, String title) + { + if (path == null) + return; + String fileName = name + "_" + title + ".raw"; + String completePath = System.IO.Path.Combine(path, fileName); + StreamWriter sw = new StreamWriter(completePath); + + for (int i = 0; i < this.faces.Count; i++) + { + string s = this.coords[this.faces[i].v1].ToString(); + s += " " + this.coords[this.faces[i].v2].ToString(); + s += " " + this.coords[this.faces[i].v3].ToString(); + + sw.WriteLine(s); + } + + sw.Close(); + } + } +} From 2ebc4be99d20269dd3cc261022f5f760b54fde6c Mon Sep 17 00:00:00 2001 From: dahlia Date: Sat, 13 Mar 2010 12:04:49 -0800 Subject: [PATCH 27/28] add a null check in ScenePresence constructor --- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 317c9088ef..6f16ff347c 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -676,7 +676,8 @@ namespace OpenSim.Region.Framework.Scenes UserAccount account = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, m_uuid); - m_userLevel = account.UserLevel; + if (account != null) + m_userLevel = account.UserLevel; IGroupsModule gm = m_scene.RequestModuleInterface(); if (gm != null) From 1e73e16fd0743ae193c59d7ba353158d30874784 Mon Sep 17 00:00:00 2001 From: dahlia Date: Sat, 13 Mar 2010 18:41:36 -0800 Subject: [PATCH 28/28] flip UVs for profile faces --- OpenSim/Region/Physics/Meshing/PrimMesher.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/Physics/Meshing/PrimMesher.cs b/OpenSim/Region/Physics/Meshing/PrimMesher.cs index b75e2712f0..6e9654bb38 100644 --- a/OpenSim/Region/Physics/Meshing/PrimMesher.cs +++ b/OpenSim/Region/Physics/Meshing/PrimMesher.cs @@ -1020,7 +1020,7 @@ namespace PrimMesher { this.faceUVs = new List(); foreach (Coord c in this.coords) - this.faceUVs.Add(new UVCoord(1.0f - (0.5f + c.X), 1.0f - (0.5f - c.Y))); + this.faceUVs.Add(new UVCoord(0.5f + c.X, 0.5f - c.Y)); } internal Profile Copy()