diff --git a/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs b/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs index 7e0b112ed2..cff7adf53c 100644 --- a/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs +++ b/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs @@ -684,6 +684,9 @@ namespace OpenSim.Groups { serviceLocation = string.Empty; name = string.Empty; + if (groupID.Equals(UUID.Zero)) + return true; + ExtendedGroupRecord group = m_LocalGroupsConnector.GetGroupRecord(UUID.Zero.ToString(), groupID, string.Empty); if (group == null) { diff --git a/OpenSim/Addons/Groups/RemoteConnectorCacheWrapper.cs b/OpenSim/Addons/Groups/RemoteConnectorCacheWrapper.cs index e7d38c2020..79d6fc58eb 100644 --- a/OpenSim/Addons/Groups/RemoteConnectorCacheWrapper.cs +++ b/OpenSim/Addons/Groups/RemoteConnectorCacheWrapper.cs @@ -209,13 +209,10 @@ namespace OpenSim.Groups public void SetAgentActiveGroup(string AgentID, GroupMembershipDelegate d) { GroupMembershipData activeGroup = d(); - if (activeGroup != null) - { - string cacheKey = "active-" + AgentID.ToString(); - lock (m_Cache) - if (m_Cache.Contains(cacheKey)) - m_Cache.AddOrUpdate(cacheKey, activeGroup, GROUPS_CACHE_TIMEOUT); - } + string cacheKey = "active-" + AgentID.ToString(); + lock (m_Cache) + if (m_Cache.Contains(cacheKey)) + m_Cache.AddOrUpdate(cacheKey, activeGroup, GROUPS_CACHE_TIMEOUT); } public ExtendedGroupMembershipData GetAgentActiveMembership(string AgentID, GroupMembershipDelegate d) diff --git a/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs b/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs index aa6203b3a3..57b4667811 100644 --- a/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs +++ b/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs @@ -174,6 +174,7 @@ namespace OpenSim.Capabilities.Handlers newTexture.Flags = AssetFlags.Collectable; newTexture.Temporary = true; + newTexture.Local = true; m_assetService.Store(newTexture); WriteTextureData(request, response, newTexture, format); return true; diff --git a/OpenSim/Data/SQLite/Resources/UserProfiles.migrations b/OpenSim/Data/SQLite/Resources/UserProfiles.migrations new file mode 100644 index 0000000000..16581f6e49 --- /dev/null +++ b/OpenSim/Data/SQLite/Resources/UserProfiles.migrations @@ -0,0 +1,90 @@ +:VERSION 1 # ------------------------------- + +begin; + +CREATE TABLE IF NOT EXISTS classifieds ( + classifieduuid char(36) NOT NULL PRIMARY KEY, + creatoruuid char(36) NOT NULL, + creationdate int(20) NOT NULL, + expirationdate int(20) NOT NULL, + category varchar(20) NOT NULL, + name varchar(255) NOT NULL, + description text NOT NULL, + parceluuid char(36) NOT NULL, + parentestate int(11) NOT NULL, + snapshotuuid char(36) NOT NULL, + simname varchar(255) NOT NULL, + posglobal varchar(255) NOT NULL, + parcelname varchar(255) NOT NULL, + classifiedflags int(8) NOT NULL, + priceforlisting int(5) NOT NULL +); + +commit; + +begin; + +CREATE TABLE IF NOT EXISTS usernotes ( + useruuid varchar(36) NOT NULL, + targetuuid varchar(36) NOT NULL, + notes text NOT NULL, + UNIQUE (useruuid,targetuuid) ON CONFLICT REPLACE +); + +commit; + +begin; + +CREATE TABLE IF NOT EXISTS userpicks ( + pickuuid varchar(36) NOT NULL PRIMARY KEY, + creatoruuid varchar(36) NOT NULL, + toppick int NOT NULL, + parceluuid varchar(36) NOT NULL, + name varchar(255) NOT NULL, + description text NOT NULL, + snapshotuuid varchar(36) NOT NULL, + user varchar(255) NOT NULL, + originalname varchar(255) NOT NULL, + simname varchar(255) NOT NULL, + posglobal varchar(255) NOT NULL, + sortorder int(2) NOT NULL, + enabled int NOT NULL +); + +commit; + +begin; + +CREATE TABLE IF NOT EXISTS userprofile ( + useruuid varchar(36) NOT NULL PRIMARY KEY, + profilePartner varchar(36) NOT NULL, + profileAllowPublish binary(1) NOT NULL, + profileMaturePublish binary(1) NOT NULL, + profileURL varchar(255) NOT NULL, + profileWantToMask int(3) NOT NULL, + profileWantToText text NOT NULL, + profileSkillsMask int(3) NOT NULL, + profileSkillsText text NOT NULL, + profileLanguages text NOT NULL, + profileImage varchar(36) NOT NULL, + profileAboutText text NOT NULL, + profileFirstImage varchar(36) NOT NULL, + profileFirstText text NOT NULL +); + +commit; + +:VERSION 2 # ------------------------------- + +begin; + +CREATE TABLE IF NOT EXISTS userdata ( + UserId char(36) NOT NULL, + TagId varchar(64) NOT NULL, + DataKey varchar(255), + DataVal varchar(255), + PRIMARY KEY (UserId,TagId) +); + +commit; + diff --git a/OpenSim/Data/SQLite/SQLiteUserProfilesData.cs b/OpenSim/Data/SQLite/SQLiteUserProfilesData.cs new file mode 100644 index 0000000000..cc1dac1c92 --- /dev/null +++ b/OpenSim/Data/SQLite/SQLiteUserProfilesData.cs @@ -0,0 +1,904 @@ +/* + * 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.Data; +using System.Reflection; +using log4net; +#if CSharpSqlite +using Community.CsharpSqlite.Sqlite; +#else +using Mono.Data.Sqlite; +#endif +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; + +namespace OpenSim.Data.SQLite +{ + public class SQLiteUserProfilesData: IProfilesData + { + private static readonly ILog m_log = + LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private SqliteConnection m_connection; + private string m_connectionString; + + private FieldInfo[] m_Fields; + private Dictionary m_FieldMap = + new Dictionary(); + + protected virtual Assembly Assembly + { + get { return GetType().Assembly; } + } + + public SQLiteUserProfilesData() + { + } + + public SQLiteUserProfilesData(string connectionString) + { + Initialise(connectionString); + } + + public void Initialise(string connectionString) + { + if (Util.IsWindows()) + Util.LoadArchSpecificWindowsDll("sqlite3.dll"); + + m_connectionString = connectionString; + + m_log.Info("[PROFILES_DATA]: Sqlite - connecting: "+m_connectionString); + + m_connection = new SqliteConnection(m_connectionString); + m_connection.Open(); + + Migration m = new Migration(m_connection, Assembly, "UserProfiles"); + m.Update(); + } + + private string[] FieldList + { + get { return new List(m_FieldMap.Keys).ToArray(); } + } + + #region IProfilesData implementation + public OSDArray GetClassifiedRecords(UUID creatorId) + { + OSDArray data = new OSDArray(); + string query = "SELECT classifieduuid, name FROM classifieds WHERE creatoruuid = :Id"; + IDataReader reader = null; + + using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) + { + cmd.CommandText = query; + cmd.Parameters.AddWithValue(":Id", creatorId); + reader = cmd.ExecuteReader(); + } + + while (reader.Read()) + { + OSDMap n = new OSDMap(); + UUID Id = UUID.Zero; + string Name = null; + try + { + UUID.TryParse(Convert.ToString( reader["classifieduuid"]), out Id); + Name = Convert.ToString(reader["name"]); + } + catch (Exception e) + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": UserAccount exception {0}", e.Message); + } + n.Add("classifieduuid", OSD.FromUUID(Id)); + n.Add("name", OSD.FromString(Name)); + data.Add(n); + } + + reader.Close(); + + return data; + } + public bool UpdateClassifiedRecord(UserClassifiedAdd ad, ref string result) + { + string query = string.Empty; + + query += "INSERT OR REPLACE INTO classifieds ("; + query += "`classifieduuid`,"; + query += "`creatoruuid`,"; + query += "`creationdate`,"; + query += "`expirationdate`,"; + query += "`category`,"; + query += "`name`,"; + query += "`description`,"; + query += "`parceluuid`,"; + query += "`parentestate`,"; + query += "`snapshotuuid`,"; + query += "`simname`,"; + query += "`posglobal`,"; + query += "`parcelname`,"; + query += "`classifiedflags`,"; + query += "`priceforlisting`) "; + query += "VALUES ("; + query += ":ClassifiedId,"; + query += ":CreatorId,"; + query += ":CreatedDate,"; + query += ":ExpirationDate,"; + query += ":Category,"; + query += ":Name,"; + query += ":Description,"; + query += ":ParcelId,"; + query += ":ParentEstate,"; + query += ":SnapshotId,"; + query += ":SimName,"; + query += ":GlobalPos,"; + query += ":ParcelName,"; + query += ":Flags,"; + query += ":ListingPrice ) "; + + if(string.IsNullOrEmpty(ad.ParcelName)) + ad.ParcelName = "Unknown"; + if(ad.ParcelId == null) + ad.ParcelId = UUID.Zero; + if(string.IsNullOrEmpty(ad.Description)) + ad.Description = "No Description"; + + DateTime epoch = new DateTime(1970, 1, 1); + DateTime now = DateTime.Now; + TimeSpan epochnow = now - epoch; + TimeSpan duration; + DateTime expiration; + TimeSpan epochexp; + + if(ad.Flags == 2) + { + duration = new TimeSpan(7,0,0,0); + expiration = now.Add(duration); + epochexp = expiration - epoch; + } + else + { + duration = new TimeSpan(365,0,0,0); + expiration = now.Add(duration); + epochexp = expiration - epoch; + } + ad.CreationDate = (int)epochnow.TotalSeconds; + ad.ExpirationDate = (int)epochexp.TotalSeconds; + + try { + using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) + { + cmd.CommandText = query; + cmd.Parameters.AddWithValue(":ClassifiedId", ad.ClassifiedId.ToString()); + cmd.Parameters.AddWithValue(":CreatorId", ad.CreatorId.ToString()); + cmd.Parameters.AddWithValue(":CreatedDate", ad.CreationDate.ToString()); + cmd.Parameters.AddWithValue(":ExpirationDate", ad.ExpirationDate.ToString()); + cmd.Parameters.AddWithValue(":Category", ad.Category.ToString()); + cmd.Parameters.AddWithValue(":Name", ad.Name.ToString()); + cmd.Parameters.AddWithValue(":Description", ad.Description.ToString()); + cmd.Parameters.AddWithValue(":ParcelId", ad.ParcelId.ToString()); + cmd.Parameters.AddWithValue(":ParentEstate", ad.ParentEstate.ToString()); + cmd.Parameters.AddWithValue(":SnapshotId", ad.SnapshotId.ToString ()); + cmd.Parameters.AddWithValue(":SimName", ad.SimName.ToString()); + cmd.Parameters.AddWithValue(":GlobalPos", ad.GlobalPos.ToString()); + cmd.Parameters.AddWithValue(":ParcelName", ad.ParcelName.ToString()); + cmd.Parameters.AddWithValue(":Flags", ad.Flags.ToString()); + cmd.Parameters.AddWithValue(":ListingPrice", ad.Price.ToString ()); + + cmd.ExecuteNonQuery(); + } + } + catch (Exception e) + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": ClassifiedesUpdate exception {0}", e.Message); + result = e.Message; + return false; + } + return true; + } + public bool DeleteClassifiedRecord(UUID recordId) + { + string query = string.Empty; + + query += "DELETE FROM classifieds WHERE "; + query += "classifieduuid = :ClasifiedId"; + + try + { + using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) + { + cmd.CommandText = query; + cmd.Parameters.AddWithValue(":ClassifiedId", recordId.ToString()); + + cmd.ExecuteNonQuery(); + } + } + catch (Exception e) + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": DeleteClassifiedRecord exception {0}", e.Message); + return false; + } + return true; + } + + public bool GetClassifiedInfo(ref UserClassifiedAdd ad, ref string result) + { + IDataReader reader = null; + string query = string.Empty; + + query += "SELECT * FROM classifieds WHERE "; + query += "classifieduuid = :AdId"; + + try + { + using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) + { + cmd.CommandText = query; + cmd.Parameters.AddWithValue(":AdId", ad.ClassifiedId.ToString()); + + using (reader = cmd.ExecuteReader()) + { + if(reader.Read ()) + { + ad.CreatorId = new UUID(reader["creatoruuid"].ToString()); + ad.ParcelId = new UUID(reader["parceluuid"].ToString ()); + ad.SnapshotId = new UUID(reader["snapshotuuid"].ToString ()); + ad.CreationDate = Convert.ToInt32(reader["creationdate"]); + ad.ExpirationDate = Convert.ToInt32(reader["expirationdate"]); + ad.ParentEstate = Convert.ToInt32(reader["parentestate"]); + ad.Flags = (byte) Convert.ToUInt32(reader["classifiedflags"]); + ad.Category = Convert.ToInt32(reader["category"]); + ad.Price = Convert.ToInt16(reader["priceforlisting"]); + ad.Name = reader["name"].ToString(); + ad.Description = reader["description"].ToString(); + ad.SimName = reader["simname"].ToString(); + ad.GlobalPos = reader["posglobal"].ToString(); + ad.ParcelName = reader["parcelname"].ToString(); + } + } + } + } + catch (Exception e) + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": GetPickInfo exception {0}", e.Message); + } + return true; + } + + public OSDArray GetAvatarPicks(UUID avatarId) + { + IDataReader reader = null; + string query = string.Empty; + + query += "SELECT `pickuuid`,`name` FROM userpicks WHERE "; + query += "creatoruuid = :Id"; + OSDArray data = new OSDArray(); + + try + { + using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) + { + cmd.CommandText = query; + cmd.Parameters.AddWithValue(":Id", avatarId.ToString()); + + using (reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + OSDMap record = new OSDMap(); + + record.Add("pickuuid",OSD.FromString((string)reader["pickuuid"])); + record.Add("name",OSD.FromString((string)reader["name"])); + data.Add(record); + } + } + } + } + catch (Exception e) + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": GetAvatarPicks exception {0}", e.Message); + } + return data; + } + public UserProfilePick GetPickInfo(UUID avatarId, UUID pickId) + { + IDataReader reader = null; + string query = string.Empty; + UserProfilePick pick = new UserProfilePick(); + + query += "SELECT * FROM userpicks WHERE "; + query += "creatoruuid = :CreatorId AND "; + query += "pickuuid = :PickId"; + + try + { + using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) + { + cmd.CommandText = query; + cmd.Parameters.AddWithValue(":CreatorId", avatarId.ToString()); + cmd.Parameters.AddWithValue(":PickId", pickId.ToString()); + + using (reader = cmd.ExecuteReader()) + { + + while (reader.Read()) + { + string description = (string)reader["description"]; + + if (string.IsNullOrEmpty(description)) + description = "No description given."; + + UUID.TryParse((string)reader["pickuuid"], out pick.PickId); + UUID.TryParse((string)reader["creatoruuid"], out pick.CreatorId); + UUID.TryParse((string)reader["parceluuid"], out pick.ParcelId); + UUID.TryParse((string)reader["snapshotuuid"], out pick.SnapshotId); + pick.GlobalPos = (string)reader["posglobal"]; + bool.TryParse((string)reader["toppick"].ToString(), out pick.TopPick); + bool.TryParse((string)reader["enabled"].ToString(), out pick.Enabled); + pick.Name = (string)reader["name"]; + pick.Desc = description; + pick.User = (string)reader["user"]; + pick.OriginalName = (string)reader["originalname"]; + pick.SimName = (string)reader["simname"]; + pick.SortOrder = (int)reader["sortorder"]; + } + } + } + } + catch (Exception e) + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": GetPickInfo exception {0}", e.Message); + } + return pick; + } + + public bool UpdatePicksRecord(UserProfilePick pick) + { + string query = string.Empty; + + query += "INSERT OR REPLACE INTO userpicks ("; + query += "pickuuid, "; + query += "creatoruuid, "; + query += "toppick, "; + query += "parceluuid, "; + query += "name, "; + query += "description, "; + query += "snapshotuuid, "; + query += "user, "; + query += "originalname, "; + query += "simname, "; + query += "posglobal, "; + query += "sortorder, "; + query += "enabled ) "; + query += "VALUES ("; + query += ":PickId,"; + query += ":CreatorId,"; + query += ":TopPick,"; + query += ":ParcelId,"; + query += ":Name,"; + query += ":Desc,"; + query += ":SnapshotId,"; + query += ":User,"; + query += ":Original,"; + query += ":SimName,"; + query += ":GlobalPos,"; + query += ":SortOrder,"; + query += ":Enabled) "; + + try + { + using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) + { + int top_pick; + int.TryParse(pick.TopPick.ToString(), out top_pick); + int enabled; + int.TryParse(pick.Enabled.ToString(), out enabled); + + cmd.CommandText = query; + cmd.Parameters.AddWithValue(":PickId", pick.PickId.ToString()); + cmd.Parameters.AddWithValue(":CreatorId", pick.CreatorId.ToString()); + cmd.Parameters.AddWithValue(":TopPick", top_pick); + cmd.Parameters.AddWithValue(":ParcelId", pick.ParcelId.ToString()); + cmd.Parameters.AddWithValue(":Name", pick.Name.ToString()); + cmd.Parameters.AddWithValue(":Desc", pick.Desc.ToString()); + cmd.Parameters.AddWithValue(":SnapshotId", pick.SnapshotId.ToString()); + cmd.Parameters.AddWithValue(":User", pick.User.ToString()); + cmd.Parameters.AddWithValue(":Original", pick.OriginalName.ToString()); + cmd.Parameters.AddWithValue(":SimName",pick.SimName.ToString()); + cmd.Parameters.AddWithValue(":GlobalPos", pick.GlobalPos); + cmd.Parameters.AddWithValue(":SortOrder", pick.SortOrder.ToString ()); + cmd.Parameters.AddWithValue(":Enabled", enabled); + + cmd.ExecuteNonQuery(); + } + } + catch (Exception e) + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": UpdateAvatarNotes exception {0}", e.Message); + return false; + } + return true; + } + + public bool DeletePicksRecord(UUID pickId) + { + string query = string.Empty; + + query += "DELETE FROM userpicks WHERE "; + query += "pickuuid = :PickId"; + + try + { + using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) + { + cmd.CommandText = query; + cmd.Parameters.AddWithValue(":PickId", pickId.ToString()); + cmd.ExecuteNonQuery(); + } + } + catch (Exception e) + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": DeleteUserPickRecord exception {0}", e.Message); + return false; + } + return true; + } + + public bool GetAvatarNotes(ref UserProfileNotes notes) + { + IDataReader reader = null; + string query = string.Empty; + + query += "SELECT `notes` FROM usernotes WHERE "; + query += "useruuid = :Id AND "; + query += "targetuuid = :TargetId"; + OSDArray data = new OSDArray(); + + try + { + using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) + { + cmd.CommandText = query; + cmd.Parameters.AddWithValue(":Id", notes.UserId.ToString()); + cmd.Parameters.AddWithValue(":TargetId", notes.TargetId.ToString()); + + using (reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) + { + while (reader.Read()) + { + notes.Notes = OSD.FromString((string)reader["notes"]); + } + } + } + } + catch (Exception e) + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": GetAvatarNotes exception {0}", e.Message); + } + return true; + } + + public bool UpdateAvatarNotes(ref UserProfileNotes note, ref string result) + { + string query = string.Empty; + bool remove; + + if(string.IsNullOrEmpty(note.Notes)) + { + remove = true; + query += "DELETE FROM usernotes WHERE "; + query += "useruuid=:UserId AND "; + query += "targetuuid=:TargetId"; + } + else + { + remove = false; + query += "INSERT OR REPLACE INTO usernotes VALUES ( "; + query += ":UserId,"; + query += ":TargetId,"; + query += ":Notes )"; + } + + try + { + using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) + { + cmd.CommandText = query; + + if(!remove) + cmd.Parameters.AddWithValue(":Notes", note.Notes); + cmd.Parameters.AddWithValue(":TargetId", note.TargetId.ToString ()); + cmd.Parameters.AddWithValue(":UserId", note.UserId.ToString()); + + cmd.ExecuteNonQuery(); + } + } + catch (Exception e) + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": UpdateAvatarNotes exception {0}", e.Message); + return false; + } + return true; + } + + public bool GetAvatarProperties(ref UserProfileProperties props, ref string result) + { + IDataReader reader = null; + string query = string.Empty; + + query += "SELECT * FROM userprofile WHERE "; + query += "useruuid = :Id"; + + using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) + { + cmd.CommandText = query; + cmd.Parameters.AddWithValue(":Id", props.UserId.ToString()); + + + try + { + reader = cmd.ExecuteReader(); + } + catch(Exception e) + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": GetAvatarProperties exception {0}", e.Message); + result = e.Message; + return false; + } + if(reader != null && reader.Read()) + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": Getting data for {0}.", props.UserId); + + props.WebUrl = (string)reader["profileURL"]; + UUID.TryParse((string)reader["profileImage"], out props.ImageId); + props.AboutText = (string)reader["profileAboutText"]; + UUID.TryParse((string)reader["profileFirstImage"], out props.FirstLifeImageId); + props.FirstLifeText = (string)reader["profileFirstText"]; + UUID.TryParse((string)reader["profilePartner"], out props.PartnerId); + props.WantToMask = (int)reader["profileWantToMask"]; + props.WantToText = (string)reader["profileWantToText"]; + props.SkillsMask = (int)reader["profileSkillsMask"]; + props.SkillsText = (string)reader["profileSkillsText"]; + props.Language = (string)reader["profileLanguages"]; + } + else + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": No data for {0}", props.UserId); + + props.WebUrl = string.Empty; + props.ImageId = UUID.Zero; + props.AboutText = string.Empty; + props.FirstLifeImageId = UUID.Zero; + props.FirstLifeText = string.Empty; + props.PartnerId = UUID.Zero; + props.WantToMask = 0; + props.WantToText = string.Empty; + props.SkillsMask = 0; + props.SkillsText = string.Empty; + props.Language = string.Empty; + props.PublishProfile = false; + props.PublishMature = false; + + query = "INSERT INTO userprofile ("; + query += "useruuid, "; + query += "profilePartner, "; + query += "profileAllowPublish, "; + query += "profileMaturePublish, "; + query += "profileURL, "; + query += "profileWantToMask, "; + query += "profileWantToText, "; + query += "profileSkillsMask, "; + query += "profileSkillsText, "; + query += "profileLanguages, "; + query += "profileImage, "; + query += "profileAboutText, "; + query += "profileFirstImage, "; + query += "profileFirstText) VALUES ("; + query += ":userId, "; + query += ":profilePartner, "; + query += ":profileAllowPublish, "; + query += ":profileMaturePublish, "; + query += ":profileURL, "; + query += ":profileWantToMask, "; + query += ":profileWantToText, "; + query += ":profileSkillsMask, "; + query += ":profileSkillsText, "; + query += ":profileLanguages, "; + query += ":profileImage, "; + query += ":profileAboutText, "; + query += ":profileFirstImage, "; + query += ":profileFirstText)"; + + using (SqliteCommand put = (SqliteCommand)m_connection.CreateCommand()) + { + put.CommandText = query; + put.Parameters.AddWithValue(":userId", props.UserId.ToString()); + put.Parameters.AddWithValue(":profilePartner", props.PartnerId.ToString()); + put.Parameters.AddWithValue(":profileAllowPublish", props.PublishProfile); + put.Parameters.AddWithValue(":profileMaturePublish", props.PublishMature); + put.Parameters.AddWithValue(":profileURL", props.WebUrl); + put.Parameters.AddWithValue(":profileWantToMask", props.WantToMask); + put.Parameters.AddWithValue(":profileWantToText", props.WantToText); + put.Parameters.AddWithValue(":profileSkillsMask", props.SkillsMask); + put.Parameters.AddWithValue(":profileSkillsText", props.SkillsText); + put.Parameters.AddWithValue(":profileLanguages", props.Language); + put.Parameters.AddWithValue(":profileImage", props.ImageId.ToString()); + put.Parameters.AddWithValue(":profileAboutText", props.AboutText); + put.Parameters.AddWithValue(":profileFirstImage", props.FirstLifeImageId.ToString()); + put.Parameters.AddWithValue(":profileFirstText", props.FirstLifeText); + + put.ExecuteNonQuery(); + } + } + } + return true; + } + + public bool UpdateAvatarProperties(ref UserProfileProperties props, ref string result) + { + string query = string.Empty; + + query += "UPDATE userprofile SET "; + query += "profilePartner=:profilePartner, "; + query += "profileURL=:profileURL, "; + query += "profileImage=:image, "; + query += "profileAboutText=:abouttext,"; + query += "profileFirstImage=:firstlifeimage,"; + query += "profileFirstText=:firstlifetext "; + query += "WHERE useruuid=:uuid"; + + try + { + using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) + { + cmd.CommandText = query; + cmd.Parameters.AddWithValue(":profileURL", props.WebUrl); + cmd.Parameters.AddWithValue(":profilePartner", props.PartnerId.ToString()); + cmd.Parameters.AddWithValue(":image", props.ImageId.ToString()); + cmd.Parameters.AddWithValue(":abouttext", props.AboutText); + cmd.Parameters.AddWithValue(":firstlifeimage", props.FirstLifeImageId.ToString()); + cmd.Parameters.AddWithValue(":firstlifetext", props.FirstLifeText); + cmd.Parameters.AddWithValue(":uuid", props.UserId.ToString()); + + cmd.ExecuteNonQuery(); + } + } + catch (Exception e) + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": AgentPropertiesUpdate exception {0}", e.Message); + + return false; + } + return true; + } + + public bool UpdateAvatarInterests(UserProfileProperties up, ref string result) + { + string query = string.Empty; + + query += "UPDATE userprofile SET "; + query += "profileWantToMask=:WantMask, "; + query += "profileWantToText=:WantText,"; + query += "profileSkillsMask=:SkillsMask,"; + query += "profileSkillsText=:SkillsText, "; + query += "profileLanguages=:Languages "; + query += "WHERE useruuid=:uuid"; + + try + { + using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) + { + cmd.CommandText = query; + cmd.Parameters.AddWithValue(":WantMask", up.WantToMask); + cmd.Parameters.AddWithValue(":WantText", up.WantToText); + cmd.Parameters.AddWithValue(":SkillsMask", up.SkillsMask); + cmd.Parameters.AddWithValue(":SkillsText", up.SkillsText); + cmd.Parameters.AddWithValue(":Languages", up.Language); + cmd.Parameters.AddWithValue(":uuid", up.UserId.ToString()); + + cmd.ExecuteNonQuery(); + } + } + catch (Exception e) + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": AgentInterestsUpdate exception {0}", e.Message); + result = e.Message; + return false; + } + return true; + } + public bool GetUserAppData(ref UserAppData props, ref string result) + { + IDataReader reader = null; + string query = string.Empty; + + query += "SELECT * FROM `userdata` WHERE "; + query += "UserId = :Id AND "; + query += "TagId = :TagId"; + + try + { + using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) + { + cmd.CommandText = query; + cmd.Parameters.AddWithValue(":Id", props.UserId.ToString()); + cmd.Parameters.AddWithValue (":TagId", props.TagId.ToString()); + + using (reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) + { + if(reader.Read()) + { + props.DataKey = (string)reader["DataKey"]; + props.DataVal = (string)reader["DataVal"]; + } + else + { + query += "INSERT INTO userdata VALUES ( "; + query += ":UserId,"; + query += ":TagId,"; + query += ":DataKey,"; + query += ":DataVal) "; + + using (SqliteCommand put = (SqliteCommand)m_connection.CreateCommand()) + { + put.Parameters.AddWithValue(":Id", props.UserId.ToString()); + put.Parameters.AddWithValue(":TagId", props.TagId.ToString()); + put.Parameters.AddWithValue(":DataKey", props.DataKey.ToString()); + put.Parameters.AddWithValue(":DataVal", props.DataVal.ToString()); + + put.ExecuteNonQuery(); + } + } + } + } + } + catch (Exception e) + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": Requst application data exception {0}", e.Message); + result = e.Message; + return false; + } + return true; + } + public bool SetUserAppData(UserAppData props, ref string result) + { + string query = string.Empty; + + query += "UPDATE userdata SET "; + query += "TagId = :TagId, "; + query += "DataKey = :DataKey, "; + query += "DataVal = :DataVal WHERE "; + query += "UserId = :UserId AND "; + query += "TagId = :TagId"; + + try + { + using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) + { + cmd.CommandText = query; + cmd.Parameters.AddWithValue(":UserId", props.UserId.ToString()); + cmd.Parameters.AddWithValue(":TagId", props.TagId.ToString ()); + cmd.Parameters.AddWithValue(":DataKey", props.DataKey.ToString ()); + cmd.Parameters.AddWithValue(":DataVal", props.DataKey.ToString ()); + + cmd.ExecuteNonQuery(); + } + } + catch (Exception e) + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": SetUserData exception {0}", e.Message); + return false; + } + return true; + } + public OSDArray GetUserImageAssets(UUID avatarId) + { + IDataReader reader = null; + OSDArray data = new OSDArray(); + string query = "SELECT `snapshotuuid` FROM {0} WHERE `creatoruuid` = :Id"; + + // Get classified image assets + + + try + { + using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) + { + cmd.CommandText = query; + cmd.Parameters.AddWithValue(":Id", avatarId.ToString()); + + using (reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) + { + while(reader.Read()) + { + data.Add(new OSDString((string)reader["snapshotuuid"].ToString())); + } + } + } + + using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) + { + cmd.CommandText = query; + cmd.Parameters.AddWithValue(":Id", avatarId.ToString()); + + using (reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) + { + if(reader.Read()) + { + data.Add(new OSDString((string)reader["snapshotuuid"].ToString ())); + } + } + } + + query = "SELECT `profileImage`, `profileFirstImage` FROM `userprofile` WHERE `useruuid` = :Id"; + + using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) + { + cmd.CommandText = query; + cmd.Parameters.AddWithValue(":Id", avatarId.ToString()); + + using (reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) + { + if(reader.Read()) + { + data.Add(new OSDString((string)reader["profileImage"].ToString ())); + data.Add(new OSDString((string)reader["profileFirstImage"].ToString ())); + } + } + } + } + catch (Exception e) + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": GetAvatarNotes exception {0}", e.Message); + } + return data; + } + #endregion + } +} + diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs index 74954cc412..d29cc618fb 100644 --- a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs +++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs @@ -1850,8 +1850,8 @@ namespace OpenSim.Framework.Servers.HttpServer m_httpListener2.Start(64); // Long Poll Service Manager with 3 worker threads a 25 second timeout for no events -// m_PollServiceManager = new PollServiceRequestManager(this, 3, 25000); m_PollServiceManager = new PollServiceRequestManager(this, 4, 25000); + m_PollServiceManager.Start(); HTTPDRunning = true; //HttpListenerContext context; @@ -1904,7 +1904,7 @@ namespace OpenSim.Framework.Servers.HttpServer HTTPDRunning = false; try { -// m_PollServiceManager.Stop(); + m_PollServiceManager.Stop(); m_httpListener2.ExceptionThrown -= httpServerException; //m_httpListener2.DisconnectHandler = null; diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs index 7628e23c4d..c2254c4642 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs @@ -203,14 +203,17 @@ namespace OpenSim.Framework.Servers.HttpServer m_server = pSrv; m_WorkerThreadCount = pWorkerThreadCount; m_workerThreads = new Thread[m_WorkerThreadCount]; + } + public void Start() + { //startup worker threads for (uint i = 0; i < m_WorkerThreadCount; i++) { m_workerThreads[i] = Watchdog.StartThread( PoolWorkerJob, - String.Format("PollServiceWorkerThread{0}", i), + string.Format("PollServiceWorkerThread{0}:{1}", i, m_server.Port), ThreadPriority.Normal, false, false, @@ -220,7 +223,7 @@ namespace OpenSim.Framework.Servers.HttpServer m_retrysThread = Watchdog.StartThread( this.CheckRetries, - "PollServiceWatcherThread", + string.Format("PollServiceWatcherThread:{0}", m_server.Port), ThreadPriority.Normal, false, true, @@ -228,7 +231,6 @@ namespace OpenSim.Framework.Servers.HttpServer 1000 * 60 * 10); } - private void ReQueueEvent(PollServiceHttpRequest req) { if (m_running) @@ -279,14 +281,14 @@ namespace OpenSim.Framework.Servers.HttpServer } } - ~PollServiceRequestManager() + public void Stop() { m_running = false; // m_timeout = -10000; // cause all to expire Thread.Sleep(1000); // let the world move foreach (Thread t in m_workerThreads) - Watchdog.AbortThread(t.ManagedThreadId); + Watchdog.AbortThread(t.ManagedThreadId); try { diff --git a/OpenSim/Region/CoreModules/Avatar/Profile/BasicProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/Profile/BasicProfileModule.cs index bf24030771..2bb24ae880 100644 --- a/OpenSim/Region/CoreModules/Avatar/Profile/BasicProfileModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Profile/BasicProfileModule.cs @@ -57,6 +57,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Profile public void Initialise(IConfigSource config) { + if(config.Configs["UserProfiles"] != null) + return; + m_log.DebugFormat("[PROFILE MODULE]: Basic Profile Module enabled"); m_Enabled = true; } diff --git a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs index a97c9b4a5b..322addd805 100644 --- a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs @@ -130,6 +130,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles if (profileConfig == null) { + m_log.Debug("[PROFILES]: UserProfiles disabled, no configuration"); Enabled = false; return; } @@ -1316,7 +1317,16 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles Stream rstream = webResponse.GetResponseStream(); OSDMap response = new OSDMap(); - response = (OSDMap)OSDParser.DeserializeJson(rstream); + try + { + response = (OSDMap)OSDParser.DeserializeJson(rstream); + } + catch (Exception e) + { + m_log.DebugFormat("[PROFILES]: JsonRpcRequest Error {0} - remote user with legacy profiles?", e.Message); + return false; + } + if(response.ContainsKey("error")) { data = response["error"]; diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/HGAssetBroker.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/HGAssetBroker.cs index d221d68f0b..9f58175722 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/HGAssetBroker.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/HGAssetBroker.cs @@ -322,7 +322,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset // a copy of the local asset. m_Cache.Cache(asset); - if (asset.Temporary || asset.Local) + if (asset.Local) { if (m_Cache != null) m_Cache.Cache(asset); diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/LocalAssetServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/LocalAssetServiceConnector.cs index 480cd695c2..52b103978e 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/LocalAssetServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/LocalAssetServiceConnector.cs @@ -258,7 +258,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset if (m_Cache != null) m_Cache.Cache(asset); - if (asset.Temporary || asset.Local) + if (asset.Local) { // m_log.DebugFormat( // "[LOCAL ASSET SERVICE CONNECTOR]: Returning asset {0} {1} without querying database since status Temporary = {2}, Local = {3}", diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/Tests/AssetConnectorTests.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/Tests/AssetConnectorTests.cs index 198247317b..7073433129 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/Tests/AssetConnectorTests.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/Tests/AssetConnectorTests.cs @@ -93,7 +93,9 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset.Tests LocalAssetServicesConnector lasc = new LocalAssetServicesConnector(); lasc.Initialise(config); + // If it is local, it should not be stored AssetBase a1 = AssetHelpers.CreateNotecardAsset(); + a1.Local = true; a1.Temporary = true; lasc.Store(a1); @@ -102,6 +104,24 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset.Tests Assert.That(lasc.GetData(a1.ID), Is.Null); Assert.That(lasc.GetMetadata(a1.ID), Is.Null); + // If it is remote, it should be stored + // AssetBase a2 = AssetHelpers.CreateNotecardAsset(); + // a2.Local = false; + // a2.Temporary = true; + + // lasc.Store(a2); + + // AssetBase retreivedA2 = lasc.Get(a2.ID); + // Assert.That(retreivedA2.ID, Is.EqualTo(a2.ID)); + // Assert.That(retreivedA2.Metadata.ID, Is.EqualTo(a2.Metadata.ID)); + // Assert.That(retreivedA2.Data.Length, Is.EqualTo(a2.Data.Length)); + + // AssetMetadata retrievedA2Metadata = lasc.GetMetadata(a2.ID); + // Assert.That(retrievedA2Metadata.ID, Is.EqualTo(a2.ID)); + + // byte[] retrievedA2Data = lasc.GetData(a2.ID); + // Assert.That(retrievedA2Data.Length, Is.EqualTo(a2.Data.Length)); + // TODO: Add cache and check that this does receive a copy of the asset } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs index cca887afa0..a4c5e08693 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs @@ -148,7 +148,7 @@ public abstract class BSPhysObject : PhysicsActor // The asset state is first 'Unknown' then 'Waiting' then either 'Failed' or 'Fetched'. public enum PrimAssetCondition { - Unknown, Waiting, Failed, Fetched + Unknown, Waiting, FailedAssetFetch, FailedMeshing, Fetched } public PrimAssetCondition PrimAssetState { get; set; } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index 423c38914e..dec6b6f24c 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs @@ -249,7 +249,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters TerrainManager.CreateInitialGroundPlaneAndTerrain(); // Put some informational messages into the log file. - m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation); + m_log.InfoFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation); InTaintTime = false; m_initialized = true; @@ -374,7 +374,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters } else { - m_log.WarnFormat("{0} Selected bullet engine {1} -> {2}/{3}", LogHeader, engineName, ret.BulletEngineName, ret.BulletEngineVersion); + m_log.InfoFormat("{0} Selected bullet engine {1} -> {2}/{3}", LogHeader, engineName, ret.BulletEngineName, ret.BulletEngineVersion); } return ret; diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs index 326fc9ee2d..a780526d04 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs @@ -167,7 +167,7 @@ public abstract class BSShape // Prevent trying to keep fetching the mesh by declaring failure. if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched) { - prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed; + prim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedMeshing; physicsScene.Logger.WarnFormat("{0} Fetched asset would not mesh. {1}, texture={2}", LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture); physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,setFailed,objNam={1},tex={2}", @@ -177,7 +177,8 @@ public abstract class BSShape { // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset if (prim.BaseShape.SculptEntry - && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Failed + && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.FailedAssetFetch + && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.FailedMeshing && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Waiting && prim.BaseShape.SculptTexture != OMV.UUID.Zero ) @@ -219,7 +220,7 @@ public abstract class BSShape } if (!assetFound) { - yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed; + yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedAssetFetch; } physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,fetchAssetCallback,found={1},isSculpt={2},ids={3}", yprim.LocalID, assetFound, yprim.BaseShape.SculptEntry, mismatchIDs ); @@ -227,7 +228,7 @@ public abstract class BSShape } else { - xprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed; + xprim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedAssetFetch; physicsScene.Logger.ErrorFormat("{0} Physical object requires asset but no asset provider. Name={1}", LogHeader, physicsScene.Name); } @@ -235,13 +236,20 @@ public abstract class BSShape } else { - if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Failed) + if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedAssetFetch) { physicsScene.Logger.WarnFormat("{0} Mesh failed to fetch asset. obj={1}, texture={2}", LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture); physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,wasFailed,objNam={1},tex={2}", prim.LocalID, prim.PhysObjectName, prim.BaseShape.SculptTexture); } + if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedMeshing) + { + physicsScene.Logger.WarnFormat("{0} Mesh asset would not mesh. obj={1}, texture={2}", + LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture); + physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,wasFailedMeshing,objNam={1},tex={2}", + prim.LocalID, prim.PhysObjectName, prim.BaseShape.SculptTexture); + } } } @@ -374,7 +382,9 @@ public class BSShapeMesh : BSShape // Check to see if mesh was created (might require an asset). newShape = VerifyMeshCreated(physicsScene, newShape, prim); - if (!newShape.isNativeShape || prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Failed) + if (!newShape.isNativeShape + || prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedMeshing + || prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedAssetFetch) { // If a mesh was what was created, remember the built shape for later sharing. // Also note that if meshing failed we put it in the mesh list as there is nothing else to do about the mesh. @@ -519,7 +529,7 @@ public class BSShapeMesh : BSShape else { // Force the asset condition to 'failed' so we won't try to keep fetching and processing this mesh. - prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed; + prim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedMeshing; physicsScene.Logger.DebugFormat("{0} All mesh triangles degenerate. Prim {1} at {2} in {3}", LogHeader, prim.PhysObjectName, prim.RawPosition, physicsScene.Name); physicsScene.DetailLog("{0},BSShapeMesh.CreatePhysicalMesh,allDegenerate,key={1}", prim.LocalID, newMeshKey); @@ -561,7 +571,9 @@ public class BSShapeHull : BSShape // Check to see if hull was created (might require an asset). newShape = VerifyMeshCreated(physicsScene, newShape, prim); - if (!newShape.isNativeShape || prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Failed) + if (!newShape.isNativeShape + || prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedMeshing + || prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedAssetFetch) { // If a mesh was what was created, remember the built shape for later sharing. Hulls.Add(newHullKey, retHull); @@ -1081,10 +1093,13 @@ public class BSShapeGImpact : BSShape // Check to see if mesh was created (might require an asset). newShape = VerifyMeshCreated(physicsScene, newShape, prim); newShape.shapeKey = newMeshKey; - if (!newShape.isNativeShape || prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Failed) + if (!newShape.isNativeShape + || prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedMeshing + || prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedAssetFetch) { // If a mesh was what was created, remember the built shape for later sharing. - // Also note that if meshing failed we put it in the mesh list as there is nothing else to do about the mesh. + // Also note that if meshing failed we put it in the mesh list as there is nothing + // else to do about the mesh. GImpacts.Add(newMeshKey, retGImpact); } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt index df1da63626..1e015263da 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt +++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt @@ -2,11 +2,6 @@ CURRENT PROBLEMS TO FIX AND/OR LOOK AT ================================================= Script changing rotation of child prim while vehicle moving (eg turning wheel) causes the wheel to appear to jump back. Looks like sending position from previous update. -Vehicle ride, get up, ride again. Second time vehicle does not act correctly. - Have to rez new vehicle and delete the old to fix situation. -Hitting RESET on Nebadon's vehicle while riding causes vehicle to get into odd - position state where it will not settle onto ground properly, etc -Two of Nebadon vehicles in a sim max the CPU. This is new. Enable vehicle border crossings (at least as poorly as ODE) Terrain skirts Avatar created in previous region and not new region when crossing border @@ -23,24 +18,17 @@ vehicle angular banking Center-of-gravity Vehicle angular deflection Preferred orientation angular correction fix -when should angular and linear motor targets be zeroed? when selected? - Need a vehicle.clear()? Or an 'else' in prestep if not physical. Teravus llMoveToTarget script debug Mixing of hover, buoyancy/gravity, moveToTarget, into one force Setting hover height to zero disables hover even if hover flags are on (from SL wiki) limitMotorUp calibration (more down?) llRotLookAt llLookAt -Avatars walking up stairs (HALF DONE) -Avatar movement - flying into a wall doesn't stop avatar who keeps appearing to move through the obstacle (DONE) - walking up stairs is not calibrated correctly (stairs out of Kepler cabin) (DONE) - avatar capsule rotation completed (NOT DONE - Bullet's capsule shape is not the solution) +Convert to avatar mesh capsule. Include rotation of capsule. Vehicle script tuning/debugging Avanti speed script Weapon shooter script Move material definitions (friction, ...) into simulator. -Add material densities to the material types. One sided meshes? Should terrain be built into a closed shape? When meshes get partially wedged into the terrain, they cannot push themselves out. It is possible that Bullet processes collisions whether entering or leaving a mesh. @@ -53,12 +41,8 @@ LINEAR_MOTOR_DIRECTION values should be clamped to reasonable numbers. Same for other velocity settings. UBit improvements to remove rubber-banding of avatars sitting on vehicle child prims: https://github.com/UbitUmarov/Ubit-opensim -Border crossing with linked vehicle causes crash - 20121129.1411: editting/moving phys object across region boundries causes crash - getPos-> btRigidBody::upcast -> getBodyType -> BOOM Vehicles (Move smoothly) Some vehicles should not be able to turn if no speed or off ground. -What to do if vehicle and prim buoyancy differ? Cannot edit/move a vehicle being ridden: it jumps back to the origional position. Neb car jiggling left and right Happens on terrain and any other mesh object. Flat cubes are much smoother. @@ -68,8 +52,6 @@ For limitMotorUp, use raycast down to find if vehicle is in the air. Verify llGetVel() is returning a smooth and good value for vehicle movement. llGetVel() should return the root's velocity if requested in a child prim. Implement function efficiency for lineaar and angular motion. -After getting off a vehicle, the root prim is phantom (can be walked through) - Need to force a position update for the root prim after compound shape destruction Linkset explosion after three "rides" on Nebadon lite vehicle (LinksetConstraint) Remove vehicle angular velocity zeroing in BSPrim.UpdateProperties(). A kludge that isn't fixing the real problem of Bullet adding extra motion. @@ -78,11 +60,10 @@ Incorporate inter-relationship of angular corrections. For instance, angularDefl creates over-correction and over-shoot and wabbling. Vehicle attributes are not restored when a vehicle is rezzed on region creation Create vehicle, setup vehicle properties, restart region, vehicle is not reinitialized. +What to do if vehicle and prim buoyancy differ? GENERAL TODO LIST: ================================================= -Explore btGImpactMeshShape as alternative to convex hulls for simplified physical objects. - Regular triangle meshes don't do physical collisions. Resitution of a prim works on another prim but not on terrain. The dropped prim doesn't bounce properly on the terrain. Add a sanity check for PIDTarget location. @@ -359,4 +340,25 @@ Lock axis (DONE 20130401) Terrain detail: double terrain mesh detail (DONE) Use the HACD convex hull routine in Bullet rather than the C# version. Speed up hullifying large meshes. (DONE) +Vehicle ride, get up, ride again. Second time vehicle does not act correctly. + Have to rez new vehicle and delete the old to fix situation. + (DONE 20130520: normalize rotations) +Hitting RESET on Nebadon's vehicle while riding causes vehicle to get into odd + position state where it will not settle onto ground properly, etc + (DONE 20130520: normalize rotations) +Two of Nebadon vehicles in a sim max the CPU. This is new. + (DONE 20130520: two problems: if asset failed to mesh, constantly refetched + asset; vehicle was sending too many messages to all linkset members) +Add material densities to the material types. (WILL NOT BE DONE: not how it is done) +Avatars walking up stairs (DONE) +Avatar movement + flying into a wall doesn't stop avatar who keeps appearing to move through the obstacle (DONE) + walking up stairs is not calibrated correctly (stairs out of Kepler cabin) (DONE) + avatar capsule rotation completed (NOT DONE - Bullet's capsule shape is not the solution) +After getting off a vehicle, the root prim is phantom (can be walked through) + Need to force a position update for the root prim after compound shape destruction + (DONE) +Explore btGImpactMeshShape as alternative to convex hulls for simplified physical objects. + Regular triangle meshes don't do physical collisions. + (DONE: discovered GImpact is VERY CPU intensive) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 7c375e6d3f..f5d5bc621d 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -5109,6 +5109,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api s = Math.Cos(angle * 0.5); t = Math.Sin(angle * 0.5); // temp value to avoid 2 more sin() calcs + axis = LSL_Vector.Norm(axis); x = axis.x * t; y = axis.y * t; z = axis.z * t; @@ -5149,7 +5150,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api y = rot.y / s; z = rot.z / s; } - + if ((double.IsNaN(x)) || double.IsInfinity(x)) x = 0; + if ((double.IsNaN(y)) || double.IsInfinity(y)) y = 0; + if ((double.IsNaN(z)) || double.IsInfinity(z)) z = 0; return new LSL_Vector(x,y,z); } @@ -5171,7 +5174,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } double angle = 2 * Math.Acos(rot.s); - + if ((double.IsNaN(angle)) || double.IsInfinity(angle)) angle = 0; return angle; } diff --git a/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs b/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs index 3e69ab9246..c685afbe31 100644 --- a/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs +++ b/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs @@ -371,6 +371,31 @@ namespace OpenSim.Region.ScriptEngine.Shared #endregion + #region Methods + public Quaternion Normalize() + { + double length = Math.Sqrt(x * x + y * y + z * z + s * s); + if (length < float.Epsilon) + { + x = 1; + y = 0; + z = 0; + s = 0; + } + else + { + + double invLength = 1.0 / length; + x *= invLength; + y *= invLength; + z *= invLength; + s *= invLength; + } + + return this; + } + #endregion + #region Overriders public override int GetHashCode()